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: package com.sun.perseus.model;
027:
028: import com.sun.perseus.platform.MathSupport;
029:
030: /**
031: * Represents a time interval in an animation.
032: *
033: * @version $Id: LeafMotionSegment.java,v 1.3 2006/06/29 10:47:32 ln156897 Exp $
034: */
035: final class LeafMotionSegment implements MotionSegment {
036: /**
037: * The segment's begin value.
038: */
039: float[][] start;
040:
041: /**
042: * The segment's end value.
043: */
044: float[][] end;
045:
046: /**
047: * Builds a new motion segment for the given previous segment and
048: * end value.
049: *
050: * @param prevSegment the preceding segment. Should not be null.
051: * @param x2 the motion's end point, on the x-axis
052: * @param y2 the motion's end point, on the y-axis
053: * @param motion the corresponding AnimateMotion
054: */
055: public LeafMotionSegment(final LeafMotionSegment prevSegment,
056: final float x2, final float y2, final AnimateMotion motion) {
057: start = prevSegment.end;
058: end = new float[6][1];
059: end[4][0] = x2;
060: end[5][0] = y2;
061:
062: computeRotate(motion);
063: }
064:
065: /**
066: * Builds a new motion segment for the given start and end
067: * points.
068: *
069: * @param x1 the motion's starting point on the x-axis
070: * @param y1 the motion's stating point, on the y-axis
071: * @param x2 the motion's end point, on the x-axis
072: * @param y2 the motion's end point, on the y-axis
073: * @param motion the corresponding AnimateMotion
074: */
075: public LeafMotionSegment(final float x1, final float y1,
076: final float x2, final float y2, final AnimateMotion motion) {
077: start = new float[6][1];
078: end = new float[6][1];
079:
080: start[0][0] = 1;
081: start[3][0] = 1;
082: start[4][0] = x1;
083: start[5][0] = y1;
084:
085: end[4][0] = x2;
086: end[5][0] = y2;
087:
088: computeRotate(motion);
089: }
090:
091: /**
092: * Computes the rotation component on the end value.
093: *
094: * @param motion the associated AnimateMotion.
095: */
096: void computeRotate(final AnimateMotion motion) {
097: float cosRotate = motion.cosRotate;
098: float sinRotate = motion.sinRotate;
099:
100: if (motion.rotateType != AnimateMotion.ROTATE_ANGLE) {
101: float dx = end[4][0] - start[4][0];
102: float dy = end[5][0] - start[5][0];
103: float theta = MathSupport.atan2(dy, dx);
104: if (motion.rotateType == AnimateMotion.ROTATE_AUTO_REVERSE) {
105: theta += MathSupport.PI;
106: }
107:
108: cosRotate = MathSupport.cos(theta);
109: sinRotate = MathSupport.sin(theta);
110: }
111:
112: end[0][0] = cosRotate;
113: end[1][0] = sinRotate;
114: end[2][0] = -sinRotate;
115: end[3][0] = cosRotate;
116: }
117:
118: /**
119: * @return the start value.
120: */
121: public Object[] getStart() {
122: return start;
123: }
124:
125: /**
126: * @return set end value.
127: */
128: public Object[] getEnd() {
129: return end;
130: }
131:
132: /**
133: * Computes an interpolated value for the given penetration in the
134: * segment.
135: *
136: * @param p the segment penetration. Should be in the [0, 1] range.
137: * @param w array where the computed value should be stored.
138: */
139: public void compute(final float p, final float[][] w) {
140: // The rotation component is kept in the end value.
141: // The translation is an interpolation of the begin and
142: // end values.
143: w[0][0] = end[0][0];
144: w[1][0] = end[1][0];
145: w[2][0] = end[2][0];
146: w[3][0] = end[3][0];
147: w[4][0] = p * end[4][0] + (1 - p) * start[4][0];
148: w[5][0] = p * end[5][0] + (1 - p) * start[5][0];
149: }
150:
151: /**
152: * Computes the 'motion' length for this segment
153: */
154: public float getLength() {
155: float dx = end[4][0] - start[4][0];
156: float dy = end[5][0] - start[5][0];
157:
158: return MathSupport.sqrt(dx * dx + dy * dy);
159: }
160:
161: /**
162: * Collapses this segment with the one passed as a parameter.
163: * Note that if the input segment is not of the same class
164: * as this one, an IllegalArgumentException is thrown. The
165: * method also throws an exception if the input segment's
166: * end does not have the same number of components as this
167: * segment's end.
168: *
169: * After this method is called, this segment's end value
170: * is the one of the input <code>seg</code> parameter.
171: *
172: * @param seg the Segment to collapse with this one.
173: * @param anim the Animation this segment is part of.
174: */
175: public void collapse(final Segment seg, final Animation anim) {
176: LeafMotionSegment mseg = (LeafMotionSegment) seg;
177: end = mseg.end;
178: computeRotate((AnimateMotion) anim);
179: }
180:
181: /**
182: * Adds the input value to this Segment's end value.
183: *
184: * @param by the value to add. Throws IllegalArgumentException if this
185: * Segment type is not additive or if the input value is incompatible (e.g.,
186: * different number of components or different number of dimensions on a
187: * component).
188: */
189: public void addToEnd(Object[] by) {
190: float[][] add = (float[][]) by;
191:
192: // Adding motion segments is equivalent to concatenating transforms.
193: // So the result of adding the input value to the end is equivalent
194: // to concatenating the by value matrix to the end value matrix.
195: float[][] tmpEnd = new float[6][1];
196: tmpEnd[0][0] = end[0][0] * add[0][0] + end[2][0] * add[1][0];
197: tmpEnd[1][0] = end[1][0] * add[0][0] + end[3][0] * add[1][0];
198:
199: tmpEnd[2][0] = end[0][0] * add[2][0] + end[2][0] * add[3][0];
200: tmpEnd[3][0] = end[1][0] * add[2][0] + end[3][0] * add[3][0];
201:
202: tmpEnd[4][0] = end[0][0] * add[4][0] + end[2][0] * add[5][0]
203: + end[4][0];
204: tmpEnd[5][0] = end[1][0] * add[4][0] + end[3][0] * add[5][0]
205: + end[5][0];
206:
207: end = tmpEnd;
208: }
209:
210: /**
211: * @return true if this segment type supports addition. false
212: * otherwise.
213: */
214: public boolean isAdditive() {
215: return true;
216: }
217:
218: /**
219: * Sets the start value to its notion of 'zero'
220: */
221: public void setZeroStart() {
222: start[4][0] = 0;
223: start[5][0] = 0;
224: }
225:
226: /**
227: * Sets the start value.
228: *
229: * @param newStart the new segment start value.
230: */
231: public void setStart(Object[] newStart) {
232: start = (float[][]) newStart;
233: }
234:
235: /**
236: * Should be called after the segment's configuration is complete
237: * to give the segment's implementation a chance to initialize
238: * internal data and cache values.
239: */
240: public void initialize() {
241: }
242: }
|