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