/*
* @(#)DiskColorWheelImageProducer.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.*;
import java.awt.color.ColorSpace;
import java.awt.geom.Point2D;
import static java.lang.Math.*;
/**
* Produces the image of a {@link JColorWheel} by interpreting two components
* of a {@code ColorSpace} as x,y Cartesian coordinates within a disk boundary.
*
*
* @see JColorWheel
*
* @author Werner Randelshofer
* @version $Id: DiskColorWheelImageProducer.java 527 2009-06-07 14:28:19Z rawcoder $
*/
public class DiskColorWheelImageProducer extends AbstractColorWheelImageProducer {
/** Lookup table for angular component values. */
protected float[] angulars;
/** Lookup table for radial component values. */
protected float[] radials;
/** Lookup table for alphas.
* The alpha value is used for antialiasing the
* color wheel.
*/
protected int[] alphas;
private boolean flipX, flipY;
/** Creates a new instance. */
public DiskColorWheelImageProducer(ColorSpace sys, int w, int h) {
this(sys,w,h,false,false);
}
/** Creates a new instance. */
public DiskColorWheelImageProducer(ColorSpace sys, int w, int h, boolean flipX, boolean flipY) {
super(sys, w, h);
this.flipX = flipX;
this.flipY = flipY;
}
protected void generateLookupTables() {
radials = new float[w * h];
angulars = new float[w * h];
alphas = new int[w * h];
float radius = getRadius();
Point2D.Float center=getCenter();
// 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
float maxR = colorSpace.getMaxValue(radialIndex);
float minR = colorSpace.getMinValue(radialIndex);
float extentR = maxR - minR;
float maxA = colorSpace.getMaxValue(angularIndex);
float minA = colorSpace.getMinValue(angularIndex);
float extentA = maxA - minA;
float cx = center.x;
float cy = center.y;
/*
int xOffset = (w - side) / 2;
int yOffset = (h - side) / 2 * w;
float extentX = side - 1;
float extentY = extentX;
*/
for (int x = 0; x < w; x++) {
float kx = (x - cx)/radius;
if (flipX) kx=-kx;
float squarekx=kx*kx;
for (int y = 0; y < h; y++) {
float ky = (y - cy)/radius;
if (flipY) ky=-ky;
int index = x + y * w;
float radiusRatio = (float) Math.sqrt(squarekx + ky * ky);
if (radiusRatio <= 1f) {
alphas[index] = 0xff000000;
//radials[index] = radiusRatio;
} else {
alphas[index] = (int) ((blend - Math.min(blend, radiusRatio - 1f)) * 255 / blend) << 24;
//radials[index] = maxR;
}
if (alphas[index] != 0) {
//angulars[index] = (float) (Math.atan2(ky, kx));
}
double angle=Math.atan2(ky,kx);
// scale from disk to box
double scale=1.0/Math.max(Math.abs(Math.sin(angle)),Math.abs(Math.cos(angle)));
scale=1.0;
radials[index] = (float)( (kx*scale+1)/2 * extentR + minR );
angulars[index] = (float)( (ky*scale+1)/2 * extentA + minA );
}
}
isLookupValid = true;
}
protected void generateLookupTablesOLD() {
radials = new float[w * h];
angulars = 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
float maxR = colorSpace.getMaxValue(radialIndex);
float minR = colorSpace.getMinValue(radialIndex);
float extentR = maxR - minR;
float maxA = colorSpace.getMaxValue(angularIndex);
float minA = colorSpace.getMinValue(angularIndex);
float extentA = maxA - minA;
int side = Math.min(w, h); // side length
int cx = side / 2;
int cy = side / 2;
int xOffset = (w - side) / 2;
int yOffset = (h - side) / 2 * w;
float extentX = side - 1;
float extentY = extentX;
for (int x = 0; x < side; x++) {
float kx = (x - cx)/radius;
if (flipX) kx=-kx;
float squarekx=kx*kx;
for (int y = 0; y < side; y++) {
float ky = (cy - y)/radius;
if (flipY) ky=-ky;
int index = x + y * w+xOffset+yOffset;
float radiusRatio = (float) Math.sqrt(squarekx + ky * ky);
if (radiusRatio <= 1f) {
alphas[index] = 0xff000000;
//radials[index] = radiusRatio;
} else {
alphas[index] = (int) ((blend - Math.min(blend, radiusRatio - 1f)) * 255 / blend) << 24;
//radials[index] = maxR;
}
if (alphas[index] != 0) {
//angulars[index] = (float) (Math.atan2(ky, kx));
}
float angle=(float)Math.atan2(ky,kx);
float scale=(float)Math.max(Math.abs(Math.sin(angle)),Math.abs(Math.cos(angle)))+0.1f;
radials[index] = (kx/scale+1f)/2f * extentR + minR;
angulars[index] = (ky/scale+1f)/2f * extentA + minA;
}
}
isLookupValid = true;
}
@Override
public boolean needsGeneration() {
return !isPixelsValid;
}
@Override
public void regenerateColorWheel() {
if (!isPixelsValid) {
generateColorWheel();
}
}
@Override
public void generateColorWheel() {
if (!isLookupValid) {
generateLookupTables();
}
float[] components = new float[colorSpace.getNumComponents()];
float[] rgb=new float[3];
for (int index = 0; index < pixels.length; index++) {
if (alphas[index] != 0) {
components[angularIndex] = angulars[index];
components[radialIndex] = radials[index];
components[verticalIndex] = verticalValue;
pixels[index] = alphas[index] | 0xffffff & ColorUtil.CStoRGB24(colorSpace, components,rgb);
}
}
newPixels();
isPixelsValid = true;
}
@Override
public Point getColorLocation(float[] components) {
float radius=getRadius();
Point2D.Float center=getCenter();
float radial = (components[radialIndex] - colorSpace.getMinValue(radialIndex))//
/ (colorSpace.getMaxValue(radialIndex) - colorSpace.getMinValue(radialIndex)) * 2 -1;
float angular = (components[angularIndex] - colorSpace.getMinValue(angularIndex))//
/ (colorSpace.getMaxValue(angularIndex) - colorSpace.getMinValue(angularIndex)) * 2 -1;
if (flipX) radial=-radial;
if (flipY) angular=-angular;
// clamp to disk
float r=(float)sqrt(angular*angular+radial*radial);
if (r>1f) {
angular/=r;
radial/=r;
}
Point p = new Point(
(int) (radius * radial + center.x),
(int) (radius * angular + center.y)//
);
return p;
}
@Override
public float[] getColorAt(int x, int y) {
float radius=getRadius();
Point2D.Float center=getCenter();
float radial=(x-center.x)/radius;
float angular=(y-center.y)/radius;
if (flipX) angular=-angular;
if (flipY) radial=-radial;
// clamp to disk
float r=(float)sqrt(angular*angular+radial*radial);
if (r>1f) {
angular/=r;
radial/=r;
}
float[] hsb = new float[3];
hsb[angularIndex] = (angular + 1f)/2f//
* (colorSpace.getMaxValue(angularIndex) - colorSpace.getMinValue(angularIndex))//
+ colorSpace.getMinValue(angularIndex);
hsb[radialIndex] = (radial + 1f)/2f//
* (colorSpace.getMaxValue(radialIndex) - colorSpace.getMinValue(radialIndex))//
+ colorSpace.getMinValue(radialIndex);
hsb[verticalIndex] = verticalValue;
return hsb;
}
}