View Javadoc

1   /* file : AffineTransform3D.java
2    * 
3    * Project : geometry
4    *
5    * ===========================================
6    * 
7    * This library is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU Lesser General Public License as published by
9    * the Free Software Foundation, either version 2.1 of the License, or (at
10   * your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful, but 
13   * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14   * or FITNESS FOR A PARTICULAR PURPOSE.
15   *
16   * See the GNU Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with this library. if not, write to :
20   * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21   * Boston, MA 02111-1307, USA.
22   * 
23   * Created on 27 nov. 2005
24   *
25   */
26  
27  package math.geom3d.transform;
28  
29  import math.geom3d.Point3D;
30  import math.geom3d.Shape3D;
31  import math.geom3d.Vector3D;
32  
33  /**
34   * @author dlegland
35   */
36  public class AffineTransform3D implements Bijection3D {
37  
38      // TODO make the class immutable
39  
40      // coefficients for x coordinate.
41      protected double m00, m01, m02, m03;
42  
43      // coefficients for y coordinate.
44      protected double m10, m11, m12, m13;
45  
46      // coefficients for y coordinate.
47      protected double m20, m21, m22, m23;
48  
49      // ===================================================================
50      // public static methods
51  
52      public final static AffineTransform3D createTranslation(Vector3D vec) {
53          return createTranslation(vec.getX(), vec.getY(), vec.getZ());
54      }
55  
56      public final static AffineTransform3D createTranslation(double x, double y,
57              double z) {
58          return new AffineTransform3D(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z);
59      }
60  
61      public final static AffineTransform3D createRotationOx(double theta) {
62          double cot = Math.cos(theta);
63          double sit = Math.sin(theta);
64          return new AffineTransform3D(1, 0, 0, 0, 0, cot, -sit, 0, 0, sit, cot,
65                  0);
66      }
67  
68      public final static AffineTransform3D createRotationOy(double theta) {
69          double cot = Math.cos(theta);
70          double sit = Math.sin(theta);
71          return new AffineTransform3D(cot, 0, sit, 0, 0, 1, 0, 0, -sit, 0, cot,
72                  0);
73      }
74  
75      public final static AffineTransform3D createRotationOz(double theta) {
76          double cot = Math.cos(theta);
77          double sit = Math.sin(theta);
78          return new AffineTransform3D(cot, -sit, 0, 0, sit, cot, 0, 0, 0, 0, 1,
79                  0);
80      }
81  
82      AffineTransform3D createScaling(double s) {
83          return createScaling(s, s, s);
84      }
85  
86      AffineTransform3D createScaling(double sx, double sy, double sz) {
87          return new AffineTransform3D(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0);
88      }
89  
90      // ===================================================================
91      // constructors
92  
93      /** Creates a new affine transform3D set to identity */
94      public AffineTransform3D() {
95          // init to identity matrix
96          m00 = m11 = m22 = 1;
97          m01 = m02 = m03 = 0;
98          m10 = m12 = m13 = 0;
99          m20 = m21 = m23 = 0;
100     }
101 
102     public AffineTransform3D(double[] coefs) {
103         if (coefs.length==9) {
104             m00 = coefs[0];
105             m01 = coefs[1];
106             m02 = coefs[2];
107             m10 = coefs[3];
108             m11 = coefs[4];
109             m12 = coefs[5];
110             m20 = coefs[6];
111             m21 = coefs[7];
112             m22 = coefs[8];
113         } else if (coefs.length==12) {
114             m00 = coefs[0];
115             m01 = coefs[1];
116             m02 = coefs[2];
117             m03 = coefs[3];
118             m10 = coefs[4];
119             m11 = coefs[5];
120             m12 = coefs[6];
121             m13 = coefs[7];
122             m20 = coefs[8];
123             m21 = coefs[9];
124             m22 = coefs[10];
125             m23 = coefs[11];
126         }
127     }
128 
129     public AffineTransform3D(double xx, double yx, double zx, double tx,
130             double xy, double yy, double zy, double ty, double xz, double yz,
131             double zz, double tz) {
132         m00 = xx;
133         m01 = yx;
134         m02 = zx;
135         m03 = tx;
136         m10 = xy;
137         m11 = yy;
138         m12 = zy;
139         m13 = ty;
140         m20 = xz;
141         m21 = yz;
142         m22 = zz;
143         m23 = tz;
144     }
145 
146     // ===================================================================
147     // accessors
148 
149     public boolean isIdentity() {
150         if (m00!=1)
151             return false;
152         if (m11!=1)
153             return false;
154         if (m22!=0)
155             return false;
156         if (m01!=0)
157             return false;
158         if (m02!=0)
159             return false;
160         if (m03!=0)
161             return false;
162         if (m10!=0)
163             return false;
164         if (m12!=0)
165             return false;
166         if (m13!=0)
167             return false;
168         if (m20!=0)
169             return false;
170         if (m21!=0)
171             return false;
172         if (m23!=0)
173             return false;
174         return true;
175     }
176 
177     /**
178      * Returns the affine coefficients of the transform. Result is an array of
179      * 12 double.
180      */
181     public double[] getCoefficients() {
182         double[] tab = { m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22,
183                 m23 };
184         return tab;
185     }
186 
187     /**
188      * Computes the determinant of this transform. Can be zero.
189      * 
190      * @return the determinant of the transform.
191      */
192     private double getDeterminant() {
193         return +m00*(m11*m22-m12*m21)-m01*(m10*m22-m20*m12)+m02
194                 *(m10*m21-m20*m11);
195     }
196 
197     /**
198      * Computes the inverse affine transform.
199      */
200     public AffineTransform3D getInverseTransform() {
201         double det = this.getDeterminant();
202         return new AffineTransform3D((m11*m22-m21*m12)/det, (m21*m01-m01*m22)
203                 /det, (m01*m12-m11*m02)/det, (m01*(m22*m13-m12*m23)+m02
204                 *(m11*m23-m21*m13)-m03*(m11*m22-m21*m12))
205                 /det, (m20*m12-m10*m22)/det, (m00*m22-m20*m02)/det,
206                 (m10*m02-m00*m12)/det, (m00*(m12*m23-m22*m13)-m02
207                         *(m10*m23-m20*m13)+m03*(m10*m22-m20*m12))
208                         /det, (m10*m21-m20*m11)/det, (m20*m01-m00*m21)/det,
209                 (m00*m11-m10*m01)/det, (m00*(m21*m13-m11*m23)+m01
210                         *(m10*m23-m20*m13)-m03*(m10*m21-m20*m11))
211                         /det);
212     }
213 
214     // ===================================================================
215     // mutators
216 
217     /**
218      * @deprecated AffineTransform3d is immutable (0.6.3)
219      */
220     @Deprecated
221     public void setTransform(double n00, double n01, double n02, double n03,
222             double n10, double n11, double n12, double n13, double n20,
223             double n21, double n22, double n23) {
224         m00 = n00;
225         m01 = n01;
226         m02 = n02;
227         m03 = n03;
228         m10 = n10;
229         m11 = n11;
230         m12 = n12;
231         m13 = n13;
232         m20 = n20;
233         m21 = n21;
234         m22 = n22;
235         m23 = n23;
236     }
237 
238     /**
239      * @deprecated AffineTransform3d is immutable (0.6.3)
240      */
241     @Deprecated
242     public void setTransform(AffineTransform3D trans) {
243         m00 = trans.m00;
244         m01 = trans.m01;
245         m02 = trans.m02;
246         m03 = trans.m03;
247         m10 = trans.m10;
248         m11 = trans.m11;
249         m12 = trans.m12;
250         m13 = trans.m13;
251         m20 = trans.m20;
252         m21 = trans.m21;
253         m22 = trans.m22;
254         m23 = trans.m23;
255     }
256 
257     /**
258      * @deprecated AffineTransform3d is immutable (0.6.3)
259      */
260     @Deprecated
261     public void setToIdentity() {
262         m00 = m11 = m22 = 1;
263         m01 = m02 = m03 = 0;
264         m10 = m12 = m13 = 0;
265         m20 = m21 = m23 = 0;
266     }
267 
268     // ===================================================================
269     // general methods
270 
271     // TODO: add methods to concatenate affine transforms.
272 
273     /**
274      * Combine this transform with another AffineTransform.
275      */
276     public void transform(AffineTransform3D trans) {
277         double n00 = m00*trans.m00+m10*trans.m01;
278         double n10 = m00*trans.m10+m10*trans.m11;
279         double n01 = m01*trans.m00+m11*trans.m01;
280         double n11 = m01*trans.m10+m11*trans.m11;
281         double n02 = m02*trans.m00+m12*trans.m01+trans.m02;
282         double n12 = m02*trans.m10+m12*trans.m11+trans.m12;
283         m00 = n00;
284         m01 = n01;
285         m02 = n02;
286         m10 = n10;
287         m11 = n11;
288         m12 = n12;
289     }
290 
291     /**
292      * Combine this transform with another AffineTransform.
293      */
294     public void preConcatenate(AffineTransform3D trans) {
295         double n00 = trans.m00*m00+trans.m10*m01;
296         double n10 = trans.m00*m10+trans.m10*m11;
297         double n01 = trans.m01*m00+trans.m11*m01;
298         double n11 = trans.m01*m10+trans.m11*m11;
299         double n02 = trans.m02*m00+trans.m12*m01+m02;
300         double n12 = trans.m02*m10+trans.m12*m11+m12;
301         m00 = n00;
302         m01 = n01;
303         m02 = n02;
304         m10 = n10;
305         m11 = n11;
306         m12 = n12;
307     }
308 
309     /**
310      * @deprecated shapes are responsible of their transform (0.6.3)
311      */
312     @Deprecated
313     public Shape3D transform(Shape3D shape) {
314         return shape.transform(this);
315     }
316 
317     public Point3D[] transformPoints(Point3D[] src, Point3D[] dst) {
318         if (dst==null)
319             dst = new Point3D[src.length];
320         if (dst[0]==null)
321             for (int i = 0; i<src.length; i++)
322                 dst[i] = new Point3D();
323 
324         double coef[] = getCoefficients();
325 
326         for (int i = 0; i<src.length; i++)
327             dst[i].setLocation(new Point3D(src[i].getX()*coef[0]+src[i].getY()
328                     *coef[1]+src[i].getZ()*coef[2]+coef[3], src[i].getX()
329                     *coef[4]+src[i].getY()*coef[5]+src[i].getZ()*coef[6]
330                     +coef[7], src[i].getX()*coef[8]+src[i].getY()*coef[9]
331                     +src[i].getZ()*coef[10]+coef[12]));
332         return dst;
333     }
334 
335     public Point3D transformPoint(Point3D src, Point3D dst) {
336         double coef[] = getCoefficients();
337         if (dst==null)
338             dst = new Point3D();
339         dst.setLocation(new Point3D(src.getX()*coef[0]+src.getY()*coef[1]
340                 +src.getZ()*coef[2]+coef[3], src.getX()*coef[4]+src.getY()
341                 *coef[5]+src.getZ()*coef[6]+coef[7], src.getX()*coef[8]
342                 +src.getY()*coef[9]+src.getZ()*coef[10]+coef[12]));
343         return dst;
344     }
345 
346     /**
347      * Compares two transforms. Returns true if all inner fields are equal up to
348      * the precision given by Shape3D.ACCURACY.
349      */
350     @Override
351     public boolean equals(Object obj) {
352         if (!(obj instanceof AffineTransform3D))
353             return false;
354 
355         double tab[] = ((AffineTransform3D) obj).getCoefficients();
356 
357         if (Math.abs(tab[0]-m00)>Shape3D.ACCURACY)
358             return false;
359         if (Math.abs(tab[1]-m01)>Shape3D.ACCURACY)
360             return false;
361         if (Math.abs(tab[2]-m02)>Shape3D.ACCURACY)
362             return false;
363         if (Math.abs(tab[3]-m03)>Shape3D.ACCURACY)
364             return false;
365         if (Math.abs(tab[4]-m10)>Shape3D.ACCURACY)
366             return false;
367         if (Math.abs(tab[5]-m11)>Shape3D.ACCURACY)
368             return false;
369         if (Math.abs(tab[6]-m12)>Shape3D.ACCURACY)
370             return false;
371         if (Math.abs(tab[7]-m13)>Shape3D.ACCURACY)
372             return false;
373         if (Math.abs(tab[8]-m20)>Shape3D.ACCURACY)
374             return false;
375         if (Math.abs(tab[9]-m21)>Shape3D.ACCURACY)
376             return false;
377         if (Math.abs(tab[10]-m22)>Shape3D.ACCURACY)
378             return false;
379         if (Math.abs(tab[11]-m23)>Shape3D.ACCURACY)
380             return false;
381         return true;
382     }
383 
384 }