001: /**
002: * Copyright (c) 2003, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.util;
031:
032: import java.awt.geom.AffineTransform;
033:
034: /**
035: * This class will be used for matrix manipulation.
036: *
037: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
038: * @version $Revision: 1.14 $
039: */
040: public class Matrix implements Cloneable {
041: private float[] single = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
042:
043: /**
044: * Constructor.
045: */
046: public Matrix() {
047: //default constructor
048: }
049:
050: /**
051: * Create an affine transform from this matrix's values.
052: *
053: * @return An affine transform with this matrix's values.
054: */
055: public AffineTransform createAffineTransform() {
056: AffineTransform retval = new AffineTransform(single[0],
057: single[1], single[3], single[4], single[6], single[7]);
058: return retval;
059: }
060:
061: /**
062: * Set the values of the matrix from the AffineTransform.
063: *
064: * @param af The transform to get the values from.
065: */
066: public void setFromAffineTransform(AffineTransform af) {
067: single[0] = (float) af.getScaleX();
068: single[1] = (float) af.getShearY();
069: single[3] = (float) af.getShearX();
070: single[4] = (float) af.getScaleY();
071: single[6] = (float) af.getTranslateX();
072: single[7] = (float) af.getTranslateY();
073: }
074:
075: /**
076: * This will get a matrix value at some point.
077: *
078: * @param row The row to get the value from.
079: * @param column The column to get the value from.
080: *
081: * @return The value at the row/column position.
082: */
083: public float getValue(int row, int column) {
084: return single[row * 3 + column];
085: }
086:
087: /**
088: * This will set a value at a position.
089: *
090: * @param row The row to set the value at.
091: * @param column the column to set the value at.
092: * @param value The value to set at the position.
093: */
094: public void setValue(int row, int column, float value) {
095: single[row * 3 + column] = value;
096: }
097:
098: /**
099: * Return a single dimension array of all values in the matrix.
100: *
101: * @return The values ot this matrix.
102: */
103: public float[][] getValues() {
104: float[][] retval = new float[3][3];
105: retval[0][0] = single[0];
106: retval[0][1] = single[1];
107: retval[0][2] = single[2];
108: retval[1][0] = single[3];
109: retval[1][1] = single[4];
110: retval[1][2] = single[5];
111: retval[2][0] = single[6];
112: retval[2][1] = single[7];
113: retval[2][2] = single[8];
114: return retval;
115: }
116:
117: /**
118: * Return a single dimension array of all values in the matrix.
119: *
120: * @return The values ot this matrix.
121: */
122: public double[][] getValuesAsDouble() {
123: double[][] retval = new double[3][3];
124: retval[0][0] = single[0];
125: retval[0][1] = single[1];
126: retval[0][2] = single[2];
127: retval[1][0] = single[3];
128: retval[1][1] = single[4];
129: retval[1][2] = single[5];
130: retval[2][0] = single[6];
131: retval[2][1] = single[7];
132: retval[2][2] = single[8];
133: return retval;
134: }
135:
136: /**
137: * This will take the current matrix and multipy it with a matrix that is passed in.
138: *
139: * @param b The matrix to multiply by.
140: *
141: * @return The result of the two multiplied matrices.
142: */
143: public Matrix multiply(Matrix b) {
144: Matrix result = new Matrix();
145:
146: float[] bMatrix = b.single;
147: float[] resultMatrix = result.single;
148: resultMatrix[0] = single[0] * bMatrix[0] + single[1]
149: * bMatrix[3] + single[2] * bMatrix[6];
150: resultMatrix[1] = single[0] * bMatrix[1] + single[1]
151: * bMatrix[4] + single[2] * bMatrix[7];
152: resultMatrix[2] = single[0] * bMatrix[2] + single[1]
153: * bMatrix[5] + single[2] * bMatrix[8];
154: resultMatrix[3] = single[3] * bMatrix[0] + single[4]
155: * bMatrix[3] + single[5] * bMatrix[6];
156: resultMatrix[4] = single[3] * bMatrix[1] + single[4]
157: * bMatrix[4] + single[5] * bMatrix[7];
158: resultMatrix[5] = single[3] * bMatrix[2] + single[4]
159: * bMatrix[5] + single[5] * bMatrix[8];
160: resultMatrix[6] = single[6] * bMatrix[0] + single[7]
161: * bMatrix[3] + single[8] * bMatrix[6];
162: resultMatrix[7] = single[6] * bMatrix[1] + single[7]
163: * bMatrix[4] + single[8] * bMatrix[7];
164: resultMatrix[8] = single[6] * bMatrix[2] + single[7]
165: * bMatrix[5] + single[8] * bMatrix[8];
166:
167: return result;
168: }
169:
170: /**
171: * Create a new matrix with just the scaling operators.
172: *
173: * @return A new matrix with just the scaling operators.
174: */
175: public Matrix extractScaling() {
176: Matrix retval = new Matrix();
177:
178: retval.single[0] = this .single[0];
179: retval.single[4] = this .single[4];
180:
181: return retval;
182: }
183:
184: /**
185: * Convenience method to create a scaled instance.
186: *
187: * @param x The xscale operator.
188: * @param y The yscale operator.
189: * @return A new matrix with just the x/y scaling
190: */
191: public static Matrix getScaleInstance(float x, float y) {
192: Matrix retval = new Matrix();
193:
194: retval.single[0] = x;
195: retval.single[4] = y;
196:
197: return retval;
198: }
199:
200: /**
201: * Create a new matrix with just the translating operators.
202: *
203: * @return A new matrix with just the translating operators.
204: */
205: public Matrix extractTranslating() {
206: Matrix retval = new Matrix();
207:
208: retval.single[6] = this .single[6];
209: retval.single[7] = this .single[7];
210:
211: return retval;
212: }
213:
214: /**
215: * Convenience method to create a translating instance.
216: *
217: * @param x The x translating operator.
218: * @param y The y translating operator.
219: * @return A new matrix with just the x/y translating.
220: */
221: public static Matrix getTranslatingInstance(float x, float y) {
222: Matrix retval = new Matrix();
223:
224: retval.single[6] = x;
225: retval.single[7] = y;
226:
227: return retval;
228: }
229:
230: /**
231: * Clones this object.
232: * @return cloned matrix as an object.
233: */
234: public Object clone() {
235: Matrix clone = new Matrix();
236: System.arraycopy(single, 0, clone.single, 0, 9);
237: return clone;
238: }
239:
240: /**
241: * This will copy the text matrix data.
242: *
243: * @return a matrix that matches this one.
244: */
245: public Matrix copy() {
246: return (Matrix) clone();
247: }
248:
249: /**
250: * This will return a string representation of the matrix.
251: *
252: * @return The matrix as a string.
253: */
254: public String toString() {
255: StringBuffer result = new StringBuffer("");
256: result.append("[[");
257: result.append(single[0] + ",");
258: result.append(single[1] + ",");
259: result.append(single[2] + "][");
260: result.append(single[3] + ",");
261: result.append(single[4] + ",");
262: result.append(single[5] + "][");
263: result.append(single[6] + ",");
264: result.append(single[7] + ",");
265: result.append(single[8] + "]]");
266:
267: return result.toString();
268: }
269:
270: /**
271: * Get the xscaling factor of this matrix.
272: * @return The x-scale.
273: */
274: public float getXScale() {
275: float xScale = single[0];
276:
277: /**
278: * BM: if the trm is rotated, the calculation is a little more complicated
279: *
280: * The rotation matrix multiplied with the scaling matrix is:
281: * ( x 0 0) ( cos sin 0) ( x*cos x*sin 0)
282: * ( 0 y 0) * (-sin cos 0) = (-y*sin y*cos 0)
283: * ( 0 0 1) ( 0 0 1) ( 0 0 1)
284: *
285: * So, if you want to deduce x from the matrix you take
286: * M(0,0) = x*cos and M(0,1) = x*sin and use the theorem of Pythagoras
287: *
288: * sqrt(M(0,0)^2+M(0,1)^2) =
289: * sqrt(x2*cos2+x2*sin2) =
290: * sqrt(x2*(cos2+sin2)) = <- here is the trick cos2+sin2 is one
291: * sqrt(x2) =
292: * abs(x)
293: */
294: if (!(single[1] == 0.0f && single[3] == 0.0f)) {
295: xScale = (float) Math.sqrt(Math.pow(single[0], 2)
296: + Math.pow(single[1], 2));
297: }
298: return xScale;
299: }
300:
301: /**
302: * Get the y scaling factor of this matrix.
303: * @return The y-scale factor.
304: */
305: public float getYScale() {
306: float yScale = single[4];
307: if (!(single[1] == 0.0f && single[3] == 0.0f)) {
308: yScale = (float) Math.sqrt(Math.pow(single[3], 2)
309: + Math.pow(single[4], 2));
310: }
311: return yScale;
312: }
313:
314: /**
315: * Get the x position in the matrix.
316: * @return The x-position.
317: */
318: public float getXPosition() {
319: return single[6];
320: }
321:
322: /**
323: * Get the y position.
324: * @return The y position.
325: */
326: public float getYPosition() {
327: return single[7];
328: }
329: }
|