View Javadoc

1   // Copyright 2004-2005, FreeHEP.
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 //  cos*m00-sin*m10 cos*m01-sin*m11 cos*m02-sin*m12
190 //  sin*m00+cos*m10 sin*m01+cos*m11 sin*m02+cos+m12
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 //  sx*m00  sx*m01  sx*m02
212 //  sy*m10  sy*m11  sy*m12
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 //  m00+shx*m10 m01+shx*m11 m02+shx*m12
227 //  m10+shy*m00 m11+shy*m01 m12+shy*m02
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 //  m00  m01  m02+tx
247 //  m10  m11  m12+ty 
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 //  m00  m01  m00*tx+m01*ty+m02
262 //  m10  m11  m10*tx+m11*ty+m12 
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 // XMLIO
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 }