Skip to main content

[JAVA3D-INTEREST] color interpolation with legend

17 replies [Last post]
Anonymous

Could anyone guide me, a novice, with the following problem:

I need to write an application that will color different triangles based on a value, like temperature. So, if I have 10 objects with values of 1-10, I want to code to color them from red to blue, deciding the color based on the scale. The user might want to select the scale. I'll also need a legend drawn. My questions are how to pick these colors, how to use a data point and interpolate which color it belongs with, etc. I'm sure weather maps and such do this regularly. From what I see of Java, you have to tell it specific colors. The only cycling I've unearthed is based on time (ColorInterpolator). Is there a cycling method (or loop) that people use to choose colors like this?

Thank you - I hope this is clear enough
[att1.html]

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Mark McKay

> I'm not knocking HUDs or overlays as some of the underlying GL
> mechanisms for overlays are fantastic, but they're just not available
> here, plus at the end of the day, item 3 is much better suited by
> swing. No one with a deadline wants to do font or layout management.
>

How do you do a Swing overlay? I thought that as Canvas3D was
heavyweight and Swing was lightweight, nothing would be rendered.

I solved this problem by rendering to a BufferedImage and then bliting
it during the post render pass of the Canvas3D. While this worked and
was fast, I was annoyed to discover that Java3D 'helps' you by
automatically scaling your image when the Canvas3D is scaled. Is there
a way to get a fast 2D overlay and have my post render bliting be 1:1?

Mark McKay

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

You can't do a swing overlay.
You might have some luck doing an awt overly, but it wouldn't be pretty.
She wants a legend, not an overlay and in this case it simply falls under
different screen real-estate than the viewport window.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

>A legend can probably be done with a 'heads up display' (HUD) approach.

This is true. It can be done. I'd still run with swing over j3d, given
1. the performance hit.
2. lack, of clean and simple supporting APIs (the one linked to isn't bad,
but its not great)
3. no simple layout mechanisms for building legends, given text and
components of arbitrary length/size and an arbitrary number of entries.

I'm not knocking HUDs or overlays as some of the underlying GL mechanisms
for overlays are fantastic, but they're just not available here, plus at
the end of the day, item 3 is much better suited by swing. No one with a
deadline wants to do font or layout management.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Mark McKay

> I'm not knocking HUDs or overlays as some of the underlying GL
> mechanisms for overlays are fantastic, but they're just not available
> here, plus at the end of the day, item 3 is much better suited by
> swing. No one with a deadline wants to do font or layout management.
>

How do you do a Swing overlay? I thought that as Canvas3D was
heavyweight and Swing was lightweight, nothing would be rendered.

I solved this problem by rendering to a BufferedImage and then bliting
it during the post render pass of the Canvas3D. While this worked and
was fast, I was annoyed to discover that Java3D 'helps' you by
automatically scaling your image when the Canvas3D is scaled. Is there
a way to get a fast 2D overlay and have my post render bliting be 1:1?

Mark McKay

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

mnjacobs
Offline
Joined: 2003-06-13

A legend can probably be done with a 'heads up display' (HUD) approach. There is support over at www.j3d.org if you want to pick up their solution. Another approach (although slow) would be to get your canvas3d, call getGraphics2D() and draw directly on the J3DGraphics2D (buffered image or rectangles for example). One last option is to use a J3D billboard.

Mike

Naomi Greenberg

I don't need Java3d to display the legend - it can be done in 2d on a side
panel. But, I don't know how to draw a box that displays a continuum of
colors in HSV

----- Original Message -----
From:
To:
Sent: Tuesday, November 02, 2004 10:19 AM
Subject: Re: [JAVA3D-INTEREST] color interpolation with legend

> A legend can probably be done with a 'heads up display' (HUD) approach.
There is support over at www.j3d.org if you want to pick up their solution.
Another approach (although slow) would be to get your canvas3d, call
getGraphics2D() and draw directly on the J3DGraphics2D (buffered image or
rectangles for example). One last option is to use a J3D billboard.
>
> Mike
> ---
> [Message sent by forum member 'mnjacobs' (Mike Jacobs)]
>
> http://www.javadesktop.org/forums/thread.jspa?messageID=36061&#36061
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
> For additional commands, e-mail: interest-help@java3d.dev.java.net
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

>panel. But, I don't know how to draw a box that displays a continuum of
>colors in HSV

OK. what you want to do is when you run through your HSV lookup in j3d,
creating Color3f to pass to your application, at the same time, you'll want
to create a java.util.Vector or array containing legend entries for your
legend, representing what that Color means.

