/* * Some classes in this package have been partly inspired by & bits ported from * Python code written by Tom De Smedt & Frederik De Bleser for the "colors" library * of Nodebox.net. * * http://nodebox.net/code/index.php/Colors * * Copyright (c) 2006-2011 Karsten Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * http://creativecommons.org/licenses/LGPL/2.1/ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ package toxi.color; import java.util.ArrayList; import java.util.HashMap; import toxi.math.MathUtils; /** * This class defines color hues and allows them to be access by name. There are * also methods to check if a hue is one of the 7 primary hues (rainbow) or to * find the closest defined hue for a given color. */ public class Hue { /** * */ protected static final HashMap NAMED_HUES = new HashMap<>(); /** * */ protected static final ArrayList PRIMARY_HUES = new ArrayList<>(); /** * */ public static final Hue RED = new Hue("red", 0, true); /** * */ public static final Hue ORANGE = new Hue("orange", 30 / 360.0f, true); /** * */ public static final Hue YELLOW = new Hue("yellow", 60 / 360.0f, true); /** * */ public static final Hue LIME = new Hue("lime", 90 / 360.0f); /** * */ public static final Hue GREEN = new Hue("green", 120 / 360.0f, true); /** * */ public static final Hue TEAL = new Hue("teal", 150 / 360.0f); /** * */ public static final Hue CYAN = new Hue("cyan", 180 / 360.0f); /** * */ public static final Hue AZURE = new Hue("azure", 210 / 360.0f); /** * */ public static final Hue BLUE = new Hue("blue", 240 / 360.0f, true); /** * */ public static final Hue INDIGO = new Hue("indigo", 270 / 360.0f); /** * */ public static final Hue PURPLE = new Hue("purple", 300 / 360.0f, true); /** * */ public static final Hue PINK = new Hue("pink", 330 / 360.0f, true); /** * Tolerance value for checking if a given hue is primary (default 0.01) */ public static float PRIMARY_VARIANCE = 0.01f; /** * Finds the closest defined & named Hue for the given hue value. * Optionally, the search can be limited to primary hues only. * * @param hue * normalized hue (0.0 ... 1.0) will be automatically wrapped * @param primaryOnly * only consider the 7 primary hues * @return closest Hue instance */ public static final Hue getClosest(float hue, boolean primaryOnly) { hue %= 1; float dist = Float.MAX_VALUE; Hue closest = null; Iterable hues = (primaryOnly ? PRIMARY_HUES : NAMED_HUES.values()); for (Hue h : hues) { float d = MathUtils.min(MathUtils.abs(h.hue - hue), MathUtils.abs(1 + h.hue - hue)); if (d < dist) { dist = d; closest = h; } } return closest; } /** * * @param name * @return */ public static final Hue getForName(String name) { return NAMED_HUES.get(name.toLowerCase()); } /** * * @param hue * @return */ public static boolean isPrimary(float hue) { return isPrimary(hue, PRIMARY_VARIANCE); } /** * * @param hue * @param variance * @return */ public static boolean isPrimary(float hue, float variance) { boolean isPrimary = false; for (Hue h : PRIMARY_HUES) { if (MathUtils.abs(hue - h.hue) < variance) { isPrimary = true; break; } } return isPrimary; } /** * */ protected String name; /** * */ protected float hue; /** * */ protected boolean isPrimary; /** * * @param name * @param hue */ public Hue(String name, float hue) { this(name, hue, false); } /** * * @param name * @param hue * @param isPrimary */ public Hue(String name, float hue, boolean isPrimary) { this.name = name; this.hue = hue; this.isPrimary = isPrimary; NAMED_HUES.put(name, this); if (isPrimary) { PRIMARY_HUES.add(this); } } /** * * @return */ public float getHue() { return hue; } /** * * @return */ public String getName() { return name; } /** * * @return */ public boolean isPrimary() { return isPrimary; } /** * * @return */ @Override public String toString() { return "Hue: ID:" + name + " @ " + (int) (hue * 360) + " degrees"; } }