001: /*
002: * $RCSfile: KBRotPosScaleSplinePathInterpolator.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.4 $
041: * $Date: 2007/02/09 17:20:11 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.behaviors.interpolators;
046:
047: import javax.media.j3d.*;
048: import java.util.*;
049: import javax.vecmath.*;
050:
051: /**
052: * KBRotPosScaleSplinePathInterpolator; A rotation and position path
053: * interpolation behavior node using Kochanek-Bartels cubic splines
054: * (also known as TCB or Tension-Continuity-Bias Splines).
055: *
056: * @since Java3D 1.2
057: */
058:
059: /**
060: * KBRotPosScaleSplinePathInterpolator behavior. This class defines a
061: * behavior that varies the rotational, translational, and scale components
062: * of its target TransformGroup by using the Kochanek-Bartels cubic spline
063: * interpolation to interpolate among a series of key frames
064: * (using the value generated by the specified Alpha object). The
065: * interpolated position, orientation, and scale are used to generate
066: * a transform in the local coordinate system of this interpolator.
067: */
068:
069: public class KBRotPosScaleSplinePathInterpolator extends
070: KBSplinePathInterpolator {
071:
072: private Transform3D rotation = new Transform3D();
073:
074: private Matrix4d pitchMat = new Matrix4d(); // pitch matrix
075: private Matrix4d bankMat = new Matrix4d(); // bank matrix
076: private Matrix4d tMat = new Matrix4d(); // transformation matrix
077: private Matrix4d sMat = new Matrix4d(); // scale matrix
078: //Quat4f iQuat = new Quat4f(); // interpolated quaternion
079: private Vector3f iPos = new Vector3f(); // interpolated position
080: private Point3f iScale = new Point3f(); // interpolated scale
081: float iHeading, iPitch, iBank; // interpolated heading,
082: // pitch and bank
083:
084: KBCubicSplineCurve cubicSplineCurve = new KBCubicSplineCurve();
085: KBCubicSplineSegment cubicSplineSegments[];
086: int numSegments;
087: int currentSegmentIndex;
088: KBCubicSplineSegment currentSegment;
089:
090: // non-public, default constructor used by cloneNode
091: KBRotPosScaleSplinePathInterpolator() {
092: }
093:
094: /**
095: * Constructs a new KBRotPosScaleSplinePathInterpolator object that
096: * varies the rotation, translation, and scale of the target
097: * TransformGroup's transform. At least 2 key frames are required for
098: * this interpolator. The first key
099: * frame's knot must have a value of 0.0 and the last knot must have a
100: * value of 1.0. An intermediate key frame with index k must have a
101: * knot value strictly greater than the knot value of a key frame with
102: * index less than k.
103: * @param alpha the alpha object for this interpolator
104: * @param target the TransformGroup node affected by this interpolator
105: * @param axisOfTransform the transform that specifies the local
106: * coordinate system in which this interpolator operates.
107: * @param keys an array of key frames that defien the motion path
108: */
109: public KBRotPosScaleSplinePathInterpolator(Alpha alpha,
110: TransformGroup target, Transform3D axisOfTransform,
111: KBKeyFrame keys[]) {
112: super (alpha, target, axisOfTransform, keys);
113:
114: // Create a spline curve using the derived key frames
115: cubicSplineCurve = new KBCubicSplineCurve(this .keyFrames);
116: numSegments = cubicSplineCurve.numSegments;
117:
118: }
119:
120: /**
121: * @deprecated As of Java 3D version 1.3, replaced by
122: * <code>TransformInterpolator.setTransformAxis(Transform3D)</code>
123: */
124: public void setAxisOfRotPosScale(Transform3D axisOfRotPosScale) {
125: setTransformAxis(axisOfRotPosScale);
126: }
127:
128: /**
129: * @deprecated As of Java 3D version 1.3, replaced by
130: * <code>TransformInterpolator.getTransformAxis()</code>
131: */
132: public Transform3D getAxisOfRotPosScale() {
133: return getTransformAxis();
134: }
135:
136: /**
137: * Set the key frame at the specified index to <code>keyFrame</code>
138: * @param index Index of the key frame to change
139: * @param keyFrame The new key frame
140: */
141: public void setKeyFrame(int index, KBKeyFrame keyFrame) {
142: super .setKeyFrame(index, keyFrame);
143:
144: // TODO Optimize this
145: // Create a spline curve using the derived key frames
146: cubicSplineCurve = new KBCubicSplineCurve(this .keyFrames);
147: numSegments = cubicSplineCurve.numSegments;
148: }
149:
150: /**
151: * Set all the key frames
152: * @param keyFrame The new key frames
153: */
154: public void setKeyFrames(KBKeyFrame[] keyFrame) {
155: super .setKeyFrames(keyFrame);
156:
157: // Create a spline curve using the derived key frames
158: cubicSplineCurve = new KBCubicSplineCurve(this .keyFrames);
159: numSegments = cubicSplineCurve.numSegments;
160: }
161:
162: /**
163: * Computes the new transform for this interpolator for a given
164: * alpha value.
165: *
166: * @param alphaValue alpha value between 0.0 and 1.0
167: * @param transform object that receives the computed transform for
168: * the specified alpha value
169: *
170: * @since Java 3D 1.3
171: */
172: public void computeTransform(float alphaValue, Transform3D transform) {
173: // compute the current value of u from alpha and the
174: // determine lower and upper knot points
175: computePathInterpolation(alphaValue);
176:
177: // Determine the segment within which we will be interpolating
178: currentSegmentIndex = this .lowerKnot - 1;
179:
180: // if we are at the start of the curve
181: if (currentSegmentIndex == 0 && currentU == 0f) {
182:
183: iHeading = keyFrames[1].heading;
184: iPitch = keyFrames[1].pitch;
185: iBank = keyFrames[1].bank;
186: iPos.set(keyFrames[1].position);
187: iScale.set(keyFrames[1].scale);
188:
189: // if we are at the end of the curve
190: } else if (currentSegmentIndex == (numSegments - 1)
191: && currentU == 1.0) {
192:
193: iHeading = keyFrames[upperKnot].heading;
194: iPitch = keyFrames[upperKnot].pitch;
195: iBank = keyFrames[upperKnot].bank;
196: iPos.set(keyFrames[upperKnot].position);
197: iScale.set(keyFrames[upperKnot].scale);
198:
199: // if we are somewhere in between the curve
200: } else {
201:
202: // Get a reference to the current spline segment i.e. the
203: // one bounded by lowerKnot and upperKnot
204: currentSegment = cubicSplineCurve
205: .getSegment(currentSegmentIndex);
206:
207: // interpolate quaternions
208: iHeading = currentSegment.getInterpolatedHeading(currentU);
209: iPitch = currentSegment.getInterpolatedPitch(currentU);
210: iBank = currentSegment.getInterpolatedBank(currentU);
211:
212: // interpolate position
213: currentSegment
214: .getInterpolatedPositionVector(currentU, iPos);
215:
216: // interpolate position
217: currentSegment.getInterpolatedScale(currentU, iScale);
218:
219: }
220:
221: // Generate a transformation matrix in tMat using interpolated
222: // heading, pitch and bank
223: pitchMat.setIdentity();
224: pitchMat.rotX(-iPitch);
225: bankMat.setIdentity();
226: bankMat.rotZ(iBank);
227: tMat.setIdentity();
228: tMat.rotY(-iHeading);
229: tMat.mul(pitchMat);
230: tMat.mul(bankMat);
231:
232: // TODO: Handle Non-Uniform scale
233: // Currently this interpolator does not handle non uniform scale
234: // We cheat by just taking the x scale component
235:
236: // Scale the transformation matrix
237: sMat.set((double) iScale.x);
238: tMat.mul(sMat);
239:
240: // Set the translation components.
241: tMat.m03 = iPos.x;
242: tMat.m13 = iPos.y;
243: tMat.m23 = iPos.z;
244: rotation.set(tMat);
245:
246: // construct a Transform3D from: axis * rotation * axisInverse
247: transform.mul(axis, rotation);
248: transform.mul(transform, axisInverse);
249: }
250:
251: /**
252: * Copies KBRotPosScaleSplinePathInterpolator information from
253: * <code>originalNode</code> into
254: * the current node. This method is called from the
255: * <code>cloneNode</code> method which is, in turn, called by the
256: * <code>cloneTree</code> method.<P>
257: *
258: * @param forceDuplicate when set to <code>true</code>, causes the
259: * <code>duplicateOnCloneTree</code> flag to be ignored. When
260: * <code>false</code>, the value of each node's
261: * <code>duplicateOnCloneTree</code> variable determines whether
262: * NodeComponent data is duplicated or copied.
263: *
264: * @exception RestrictedAccessException if this object is part of a live
265: * or compiled scenegraph.
266: *
267: * @see Node#duplicateNode
268: * @see Node#cloneTree
269: * @see NodeComponent#setDuplicateOnCloneTree
270: */
271: public Node cloneNode(boolean forceDuplicate) {
272: KBRotPosScaleSplinePathInterpolator spline = new KBRotPosScaleSplinePathInterpolator();
273:
274: spline.duplicateNode(this , forceDuplicate);
275: return spline;
276: }
277:
278: /**
279: * Copies KBRotPosScaleSplinePathInterpolator information from
280: * <code>originalNode</code> into
281: * the current node. This method is called from the
282: * <code>cloneNode</code> method which is, in turn, called by the
283: * <code>cloneTree</code> method.<P>
284: *
285: * @param originalNode the original node to duplicate.
286: * @param forceDuplicate when set to <code>true</code>, causes the
287: * <code>duplicateOnCloneTree</code> flag to be ignored. When
288: * <code>false</code>, the value of each node's
289: * <code>duplicateOnCloneTree</code> variable determines whether
290: * NodeComponent data is duplicated or copied.
291: *
292: * @exception RestrictedAccessException if this object is part of a live
293: * or compiled scenegraph.
294: *
295: * @see Node#duplicateNode
296: * @see Node#cloneTree
297: * @see NodeComponent#setDuplicateOnCloneTree
298: */
299: public void duplicateNode(Node originalNode, boolean forceDuplicate) {
300: super .duplicateNode(originalNode, forceDuplicate);
301:
302: KBRotPosScaleSplinePathInterpolator interpolator = (KBRotPosScaleSplinePathInterpolator) originalNode;
303: setAxisOfRotPosScale(interpolator.axis);
304: target = interpolator.target;
305: cubicSplineCurve = new KBCubicSplineCurve(
306: interpolator.keyFrames);
307: numSegments = cubicSplineCurve.numSegments;
308: }
309: }
|