/** * @(#)HSLHarmonicColorWheelImageProducer.java * * Copyright (c) 2008 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.color; import java.awt.Color; import java.awt.Point; import java.awt.color.ColorSpace; /** * HSLHarmonicColorWheelImageProducer. * * @author Werner Randelshofer * @version $Id: HSLHarmonicColorWheelImageProducer.java 717 2010-11-21 * 12:30:57Z rawcoder $ */ public class HSLHarmonicColorWheelImageProducer extends PolarColorWheelImageProducer { private float[] brights; private boolean isDiscrete = true; public HSLHarmonicColorWheelImageProducer(int w, int h) { super(HSLPhysiologicColorSpace.getInstance(), w, h); } public HSLHarmonicColorWheelImageProducer(ColorSpace sys, int w, int h) { super(sys, w, h); } @Override protected void generateLookupTables() { isDiscrete = false; if (isDiscrete) { generateDiscreteLookupTables(); } else { generateContiguousLookupTables(); } } protected void generateContiguousLookupTables() { radials = new float[w * h]; angulars = new float[w * h]; brights = new float[w * h]; alphas = new int[w * h]; float radius = getRadius(); // blend is used to create a linear alpha gradient of two extra pixels float blend = (radius + 2f) / radius - 1f; // Center of the color wheel circle int cx = w / 2; int cy = h / 2; for (int x = 0; x < w; x++) { int kx = x - cx; // Kartesian coordinates of x int squarekx = kx * kx; // Square of kartesian x for (int y = 0; y < h; y++) { int ky = cy - y; // Kartesian coordinates of y int index = x + y * w; float r = (float) Math.sqrt(squarekx + ky * ky) / radius; float sat = r; if (r <= 1f) { alphas[index] = 0xff000000; radials[index] = 1f; brights[index] = 1f - sat; } else { alphas[index] = (int) ((blend - Math.min(blend, r - 1f)) * 255 / blend) << 24; radials[index] = 1f; brights[index] = 0; } if (alphas[index] != 0) { angulars[index] = (float) (Math.atan2(ky, kx) / Math.PI / 2d); } } } } protected void generateDiscreteLookupTables() { radials = new float[w * h]; angulars = new float[w * h]; brights = new float[w * h]; alphas = new int[w * h]; float radius = getRadius(); // blend is used to create a linear alpha gradient of two extra pixels float blend = (radius + 2f) / radius - 1f; // Center of the color wheel circle int cx = w / 2; int cy = h / 2; for (int x = 0; x < w; x++) { int kx = x - cx; // Kartesian coordinates of x int squarekx = kx * kx; // Square of kartesian x for (int y = 0; y < h; y++) { int ky = cy - y; // Kartesian coordinates of y int index = x + y * w; float r = (float) Math.sqrt(squarekx + ky * ky) / radius; float sat = r; if (r <= 1f) { alphas[index] = 0xff000000; radials[index] = 1f; brights[index] = (float) Math.round((1f - sat) * 12f) / 12f; } else { alphas[index] = (int) ((blend - Math.min(blend, r - 1f)) * 255 / blend) << 24; radials[index] = 1f; brights[index] = 0f; } if (alphas[index] != 0) { angulars[index] = Math.round((float) (Math.atan2(ky, kx) / Math.PI / 2d) * 12f) / 12f; } } } } @Override public void generateColorWheel() { float[] components = new float[3]; float[] rgb = new float[3]; for (int index = 0; index < pixels.length; index++) { if (alphas[index] != 0) { components[0] = angulars[index]; components[1] = radials[index]; components[2] = brights[index]; pixels[index] = alphas[index] | 0xffffff & ColorUtil.CStoRGB24(colorSpace, components, rgb); } } newPixels(); isPixelsValid = false; } @Override public Point getColorLocation(Color c) { float[] hsb = ColorUtil.fromColor(colorSpace, c); return getColorLocation(hsb); } @Override public Point getColorLocation(float[] hsb) { float hue = hsb[0]; float brightness = hsb[2]; float radius = Math.min(w, h) / 2f; brightness = Math.max(0f, Math.min(1f, brightness)); Point p; p = new Point( w / 2 + (int) ((radius - radius * brightness) * Math.cos(hue * Math.PI * 2d)), h / 2 - (int) ((radius - radius * brightness) * Math.sin(hue * Math.PI * 2d))); return p; } @Override public float[] getColorAt(int x, int y) { x -= w / 2; y -= h / 2; float r = (float) Math.sqrt(x * x + y * y); float theta = (float) Math.atan2(-y, x); float radius = Math.min(w, h) / 2f; float[] hsb; float sat = r / radius; float hue = (float) (theta / Math.PI / 2d); if (hue < 0) { hue += 1f; } hsb = new float[]{ hue, 1f, 1f - sat }; return hsb; } }