How to create Tri-Color Rectangular Gradient (e.g, implement PaintContext).
I am having a hard time figuring out how to modify the elliptical gradient into a tricolor rectangular gradient. Does anyone know how to modify the code to draw an rectangular gradient?
Thanks
# 1
What would I need to do to modify this code to fill a rectangle:
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = getColorModel().createCompatibleWritableRaster(w,h);
int[] data = new int[w*h*4];
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
double distance = mPoint.distance(x+i,y+j);
double dy = y+j - mPoint.getY();
double dx = x+i - mPoint.getX();
double theta = Math.atan2(dy, dx);
double xp = mPoint.getX() + R * Math.cos(theta);
double yp = mPoint.getY() + R * Math.sin(theta);
line.setLine(mPoint.getX(), mPoint.getY(), xp, yp);
double roundDegrees = Math.round(Math.toDegrees(theta));
double radius = lookup.get(Double.valueOf(roundDegrees));
double ratio = distance / radius;
if(ratio > 1.0)
ratio = 1.0;
int base = (j * w + i) * 4;
data[base + 0] = (int)(mC1.getRed() +
ratio * (mC2.getRed() - mC1.getRed()));
data[base + 1] = (int)(mC1.getGreen() +
ratio * (mC2.getGreen() - mC1.getGreen()));
data[base + 2] = (int)(mC1.getBlue() +
ratio * (mC2.getBlue() - mC1.getBlue()));
data[base + 3] = (int)(mC1.getAlpha() +
ratio * (mC2.getAlpha() - mC1.getAlpha()));
}
}
raster.setPixels(0,0,w,h,data);
return raster;
}
# 2
You might find this demo program (included in the demos that can be installed in the JDK) useful, it's a rectangular gradient color dither.
In my machine it's here:
C:\Program Files\Java\jdk1.6.0_02\demo\applets\DitherTest
# 3
more specifically
This data array that I am building is a little confusing. What do you do to manipulate the color? I have three very spesific color's that I need to output.
data[base + 0] = (int)(mC1.getRed() + ratio * (mC2.getRed() - mC1.getRed()));
data[base + 1] = (int)(mC1.getGreen() + ratio * (mC2.getGreen() - 1.getGreen()));
data[base + 2] = (int)(mC1.getBlue() + ratio * (mC2.getBlue() - mC1.getBlue()));
data[base + 3] = (int)(mC1.getAlpha() +ratio * (mC2.getAlpha() - C1.getAlpha()));
# 4
This is what I love about class documentation.
This documentation tells me nothing about what an iArray is other than (iArray - The input int pixel array.)
public void setPixels(int x,
int y,
int w,
int h,
int[] iArray)
Sets all samples for a rectangle of pixels from an int array containing one sample per array element. An ArrayIndexOutOfBoundsException may be thrown if the coordinates are not in bounds.
Parameters:
x - The X coordinate of the upper left pixel location.
y - The Y coordinate of the upper left pixel location.
w - Width of the pixel rectangle.
h - Height of the pixel rectangle.
iArray - The input int pixel array.
# 5
Not sure if this is what you're looking for, but my ColorGradient class can definitely do a rectangular gradient
You are welcome to use and modify this class, but please don't change the package or take credit for it as your own work
ColorGradient.java
===============
/*
* Created on Jun 14, 2006 by @author Tom Jacobs
*
*/
package tjacobs.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import tjacobs.MathUtils;
import tjacobs.print.StandardPrint;
public class ColorGradient extends BufferedImage {
private Color[] mColors;
private double mSpan;
private Point mCenter;
private int mOrientation;
private boolean mAutoRender = false;
private boolean mOptimized;
private int[] mDrawColors;
public static final int BOTH = 0;
private static final int HORIZONTAL = 1;
private static final int VERTICAL = 2;
public ColorGradient(int width, int height) {
super(width, height, BufferedImage.TYPE_INT_RGB);
setSpan(MathUtils.distance(width, height) / 7);
setCenter(0,0);
setOrientation(BOTH);
setColors(getROYGBIV());
render();
mAutoRender = true;
}
public void setAutoRender(boolean b) {
mAutoRender = b;
}
public boolean getAutoRender() {
return mAutoRender;
}
public ColorGradient(int width, int height, boolean autoRender) {
this(width, height);
mAutoRender = autoRender;
}
/**
* sets the span of the color gradient
*/
public void setSpan(double d) {
mSpan = d;
if (mAutoRender) {
render();
}
}
public double getSpan() {
return mSpan;
}
/**
* sets the center of the color gradient. Default is 0,0
*/
public void setCenter(int x, int y) {
if (mCenter == null) {
mCenter = new Point(x,y);
}
else {
mCenter.x = x; mCenter.y = y;
}
if (mAutoRender) render();
}
public Point getCenter() {
return mCenter;
}
/**
* sets the colors to use in the color gradient. Default is ROYGBIV
*/
public void setColors(Color[] colors) {
mColors = colors;
if (mAutoRender) render();
}
public Color[] getColors() {
return mColors;
}
public int getOrientation() {
return mOrientation;
}
/**
* sets the orientation of the gradient in case you want a gradient
* just in one direction. default is both directions
*/
public void setOrientation(int orientation) {
mOrientation = orientation;
if (mAutoRender) render();
}
protected double getScore(int CenterX, int CenterY, int x2, int y2) {
double distance = 0;
if (mOrientation == BOTH) {
distance = MathUtils.distance(CenterX, CenterY, x2, y2);
}
else if (mOrientation == HORIZONTAL) {
distance = Math.abs(CenterX - x2);
}
else {
distance = Math.abs(CenterY - y2);
}
return distance;
}
public void renderMoveCenter(int x1, int y1, int x2, int y2) {
if (mColors == null) {
return;
}
int width = getWidth();
int height = getHeight();
int x = mCenter.x;
int y = mCenter.y;
float parts1[] = new float[3], parts2[] = new float[3], partsEnd[] = new float[3];
int xDiff = x2 - x1;
int yDiff = y2 - y1;
int absXDiff = xDiff, absYDiff = yDiff;
if (absXDiff < 0) absXDiff = -absXDiff;
if (absYDiff < 0) absYDiff = -absYDiff;
if (xDiff >= 0) {
for (int i = width - 1; i < width - absXDiff ; i--) {
if (yDiff >= 0) {
for (int j = height - 1; j < height -absYDiff; j--) {
}
}
}
}
else {
for (int i = 0; i < width - absXDiff ; i++) {
}
}
for (int i = 0; i < width - absXDiff ; i++) {
for (int j = 0; j < height - absYDiff; j++) {
double distance;
double seg;
int low;
int high;
distance = getScore(x, y, i, j);
seg = distance / mSpan;
low = (int) seg;
high = low + 1;
if (low >= mColors.length) {
low = mColors.length - 1;
high = low;
}
if (high >= mColors.length) {
high = mColors.length - 1;
}
float lowPart = (float) seg - low ;
mColors[low].getColorComponents(parts1);
mColors[high].getColorComponents(parts2);
float hipart = (1 - lowPart);
for (int k = 0; k < 3; k++) {
partsEnd[k] = parts2[k] * lowPart + parts1[k] * hipart;
}
int rgb = (((int) (partsEnd[0]*255+0.5)) & 0xff) << 16 |
(((int) (partsEnd[1]*255+0.5)) & 0xff) << 8 |
(((int) (partsEnd[2]*255+0.5)) & 0xff);
super.setRGB(i, j, rgb);
}
}
}
public void render() {
if (mColors == null) {
return;
}
int width = getWidth();
int height = getHeight();
int x = mCenter.x;
int y = mCenter.y;
if (!mOptimized) {
float parts1[] = new float[3], parts2[] = new float[3], partsEnd[] = new float[3];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
double distance = getScore(x, y, i, j);
double seg = distance / mSpan;
int low = (int) seg;
int high = low + 1;
if (low >= mColors.length) {
low = mColors.length - 1;
high = low;
}
if (high >= mColors.length) {
high = mColors.length - 1;
}
float lowPart = (float) seg - low ;
mColors[low].getColorComponents(parts1);
mColors[high].getColorComponents(parts2);
float hipart = (1 - lowPart);
for (int k = 0; k < 3; k++) {
partsEnd[k] = parts2[k] * lowPart + parts1[k] * hipart;
}
int rgb = (((int) (partsEnd[0]*255+0.5)) & 0xff) << 16 |
(((int) (partsEnd[1]*255+0.5)) & 0xff) << 8 |
(((int) (partsEnd[2]*255+0.5)) & 0xff);
super.setRGB(i, j, rgb);
}
}
} else {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int distance = (int)Math.round(getScore(x, y, i, j));
if (distance >= mDrawColors.length) {
distance = mDrawColors.length - 1;
}
setRGB(i, j, mDrawColors[distance]);
}
}
}
}
public static Color[] getROYGBIV() {
return new Color[] {Color.RED, Color.ORANGE, Color.YELLOW,
Color.GREEN, Color.BLUE, Color.MAGENTA};
}
public static class GradientPane extends JComponent {
private ColorGradient mGradient;
private JPopupMenu mPopup;
private MouseListener mPopupListener;
public class ReportColorMenuItem extends ColorMenuItem {
public ReportColorMenuItem(Color c) {
super(c);
}
public ReportColorMenuItem(Color c, boolean addListener) {
super(c, addListener);
}
public void setColor(Color c) {
super.setColor(c);
updateColorsFromPopup();
}
}
public GradientPane(int width, int height) {
setSize(width, height);
setPreferredSize(new Dimension(width, height));
mGradient = new ColorGradient(width, height);
mGradient.render();
}
public ColorGradient getGradient() {
return mGradient;
}
private void updateColorsFromPopup() {
Color[] colors = new Color[mPopup.getComponentCount() - 2];
for (int i = 0; i < colors.length; i++) {
colors[i] = ((ColorMenuItem)mPopup.getComponent(i)).getColor();
}
getGradient().setColors(colors);
if (!getGradient().getAutoRender()) {
getGradient().render();
}
repaint();
}
public void useColorSelectorPopup(boolean b) {
if (b && mPopup == null) {
mPopup = new JPopupMenu();
ColorGradient grad = getGradient();
Color[] colors = grad.getColors();
for (int i = 0; i < colors.length; i++) {
mPopup.add(new ReportColorMenuItem(colors[i]));
}
final JMenu remove = new JMenu("Remove");
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//int num = Integer.parseInt(ae.getActionCommand());
int num = -1;
Object src = ae.getSource();
for (int i = 0; i < remove.getMenuComponentCount(); i++) {
if (remove.getMenuComponent(i) == src) {
num = i;
break;
}
}
if (num == -1) {
System.out.println("Trouble");
}
getGradient().removeColor(num);
repaint();
mPopup.remove(num);
remove.remove(num);
}
};
for (int i = 0; i < colors.length; i++) {
JMenuItem item = new ColorMenuItem(colors[i], false);
item.setActionCommand(String.valueOf(i));
item.addActionListener(al);
remove.add(item);
}
JMenuItem add = new JMenuItem("Add");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JMenuItem src = (JMenuItem) ae.getSource();
mPopup.remove(src);
mPopup.remove(remove);
Color toAdd = Color.WHITE;
mPopup.add(new ReportColorMenuItem(toAdd));
ColorGradient cg = getGradient();
cg.addColor(toAdd);
if (!cg.getAutoRender()) {
cg.render();
}
mPopup.add(src);
mPopup.add(remove);
remove.add(new ReportColorMenuItem(toAdd, false));
repaint();
}
});
mPopup.add(add);
mPopup.add(remove);
mPopupListener = WindowUtilities.addAsPopup(mPopup, this);
}
else if (!b && mPopup != null) {
mPopup = null;
removeMouseListener(mPopupListener);
mPopupListener = null;
}
}
public void paintComponent(Graphics g) {
g.drawImage(mGradient, 0, 0, null);
}
}
public void addColor(Color c) {
Color[] nc = new Color[mColors.length + 1];
for (int i = 0; i < mColors.length; i++) {
nc[i] = mColors[i];
}
nc[nc.length - 1] = c;
mColors = nc;
render();
}
public void removeColor(int colorNum) {
Color[] nc = new Color[mColors.length -1];
for (int i = 0; i < mColors.length - 1; i++) {
nc[i] = mColors[i < colorNum ? i : i + 1];
}
mColors = nc;
render();
}
public void setOptimized(boolean b) {
mOptimized = b;
if (b) {
int maxDistance = (int) MathUtils.distance(getWidth(), getHeight()) + 1;
mDrawColors = new int[maxDistance];
float[] parts1 = new float[3], parts2 = new float[3], partsEnd = new float[3];
for (int distance = 0; distance < maxDistance; distance++) {
double seg = distance / mSpan;
int low = (int) seg;
int high = low + 1;
if (low >= mColors.length) {
low = mColors.length - 1;
high = low;
}
if (high >= mColors.length) {
high = mColors.length - 1;
}
float lowPart = (float) seg - low ;
mColors[low].getColorComponents(parts1);
mColors[high].getColorComponents(parts2);
float hipart = (1 - lowPart);
for (int k = 0; k < 3; k++) {
partsEnd[k] = parts2[k] * lowPart + parts1[k] * hipart;
}
int rgb = (((int) (partsEnd[0]*255+0.5)) & 0xff) << 16 |
(((int) (partsEnd[1]*255+0.5)) & 0xff) << 8 |
(((int) (partsEnd[2]*255+0.5)) & 0xff);
mDrawColors[distance] = rgb;
//super.setRGB(i, j, rgb);
}
}
else {
mDrawColors = null;
}
}
public static void main(String args[]) {
final GradientPane gp = new GradientPane(800, 800);
gp.getGradient().setOptimized(true);
/*
CreatePopupWindow cpw = new CreatePopupWindow() {
public Window createPopupWindow(Point p) {
//ParamDialog pd = new ParamDialog((JFrame)SwingUtilities.windowForComponent(gp), new String[] {"Center", "Colors", "Orientation", "Span"});
//JDialog pd = new JDialog((JFrame)SwingUtilities.windowForComponent(gp));
//pd.setDefaultCloseOperation(pd.DISPOSE_ON_CLOSE);
JWindow pd = new JWindow();
pd.add(new JLabel("Hello"));
//PopupFactory fac = PopupFactory.getSharedInstance();
//Popup pd = fac.getPopup(gp, new JLabel("Hello"), p.x, p.y);
return pd;
}
};
*/
gp.useColorSelectorPopup(true);
//gp.setPreferredSize(new Dimension(200, 200));
//gp.getGradient().setCenter(100,100);
final JPanel handle = new JPanel();
handle.setSize(5,5);
handle.setLocation(10,10);
handle.setBackground(Color.PINK);
handle.addComponentListener(new ComponentAdapter() {
public void componentMoved(ComponentEvent ev) {
gp.getGradient().setCenter(handle.getX(), handle.getY());
gp.repaint();
}
});
gp.setLayout(null);
new Draggable(handle);
gp.add(handle);
Dimension d = new Dimension(800,800);
gp.setPreferredSize(d);
gp.setSize(d);
WindowUtilities.visualize(gp);
GradientPane gp2 = new GradientPane(200,200);
gp2.getGradient().setOrientation(HORIZONTAL);
WindowUtilities.visualize(gp2);
GradientPane gp3 = new GradientPane(200,200);
gp3.getGradient().setOrientation(VERTICAL);
Window w3 = WindowUtilities.visualize(gp3);
StandardPrint sp1 = new StandardPrint(gp);
StandardPrint sp2 = new StandardPrint(w3);
WindowUtilities.visualize(sp1.preview(200, 200, sp1, sp1.getPageFormat(0), 0));
WindowUtilities.visualize(sp1.preview(200, 200, sp2, sp2.getPageFormat(0), 0));
}
}
# 6
What is your MathUtils.distance function doing?
I do not need the class itself...i will just spoof it.
# 7
Distance formula
http://en.wikipedia.org/wiki/Euclidean_distance
In java, this means that if you have 2 points (x1, y1) and (x2,y2)
int x1, y1, x2, y2;
double distance = Math.sqrt((x1 - x2)^2, (y1 - y2)^2);
Note that you'll have to use the Math.sqr or Math.pow function instead of ^
# 8
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
public class RG extends JPanel implements ActionListener {
boolean showGradient = true;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
if(showGradient) {
g2.setPaint(new TriGradientPaint(w/2, 0, Color.red,
0, h, Color.green.darker(),
w, h, Color.blue));
g2.fillRect(0,0,w,h);
} else {
g2.setPaint(Color.pink);
g2.draw(new Line2D.Double(w/2, h/2, 0, 0));
g2.draw(new Line2D.Double(w/2, h/2, w, 0));
g2.draw(new Line2D.Double(w/2, h/2, w/2, h));
g2.setPaint(Color.red);
g2.draw(new Line2D.Double(w/2, h/2, w/2, 0));
g2.fill(new Rectangle2D.Double(w/2-5,0,10,10));
g2.setPaint(Color.green.darker());
g2.draw(new Line2D.Double(w/2, h/2, 0, h));
g2.fill(new Rectangle2D.Double(0,h-10,10,10));
g2.setPaint(Color.blue);
g2.draw(new Line2D.Double(w/2, h/2, w, h));
g2.fill(new Rectangle2D.Double(w-10,h-10,10,10));
}
}
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand();
showGradient = Boolean.parseBoolean(ac);
repaint();
}
private JPanel getLast() {
String[] ids = { "gradient", "strategy" };
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
for(int j = 0; j < ids.length; j++) {
JRadioButton rb = new JRadioButton(ids[j]);
rb.setActionCommand((j==0) ? "true" : "false");
rb.addActionListener(this);
group.add(rb);
panel.add(rb);
}
return panel;
}
public static void main(String[] args) {
RG test = new RG();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(test);
f.getContentPane().add(test.getLast(), "Last");
f.setSize(500,350);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TriGradientContext implements PaintContext {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
double cx, cy;
Polygon nw, ne, east, se, sw, west;
public TriGradientContext(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
cx = x1 - x2;
cy = (y2 - y1)/2.0;
int[] xpoints = { 0, (int)cx, (int)cx };
int[] ypoints = { 0,0, (int)cy };
nw = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)cx, (int)cx, (int)x3 };
ypoints = new int[] {0, (int)cy,0 };
ne = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)x3, (int)cx, (int)x3 };
ypoints = new int[] {0, (int)cy, (int)y3 };
east = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)cx, (int)cx, (int)x3 };
ypoints = new int[] { (int)cy, (int)y3, (int)y3 };
se = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)cx, (int)cx, (int)x2 };
ypoints = new int[] { (int)cy, (int)y2, (int)y2 };
sw = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { 0, (int)cx, (int)x2 };
ypoints = new int[] { 0, (int)cy, (int)y2 };
west = new Polygon(xpoints, ypoints, 3);
}
public void dispose() {}
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
int[] data = new int[w * h * 4];
Color start = color1;
Color end= color1;
double distance = 1.0, total = 1.0;
for(int k = 0; k < h; k++) {
for(int j = 0; j < w; j++) {
if(nw.contains(x+j, y+k)) {
distance = cx - (x+j);
total = cx*((cy-(y+k))/cy);
start = color1;
end = getBlend(color1, color2);
} else if(ne.contains(x+j, y+k)) {
distance = (x+j) - cx;
total = cx*((cy-(y+k))/cy);
start = color1;
end = getBlend(color1, color3);
} else if(east.contains(x+j, y+k)) {
double dy = cy*(1.0-(((x+j)-cx)/cx));
distance = y3 - (y+k) - dy;
total = y3 - 2*dy;
start = color3;
end = getBlend(color1, color3);
} else if(se.contains(x+j, y+k)) {
distance = (x+j) - cx;
total = cx*(((y+k)-cy)/cy);
start = getBlend(color2, color3);
end = color3;
} else if(sw.contains(x+j, y+k)) {
distance = cx - (x+j);
total = cx*(((y+k)-cy)/cy);
start = getBlend(color2, color3);
end = color2;
} else if(west.contains(x+j, y+k)) {
double dy = cy*((x+j)/cx);
distance = y2 - (y+k) - dy;
total = y2 - 2*dy;
start = color2;
end = getBlend(color1, color2);
}
double ratio = distance / total;
if(ratio > 1.0)
ratio = 1.0;
int base = (k * w + j) * 4;
data[base + 0] = (int)(start.getRed() + ratio *
(end.getRed() - start.getRed()));
data[base + 1] = (int)(start.getGreen() + ratio *
(end.getGreen() - start.getGreen()));
data[base + 2] = (int)(start.getBlue() + ratio *
(end.getBlue() - start.getBlue()));
data[base + 3] = (int)(start.getAlpha() + ratio *
(end.getAlpha() - start.getAlpha()));
}
}
raster.setPixels(0, 0, w, h, data);
return raster;
}
private Color getBlend(Color c1, Color c2) {
int r = (c1.getRed() + c2.getRed())/2;
int g = (c1.getGreen() + c2.getGreen())/2;
int b = (c1.getBlue() + c2.getBlue())/2;
return new Color(r, g, b);
}
}
class TriGradientPaint implements Paint {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
public TriGradientPaint(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
checkGeometry();
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints) {
return new TriGradientContext(x1, y1, color1,
x2, y2, color2,
x3, y3, color3);
}
public int getTransparency() {
int a1 = color1.getAlpha();
int a2 = color2.getAlpha();
return (((a1 & a2) == 0xff) ? OPAQUE : TRANSLUCENT);
}
private void checkGeometry() {
if(Math.abs((x3 - x2)/2 - x1) > 1f ||
y1 > y2 || y1 > y3 ||
x2 > x3 || Math.abs(y2 - y3) > 1f) {
throw new IllegalArgumentException("First point must be top center " +
"with second southwest and third southeast.");
}
}
}
# 9
This is pretty close to what I am looking for. I need to adjust the getRaster function for add the pixels differently.
I am a little confused on what this line of code is doing inside the getRaster function. Anyone care to enlighten?
distance = (x+j) - cx;
total = cx*(((y+k)-cy)/cy);
Thanks much for all the assistance so far.
# 10
nvrmind i figured this one out
Message was edited by:
MattBallard
# 11
what this line of code is doing inside the getRaster function
else if(sw.contains(x+j, y+k)) {
distance = cx - (x+j);
total = cx*(((y+k)-cy)/cy);
start = getBlend(color2, color3);
end = color2;
It is a way to scale between the two colors from the lower centerline (in the strategy
view of the gui), with the blue–green blend to the green diagonal line extending from the
center to the southwest corner, green color. The total is the straight–
line/horizontal distance across from one line to the other for any (y + k) value. The
distance is the length from the vertical centerline to the (x + j) at the same
height (y + k). Use these to calculate the ratio for the apportioning of color values.
* cx, cy
* |
*|
*|
*| location "x" = (x+j), (y+k)
*<x-->| "total"
*|<- d ->| "distance" d = cx - (x+j)
*|
|<cx>|
Rule of similar triangles:
total(y+k)-cy
-- = --
cxcy
(y+k) - cy is the vertical section from the center of the gui (cx, cy) extending
down to the "x" at (x+j), (y+k).
# 12
I understand.
I have modified the code inside the PaintContext as follows:
public TriGradientContext(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
cx = x1 - x2;
cy = (y2 - y1)/2.0;
int[] xpoints = { 0, (int)cx,0 };
int[] ypoints = { 0,0, (int)cy };
rRy = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)cx, (int)x3,0,0 };
ypoints = new int[] {0,0, (int)cy, (int)y2 };
rYy = new Polygon(xpoints, ypoints, 4);
xpoints = new int[] { (int)x3, (int)x3, (int)x1,0 };
ypoints = new int[] {0, (int)cy, (int)y2,(int)y2 };
yYg = new Polygon(xpoints, ypoints, 4);
xpoints = new int[] { (int)cx, (int)x3, (int)x3 };
ypoints = new int[] { (int)y2, (int)y2, (int)y3 };
yGg = new Polygon(xpoints, ypoints, 3);
}
The two triangles (yGg and rRy) will be mirror images of each other with one starting at (0, 0) and the other ending at (x3, y3). Then I need to fill the two center 4 sided polygon's.
yGg will represent my transformation from yellow-green (7FFF00) to green (00ff00). with the green color starting at (x3, y3) .
# 13
I need to fill the rectangle like this:
* cx, cy
* |
*|
*\ |
**| location "x" = (x+j), (y+k)
* *| "total"
*x| "distance" d = cx - (x+j)
**|
** |
|<cx>|
# 14
This does not make sense to me.
"The total is the straight
line/horizontal distance across from one line to the other for any (y + k) value. "
also...
documentation on WritableRaster's is sub par at best.
I am still not sure why everything is reversed either. The setPixels method fills from the top down?
Just seems backwards to me.
Here is the code you offered up with my edits so far:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
public class RG extends JPanel implements ActionListener {
boolean showGradient = true;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
if(showGradient) {
g2.setPaint(new TriGradientPaint(w/2, 0, Color.RED,
0, h, Color.YELLOW,
w, h, Color.GREEN));
g2.fillRect(0,0,w,h);
} else {
g2.setPaint(Color.pink);
g2.draw(new Line2D.Double(w/2, h/2, 0, 0));
g2.draw(new Line2D.Double(w/2, h/2, w, 0));
g2.draw(new Line2D.Double(w/2, h/2, w/2, h));
g2.setPaint(Color.red);
g2.draw(new Line2D.Double(w/2, h/2, w/2, 0));
g2.fill(new Rectangle2D.Double(w/2-5,0,10,10));
g2.setPaint(Color.green.darker());
g2.draw(new Line2D.Double(w/2, h/2, 0, h));
g2.fill(new Rectangle2D.Double(0,h-10,10,10));
g2.setPaint(Color.YELLOW);
g2.draw(new Line2D.Double(w/2, h/2, w, h));
g2.fill(new Rectangle2D.Double(w-10,h-10,10,10));
}
}
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand();
showGradient = Boolean.parseBoolean(ac);
repaint();
}
private JPanel getLast() {
String[] ids = { "gradient", "strategy" };
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
for(int j = 0; j < ids.length; j++) {
JRadioButton rb = new JRadioButton(ids[j]);
rb.setActionCommand((j==0) ? "true" : "false");
rb.addActionListener(this);
group.add(rb);
panel.add(rb);
}
return panel;
}
public static void main(String[] args) {
RG test = new RG();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(test);
f.getContentPane().add(test.getLast(), "Last");
f.setSize(500,350);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TriGradientContext implements PaintContext {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
double cx, cy;
Polygon yGg, rYy, rRy, yYg;
public TriGradientContext(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
cx = x1 - x2;
cy = (y2 - y1)/2.0;
int[] xpoints = { 0, (int)cx,0 };
int[] ypoints = { 0,0, (int)cy };
rRy = new Polygon(xpoints, ypoints, 3);
xpoints = new int[] { (int)cx, (int)x3,0,0 };
ypoints = new int[] {0,0, (int)cy, (int)y2 };
rYy = new Polygon(xpoints, ypoints, 4);
xpoints = new int[] { (int)x3, (int)x3, (int)x1,0 };
ypoints = new int[] {0, (int)cy, (int)y2,(int)y2 };
yYg = new Polygon(xpoints, ypoints, 4);
xpoints = new int[] { (int)cx, (int)x3, (int)x3 };
ypoints = new int[] { (int)y2, (int)y2, (int)cy };
yGg = new Polygon(xpoints, ypoints, 3);
}
public void dispose() {}
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
int[] data = new int[w * h * 4];
Color start = color1;
Color end= color3;
double distance = 1.0, total = 1.0;
for(int k = 0; k < h; k++) {
for(int j = 0; j < w; j++) {
if(rRy.contains(x+j, y+k)) {
distance = (x+j) - cx;
total = cx*(((y+k)-cy)/cy);
start = color1;
end = getBlend(color1, color2);
//} else
//if(rYy.contains(x+j, y+k)) {
//double dy = cy*(1.0-(((x+j)-cx)/cx));
//distance = y3 - (y+k) - dy;
//total = y3 - 2*dy;
//start = getBlend(color1, color2);
//end = color2;
//} else if(yYg.contains(x+j, y+k)) {
//double dy = cy*((x+j)/cx);
//distance = y2 - (y+k) - dy;
//total = y2 - 2*dy;
//start = color2;
//end = getBlend(color2, color3);
} else if(yGg.contains(x+j, y+k)) {
distance = cx - (x+j);
total = cx*((cy-(y+k))/cy);
start = getBlend(color2, color3);;
end = color3;
}
double ratio = distance / total;
if(ratio > 1.0)
ratio = 1.0;
int base = (k * w + j) * 4;
data[base + 0] = (int)(start.getRed() + ratio *
(end.getRed() - start.getRed()));
data[base + 1] = (int)(start.getGreen() + ratio *
(end.getGreen() - start.getGreen()));
data[base + 2] = (int)(start.getBlue() + ratio *
(end.getBlue() - start.getBlue()));
data[base + 3] = (int)(start.getAlpha() + ratio *
(end.getAlpha() - start.getAlpha()));
}
}
raster.setPixels(0, 0, w, h, data);
return raster;
}
private Color getBlend(Color c1, Color c2) {
int r = (c1.getRed() + c2.getRed())/2;
int g = (c1.getGreen() + c2.getGreen())/2;
int b = (c1.getBlue() + c2.getBlue())/2;
return new Color(r, g, b);
}
}
class TriGradientPaint implements Paint {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
public TriGradientPaint(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
checkGeometry();
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints) {
return new TriGradientContext(x1, y1, color1,
x2, y2, color2,
x3, y3, color3);
}
public int getTransparency() {
int a1 = color1.getAlpha();
int a2 = color2.getAlpha();
return (((a1 & a2) == 0xff) ? OPAQUE : TRANSLUCENT);
}
private void checkGeometry() {
if(Math.abs((x3 - x2)/2 - x1) > 1f ||
y1 > y2 || y1 > y3 ||
x2 > x3 || Math.abs(y2 - y3) > 1f) {
throw new IllegalArgumentException("First point must be top center " +
"with second southwest and third southeast.");
}
}
}
# 15
I changed around the coordinates for rYy to get a congruent, ie, no lines are crossing,
Polygon and it is drawn in the strategy view. If I understand your replies 12 and 13 you
want a threecolor gradient as shown in the gradient view.
From reply 14:
"The total is the straight
line/horizontal distance across from one line to the other for any (y + k) value. "
I tried to illustrate this in the "total" view.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class StrategyCheck extends JPanel {
boolean showGradient = true;
boolean showTotal = false;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
if(showGradient) {// gradient
double diagLength = Math.sqrt(w*w + h*h);
double scale = diagLength/Math.min(w, h);
double theta = Math.atan2(w, h);
double x = (1.0 - scale)*w/2;
double y = (1.0 - scale)*h/2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
at.rotate(theta, w/2, h/2);
GradientPaint left = new GradientPaint(0, 0, Color.blue,
w/2, 0, Color.yellow);
GradientPaint right = new GradientPaint(w/2, 0, Color.yellow,
w, 0, Color.green.darker());
g2.setTransform(at);
g2.setPaint(left);
g2.fill(new Rectangle2D.Float(0, 0, w/2, h));
g2.setPaint(right);
g2.fill(new Rectangle2D.Float(w/2, 0, w/2, h));
// Check orientation of axes after rotation.
//g2.setPaint(Color.magenta);
//g2.draw(new Line2D.Double(0,h/2,w,h/2));
//g2.setPaint(Color.cyan);
//g2.draw(new Line2D.Double(w/2,0,w/2,h));
} else if(!showTotal) {// strategy
int x1 = w/2, y1 = 0;
int x2 = 0,y2 = h-1;
int x3 = w-1, y3 = h-1;
int cx = x1 - x2;
int cy = (y2 - y1)/2;
int[] xpoints = { 0, cx, 0 };
int[] ypoints = { 0, 0, cy };
g2.draw(/*rRy*/new Polygon(xpoints, ypoints, 3));
// Altered this one for congruency.
xpoints = new int[] { cx, 0, x2, x3 };
ypoints = new int[] { 0, cy, y2, 0 };
g2.draw(/*rYy*/new Polygon(xpoints, ypoints, 4));
xpoints = new int[] { x3, x3, x1, 0 };
ypoints = new int[] { 0, cy, y2, y2 };
g2.draw(/*yYg*/new Polygon(xpoints, ypoints, 4));
xpoints = new int[] { cx, x3, x3 };
ypoints = new int[] { y2, y2, y3 };
g2.draw(/*yGg*/new Polygon(xpoints, ypoints, 3));
markColorOrigin(0, 0, Color.blue, g2);
markColorOrigin(cx, cy, Color.yellow, g2);
markColorOrigin(x3, y3, Color.green.darker(), g2);
} else { // total
g2.setPaint(Color.pink);
g2.draw(new Line2D.Double(w/2, h/2, w/2, h));
g2.setPaint(Color.green.darker());
g2.draw(new Line2D.Double(w/2, h/2, 0, h));
g2.fill(new Rectangle2D.Double(0,h-10,10,10));
g2.setPaint(Color.blue);
g2.draw(new Line2D.Double(w/2, h/2, w, h));
g2.fill(new Rectangle2D.Double(w-10,h-10,10,10));
double cx = w/2.0;
double cy = h/2.0;
double x = w/4;// (x + j)
double y = h*7/8;// (y + k)
double distance = cx - x;
double total = cx*((y-cy)/cy);
// Offset lines +/-1 for visibility.
// Draw distance.
double tx = cx - distance;
g2.setPaint(Color.red);
g2.draw(new Line2D.Double(cx, y-1, tx, y-1));
// Draw total.
double dx = cx - total;
g2.setPaint(Color.blue);
g2.draw(new Line2D.Double(cx, y+1, dx, y+1));
g2.setPaint(Color.cyan);
g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
}
}
private void markColorOrigin(int x, int y, Color color, Graphics2D g2) {
g2.setPaint(color);
g2.fill(new Ellipse2D.Double(x-10, y-10, 20, 20));
}
private JPanel getLast() {
String[] ids = { "gradient", "strategy", "total" };
final JRadioButton[] rbs = new JRadioButton[ids.length];
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JRadioButton rb = (JRadioButton)e.getSource();
showGradient = rbs[0].isSelected();
showTotal = rbs[2].isSelected();
repaint();
}
};
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
for(int j = 0; j < ids.length; j++) {
rbs[j] = new JRadioButton(ids[j],j==0);
rbs[j].addActionListener(al);
group.add(rbs[j]);
panel.add(rbs[j]);
}
return panel;
}
public static void main(String[] args) {
StrategyCheck test = new StrategyCheck();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(test);
f.getContentPane().add(test.getLast(), "Last");
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
# 16
You have been of Great Help!
I uncommented the code that is used to "check the orientation of axes after rotation".
Is it possible to tweak the orientation of the axis depending on the size of the window? It would be nice to always have each axis at the corner's of the window. I need to control the precision of the gradient. Sometimes I will need more red given a certain situation. The same goes for the other two colors.
I can experiment with fixing that...I assume I would just mess with the diagLength variable....check to see if it is rectangle or square then run the diag function.
I will eventually need to have the red start at the bottom left of the window and the green be in the top right. I think all I have to do is add this code
at.rotate(-theta, w/2, h/2);
Thanks much for helping me out.
# 17
It seems as though my Y axis is distorted after the AffineTransform. It does not line up with the edge of the rectangle like the X does. This causes my gradient not to display correctly.
I guess my question is: How can I control the precision of my axes orientation before I rotate?
In some cases I need the Y axis to be perfectly aligned in the corner after I do the AffineTransform.
# 18
Being able to control the amount of saturation is KEY in what I am trying to accomplish.
# 19
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
public class DiagonalGradient extends JPanel implements ActionListener {
boolean showGradient = true;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
if(showGradient) {
g2.setPaint(new TGPaint(0,0, Color.red,
w/2, h/2, Color.green.darker(),
w,h, Color.blue));
g2.fillRect(0,0,w,h);
} else {
int x1 = 0,y1 = 0;
int x2 = w/2, y2 = h/2;
int x3 = w-1, y3 = h-1;
int cx = x2;
int cy = y2;
int[] xpoints = { 0, cx, 0 };
int[] ypoints = { 0, 0, cy };
g2.draw(new Polygon(xpoints, ypoints, 3));// rRy
xpoints = new int[] { cx, x3, 0, 0 };
ypoints = new int[] { 0, 0, y3, cy };
g2.draw(new Polygon(xpoints, ypoints, 4));// rYy
xpoints = new int[] { x3, x3, x2, 0 };
ypoints = new int[] { 0, cy, y3, y3 };
g2.draw(new Polygon(xpoints, ypoints, 4));// yYg
xpoints = new int[] { cx, x3, x3 };
ypoints = new int[] { y3, y3, y2 };
g2.draw(new Polygon(xpoints, ypoints, 3));// yGg
markColorOrigin(0, 0, Color.red, g2);
markColorOrigin(cx, cy, Color.yellow, g2);
markColorOrigin(x3, y3, Color.green.darker(), g2);
}
}
private void markColorOrigin(int x, int y, Color color, Graphics2D g2) {
g2.setPaint(color);
g2.fill(new Ellipse2D.Double(x-10, y-10, 20, 20));
}
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand();
showGradient = Boolean.parseBoolean(ac);
repaint();
}
private JPanel getLast() {
String[] ids = { "gradient", "strategy" };
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
for(int j = 0; j < ids.length; j++) {
JRadioButton rb = new JRadioButton(ids[j],j==0);
rb.setActionCommand((j==0) ? "true" : "false");
rb.addActionListener(this);
group.add(rb);
panel.add(rb);
}
return panel;
}
public static void main(String[] args) {
DiagonalGradient test = new DiagonalGradient();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(test);
f.getContentPane().add(test.getLast(), "Last");
f.setSize(500,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TGContext implements PaintContext {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
double cx, cy;
Polygon nw, nwc, sec, se;
Line2D.Double diagonalLine;
double parallelDist;
Map<Integer,Double> lookup;
public TGContext(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
cx = x2;
cy = y2;
int[] xpoints = { 0, (int)cx,0 };
int[] ypoints = { 0,0, (int)cy };
nw = new Polygon(xpoints, ypoints, 3);// rRy
xpoints = new int[] { (int)cx, (int)x3,0,0 };
ypoints = new int[] {0,0, (int)y3, (int)cy };
nwc = new Polygon(xpoints, ypoints, 4);// rYy
xpoints = new int[] { (int)x3, (int)x3, (int)x2,0 };
ypoints = new int[] {0, (int)cy, (int)y3, (int)y3 };
sec = new Polygon(xpoints, ypoints, 4);// yYg
xpoints = new int[] { (int)cx, (int)x3, (int)x3 };
ypoints = new int[] { (int)y3, (int)y3, (int)y2 };
se = new Polygon(xpoints, ypoints, 3);// yGg
diagonalLine = new Line2D.Double(0, y3, x3, 0);
// Orthogonal distance between parallel lines.
parallelDist = diagonalLine.ptLineDist(0, cy);
createLookup();
}
public void dispose() {}
public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
int[] data = new int[w * h * 4];
Color start = color1;
Color end= color1;
double distance = 1.0, total = 1.0;
for(int k = 0; k < h; k++) {
for(int j = 0; j < w; j++) {
if(nw.contains(x+j, y+k)) {
double dy = (y+k);
double dx = (x+j);
distance = Math.sqrt(dx*dx + dy*dy);
int theta = (int)Math.round(Math.toDegrees(Math.atan2(dy,dx)));
Integer key = Integer.valueOf(theta);
total = ((Double)lookup.get(key)).doubleValue();
start = color1;
end = getBlend(color1, color2);
} else if(nwc.contains(x+j, y+k)) {
distance = diagonalLine.ptSegDist((x+j), (y+k));
total = parallelDist;
start = color2;
end = getBlend(color1, color2);
} else if(sec.contains(x+j, y+k)) {
distance = diagonalLine.ptSegDist((x+j), (y+k));
total = parallelDist;
start = color2;
end = getBlend(color2, color3);
} else if(se.contains(x+j, y+k)) {
double dy = (y+k) - y3;
double dx = (x+j) - x3;
distance = Math.sqrt(dx*dx + dy*dy);
int theta =
(int)Math.round(Math.toDegrees(Math.atan2(dy,dx)+Math.PI));
Integer key = Integer.valueOf(theta);
total = ((Double)lookup.get(key)).doubleValue();
start = color3;
end = getBlend(color2, color3);
}
double ratio = distance / total;
if(ratio > 1.0)
ratio = 1.0;
int base = (k * w + j) * 4;
data[base + 0] = (int)(start.getRed() + ratio *
(end.getRed() - start.getRed()));
data[base + 1] = (int)(start.getGreen() + ratio *
(end.getGreen() - start.getGreen()));
data[base + 2] = (int)(start.getBlue() + ratio *
(end.getBlue() - start.getBlue()));
data[base + 3] = (int)(start.getAlpha() + ratio *
(end.getAlpha() - start.getAlpha()));
}
}
raster.setPixels(0, 0, w, h, data);
return raster;
}
private Color getBlend(Color c1, Color c2) {
int r = (c1.getRed() + c2.getRed())/2;
int g = (c1.getGreen() + c2.getGreen())/2;
int b = (c1.getBlue() + c2.getBlue())/2;
return new Color(r, g, b);
}
/** Distance from corner to closest line for [0 - 90] degrees of arc. */
private void createLookup() {
lookup = new HashMap<Integer,Double>();
double length = Math.sqrt(cx*cx + cy*cy);
Line2D.Double fixed = new Line2D.Double(cx,0,0,cy);
// Clockwise from zero by degree 0 -> 90.
for(int j = 0; j <= 90; j++) {
double theta = Math.toRadians(j);
double x = length*Math.cos(theta);
double y = length*Math.sin(theta);
Line2D.Double sweep = new Line2D.Double(0,0,x,y);
Point2D.Double p = getIntersection(fixed, sweep);
double distance = Math.sqrt(p.x*p.x + p.y*p.y);
lookup.put(Integer.valueOf(j), Double.valueOf(distance));
}
}
private Point2D.Double getIntersection(Line2D.Double line1, Line2D.Double line2) {
double x1 = line1.getX1();
double y1 = line1.getY1();
double x2 = line1.getX2();
double y2 = line1.getY2();
double x3 = line2.getX1();
double y3 = line2.getY1();
double x4 = line2.getX2();
double y4 = line2.getY2();
double aDividend = (x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3);
double aDivisor = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
double ua = aDividend / aDivisor;
double bDividend = (x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3);
double bDivisor = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
double ub = bDividend / bDivisor;
Point2D.Double p = new Point2D.Double();
p.x = x1 + ua * (x2 - x1);
p.y = y1 + ua * (y2 - y1);
return p;
}
}
class TGPaint implements Paint {
float x1, y1;
float x2, y2;
float x3, y3;
Color color1;
Color color2;
Color color3;
public TGPaint(float x1, float y1, Color color1,
float x2, float y2, Color color2,
float x3, float y3, Color color3) {
this.x1 = x1;this.y1 = y1;this.color1 = color1;
this.x2 = x2;this.y2 = y2;this.color2 = color2;
this.x3 = x3;this.y3 = y3;this.color3 = color3;
checkGeometry();
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints) {
return new TGContext(x1, y1, color1,
x2, y2, color2,
x3, y3, color3);
}
public int getTransparency() {
int a1 = color1.getAlpha();
int a2 = color2.getAlpha();
return (((a1 & a2) == 0xff) ? OPAQUE : TRANSLUCENT);
}
private void checkGeometry() {
if(Math.abs((x3 - x2) - (x2 - x1)) > 1f ||
Math.abs((y3 - y2) - (y2 - y1)) > 1f) {
throw new IllegalArgumentException("First point must be northwest " +
"with second in center and third southeast.");
}
}
}
# 20
Could you explain that code a bit. ?
How can I control the saturation of colors?
# 21
explain that code a bit
In the corner sections (of the strategy view) the corners are treated as a point source
blending toward the straight line blended/average color. I made up a lookup table for the
distance from point to line for each degree (in an effort) to speed up the calculations.
The gradient between parallel line segments is a straight gradient figured from the
center/diagonal line toward each of the other two parallel lines.
How can I control the saturation of colors?
You can use the HSB color values which give access to saturation and light in the color for
any hue. The saturation is the "amount of color" for any hue. The Color class api has
methods for dealing with HSB. There are other systems and names, egs, HSL and HSV, and
discussions about accuracy, validity, efficacy, etc(Google). The java implementation seems
to do okay.
# 22
If I used a:
AffiniteTransform.getRotateInstance(Math.PI/2);
g2.setTransform(at);
this would give me a Graphics2D (after the setTransform method is called) object with the red starting at Cartesian Coordinate (0,0)?