Home | History | Annotate | Download | only in math
      1 /*
      2  * Copyright (c) 2009-2010 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.jme3.math;
     34 
     35 import com.jme3.export.*;
     36 import java.io.IOException;
     37 
     38 /**
     39  * Started Date: Jul 16, 2004<br><br>
     40  * Represents a translation, rotation and scale in one object.
     41  *
     42  * @author Jack Lindamood
     43  * @author Joshua Slack
     44  */
     45 public final class Transform implements Savable, Cloneable, java.io.Serializable {
     46 
     47     static final long serialVersionUID = 1;
     48 
     49     public static final Transform IDENTITY = new Transform();
     50 
     51     private Quaternion rot = new Quaternion();
     52     private Vector3f translation = new Vector3f();
     53     private Vector3f scale = new Vector3f(1,1,1);
     54 
     55     public Transform(Vector3f translation, Quaternion rot){
     56         this.translation.set(translation);
     57         this.rot.set(rot);
     58     }
     59 
     60     public Transform(Vector3f translation, Quaternion rot, Vector3f scale){
     61         this(translation, rot);
     62         this.scale.set(scale);
     63     }
     64 
     65     public Transform(Vector3f translation){
     66         this(translation, Quaternion.IDENTITY);
     67     }
     68 
     69     public Transform(Quaternion rot){
     70         this(Vector3f.ZERO, rot);
     71     }
     72 
     73     public Transform(){
     74         this(Vector3f.ZERO, Quaternion.IDENTITY);
     75     }
     76 
     77     /**
     78      * Sets this rotation to the given Quaternion value.
     79      * @param rot The new rotation for this matrix.
     80      * @return this
     81      */
     82     public Transform setRotation(Quaternion rot) {
     83         this.rot.set(rot);
     84         return this;
     85     }
     86 
     87     /**
     88      * Sets this translation to the given value.
     89      * @param trans The new translation for this matrix.
     90      * @return this
     91      */
     92     public Transform setTranslation(Vector3f trans) {
     93         this.translation.set(trans);
     94         return this;
     95     }
     96 
     97     /**
     98      * Return the translation vector in this matrix.
     99      * @return translation vector.
    100      */
    101     public Vector3f getTranslation() {
    102         return translation;
    103     }
    104 
    105     /**
    106      * Sets this scale to the given value.
    107      * @param scale The new scale for this matrix.
    108      * @return this
    109      */
    110     public Transform setScale(Vector3f scale) {
    111         this.scale.set(scale);
    112         return this;
    113     }
    114 
    115     /**
    116      * Sets this scale to the given value.
    117      * @param scale The new scale for this matrix.
    118      * @return this
    119      */
    120     public Transform setScale(float scale) {
    121         this.scale.set(scale, scale, scale);
    122         return this;
    123     }
    124 
    125     /**
    126      * Return the scale vector in this matrix.
    127      * @return scale vector.
    128      */
    129     public Vector3f getScale() {
    130         return scale;
    131     }
    132 
    133     /**
    134      * Stores this translation value into the given vector3f.  If trans is null, a new vector3f is created to
    135      * hold the value.  The value, once stored, is returned.
    136      * @param trans The store location for this matrix's translation.
    137      * @return The value of this matrix's translation.
    138      */
    139     public Vector3f getTranslation(Vector3f trans) {
    140         if (trans==null) trans=new Vector3f();
    141         trans.set(this.translation);
    142         return trans;
    143     }
    144 
    145     /**
    146      * Stores this rotation value into the given Quaternion.  If quat is null, a new Quaternion is created to
    147      * hold the value.  The value, once stored, is returned.
    148      * @param quat The store location for this matrix's rotation.
    149      * @return The value of this matrix's rotation.
    150      */
    151     public Quaternion getRotation(Quaternion quat) {
    152         if (quat==null) quat=new Quaternion();
    153         quat.set(rot);
    154         return quat;
    155     }
    156 
    157     /**
    158      * Return the rotation quaternion in this matrix.
    159      * @return rotation quaternion.
    160      */
    161     public Quaternion getRotation() {
    162         return rot;
    163     }
    164 
    165     /**
    166      * Stores this scale value into the given vector3f.  If scale is null, a new vector3f is created to
    167      * hold the value.  The value, once stored, is returned.
    168      * @param scale The store location for this matrix's scale.
    169      * @return The value of this matrix's scale.
    170      */
    171     public Vector3f getScale(Vector3f scale) {
    172         if (scale==null) scale=new Vector3f();
    173         scale.set(this.scale);
    174         return scale;
    175     }
    176 
    177     /**
    178      * Sets this matrix to the interpolation between the first matrix and the second by delta amount.
    179      * @param t1 The begining transform.
    180      * @param t2 The ending transform.
    181      * @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
    182      */
    183     public void interpolateTransforms(Transform t1, Transform t2, float delta) {
    184         this.rot.slerp(t1.rot,t2.rot,delta);
    185         this.translation.interpolate(t1.translation,t2.translation,delta);
    186         this.scale.interpolate(t1.scale,t2.scale,delta);
    187     }
    188 
    189     /**
    190      * Changes the values of this matrix acording to it's parent.  Very similar to the concept of Node/Spatial transforms.
    191      * @param parent The parent matrix.
    192      * @return This matrix, after combining.
    193      */
    194     public Transform combineWithParent(Transform parent) {
    195         scale.multLocal(parent.scale);
    196 //        rot.multLocal(parent.rot);
    197         parent.rot.mult(rot, rot);
    198 
    199         // This here, is evil code
    200 //        parent
    201 //            .rot
    202 //            .multLocal(translation)
    203 //            .multLocal(parent.scale)
    204 //            .addLocal(parent.translation);
    205 
    206         translation.multLocal(parent.scale);
    207         parent
    208             .rot
    209             .multLocal(translation)
    210             .addLocal(parent.translation);
    211         return this;
    212     }
    213 
    214     /**
    215      * Sets this matrix's translation to the given x,y,z values.
    216      * @param x This matrix's new x translation.
    217      * @param y This matrix's new y translation.
    218      * @param z This matrix's new z translation.
    219      * @return this
    220      */
    221     public Transform setTranslation(float x,float y, float z) {
    222         translation.set(x,y,z);
    223         return this;
    224     }
    225 
    226     /**
    227      * Sets this matrix's scale to the given x,y,z values.
    228      * @param x This matrix's new x scale.
    229      * @param y This matrix's new y scale.
    230      * @param z This matrix's new z scale.
    231      * @return this
    232      */
    233     public Transform setScale(float x, float y, float z) {
    234         scale.set(x,y,z);
    235         return this;
    236     }
    237 
    238     public Vector3f transformVector(final Vector3f in, Vector3f store){
    239         if (store == null)
    240             store = new Vector3f();
    241 
    242         // multiply with scale first, then rotate, finally translate (cf.
    243         // Eberly)
    244         return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation);
    245     }
    246 
    247     public Vector3f transformInverseVector(final Vector3f in, Vector3f store){
    248         if (store == null)
    249             store = new Vector3f();
    250 
    251         // The author of this code should look above and take the inverse of that
    252         // But for some reason, they didnt ..
    253 //        in.subtract(translation, store).divideLocal(scale);
    254 //        rot.inverse().mult(store, store);
    255 
    256         in.subtract(translation, store);
    257         rot.inverse().mult(store, store);
    258         store.divideLocal(scale);
    259 
    260         return store;
    261     }
    262 
    263     /**
    264      * Loads the identity.  Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1.
    265      */
    266     public void loadIdentity() {
    267         translation.set(0,0,0);
    268         scale.set(1,1,1);
    269         rot.set(0,0,0,1);
    270     }
    271 
    272     @Override
    273     public String toString(){
    274         return getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n"
    275                                           + "[ " + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "]\n"
    276                                           + "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]";
    277     }
    278 
    279     /**
    280      * Sets this matrix to be equal to the given matrix.
    281      * @param matrixQuat The matrix to be equal to.
    282      * @return this
    283      */
    284     public Transform set(Transform matrixQuat) {
    285         this.translation.set(matrixQuat.translation);
    286         this.rot.set(matrixQuat.rot);
    287         this.scale.set(matrixQuat.scale);
    288         return this;
    289     }
    290 
    291     public void write(JmeExporter e) throws IOException {
    292         OutputCapsule capsule = e.getCapsule(this);
    293         capsule.write(rot, "rot", new Quaternion());
    294         capsule.write(translation, "translation", Vector3f.ZERO);
    295         capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
    296     }
    297 
    298     public void read(JmeImporter e) throws IOException {
    299         InputCapsule capsule = e.getCapsule(this);
    300 
    301         rot = (Quaternion)capsule.readSavable("rot", new Quaternion());
    302         translation = (Vector3f)capsule.readSavable("translation", Vector3f.ZERO);
    303         scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ);
    304     }
    305 
    306     @Override
    307     public Transform clone() {
    308         try {
    309             Transform tq = (Transform) super.clone();
    310             tq.rot = rot.clone();
    311             tq.scale = scale.clone();
    312             tq.translation = translation.clone();
    313             return tq;
    314         } catch (CloneNotSupportedException e) {
    315             throw new AssertionError();
    316         }
    317     }
    318 }
    319