001: /*
002: * $RCSfile: RotPosPathInterpolator.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.5 $
028: * $Date: 2008/02/28 20:17:29 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.Vector3f;
035: import javax.vecmath.Quat4f;
036: import javax.vecmath.Matrix4d;
037: import javax.vecmath.Point3f;
038:
039: /**
040: * RotPosPathInterpolator behavior. This class defines a behavior that
041: * modifies the rotational and translational components of its target
042: * TransformGroup by linearly interpolating among a series of predefined
043: * knot/positon and knot/orientation pairs (using the value generated
044: * by the specified Alpha object). The interpolated position and
045: * orientation are used to generate a transform in the local coordinate
046: * system of this interpolator.
047: */
048:
049: public class RotPosPathInterpolator extends PathInterpolator {
050: private Transform3D rotation = new Transform3D();
051:
052: private Vector3f pos = new Vector3f();
053: private Quat4f tQuat = new Quat4f();
054: private Matrix4d tMat = new Matrix4d();
055:
056: // Arrays of quaternions and positions at each knot
057: private Quat4f quats[];
058: private Point3f positions[];
059: private float prevInterpolationValue = Float.NaN;
060:
061: // We can't use a boolean flag since it is possible
062: // that after alpha change, this procedure only run
063: // once at alpha.finish(). So the best way is to
064: // detect alpha value change.
065: private float prevAlphaValue = Float.NaN;
066: private WakeupCriterion passiveWakeupCriterion = (WakeupCriterion) new WakeupOnElapsedFrames(
067: 0, true);
068:
069: // non-public, default constructor used by cloneNode
070: RotPosPathInterpolator() {
071: }
072:
073: /**
074: * Constructs a new interpolator that varies the rotation and translation
075: * of the target TransformGroup's transform.
076: * @param alpha the alpha object for this interpolator
077: * @param target the TransformGroup node affected by this translator
078: * @param axisOfTransform the transform that defines the local coordinate
079: * system in which this interpolator operates
080: * @param knots an array of knot values that specify interpolation points.
081: * @param quats an array of quaternion values at the knots.
082: * @param positions an array of position values at the knots.
083: * @exception IllegalArgumentException if the lengths of the
084: * knots, quats, and positions arrays are not all the same.
085: */
086: public RotPosPathInterpolator(Alpha alpha, TransformGroup target,
087: Transform3D axisOfTransform, float[] knots, Quat4f[] quats,
088: Point3f[] positions) {
089: super (alpha, target, axisOfTransform, knots);
090:
091: if (knots.length != positions.length)
092: throw new IllegalArgumentException(J3dI18N
093: .getString("RotPosPathInterpolator0"));
094:
095: if (knots.length != quats.length)
096: throw new IllegalArgumentException(J3dI18N
097: .getString("RotPosPathInterpolator0"));
098:
099: setPathArrays(quats, positions);
100: }
101:
102: /**
103: * Sets the quat at the specified index for this interpolator.
104: * @param index the index to be changed
105: * @param quat the new quat value
106: */
107: public void setQuat(int index, Quat4f quat) {
108: this .quats[index].set(quat);
109: }
110:
111: /**
112: * Retrieves the quat value at the specified index.
113: * @param index the index of the value requested
114: * @param quat the quat to receive the quat value at the index
115: */
116: public void getQuat(int index, Quat4f quat) {
117: quat.set(this .quats[index]);
118: }
119:
120: /**
121: * Sets the position at the specified index for this
122: * interpolator.
123: * @param index the index to be changed
124: * @param position the new position value
125: */
126: public void setPosition(int index, Point3f position) {
127: this .positions[index].set(position);
128: }
129:
130: /**
131: * Retrieves the position value at the specified index.
132: * @param index the index of the value requested
133: * @param position the position to receive the position value at the index
134: */
135: public void getPosition(int index, Point3f position) {
136: position.set(this .positions[index]);
137: }
138:
139: /**
140: * Replaces the existing arrays of knot values, quaternion
141: * values, and position values with the specified arrays.
142: * The arrays of knots, quats, and positions are copied
143: * into this interpolator object.
144: * @param knots a new array of knot values that specify
145: * interpolation points.
146: * @param quats a new array of quaternion values at the knots.
147: * @param positions a new array of position values at the knots.
148: * @exception IllegalArgumentException if the lengths of the
149: * knots, quats, and positions arrays are not all the same.
150: *
151: * @since Java 3D 1.2
152: */
153: public void setPathArrays(float[] knots, Quat4f[] quats,
154: Point3f[] positions) {
155:
156: if (knots.length != quats.length)
157: throw new IllegalArgumentException(J3dI18N
158: .getString("RotPosPathInterpolator0"));
159:
160: if (knots.length != positions.length)
161: throw new IllegalArgumentException(J3dI18N
162: .getString("RotPosPathInterpolator0"));
163:
164: setKnots(knots);
165: setPathArrays(quats, positions);
166: }
167:
168: // Set the specific arrays for this path interpolator
169: private void setPathArrays(Quat4f[] quats, Point3f[] positions) {
170:
171: this .quats = new Quat4f[quats.length];
172: for (int i = 0; i < quats.length; i++) {
173: this .quats[i] = new Quat4f();
174: this .quats[i].set(quats[i]);
175: }
176:
177: this .positions = new Point3f[positions.length];
178: for (int i = 0; i < positions.length; i++) {
179: this .positions[i] = new Point3f();
180: this .positions[i].set(positions[i]);
181: }
182: }
183:
184: /**
185: * Copies the array of quaternion values from this interpolator
186: * into the specified array.
187: * The array must be large enough to hold all of the quats.
188: * The individual array elements must be allocated by the caller.
189: * @param quats array that will receive the quats.
190: *
191: * @since Java 3D 1.2
192: */
193: public void getQuats(Quat4f[] quats) {
194: for (int i = 0; i < this .quats.length; i++) {
195: quats[i].set(this .quats[i]);
196: }
197: }
198:
199: /**
200: * Copies the array of position values from this interpolator
201: * into the specified array.
202: * The array must be large enough to hold all of the positions.
203: * The individual array elements must be allocated by the caller.
204: * @param positions array that will receive the positions.
205: *
206: * @since Java 3D 1.2
207: */
208: public void getPositions(Point3f[] positions) {
209: for (int i = 0; i < this .positions.length; i++) {
210: positions[i].set(this .positions[i]);
211: }
212: }
213:
214: /**
215: * @deprecated As of Java 3D version 1.3, replaced by
216: * <code>TransformInterpolator.setTransformAxis(Transform3D)</code>
217: */
218:
219: public void setAxisOfRotPos(Transform3D axisOfRotPos) {
220: setTransformAxis(axisOfRotPos);
221: }
222:
223: /**
224: * @deprecated As of Java 3D version 1.3, replaced by
225: * <code>TransformInterpolator.getTransformAxis()</code>
226: */
227: public Transform3D getAxisOfRotPos() {
228: return getTransformAxis();
229: }
230:
231: /**
232: * Computes the new transform for this interpolator for a given
233: * alpha value.
234: *
235: * @param alphaValue alpha value between 0.0 and 1.0
236: * @param transform object that receives the computed transform for
237: * the specified alpha value
238: *
239: * @since Java 3D 1.3
240: */
241: public void computeTransform(float alphaValue, Transform3D transform) {
242: double quatDot;
243:
244: computePathInterpolation(alphaValue);
245:
246: if (currentKnotIndex == 0 && currentInterpolationValue == 0f) {
247: tQuat.x = quats[0].x;
248: tQuat.y = quats[0].y;
249: tQuat.z = quats[0].z;
250: tQuat.w = quats[0].w;
251: pos.x = positions[0].x;
252: pos.y = positions[0].y;
253: pos.z = positions[0].z;
254: } else {
255: quatDot = quats[currentKnotIndex].x
256: * quats[currentKnotIndex + 1].x
257: + quats[currentKnotIndex].y
258: * quats[currentKnotIndex + 1].y
259: + quats[currentKnotIndex].z
260: * quats[currentKnotIndex + 1].z
261: + quats[currentKnotIndex].w
262: * quats[currentKnotIndex + 1].w;
263: if (quatDot < 0) {
264: tQuat.x = quats[currentKnotIndex].x
265: + (-quats[currentKnotIndex + 1].x - quats[currentKnotIndex].x)
266: * currentInterpolationValue;
267: tQuat.y = quats[currentKnotIndex].y
268: + (-quats[currentKnotIndex + 1].y - quats[currentKnotIndex].y)
269: * currentInterpolationValue;
270: tQuat.z = quats[currentKnotIndex].z
271: + (-quats[currentKnotIndex + 1].z - quats[currentKnotIndex].z)
272: * currentInterpolationValue;
273: tQuat.w = quats[currentKnotIndex].w
274: + (-quats[currentKnotIndex + 1].w - quats[currentKnotIndex].w)
275: * currentInterpolationValue;
276: } else {
277: tQuat.x = quats[currentKnotIndex].x
278: + (quats[currentKnotIndex + 1].x - quats[currentKnotIndex].x)
279: * currentInterpolationValue;
280: tQuat.y = quats[currentKnotIndex].y
281: + (quats[currentKnotIndex + 1].y - quats[currentKnotIndex].y)
282: * currentInterpolationValue;
283: tQuat.z = quats[currentKnotIndex].z
284: + (quats[currentKnotIndex + 1].z - quats[currentKnotIndex].z)
285: * currentInterpolationValue;
286: tQuat.w = quats[currentKnotIndex].w
287: + (quats[currentKnotIndex + 1].w - quats[currentKnotIndex].w)
288: * currentInterpolationValue;
289: }
290: pos.x = positions[currentKnotIndex].x
291: + (positions[currentKnotIndex + 1].x - positions[currentKnotIndex].x)
292: * currentInterpolationValue;
293: pos.y = positions[currentKnotIndex].y
294: + (positions[currentKnotIndex + 1].y - positions[currentKnotIndex].y)
295: * currentInterpolationValue;
296: pos.z = positions[currentKnotIndex].z
297: + (positions[currentKnotIndex + 1].z - positions[currentKnotIndex].z)
298: * currentInterpolationValue;
299: }
300: tQuat.normalize();
301:
302: // Set the rotation components
303: tMat.set(tQuat);
304:
305: // Set the translation components.
306: tMat.m03 = pos.x;
307: tMat.m13 = pos.y;
308: tMat.m23 = pos.z;
309: rotation.set(tMat);
310:
311: // construct a Transform3D from: axis * rotation * axisInverse
312: transform.mul(axis, rotation);
313: transform.mul(transform, axisInverse);
314: }
315:
316: /**
317: * Used to create a new instance of the node. This routine is called
318: * by <code>cloneTree</code> to duplicate the current node.
319: * @param forceDuplicate when set to <code>true</code>, causes the
320: * <code>duplicateOnCloneTree</code> flag to be ignored. When
321: * <code>false</code>, the value of each node's
322: * <code>duplicateOnCloneTree</code> variable determines whether
323: * NodeComponent data is duplicated or copied.
324: *
325: * @see Node#cloneTree
326: * @see Node#cloneNode
327: * @see Node#duplicateNode
328: * @see NodeComponent#setDuplicateOnCloneTree
329: */
330: public Node cloneNode(boolean forceDuplicate) {
331: RotPosPathInterpolator rppi = new RotPosPathInterpolator();
332: rppi.duplicateNode(this , forceDuplicate);
333: return rppi;
334: }
335:
336: /**
337: * Copies all RotPosPathInterpolator information from
338: * <code>originalNode</code> into
339: * the current node. This method is called from the
340: * <code>cloneNode</code> method which is, in turn, called by the
341: * <code>cloneTree</code> method.<P>
342: *
343: * @param originalNode the original node to duplicate.
344: * @param forceDuplicate when set to <code>true</code>, causes the
345: * <code>duplicateOnCloneTree</code> flag to be ignored. When
346: * <code>false</code>, the value of each node's
347: * <code>duplicateOnCloneTree</code> variable determines whether
348: * NodeComponent data is duplicated or copied.
349: *
350: * @exception RestrictedAccessException if this object is part of a live
351: * or compiled scenegraph.
352: *
353: * @see Node#duplicateNode
354: * @see Node#cloneTree
355: * @see NodeComponent#setDuplicateOnCloneTree
356: */
357: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
358: super .duplicateAttributes(originalNode, forceDuplicate);
359:
360: RotPosPathInterpolator ri = (RotPosPathInterpolator) originalNode;
361:
362: int len = ri.getArrayLengths();
363:
364: // No API availble to set array size, so explicitly set it here
365: positions = new Point3f[len];
366: quats = new Quat4f[len];
367:
368: Point3f point = new Point3f();
369: Quat4f quat = new Quat4f();
370:
371: for (int i = 0; i < len; i++) {
372: positions[i] = new Point3f();
373: ri.getPosition(i, point);
374: setPosition(i, point);
375:
376: quats[i] = new Quat4f();
377: ri.getQuat(i, quat);
378: setQuat(i, quat);
379: }
380:
381: }
382: }
|