001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.perseus.model;
028:
029: /**
030: * @version $Id: MotionRefValues.java,v 1.3 2006/06/29 10:47:33 ln156897 Exp $
031: */
032: public class MotionRefValues implements RefValues {
033: /**
034: * This RefValues Segments. They can be CompositeSegment or MotionSegment
035: * instances.
036: */
037: MotionSegment[] segments;
038:
039: /**
040: * A working array to return a value from the compute method.
041: */
042: float[][] w;
043:
044: /**
045: * Used to store the length of this RefValues
046: */
047: float length;
048:
049: /**
050: * Used to store the normalized length of each segment
051: */
052: float[] nSegLength;
053:
054: /**
055: * Used to store the length of each segment
056: */
057: float[] segLength;
058:
059: /**
060: * The associated AnimateMotion
061: */
062: AnimateMotion motion;
063:
064: /**
065: * Builds a new MotionRefValues associated with the given AnimateMotion
066: * instance.
067: *
068: * @param motion the associated AnimateMotion
069: */
070: public MotionRefValues(final AnimateMotion motion) {
071: this .motion = motion;
072: }
073:
074: /**
075: * Computes the segment index for the given normalized distance.
076: *
077: * @param sisp a float array where the mapped si and sp values should be
078: * stored.
079: * @param dist the distance for which the segment indices should be
080: * computed. This value is normalized to the [0, 1] interval.
081: */
082: public void getSegmentAtDist(float[] sisp, float dist) {
083: if (dist >= 1) {
084: sisp[0] = segments.length - 1;
085: sisp[1] = 1;
086: return;
087: }
088:
089: if (dist < 0) {
090: sisp[0] = 0;
091: sisp[1] = 0;
092: return;
093: }
094:
095: int i = 0;
096: float prevSegLength = 0;
097: for (; i < nSegLength.length - 1; i++) {
098: if (dist < nSegLength[i]) {
099: break;
100: }
101: prevSegLength = nSegLength[i];
102: }
103:
104: // Now, compute the penetration in the segment.
105: float p = 1;
106:
107: if (nSegLength[i] > prevSegLength) {
108: p = (dist - prevSegLength)
109: / (nSegLength[i] - prevSegLength);
110: }
111:
112: sisp[0] = i;
113: sisp[1] = p;
114: }
115:
116: /**
117: * @param i requested segment index.
118: * @return Segment at index i
119: */
120: public Segment getSegment(int i) {
121: return segments[i];
122: }
123:
124: /**
125: * @return the number of segments in refValues
126: */
127: public int getSegments() {
128: return segments.length;
129: }
130:
131: /**
132: * @return the number of components. There is an array of float for each
133: * component.
134: */
135: public int getComponents() {
136: return segments[0].getStart().length;
137: }
138:
139: /**
140: * Computes the value for the input interpolated values.
141: * There should be as many entries in the return array as there
142: * are components in the RefValues.
143: *
144: * @param si the current segment index
145: * @param p the current penetration
146: * @param the interpolated value.
147: */
148: public Object[] compute(int si, float p) {
149: segments[si].compute(p, w);
150: return w;
151: }
152:
153: /**
154: * Adds a new time segment so accomodate for discreet behavior.
155: * If there is only one segment for discreet animations, the
156: * last value is never shown. To accomodate for that, this
157: * method should add a segment to the RefValues so that the
158: * last animation value is shown during the last value interval
159: * of a discreet animation.
160: */
161: public void makeDiscrete() {
162: MotionSegment[] tmpSegments = new MotionSegment[segments.length + 1];
163: System.arraycopy(segments, 0, tmpSegments, 0, segments.length);
164: Segment lastSeg = segments[segments.length - 1];
165: float[][] end = (float[][]) lastSeg.getEnd();
166: LeafMotionSegment newSeg = new LeafMotionSegment(end[4][0],
167: end[5][0], end[4][0], end[5][0], motion);
168: tmpSegments[tmpSegments.length - 1] = newSeg;
169: segments = tmpSegments;
170: }
171:
172: /**
173: * Computes the length of the RefValues. This is meant for paced timing
174: * computation.
175: *
176: * @return the total length of refValues, along each component. Therefore,
177: * there are as many entries in the returned array as there are
178: * components in RefValues.
179: */
180: public float getLength() {
181: return length;
182: }
183:
184: /**
185: * Computes the length of segment at index si
186: *
187: * @param si the segment index.
188: */
189: public float getLength(final int si) {
190: return segLength[si];
191: }
192:
193: /**
194: * Should be called after the RefValue's configuration is complete
195: * to give the implementation a chance to initialize
196: * internal data and cache values.
197: */
198: public void initialize() {
199: // Initialize the working buffer
200: final int nc = segments[0].getStart().length;
201: w = new float[nc][];
202: for (int ci = 0; ci < nc; ci++) {
203: // There is one dimension per component for motion
204: // values, which are matrix values.
205: w[ci] = new float[1];
206: }
207:
208: // Initialize sub-segments.
209: final int ns = segments.length;
210: for (int si = 0; si < ns; si++) {
211: segments[si].initialize();
212: }
213:
214: // Initialize cached length values.
215: nSegLength = new float[ns];
216: segLength = new float[ns];
217:
218: for (int si = 0; si < segments.length; si++) {
219: segLength[si] = segments[si].getLength();
220: length += segLength[si];
221: }
222:
223: // Now, initialize the normalized segment lengths array
224: if (length > 0) {
225: float curLength = 0;
226: for (int si = 0; si < ns - 1; si++) {
227: curLength += segLength[si];
228: nSegLength[si] = curLength / length;
229: }
230: } else {
231: for (int si = 0; si < ns - 1; si++) {
232: nSegLength[si] = 0;
233: }
234: }
235:
236: // Make sure that, in all cases, the last value is 1.
237: nSegLength[nSegLength.length - 1] = 1;
238: }
239:
240: /**
241: * Debug helper.
242: */
243: /*
244: public String toString() {
245: StringBuffer sb = new StringBuffer();
246: sb.append("MotionRefValues[" + getSegments() + "]\n");
247: for (int si = 0; si < getSegments(); si++) {
248: Segment seg = getSegment(si);
249: sb.append("seg[" + si + "] : " + seg.toString() + "\n");
250: }
251: return sb.toString();
252: }
253: */
254: }
|