001: /*
002: * $RCSfile: Node.java,v $
003: *
004: * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.7 $
028: * $Date: 2008/02/28 20:17:26 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.Hashtable;
035: import java.util.Enumeration;
036: import java.lang.reflect.Constructor;
037:
038: /**
039: * The Node class provides an abstract class for all Group and Leaf Nodes.
040: * It provides a common framework for constructing a Java 3D scene graph,
041: * specifically bounding volumes.
042: *
043: * <p>
044: * For more information, see the
045: * <a href="doc-files/intro.html">Introduction to the Java 3D API</a>.
046: *
047: * <p>
048: * NOTE: Applications should <i>not</i> extend this class directly.
049: */
050: public abstract class Node extends SceneGraphObject {
051:
052: /**
053: * Specifies that this Node will be reported in the pick
054: * SceneGraphPath if a pick occurs. This capability is only
055: * specifiable for Group nodes; it is ignored for leaf nodes.
056: * The default for Group nodes is false. All interior nodes not
057: * needed for uniqueness in a SceneGraphPath that don't have
058: * ENABLE_PICK_REPORTING set to true will not be reported in the
059: * SceneGraphPath.
060: * @see SceneGraphPath
061: */
062: public static final int ENABLE_PICK_REPORTING = CapabilityBits.NODE_ENABLE_PICK_REPORTING;
063:
064: /**
065: * Specifies that this Node will be reported in the collision
066: * SceneGraphPath if a collision occurs. This capability is only
067: * specifiable for Group nodes; it is ignored for leaf nodes.
068: * The default for Group nodes is false. All interior nodes not
069: * needed for uniqueness in a SceneGraphPath that don't have
070: * ENABLE_COLLISION_REPORTING set to true will not be reported
071: * in the SceneGraphPath.
072: * @see SceneGraphPath
073: */
074: public static final int ENABLE_COLLISION_REPORTING = CapabilityBits.NODE_ENABLE_COLLISION_REPORTING;
075:
076: /**
077: * Specifies that this Node allows read access to its bounds
078: * information.
079: */
080: public static final int ALLOW_BOUNDS_READ = CapabilityBits.NODE_ALLOW_BOUNDS_READ;
081:
082: /**
083: * Specifies that this Node allows write access to its bounds
084: * information.
085: */
086: public static final int ALLOW_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_BOUNDS_WRITE;
087:
088: /**
089: * Specifies that this Node allows reading its pickability state.
090: */
091: public static final int ALLOW_PICKABLE_READ = CapabilityBits.NODE_ALLOW_PICKABLE_READ;
092:
093: /**
094: * Specifies that this Node allows write access its pickability state.
095: */
096: public static final int ALLOW_PICKABLE_WRITE = CapabilityBits.NODE_ALLOW_PICKABLE_WRITE;
097:
098: /**
099: * Specifies that this Node allows reading its collidability state.
100: */
101: public static final int ALLOW_COLLIDABLE_READ = CapabilityBits.NODE_ALLOW_COLLIDABLE_READ;
102:
103: /**
104: * Specifies that this Node allows write access its collidability state.
105: */
106: public static final int ALLOW_COLLIDABLE_WRITE = CapabilityBits.NODE_ALLOW_COLLIDABLE_WRITE;
107:
108: /**
109: * Specifies that this Node allows read access to its bounds
110: * auto compute information.
111: */
112: public static final int ALLOW_AUTO_COMPUTE_BOUNDS_READ = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_READ;
113:
114: /**
115: * Specifies that this Node allows write access to its bounds
116: * auto compute information.
117: */
118: public static final int ALLOW_AUTO_COMPUTE_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_WRITE;
119:
120: /**
121: * Specifies that this Node allows read access to its local
122: * coordinates to virtual world (Vworld) coordinates transform.
123: */
124: public static final int ALLOW_LOCAL_TO_VWORLD_READ = CapabilityBits.NODE_ALLOW_LOCAL_TO_VWORLD_READ;
125:
126: /**
127: * Specifies that this Node allows read access to its parent Group node.
128: *
129: * @since Java 3D 1.4
130: */
131: public static final int ALLOW_PARENT_READ = CapabilityBits.NODE_ALLOW_PARENT_READ;
132:
133: /**
134: * Specifies that this Node allows read access to its Locale.
135: *
136: * @since Java 3D 1.4
137: */
138: public static final int ALLOW_LOCALE_READ = CapabilityBits.NODE_ALLOW_LOCALE_READ;
139:
140: // Array for setting default read capabilities
141: private static final int[] readCapabilities = { ALLOW_BOUNDS_READ,
142: ALLOW_PICKABLE_READ, ALLOW_COLLIDABLE_READ,
143: ALLOW_AUTO_COMPUTE_BOUNDS_READ, ALLOW_LOCAL_TO_VWORLD_READ,
144: ALLOW_PARENT_READ, ALLOW_LOCALE_READ };
145:
146: // for checking for cycles
147: private boolean visited = false;
148:
149: /**
150: * Constructs a Node object with default parameters. The default
151: * values are as follows:
152: * <ul>
153: * pickable : true<br>
154: * collidable : true<br>
155: * bounds auto compute : true<br>
156: * bounds : N/A (automatically computed)<br>
157: * </ul>
158: */
159: public Node() {
160: // set default read capabilities
161: setDefaultReadCapabilities(readCapabilities);
162: }
163:
164: /**
165:
166: * @return the parent of this node, or null if this node has no parent
167: * @exception CapabilityNotSetException if appropriate capability is
168: * not set and this object is part of live or compiled scene graph
169: */
170: public Node getParent() {
171: if (isLiveOrCompiled()) {
172: if (!this .getCapability(ALLOW_PARENT_READ)) {
173: throw new CapabilityNotSetException(J3dI18N
174: .getString("Node0"));
175: }
176: }
177:
178: NodeRetained nr = ((NodeRetained) this .retained).getParent();
179: return (nr == null ? null : (Node) nr.getSource());
180: }
181:
182: /**
183: * Sets the geometric bounds of a node.
184: * @param bounds the bounding object for a node
185: * @exception CapabilityNotSetException if appropriate capability is
186: * not set and this object is part of live or compiled scene graph
187: */
188: public void setBounds(Bounds bounds) {
189: if (isLiveOrCompiled())
190: if (!this .getCapability(ALLOW_BOUNDS_WRITE))
191: throw new CapabilityNotSetException(J3dI18N
192: .getString("Node1"));
193:
194: ((NodeRetained) this .retained).setBounds(bounds);
195: }
196:
197: /**
198: * Returns the bounding object of a node.
199: * @return the node's bounding object
200: * @exception CapabilityNotSetException if appropriate capability is
201: * not set and this object is part of live or compiled scene graph
202: * @exception SceneGraphCycleException if there is a cycle in the
203: * scene graph
204: */
205: public Bounds getBounds() {
206:
207: if (isLiveOrCompiled()) {
208: if (!this .getCapability(ALLOW_BOUNDS_READ)) {
209: throw new CapabilityNotSetException(J3dI18N
210: .getString("Node2"));
211: }
212: } else {
213: // this will throw a SceneGraphCycleException if there is
214: // a cycle
215: checkForCycle();
216: }
217:
218: return ((NodeRetained) this .retained).getBounds();
219: }
220:
221: /**
222: * Returns the collidable value; this value determines whether this node
223: * and it's children, if a group node, can be considered for collision
224: * purposes; if it is set to false, then neither this node nor any
225: * children nodes will be traversed for collision purposes; the default
226: * value is true. The collidable setting is the way that an
227: * application can perform collision culling.
228: * @return the present collidable value for this node
229: */
230: public boolean getCollidable() {
231: if (isLiveOrCompiled())
232: if (!this .getCapability(ALLOW_COLLIDABLE_READ))
233: throw new CapabilityNotSetException(J3dI18N
234: .getString("Node16"));
235:
236: return ((NodeRetained) retained).getCollidable();
237: }
238:
239: /**
240: * Sets the collidable value; determines whether this node and any of its
241: * children, if a group node, can be considered for collision purposes.
242: * @param collidable the new collidable value for this node
243: */
244: public void setCollidable(boolean collidable) {
245: if (isLiveOrCompiled())
246: if (!this .getCapability(ALLOW_COLLIDABLE_WRITE))
247: throw new CapabilityNotSetException(J3dI18N
248: .getString("Node4"));
249:
250: ((NodeRetained) retained).setCollidable(collidable);
251: }
252:
253: /**
254: * Turns the automatic calcuation of geometric bounds of a node on/off.
255: * @param autoCompute indicates if the node's bounding object is
256: * automatically computed.
257: * @exception CapabilityNotSetException if appropriate capability is
258: * not set and this object is part of live or compiled scene graph
259: */
260: public void setBoundsAutoCompute(boolean autoCompute) {
261: if (isLiveOrCompiled())
262: if (!this .getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_WRITE))
263: throw new CapabilityNotSetException(J3dI18N
264: .getString("Node5"));
265:
266: ((NodeRetained) this .retained)
267: .setBoundsAutoCompute(autoCompute);
268: }
269:
270: /**
271: * Gets the value indicating if the automatic calcuation of geometric bounds of a node is on/off.
272: * @return the node's auto compute flag for the geometric bounding object
273: * @exception CapabilityNotSetException if appropriate capability is
274: * not set and this object is part of live or compiled scene graph
275: */
276: public boolean getBoundsAutoCompute() {
277: if (isLiveOrCompiled())
278: if (!this .getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_READ))
279: throw new CapabilityNotSetException(J3dI18N
280: .getString("Node6"));
281:
282: return ((NodeRetained) this .retained).getBoundsAutoCompute();
283: }
284:
285: /**
286: * Retrieves the local coordinates to virtual world coordinates
287: * transform for this node in the scene graph. This is the composite
288: * of all transforms in the scene graph from the root down to
289: * <code>this</code> node. It is only valid
290: * for nodes that are part of a live scene graph.
291: * If the node is not part of a live scene graph then the coordinates are
292: * calculated as if the graph was attached at the origin of a locale.
293: * @param t the object that will receive the local coordinates to
294: * Vworld coordinates transform.
295: * @exception RestrictedAccessException if the node is compiled but not
296: * part of a live scene graph
297: * @exception CapabilityNotSetException if appropriate capability is
298: * not set and this node is part of live or compiled scene graph
299: * @exception IllegalSharingException if the node is a descendant
300: * of a SharedGroup node.
301: */
302: public void getLocalToVworld(Transform3D t) {
303: if (isLiveOrCompiled()) {
304: if (!this .getCapability(ALLOW_LOCAL_TO_VWORLD_READ))
305: throw new CapabilityNotSetException(J3dI18N
306: .getString("Node8"));
307: }
308:
309: if (!isLive()) {
310: // TODO Support compiled graphs
311: if (isCompiled())
312: throw new RestrictedAccessException(J3dI18N
313: .getString("Node7"));
314:
315: // In 1.4 we support getLocalToVworld for non live nodes
316: ((NodeRetained) this .retained).computeNonLiveLocalToVworld(
317: t, this );
318: //throw new RestrictedAccessException(J3dI18N.getString("Node7"));
319: } else {
320: ((NodeRetained) this .retained).getLocalToVworld(t);
321: }
322: }
323:
324: /**
325: * Retrieves the local coordinates to virtual world coordinates
326: * transform for the particular path in the scene graph ending with
327: * this node. This is the composite
328: * of all transforms in the scene graph from the root down to
329: * <code>this</code> node via the specified Link nodes. It is
330: * only valid for nodes that are part of a live scene graph.
331: * @param path the specific path from the node to the Locale
332: * @param t the object that will receive the local coordinates to
333: * Vworld coordinates transform.
334: * @exception RestrictedAccessException if the node is <em>not</em>
335: * part of a live scene graph
336: * @exception CapabilityNotSetException if appropriate capability is
337: * not set and this node is part of live scene graph
338: * @exception IllegalArgumentException if the specified path does
339: * not contain a valid Locale, or if the last node in the path is
340: * different from this node
341: * @exception IllegalSharingException if the node is not a descendant
342: * of a SharedGroup node.
343: */
344: public void getLocalToVworld(SceneGraphPath path, Transform3D t) {
345: if (!isLive()) {
346: throw new RestrictedAccessException(J3dI18N
347: .getString("Node7"));
348: }
349:
350: if (!this .getCapability(ALLOW_LOCAL_TO_VWORLD_READ))
351: throw new CapabilityNotSetException(J3dI18N
352: .getString("Node8"));
353:
354: ((NodeRetained) this .retained).getLocalToVworld(path, t);
355:
356: }
357:
358: /**
359: * Retrieves the locale to which this node is attached. If the
360: * node is not part of a live scene graph, null is returned.
361: *
362: * @return the locale to which this node is attached.
363: *
364: * @exception CapabilityNotSetException if appropriate capability is
365: * not set and this node is part of live scene graph
366: * @exception IllegalSharingException if the node is a descendant
367: * of a SharedGroup node.
368: *
369: * @since Java 3D 1.4
370: */
371: public Locale getLocale() {
372: if (!isLive()) {
373: return null;
374: }
375:
376: if (!this .getCapability(ALLOW_LOCALE_READ)) {
377: throw new CapabilityNotSetException(J3dI18N
378: .getString("Node17"));
379: }
380:
381: return ((NodeRetained) this .retained).getLocale();
382: }
383:
384: /**
385: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
386: * the group node is duplicated via a call to <code>cloneNode</code>
387: * and then <code>cloneTree</code>
388: * is called for each child node. For Leaf Nodes, component
389: * data can either be duplicated or be made a reference to the original
390: * data. Leaf Node cloneTree behavior is determined by the
391: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
392: * component data class and by the <code>forceDuplicate</code> paramter.
393: * @return a reference to the cloned sub-graph.
394: * @exception DanglingReferenceException When a dangling reference is
395: * discovered during the cloneTree operation.
396: * @exception RestrictedAccessException if this object is part of live
397: * or compiled scene graph
398: * @exception SceneGraphCycleException if there is a cycle in the
399: * scene graph
400: * @see NodeComponent#setDuplicateOnCloneTree
401: */
402: public Node cloneTree() {
403: return cloneTree(new NodeReferenceTable(), false, false);
404: }
405:
406: /**
407: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
408: * the group node is duplicated via a call to <code>cloneNode</code>
409: * and then <code>cloneTree</code> is called for each child node.
410: * For Leaf Nodes, component
411: * data can either be duplicated or be made a reference to the original
412: * data. Leaf Node cloneTree behavior is determined by the
413: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
414: * component data class and by the <code>forceDuplicate</code> paramter.
415: * @param forceDuplicate when set to <code>true</code>, causes the
416: * <code>duplicateOnCloneTree</code> flag to be ignored. When
417: * <code>false</code>, the value of each node's
418: * <code>duplicateOnCloneTree</code> determines whether data is
419: * duplicated or copied.
420: * @return a reference to the cloned scene graph.
421: * @exception DanglingReferenceException When a dangling reference is
422: * discovered during the cloneTree operation.
423: * @exception RestrictedAccessException if this object is part of live
424: * or compiled scene graph
425: * @exception SceneGraphCycleException if there is a cycle in the
426: * scene graph
427: * @see NodeComponent#setDuplicateOnCloneTree
428: */
429: public Node cloneTree(boolean forceDuplicate) {
430: return cloneTree(new NodeReferenceTable(), forceDuplicate,
431: false);
432: }
433:
434: /**
435: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
436: * the group node is duplicated via a call to <code>cloneNode</code> and
437: * then <code>cloneTree</code> is called for each child node. For
438: * Leaf Nodes, component
439: * data can either be duplicated or be made a reference to the original
440: * data. Leaf Node cloneTree behavior is determined by the
441: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
442: * component data class and by the <code>forceDuplicate</code> paramter.
443: *
444: * @param forceDuplicate when set to <code>true</code>, causes the
445: * <code>duplicateOnCloneTree</code>
446: * flag to be ignored. When <code>false</code>, the value of each node's
447: * <code>duplicateOnCloneTree</code> determines whether data is
448: * duplicated or copied.
449: *
450: * @param allowDanglingReferences when set to <code>true</code> allows
451: * the <code>cloneTree</code>
452: * method to complete even whan a dangling reference is discovered. When
453: * this parameter is <code>false</code> a
454: * <code>DanglingReferenceException</code> is generated as
455: * soon as cloneTree detects this situation.
456: *
457: * @return a reference to the cloned scene graph.
458: *
459: * @exception DanglingReferenceException When a dangling reference is
460: * discovered during the cloneTree operation and the
461: * <code>allowDanglingReference</code> parameter is </code>false</code>.
462: * @exception RestrictedAccessException if this object is part of live
463: * or compiled scene graph
464: * @exception SceneGraphCycleException if there is a cycle in the
465: * scene graph
466: *
467: * @see NodeComponent#setDuplicateOnCloneTree
468: */
469: public Node cloneTree(boolean forceDuplicate,
470: boolean allowDanglingReferences) {
471: return cloneTree(new NodeReferenceTable(), forceDuplicate,
472: allowDanglingReferences);
473: }
474:
475: /**
476: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
477: * the group node is duplicated via a call to <code>cloneNode</code>
478: * and then <code>cloneTree</code>
479: * is called for each child node. For Leaf Nodes, component
480: * data can either be duplicated or be made a reference to the original
481: * data. Leaf Node cloneTree behavior is determined by the
482: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
483: * component data class and by the <code>forceDuplicate</code> paramter.
484: * @param referenceTable table that stores the mapping between
485: * original and cloned nodes. All previous values in the
486: * referenceTable will be cleared before the clone is made.
487: * @return a reference to the cloned sub-graph.
488: * @exception DanglingReferenceException When a dangling reference is
489: * discovered during the cloneTree operation.
490: * @exception RestrictedAccessException if this object is part of live
491: * or compiled scene graph
492: * @exception SceneGraphCycleException if there is a cycle in the
493: * scene graph
494: * @see NodeComponent#setDuplicateOnCloneTree
495: * @since Java 3D 1.2
496: */
497: public Node cloneTree(NodeReferenceTable referenceTable) {
498: return cloneTree(referenceTable, false, false);
499: }
500:
501: /**
502: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
503: * the group node is duplicated via a call to <code>cloneNode</code>
504: * and then <code>cloneTree</code> is called for each child node.
505: * For Leaf Nodes, component
506: * data can either be duplicated or be made a reference to the original
507: * data. Leaf Node cloneTree behavior is determined by the
508: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
509: * component data class and by the <code>forceDuplicate</code> paramter.
510: * @param referenceTable table that stores the mapping between
511: * original and cloned nodes. All previous values in the
512: * referenceTable will be cleared before the clone is made.
513: * @param forceDuplicate when set to <code>true</code>, causes the
514: * <code>duplicateOnCloneTree</code> flag to be ignored. When
515: * <code>false</code>, the value of each node's
516: * <code>duplicateOnCloneTree</code> determines whether data is
517: * duplicated or copied.
518: * @return a reference to the cloned scene graph.
519: * @exception DanglingReferenceException When a dangling reference is
520: * discovered during the cloneTree operation.
521: * @exception RestrictedAccessException if this object is part of live
522: * or compiled scene graph
523: * @exception SceneGraphCycleException if there is a cycle in the
524: * scene graph
525: * @see NodeComponent#setDuplicateOnCloneTree
526: * @since Java 3D 1.2
527: */
528: public Node cloneTree(NodeReferenceTable referenceTable,
529: boolean forceDuplicate) {
530: return cloneTree(referenceTable, forceDuplicate, false);
531: }
532:
533: /**
534: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
535: * the group node is duplicated via a call to <code>cloneNode</code>
536: * and then <code>cloneTree</code> is called for each child node.
537: * For Leaf Nodes, component
538: * data can either be duplicated or be made a reference to the original
539: * data. Leaf Node cloneTree behavior is determined by the
540: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
541: * component data class and by the <code>forceDuplicate</code> paramter.
542: * @param referenceTable table that stores the mapping between
543: * original and cloned nodes. All previous values in the
544: * referenceTable will be cleared before the clone is made.
545: * @param forceDuplicate when set to <code>true</code>, causes the
546: * <code>duplicateOnCloneTree</code> flag to be ignored. When
547: * <code>false</code>, the value of each node's
548: * <code>duplicateOnCloneTree</code> determines whether data is
549: * duplicated or copied.
550: *
551: * @param allowDanglingReferences when set to <code>true</code> allows
552: * the <code>cloneTree</code>
553: * method to complete even whan a dangling reference is discovered. When
554: * this parameter is <code>false</code> a
555: * <code>DanglingReferenceException</code> is generated as
556: * soon as cloneTree detects this situation.
557: *
558: * @return a reference to the cloned scene graph.
559: * @exception DanglingReferenceException When a dangling reference is
560: * discovered during the cloneTree operation.
561: * @exception RestrictedAccessException if this object is part of live
562: * or compiled scene graph
563: * @exception SceneGraphCycleException if there is a cycle in the
564: * scene graph
565: * @see NodeComponent#setDuplicateOnCloneTree
566: * @since Java 3D 1.2
567: */
568: public Node cloneTree(NodeReferenceTable referenceTable,
569: boolean forceDuplicate, boolean allowDanglingReferences) {
570:
571: if (!isLiveOrCompiled()) {
572: // this will throw a SceneGraphCycleException if there is
573: // a cycle
574: checkForCycle();
575: }
576:
577: referenceTable.set(allowDanglingReferences, new Hashtable());
578: Node n = cloneTree(forceDuplicate,
579: referenceTable.objectHashtable);
580:
581: // go through hash table looking for Leaf nodes.
582: // call updateNodeReferences for each.
583: Enumeration e = referenceTable.objectHashtable.elements();
584:
585: while (e.hasMoreElements()) {
586: SceneGraphObject o = (SceneGraphObject) e.nextElement();
587: o.updateNodeReferences(referenceTable);
588: }
589: return n;
590: }
591:
592: /**
593: * Duplicates all the nodes of the specified sub-graph. For Group Nodes
594: * the group node is duplicated via a call to <code>cloneNode</code> and
595: * then <code>cloneTree</code> is called for each child node. For
596: * Leaf Nodes, component
597: * data can either be duplicated or be made a reference to the original
598: * data. Leaf Node cloneTree behavior is determined by the
599: * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's
600: * component data class and by the <code>forceDuplicate</code> paramter.
601: *
602: * @param forceDuplicate when set to <code>true</code>, causes the
603: * <code>duplicateOnCloneTree</code>
604: * flag to be ignored. When <code>false</code>, the value of each node's
605: * <code>duplicateOnCloneTree</code> determines whether data is
606: * duplicated or copied.
607: *
608: * @param nodeHashtable a hashtable used to map orignal node references to
609: * their cloned counterpart.
610: *
611: * @return a reference to the cloned scene graph.
612: *
613: * @see NodeComponent#setDuplicateOnCloneTree
614: */
615: Node cloneTree(boolean forceDuplicate, Hashtable nodeHashtable) {
616: Node l;
617: this .nodeHashtable = nodeHashtable;
618: try {
619: l = cloneNode(forceDuplicate);
620: } catch (RuntimeException e) {
621: this .nodeHashtable = null;
622: throw e;
623: }
624: // must reset to null so that we can tell whether the call is from user
625: // or cloneTree
626: this .nodeHashtable = null;
627: nodeHashtable.put(this , l);
628: return l;
629: }
630:
631: /**
632: * Used to create a new instance of the node. This routine is called
633: * by <code>cloneTree</code> to duplicate the current node.
634: * <code>cloneNode</code> should be overridden by any user subclassed
635: * objects. All subclasses must have their <code>cloneNode</code>
636: * method consist of the following lines:
637: * <P><blockquote><pre>
638: * public Node cloneNode(boolean forceDuplicate) {
639: * UserSubClass usc = new UserSubClass();
640: * usc.duplicateNode(this, forceDuplicate);
641: * return usc;
642: * }
643: * </pre></blockquote>
644: * NOTE: Applications should <i>not</i> call this method directly.
645: * It should only be called by the cloneTree method.
646: *
647: * @param forceDuplicate when set to <code>true</code>, causes the
648: * <code>duplicateOnCloneTree</code> flag to be ignored. When
649: * <code>false</code>, the value of each node's
650: * <code>duplicateOnCloneTree</code> variable determines whether
651: * NodeComponent data is duplicated or copied.
652: *
653: * @exception RestrictedAccessException if this object is part of live
654: * or compiled scene graph
655: *
656: * @see Node#cloneTree
657: * @see Node#duplicateNode
658: * @see NodeComponent#setDuplicateOnCloneTree
659: */
660: public Node cloneNode(boolean forceDuplicate) {
661: throw new RuntimeException(J3dI18N.getString("Node12"));
662: }
663:
664: /**
665: * Copies all node information from <code>originalNode</code> into
666: * the current node. This method is called from the
667: * <code>cloneNode</code> method which is, in turn, called by the
668: * <code>cloneTree</code> method.
669: * <P>
670: * For any <code>NodeComponent</code> objects
671: * contained by the object being duplicated, each <code>NodeComponent</code>
672: * object's <code>duplicateOnCloneTree</code> value is used to determine
673: * whether the <code>NodeComponent</code> should be duplicated in the new node
674: * or if just a reference to the current node should be placed in the
675: * new node. This flag can be overridden by setting the
676: * <code>forceDuplicate</code> parameter in the <code>cloneTree</code>
677: * method to <code>true</code>.
678: *
679: * <br>
680: * NOTE: Applications should <i>not</i> call this method directly.
681: * It should only be called by the cloneNode method.
682: *
683: * @param originalNode the original node to duplicate.
684: * @param forceDuplicate when set to <code>true</code>, causes the
685: * <code>duplicateOnCloneTree</code> flag to be ignored. When
686: * <code>false</code>, the value of each node's
687: * <code>duplicateOnCloneTree</code> variable determines whether
688: * NodeComponent data is duplicated or copied.
689: *
690: * @see Group#cloneNode
691: * @see Node#duplicateNode
692: * @see Node#cloneTree
693: * @see NodeComponent#setDuplicateOnCloneTree
694: */
695: public void duplicateNode(Node originalNode, boolean forceDuplicate) {
696: duplicateAttributes(originalNode, forceDuplicate);
697: }
698:
699: /**
700: * Copies all node information from <code>originalNode</code> into
701: * the current node. This method is called from subclass of
702: * <code>duplicateNode</code> method which is, in turn, called by the
703: * <code>cloneNode</code> method.
704: * <P>
705: * For any <i>NodeComponent</i> objects
706: * contained by the object being duplicated, each <i>NodeComponent</i>
707: * object's <code>duplicateOnCloneTree</code> value is used to determine
708: * whether the <i>NodeComponent<i> should be duplicated in the new node
709: * or if just a reference to the current node should be placed in the
710: * new node. This flag can be overridden by setting the
711: * <code>forceDuplicate</code> parameter in the <code>cloneTree</code>
712: * method to <code>true</code>.
713: *
714: *
715: * @param originalNode the original node to duplicate.
716: * @param forceDuplicate when set to <code>true</code>, causes the
717: * <code>duplicateOnCloneTree</code> flag to be ignored. When
718: * <code>false</code>, the value of each node's
719: * <code>duplicateOnCloneTree</code> variable determines whether
720: * NodeComponent data is duplicated or copied.
721: *
722: * @see Group#cloneNode
723: * @see Node#duplicateNode
724: * @see Node#cloneTree
725: * @see NodeComponent#setDuplicateOnCloneTree
726: */
727: final void checkDuplicateNode(Node originalNode,
728: boolean forceDuplicate) {
729: if (originalNode.nodeHashtable != null) {
730: duplicateAttributes(originalNode, forceDuplicate);
731: } else {
732: // user call cloneNode() or duplicateNode() directly
733: // instead of via cloneTree()
734: originalNode.nodeHashtable = new Hashtable();
735: duplicateAttributes(originalNode, forceDuplicate);
736: originalNode.nodeHashtable = null;
737: }
738: }
739:
740: /**
741: * Copies all Node information from
742: * <code>originalNode</code> into
743: * the current node. This method is called from the
744: * <code>cloneNode</code> method which is, in turn, called by the
745: * <code>cloneTree</code> method.<P>
746: *
747: * @param originalNode the original node to duplicate.
748: * @param forceDuplicate when set to <code>true</code>, causes the
749: * <code>duplicateOnCloneTree</code> flag to be ignored. When
750: * <code>false</code>, the value of each node's
751: * <code>duplicateOnCloneTree</code> variable determines whether
752: * NodeComponent data is duplicated or copied.
753: *
754: * @exception RestrictedAccessException if originalNode object is part of a live
755: * or compiled scenegraph.
756: *
757: * @see Node#duplicateNode
758: * @see Node#cloneTree
759: * @see NodeComponent#setDuplicateOnCloneTree
760: */
761: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
762:
763: if (originalNode.isLiveOrCompiled()) {
764: throw new RestrictedAccessException(J3dI18N
765: .getString("Node13"));
766: }
767: super .duplicateSceneGraphObject(originalNode);
768: NodeRetained attr = (NodeRetained) originalNode.retained;
769: NodeRetained rt = (NodeRetained) retained;
770:
771: rt.setPickable(attr.getPickable());
772: rt.setCollidable(attr.getCollidable());
773: }
774:
775: /**
776: * When set to <code>true</code> this <code>Node</code> can be Picked.
777: * Setting to false indicates that this node and it's children
778: * are ALL unpickable.
779: *
780: * @param pickable Indicates if this node should be pickable or not
781: */
782: public void setPickable(boolean pickable) {
783: if (isLiveOrCompiled())
784: if (!this .getCapability(ALLOW_PICKABLE_WRITE))
785: throw new CapabilityNotSetException(J3dI18N
786: .getString("Node14"));
787:
788: ((NodeRetained) retained).setPickable(pickable);
789: }
790:
791: /**
792: * Returns true if this <code>Node</code> is pickable,
793: * false if it is not pickable.
794: */
795: public boolean getPickable() {
796: if (isLiveOrCompiled())
797: if (!this .getCapability(ALLOW_PICKABLE_READ))
798: throw new CapabilityNotSetException(J3dI18N
799: .getString("Node3"));
800:
801: return ((NodeRetained) retained).getPickable();
802: }
803:
804: /**
805: * checks for cycles in the scene graph
806: */
807: void checkForCycle() {
808: if (visited) {
809: throw new SceneGraphCycleException(J3dI18N
810: .getString("Node15"));
811: }
812: visited = true;
813: Node parent = getParent();
814: if (parent != null) {
815: parent.checkForCycle();
816: }
817: visited = false;
818: }
819:
820: }
|