001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: TransformStackElement.java 496556 2007-01-16 00:59:48Z cam $ */
019:
020: package org.apache.xmlgraphics.java2d;
021:
022: import java.awt.geom.AffineTransform;
023:
024: /**
025: * Contains a description of an elementary transform stack element,
026: * such as a rotate or translate. A transform stack element has a
027: * type and a value, which is an array of double values.<br>
028: *
029: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
030: * @author <a href="mailto:paul_evenblij@compuware.com">Paul Evenblij</a>
031: * @version $Id: TransformStackElement.java 496556 2007-01-16 00:59:48Z cam $
032: */
033: public abstract class TransformStackElement implements Cloneable {
034:
035: /**
036: * Transform type
037: */
038: private TransformType type;
039:
040: /**
041: * Value
042: */
043: private double[] transformParameters;
044:
045: /**
046: * @param type transform type
047: * @param transformParameters parameters for transform
048: */
049: protected TransformStackElement(TransformType type,
050: double[] transformParameters) {
051: this .type = type;
052: this .transformParameters = transformParameters;
053: }
054:
055: /**
056: * @return an object which is a deep copy of this one
057: */
058: public Object clone() {
059: TransformStackElement newElement = null;
060:
061: // start with a shallow copy to get our implementations right
062: try {
063: newElement = (TransformStackElement) super .clone();
064: } catch (java.lang.CloneNotSupportedException ex) {
065: }
066:
067: // now deep copy the parameter array
068: double[] transformParameters = new double[this .transformParameters.length];
069: System.arraycopy(this .transformParameters, 0,
070: transformParameters, 0, transformParameters.length);
071: newElement.transformParameters = transformParameters;
072: return newElement;
073: }
074:
075: /*
076: * Factory methods
077: */
078:
079: public static TransformStackElement createTranslateElement(
080: double tx, double ty) {
081: return new TransformStackElement(TransformType.TRANSLATE,
082: new double[] { tx, ty }) {
083: boolean isIdentity(double[] parameters) {
084: return parameters[0] == 0 && parameters[1] == 0;
085: }
086: };
087: }
088:
089: public static TransformStackElement createRotateElement(double theta) {
090: return new TransformStackElement(TransformType.ROTATE,
091: new double[] { theta }) {
092: boolean isIdentity(double[] parameters) {
093: return Math.cos(parameters[0]) == 1;
094: }
095: };
096: }
097:
098: public static TransformStackElement createScaleElement(
099: double scaleX, double scaleY) {
100: return new TransformStackElement(TransformType.SCALE,
101: new double[] { scaleX, scaleY }) {
102: boolean isIdentity(double[] parameters) {
103: return parameters[0] == 1 && parameters[1] == 1;
104: }
105: };
106: }
107:
108: public static TransformStackElement createShearElement(
109: double shearX, double shearY) {
110: return new TransformStackElement(TransformType.SHEAR,
111: new double[] { shearX, shearY }) {
112: boolean isIdentity(double[] parameters) {
113: return parameters[0] == 0 && parameters[1] == 0;
114: }
115: };
116: }
117:
118: public static TransformStackElement createGeneralTransformElement(
119: AffineTransform txf) {
120: double[] matrix = new double[6];
121: txf.getMatrix(matrix);
122: return new TransformStackElement(TransformType.GENERAL, matrix) {
123: boolean isIdentity(double[] m) {
124: return (m[0] == 1 && m[2] == 0 && m[4] == 0
125: && m[1] == 0 && m[3] == 1 && m[5] == 0);
126: }
127: };
128: }
129:
130: /**
131: * Implementation should determine if the parameter list represents
132: * an identity transform, for the instance transform type.
133: */
134: abstract boolean isIdentity(double[] parameters);
135:
136: /**
137: * @return true iff this transform is the identity transform
138: */
139: public boolean isIdentity() {
140: return isIdentity(transformParameters);
141: }
142:
143: /**
144: * @return array of values containing this transform element's parameters
145: */
146: public double[] getTransformParameters() {
147: return transformParameters;
148: }
149:
150: /**
151: * @return this transform type
152: */
153: public TransformType getType() {
154: return type;
155: }
156:
157: /*
158: * Concatenation utility. Requests this transform stack element
159: * to concatenate with the input stack element. Only elements
160: * of the same types are concatenated. For example, if this
161: * element represents a translation, it will concatenate with
162: * another translation, but not with any other kind of
163: * stack element.
164: * @param stackElement element to be concatenated with this one.
165: * @return true if the input stackElement was concatenated with
166: * this one. False otherwise.
167: */
168: public boolean concatenate(TransformStackElement stackElement) {
169: boolean canConcatenate = false;
170:
171: if (type.toInt() == stackElement.type.toInt()) {
172: canConcatenate = true;
173: switch (type.toInt()) {
174: case TransformType.TRANSFORM_TRANSLATE:
175: transformParameters[0] += stackElement.transformParameters[0];
176: transformParameters[1] += stackElement.transformParameters[1];
177: break;
178: case TransformType.TRANSFORM_ROTATE:
179: transformParameters[0] += stackElement.transformParameters[0];
180: break;
181: case TransformType.TRANSFORM_SCALE:
182: transformParameters[0] *= stackElement.transformParameters[0];
183: transformParameters[1] *= stackElement.transformParameters[1];
184: break;
185: case TransformType.TRANSFORM_GENERAL:
186: transformParameters = matrixMultiply(
187: transformParameters,
188: stackElement.transformParameters);
189: break;
190: default:
191: canConcatenate = false;
192: }
193: }
194:
195: return canConcatenate;
196: }
197:
198: /**
199: * Multiplies two 2x3 matrices of double precision values
200: */
201: private double[] matrixMultiply(double[] matrix1, double[] matrix2) {
202: double[] product = new double[6];
203: AffineTransform transform1 = new AffineTransform(matrix1);
204: transform1.concatenate(new AffineTransform(matrix2));
205: transform1.getMatrix(product);
206: return product;
207: }
208:
209: }
|