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: import com.sun.perseus.util.SVGConstants;
030:
031: import org.w3c.dom.DOMException;
032:
033: import java.util.Vector;
034:
035: import com.sun.perseus.j2d.Path;
036:
037: /**
038: * @version $Id: MotionTraitAnim.java,v 1.4 2006/06/29 10:47:33 ln156897 Exp $
039: */
040: class MotionTraitAnim extends TransformTraitAnim {
041: /**
042: * Constructs a new TransformTraitAnim for a given ElementNode trait.
043: *
044: * @param targetElement the ElementNode whose trait is animated.
045: * @param targetTrait the name of the animated trait.
046: */
047: public MotionTraitAnim(final ElementNode targetElement,
048: final String traitName) {
049: super (targetElement, traitName);
050: }
051:
052: /**
053: * Converts the input values set to a RefValues object. For
054: * a MotionTraitAnim, the input values may be the to/from/by/values values
055: * or the path attribute value.
056: *
057: * @param anim the <code>Animation</code> for which the values should be
058: * converted.
059: * @param values a semi-colon seperated list of values which need to be
060: * validated.
061: * @param reqTraitNamespace the namespace of the trait which has the values
062: * value on the requesting element.
063: * @param reqTraitName the name of the trait which has the values value on
064: * the requesting element.
065: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
066: * value is incompatible with the given trait.
067: * @throws NullPointerException if values is null.
068: */
069: RefValues toRefValues(final Animation anim, String[] values,
070: final String reqTraitNamespace, final String reqTraitName)
071: throws DOMException {
072: AnimateMotion motion = (AnimateMotion) anim;
073:
074: // The interpretation of values depends on the attribute type.
075: MotionRefValues refValues = new MotionRefValues(motion);
076:
077: if (values.length < 1) {
078: throw new IllegalArgumentException();
079: }
080:
081: if (!SVGConstants.SVG_PATH_ATTRIBUTE.equals(reqTraitName)
082: && !SVGConstants.SVG_D_ATTRIBUTE.equals(reqTraitName)) {
083:
084: //
085: // We are dealing with a to/from/by or values attribute
086: //
087:
088: if (values.length == 1) {
089: String[] tmpValues = new String[2];
090: tmpValues[0] = values[0];
091: tmpValues[1] = values[0];
092: values = tmpValues;
093: }
094:
095: int nSegments = values.length - 1;
096: refValues.segments = new MotionSegment[nSegments];
097:
098: // Build the first segment.
099: float[] startPt = new float[2];
100: float[] endPt = new float[2];
101:
102: validateCoordinate(anim, reqTraitNamespace, reqTraitName,
103: values[0], startPt);
104:
105: validateCoordinate(anim, reqTraitNamespace, reqTraitName,
106: values[1], endPt);
107:
108: refValues.segments[0] = new LeafMotionSegment(startPt[0],
109: startPt[1], endPt[0], endPt[1], motion);
110:
111: for (int i = 1; i < nSegments; i++) {
112: validateCoordinate(anim, reqTraitNamespace,
113: reqTraitNamespace, values[i + 1], endPt);
114: refValues.segments[i] = new LeafMotionSegment(
115: (LeafMotionSegment) refValues.segments[i - 1],
116: endPt[0], endPt[1], motion);
117: }
118: } else {
119: //
120: // We are dealing with the path attribute on animateMotion
121: // or with the d attribute on a path element referenced from
122: // an mpath element.
123: //
124:
125: // a) convert the path attribute to a Path
126: Path path = anim.parsePathTrait(anim.traitName, values[0]);
127:
128: // b) turn the path into a set of segments after linear
129: // approximation.
130: int type = 0;
131: float[] coords = new float[6];
132: float[] curPos = new float[2];
133: float[] endPos = new float[2];
134: float[][] curve = new float[4][2];
135: float[] lastMove = new float[2];
136:
137: Vector segments = new Vector();
138: Vector curves = new Vector();
139: LeafMotionSegment prevSegment = null;
140:
141: int nSegments = path.getNumberOfSegments();
142: for (int i = 0; i < nSegments; i++) {
143: type = path.getSegment(i);
144: switch (type) {
145: case Path.MOVE_TO:
146: curPos[0] = path.getSegmentParam(i, 0);
147: curPos[1] = path.getSegmentParam(i, 1);
148: lastMove[0] = curPos[0];
149: lastMove[1] = curPos[1];
150: break;
151: case Path.LINE_TO:
152: if (prevSegment == null) {
153: prevSegment = new LeafMotionSegment(curPos[0],
154: curPos[1], path.getSegmentParam(i, 0),
155: path.getSegmentParam(i, 1), motion);
156: } else {
157: prevSegment = new LeafMotionSegment(
158: prevSegment,
159: path.getSegmentParam(i, 0), path
160: .getSegmentParam(i, 1), motion);
161: }
162: segments.addElement(prevSegment);
163: curPos[0] = path.getSegmentParam(i, 0);
164: curPos[1] = path.getSegmentParam(i, 1);
165: break;
166: case Path.QUAD_TO:
167: // First, linearize the curve.
168: // This is an overkill because we use the same code for
169: // quad curves as for cubic curves.
170: curve[0][0] = curPos[0];
171: curve[0][1] = curPos[1];
172: curve[1][0] = path.getSegmentParam(i, 0);
173: curve[1][1] = path.getSegmentParam(i, 1);
174: curve[2][0] = path.getSegmentParam(i, 0);
175: curve[2][1] = path.getSegmentParam(i, 1);
176: curve[3][0] = path.getSegmentParam(i, 2);
177: curve[3][1] = path.getSegmentParam(i, 3);
178: prevSegment = addCubicSegment(motion, curve,
179: segments, curves, prevSegment);
180: curPos[0] = path.getSegmentParam(i, 2);
181: curPos[1] = path.getSegmentParam(i, 3);
182: break;
183: case Path.CURVE_TO:
184: curve[0][0] = curPos[0];
185: curve[0][1] = curPos[1];
186: curve[1][0] = path.getSegmentParam(i, 0);
187: curve[1][1] = path.getSegmentParam(i, 1);
188: curve[2][0] = path.getSegmentParam(i, 2);
189: curve[2][1] = path.getSegmentParam(i, 3);
190: curve[3][0] = path.getSegmentParam(i, 4);
191: curve[3][1] = path.getSegmentParam(i, 5);
192: prevSegment = addCubicSegment(motion, curve,
193: segments, curves, prevSegment);
194: curPos[0] = path.getSegmentParam(i, 4);
195: curPos[1] = path.getSegmentParam(i, 5);
196: break;
197: case Path.CLOSE:
198: default:
199: if (prevSegment == null) {
200: prevSegment = new LeafMotionSegment(curPos[0],
201: curPos[1], lastMove[0], lastMove[1],
202: motion);
203: } else {
204: prevSegment = new LeafMotionSegment(
205: prevSegment, lastMove[0], lastMove[1],
206: motion);
207: }
208: segments.addElement(prevSegment);
209: curPos[0] = lastMove[0];
210: curPos[1] = lastMove[1];
211: break;
212: }
213: }
214:
215: if (segments.size() == 0) {
216: // This is a degenerate case, for a path with only a moveto or
217: // empty.
218: segments.addElement(new LeafMotionSegment(curPos[0],
219: curPos[1], curPos[0], curPos[1], motion));
220: }
221:
222: refValues.segments = new MotionSegment[segments.size()];
223: segments.copyInto(refValues.segments);
224: }
225:
226: return refValues;
227: }
228:
229: /**
230: * Adds the input curve as a CompositeSegment to the segments vector.
231: *
232: * @param motion the AnimateMotion element for which the curve is added.
233: * @param curve a float array with the curve definition.
234: * @param segments the vector holding all the animation segments.
235: * @param motionCoords a working vector where coordinates for the various
236: * linear approximations can be stored.
237: * @param prevSegment the previous LeafMotionSegment. May be null.
238: * @return the last LeafMotionSegment added to into the segments vector.
239: */
240: LeafMotionSegment addCubicSegment(final AnimateMotion motion,
241: final float[][] curve, final Vector segments,
242: final Vector motionCoords, LeafMotionSegment prevSegment) {
243: motionCoords.removeAllElements();
244: motionCoords
245: .addElement(new float[] { curve[0][0], curve[0][1] }); // Adds the current position.
246: AbstractAnimate.toRefSpline(curve, motionCoords);
247:
248: int nPoints = motionCoords.size();
249: float[] curPos = (float[]) motionCoords.elementAt(0);
250: LeafMotionSegment[] subSegments = new LeafMotionSegment[nPoints - 1];
251:
252: if (nPoints > 1) {
253: float[] endPos = (float[]) motionCoords.elementAt(1);
254: if (prevSegment == null) {
255: subSegments[0] = new LeafMotionSegment(curPos[0],
256: curPos[1], endPos[0], endPos[1], motion);
257: } else {
258: subSegments[0] = new LeafMotionSegment(prevSegment,
259: endPos[0], endPos[1], motion);
260: }
261: curPos = endPos;
262: prevSegment = subSegments[0];
263: }
264:
265: for (int i = 2; i < nPoints; i++) {
266: float[] endPos = (float[]) motionCoords.elementAt(i);
267: subSegments[i - 1] = new LeafMotionSegment(prevSegment,
268: endPos[0], endPos[1], motion);
269: curPos = endPos;
270: prevSegment = subSegments[i - 1];
271: }
272:
273: CompositeMotionSegment cSeg = new CompositeMotionSegment();
274: cSeg.segments = subSegments;
275: segments.addElement(cSeg);
276: return prevSegment;
277: }
278:
279: /**
280: * Parses a coordinate pair.
281: *
282: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
283: * value is incompatible with the given trait.
284: */
285: public void validateCoordinate(final Animation anim,
286: final String traitNamespace, final String traitName,
287: final String value, final float[] pt) throws DOMException {
288: float[] v = anim.parseFloatArrayTrait(traitName, value);
289: if (v.length < 1 || v.length > 2) {
290: throw anim.illegalTraitValue(traitName, value);
291: }
292:
293: // x
294: pt[0] = v[0];
295:
296: // translate y
297: if (v.length > 1) {
298: pt[1] = v[1];
299: } else {
300: pt[1] = v[0];
301: }
302: }
303: }
|