A custom class to accommodate this would look something like

package ca.beq.demo.swing;
import java.awt.Color;

class LegendEntry {
// String that describes what this entry represents
String legendText;

// Color (stored in RGB, but created in HSV) represented by this entry
// it has the same makeup as Color3f, but is stored in a swing class,
// rather than j3d
Color legendColour;

public LegendEntry ( String text, Color colour ) {
legendText = text;
legendColour = colour;
}

}

Once you have the Vector or array, pass it to your JList constructor.

Assign your JList a ListCellRenderer that looks something like this:

package ca.beq.demo.swing;
import java.awt.Component;
import java.awt.Dimension;

import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;

public class LegendEntryRenderer implements ListCellRenderer {

/**
* @see
javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList,
java.lang.Object, int, boolean, boolean)
*/
public Component getListCellRendererComponent( JList list, Object
value, int index, boolean isSelected, boolean cellHasFocus ) {
// return a jpanel as the rendering component
JPanel component = new JPanel();

// This is the beast you created which has the colour and text
LegendEntry entry = (LegendEntry) value;

JPanel colourBox = new JPanel();
// make box the correct colour
colourBox.setBackground( entry.legendColour );
// give box a consistant size
colourBox.setPreferredSize( new Dimension( 64, 32 ) );

JLabel legendText = new JLabel( entry.legendText );

// use the default FlowLayout to position box and text
component.add( colourBox );
component.add( legendText );

return component;
}

}

This is a template for a cell renderer, it will work, but you can get much
more creative and less vanilla than this. It won't change colour when an
entry gets selected or has focus, so selection and focus on legend elements
is largely irrelevant from a visual standpoint.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Naomi Greenberg

I don't want a list with selections. I want to draw a bar with the color
shading from lowest to highest in it and I'll draw a label on either end
with the min/max data values associated with the colors. Sort of like a
weather map.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

Create a custom simple Component (I'd extend Canvas, but Panel works
too). I'd override the paint method so it looks something like this:

public final void paint( Graphics g ) {
for ( int i = 0; i < getHeight(); i++ ) {
Color hsvColor = getHsvColor( (double) i / ( getHeight() - 1 ) );
g.setColor( hsvColor );
g.drawLine(0, i, getWidth() - 1, i);
}

} // paint

Note: getHsvColor() does a HSV lookup on a double between 0 and 1 and
returns the RGB colour that matches so that 0 returns red and 1 returns blue.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

mnjacobs
Offline
Joined: 2003-06-13

