001: /*
002: * $RCSfile: DistanceLOD.java,v $
003: *
004: * Copyright 1997-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.6 $
028: * $Date: 2008/02/28 20:17:21 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.Point3f;
035: import java.util.Enumeration;
036:
037: /**
038: * This class defines a distance-based LOD behavior node that operates on
039: * a Switch group node to select one of the children of that Switch node
040: * based on the distance of this LOD node from the viewer.
041: * An array of <i>n</i> monotonically increasing distance values is
042: * specified, such that distances[0] is associated with the highest level of
043: * detail and distances[<i>n</i>-1] is associated with the lowest level of
044: * detail. Based on the actual distance from the viewer to
045: * this DistanceLOD node, these <i>n</i>
046: * distance values [0, <i>n</i>-1] select from among <i>n</i>+1
047: * levels of detail [0, <i>n</i>]. If <i>d</i> is the distance from
048: * the viewer to the LOD node, then the equation for determining
049: * which level of detail (child of the Switch node) is selected is:
050: * <p>
051: * <ul>
052: * 0, if <i>d</i> <= distances[0]
053: * <br>
054: * <i>i</i>, if distances[<i>i</i>-1] < <i>d</i> <= distances[<i>i</i>]
055: * <br>
056: * <i>n</i>, if d > distances[<i>n</i>-1]
057: * </ul>
058: * <p>
059: * Note that both the position and the array of distances are
060: * specified in the local coordinate system of this node.
061: */
062: public class DistanceLOD extends LOD {
063:
064: private double distances[];
065: private Point3f position = new Point3f(0.0f, 0.0f, 0.0f);
066:
067: // variables for processStimulus
068: private Point3f center = new Point3f();
069: private Point3f viewPosition = new Point3f();
070:
071: /**
072: * Constructs and initializes a DistanceLOD node with default values.
073: * Note that the default constructor creates a DistanceLOD object with
074: * a single distance value set to 0.0 and is, therefore, not useful.
075: */
076: public DistanceLOD() {
077: distances = new double[1];
078: distances[0] = 0.0;
079: }
080:
081: /**
082: * Constructs and initializes a DistanceLOD node with the specified
083: * array of distances and a default position of (0,0,0).
084: * @param distances an array of values representing LOD cutoff distances
085: */
086: public DistanceLOD(float[] distances) {
087: this .distances = new double[distances.length];
088:
089: for (int i = 0; i < distances.length; i++) {
090: this .distances[i] = (double) distances[i];
091: }
092: }
093:
094: /**
095: * Constructs and initializes a DistanceLOD node with the specified
096: * array of distances and the specified position.
097: * @param distances an array of values representing LOD cutoff distances
098: * @param position the position of this LOD node
099: */
100: public DistanceLOD(float[] distances, Point3f position) {
101: this .distances = new double[distances.length];
102:
103: for (int i = 0; i < distances.length; i++) {
104: this .distances[i] = (double) distances[i];
105: }
106: this .position.set(position);
107: }
108:
109: /**
110: * Sets the position of this LOD node. This position is specified in
111: * the local coordinates of this node, and is
112: * the position from which the distance to the viewer is computed.
113: * @param position the new position
114: */
115: public void setPosition(Point3f position) {
116: if (((NodeRetained) retained).staticTransform != null) {
117: ((NodeRetained) retained).staticTransform.transform
118: .transform(position, this .position);
119: } else {
120: this .position.set(position);
121: }
122: }
123:
124: /**
125: * Retrieves the current position of this LOD node. This position is
126: * in the local coordinates of this node.
127: * @param position the object that will receive the current position
128: */
129: public void getPosition(Point3f position) {
130: if (((NodeRetained) retained).staticTransform != null) {
131: Transform3D invTransform = ((NodeRetained) retained).staticTransform
132: .getInvTransform();
133: invTransform.transform(this .position, position);
134: } else {
135: position.set(this .position);
136: }
137: }
138:
139: /**
140: * Returns a count of the number of LOD distance cut-off parameters.
141: * Note that the number of levels of detail (children of the Switch node)
142: * is one greater than the number of distance values.
143: * @return a count of the LOD cut-off distances
144: */
145: public int numDistances() {
146: return distances.length;
147: }
148:
149: /**
150: * Returns a particular LOD cut-off distance.
151: * @param whichDistance an index specifying which LOD distance to return
152: * @return the cut-off distance value associated with the index provided
153: */
154: public double getDistance(int whichDistance) {
155: return distances[whichDistance];
156: }
157:
158: /**
159: * Sets a particular LOD cut-off distance.
160: * @param whichDistance an index specifying which LOD distance to modify
161: * @param distance the cut-off distance associated with the index provided
162: */
163: public void setDistance(int whichDistance, double distance) {
164: distances[whichDistance] = distance;
165: }
166:
167: /**
168: * Initialize method that sets up initial wakeup criteria.
169: */
170: public void initialize() {
171: // Insert wakeup condition into queue
172: wakeupOn(wakeupFrame);
173: }
174:
175: /**
176: * Process stimulus method that computes appropriate level of detail.
177: * @param criteria an enumeration of the criteria that caused the
178: * stimulus
179: */
180: public void processStimulus(Enumeration criteria) {
181:
182: // compute distance in virtual world
183: View v = this .getView();
184: if (v == null) {
185: wakeupOn(wakeupFrame);
186: return;
187: }
188:
189: ViewPlatform vp = v.getViewPlatform();
190: if (vp == null) {
191: return;
192: }
193:
194: // Handle stimulus
195: double viewDistance = 0.0;
196: int nSwitches, i, index = 0;
197:
198: Transform3D localToWorldTrans = new Transform3D();
199:
200: localToWorldTrans.set(((NodeRetained) this .retained)
201: .getCurrentLocalToVworld());
202:
203: // DistanceLOD's location in virutal world
204: localToWorldTrans.transform(position, center);
205:
206: viewPosition.x = (float) ((ViewPlatformRetained) vp.retained).schedSphere.center.x;
207: viewPosition.y = (float) ((ViewPlatformRetained) vp.retained).schedSphere.center.y;
208: viewPosition.z = (float) ((ViewPlatformRetained) vp.retained).schedSphere.center.z;
209: viewDistance = center.distance(viewPosition);
210:
211: // convert distance into local coordinates
212: viewDistance = viewDistance
213: / localToWorldTrans.getDistanceScale();
214:
215: nSwitches = numSwitches();
216:
217: index = distances.length; // viewDistance > distances[n-1]
218:
219: if (viewDistance <= distances[0]) {
220: index = 0;
221: } else {
222: for (i = 1; i < distances.length; i++) {
223: if ((viewDistance > distances[i - 1])
224: && (viewDistance <= distances[i])) {
225: index = i;
226: break;
227: }
228: }
229: }
230:
231: for (i = nSwitches - 1; i >= 0; i--) {
232: Switch sw = getSwitch(i);
233: // Optimize, this behavior is passive
234: // Note that we skip the capability check for getWhichChild()
235: if (((SwitchRetained) sw.retained).getWhichChild() != index) {
236: sw.setWhichChild(index);
237: }
238: }
239: // Insert wakeup condition into queue
240: wakeupOn(wakeupFrame);
241:
242: }
243:
244: /**
245: * Used to create a new instance of the node. This routine is called
246: * by <code>cloneTree</code> to duplicate the current node.
247: * @param forceDuplicate when set to <code>true</code>, causes the
248: * <code>duplicateOnCloneTree</code> flag to be ignored. When
249: * <code>false</code>, the value of each node's
250: * <code>duplicateOnCloneTree</code> variable determines whether
251: * NodeComponent data is duplicated or copied.
252: *
253: * @see Node#cloneTree
254: * @see Node#cloneNode
255: * @see Node#duplicateNode
256: * @see NodeComponent#setDuplicateOnCloneTree
257: */
258: public Node cloneNode(boolean forceDuplicate) {
259: DistanceLOD d = new DistanceLOD();
260: d.duplicateNode(this , forceDuplicate);
261: return d;
262: }
263:
264: /**
265: * Copies all DistanceLOD information from
266: * <code>originalNode</code> into
267: * the current node. This method is called from the
268: * <code>cloneNode</code> method which is, in turn, called by the
269: * <code>cloneTree</code> method.<P>
270: *
271: * @param originalNode the original node to duplicate.
272: * @param forceDuplicate when set to <code>true</code>, causes the
273: * <code>duplicateOnCloneTree</code> flag to be ignored. When
274: * <code>false</code>, the value of each node's
275: * <code>duplicateOnCloneTree</code> variable determines whether
276: * NodeComponent data is duplicated or copied.
277: *
278: * @exception RestrictedAccessException if this object is part of a live
279: * or compiled scenegraph.
280: *
281: * @see Node#duplicateNode
282: * @see Node#cloneTree
283: * @see NodeComponent#setDuplicateOnCloneTree
284: */
285: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
286: super .duplicateAttributes(originalNode, forceDuplicate);
287:
288: DistanceLOD lod = (DistanceLOD) originalNode;
289:
290: int numD = lod.numDistances();
291:
292: // No API available to set the size of this array after initialize
293: this .distances = new double[numD];
294:
295: for (int i = 0; i < numD; i++)
296: setDistance(i, lod.getDistance(i));
297:
298: Point3f p = new Point3f();
299: lod.getPosition(p);
300: setPosition(p);
301: }
302:
303: void mergeTransform(TransformGroupRetained xform) {
304: xform.transform.transform(position, position);
305: }
306: }
|