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.j2d;
027:
028: import org.w3c.dom.DOMException;
029: import org.w3c.dom.svg.SVGException;
030: import org.w3c.dom.svg.SVGMatrix;
031:
032: import com.sun.perseus.platform.MathSupport;
033:
034: /**
035: * Class for 2D transforms.
036: *
037: * @version $Id: Transform.java,v 1.8 2006/04/21 06:35:16 st125089 Exp $
038: */
039: public class Transform implements SVGMatrix {
040: /**
041: * The (0, 0) component of this 3x3 transformation matrix.
042: */
043: float m0;
044:
045: /**
046: * The (1, 0) component of this 3x3 transformation matrix.
047: */
048: float m1;
049:
050: /**
051: * The (0, 1) component of this 3x3 transformation matrix.
052: */
053: float m2;
054:
055: /**
056: * The (1, 1) component of this 3x3 transformation matrix.
057: */
058: float m3;
059:
060: /**
061: * The (0, 2) component of this 3x3 transformation matrix.
062: */
063: float m4;
064:
065: /**
066: * The (1, 2) component of this 3x3 transformation matrix.
067: */
068: float m5;
069:
070: /**
071: * Constructs an <code>Transform</code> with a given set of
072: * components, representing the transform:
073: *
074: * <pre>
075: * x' = m0*x + m2*y + m4
076: * y' = m1*x + m3*y + m5
077: * </pre>
078: *
079: * or, representing the matrix:
080: *
081: * <pre>
082: * [ m0 m2 m4 ]
083: * [ m1 m3 m5 ]
084: * [ 0 0 1 ]
085: * </pre>
086: *
087: * @param m0 (0, 0) matrix value
088: * @param m1 (1, 0) matrix value
089: * @param m2 (0, 1) matrix value
090: * @param m3 (1, 1) matrix value
091: * @param m4 (0, 2) matrix value
092: * @param m5 (1, 2) matrix value
093: */
094: public Transform(final float m0, final float m1, final float m2,
095: final float m3, final float m4, final float m5) {
096: setTransform(m0, m1, m2, m3, m4, m5);
097: }
098:
099: /**
100: * Sets the transform to the matrix defined by the input parameters:
101: *
102: * <pre>
103: * [ m0 m2 m4 ]
104: * [ m1 m3 m5 ]
105: * [ 0 0 1 ]
106: * </pre>
107: *
108: * @param m0 (0, 0) matrix value
109: * @param m1 (1, 0) matrix value
110: * @param m2 (0, 1) matrix value
111: * @param m3 (1, 1) matrix value
112: * @param m4 (0, 2) matrix value
113: * @param m5 (1, 2) matrix value
114: */
115: public void setTransform(final float m0, final float m1,
116: final float m2, final float m3, final float m4,
117: final float m5) {
118: this .m0 = m0;
119: this .m1 = m1;
120: this .m2 = m2;
121: this .m3 = m3;
122: this .m4 = m4;
123: this .m5 = m5;
124: }
125:
126: /**
127: * Sets the transform to the value defined by the input matrix.
128: *
129: * @param transform the transform whose value should be copied. If null,
130: * this transform is set to identity.
131: */
132: public void setTransform(final SVGMatrix transform) {
133: Transform txf = (Transform) transform;
134:
135: if (txf == null) {
136: m0 = 1; // create IDENTITY transformation
137: m1 = 0;
138: m2 = 0;
139: m3 = 1;
140: m4 = 0;
141: m5 = 0;
142: return;
143: }
144:
145: this .m0 = txf.m0;
146: this .m1 = txf.m1;
147: this .m2 = txf.m2;
148: this .m3 = txf.m3;
149: this .m4 = txf.m4;
150: this .m5 = txf.m5;
151: }
152:
153: /**
154: * Transforms a point's coordinates.
155: *
156: * @param pt the point to transform
157: * @param opt the transformed point coordinates.
158: */
159: public void transformPoint(final float[] pt, final float[] opt) {
160: opt[0] = pt[0] * m0 + pt[1] * m2 + m4;
161: opt[1] = pt[0] * m1 + pt[1] * m3 + m5;
162: }
163:
164: /**
165: * Constructs an <code>Transform</code> representing the same
166: * transform as the given <code>Transform</code>. Future changes
167: * to the object supplied as the <code>transform</code> parameter
168: * will not affect the newly constructed <code>Transform</code>.
169: * If <code>transform</code> is null, the matrix is initialized
170: * to be the identity matrix.
171: *
172: * @param transform defines the initial
173: * state for the newly constructed <code>Transform</code>.
174: */
175: public Transform(final SVGMatrix transform) {
176: setTransform(transform);
177: }
178:
179: /**
180: * The components of the matrix denoted a to f in the API are :
181: *
182: * [ a c e ]
183: * [ b d f ]
184: * [ 0 0 1 ]
185: *
186: * @param index component index for this matrix
187: * @return the component of the matrix corresponding to the index.
188: * @throws DOMException - INDEX_SIZE_ERR if the <code>index</code> is
189: * invalid.
190: */
191: public float getComponent(final int index) throws DOMException {
192: switch (index) {
193: case 0:
194: return m0;
195: case 1:
196: return m1;
197: case 2:
198: return m2;
199: case 3:
200: return m3;
201: case 4:
202: return m4;
203: case 5:
204: return m5;
205: default:
206: throw new DOMException(
207: DOMException.INDEX_SIZE_ERR,
208: Messages
209: .formatMessage(
210: Messages.ERROR_OUT_OF_BOUND_PARAMETER_VALUE,
211: new String[] { "SVGMatrix",
212: "getComponent", "index",
213: "" + index }));
214: }
215: }
216:
217: /**
218: *
219: */
220: public SVGMatrix mMultiply(final SVGMatrix secondMatrix)
221: throws NullPointerException {
222: if (secondMatrix == null) {
223: throw new NullPointerException();
224: }
225:
226: Transform sm = (Transform) secondMatrix;
227:
228: float t0 = sm.m0;
229: float t1 = sm.m1;
230: float t2 = sm.m2;
231: float t3 = sm.m3;
232: float t4 = sm.m4;
233: float t5 = sm.m5;
234:
235: float mM0 = m0;
236: float mM1 = m2;
237: m0 = t0 * mM0 + t1 * mM1;
238: m2 = t2 * mM0 + t3 * mM1;
239: m4 += t4 * mM0 + t5 * mM1;
240:
241: mM0 = m1;
242: mM1 = m3;
243: m1 = t0 * mM0 + t1 * mM1;
244: m3 = t2 * mM0 + t3 * mM1;
245: m5 += t4 * mM0 + t5 * mM1;
246:
247: return this ;
248: }
249:
250: /**
251: * Returns the inverse matrix.
252: *
253: * @return the inverted matrix.
254: * @throws SVGException - SVG_MATRIX_NOT_INVERTABLE when determinant
255: * of this matrix is zero.
256: */
257: public SVGMatrix inverse() throws SVGException {
258: Transform svm = new Transform(1, 0, 0, 1, 0, 0);
259: inverse(svm);
260: return svm;
261: }
262:
263: /**
264: * Returns true if the matrix is invertible.
265: *
266: * @return true if the matrix is invertible.
267: */
268: public boolean isInvertible() {
269: return (m0 * m3 - m1 * m2) != 0;
270: }
271:
272: /**
273: * Inverses this transform and stores the resulting transform into
274: * the input transform.
275: *
276: * @param txf the SVGMatrix into which the result should be stored.
277: * @throws SVGException - SVG_MATRIX_NOT_INVERTABLE when determinant
278: * of this matrix is zero.
279: */
280: public SVGMatrix inverse(SVGMatrix txf) throws SVGException {
281: Transform svm = (Transform) txf;
282:
283: float det = m0 * m3 - m2 * m1;
284: if (MathSupport.abs(det) <= Float.MIN_VALUE) {
285: throw new SVGException(
286: SVGException.SVG_MATRIX_NOT_INVERTABLE, this
287: .toString());
288: }
289:
290: if (svm == null) {
291: svm = new Transform(1, 0, 0, 1, 0, 0);
292: }
293:
294: if (isIdentity()) {
295: svm.setTransform(1, 0, 0, 1, 0, 0);
296: return svm;
297: }
298:
299: svm.m0 = m3 / det;
300: svm.m2 = -m2 / det;
301: svm.m4 = (m2 * m5 - m3 * m4) / det;
302: svm.m1 = -m1 / det;
303: svm.m3 = m0 / det;
304: svm.m5 = (m1 * m4 - m0 * m5) / det;
305:
306: return svm;
307: }
308:
309: /**
310: *
311: */
312: public SVGMatrix mTranslate(final float x, final float y) {
313: m4 = x * m0 + y * m2 + m4;
314: m5 = x * m1 + y * m3 + m5;
315:
316: return this ;
317: }
318:
319: /**
320: *
321: */
322: public SVGMatrix mScale(final float scaleFactor) {
323: m0 *= scaleFactor;
324: m2 *= scaleFactor;
325: m1 *= scaleFactor;
326: m3 *= scaleFactor;
327: return this ;
328: }
329:
330: /**
331: * Post-multiplies a scale transformation on the current matrix and
332: * returns the resulting matrix.
333: * <p>
334: * <pre>
335: * [ scaleFactorX 0 0 ]
336: * [ 0 scaleFactorY 0 ]
337: * [ 0 0 1 ]
338: * </pre>
339: * </p>
340: *
341: * @param scaleFactorX the factor by which coordinates are scaled along the
342: * X axis direction.
343: * @param scaleFactorY the factor by which coordinates are scaled along the
344: * Y axis direction.
345: * @return this matrix scaled by the scaleFactor.
346: */
347: public SVGMatrix mScale(final float scaleFactorX,
348: final float scaleFactorY) {
349: m0 *= scaleFactorX;
350: m2 *= scaleFactorY;
351: m1 *= scaleFactorX;
352: m3 *= scaleFactorY;
353: return this ;
354: }
355:
356: /**
357: *
358: */
359: public SVGMatrix mRotate(final float angle) {
360: final float angl = MathSupport.toRadians(angle);
361: final float trigTOLERANCE = 1E-7f;
362: final float sin = MathSupport.sin(angl);
363: final float cos = MathSupport.cos(angl);
364:
365: if (MathSupport.abs(sin) < trigTOLERANCE) { // angle = 0 or 180 deg.
366: if (cos < 0f) { // angle = 180 deg.
367: m0 = -m0;
368: m3 = -m3;
369: m2 = -m2;
370: m1 = -m1;
371: }
372: return this ;
373: }
374:
375: if (MathSupport.abs(cos) < trigTOLERANCE) { // angle = 90 or 270 deg.
376: if (sin < 0f) { // angle = 270 deg
377: float mM0 = m0;
378: m0 = -m2;
379: m2 = mM0;
380: mM0 = m1;
381: m1 = -m3;
382: m3 = mM0;
383: } else { // angle = 90 deg
384: float mM0 = m0;
385: m0 = m2;
386: m2 = -mM0;
387: mM0 = m1;
388: m1 = m3;
389: m3 = -mM0;
390: }
391: return this ;
392: }
393:
394: float mM0, mM1;
395: mM0 = m0;
396: mM1 = m2;
397: m0 = cos * mM0 + sin * mM1;
398: m2 = -sin * mM0 + cos * mM1;
399: mM0 = m1;
400: mM1 = m3;
401: m1 = cos * mM0 + sin * mM1;
402: m3 = -sin * mM0 + cos * mM1;
403:
404: return this ;
405: }
406:
407: /**
408: * Returns <code>true</code> if the current <code>SVGMatrix</code>
409: * is equivalent to the identity matrix, <code>false</code>
410: * otherwise.
411: *
412: * @return true if this matrix is identity, false otherwise.
413: */
414: public boolean isIdentity() {
415: return (m0 == 1f && m2 == 0f && m4 == 0f && m1 == 0f
416: && m3 == 1f && m5 == 0f);
417: }
418:
419: /**
420: * @return true if obj is a Transform and all its components are the
421: * same as this instance.
422: */
423: public boolean equals(final Object obj) {
424: if (obj == null || !(obj instanceof Transform)) {
425: return false;
426: }
427:
428: if (obj == this ) {
429: return true;
430: }
431:
432: Transform t = (Transform) obj;
433: return t.m0 == m0 && t.m1 == m1 && t.m2 == m2 && t.m3 == m3
434: && t.m4 == m4 && t.m5 == m5;
435: }
436:
437: /**
438: * @param a 6x1 float array containing the transform matrix.
439: * @return true if this transform is equal to the input matrix.
440: */
441: public boolean equals(final float[][] m) {
442: return m[0][0] == m0 && m[1][0] == m1 && m[2][0] == m2
443: && m[3][0] == m3 && m[4][0] == m4 && m[5][0] == m5;
444: }
445: }
|