001: /*
002: * $RCSfile: ShowBoundsBehavior.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.3 $
041: * $Date: 2007/02/09 17:17:03 $
042: * $State: Exp $
043: */
044:
045: package org.jdesktop.j3d.utils.scenegraph.visualtools;
046:
047: import java.util.ArrayList;
048: import java.util.Enumeration;
049: import javax.media.j3d.*;
050: import javax.vecmath.Point3d;
051: import javax.vecmath.Vector3f;
052: import javax.vecmath.Vector3d;
053: import com.sun.j3d.utils.geometry.Primitive;
054: import com.sun.j3d.utils.geometry.Sphere;
055: import com.sun.j3d.utils.geometry.Box;
056:
057: /**
058: * This behavior will display the bounds (using getBounds) on each
059: * Java3D Node registered with it.
060: */
061: public class ShowBoundsBehavior extends Behavior {
062:
063: public final static Integer NODE_BOUNDS = new Integer(1);
064: public final static Integer SCHEDULING_BOUNDS = new Integer(2);
065: public final static Integer INFLUENCING_BOUNDS = new Integer(3);
066:
067: WakeupOnElapsedFrames frameCondition;
068: WakeupOnBehaviorPost waitCondition;
069: WakeupCondition currentCondition;
070: ArrayList nodes = new ArrayList();
071: ArrayList bounds = new ArrayList();
072: ArrayList transforms = new ArrayList();
073: ArrayList boundsType = new ArrayList();
074: Switch root = new Switch();
075: boolean newNode = false;
076:
077: TransformGroup testtg;
078: Sphere tests;
079: Shape3D shp;
080:
081: private Transform3D tmpTransform = new Transform3D();
082:
083: public ShowBoundsBehavior(BranchGroup parent) {
084: super ();
085: root.setCapability(Switch.ALLOW_CHILDREN_READ);
086: root.setCapability(Switch.ALLOW_CHILDREN_WRITE);
087: root.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
088: root.setWhichChild(Switch.CHILD_ALL);
089: parent.addChild(root);
090: parent.addChild(this );
091:
092: this .setSchedulingBounds(new BoundingSphere(new Point3d(),
093: Double.POSITIVE_INFINITY));
094:
095: frameCondition = new WakeupOnElapsedFrames(0, true);
096: waitCondition = new WakeupOnBehaviorPost(this , 1);
097: currentCondition = waitCondition;
098: }
099:
100: /**
101: * Add node to the list of nodes which will have their bounds displayed
102: * This method sets the ALLOW_BOUNDS_READ capability bit on node
103: */
104: public void showBounds(Node node) {
105: node.setCapability(Node.ALLOW_BOUNDS_READ);
106: node.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
107: if (node instanceof TransformGroup)
108: node.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
109: nodes.add(node);
110: bounds.add(node.getBounds());
111: boundsType.add(NODE_BOUNDS);
112: root.addChild(drawBounds(node, node.getBounds(), -1));
113: newNode = true;
114:
115: currentCondition = frameCondition;
116: postId(1);
117: }
118:
119: public void showSchedulingBounds(Node node) {
120: Bounds schedBounds = null;
121:
122: if (node instanceof Behavior || node instanceof Sound) {
123:
124: if (node instanceof Sound) {
125: node.setCapability(Sound.ALLOW_SCHEDULING_BOUNDS_READ);
126: schedBounds = ((Sound) node).getSchedulingBounds();
127: } else if (node instanceof Behavior) {
128: //node.setCapability( Behavior.ALLOW_SCHEDULING_BOUNDS_READ );
129: schedBounds = ((Behavior) node).getSchedulingBounds();
130: }
131:
132: node.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
133: nodes.add(node);
134: bounds.add(schedBounds);
135: boundsType.add(SCHEDULING_BOUNDS);
136: root.addChild(drawBounds(node, schedBounds, -1));
137: newNode = true;
138:
139: currentCondition = frameCondition;
140: postId(1);
141:
142: } else
143: throw new RuntimeException(node
144: + " not supported in showSchedulingBounds");
145:
146: }
147:
148: public void showInfluencingBounds(Node node) {
149: if (node instanceof Light || node instanceof Fog) {
150:
151: throw new RuntimeException("Not Implemented");
152: } else
153: throw new RuntimeException(node
154: + " not supported in showInfluencingBounds");
155: }
156:
157: /**
158: * Remove node from the bounds being displayed
159: */
160: public void hideBounds(Node node, Integer type) {
161: int i = -1;
162:
163: for (int j = 0; j < nodes.size() && i == -1; j++)
164: if (nodes.get(j) == node && boundsType.get(j) == type)
165: i = j;
166:
167: if (i == -1) {
168: System.out.println("WARNING - error removing bounds");
169: return;
170: }
171:
172: nodes.remove(i);
173: bounds.remove(i);
174: boundsType.remove(i);
175: root.removeChild(i);
176: }
177:
178: /**
179: * Stop displaying and remove all references to existing bounds
180: */
181: public void removeAllBounds() {
182: nodes.clear();
183: bounds.clear();
184: while (root.numChildren() > 0)
185: root.removeChild(0);
186: }
187:
188: public void initialize() {
189:
190: wakeupOn(currentCondition);
191: }
192:
193: public void processStimulus(Enumeration criteria) {
194: Bounds bnds;
195: Node node;
196: Integer type;
197: Transform3D nodeTrans = new Transform3D();
198: Transform3D local2vw = new Transform3D();
199: TransformGroup transform;
200: Bounds newBounds = null;
201:
202: for (int i = 0; i < nodes.size(); i++) {
203: node = (Node) nodes.get(i);
204: bnds = (Bounds) bounds.get(i);
205: type = (Integer) boundsType.get(i);
206:
207: if (type == NODE_BOUNDS)
208: newBounds = node.getBounds();
209: else if (type == SCHEDULING_BOUNDS) {
210: if (node instanceof Sound)
211: newBounds = ((Sound) node).getSchedulingBounds();
212: else if (node instanceof Behavior)
213: newBounds = ((Behavior) node).getSchedulingBounds();
214: }
215:
216: if (bnds instanceof BoundingSphere && node.isLive()) {
217: if (boundsNotEqual(bnds, newBounds) || newNode) {
218: root.setChild(drawBounds(node, newBounds, i), i);
219: bounds.set(i, newBounds);
220: } else {
221: node.getLocalToVworld(local2vw);
222: if (node instanceof TransformGroup) {
223: // Apply the transform of the current node to the
224: // local2vw so we get the bounds of this transform
225: // not the node above.
226: ((TransformGroup) node).getTransform(nodeTrans);
227: local2vw.mul(nodeTrans);
228: }
229: setTransform(i, local2vw);
230: }
231: } else if (bnds instanceof BoundingBox && node.isLive()) {
232: if (boundsNotEqual(bnds, newBounds)) {
233: root.setChild(drawBounds(node, newBounds, i), i);
234: bounds.set(i, newBounds);
235: } else {
236: node.getLocalToVworld(local2vw);
237: if (node instanceof TransformGroup) {
238: // Apply the transform of the current node to the
239: // local2vw so we get the bounds of this transform
240: // not the node above.
241: ((TransformGroup) node).getTransform(nodeTrans);
242: local2vw.mul(nodeTrans);
243: }
244: setTransform(i, local2vw);
245: }
246: } else if (node.isLive()) {
247: throw new RuntimeException(
248: "showBounds does not handle this type of bounds"
249: + bnds.getClass().getName());
250: }
251: // TODO: Handle polytopes
252: }
253: newNode = false;
254:
255: if (nodes.size() > 0)
256: currentCondition = frameCondition;
257: else
258: currentCondition = waitCondition;
259:
260: wakeupOn(currentCondition);
261: }
262:
263: /**
264: * Set the transformGroup and <code>index</code> to newTransform.
265: * Checks if the transform has changed so we don't make unecesary
266: * updates.
267: */
268: private void setTransform(int index, Transform3D newTransform) {
269: ((TransformGroup) transforms.get(index))
270: .getTransform(tmpTransform);
271:
272: if (!tmpTransform.equals(newTransform))
273: ((TransformGroup) transforms.get(index))
274: .setTransform(newTransform);
275: }
276:
277: private BranchGroup drawBounds(Node node, Bounds bounds, int i) {
278: BranchGroup ret = new BranchGroup();
279: Appearance appearance = new Appearance();
280: PolygonAttributes poly = new PolygonAttributes();
281: poly.setPolygonMode(PolygonAttributes.POLYGON_LINE);
282: appearance.setPolygonAttributes(poly);
283: ret.setCapability(BranchGroup.ALLOW_DETACH);
284: Transform3D nodeTrans = new Transform3D();
285:
286: Primitive primitive = null;
287: Point3d c = new Point3d();
288:
289: if (bounds instanceof BoundingSphere) {
290: ((BoundingSphere) bounds).getCenter(c);
291: double radius = ((BoundingSphere) bounds).getRadius();
292:
293: if (radius > 0.0) { // Radius = -1 before renderer is running
294: primitive = new Sphere((float) radius,
295: Sphere.GEOMETRY_NOT_SHARED, 10, appearance);
296: } else
297: return ret;
298:
299: } else if (bounds instanceof BoundingBox) {
300: Point3d upper = new Point3d();
301: Point3d lower = new Point3d();
302: ((BoundingBox) bounds).getUpper(upper);
303: ((BoundingBox) bounds).getLower(lower);
304: Vector3f size = new Vector3f();
305: size.x = (float) (upper.x - lower.x);
306: size.y = (float) (upper.y - lower.y);
307: size.z = (float) (upper.z - lower.z);
308:
309: c.x = lower.x + size.x / 2f;
310: c.y = lower.y + size.y / 2f;
311: c.z = lower.z + size.z / 2f;
312:
313: // A box of size 2 has vertex length of 4 so we have
314: // to /2
315: primitive = new Box(size.x / 2f, size.y / 2f, size.z / 2f,
316: appearance);
317: } else
318: throw new RuntimeException("Not implemented yet");
319:
320: Transform3D trans = new Transform3D();
321: trans.set(new Vector3d(c.x, c.y, c.z));
322:
323: Transform3D local2vw = new Transform3D();
324: if (node.isLive())
325: node.getLocalToVworld(local2vw);
326:
327: if (node instanceof TransformGroup) {
328: // Apply the transform of the current node to the
329: // local2vw so we get the bounds of this transform
330: // not the node above.
331: ((TransformGroup) node).getTransform(nodeTrans);
332: local2vw.mul(nodeTrans);
333: }
334:
335: TransformGroup tg = new TransformGroup(trans);
336: TransformGroup tgvw = new TransformGroup(local2vw);
337: tgvw.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
338: tgvw.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
339:
340: if (i > transforms.size() - 1)
341: transforms.add(tgvw);
342: else
343: transforms.set(i, tgvw);
344:
345: tg.addChild(primitive);
346: tgvw.addChild(tg);
347: ret.addChild(tgvw);
348:
349: return ret;
350: }
351:
352: private boolean boundsNotEqual(Bounds b1, Bounds b2) {
353: if (b1 instanceof BoundingBox && b2 instanceof BoundingBox) {
354: Point3d p1u = new Point3d();
355: Point3d p1l = new Point3d();
356: Point3d p2u = new Point3d();
357: Point3d p2l = new Point3d();
358:
359: ((BoundingBox) b1).getUpper(p1u);
360: ((BoundingBox) b1).getLower(p1l);
361: ((BoundingBox) b2).getUpper(p2u);
362: ((BoundingBox) b2).getLower(p2l);
363:
364: if (p1u.equals(p2u) && p1l.equals(p2l))
365: return false; // We are NotEqual
366: else
367: return true;
368: } else if (b1 instanceof BoundingPolytope
369: && b2 instanceof BoundingPolytope) {
370: throw new RuntimeException("Not Implemented yet");
371: } else if (b1 instanceof BoundingSphere
372: && b2 instanceof BoundingSphere) {
373: Point3d b1Center = new Point3d();
374: Point3d b2Center = new Point3d();
375: double b1radius;
376: double b2radius;
377:
378: ((BoundingSphere) b1).getCenter(b1Center);
379: ((BoundingSphere) b2).getCenter(b2Center);
380: b1radius = ((BoundingSphere) b1).getRadius();
381: b2radius = ((BoundingSphere) b2).getRadius();
382:
383: if (b1Center.equals(b2Center) && b1radius == b2radius)
384: return false; // NotEqual is false ie we are equal
385: else
386: return true;
387: } else
388: return true;
389: }
390: }
|