Interpolating in the RGB space may not look right. This is because color intensity is not linear in RGB. I believe you want to interpolate the hue. In order to interpolate the hue, the target colors you want to use need to converted to the HSV color model (see http://en.wikipedia.org/wiki/HSV_color_space). The transitions you are looking for (blue, green, yellow, orange, red) follow a decreasing hue so the interpolation should be straight forward.

There are a few ways to do the conversion. One is to use the AWT classes: http://java.sun.com/developer/technicalArticles/Media/ColorClasses/. A second approach is to create or find a utility class that does the RGB to HSV and HSV to RGB conversions. The algorithms for these conversions are well documented (Foley and Van Dam for example).

Mike

Naomi Greenberg

Many thanks for this response. I was able to interpolate my values using
hue and translating to RGB color using the formulas cited in the wikipedia
article. Now, any idea how to draw a color legend where I display my colors
from blue to red (by HSV) and show below the values associated with each
color?

Thanks,
Naomi Greenberg

----- Original Message -----
From:
To:
Sent: Friday, October 22, 2004 9:43 AM
Subject: Re: [JAVA3D-INTEREST] color interpolation with legend

> Interpolating in the RGB space may not look right. This is because color
intensity is not linear in RGB. I believe you want to interpolate the hue.
In order to interpolate the hue, the target colors you want to use need to
converted to the HSV color model (see
http://en.wikipedia.org/wiki/HSV_color_space). The transitions you are
looking for (blue, green, yellow, orange, red) follow a decreasing hue so
the interpolation should be straight forward.
>
> There are a few ways to do the conversion. One is to use the AWT classes:
http://java.sun.com/developer/technicalArticles/Media/ColorClasses/. A
second approach is to create or find a utility class that does the RGB to
HSV and HSV to RGB conversions. The algorithms for these conversions are
well documented (Foley and Van Dam for example).
>
> Mike
> ---
> [Message sent by forum member 'mnjacobs' (Mike Jacobs)]
>
> http://www.javadesktop.org/forums/thread.jspa?messageID=34806&#34806
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
> For additional commands, e-mail: interest-help@java3d.dev.java.net
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

Offhand, I would use a JList or JTable swing widget outside the j3d window,
rather than trying to model and render a legend in j3d.

http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html

Has a good rundown on the basics of what I'm describing, though you'll have
to put significantly more effort into creating the CellRenderer and data
types stored within the list, than the simple example. You may want to get
to know Swing better if nothing I've describe here makes sense...
http://java.sun.com/products/jfc/tsc/articles/index.html

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

bayblade
Offline
Joined: 2006-02-17

Well, I'm going to assume you're comfortable with the actual ASSIGNEMNT of the colour, and are having trouble creating a ramp from red to blue. (a ramp is a single-axis colour lookup table). If you need to see how to assign colour to an object, there's a thousand examples around the web, including a couple earlier on this board.

This method will return an array of colours with 0 being red, and rampSize -1 being blue. (this is one less than 1 to rampSize, so for your example of 1 to 10, you index 0 to 9, if the user wants 100 colours, use a rampSize of 100, index from 0 to 99...you get the idea). Note that rampSize must be a positive number, this method doesn't check for negative sizes, and will throw an exception if you pass it one.

public static final Color3f[] getRedtoBlueRamp( int rampSize ) {
Color3f[] ramp = new Color3f[rampSize];
if ( rampSize == 1 ) {
ramp[0] = new Color3f( 0.5f, 0, 0.5f );
return ramp;
}

for ( int i = 0; i < rampSize; i++ ) {
float ratio = (float) i / (rampSize - 1);
ramp[i] = new Color3f( 1 - ratio, 0, ratio );
}

return ramp;

} // getRedtoBlueRamp

Naomi Greenberg

I didn't make myself very clear. For temperature, I want to map RGB values
to colors ranging from blue to green to yellow to orange to red (like on
contour and surface maps). This means that the ramping can't be done in
equal amounts of R, G, and B. My only idea is to create a lookup table with
these 5 colors, correspond it with my range of values and them interpolate
the RGB values between the 2 colors that my data falls within. Does this
make any sense? Is there any standard software around that does this (with
a nice legend, maybe?)

Thanks!

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

Well, ramps are usually stored as 256-color images at a 256x1 resolution,
and then they can be swapped in and out for different visual effects or
themes. You can always steal a spectrum ramp off the web somewhere and do
a lookup on your own image (this will limit you to a maximum rampSize of
your image resolution, but for most practical purposes this doesn't matter
much.

Programmatically, you can also take a simple route and traverse Hue across
the HSV color model rather than RGB, just remember H is cyclic, so you may
want to go from 0 (red)to about 0.66 (blue) and not go all the way to 1.0
(red) again. The ColorUtils class from j3d.org will help you here:
ftp://ftp.j3d.org/pub/code/j3d-org-src-0.6.zip.

You can also get really elaborate and model a spline through 3D color
space, but I think for most intents and purposes, the Hue traversal is what
you want.

Matt

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Matthew Hilliard

And without making things too much worse, I think our good friend Justin
who went to the effort of creating ColorUtils, may have used the domain
0..360 for Hue, instead of 0..1 You may want to investigate this, before
jumping in head first, of if anyone on the list would care to clarify...

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Justin Couch

Matthew Hilliard wrote:

> And without making things too much worse, I think our good friend Justin
> who went to the effort of creating ColorUtils, may have used the domain
> 0..360 for Hue, instead of 0..1 You may want to investigate this, before
> jumping in head first, of if anyone on the list would care to clarify...

Haven't looked at the code. No time right now - one day before large
project deadling. I remember vaguely somethig about this because it came
from Foley & van Damm. IIRC it was integer based colours, not floats.
Remind me mid next week to go look at this. I know the basic algorithm
is correct because the interpolations come out correctly for conformance
testing with the X3D/VRML spec requirements for HSV interpolatiion.

--
Justin Couch http://www.vlc.com.au/~justin/
Java Architect & Bit Twiddler http://www.yumetech.com/
Author, Java 3D FAQ Maintainer http://www.j3d.org/
-------------------------------------------------------------------
"Look through the lens, and the light breaks down into many lights.
Turn it or move it, and a new set of arrangements appears... is it
a single light or many lights, lights that one must know how to
distinguish, recognise and appreciate? Is it one light with many
frames or one frame for many lights?" -Subcomandante Marcos
-------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net