1
2 package hep.wired.util;
3
4 import org.jdom.DataConversionException;
5
6 import org.freehep.xml.io.XMLIO;
7 import org.freehep.xml.io.XMLIOManager;
8
9 import java.awt.geom.NoninvertibleTransformException;
10 import java.text.DecimalFormat;
11
12 /***
13 * A 2x3 matrix for projection of 2D space to 2D space.
14 *
15 * @author Mark Donszelmann
16 * @version $Id: Matrix2D.java 2083 2005-07-20 17:16:52Z duns $
17 */
18
19 public class Matrix2D implements XYZindices, UVWindices, Cloneable, XMLIO {
20
21 private static final DecimalFormat fmt = new DecimalFormat("0000.000");
22
23 private double m00, m01, m02;
24 private double m10, m11, m12;
25
26 /***
27 * Creates an identity matrix.
28 */
29 public Matrix2D() {
30 this(1, 0,
31 0, 1,
32 0, 0);
33 }
34
35 /***
36 * Creates a matrix with given parameters.
37 */
38 public Matrix2D(double m00, double m10,
39 double m01, double m11,
40 double m02, double m12) {
41 set(m00, m10,
42 m01, m11,
43 m02, m12);
44 }
45
46 public Object clone() {
47 return new Matrix2D(m00, m10,
48 m01, m11,
49 m02, m12);
50 }
51
52 public int hashCode() {
53 long bits;
54 bits = Double.doubleToLongBits(m00);
55 bits = bits * 31 + Double.doubleToLongBits(m10);
56 bits = bits * 31 + Double.doubleToLongBits(m01);
57 bits = bits * 31 + Double.doubleToLongBits(m11);
58 bits = bits * 31 + Double.doubleToLongBits(m02);
59 bits = bits * 31 + Double.doubleToLongBits(m12);
60 return (((int) bits) ^ ((int) (bits >> 32)));
61 }
62
63 public boolean equals(Object obj) {
64 if (!(obj instanceof Matrix2D)) return super.equals(obj);
65
66 Matrix2D m = (Matrix2D)obj;
67
68 return (m.m00 == m00) && (m.m10 == m10)
69 && (m.m01 == m01) && (m.m11 == m11)
70 && (m.m02 == m02) && (m.m12 == m12);
71 }
72
73 /***
74 * Returns the sx value (m00).
75 */
76 public double getScaleX() {
77 return m00;
78 }
79
80 /***
81 * Returns the sy value (m11).
82 */
83 public double getScaleY() {
84 return m11;
85 }
86
87 /***
88 * Returns the shx value (m01).
89 */
90 public double getShearX() {
91 return m01;
92 }
93
94 /***
95 * Returns the shy value (m10).
96 */
97 public double getShearY() {
98 return m10;
99 }
100
101 /***
102 * Returns the tx value (m02).
103 */
104 public double getTranslateX() {
105 return m02;
106 }
107
108 /***
109 * Returns the ty value (m12).
110 */
111 public double getTranslateY() {
112 return m12;
113 }
114
115 private void set(double m00, double m10,
116 double m01, double m11,
117 double m02, double m12) {
118 this.m00 = m00;
119 this.m10 = m10;
120 this.m01 = m01;
121 this.m11 = m11;
122 this.m02 = m02;
123 this.m12 = m12;
124 }
125
126 /***
127 * Returns the determinant.
128 */
129 public double getDeterminant() {
130 return m00 * m11 - m01 * m10;
131 }
132
133 /***
134 * Creates and returns the inverse of this matrix.
135 */
136 public Matrix2D createInverse() throws NoninvertibleTransformException {
137 double d = getDeterminant();
138 if (Math.abs(d) <= Double.MIN_VALUE) throw new NoninvertibleTransformException("Matrix2D cannot be inverted. Determinant: "+d+"\n"+toString());
139
140 return new Matrix2D(
141 m11 / d, -m10 / d,
142 -m01 / d, m00 / d,
143 (m01 * m12 - m11 * m02) / d,
144 (m10 * m02 - m00 * m12) / d
145 );
146 }
147
148 /***
149 * Concatenates this matrix with m, such that M' = M * m.
150 */
151 public void concatenate(Matrix2D m) {
152 set(
153 m00*m.m00 + m01*m.m10,
154 m10*m.m00 + m11*m.m10,
155
156 m00*m.m01 + m01*m.m11,
157 m10*m.m01 + m11*m.m11,
158
159 m00*m.m02 + m01*m.m12 + m02,
160 m10*m.m02 + m11*m.m12 + m12
161 );
162 }
163
164 /***
165 * Pre-concatenates this matrix with m, such that M' = m * M.
166 */
167 public void preConcatenate(Matrix2D m) {
168 set(
169 m.m00*m00 + m.m01*m10,
170 m.m10*m00 + m.m11*m10,
171
172 m.m00*m01 + m.m01*m11,
173 m.m10*m01 + m.m11*m11,
174
175 m.m00*m02 + m.m01*m12 + m.m02,
176 m.m10*m02 + m.m11*m12 + m.m12
177 );
178 }
179
180 /***
181 * Rotates theta radians. Preconcatenates with the matrix:
182 * <pre>
183 * [ cos(theta) -sin(theta) 0 ]
184 * [ sin(theta) cos(theta) 0 ]
185 * [ 0 0 1 ]
186 * </pre>
187 */
188 public void rotate(double theta) {
189
190
191 double cos = Math.cos(theta);
192 double sin = Math.sin(theta);
193 set(cos*m00 - sin*m10,
194 sin*m00 + cos*m10,
195 cos*m01 - sin*m11,
196 sin*m01 + cos*m11,
197 cos*m02 - sin*m12,
198 sin*m02 + cos*m12
199 );
200 }
201
202 /***
203 * Scales by sx and sy. Preconcatenates with the matrix:
204 * <pre>
205 * [ sx 0 0 ]
206 * [ 0 sy 0 ]
207 * [ 0 0 1 ]
208 * </pre>
209 */
210 public void scale(double sx, double sy) {
211
212
213 m00 *= sx; m01 *= sx; m02 *= sx;
214 m10 *= sy; m11 *= sy; m12 *= sy;
215 }
216
217 /***
218 * Shears by shx and shy. Preconcatenates with the matrix:
219 * <pre>
220 * [ 1 shx 0 ]
221 * [ shy 1 0 ]
222 * [ 0 0 1 ]
223 * </pre>
224 */
225 public void shear(double shx, double shy) {
226
227
228 set(m00 + shx*m10,
229 m10 + shy*m00,
230 m01 + shx*m11,
231 m11 + shy*m01,
232 m02 + shx*m12,
233 m12 + shy*m02
234 );
235 }
236
237 /***
238 * Translates by tx and ty. Preconcatenates with the matrix:
239 * <pre>
240 * [ 1 0 tx ]
241 * [ 0 1 ty ]
242 * [ 0 0 1 ]
243 * </pre>
244 */
245 public void translate(double tx, double ty) {
246
247
248 m02 += tx;
249 m12 += ty;
250 }
251
252 /***
253 * Model-Translates by tx and ty. Concatenates with the matrix:
254 * <pre>
255 * [ 1 0 tx ]
256 * [ 0 1 ty ]
257 * [ 0 0 1 ]
258 * </pre>
259 */
260 public void modelTranslate(double tx, double ty) {
261
262
263 m02 += m00*tx+m01*ty;
264 m12 += m10*tx+m11*ty;
265 }
266
267
268
269
270 /***
271 * Transforms xyz by this matrix, using translation if delta is false.
272 * The input array is returned.
273 */
274 public double[] transform(double[] xyz, boolean delta) {
275 int d = delta ? 0 : 1;
276 double x = xyz[X];
277 double y = xyz[Y];
278
279 xyz[U] = m00*x + m01*y + m02*d;
280 xyz[V] = m10*x + m11*y + m12*d;
281
282 return xyz;
283 }
284
285 /***
286 * Transforms xyz by this matrix for n points, using translation if delta is false.
287 * The input array is returned.
288 */
289 public double[][] transform(double[][] xyz, int n, boolean delta) {
290 int d = delta ? 0 : 1;
291 for (int i=0; i<n; i++) {
292 double x = xyz[X][i];
293 double y = xyz[Y][i];
294 xyz[U][i] = m00*x + m01*y + m02*d;
295 xyz[V][i] = m10*x + m11*y + m12*d;
296 }
297 return xyz;
298 }
299
300 public String toString() {
301 StringBuffer s = new StringBuffer();
302 s.append("Matrix2D: ");
303 s.append(fmt.format(m00));
304 s.append(", ");
305 s.append(fmt.format(m01));
306 s.append(", ");
307 s.append(fmt.format(m02));
308 s.append("\n");
309
310 s.append(" ");
311 s.append(fmt.format(m10));
312 s.append(", ");
313 s.append(fmt.format(m11));
314 s.append(", ");
315 s.append(fmt.format(m12));
316 s.append("\n");
317
318 return s.toString();
319 }
320
321
322
323
324
325 public void save(XMLIOManager xmlioManager,
326 org.jdom.Element nodeEl) {
327 nodeEl.setAttribute("m00", Double.toString(m00));
328 nodeEl.setAttribute("m10", Double.toString(m10));
329
330 nodeEl.setAttribute("m01", Double.toString(m01));
331 nodeEl.setAttribute("m11", Double.toString(m11));
332
333 nodeEl.setAttribute("m02", Double.toString(m02));
334 nodeEl.setAttribute("m12", Double.toString(m12));
335 }
336
337 public void restore(XMLIOManager xmlioManager,
338 org.jdom.Element nodeEl) {
339 try {
340 set(nodeEl.getAttribute("m00").getDoubleValue(),
341 nodeEl.getAttribute("m10").getDoubleValue(),
342
343 nodeEl.getAttribute("m01").getDoubleValue(),
344 nodeEl.getAttribute("m11").getDoubleValue(),
345
346 nodeEl.getAttribute("m02").getDoubleValue(),
347 nodeEl.getAttribute("m12").getDoubleValue()
348 );
349 } catch (DataConversionException dce) {
350 throw new IllegalArgumentException(getClass()+": "+dce.getMessage());
351 }
352 }
353 }