001: /*
002: * $Header: /cvs/j3dfly/J3dEditor/src/org/jdesktop/j3dedit/scenegrapheditor/visualtools/ShowBoundsBehavior.java,v 1.1 2005/04/20 22:21:30 paulby Exp $
003: *
004: * Sun Public License Notice
005: *
006: * The contents of this file are subject to the Sun Public License Version
007: * 1.0 (the "License"). You may not use this file except in compliance with
008: * the License. A copy of the License is available at http://www.sun.com/
009: *
010: * The Original Code is the Java 3D(tm) Scene Graph Editor.
011: * The Initial Developer of the Original Code is Paul Byrne.
012: * Portions created by Paul Byrne are Copyright (C) 2002.
013: * All Rights Reserved.
014: *
015: * Contributor(s): Paul Byrne.
016: *
017: **/
018: package org.jdesktop.j3dedit.scenegrapheditor.visualtools;
019:
020: import java.util.ArrayList;
021: import java.util.Enumeration;
022: import javax.media.j3d.*;
023: import javax.vecmath.Point3d;
024: import javax.vecmath.Vector3f;
025: import javax.vecmath.Vector3d;
026: import com.sun.j3d.utils.geometry.Primitive;
027: import com.sun.j3d.utils.geometry.Sphere;
028: import com.sun.j3d.utils.geometry.Box;
029:
030: /**
031: * This behavior will display the bounds (using getBounds) on each
032: * Java3D Node registered with it.
033: */
034: public class ShowBoundsBehavior extends Behavior {
035:
036: public final static Integer NODE_BOUNDS = new Integer(1);
037: public final static Integer SCHEDULING_BOUNDS = new Integer(2);
038: public final static Integer INFLUENCING_BOUNDS = new Integer(3);
039:
040: WakeupOnElapsedFrames frameCondition;
041: WakeupOnBehaviorPost waitCondition;
042: WakeupCondition currentCondition;
043: ArrayList nodes = new ArrayList();
044: ArrayList bounds = new ArrayList();
045: ArrayList transforms = new ArrayList();
046: ArrayList boundsType = new ArrayList();
047: Switch root = new Switch();
048: boolean newNode = false;
049:
050: TransformGroup testtg;
051: Sphere tests;
052: Shape3D shp;
053:
054: private Transform3D tmpTransform = new Transform3D();
055:
056: public ShowBoundsBehavior(BranchGroup parent) {
057: super ();
058: root.setCapability(Switch.ALLOW_CHILDREN_READ);
059: root.setCapability(Switch.ALLOW_CHILDREN_WRITE);
060: root.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
061: root.setWhichChild(Switch.CHILD_ALL);
062: parent.addChild(root);
063: parent.addChild(this );
064:
065: this .setSchedulingBounds(new BoundingSphere(new Point3d(),
066: Double.POSITIVE_INFINITY));
067:
068: frameCondition = new WakeupOnElapsedFrames(0, true);
069: waitCondition = new WakeupOnBehaviorPost(this , 1);
070: currentCondition = waitCondition;
071: }
072:
073: /**
074: * Add node to the list of nodes which will have their bounds displayed
075: * This method sets the ALLOW_BOUNDS_READ capability bit on node
076: */
077: public void showBounds(Node node) {
078: node.setCapability(Node.ALLOW_BOUNDS_READ);
079: node.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
080: if (node instanceof TransformGroup)
081: node.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
082: nodes.add(node);
083: bounds.add(node.getBounds());
084: boundsType.add(NODE_BOUNDS);
085: root.addChild(drawBounds(node, node.getBounds(), -1));
086: newNode = true;
087:
088: currentCondition = frameCondition;
089: postId(1);
090: }
091:
092: public void showSchedulingBounds(Node node) {
093: Bounds schedBounds = null;
094:
095: if (node instanceof Behavior || node instanceof Sound) {
096:
097: if (node instanceof Sound) {
098: node.setCapability(Sound.ALLOW_SCHEDULING_BOUNDS_READ);
099: schedBounds = ((Sound) node).getSchedulingBounds();
100: } else if (node instanceof Behavior) {
101: //node.setCapability( Behavior.ALLOW_SCHEDULING_BOUNDS_READ );
102: schedBounds = ((Behavior) node).getSchedulingBounds();
103: }
104:
105: node.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
106: nodes.add(node);
107: bounds.add(schedBounds);
108: boundsType.add(SCHEDULING_BOUNDS);
109: root.addChild(drawBounds(node, schedBounds, -1));
110: newNode = true;
111:
112: currentCondition = frameCondition;
113: postId(1);
114:
115: } else
116: throw new RuntimeException(node
117: + " not supported in showSchedulingBounds");
118:
119: }
120:
121: public void showInfluencingBounds(Node node) {
122: if (node instanceof Light || node instanceof Fog) {
123:
124: throw new RuntimeException("Not Implemented");
125: } else
126: throw new RuntimeException(node
127: + " not supported in showInfluencingBounds");
128: }
129:
130: /**
131: * Remove node from the bounds being displayed
132: */
133: public void hideBounds(Node node, Integer type) {
134: int i = -1;
135:
136: for (int j = 0; j < nodes.size() && i == -1; j++)
137: if (nodes.get(j) == node && boundsType.get(j) == type)
138: i = j;
139:
140: if (i == -1) {
141: System.out.println("WARNING - error removing bounds");
142: return;
143: }
144:
145: nodes.remove(i);
146: bounds.remove(i);
147: boundsType.remove(i);
148: root.removeChild(i);
149: }
150:
151: /**
152: * Stop displaying and remove all references to existing bounds
153: */
154: public void removeAllBounds() {
155: nodes.clear();
156: bounds.clear();
157: while (root.numChildren() > 0)
158: root.removeChild(0);
159: }
160:
161: public void initialize() {
162:
163: wakeupOn(currentCondition);
164: }
165:
166: public void processStimulus(Enumeration criteria) {
167: Bounds bnds;
168: Node node;
169: Integer type;
170: Transform3D nodeTrans = new Transform3D();
171: Transform3D local2vw = new Transform3D();
172: TransformGroup transform;
173: Bounds newBounds = null;
174:
175: for (int i = 0; i < nodes.size(); i++) {
176: node = (Node) nodes.get(i);
177: bnds = (Bounds) bounds.get(i);
178: type = (Integer) boundsType.get(i);
179:
180: if (type == NODE_BOUNDS)
181: newBounds = node.getBounds();
182: else if (type == SCHEDULING_BOUNDS) {
183: if (node instanceof Sound)
184: newBounds = ((Sound) node).getSchedulingBounds();
185: else if (node instanceof Behavior)
186: newBounds = ((Behavior) node).getSchedulingBounds();
187: }
188:
189: if (bnds instanceof BoundingSphere && node.isLive()) {
190: if (boundsNotEqual(bnds, newBounds) || newNode) {
191: root.setChild(drawBounds(node, newBounds, i), i);
192: bounds.set(i, newBounds);
193: } else {
194: node.getLocalToVworld(local2vw);
195: if (node instanceof TransformGroup) {
196: // Apply the transform of the current node to the
197: // local2vw so we get the bounds of this transform
198: // not the node above.
199: ((TransformGroup) node).getTransform(nodeTrans);
200: local2vw.mul(nodeTrans);
201: }
202: setTransform(i, local2vw);
203: }
204: } else if (bnds instanceof BoundingBox && node.isLive()) {
205: if (boundsNotEqual(bnds, newBounds)) {
206: root.setChild(drawBounds(node, newBounds, i), i);
207: bounds.set(i, newBounds);
208: } else {
209: node.getLocalToVworld(local2vw);
210: if (node instanceof TransformGroup) {
211: // Apply the transform of the current node to the
212: // local2vw so we get the bounds of this transform
213: // not the node above.
214: ((TransformGroup) node).getTransform(nodeTrans);
215: local2vw.mul(nodeTrans);
216: }
217: setTransform(i, local2vw);
218: }
219: } else if (node.isLive()) {
220: throw new RuntimeException(
221: "showBounds does not handle this type of bounds"
222: + bnds.getClass().getName());
223: }
224: // TODO: Handle polytopes
225: }
226: newNode = false;
227:
228: if (nodes.size() > 0)
229: currentCondition = frameCondition;
230: else
231: currentCondition = waitCondition;
232:
233: wakeupOn(currentCondition);
234: }
235:
236: /**
237: * Set the transformGroup and <code>index</code> to newTransform.
238: * Checks if the transform has changed so we don't make unecesary
239: * updates.
240: */
241: private void setTransform(int index, Transform3D newTransform) {
242: ((TransformGroup) transforms.get(index))
243: .getTransform(tmpTransform);
244:
245: if (!tmpTransform.equals(newTransform))
246: ((TransformGroup) transforms.get(index))
247: .setTransform(tmpTransform);
248: }
249:
250: private BranchGroup drawBounds(Node node, Bounds bounds, int i) {
251: BranchGroup ret = new BranchGroup();
252: Appearance appearance = new Appearance();
253: PolygonAttributes poly = new PolygonAttributes();
254: poly.setPolygonMode(PolygonAttributes.POLYGON_LINE);
255: appearance.setPolygonAttributes(poly);
256: ret.setCapability(BranchGroup.ALLOW_DETACH);
257: Transform3D nodeTrans = new Transform3D();
258:
259: Primitive primitive = null;
260: Point3d c = new Point3d();
261:
262: if (bounds instanceof BoundingSphere) {
263: ((BoundingSphere) bounds).getCenter(c);
264: double radius = ((BoundingSphere) bounds).getRadius();
265:
266: if (radius > 0.0) { // Radius = -1 before renderer is running
267: primitive = new Sphere((float) radius,
268: Sphere.GEOMETRY_NOT_SHARED, 10, appearance);
269: } else
270: return ret;
271:
272: } else if (bounds instanceof BoundingBox) {
273: Point3d upper = new Point3d();
274: Point3d lower = new Point3d();
275: ((BoundingBox) bounds).getUpper(upper);
276: ((BoundingBox) bounds).getLower(lower);
277: Vector3f size = new Vector3f();
278: size.x = (float) (upper.x - lower.x);
279: size.y = (float) (upper.y - lower.y);
280: size.z = (float) (upper.z - lower.z);
281:
282: c.x = lower.x + size.x / 2f;
283: c.y = lower.y + size.y / 2f;
284: c.z = lower.z + size.z / 2f;
285:
286: // A box of size 2 has vertex length of 4 so we have
287: // to /2
288: primitive = new Box(size.x / 2f, size.y / 2f, size.z / 2f,
289: appearance);
290: } else
291: throw new RuntimeException("Not implemented yet");
292:
293: Transform3D trans = new Transform3D();
294: trans.set(new Vector3d(c.x, c.y, c.z));
295:
296: Transform3D local2vw = new Transform3D();
297: if (node.isLive())
298: node.getLocalToVworld(local2vw);
299:
300: if (node instanceof TransformGroup) {
301: // Apply the transform of the current node to the
302: // local2vw so we get the bounds of this transform
303: // not the node above.
304: ((TransformGroup) node).getTransform(nodeTrans);
305: local2vw.mul(nodeTrans);
306: }
307:
308: TransformGroup tg = new TransformGroup(trans);
309: TransformGroup tgvw = new TransformGroup(local2vw);
310: tgvw.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
311: tgvw.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
312:
313: if (i < 0)
314: transforms.add(tgvw);
315: else
316: transforms.set(i, tgvw);
317:
318: tg.addChild(primitive);
319: tgvw.addChild(tg);
320: ret.addChild(tgvw);
321:
322: return ret;
323: }
324:
325: private boolean boundsNotEqual(Bounds b1, Bounds b2) {
326: if (b1 instanceof BoundingBox && b2 instanceof BoundingBox) {
327: Point3d p1u = new Point3d();
328: Point3d p1l = new Point3d();
329: Point3d p2u = new Point3d();
330: Point3d p2l = new Point3d();
331:
332: ((BoundingBox) b1).getUpper(p1u);
333: ((BoundingBox) b1).getLower(p1l);
334: ((BoundingBox) b2).getUpper(p2u);
335: ((BoundingBox) b2).getLower(p2l);
336:
337: if (p1u.equals(p2u) && p1l.equals(p2l))
338: return false; // We are NotEqual
339: else
340: return true;
341: } else if (b1 instanceof BoundingPolytope
342: && b2 instanceof BoundingPolytope) {
343: throw new RuntimeException("Not Implemented yet");
344: } else if (b1 instanceof BoundingSphere
345: && b2 instanceof BoundingSphere) {
346: Point3d b1Center = new Point3d();
347: Point3d b2Center = new Point3d();
348: double b1radius;
349: double b2radius;
350:
351: ((BoundingSphere) b1).getCenter(b1Center);
352: ((BoundingSphere) b2).getCenter(b2Center);
353: b1radius = ((BoundingSphere) b1).getRadius();
354: b2radius = ((BoundingSphere) b2).getRadius();
355:
356: if (b1Center.equals(b2Center) && b1radius == b2radius)
357: return false; // NotEqual is false ie we are equal
358: else
359: return true;
360: } else
361: return true;
362: }
363: }
|