]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d/src/org/simantics/g3d/math/MathTools.java
08a1e7b0420c1b73c794362def6daa888d39b8cb
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / g3d / math / MathTools.java
1 /*******************************************************************************
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g3d.math;
13
14 import javax.vecmath.AxisAngle4d;
15 import javax.vecmath.Matrix3d;
16 import javax.vecmath.Matrix4d;
17 import javax.vecmath.Quat4d;
18 import javax.vecmath.Tuple2d;
19 import javax.vecmath.Tuple3d;
20 import javax.vecmath.Tuple4d;
21 import javax.vecmath.Vector2d;
22 import javax.vecmath.Vector2f;
23 import javax.vecmath.Vector3d;
24
25 import org.simantics.g3d.math.EulerTools.Order;
26
27
28 /**
29  * Some useful geometry related math functions. Beware, methods may modify their input parameters!
30  * 
31  * @author Marko Luukkainen
32  *
33  */
34 public class MathTools {
35     
36     public static double NEAR_ZERO = 0.000000001;
37     public static double NEAR_HALF = 0.499999999;
38     
39     public static final Vector3d Z_AXIS = new Vector3d(0.0,0.0,1.0);
40         public static final Vector3d Y_AXIS = new Vector3d(0.0,1.0,0.0);
41         public static final Vector3d X_AXIS = new Vector3d(1.0,0.0,0.0);
42         public static final Vector3d ORIGIN = new Vector3d(0.0,0.0,0.0);
43         
44         final static double EPS = 1.0e-12;
45         
46         
47         public static boolean equals(double d1, double d2) {
48                 return Math.abs(d1-d2) < EPS;
49         }
50         
51         public static boolean equals(Tuple3d p1, Tuple3d p2) {
52                 return distanceSquared(p1, p2) < NEAR_ZERO;
53         }
54         
55         public static boolean equals(Tuple4d p1, Tuple4d p2) {
56                 return distanceSquared(p1, p2) < NEAR_ZERO;
57         }
58         
59         public static double distance(Tuple3d p1, Tuple3d p2) {
60                 double dx, dy, dz;
61
62                 dx = p2.x - p1.x;
63                 dy = p2.y - p1.y;
64                 dz = p2.z - p1.z;
65                 return Math.sqrt(dx*dx+dy*dy+dz*dz);
66         }
67         
68         public static double distance(Tuple4d p1, Tuple4d p2) {
69                 double dx, dy, dz, dw;
70
71                 dx = p2.x - p1.x;
72                 dy = p2.y - p1.y;
73                 dz = p2.z - p1.z;
74                 dw = p2.w - p1.w;
75                 return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw);
76         }
77         
78         public static double distanceSquared(Tuple3d p1, Tuple3d p2) {
79                 double dx, dy, dz;
80
81                 dx = p2.x - p1.x;
82                 dy = p2.y - p1.y;
83                 dz = p2.z - p1.z;
84                 return dx*dx+dy*dy+dz*dz;
85         }
86         
87         public static double distanceSquared(Tuple4d p1, Tuple4d p2) {
88                 double dx, dy, dz, dw;
89
90                 dx = p2.x - p1.x;
91                 dy = p2.y - p1.y;
92                 dz = p2.z - p1.z;
93                 dw = p2.w - p1.w;
94                 return dx*dx+dy*dy+dz*dz+dw*dw;
95         }
96         
97         public static boolean isValid(Tuple3d t) {
98                 return !(Double.isInfinite(t.x) || Double.isNaN(t.x) ||
99                                  Double.isInfinite(t.y) || Double.isNaN(t.y) ||
100                                  Double.isInfinite(t.z) || Double.isNaN(t.z));
101         }
102     
103     public static Vector3d closestPointOnEdge(Vector3d point, Vector3d edgePoint1, Vector3d edgePoint2) {
104         point.sub(edgePoint1);
105         Vector3d v = new Vector3d(edgePoint2);
106         v.sub(edgePoint1);
107         double t = v.dot(point);
108         t /= v.lengthSquared();
109         if (t <= 0.0f)
110           return edgePoint1;
111         if (t >= 1.0f)
112           return edgePoint2;
113         v.scale(t);
114         v.add(edgePoint1);
115         return v;   
116     }
117     
118     public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir) {
119         Vector3d v = new Vector3d(point);
120         v.sub(straightPoint);
121         double t = straightDir.dot(v);
122         t /= straightDir.lengthSquared();
123         v.set(straightDir);
124         v.scale(t);
125         v.add(straightPoint);
126         return v;   
127     }
128     
129     public static Vector3d closestPointOnStraight(Tuple3d point, Tuple3d straightPoint, Vector3d straightDir, double u[]) {
130         Vector3d v = new Vector3d(point);
131         v.sub(straightPoint);
132         u[0] = straightDir.dot(v);
133         u[0] /= straightDir.lengthSquared();
134         v.set(straightDir);
135         v.scale(u[0]);
136         v.add(straightPoint);
137         return v;   
138     }
139     
140     public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, Tuple3d planePoint) {
141         point.sub(planePoint);
142         
143         return planeNormal.dot(point);
144     }
145       
146     public static double distanceFromPlane(Vector3d point, Vector3d planeNormal, float d) {
147         return (planeNormal.dot(point) + d);
148     }
149     
150     public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Tuple3d intersectPoint) {
151         intersectPoint.set(planePoint);
152         intersectPoint.sub(linePoint);
153         double u = planeNormal.dot(new Vector3d(intersectPoint));
154         double v = planeNormal.dot(lineDir);
155         if (Math.abs(v) < NEAR_ZERO)
156             return false;
157         u /= v;
158         intersectPoint.set(lineDir);
159         intersectPoint.scale(u);
160         intersectPoint.add(linePoint);
161         return true;
162     }
163     
164     public static boolean intersectStraightPlane(Tuple3d linePoint, Vector3d lineDir, Tuple3d planePoint, Vector3d planeNormal, Vector3d intersectPoint, double[] u) {
165         intersectPoint.set(planePoint);
166         intersectPoint.sub(linePoint);
167         u[0] = planeNormal.dot(intersectPoint);
168         double v = planeNormal.dot(lineDir);
169         if (Math.abs(v) < NEAR_ZERO)
170             return false;
171         u[0] /= v;
172         intersectPoint.set(lineDir);
173         intersectPoint.scale(u[0]);
174         intersectPoint.add(linePoint);
175         return true;
176     }
177     
178     public static boolean intersectLineLine(Tuple3d l1_start,Tuple3d l1_end,Tuple3d l2_start,Tuple3d l2_end,Tuple3d l1_pos, Tuple3d l2_pos) {
179             Vector3d p13 = new Vector3d();
180             Vector3d p43 = new Vector3d();
181             Vector3d p21 = new Vector3d();
182             double d1343,d4321,d1321,d4343,d2121;
183             double numer,denom;
184             p13.sub(l1_start, l2_start);
185             p43.sub(l2_end,l2_start);
186             if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)
187                return false;
188             p21.sub(l1_end,l1_start);
189             if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)
190                return false;
191
192             d1343 = p13.dot(p43);
193             d4321 = p43.dot(p21);
194             d1321 = p13.dot(p21);
195             d4343 = p43.lengthSquared();
196             d2121 = p21.lengthSquared();
197
198             denom = d2121 * d4343 - d4321 * d4321;
199             if (Math.abs(denom) < NEAR_ZERO)
200                return false;
201             numer = d1343 * d4321 - d1321 * d4343;
202
203             double mua = numer / denom;
204             double mub = (d1343 + d4321 * mua) / d4343;
205  
206             l1_pos.x = l1_start.x + mua * p21.x;
207             l1_pos.y = l1_start.y + mua * p21.y;
208             l1_pos.z = l1_start.z + mua * p21.z;
209             l2_pos.x = l2_start.x + mub * p43.x;
210             l2_pos.y = l2_start.y + mub * p43.y;
211             l2_pos.z = l2_start.z + mub * p43.z;
212
213             return true;
214     }
215     
216     public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb) {
217         Vector3d p13 = new Vector3d();
218
219         double d1343,d4321,d1321,d4343,d2121;
220         double numer,denom;
221         
222         p13.sub(p1, p3);
223         if (Math.abs(p43.x)  < NEAR_ZERO && Math.abs(p43.y)  < NEAR_ZERO && Math.abs(p43.z)  < NEAR_ZERO)
224            return false;
225         if (Math.abs(p21.x)  < NEAR_ZERO && Math.abs(p21.y)  < NEAR_ZERO && Math.abs(p21.z)  < NEAR_ZERO)
226            return false;
227
228         d1343 = p13.dot(p43);
229         d4321 = p43.dot(p21);
230         d1321 = p13.dot(p21);
231         d4343 = p43.lengthSquared();
232         d2121 = p21.lengthSquared();
233
234         denom = d2121 * d4343 - d4321 * d4321;
235         if (Math.abs(denom) < NEAR_ZERO)
236            return false;
237         numer = d1343 * d4321 - d1321 * d4343;
238
239         double mua = numer / denom;
240         double mub = (d1343 + d4321 * mua) / d4343;
241
242         pa.x = p1.x + mua * p21.x;
243         pa.y = p1.y + mua * p21.y;
244         pa.z = p1.z + mua * p21.z;
245         pb.x = p3.x + mub * p43.x;
246         pb.y = p3.y + mub * p43.y;
247         pb.z = p3.z + mub * p43.z;
248
249         return true;
250    }
251     
252     /**
253      * Calculate the line segment PaPb that is the shortest route between
254      *  two lines P1P2 and P3P4. Calculate also the values of mua and mub where
255      *  Pa = P1 + mua (P2 - P1)
256      *  Pb = P3 + mub (P4 - P3)
257      * @param p1
258      * @param p21
259      * @param p3
260      * @param p43
261      * @param pa
262      * @param pb
263      * @param mu
264      * @return
265      */
266     public static boolean intersectStraightStraight(Tuple3d p1,Vector3d p21,Tuple3d p3,Vector3d p43,Tuple3d pa,Tuple3d pb, double mu[]) {
267         Vector3d p13 = new Vector3d();
268
269         double d1343,d4321,d1321,d4343,d2121;
270         double numer,denom;
271         double EPS = 0.001;
272         p13.sub(p1, p3);
273         if (Math.abs(p43.x)  < EPS && Math.abs(p43.y)  < EPS && Math.abs(p43.z)  < EPS)
274            return false;
275         if (Math.abs(p21.x)  < EPS && Math.abs(p21.y)  < EPS && Math.abs(p21.z)  < EPS)
276            return false;
277
278         d1343 = p13.dot(p43);
279         d4321 = p43.dot(p21);
280         d1321 = p13.dot(p21);
281         d4343 = p43.lengthSquared();
282         d2121 = p21.lengthSquared();
283
284         denom = d2121 * d4343 - d4321 * d4321;
285         if (Math.abs(denom) < EPS)
286            return false;
287         numer = d1343 * d4321 - d1321 * d4343;
288
289         mu[0] = numer / denom;
290         mu[1] = (d1343 + d4321 * mu[0]) / d4343;
291
292         pa.x = p1.x + mu[0] * p21.x;
293         pa.y = p1.y + mu[0] * p21.y;
294         pa.z = p1.z + mu[0] * p21.z;
295         pb.x = p3.x + mu[1] * p43.x;
296         pb.y = p3.y + mu[1] * p43.y;
297         pb.z = p3.z + mu[1] * p43.z;
298
299         return true;
300    }
301    
302   
303    
304    public static void rotate(Quat4d q, Tuple3d in, Tuple3d out) {
305        // p' = q * p * q'
306        double tw =           - q.x*in.x - q.y*in.y - q.z*in.z;
307        double tx =  q.w*in.x            + q.y*in.z - q.z*in.y;
308        double ty =  q.w*in.y - q.x*in.z            + q.z*in.x;
309        double tz =  q.w*in.z + q.x*in.y - q.y*in.x           ;
310        
311        //temp * q' -> x = -x, y = -y z = -z
312        //out.w = tw*q.w + tx*q.x + ty*q.y + tz*q.z;
313        out.x =  -tw*q.x + tx*q.w - ty*q.z + tz*q.y;
314        out.y =  -tw*q.y + tx*q.z + ty*q.w - tz*q.x;
315        out.z =  -tw*q.z - tx*q.y + ty*q.x + tz*q.w;  
316    }
317    
318    public static void getMatrix(Quat4d quat, Matrix3d m) {
319                    m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z);
320                    m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z);
321                    m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y);
322                    m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z);
323                    m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z);
324                    m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x);
325                    m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y);
326                    m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x);
327                    m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y);
328
329    }
330    
331    public static void getMatrix(Quat4d quat, Matrix4d m) {
332            m.setZero();
333            m.m00 = 1.0f - 2.0 * (quat.y * quat.y + quat.z * quat.z);
334            m.m01 = 2.0 * (quat.x * quat.y + quat.w * quat.z);
335            m.m02 = 2.0 * (quat.x * quat.z - quat.w * quat.y);
336            m.m10 = 2.0 * (quat.x * quat.y - quat.w * quat.z);
337            m.m11 = 1.0 - 2.0f * (quat.x * quat.x + quat.z * quat.z);
338            m.m12 = 2.0 * (quat.y * quat.z + quat.w * quat.x);
339            m.m20 = 2.0 * (quat.x * quat.z + quat.w * quat.y);
340            m.m21 = 2.0 * (quat.y * quat.z - quat.w * quat.x);
341            m.m22 = 1.0 - 2.0f * (quat.x * quat.x + quat.y * quat.y);
342            m.m33 = 1.0;
343    }
344    
345    private static double q[] = new double[3];
346    private static int nxt[] = { 1, 2, 0 };
347    /**
348     * Converts Matrix to Quaternion
349     * 
350     * Note: non-thread safe.
351     * 
352     * @param mat
353     * @param quat
354     */
355    public static void getQuat(Matrix3d mat, Quat4d quat) {
356            double tr = mat.m00 + mat.m11 + mat.m22;
357                 if (tr > 0.0) {
358                         double s = Math.sqrt(tr + 1.0);
359                         quat.w = 0.5 * s;
360                         s = 0.5 / s;
361                         quat.x = (mat.m21 - mat.m12) * s;
362                         quat.y = (mat.m02 - mat.m20) * s;
363                         quat.z = (mat.m10 - mat.m01) * s;
364                 } else {
365                         int i = 0, j, k;
366                         if (mat.m11 > mat.m00)
367                                 i = 1;
368                         if (mat.m22 > mat.getElement(i, i))
369                                 i = 2;
370                         
371
372                         j = nxt[i];
373                         k = nxt[j];
374
375                         double s = Math.sqrt((mat.getElement(i, i) - (mat.getElement(j, j) + mat.getElement(k, k))) + 1.0);
376
377                         q[i] = s * 0.5;
378
379                         if (Math.abs(s) > 0.001)
380                                 s = 0.5 / s;
381
382                         quat.w = (mat.getElement(k, j) - mat.getElement(j, k)) * s;
383                         q[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s;
384                         q[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s;
385
386                         quat.x = q[0];
387                         quat.y = q[1];
388                         quat.z = q[2];
389                 }
390         }
391    
392    public static Quat4d getQuat(Matrix3d mat) {
393            Quat4d q = new Quat4d();
394            getQuat(mat, q);
395            return q;
396    }
397    
398    public static AxisAngle4d getFromPseudoEuler(Vector3d euler) {
399        AxisAngle4d aa = new AxisAngle4d();
400        aa.angle = euler.length();
401        Vector3d normal = new Vector3d(euler);
402        if (aa.angle > NEAR_ZERO) {
403            normal.normalize();
404            aa.x = normal.x;
405            aa.y = normal.y;
406            aa.z = normal.z;
407        } else {
408            aa.x = 1.0;
409            aa.y = 0.0;
410            aa.z = 0.0;
411        }
412        
413        return aa;
414    }
415    
416    public static Vector3d getPseudoEuler(AxisAngle4d aa) {
417        Vector3d euler = new Vector3d(aa.x,aa.y,aa.z);
418        euler.scale(aa.angle);
419        return euler;
420    }
421    
422    
423    public static void getQuat(Vector3d euler, Quat4d quat)  {
424            Quat4d q = EulerTools.getQuatFromEuler(Order.YXZ, euler.y,euler.x,euler.z);
425            quat.set(q);
426         // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms
427         // Using the x-convention, the 3-1-3 Euler angles phi, theta and psi (around the Z, X and again the Z-axis)   
428 //         quat.x = -Math.cos((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);
429 //         quat.y = -Math.sin((euler.x - euler.z)*0.5)*Math.sin(euler.y*0.5);
430 //         quat.z = -Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);
431 //         quat.w = Math.sin((euler.x + euler.z)*0.5)*Math.cos(euler.y*0.5);
432            
433            // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
434            // Y, Z, X order
435 //          double c1 = Math.cos(euler.y*0.5);
436 //          double s1 = Math.sin(euler.y*0.5);
437 //          double c2 = Math.cos(euler.z*0.5);
438 //          double s2 = Math.sin(euler.z*0.5);
439 //          double c3 = Math.cos(euler.x*0.5);
440 //          double s3 = Math.sin(euler.x*0.5);
441 //          double c1c2 = c1*c2;
442 //          double s1s2 = s1*s2;
443 //          quat.w =c1c2*c3 - s1s2*s3;
444 //          quat.x =c1c2*s3 + s1s2*c3;
445 //          quat.y =s1*c2*c3 + c1*s2*s3;
446 //          quat.z =c1*s2*c3 - s1*c2*s3;
447
448 //          Quat4d q2 = EulerTools.getQuatFromEuler(Order.YZX, euler.y,euler.z,euler.x);
449 //          System.out.println("Q " + quat + " Q2 " + q2);
450 //         double c1 = Math.cos(euler.y);
451 //          double s1 = Math.sin(euler.y);
452 //          double c2 = Math.cos(euler.z);
453 //          double s2 = Math.sin(euler.z);
454 //          double c3 = Math.cos(euler.x);
455 //          double s3 = Math.sin(euler.x);
456 //          quat.w = Math.sqrt(1.0 + c1 * c2 + c1*c3 - s1 * s2 * s3 + c2*c3) / 2.0;
457 //          double w4 = (4.0 * quat.w);
458 //          quat.x = (c2 * s3 + c1 * s3 + s1 * s2 * c3) / w4 ;
459 //          quat.y = (s1 * c2 + s1 * c3 + c1 * s2 * s3) / w4 ;
460 //          quat.z = (-s1 * s3 + c1 * s2 * c3 +s2) / w4 ;
461    }
462    
463    
464   
465    
466    public static void getEuler(Quat4d quat,Vector3d euler)  {
467            Vector3d e = EulerTools.getEulerFromQuat(Order.YXZ, quat);
468            euler.x = e.y;
469            euler.y = e.x;
470            euler.z = e.z;
471            
472            // http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Conversion_formulae_between_formalisms
473 //         euler.x = Math.atan2(quat.x * quat.z + quat.y* quat.w, quat.y*quat.z - quat.x * quat.w);
474 //         euler.y = Math.acos(-square(quat.x) - square(quat.y) + square(quat.z) + square(quat.w));
475 //         euler.z = -Math.atan2(quat.x * quat.z - quat.y* quat.w, quat.y*quat.z + quat.x * quat.w);
476            
477            // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm
478           // Y, Z, X order
479 //         double test = quat.x * quat.y + quat.z * quat.w;
480 //         if (test > NEAR_HALF) {
481 //                 euler.y = 2.0 * Math.atan2(quat.x,quat.w);
482 //                 euler.z = Math.PI * 0.5;
483 //                 euler.x = 0.0;
484 //         } else if (test < -NEAR_HALF) {
485 //                 euler.y = -2.0 * Math.atan2(quat.x,quat.w);
486 //                 euler.z = -Math.PI * 0.5;
487 //                 euler.x = 0.0;
488 //         } else {
489 //                 double sqx = square(quat.x);
490 //                 double sqy = square(quat.y);
491 //                 double sqz = square(quat.z);
492 //                 euler.y = Math.atan2(2.0*(quat.y*quat.w-quat.x*quat.z), 1.0 - 2.0*(sqy-sqz));
493 //                 euler.z = Math.asin(2.0*test);
494 //                 euler.x = Math.atan2(2.0*(quat.x*quat.w-quat.y*quat.z), 1.0 - 2.0*(sqx-sqz));
495 //                 System.out.println(euler + " " + EulerTools.getEulerFromQuat(Order.YXZ, quat) +  " " + quat);
496 //         }
497 //         double sqw = quat.w*quat.w;
498 //          double sqx = quat.x*quat.x;
499 //          double sqy = quat.y*quat.y;
500 //          double sqz = quat.z*quat.z;
501 //              double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
502 //              double test = quat.x*quat.y + quat.z*quat.w;
503 //              if (test > 0.499*unit) { // singularity at north pole
504 //                      euler.y = 2 * Math.atan2(quat.x,quat.w);
505 //                      euler.z = Math.PI/2;
506 //                      euler.x = 0;
507 //                      return;
508 //              }
509 //              if (test < -0.499*unit) { // singularity at south pole
510 //                      euler.y = -2 * Math.atan2(quat.x,quat.w);
511 //                      euler.z = -Math.PI/2;
512 //                      euler.x = 0;
513 //                      return;
514 //              }
515 //              euler.y = Math.atan2(2*quat.y*quat.w-2*quat.x*quat.z , sqx - sqy - sqz + sqw);
516 //              euler.z = Math.asin(2*test/unit);
517 //              euler.x = Math.atan2(2*quat.x*quat.w-2*quat.y*quat.z , -sqx + sqy - sqz + sqw);
518    }
519    
520    public static Quat4d getQuat(Vector3d euler) {
521            Quat4d q = new Quat4d();
522            getQuat(euler,q);
523            return q;
524    }
525    
526    
527    public static Vector3d getEuler(Quat4d quat) {
528            Vector3d v = new Vector3d();
529            getEuler(quat, v);
530            return v;
531    }
532    
533    public static Quat4d getQuat(AxisAngle4d aa) {
534            Quat4d q = new Quat4d();
535            getQuat(aa, q);
536            return q;
537    }
538    
539         public static AxisAngle4d getAxisAngle(Quat4d q) {
540                 AxisAngle4d aa = new AxisAngle4d();
541                 double mag = q.x * q.x + q.y * q.y + q.z * q.z;
542
543                 if (mag > EPS) {
544                         mag = Math.sqrt(mag);
545                         aa.angle = 2.0 * Math.atan2(mag, q.w);
546                         mag = 1.0 / mag;
547                         aa.x = q.x * mag;
548                         aa.y = q.y * mag;
549                         aa.z = q.z * mag;
550                         
551                 } else {
552                         aa.x = 0.0;
553                         aa.y = 1.0;
554                         aa.z = 0.0;
555                         aa.angle = 0.0;
556                 }
557                 // aa.set(q);
558                 return aa;
559         }
560    
561    public static Quat4d getIdentityQuat() {
562            return new Quat4d(0, 0, 0, 1);
563    }
564    
565    public static void getQuat(AxisAngle4d aa, Quat4d q) {
566            double mag,amag;
567                 // Quat = cos(theta/2) + sin(theta/2)(roation_axis) 
568                 
569                 amag = Math.sqrt( aa.x*aa.x + aa.y*aa.y + aa.z*aa.z);
570                 if( amag < NEAR_ZERO ) {
571                     q.w = 1.0;
572                     q.x = 0.0;
573                     q.y = 0.0;
574                     q.z = 0.0;
575                 } else {  
576                    amag = 1.0/amag; 
577                    double a2 = aa.angle * 0.5;
578                    mag = Math.sin(a2);
579                    q.w = Math.cos(a2);
580                q.x = aa.x*amag*mag;
581                q.y = aa.y*amag*mag;
582                q.z = aa.z*amag*mag;
583                 }
584    }
585    
586    
587         /*
588          * Cohen-Sutherland
589          */
590         
591         private static final int IN = 0;
592         private static final int LEFT = 1;
593         private static final int RIGHT = 2;
594         private static final int BOTTOM = 4;
595         private static final int TOP = 8;
596         
597         
598         private static int bitcode(Vector2f p1, Vector2f min, Vector2f max) {
599                 int code = IN;
600                 if (p1.x < min.x)
601                         code |= LEFT;
602                 else if (p1.x > max.x)
603                         code |= RIGHT;
604                 if (p1.y < min.y)
605                         code |= BOTTOM;
606                 else if (p1.y > max.y)
607                         code |= TOP;
608                 return code;
609         }
610         
611         public static boolean clipLineRectangle(Vector2f p1,Vector2f p2, Vector2f min, Vector2f max, Vector2f r1, Vector2f r2) {
612                 while (true) {
613                         int o1 = bitcode(p1, min, max);
614                         int o2 = bitcode(p2, min, max);
615                         int and = o1 & o2;
616                         int or = o1 | o2;
617                         if (and != IN) {
618                                 return false;
619                         }
620                         if (or == IN) {
621                                 r1.set(p1);
622                                 r2.set(p2);
623                                 return true;
624                         }
625                         if (o1 == IN) {
626                                 Vector2f t = p1;
627                                 p1 = p2;
628                                 p2 = t;
629                                 int t2 = o1;
630                                 o1 = o2;
631                                 o2 = t2;
632                         }
633                         if ((o1 & TOP) != IN) {
634                                 float t = (max.y - p1.y) / (p2.y - p1.y);
635                                 p1.x += t * (p2.x - p1.x);
636                                 p1.y = max.y;
637                         } else if ((o1 & BOTTOM) != IN) {
638                                 float t = (min.y - p1.y) / (p2.y - p1.y);
639                                 p1.x += t * (p2.x - p1.x);
640                                 p1.y = min.y;
641                         } else if ((o1 & LEFT) != IN) {
642                                 float t = (min.x - p1.x) / (p2.x - p1.x);
643                                 p1.y += t * (p2.y - p1.y);
644                                 p1.x = min.x;
645                         } else if ((o1 & RIGHT) != IN) {
646                                 float t = (max.x - p1.x) / (p2.x - p1.x);
647                                 p1.y += t * (p2.y - p1.y);
648                                 p1.x = max.x;
649                         } else {
650                                 throw new RuntimeException("Error in clipping code");
651                         }
652                 }
653                 
654         }
655         
656         public static double square(double d) {
657                 return d * d;
658         }
659         
660         
661          public static void multiplyOrientation(AxisAngle4d aa, AxisAngle4d rot)  {
662                 Quat4d q1 = new Quat4d();
663                 getQuat(aa, q1);
664                 Quat4d q2 = new Quat4d();
665                 getQuat(rot, q2);
666                 q2.mul(q1);
667                 rot.set(q2);
668          }
669          
670          public static double radToDeg(double rad) {
671                  return (rad / Math.PI) * 180.0;
672          }
673          
674          public static double degToRad(double deg) {
675                  return (deg / 180.0) * Math.PI;
676          }
677          
678          public static double clamp(double min, double max,double v) {
679                  if (v < min)
680                          return min;
681                  if (v > max)
682                          return max;
683                  return v;
684          }
685          
686          public static AxisAngle4d createRotation(Vector3d original, Vector3d rotated) { 
687                 AxisAngle4d result = new AxisAngle4d();
688                 if (createRotation(original, rotated, result))
689                         return result;
690                 return null;
691          }
692          
693          
694          public static void setIdentity(Quat4d q) {
695                 q.w = 1.0;
696                 q.x = 0.0;
697                 q.y = 0.0;
698                 q.z = 0.0;
699          }
700          
701         public static void setIdentity(AxisAngle4d aa) {
702                 aa.angle = 0.0;
703                 aa.x = 0.0;
704                 aa.y = 1.0;
705                 aa.z = 0.0;
706         }
707         
708         public static void set(Matrix3d mat, double m00, double m01, double m02,
709                         double m10, double m11, double m12, double m20, double m21,
710                         double m22) {
711                 mat.m00 = m00;
712                 mat.m01 = m01;
713                 mat.m02 = m02;
714
715                 mat.m10 = m10;
716                 mat.m11 = m11;
717                 mat.m12 = m12;
718
719                 mat.m20 = m20;
720                 mat.m21 = m21;
721                 mat.m22 = m22;
722         }
723         
724         public static void set(Matrix4d mat, double[] v) {
725                 mat.m00 = v[0];
726                 mat.m01 = v[1];
727                 mat.m02 = v[2];
728                 mat.m03 = v[3];
729
730                 mat.m10 = v[4];
731                 mat.m11 = v[5];
732                 mat.m12 = v[6];
733                 mat.m13 = v[7];
734
735                 mat.m20 = v[8];
736                 mat.m21 = v[9];
737                 mat.m22 = v[10];
738                 mat.m23 = v[11];
739
740                 mat.m30 = v[12];
741                 mat.m31 = v[13];
742                 mat.m32 = v[14];
743                 mat.m33 = v[15];
744
745         }
746          
747          public static boolean createRotation(Vector3d original, Vector3d rotated, AxisAngle4d result) {
748                  
749                         if (rotated.lengthSquared() > 0.01)
750                                 rotated.normalize();
751                         else
752                                 return false;
753                         double d = original.dot(rotated);
754                         if (d > 0.9999) {
755                                 // original and rotated are parallel, pointing at the same direction
756                                 result.angle = 0.0;
757                                 result.x = 0.0;
758                                 result.y = 1.0;
759                                 result.z = 0.0;
760                         } else if (d < -0.9999) {
761                                 // original and rotated are parallel, pointing at the opposite direction 
762                                 Vector3d a = Z_AXIS;
763                                 if (Math.abs(a.dot(original)) > 0.8 )
764                                         a = Y_AXIS;
765                                 result.set(a, Math.PI);
766                         } else {
767                                 double angle = original.angle(rotated);
768                                 Vector3d axis = new Vector3d();
769                                 axis.cross(original, rotated);
770                                 result.set(axis,angle);
771                         }
772                         return true;
773                  }
774          
775          public static boolean createRotation(Vector3d original, Vector3d rotated, Quat4d result) {
776                  
777                         if (rotated.lengthSquared() > 0.01)
778                                 rotated.normalize();
779                         else
780                                 return false;
781                         double d = original.dot(rotated);
782                         if (d > 0.9999) {
783                                 // original and rotated are parallel, pointing at the same direction
784                                 result.w = 1.0;
785                                 result.x = 0.0;
786                                 result.y = 0.0;
787                                 result.z = 0.0;
788                         } else if (d < -0.9999) {
789                                 // original and rotated are parallel, pointing at the opposite direction 
790                                 Vector3d a = Z_AXIS;
791                                 if (Math.abs(a.dot(original)) > 0.8 )
792                                         a = Y_AXIS;
793                                 getQuat(a, Math.PI, result);
794                                 
795                         } else {
796                                 double angle = original.angle(rotated);
797                                 Vector3d axis = new Vector3d();
798                                 axis.cross(original, rotated);
799                                 getQuat(axis, angle, result);
800                         }
801                         return true;
802                  }
803          
804          public static void getQuat(Vector3d axis, double angle, Quat4d q)
805     {
806                 double mag,amag;
807                 // Quat = cos(theta/2) + sin(theta/2)(roation_axis) 
808                 
809                 amag = Math.sqrt( axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
810                 if( amag < EPS ) {
811                     q.w = 1.0;
812                     q.x = 0.0;
813                     q.y = 0.0;
814                     q.z = 0.0;
815                 } else {  
816                     amag = 1.0/amag; 
817                     double a2 = angle*0.5;
818                     mag = Math.sin(a2);
819                     q.w = Math.cos(a2);
820                     q.x = axis.x*amag*mag;
821                     q.y = axis.y*amag*mag;
822                     q.z = axis.z*amag*mag;
823                 }
824         
825     }
826          
827          /**
828           * Linear interpolation of quaternions. Result IS set to q1.
829           * @param q1
830           * @param q2
831           * @param alpha
832           */
833          public static void lip(Quat4d q1, Quat4d q2, double alpha) {
834                  double s1 = 1.0 - alpha;
835                  double s2 = alpha;
836                  q1.scale(s1);
837                  mad(q1,q2,s2);
838                  q1.normalize();
839          }
840          
841          public static double dot(Quat4d q1, Quat4d q2) {
842                  return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
843          }
844          
845          public static void mad(Tuple3d q1, Tuple3d q2, double s2) {
846                  q1.x += q2.x * s2;
847                  q1.y += q2.y * s2;
848                  q1.z += q2.z * s2;
849          }
850          
851          public static void mad(Quat4d q1, Quat4d q2, double s2) {
852                  q1.x += q2.x * s2;
853                  q1.y += q2.y * s2;
854                  q1.z += q2.z * s2;
855                  q1.w += q2.w * s2;
856          }
857          
858          /**
859           * Slerp
860           * 
861           * Sets results to q1. Modifies q2.
862           * 
863           * @param q1
864           * @param q2
865           * @param alpha
866           */
867          public static void sip(Quat4d q1, Quat4d q2, double alpha) {
868                  double cosom = dot(q1,q2);
869                  if (cosom < 0.0) {
870                          cosom = -cosom;
871                          q2.negate();
872                  }
873                  
874                  if (cosom > 0.9999) {
875                          q2.sub(q1);
876                          q2.scale(alpha);
877                          q1.add(q2);
878                          q1.normalize();
879                          return;
880                  }
881                  double theta_0 = Math.acos(cosom);
882                  double theta = theta_0 * alpha;
883                  Quat4d t = new Quat4d(q1);
884                  t.scale(-cosom);
885                  t.add(q2);
886                  t.normalize();
887                  t.scale(Math.sin(theta));
888                  q1.scale(Math.cos(theta));
889                  q1.add(t);
890          }
891          
892          
893          public static void rotate(double angle, Tuple2d v1, Tuple2d v2) {
894                  // TODO : verify implementation
895         double sin = Math.sin(angle);
896         if (sin == 1.0) {
897             v2.x = v1.y;
898             v2.y = -v1.x;
899         } else if (sin == -1.0) {
900                 v2.x = -v1.y;
901             v2.y = v1.x;
902         } else {
903             double cos = Math.cos(angle);
904             if (cos == -1.0) {
905                 v2.x = -v1.x;
906                 v2.y = -v1.y;
907             } else if (cos != 1.0) {
908                 v2.x= v1.x * cos + v1.y * -sin;
909                 v2.y= v1.x* sin + v1.y *cos;
910             }
911         }       
912          }
913          
914          public static Tuple3d getPosRot(double m3x2[]) {
915                  Vector3d t = new Vector3d();
916                  t.x = m3x2[4];
917                  t.y = m3x2[5];
918                  
919                  
920                  Vector2d v2 = new Vector2d(1,0);
921                  Vector2d v = new Vector2d();
922                  // use rotation of (1,0) to calculate the rotation component
923          v.x  =  m3x2[0];
924          v.y  =  m3x2[2];
925          double a1 = v2.angle(v);
926          if (v.y < 0) {
927                  t.z = a1;
928          } else {
929                  t.z = Math.PI*2.0 - a1;
930          }
931          return t;
932          }
933          
934          public static Matrix4d glFrustum(double l, double r, double b, double t, double n, double f) {
935                  Matrix4d mat = new Matrix4d();
936                  mat.m00 = 2.0 * n / (r - l);
937                  mat.m11 = 2.0 * n / (t - b);
938                  mat.m02 = (r+l) / (r-l);
939                  mat.m12 = (t+b) / (t-b);
940                  mat.m22 = -(f+n) / (f-n);
941                  mat.m23 = -(2.0 *f * n) / (f-n);
942                  mat.m32 = -1.0;
943                  return mat;
944          }
945          
946          public static Matrix4d glOrtho(double l, double r, double b, double t, double n, double f) {
947                  Matrix4d mat = new Matrix4d();
948                  mat.m00 = 2.0 / (r - l);
949                  mat.m11 = 2.0 / (t - b);
950                  mat.m22 = -2.0 / (f-n);
951                  mat.m33 =  1.0;
952                  mat.m03 = -(r+l)/(r-l);
953                  mat.m13 = -(t+b)/(t-b);
954                  mat.m23 = -(f+n)/(f-n);
955                  return mat;
956          }
957 }