/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.portrayal3d.network;
import sim.portrayal3d.*;
import sim.portrayal.*;
import sim.util.*;
import java.awt.*;
import sim.field.network.*;
import javax.vecmath.*;
import javax.media.j3d.*;
/*
* A simple portrayal for edges in a network field.
*/
public class SimpleEdgePortrayal3D extends SimplePortrayal3D
{
Color fromColor;
Color toColor;
Color labelColor;
Font labelFont;
//Font3D labelFont3D; // only used if we're doing Text3D
boolean showLabels;
// A larger font size makes the label bigger but also uses much more memory
static final int FONT_SIZE = 18;
// A smaller scaling factor reduces the label size
static final double SCALING_MODIFIER = 1.0 / 5.0;
double labelScale = 1.0;
public double getLabelScale() { return labelScale; }
public void setLabelScale(double s) { labelScale = Math.abs(s); }
/** @deprecated */
public void setShowLabels(boolean val) { showLabels = val; }
/** @deprecated */
public boolean getShowLabels() { return showLabels; }
public SimpleEdgePortrayal3D()
{
this(Color.gray, Color.gray, Color.white, null);
}
public SimpleEdgePortrayal3D(Color edgeColor, Color labelColor)
{
this(edgeColor, edgeColor, labelColor, null);
}
public SimpleEdgePortrayal3D(Color edgeColor, Color labelColor, Font labelFont)
{
this(edgeColor, edgeColor, labelColor, labelFont);
}
public SimpleEdgePortrayal3D(Color fromColor, Color toColor, Color labelColor)
{
this(fromColor, toColor, labelColor, null);
}
/**
* If fromColor == toColor, one single color line will be drawn, and if
* labelColor is null, no label is drawn.
*/
public SimpleEdgePortrayal3D(Color fromColor, Color toColor, Color labelColor, Font labelFont)
{
this.fromColor = fromColor;
this.toColor = toColor;
this.labelColor = labelColor;
if (labelFont == null)
labelFont = new Font("SansSerif", Font.PLAIN, FONT_SIZE);
this.labelFont = labelFont;
//labelFont3D = new Font3D(labelFont, new FontExtrusion());
showLabels = (labelColor != null);
if (this.labelColor == null)
this.labelColor = Color.white; // just in case the user turns on labels again
}
Transform3D transformForOffset(double x, double y, double z)
{
Transform3D offset = new Transform3D();
offset.setTranslation(new Vector3d(x, y, z));
return offset;
}
/**
* Returns a name appropriate for the edge. By default, this returns
* (edge.info == null ? "" : "" + edge.info). Override this to make a more
* customized label to display for the edge on-screen.
*/
public String getLabel(Edge edge)
{
Object obj = edge.info;
if (obj == null)
return "";
return "" + obj;
}
double[] startPoint = new double[3];
double[] endPoint = new double[3];
double[] middlePoint = new double[3];
public TransformGroup getModel(Object object, TransformGroup j3dModel)
{
Double3D firstPoint;
Double3D secondPoint;
SpatialNetwork3D field;
LocationWrapper wrapper;
Transform3D trans = null;
wrapper = (LocationWrapper) object;
Edge edge = (Edge)(wrapper.getLocation());
field = (SpatialNetwork3D) wrapper.fieldPortrayal.getField();
secondPoint = field.getObjectLocation(edge.to());
firstPoint = field.getObjectLocation(edge.from());
startPoint[0] = firstPoint.x;
startPoint[1] = firstPoint.y;
startPoint[2] = firstPoint.z;
endPoint[0] = secondPoint.x;
endPoint[1] = secondPoint.y;
endPoint[2] = secondPoint.z;
middlePoint[0] = (secondPoint.x + firstPoint.x) / 2;
middlePoint[1] = (secondPoint.y + firstPoint.y) / 2;
middlePoint[2] = (secondPoint.z + firstPoint.z) / 2;
if (showLabels)
trans = transformForOffset(middlePoint[0], middlePoint[1], middlePoint[2]);
if (j3dModel == null)
{
// build the whole model from scratch
j3dModel = new TransformGroup();
j3dModel.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
LineArray lineGeometry1 = new LineArray(2, GeometryArray.COORDINATES);
lineGeometry1.setCoordinate(0, startPoint);
lineGeometry1.setCoordinate(1, middlePoint);
lineGeometry1.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
Shape3D lineShape1 = new Shape3D(lineGeometry1, SimplePortrayal3D.appearanceForColor(fromColor));
lineShape1.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
setPickableFlags(lineShape1);
lineShape1.setUserData(wrapper);
j3dModel.addChild(lineShape1);
LineArray lineGeometry2 = new LineArray(2, GeometryArray.COORDINATES);
lineGeometry2.setCoordinate(0, middlePoint);
lineGeometry2.setCoordinate(1, endPoint);
lineGeometry2.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
Shape3D lineShape2 = new Shape3D(lineGeometry2, SimplePortrayal3D.appearanceForColor(toColor));
lineShape2.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
setPickableFlags(lineShape2);
lineShape2.setUserData(wrapper);
j3dModel.addChild(lineShape2);
// draw the edge labels if the user wants
if (showLabels)
{
String str = getLabel(edge);
com.sun.j3d.utils.geometry.Text2D text = new com.sun.j3d.utils.geometry.Text2D(
str, new Color3f(labelColor), labelFont.getFamily(),
labelFont.getSize(), labelFont.getStyle());
text.setRectangleScaleFactor((float)(labelScale * SCALING_MODIFIER));
//text = new Shape3D(new Text3D(labelFont3D, ""));
OrientedShape3D o3d = new OrientedShape3D(text.getGeometry(),
text.getAppearance(),
OrientedShape3D.ROTATE_ABOUT_POINT,
new Point3f(0, 0, 0));
o3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); // may need to change the appearance (see below)
o3d.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); // may need to change the geometry (see below)
o3d.clearCapabilityIsFrequent(Shape3D.ALLOW_APPEARANCE_WRITE);
o3d.clearCapabilityIsFrequent(Shape3D.ALLOW_GEOMETRY_WRITE);
// make the offset TransformGroup
TransformGroup o = new TransformGroup();
o.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
o.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
o.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
o.clearCapabilityIsFrequent(TransformGroup.ALLOW_CHILDREN_READ);
o.setTransform(trans);
o.setUserData(str);
// the label shouldn't be pickable -- we'll turn this off in the
// TransformGroup
clearPickableFlags(o);
o.addChild(o3d); // Add label to the offset TransformGroup
j3dModel.addChild(o);
}
}
else
{
Shape3D shape = (Shape3D)j3dModel.getChild(0);
LineArray geo = (LineArray)shape.getGeometry();
geo.setCoordinate(0, startPoint);
geo.setCoordinate(1, middlePoint);
shape = (Shape3D)j3dModel.getChild(1);
geo = (LineArray)shape.getGeometry();
geo.setCoordinate(0, startPoint);
geo.setCoordinate(1, endPoint);
if (showLabels)
{
TransformGroup tg = (TransformGroup) j3dModel.getChild(2);
String str = getLabel(edge);
// see if the label has changed?
if (!tg.getUserData().equals(str))
{
// make the text again
com.sun.j3d.utils.geometry.Text2D text = new com.sun.j3d.utils.geometry.Text2D(
str, new Color3f(labelColor),
labelFont.getFamily(), labelFont.getSize(),
labelFont.getStyle());
text.setRectangleScaleFactor((float)(labelScale * SCALING_MODIFIER));
//Shape3D text = new Shape3D(new Text3D(labelFont3D, str));
// Grab the OrientedShape3D
OrientedShape3D o3d = (OrientedShape3D) (tg.getChild(0));
// update its geometry and appearance to reflect the new text.
o3d.setGeometry(text.getGeometry());
o3d.setAppearance(text.getAppearance());
// update user data to reflect the new text
tg.setUserData(str);
}
// update the position of the text
tg.setTransform(trans);
}
}
return j3dModel;
}
public String getName(LocationWrapper wrapper)
{
// indicate it's an edge
return "Edge: " + super.getName(wrapper);
}
}