//
// ImageRendererJ3D.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.bom;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.media.j3d.BranchGroup;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import visad.AnimationControl;
import visad.BadMappingException;
import visad.CoordinateSystem;
import visad.CachingCoordinateSystem;
import visad.InverseLinearScaledCS;
import visad.Data;
import visad.DataDisplayLink;
import visad.DataReference;
import visad.DataReferenceImpl;
import visad.Display;
import visad.DisplayException;
import visad.DisplayImpl;
import visad.DisplayRealType;
import visad.DisplayTupleType;
import visad.Field;
import visad.FieldImpl;
import visad.FlatField;
import visad.FunctionType;
import visad.Gridded1DDoubleSet;
import visad.MathType;
import visad.RealTupleType;
import visad.RealType;
import visad.ScalarMap;
import visad.ScalarType;
import visad.Set;
import visad.ShadowType;
import visad.ShadowRealType;
import visad.ShadowRealTupleType;
import visad.ShadowFunctionOrSetType;
import visad.VisADError;
import visad.VisADException;
import visad.data.netcdf.Plain;
import visad.java3d.DefaultRendererJ3D;
import visad.java3d.DisplayImplJ3D;
import visad.java3d.ShadowTypeJ3D;
import visad.java3d.VisADBranchGroup;
import visad.java3d.VisADImageNode;
import visad.util.Delay;
/**
ImageRendererJ3D is the VisAD class for fast loading of images
and image sequences under Java3D.
WARNING - when reUseFrames is true during doTransform()
ImageRendererJ3D makes these assumptions:
1. That the images in a new time sequence are identical to
any images at the same time in a previous sequence.
2. That the image sequence defines the entire animation
sampling.<P>
*/
public class ImageRendererJ3D extends DefaultRendererJ3D {
// FOR DEVELOPMENT PURPOSES //////////////////////////////////
private static final int DEF_IMG_TYPE;
//GEOMETRY/COLORBYTE REUSE LOGIC VARIABLES (STARTS HERE)
private int last_curve_size = -1;
private float last_zaxis_value = Float.NaN;
private float last_alpha_value = Float.NaN;
private long last_data_hash_code = -1;
private boolean adjust_projection_seam = false; //27FEB2012: Projection Seam Change Bug Fix
//GEOMETRY/COLORBYTE REUSE LOGIC VARIABLES (ENDS HERE)
static {
String val = System.getProperty("visad.java3d.8bit", "false");
if (Boolean.parseBoolean(val)) {
DEF_IMG_TYPE = BufferedImage.TYPE_BYTE_GRAY;
System.err.println("WARN: 8bit enabled via system property");
} else {
DEF_IMG_TYPE = BufferedImage.TYPE_4BYTE_ABGR;
}
}
//////////////////////////////////////////////////////////////
// MathTypes that data must equalsExceptNames()
private static MathType image_sequence_type, image_type;
private static MathType image_sequence_type2, image_type2;
private static MathType image_sequence_type3, image_type3;
// initialize above MathTypes
static {
try {
image_type = MathType.stringToType(
"((ImageElement, ImageLine) -> ImageValue)");
image_sequence_type = new FunctionType(RealType.Time, image_type);
image_type2 = MathType.stringToType(
"((ImageElement, ImageLine) -> (ImageValue))");
image_sequence_type2 = new FunctionType(RealType.Time, image_type2);
image_type3 = MathType.stringToType(
"((ImageElement, ImageLine) -> (Red, Green, Blue))");
image_sequence_type3 = new FunctionType(RealType.Time, image_type3);
}
catch (VisADException e) {
throw new VisADError(e.getMessage());
}
}
/** determine whether the given MathType is usable with ImageRendererJ3D */
public static boolean isImageType(MathType type) {
return (image_sequence_type.equalsExceptName(type) ||
image_sequence_type2.equalsExceptName(type) ||
image_sequence_type3.equalsExceptName(type) ||
image_type.equalsExceptName(type) ||
image_type2.equalsExceptName(type) ||
image_type3.equalsExceptName(type));
}
/** @deprecated Use isRendererUsable(MathType, ScalarMap[]) instead. */
public static void verifyImageRendererUsable(MathType type, ScalarMap[] maps)
throws VisADException
{
isRendererUsable(type, maps);
}
/** determine whether the given MathType and collection of ScalarMaps
meets the criteria to use ImageRendererJ3D. Throw a VisADException
if ImageRenderer cannot be used, otherwise return true. */
public static boolean isRendererUsable(MathType type, ScalarMap[] maps)
throws VisADException
{
RealType time = null;
RealTupleType domain = null;
RealTupleType range = null;
RealType x = null, y = null;
RealType rx = null, ry = null; // WLH 19 July 2000
RealType r = null, g = null, b = null;
RealType rgb = null;
// must be a function
if (!(type instanceof FunctionType)) {
throw new VisADException("Not a FunctionType");
}
FunctionType function = (FunctionType) type;
RealTupleType functionD = function.getDomain();
MathType functionR = function.getRange();
// time function
if (function.equalsExceptName(image_sequence_type) ||
function.equalsExceptName(image_sequence_type2) ||
function.equalsExceptName(image_sequence_type3))
{
// strip off time RealType
time = (RealType) functionD.getComponent(0);
function = (FunctionType) functionR;
functionD = function.getDomain();
functionR = function.getRange();
}
// ((ImageLine, ImageElement) -> ImageValue)
// ((ImageLine, ImageElement) -> (ImageValue))
// ((ImageLine, ImageElement) -> (Red, Green, Blue))
if (function.equalsExceptName(image_type) ||
function.equalsExceptName(image_type2) ||
function.equalsExceptName(image_type3)) {
domain = function.getDomain();
MathType rt = function.getRange();
if (rt instanceof RealType) {
range = new RealTupleType((RealType) rt);
}
else if (rt instanceof RealTupleType) {
range = (RealTupleType) rt;
}
else {
// illegal MathType
throw new VisADException("Illegal RangeType");
}
}
else {
// illegal MathType
throw new VisADException("Illegal MathType");
}
// extract x and y from domain
x = (RealType) domain.getComponent(0);
y = (RealType) domain.getComponent(1);
// WLH 19 July 2000
CoordinateSystem cs = domain.getCoordinateSystem();
if (cs != null) {
RealTupleType rxy = cs.getReference();
rx = (RealType) rxy.getComponent(0);
ry = (RealType) rxy.getComponent(1);
}
// extract colors from range
int dim = range.getDimension();
if (dim == 1) rgb = (RealType) range.getComponent(0);
else { // dim == 3
r = (RealType) range.getComponent(0);
g = (RealType) range.getComponent(1);
b = (RealType) range.getComponent(2);
}
// verify that collection of ScalarMaps is legal
boolean btime = (time == null);
boolean bx = false, by = false;
boolean brx = false, bry = false; // WLH 19 July 2000
boolean br = false, bg = false, bb = false;
boolean dbr = false, dbg = false, dbb = false;
Boolean latlon = null;
DisplayRealType spatial = null;
for (int i=0; i<maps.length; i++) {
ScalarMap m = maps[i];
ScalarType md = m.getScalar();
DisplayRealType mr = m.getDisplayScalar();
boolean ddt = md.equals(time);
boolean ddx = md.equals(x);
boolean ddy = md.equals(y);
boolean ddrx = md.equals(rx);
boolean ddry = md.equals(ry);
boolean ddr = md.equals(r);
boolean ddg = md.equals(g);
boolean ddb = md.equals(b);
boolean ddrgb = md.equals(rgb);
// animation mapping
if (ddt) {
if (btime) throw new VisADException("Multiple Time mappings");
if (!mr.equals(Display.Animation)) {
throw new VisADException(
"Time mapped to something other than Animation");
}
btime = true;
}
// spatial mapping
else if (ddx || ddy || ddrx || ddry) {
if (ddx && bx || ddy && by || ddrx && brx || ddry && bry) {
throw new VisADException("Duplicate spatial mappings");
}
if (((ddx || ddy) && (brx || bry)) ||
((ddrx || ddry) && (bx || by))) {
throw new VisADException("reference and non-reference spatial mappings");
}
RealType q = (ddx ? x : null);
if (ddy) q = y;
if (ddrx) q = rx;
if (ddry) q = ry;
boolean ll;
if (mr.equals(Display.XAxis) || mr.equals(Display.YAxis) ||
mr.equals(Display.ZAxis))
{
ll = false;
}
else if (mr.equals(Display.Latitude) || mr.equals(Display.Longitude) ||
mr.equals(Display.Radius))
{
ll = true;
}
else throw new VisADException("Illegal domain mapping");
if (latlon == null) {
latlon = new Boolean(ll);
spatial = mr;
}
else if (latlon.booleanValue() != ll) {
throw new VisADException("Multiple spatial coordinate systems");
}
// two mappings to the same spatial DisplayRealType are not allowed
else if (spatial == mr) {
throw new VisADException(
"Multiple mappings to the same spatial DisplayRealType");
}
if (ddx) bx = true;
else if (ddy) by = true;
else if (ddrx) brx = true;
else if (ddry) bry = true;
}
// rgb mapping
else if (ddrgb) {
if (br || bg || bb) {
throw new VisADException("Duplicate color mappings");
}
if (rgb == null ||
!(mr.equals(Display.RGB) || mr.equals(Display.RGBA))) {
throw new VisADException("Illegal RGB/RGBA mapping");
}
dbr = dbg = dbb = true;
br = bg = bb = true;
}
// color mapping
else if (ddr || ddg || ddb) {
if (rgb != null) throw new VisADException("Illegal RGB mapping");
RealType q = (ddr ? r : (ddg ? g : b));
if (mr.equals(Display.Red)) dbr = true;
else if (mr.equals(Display.Green)) dbg = true;
else if (mr.equals(Display.Blue)) dbb = true;
else throw new VisADException("Illegal color mapping");
if (ddr) br = true;
else if (ddg) bg = true;
else bb = true;
}
// illegal ScalarMap involving this MathType
else if (ddt || ddx || ddy || ddrx || ddry ||
ddr || ddg || ddb || ddrgb)
{
throw new VisADException("Illegal mapping: " + m);
}
}
// return true if all conditions for ImageRendererJ3D are met
if (!(btime && ((bx && by) || (brx && bry)) &&
br && bg && bb && dbr && dbg && dbb)) {
throw new VisADException("Insufficient mappings");
}
return true;
}
// flag to indicate:
// 1. That the images in a new time sequence are identical to
// any images at the same time in a previous sequence.
// 2. That the image sequence defines the entire animation
// sampling.<P>
private boolean reUseFrames = false;
private int suggestedBufImgType = DEF_IMG_TYPE;
private boolean setSetOnReUseFrames = true;
private VisADImageNode imagesNode = null;
private boolean lastByRef = false;
public static boolean isByRefUsable(DataDisplayLink link, ShadowType shadow) throws VisADException, RemoteException {
ShadowFunctionOrSetType shadowType = (ShadowFunctionOrSetType) shadow.getAdaptedShadowType();
CoordinateSystem dataCoordinateSystem = null;
FlatField fltField = null;
int num_images = 1;
FieldImpl field = (FieldImpl) link.getData();
if (!(field instanceof FlatField)) {
num_images = field.getDomainSet().getLength();
if (1 == num_images) { //If there is a single image in the animation dont do anything, simply return true
return true;
}
shadowType = (ShadowFunctionOrSetType) shadowType.getRange();
fltField = (FlatField) field.getSample(0);
dataCoordinateSystem = fltField.getDomainCoordinateSystem();
} else {
dataCoordinateSystem = ((FlatField)field).getDomainCoordinateSystem();
return true;
}
// cs might be cached
if (dataCoordinateSystem instanceof CachingCoordinateSystem) {
dataCoordinateSystem = ((CachingCoordinateSystem) dataCoordinateSystem).getCachedCoordinateSystem();
}
ShadowRealType[] DomainComponents = shadowType.getDomainComponents();
ShadowRealTupleType Domain = shadowType.getDomain();
ShadowRealTupleType domain_reference = Domain.getReference();
ShadowRealType[] DC = DomainComponents;
if (domain_reference != null &&
domain_reference.getMappedDisplayScalar()) {
DC = shadowType.getDomainReferenceComponents();
}
DisplayTupleType spatial_tuple = null;
for (int i=0; i<DC.length; i++) {
java.util.Enumeration maps = DC[i].getSelectedMapVector().elements();
ScalarMap map = (ScalarMap) maps.nextElement();
DisplayRealType real = map.getDisplayScalar();
spatial_tuple = real.getTuple();
}
CoordinateSystem coord = spatial_tuple.getCoordinateSystem();
if (coord instanceof CachingCoordinateSystem) {
coord = ((CachingCoordinateSystem)coord).getCachedCoordinateSystem();
}
boolean useLinearTexture = false;
if (coord instanceof InverseLinearScaledCS) {
InverseLinearScaledCS invCS = (InverseLinearScaledCS)coord;
useLinearTexture = (invCS.getInvertedCoordinateSystem()).equals(dataCoordinateSystem);
}
/** if useLinearTexture is true at this point, it's true for the first image of a sequence with numimages > 1. We'll
have to assume that byRef will apply until below is resolved.
*/
/** more consideration/work needed here. CoordinateSystems might be equal even if they aren't the same transform (i,j) -> (lon,lat)
if (!useLinearTexture) { //If DisplayCoordinateSystem != DataCoordinateSystem
if (num_images > 1) { //Its an animation
int lengths[] = ((visad.GriddedSet) fltField.getDomainSet()).getLengths();
int data_width = lengths[0];
int data_height = lengths[1];
for (int i = 1; i < num_images; i++) {//Playing safe: go down the full sequence to find if the full set is Geostaionary or NOT
FlatField ff = (FlatField) field.getSample(i); //Quicker Approach would be to just compare only the first two images in the sequence. But that may not be safe.
CoordinateSystem dcs = ff.getDomainCoordinateSystem();
// dcs might be cached
if (dcs instanceof CachingCoordinateSystem) {
dcs = ((CachingCoordinateSystem) dcs).getCachedCoordinateSystem();
}
int[] lens = ((visad.GriddedSet) ff.getDomainSet()).getLengths();
if (lens[0] != data_width || lens[1] != data_height || ( (dcs != null) && (dataCoordinateSystem != null) && !dcs.equals(dataCoordinateSystem))) {
useLinearTexture = false;
break;
}
}
}
}
*/
return useLinearTexture;
}
// factory for ShadowFunctionType that defines unique behavior
// for ImageRendererJ3D
public ShadowType makeShadowFunctionType(
FunctionType type, DataDisplayLink link, ShadowType parent)
throws VisADException, RemoteException {
return new ShadowImageFunctionTypeJ3D(type, link, parent);
}
/**
* Toggle the re-using of frames when a new image or set of images
* is set in the datareference.<P>
* <B>WARNING</B> - when reUseFrames is true during doTransform()
* ImageRendererJ3D makes these assumptions:
* <OL>
* <LI>That the images in a new time sequence are identical to
* any images at the same time in a previous sequence.
* <LI>That the image sequence defines the entire animation
* sampling.<P>
* </OL>
*/
public void setReUseFrames(boolean reuse) {
reUseFrames = reuse;
}
/**
* Suggest to the underlying shadow type the buffered image type
* to use.
*
* <b>Experimental</b>: This may changed or removed in future releases.
*/
public void suggestBufImageType(int imageType) {
switch (imageType) {
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_BYTE_GRAY:
// case BufferedImage.TYPE_USHORT_GRAY:
break;
default:
throw new IllegalArgumentException("unsupported image type");
}
this.suggestedBufImgType = imageType;
}
/**
* Get the image type.
* @return The buffered image type used to render the image.
*/
int getSuggestedBufImageType() {
return suggestedBufImgType;
}
public void setImageNode(VisADImageNode node) {
this.imagesNode = node;
}
public VisADImageNode getImageNode() {
return this.imagesNode;
}
/**
* Turn on the reusing of frames
* @deprecated - use setReUseFrames(boolean reuse)
*/
public void setReUseFrames() {
setReUseFrames(true);
}
public boolean getReUseFrames() {
return reUseFrames;
}
public void setSetSetOnReUseFrames(boolean ss) {
setSetOnReUseFrames = ss;
}
public boolean getSetSetOnReUseFrames() {
return setSetOnReUseFrames;
}
// logic to allow ShadowImageFunctionTypeJ3D to 'mark' missing frames
private VisADBranchGroup vbranch = null;
public void clearScene() {
vbranch = null;
super.clearScene();
}
void setVisADBranch(VisADBranchGroup branch) {
vbranch = branch;
}
void markMissingVisADBranch() {
if (vbranch != null) vbranch.scratchTime();
}
// end of logic to allow ShadowImageFunctionTypeJ3D to 'mark' missing frames
public BranchGroup doTransform() throws VisADException, RemoteException {
DataDisplayLink[] Links = getLinks();
if (Links == null || Links.length == 0) {
return null;
}
DataDisplayLink link = Links[0];
ShadowTypeJ3D type = (ShadowTypeJ3D) link.getShadow();
boolean doByRef = false;
if (isByRefUsable(link, type) && ShadowType.byReference) {
doByRef = true;
type = new ShadowImageByRefFunctionTypeJ3D(link.getData().getType(), link, null,
((ShadowFunctionOrSetType)type.getAdaptedShadowType()).getInheritedValues(),
(ShadowFunctionOrSetType)type.getAdaptedShadowType(), type.getLevelOfDifficulty());
}
BranchGroup branch = null;
if ((lastByRef && doByRef) || (!lastByRef && !doByRef)) {
branch = getBranch();
}
lastByRef = doByRef;
if (branch == null) {
branch = new BranchGroup();
branch.setCapability(BranchGroup.ALLOW_DETACH);
branch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
branch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
branch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
last_curve_size = -1;
last_zaxis_value = Float.NaN;
last_alpha_value = Float.NaN;
last_data_hash_code = -1;
adjust_projection_seam = false; //27FEB2012: Projection Seam Change Bug Fix
}
// initialize valueArray to missing
int valueArrayLength = getDisplay().getValueArrayLength();
float[] valueArray = new float[valueArrayLength];
for (int i=0; i<valueArrayLength; i++) {
valueArray[i] = Float.NaN;
}
Data data;
try {
data = link.getData();
} catch (RemoteException re) {
if (visad.collab.CollabUtil.isDisconnectException(re)) {
getDisplay().connectionFailed(this, link);
removeLink(link);
return null;
}
throw re;
}
if (data == null) {
branch = null;
addException(
new DisplayException("Data is null: DefaultRendererJ3D.doTransform"));
}
else {
// check MathType of non-null data, to make sure it is a single-band
// image or a sequence of single-band images
MathType mtype = link.getType();
if (!isImageType(mtype)) {
throw new BadMappingException("must be image or image sequence");
}
link.start_time = System.currentTimeMillis();
link.time_flag = false;
vbranch = null;
// transform data into a depiction under branch
long t1 = System.currentTimeMillis();
try {
if (type instanceof ShadowImageByRefFunctionTypeJ3D) { //GEOMETRY/COLORBYTE REUSE LOGIC Only for ByRef for Time being
if (checkAction()) { //This generally decides whether at all retransformation is required or not.
type.doTransform(branch, data, valueArray,
link.getDefaultValues(), this);
}
} else { //Not byRef (ShadowImageFunctionTypeJ3D)
type.doTransform(branch, data, valueArray,
link.getDefaultValues(), this);
}
} catch (RemoteException re) {
if (visad.collab.CollabUtil.isDisconnectException(re)) {
getDisplay().connectionFailed(this, link);
removeLink(link);
return null;
}
throw re;
}
long t2 = System.currentTimeMillis();
//System.err.println("Time taken:" + (t2-t1));
}
link.clearData();
return branch;
}
public Object clone() {
return new ImageRendererJ3D();
}
/** run 'java visad.bom.ImageRendererJ3D len step'
to test animation behavior of ImageRendererJ3D
renders a loop of len at step ms per frame
then updates loop by deleting first time and adding a new last time */
public static void main(String args[])
throws VisADException, RemoteException, IOException {
int step = 1000;
int len = 3;
if (args.length > 0) {
try {
len = Integer.parseInt(args[0]);
}
catch(NumberFormatException e) {
len = 3;
}
}
if (len < 1) len = 1;
if (args.length > 1) {
try {
step = Integer.parseInt(args[1]);
}
catch(NumberFormatException e) {
step = 1000;
}
}
if (step < 1) step = 1;
// create a netCDF reader
Plain plain = new Plain();
// open a netCDF file containing an image sequence and adapt
// it to a Field Data object
Field raw_image_sequence = null;
try {
// raw_image_sequence = (Field) plain.open("images256x256.nc");
raw_image_sequence = (Field) plain.open("images.nc");
}
catch (IOException exc) {
String s = "To run this example, the images.nc file must be "
+"present in\nthe current directory."
+"You can obtain this file from:\n"
+" ftp://www.ssec.wisc.edu/pub/visad-2.0/images.nc.Z";
System.out.println(s);
System.exit(0);
}
// just take first half of raw_image_sequence
FunctionType image_sequence_type =
(FunctionType) raw_image_sequence.getType();
Set raw_set = raw_image_sequence.getDomainSet();
float[][] raw_times = raw_set.getSamples();
int raw_len = raw_times[0].length;
if (raw_len != 4) {
throw new VisADException("wrong number of images in sequence");
}
float raw_span = (4.0f / 3.0f) * (raw_times[0][3] - raw_times[0][0]);
double[][] times = new double[1][len];
for (int i=0; i<len; i++) {
times[0][i] = raw_times[0][i % raw_len] + raw_span * (i / raw_len);
}
Gridded1DDoubleSet set =
new Gridded1DDoubleSet(raw_set.getType(), times, len);
Field image_sequence = new FieldImpl(image_sequence_type, set);
for (int i=0; i<len; i++) {
image_sequence.setSample(i, raw_image_sequence.getSample(i % raw_len));
}
// create a DataReference for image sequence
final DataReference image_ref = new DataReferenceImpl("image");
image_ref.setData(image_sequence);
// create a Display using Java3D
DisplayImpl display = new DisplayImplJ3D("image display");
// extract the type of image and use
// it to determine how images are displayed
FunctionType image_type =
(FunctionType) image_sequence_type.getRange();
RealTupleType domain_type = image_type.getDomain();
// map image coordinates to display coordinates
display.addMap(new ScalarMap((RealType) domain_type.getComponent(0),
Display.XAxis));
display.addMap(new ScalarMap((RealType) domain_type.getComponent(1),
Display.YAxis));
// map image brightness values to RGB (default is grey scale)
display.addMap(new ScalarMap((RealType) image_type.getRange(),
Display.RGB));
RealType hour_type =
(RealType) image_sequence_type.getDomain().getComponent(0);
ScalarMap animation_map = new ScalarMap(hour_type, Display.Animation);
display.addMap(animation_map);
AnimationControl animation_control =
(AnimationControl) animation_map.getControl();
animation_control.setStep(step);
animation_control.setOn(true);
/*
// link the Display to image_ref
ImageRendererJ3D renderer = new ImageRendererJ3D();
display.addReferences(renderer, image_ref);
// display.addReference(image_ref);
*/
// create JFrame (i.e., a window) for display and slider
JFrame frame = new JFrame("ImageRendererJ3D test");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
// create JPanel in JFrame
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
frame.getContentPane().add(panel);
// add display to JPanel
panel.add(display.getComponent());
// set size of JFrame and make it visible
frame.setSize(500, 500);
frame.setVisible(true);
System.out.println("first animation sequence");
// link the Display to image_ref
ImageRendererJ3D renderer = new ImageRendererJ3D();
display.addReferences(renderer, image_ref);
// display.addReference(image_ref);
// wait 4 * len seconds
new Delay(len * 4000);
// substitute a new image sequence for the old one
for (int i=0; i<len; i++) {
times[0][i] =
raw_times[0][(i + 1) % raw_len] + raw_span * ((i + 1) / raw_len);
}
set = new Gridded1DDoubleSet(raw_set.getType(), times, len);
FieldImpl new_image_sequence = new FieldImpl(image_sequence_type, set);
for (int i=0; i<len; i++) {
new_image_sequence.setSample(i,
raw_image_sequence.getSample((i + 1) % raw_len));
}
System.out.println("second animation sequence");
// tell renderer to resue frames in its scene graph
renderer.setReUseFrames(true);
image_ref.setData(new_image_sequence);
}
//GEOMETRY/COLORBYTE REUSE UTILITY METHODS (STARTS HERE)
public int getLastCurveSize() {
return last_curve_size;
}
public void setLastCurveSize(int csize) {
last_curve_size = csize;
}
public float getLastZAxisValue() {
return last_zaxis_value;
}
public void setLastZAxisValue(float zaxis_value) {
last_zaxis_value = zaxis_value;
}
public float getLastAlphaValue() {
return last_alpha_value;
}
public void setLastAlphaValue(float alpha) {
last_alpha_value = alpha;
}
public long getLastDataHashCode() {
return last_data_hash_code;
}
public void setLastDataHashCode(long lastdata_hashcode) {
last_data_hash_code = lastdata_hashcode;
}
//27FEB2012: Projection Seam Change Bug Fix (starts here)
public boolean getLastAdjustProjectionSeam() {
return adjust_projection_seam;
}
public void setLastAdjustProjectionSeam(boolean adjust) {
adjust_projection_seam = adjust;
}
//27FEB2012: Projection Seam Change Bug Fix (ends here)
//GEOMETRY/COLORBYTE REUSE UTILITY METHODS (ENDS HERE)
}