OSDN Git Service

Set optimal mime types and executable settings.
[mikumikustudio/MikuMikuStudio.git] / src / com / jme / math / TransformMatrix.java
1 /*
2  * Copyright (c) 2003-2009 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 package com.jme.math;
34
35 import java.io.IOException;
36 import java.io.Serializable;
37 import java.util.logging.Logger;
38
39 import com.jme.scene.Spatial;
40 import com.jme.system.JmeException;
41 import com.jme.util.export.InputCapsule;
42 import com.jme.util.export.JMEExporter;
43 import com.jme.util.export.JMEImporter;
44 import com.jme.util.export.OutputCapsule;
45 import com.jme.util.export.Savable;
46
47 /**
48  * TransformMatrix holds a rotation (Matrix3f)  and translation (Vector3f) for point manipulation
49  *
50  * @author Jack Lindamood
51  * @author Joshua Slack
52  */
53 public class TransformMatrix  implements Serializable, Savable, Cloneable {
54     private static final Logger logger = Logger.getLogger(TransformMatrix.class
55             .getName());
56     
57     // TODO: Clean up and standardize this class's functionality
58     private static final long serialVersionUID = 1L;
59
60     private Matrix3f rot=new Matrix3f();
61     private Vector3f translation=new Vector3f();
62     private Vector3f scale=new Vector3f(1,1,1);
63
64     /**
65      * Constructor instantiates a new <code>TransformMatrix</code> that is set to the
66      * identity matrix by default.
67      *
68      */
69     public TransformMatrix() {
70     }
71
72     /**
73      * Constructor instantiates a new <code>TransformMatrix</code> that is set to the
74      * provided matrix. This constructor copies a given matrix. If the
75      * provided matrix is null, the constructor sets the matrix to the
76      * identity.
77      * @param mat the matrix to copy.
78      */
79     public TransformMatrix(TransformMatrix mat) {
80         set(mat);
81     }
82
83     /**
84      * Constructor instantiates a new <code>TransformMatrix</code> that has rotation
85      * and translation defined by its parameters
86      * @param myRot The given rotation, as a <code>Quaternion</code>
87      * @param myPos The given translation, as a <code>Vector3f</code>
88      */
89     public TransformMatrix(Quaternion myRot, Vector3f myPos) {
90         rot.set(myRot);
91         translation.set(myPos);
92     }
93
94     /**
95      * <code>set</code> transfers the contents of a given matrix to this
96      * matrix. If a null matrix is supplied, this matrix is set to the
97      * identity matrix.
98      * @param matrix the matrix to copy.
99      */
100     public void set(TransformMatrix matrix) {
101         if (matrix == null) {
102             loadIdentity();
103         } else {
104             rot.copy(matrix.rot);
105             translation.set(matrix.translation);
106             scale.set(matrix.scale);
107         }
108     }
109
110
111     /**
112      *
113      * <code>set</code> defines the values of the matrix based on a supplied
114      * <code>Quaternion</code>. It should be noted that all previous values
115      * will be overridden.
116      * @param quaternion the quaternion to create a rotational matrix from.
117      */
118     public void set(Quaternion quaternion) {
119         rot.set(quaternion);
120         translation.zero();
121         scale.set(1,1,1);
122     }
123
124     /**
125      * <code>loadIdentity</code> sets this matrix to the identity matrix,
126      * namely all zeros with ones along the diagonal.
127      *
128      */
129     public void loadIdentity() {
130         rot.loadIdentity();
131         translation.zero();
132         scale.set(1,1,1);
133     }
134
135     /**
136      * Multiplies every value in the matrix by a scalar
137      * @param scalar
138      */
139     public void mult(float scalar) {
140         rot.multLocal(scalar);
141         translation.mult(scalar);
142         scale.multLocal(scalar);
143     }
144
145     /**
146      * <code>multLocal</code> multiplies this matrix with another matrix and stores
147      * the result back in this, returning this.  if null is passed, nothing happens
148      * This function changes this matrix to what the child would look like if this were applied as it's parent
149      * @param child The matrix to multiply by
150      * @param tempStore A temporary Vector3f object for this TransformMatrix to use during the calculation.
151      * @return this matrix after multiplication
152      */
153     public TransformMatrix multLocal(TransformMatrix child,Vector3f tempStore){
154         this.scale.multLocal(child.scale);
155         this.translation.addLocal(rot.mult(child.translation,tempStore).multLocal(child.scale));
156         this.rot.multLocal(child.rot);
157         return this;
158     }
159
160     /**
161      * Sets this transform to an interpolation between the start and end transforms.  Note that
162      * this function isn't very efficient as it has to create 2 new Quaternions to do the
163      * rotation interpolation
164      * @param start Begining transform (delta=0)
165      * @param end Ending transform (delta=1)
166      * @param delta Value between 0.0 and 1.0 to show which side the transform leans towards
167      */
168     public void interpolateTransforms(TransformMatrix start,TransformMatrix end,float delta){
169         this.translation.set(start.translation).interpolate(end.translation,delta);
170         this.scale.set(start.scale).interpolate(end.scale,delta);
171         Quaternion q1=new Quaternion(),q2=new Quaternion();
172         start.getRotation(q1);
173         end.getRotation(q2);
174         q1.slerp(q2,delta);
175         this.setRotationQuaternion(q1);
176     }
177
178     /**
179      * Sets this transform to an interpolation between the start and end transforms.  Same as above but doesn't
180      * create 2 new Quaternions
181      * @param start Begining transform (delta=0)
182      * @param end Ending transform (delta=1)
183      * @param delta Value between 0.0 and 1.0 to show which side the transform leans towards
184      * @param q1 A temporary Quaternion
185      * @param q2 Another temporary Quaternion
186      */
187     public void interpolateTransforms(TransformMatrix start,TransformMatrix end,float delta,Quaternion q1,Quaternion q2){
188         this.translation.set(start.translation).interpolate(end.translation,delta);
189         this.scale.set(start.scale).interpolate(end.scale,delta);
190         start.getRotation(q1);
191         end.getRotation(q2);
192         q1.slerp(q2,delta);
193         this.setRotationQuaternion(q1);
194     }
195
196
197     /**
198      * <code>mult</code> multiplies a normal about a transform matrix and
199      * stores the result back in vec. The resulting vector is returned
200      * with translational ignored.
201      * @param vec the rotation normal.
202      * @return The given Vector3f, after rotation
203      */
204     public Vector3f multNormal(Vector3f vec) {
205         if (null == vec) {
206             logger.warning("Source vector is null, null result returned.");
207             return null;
208         }
209         return rot.multLocal(vec);
210     }
211
212     /**
213      * <code>mult</code> multiplies a vector about a transform matrix. The
214      * resulting vector is saved in vec and returned.
215      * @param vec The point to rotate.
216      * @return The rotated vector.
217      */
218     public Vector3f multPoint(Vector3f vec) {
219         if (null == vec) {
220             logger.warning("Source vector is null, null result returned.");
221             return null;
222         }
223         return rot.multLocal(vec).multLocal(scale).addLocal(translation);
224     }
225
226
227     /**
228      * Sets the rotation matrix to the given rotation matrix via a copy.  If null is supplied, the identity is set
229      * @param rot The new rotation
230      */
231     public void setRotation(Matrix3f rot){
232         this.rot.copy(rot);
233     }
234
235     /**
236      * <code>setTranslation</code> will set the matrix's translation values.
237      * @param transArray the new values for the translation.
238      * @throws JmeException if translation is null or not size 3.
239      */
240     public void setTranslation(float[] transArray) {
241         if (transArray == null || transArray.length != 3) {
242             throw new JmeException("Translation size must be 3.");
243         }
244         translation.x = transArray[0];
245         translation.y = transArray[1];
246         translation.z = transArray[2];
247     }
248
249     /** <code>setTranslation</code> will copy the given Vector3f's values
250      * into this Matrix's translational component
251      *
252      * @param trans
253      */
254     public void setTranslation(Vector3f trans){
255         if (trans==null){
256             throw new JmeException("Vector3f translation must be non-null");
257         }
258         translation.set(trans);
259     }
260
261     /**
262      * Sets the Transform's Translational component
263      * @param x New X translation
264      * @param y New Y translation
265      * @param z New Z translation
266      */
267     public void setTranslation(float x,float y,float z){
268         translation.set(x,y,z);
269     }
270
271     /**
272      * Sets the rotational component of this transform to the matrix represented
273      * by an Euler rotation about x, y, then z.
274      * @param x The X rotation, in radians
275      * @param y The Y rotation, in radians
276      * @param z The Z rotation, in radians
277      */
278     public void setEulerRot(float x,float y,float z){
279         double A = Math.cos(x);
280         double B = Math.sin(x);
281         double C = Math.cos(y);
282         double D = Math.sin(y);
283         double E = Math.cos(z);
284         double F = Math.sin(z);
285         double AD =   A * D;
286         double BD =   B * D;
287         rot.m00 = (float) (C * E);
288         rot.m01 = (float) (BD * E + -(A * F));
289         rot.m02 = (float) (AD * E + B * F);
290         rot.m10 = (float) (C * F);
291         rot.m11 = (float) (BD * F + A * E);
292         rot.m12 = (float) (AD * F + -(B * E));
293         rot.m20 = (float) -D;
294         rot.m21 = (float) (B * C);
295         rot.m22 = (float) (A * C);
296     }
297
298     /**
299      * <code>setRotationQuaternion</code> builds a rotation from a
300      * <code>Quaternion</code>.
301      * @param quat The quaternion to build the rotation from.
302      * @throws JmeException if quat is null.
303      */
304     public void setRotationQuaternion(Quaternion quat) {
305         if (null == quat) {
306             throw new JmeException("Quat may not be null.");
307         }
308         rot.set(quat);
309     }
310
311     /**
312      * <code>invertRotInPlace</code> inverts the rotational component of this Matrix
313      * in place
314      */
315     private void invertRotInPlace() {
316         float temp;
317         temp=rot.m01;
318         rot.m01=rot.m10;
319         rot.m10=temp;
320         temp=rot.m02;
321         rot.m02=rot.m20;
322         rot.m20=temp;
323         temp=rot.m21;
324         rot.m21=rot.m12;
325         rot.m12=temp;
326
327     }
328
329
330     /**
331      * Stores the rotational part of this matrix into the passed matrix.
332      * Will create a new Matrix3f if given matrix is null.  Returns the
333      * given matrix after it has been loaded with rotation values, to allow
334      * chaining
335      *
336      * @param rotStore The matrix to store rotation values
337      * @return The given matrix with updated values
338      */
339     public Matrix3f getRotation(Matrix3f rotStore){
340         if (rotStore==null) rotStore=new Matrix3f();
341         rotStore.copy(rot);
342         return rotStore;
343     }
344
345     /**
346      * Stores the translational part of this matrix into the passed matrix.
347      * Will create a new Vector3f if given vector is null.  Returns the
348      * given vector after it has been loaded with translation values, to allow
349      * chaining
350      *
351      * @param tranStore The vector to store translation values
352      * @return The given Vector with updated values
353      */
354     public Vector3f getTranslation(Vector3f tranStore){
355         if (tranStore==null) tranStore=new Vector3f();
356         tranStore.set(translation);
357         return tranStore;
358     }
359
360     /**
361      * Stores the rotational part of this matrix into the passed Quaternion.
362      * Will create a new Quaternion if given quaternion is null.  Returns the
363      * given Quaternion after it has been loaded with rotation values, to allow
364      * chaining
365      *
366      * @param rotStore The Quat to store translation values
367      * @return The given Vector with updated values
368      */
369     public Quaternion getRotation(Quaternion rotStore){
370         if (rotStore==null) rotStore=new Quaternion();
371         rotStore.fromRotationMatrix(rot);
372         return rotStore;
373     }
374
375     /**
376      * <code>toString</code> returns the string representation of this object.
377      * It is simply a toString() call of the rotational matrix and the translational vector
378      * @return the string representation of this object.
379      */
380     public String toString() {
381         return "com.jme.math.TransformMatrix\n[\n"+
382                 rot.toString() + ":" +
383                 translation.toString() + ":" +
384                 scale.toString();
385     }
386
387     /**
388      * <code>inverse</code> turns this matrix into it's own inverse
389      */
390     public void inverse() {
391         invertRotInPlace();
392         rot.multLocal(translation);
393         translation.multLocal(-1);
394         scale.set(1/scale.x,1/scale.y,1/scale.z);
395     }
396
397     /**
398      * <code>setEulerRot</code> is equivalent to
399      * setEulerRot(eulerVec.x,eulverVec.y,eulverVec.z){
400      * @param eulerVec A Vector3f representing the new rotation in Euler angles
401      */
402     public void setEulerRot(Vector3f eulerVec) {
403         this.setEulerRot(eulerVec.x,eulerVec.y,eulerVec.z);
404     }
405
406     /**
407      * <code>set</code> changes this matrix's rotational and translational components
408      * to that represented by the given parameters
409      * @param rotation The new rotaiton
410      * @param translation The new translation
411      */
412     public void set(Quaternion rotation, Vector3f translation) {
413         this.set(rotation);
414         this.setTranslation(translation);
415     }
416
417     /**
418      * Sets this TransformMatrix's scale to the given scale (x,y,z)
419      * @param scale The new scale
420      */
421     public void setScale(Vector3f scale) {
422         this.scale.set(scale);
423     }
424
425     /**
426      * Sets this TransformMatrix's scale to the given x,y,z
427      * @param x The x scale
428      * @param y The y scale
429      * @param z The z scale
430      */
431     public void setScale(float x, float y, float z) {
432         scale.set(x,y,z);
433     }
434
435     /**
436      * Returns this TransformMatrix's scale factor
437      * @param storeS The place to store the current scale factor
438      * @return The given scale factor
439      */
440     public Vector3f getScale(Vector3f storeS) {
441         if (storeS==null) storeS=new Vector3f();
442         return storeS.set(this.scale);
443     }
444
445     /**
446      * Applies this TransformMatrix to the given spatial, by updating the spatial's local translation, rotation, scale.
447      * @param spatial The spatial to update
448      */
449     public void applyToSpatial(Spatial spatial) {
450         spatial.setLocalTranslation(translation);
451         spatial.setLocalRotation(rot);
452         spatial.setLocalScale(scale);
453     }
454
455     /**
456      * Combines this TransformMatrix with a parent TransformMatrix.
457      * @param parent The parent matrix.
458      * @return This matrix, after it has been updated by it's parent.
459      */
460     public TransformMatrix combineWithParent(TransformMatrix parent){
461         this.scale.multLocal(parent.scale);
462         this.rot.multLocal(parent.rot);
463         parent.rot.multLocal(this.translation).multLocal(parent.scale).addLocal(parent.translation);
464         return this;
465
466     }
467
468     public void write(JMEExporter e) throws IOException {
469         OutputCapsule capsule = e.getCapsule(this);
470         capsule.write(rot, "rot", new Matrix3f());
471         capsule.write(translation, "translation", Vector3f.ZERO);
472         capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
473     }
474
475     public void read(JMEImporter e) throws IOException {
476         InputCapsule capsule = e.getCapsule(this);
477         rot = (Matrix3f)capsule.readSavable("rot", new Matrix3f());
478         translation = (Vector3f)capsule.readSavable("translation", Vector3f.ZERO.clone());
479         scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ.clone());
480     }
481     
482     public Class<? extends TransformMatrix> getClassTag() {
483         return this.getClass();
484     }
485
486     @Override
487     public TransformMatrix clone() {
488         try {
489             TransformMatrix tm = (TransformMatrix) super.clone();
490             tm.rot = rot.clone();
491             tm.scale = scale.clone();
492             tm.translation = translation.clone();
493             return tm;
494         } catch (CloneNotSupportedException e) {
495             throw new AssertionError();
496         }
497     }
498 }
499