/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2007, by :
* Corporate:
* EADS Astrium
* Individual:
* Claude Cazenave
*
* $Id: PrimitiveNode.java,v 1.9 2008/12/17 22:37:53 cazenave Exp $
*
* Changes
* -------
* 10 janv. 08 : Initial public release
*
*/
package jsynoptic.plugins.java3d.tree;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.media.j3d.Appearance;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.event.UndoableEditEvent;
import javax.vecmath.Color3f;
import jsynoptic.plugins.java3d.edit.AddEdit;
import jsynoptic.plugins.java3d.panels.AxisDialog;
import jsynoptic.plugins.java3d.panels.DiscDialog;
import jsynoptic.plugins.java3d.panels.PointsDialog;
import jsynoptic.plugins.java3d.panels.PrimitiveDialog;
import jsynoptic.plugins.java3d.util.Geometries;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.Cylinder;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Sphere;
/**
* A Node for java3d Primitives : Cone, Cylinder, Cube and Sphere
*/
public class PrimitiveNode extends GroupNode {
/**
* Register nodes resources and actions
*/
static void loadResources(){
addResources("com.sun.j3d.utils.geometry.Cylinder", "Cylinder");
addResources("com.sun.j3d.utils.geometry.Box", "Cube");
addResources("com.sun.j3d.utils.geometry.Cone", "Cone");
addResources("com.sun.j3d.utils.geometry.Sphere", "Sphere");
addActions("AddPrimitive",
SphereAction.class,CubeAction.class,
CylinderAction.class,ConeAction.class,
DiscAction.class,QuadAction.class,TriangleAction.class,LineAction.class,
FrameAction.class,SolidFrameAction.class,AxisAction.class);
}
// required for dynamic node creation
public PrimitiveNode(Tree tree, Object graphObject, boolean getChildren) {
super(tree, graphObject, getChildren);
}
static class PrimitiveAction extends AbstractNodeAction {
protected final Class<? extends Primitive> _primitiveClass;
protected final String _title;
protected PrimitiveAction(Class<? extends Primitive> primitiveClass,String title){
_primitiveClass=primitiveClass;
_title=title;
}
@Override
public void actionPerformed(ActionEvent e) {
PrimitiveDialog d=new PrimitiveDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),
_primitiveClass, _title);
Primitive n=d.getResult();
if(n!=null){
GroupNode gn=(GroupNode)getNode();
gn.addChild(n);
AddEdit ae=new AddEdit(gn, n, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
}
static class SphereAction extends PrimitiveAction { public SphereAction(){super(Sphere.class,"Sphere");}} // TODO i18n
static class ConeAction extends PrimitiveAction { public ConeAction(){super(Cone.class,"Cone");}}
static class CubeAction extends PrimitiveAction { public CubeAction(){super(Box.class,"Box");}}
static class CylinderAction extends PrimitiveAction { public CylinderAction(){super(Cylinder.class,"Cylinder");}}
static class FrameAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
GroupNode gn=(GroupNode)getNode();
Group g=new Group();
// TODO i18n
g.setName("Frame");
float[] axis = makeAxis(0);
LineArray la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ColoringAttributes ca = new ColoringAttributes();
ca.setColor(0.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
Shape3D saxis = new Shape3D(la, a);
saxis.setName("X");
g.addChild(saxis);
// Y axis in green
axis = makeAxis(1);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(0.0f,1.0f,0.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
saxis.setName("Y");
g.addChild(saxis);
// Z axis in purple
axis = makeAxis(2);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(1.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
saxis.setName("Z");
g.addChild(saxis);
gn.addChild(g);
AddEdit ae=new AddEdit(gn, g, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
/**
* Creates lines and arrows to visualize the axis
* @return an array of line coordinates for the axis,
* composed of float numbers in the order (l1p1, l1p2, l2p1, l2p2...)
* with l and p the line and points, p made of 3 floats x y z
*/
public static float[] makeAxis(int n) {
switch (n) {
case 0:
return new float[] {
0, 0, 0, 1, 0, 0, // x line
0.1f, 0.9f, 0, 0, 1, 0, // y arrow 1
-0.1f, 0.9f, 0, 0, 1, 0, // y arrow 2
0.1f, 0, 0.9f, 0, 0, 1, // z arrow 1
-0.1f, 0, 0.9f, 0, 0, 1, // z arrow 2
};
case 1:
return new float[] {
0, 0, 0, 0, 1, 0, // y line
0, 0.1f, 0.9f, 0, 0, 1, // z arrow 3
0, -0.1f, 0.9f, 0, 0, 1, // z arrow 4
0.9f, 0.1f, 0, 1, 0, 0, // x arrow 1
0.9f, -0.1f, 0, 1, 0, 0, // x arrow 2
};
case 2:
return new float[] {
0, 0, 0, 0, 0, 1, // z line
0, 0.9f, 0.1f, 0, 1, 0, // y arrow 3
0, 0.9f, -0.1f, 0, 1, 0, // y arrow 4
0.9f, 0, 0.1f, 1, 0, 0, // x arrow 3
0.9f, 0, -0.1f, 1, 0, 0, // x arrow 4
};
}
return null;
}
static class SolidFrameAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
GroupNode gn=(GroupNode)getNode();
TransformGroup g=new TransformGroup();
// TODO i18n
g.setName("SolidFrame");
Transform3D nz=new Transform3D();
nz.rotZ(-Math.PI/2.);
TransformGroup tgx=new TransformGroup(nz);
tgx.setName("X");
makeSolidAxis(tgx, 1.f, 0.04f, 0.02f, 0.04f, Color.RED, Color.RED, 10);
g.addChild(tgx);
TransformGroup tgy=new TransformGroup(new Transform3D());
tgy.setName("Y");
makeSolidAxis(tgy, 1.f, 0.04f, 0.02f, 0.04f, Color.GREEN, Color.GREEN, 10);
g.addChild(tgy);
Transform3D px=new Transform3D();
px.rotX(Math.PI/2.);
TransformGroup tgz=new TransformGroup(px);
tgz.setName("Z");
makeSolidAxis(tgz, 1.f, 0.04f, 0.02f, 0.04f, Color.BLUE, Color.BLUE, 10);
g.addChild(tgz);
gn.addChild(g);
AddEdit ae=new AddEdit(gn, g, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
static class AxisAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
AxisDialog d=new AxisDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),"Axis"); // TODO i18n
AxisDialog.Result n=d.getResult();
if(n!=null){
GroupNode gn=(GroupNode)getNode();
TransformGroup g=new TransformGroup();
// TODO i18n
g.setName("Axis");
makeSolidAxis(g, n.height, n.arrowHeight, n.radius, n.arrowRadius, Color.WHITE, Color.WHITE, n.divisions);
gn.addChild(g);
AddEdit ae=new AddEdit(gn, g, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
}
/**
* Create a solid axis with the following parameters
* @param group the group where to add the created axis
* @param length the full axis length along the X axis
* @param arrowLength the arrow length (must be lower than length)
* @param radius the axis radius along the Y axis
* @param arrowRadius the arrow radius (should be greater than radius)
* @param color the axis color
* @param arrowColor the arrow color
* @param divisions number of divisions for primitives
*/
public static void makeSolidAxis(Group group, float length, float arrowLength,
float radius, float arrowRadius, Color color, Color arrowColor, int divisions) {
float l=length-arrowLength;
Shape3D cy= new Shape3D(Geometries.cylinder(radius, l-arrowLength, divisions));
group.addChild(cy);
Shape3D bcy= new Shape3D(Geometries.disc(radius, divisions,false,0.));
group.addChild(bcy);
Shape3D co= new Shape3D(Geometries.cone(arrowRadius, arrowLength, divisions,true,l-arrowLength));
group.addChild(co);
Shape3D bco= new Shape3D(Geometries.disc(arrowRadius, divisions,false,l-arrowLength));
group.addChild(bco);
Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f);
Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);
Appearance cya=new Appearance();
cya.setColoringAttributes(new ColoringAttributes(new Color3f(color),ColoringAttributes.SHADE_GOURAUD));
Material cym = new Material(aColor, eColor, new Color3f(color), sColor, 100.0f);
cym.setLightingEnable(true);
cya.setMaterial(cym);
cy.setAppearance(cya);
bcy.setAppearance(cya);
Appearance coa=new Appearance();
coa.setColoringAttributes(new ColoringAttributes(new Color3f(arrowColor),ColoringAttributes.SHADE_GOURAUD));
Material com = new Material(aColor, eColor, new Color3f(arrowColor), sColor, 100.0f);
com.setLightingEnable(true);
coa.setMaterial(com);
co.setAppearance(coa);
bco.setAppearance(coa);
}
static class DiscAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
DiscDialog d=new DiscDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),"Disc"); // TODO i18n
DiscDialog.Result n=d.getResult();
if(n!=null){
GroupNode gn=(GroupNode)getNode();
Shape3D sd= new Shape3D(Geometries.disc(n.radius, n.divisions,n.up,0.));
Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f);
Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);
Appearance cya=new Appearance();
cya.setColoringAttributes(new ColoringAttributes(new Color3f(Color.WHITE),ColoringAttributes.SHADE_GOURAUD));
cya.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0));
Material cym = new Material(aColor, eColor, new Color3f(Color.WHITE), sColor, 100.0f);
cym.setLightingEnable(true);
cya.setMaterial(cym);
sd.setAppearance(cya);
gn.addChild(sd);
AddEdit ae=new AddEdit(gn, sd, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
}
static class LineAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
PointsDialog d=new PointsDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),"Line",2); // TODO i18n
double[] v=d.getResult();
if(v!=null){
GroupNode gn=(GroupNode)getNode();
LineArray la = new LineArray(2, LineArray.COORDINATES);
la.setCoordinates(0,v);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ColoringAttributes ca = new ColoringAttributes();
ca.setColor(1.0f,1.0f,1.0f);
a.setColoringAttributes(ca);
Shape3D sd = new Shape3D(la, a);
gn.addChild(sd);
AddEdit ae=new AddEdit(gn, sd, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
}
static class TriangleAction extends AbstractNodeAction {
@Override
public void actionPerformed(ActionEvent e) {
PointsDialog d=new PointsDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),"Triangle",3); // TODO i18n
double[] v=d.getResult();
if(v!=null){
apply(v);
}
}
void apply(double[] v){
GroupNode gn=(GroupNode)getNode();
Shape3D sd= new Shape3D(Geometries.polygon(v));
Color3f aColor = new Color3f(0.1f, 0.1f, 0.1f);
Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f);
Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);
Appearance cya=new Appearance();
cya.setColoringAttributes(new ColoringAttributes(new Color3f(Color.WHITE),ColoringAttributes.SHADE_GOURAUD));
cya.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0));
Material cym = new Material(aColor, eColor, new Color3f(Color.WHITE), sColor, 100.0f);
cym.setLightingEnable(true);
cya.setMaterial(cym);
sd.setAppearance(cya);
gn.addChild(sd);
AddEdit ae=new AddEdit(gn, sd, null);
getNode().getTree().getUndoableEditListener().undoableEditHappened(
new UndoableEditEvent(this, ae));
getNode().refresh();
}
}
static class QuadAction extends TriangleAction {
@Override
public void actionPerformed(ActionEvent e) {
PointsDialog d=new PointsDialog(
javax.swing.SwingUtilities.getWindowAncestor( getNode().getTree()),
getLocation(),"Quadrangle",4); // TODO i18n
double[] v=d.getResult();
if(v!=null){
apply(v);
}
}
}
}