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: /**
029: * A composite implementation of the <code>Segment</code> interface.
030: * This is used in AnimateMotion to handle linearization of
031: * quadratic and cubic segments.
032: *
033: * @version $Id: CompositeMotionSegment.java,v 1.3 2006/04/21 06:36:43 st125089 Exp $
034: */
035: class CompositeMotionSegment implements MotionSegment {
036: /**
037: * The list of segment components.
038: */
039: MotionSegment[] segments;
040:
041: /**
042: * The cached segment length.
043: */
044: float length;
045:
046: /**
047: * The cached, normalized segment length
048: */
049: float[] nSegLength;
050:
051: /**
052: * @return the start value.
053: */
054: public Object[] getStart() {
055: return segments[0].getStart();
056: }
057:
058: /**
059: * @return set end value.
060: */
061: public Object[] getEnd() {
062: return segments[segments.length - 1].getEnd();
063: }
064:
065: /**
066: * Computes an interpolated value for the given penetration in the
067: * segment.
068: *
069: * @param p the segment penetration. Should be in the [0, 1] range.
070: * @param w array where the computed value should be stored.
071: * @return the interpolated value.
072: */
073: public void compute(float p, final float[][] w) {
074: // First, identify the child MotionSegment at the desired
075: // normalized distance.
076: int si = segments.length - 1;
077: float prevSegLength = 0;
078:
079: if (p < 1) {
080: for (si = 0; si < segments.length; si++) {
081: if (p < nSegLength[si]) {
082: break;
083: }
084: prevSegLength = nSegLength[si];
085: }
086: } else {
087: if (si > 0) {
088: prevSegLength = nSegLength[si - 1];
089: }
090: }
091:
092: // The sub-segment is at index si. Now, we need to
093: // compute the penetration in that segment.
094: if (nSegLength[si] > prevSegLength) {
095: p = (p - prevSegLength) / (nSegLength[si] - prevSegLength);
096: } else {
097: p = 1;
098: }
099:
100: segments[si].compute(p, w);
101: }
102:
103: /**
104: * Computes this segment's length
105: */
106: public float getLength() {
107: return length;
108: }
109:
110: /**
111: * Collapses this segment with the one passed as a parameter.
112: * Note that if the input segment is not of the same class
113: * as this one, an IllegalArgumentException is thrown. The
114: * method also throws an exception if the input segment's
115: * end does not have the same number of components as this
116: * segment's end.
117: *
118: * After this method is called, this segment's end value
119: * is the one of the input <code>seg</code> parameter.
120: *
121: * @param seg the Segment to collapse with this one.
122: * @param anim the Animation this segment is part of.
123: */
124: public void collapse(final Segment seg, final Animation anim) {
125: CompositeMotionSegment cseg = (CompositeMotionSegment) seg;
126: MotionSegment[] newSegments = new MotionSegment[segments.length
127: + cseg.segments.length];
128:
129: System.arraycopy(segments, 0, newSegments, 0, segments.length);
130:
131: System.arraycopy(cseg.segments, 0, newSegments,
132: segments.length, cseg.segments.length);
133:
134: segments = newSegments;
135: }
136:
137: /**
138: * Adds the input value to this Segment's end value.
139: *
140: * @param by the value to add. Throws IllegalArgumentException if this
141: * Segment type is not additive or if the input value is incompatible (e.g.,
142: * different number of components or different number of dimensions on a
143: * component).
144: */
145: public void addToEnd(Object[] by) {
146: segments[segments.length - 1].addToEnd(by);
147: }
148:
149: /**
150: * @return true if this segment type supports addition. false
151: * otherwise.
152: */
153: public boolean isAdditive() {
154: return segments[0].isAdditive();
155: }
156:
157: /**
158: * Sets the start value to its notion of 'zero'
159: */
160: public void setZeroStart() {
161: segments[0].setZeroStart();
162: }
163:
164: /**
165: * Sets the start value.
166: *
167: * @param newStart the new segment start value.
168: */
169: public void setStart(Object[] newStart) {
170: segments[0].setStart(newStart);
171: }
172:
173: /**
174: * Should be called after the segment's configuration is complete
175: * to give the segment's implementation a chance to initialize
176: * internal data and cache values.
177: */
178: public void initialize() {
179: // Initialize the component segments.
180: final int ns = segments.length;
181: for (int si = 0; si < ns; si++) {
182: segments[si].initialize();
183: }
184:
185: // Now, initialize the length cache.
186: length = 0;
187: nSegLength = new float[ns];
188: for (int si = 0; si < segments.length; si++) {
189: nSegLength[si] = segments[si].getLength();
190: length += nSegLength[si];
191: }
192:
193: // Now, initialize the normalized segment lengths array
194: if (length > 0) {
195: float curLength = 0;
196: for (int si = 0; si < ns - 1; si++) {
197: curLength += nSegLength[si];
198: nSegLength[si] = curLength / length;
199: }
200: } else {
201: for (int si = 0; si < ns - 1; si++) {
202: nSegLength[si] = 0;
203: }
204: }
205:
206: // Make sure that, in all cases, the last value is 1.
207: nSegLength[ns - 1] = 1;
208: }
209:
210: }
|