001: /*
002: * $RCSfile: KBSplinePathInterpolator.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:12 $
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: import com.sun.j3d.internal.J3dUtilsI18N;
051:
052: /**
053: * KBSplinePathInterpolator behavior. This class defines the base class for
054: * all Kochanek-Bartels (also known as TCB or Tension-Continuity-Bias)
055: * Spline Path Interpolators.
056: *
057: * @since Java3D 1.2
058: */
059:
060: public abstract class KBSplinePathInterpolator extends
061: TransformInterpolator {
062:
063: private int keysLength;
064: /**
065: * An array of KBKeyFrame for interpolator
066: */
067: protected KBKeyFrame[] keyFrames;
068:
069: /**
070: * This value is the distance between knots
071: * value which can be used in further calculations by the subclass.
072: */
073: protected float currentU;
074:
075: /**
076: * The lower knot
077: */
078: protected int lowerKnot;
079: /**
080: * The upper knot
081: */
082: protected int upperKnot;
083:
084: /**
085: * Constructs a KBSplinePathInterpolator node with a null alpha value and
086: * a null target of TransformGroup
087: *
088: * @since Java 3D 1.3
089: */
090: KBSplinePathInterpolator() {
091: }
092:
093: /**
094: * @deprecated As of Java 3D version 1.3, replaced by
095: * <code>KBSplinePathInterpolator(Alpha, TransformGroup, TCBKeyFrame[]) </code>
096: */
097: public KBSplinePathInterpolator(Alpha alpha, KBKeyFrame keys[]) {
098: this (alpha, null, keys);
099: }
100:
101: /**
102: * Constructs a new KBSplinePathInterpolator object that interpolates
103: * between keyframes with specified alpha, target and an default
104: * axisOfTranform set to identity.
105: * It takes at least two key frames. The first key
106: * frame's knot must have a value of 0.0 and the last knot must have a
107: * value of 1.0. An intermediate key frame with index k must have a
108: * knot value strictly greater than the knot value of a key frame with
109: * index less than k. Once this constructor has all the valid key frames
110: * it creates its own list of key fames that duplicates the first key frame
111: * at the beginning of the list and the last key frame at the end of the
112: * list.
113: * @param alpha the alpha object for this interpolator
114: * @param target the TransformGroup node affected by this interpolator
115: * @param keys an array of KBKeyFrame. Requires at least two key frames.
116: *
117: * @since Java 3D 1.3
118: */
119: public KBSplinePathInterpolator(Alpha alpha, TransformGroup target,
120: KBKeyFrame keys[]) {
121: super (alpha, target);
122: processKeyFrames(keys);
123: }
124:
125: /**
126: * Constructs a new KBSplinePathInterpolator object that interpolates
127: * between keyframes with specified alpha, target and axisOfTransform.
128: * It takes at least two key frames. The first key
129: * frame's knot must have a value of 0.0 and the last knot must have a
130: * value of 1.0. An intermediate key frame with index k must have a
131: * knot value strictly greater than the knot value of a key frame with
132: * index less than k. Once this constructor has all the valid key frames
133: * it creates its own list of key fames that duplicates the first key frame
134: * at the beginning of the list and the last key frame at the end of the
135: * list.
136: * @param alpha the alpha object for this interpolator
137: * @param target the TransformGroup node affected by this interpolator
138: * @param axisOfTransform the transform that defines the local coordinate
139: * @param keys an array of KBKeyFrame. Requires at least two key frames
140: *
141: * @since Java 3D 1.3
142: */
143: public KBSplinePathInterpolator(Alpha alpha, TransformGroup target,
144: Transform3D axisOfTransform, KBKeyFrame keys[]) {
145: super (alpha, target, axisOfTransform);
146: processKeyFrames(keys);
147: }
148:
149: /**
150: * Process the new array of key frames
151: */
152: private void processKeyFrames(KBKeyFrame[] keys) {
153:
154: // Make sure that we have at least two key frames
155: keysLength = keys.length;
156: if (keysLength < 2) {
157: throw new IllegalArgumentException(J3dUtilsI18N
158: .getString("KBSplinePathInterpolator0"));
159:
160: }
161:
162: // Make sure that the first key frame's knot is equal to 0.0
163: if (keys[0].knot < -0.0001 || keys[0].knot > 0.0001) {
164: throw new IllegalArgumentException(J3dUtilsI18N
165: .getString("KBSplinePathInterpolator1"));
166: }
167:
168: // Make sure that the last key frames knot is equal to 1.0
169: if (keys[keysLength - 1].knot - 1.0 < -0.0001
170: || keys[keysLength - 1].knot - 1.0 > 0.0001) {
171: throw new IllegalArgumentException(J3dUtilsI18N
172: .getString("KBSplinePathInterpolator2"));
173: }
174:
175: // Make sure that all the knots are in sequence
176: for (int i = 0; i < keysLength; i++) {
177: if (i > 0 && keys[i].knot < keys[i - 1].knot) {
178: throw new IllegalArgumentException(J3dUtilsI18N
179: .getString("KBSplinePathInterpolator3"));
180: }
181: }
182:
183: // Make space for a leading and trailing key frame in addition to
184: // the keys passed in
185: keyFrames = new KBKeyFrame[keysLength + 2];
186: keyFrames[0] = new KBKeyFrame();
187: keyFrames[0] = keys[0];
188: for (int i = 1; i < keysLength + 1; i++) {
189: keyFrames[i] = keys[i - 1];
190: }
191: keyFrames[keysLength + 1] = new KBKeyFrame();
192: keyFrames[keysLength + 1] = keys[keysLength - 1];
193:
194: // Make key frame length reflect the 2 added key frames
195: keysLength += 2;
196: }
197:
198: /**
199: * This method retrieves the length of the key frame array.
200: * @return the number of key frames
201: */
202: public int getArrayLength() {
203: return keysLength - 2;
204: }
205:
206: /**
207: * This method retrieves the key frame at the specified index.
208: * @param index the index of the key frame requested
209: * @return the key frame at the associated index
210: */
211: public KBKeyFrame getKeyFrame(int index) {
212:
213: // We add 1 to index because we have added a leading keyFrame
214: return this .keyFrames[index + 1];
215: }
216:
217: /**
218: * Set the key frame at the specified index to <code>keyFrame</code>
219: * @param index Index of the key frame to change
220: * @param keyFrame The new key frame
221: * @since Java 3D 1.3
222: */
223: public void setKeyFrame(int index, KBKeyFrame keyFrame) {
224: this .keyFrames[index + 1] = keyFrame;
225: }
226:
227: /**
228: * Set allthe key frames
229: * @param keyFrames The new key frame
230: * @since Java 3D 1.3
231: */
232: public void setKeyFrames(KBKeyFrame[] keyFrames) {
233: processKeyFrames(keyFrames);
234: }
235:
236: /**
237: * @deprecated As of Java 3D version 1.3, replaced by
238: * <code>computePathInterpolation(float)</code>
239: */
240: protected void computePathInterpolation() {
241: computePathInterpolation(this .getAlpha().value());
242: }
243:
244: /**
245: * This method computes the bounding knot indices and interpolation value
246: * "CurrentU" given the current value of the knots[] array and the
247: * specified alpha value
248: * @param alphaValue alpha value between 0.0 and 1.0
249: *
250: * @since Java 3D 1.3
251: */
252: protected void computePathInterpolation(float alphaValue) {
253:
254: // skip knots till we find the two we fall between
255: int i = 1;
256: int len = keysLength - 2;
257: while ((alphaValue > keyFrames[i].knot) && (i < len)) {
258: i++;
259: }
260:
261: if (i == 1) {
262: currentU = 0f;
263: lowerKnot = 1;
264: upperKnot = 2;
265: } else {
266: currentU = (alphaValue - keyFrames[i - 1].knot)
267: / (keyFrames[i].knot - keyFrames[i - 1].knot);
268: lowerKnot = i - 1;
269: upperKnot = i;
270: }
271: }
272:
273: /**
274: * Copies all KBSplinePathInterpolator information from
275: * <code>originalNode</code> into
276: * the current node. This method is called from the
277: * <code>cloneNode</code> method which is, in turn, called by the
278: * <code>cloneTree</code> method.<P>
279: *
280: * @param originalNode the original node to duplicate.
281: * @param forceDuplicate when set to <code>true</code>, causes the
282: * <code>duplicateOnCloneTree</code> flag to be ignored. When
283: * <code>false</code>, the value of each node's
284: * <code>duplicateOnCloneTree</code> variable determines whether
285: * NodeComponent data is duplicated or copied.
286: *
287: * @exception RestrictedAccessException if this object is part of a live
288: * or compiled scenegraph.
289: *
290: * @see Node#duplicateNode
291: * @see Node#cloneTree
292: * @see NodeComponent#setDuplicateOnCloneTree
293: */
294: public void duplicateNode(Node originalNode, boolean forceDuplicate) {
295: super .duplicateNode(originalNode, forceDuplicate);
296: KBSplinePathInterpolator originalSpline = (KBSplinePathInterpolator) originalNode;
297: setAlpha(originalSpline.getAlpha());
298: keysLength = originalSpline.keysLength;
299: keyFrames = new KBKeyFrame[keysLength];
300: System.arraycopy(originalSpline.keyFrames, 0, keyFrames, 0,
301: keysLength);
302: }
303:
304: }
|