
eu.mihosoft.vrl.v3d.Transform Maven / Gradle / Ivy
/**
* Transform.java
*
* Copyright 2014-2014 Michael Hoffer . All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Michael Hoffer "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Michael Hoffer OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Michael Hoffer
* .
*/
package eu.mihosoft.vrl.v3d;
import javax.vecmath.Matrix4d;
/**
* Transform. Transformations (translation, rotation, scale) can be applied to
* geometrical objects like {@link CSG}, {@link Polygon}, {@link Vertex} and
* {@link Vector3d}.
*
* This transform class uses the builder pattern to define combined
* transformations.
*
* Example:
*
*
* // t applies rotation and translation
* Transform t = Transform.unity().rotX(45).translate(2,1,0);
*
*
* TODO: use quaternions for rotations.
*
* @author Michael Hoffer <[email protected]>
*/
public class Transform {
/**
* Internal 4x4 matrix.
*/
private final Matrix4d m;
/**
* Constructor.
*
* Creates a unit transform.
*/
public Transform() {
m = new Matrix4d();
m.m00 = 1;
m.m11 = 1;
m.m22 = 1;
m.m33 = 1;
}
/**
* Returns a new unity transform.
*
* @return unity transform
*/
public static Transform unity() {
return new Transform();
}
/**
* Constructor.
*
* @param m matrix
*/
private Transform(Matrix4d m) {
this.m = m;
}
/**
* Applies rotation operation around the x axis to this transform.
*
* @param degrees degrees
* @return this transform
*/
public Transform rotX(double degrees) {
double radians = degrees * Math.PI * (1.0 / 180.0);
double cos = Math.cos(radians);
double sin = Math.sin(radians);
double elemenents[] = {
1, 0, 0, 0, 0, cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies rotation operation around the y axis to this transform.
*
* @param degrees degrees
*
* @return this transform
*/
public Transform rotY(double degrees) {
double radians = degrees * Math.PI * (1.0 / 180.0);
double cos = Math.cos(radians);
double sin = Math.sin(radians);
double elemenents[] = {
cos, 0, -sin, 0, 0, 1, 0, 0, sin, 0, cos, 0, 0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies rotation operation around the z axis to this transform.
*
* @param degrees degrees
*
* @return this transform
*/
public Transform rotZ(double degrees) {
double radians = degrees * Math.PI * (1.0 / 180.0);
double cos = Math.cos(radians);
double sin = Math.sin(radians);
double elemenents[] = {
cos, sin, 0, 0, -sin, cos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a rotation operation to this transform.
*
* @param x x axis rotation (degrees)
* @param y y axis rotation (degrees)
* @param z z axis rotation (degrees)
*
* @return this transform
*/
public Transform rot(double x, double y, double z) {
return rotX(x).rotY(y).rotZ(z);
}
/**
* Applies a rotation operation to this transform.
*
* @param vec axis rotation for x, y, z (degrees)
*
* @return this transform
*/
public Transform rot(Vector3d vec) {
// TODO: use quaternions
return rotX(vec.x).rotY(vec.y).rotZ(vec.z);
}
/**
* Applies a translation operation to this transform.
*
* @param vec translation vector (x,y,z)
*
* @return this transform
*/
public Transform translate(Vector3d vec) {
return translate(vec.x, vec.y, vec.z);
}
/**
* Applies a translation operation to this transform.
*
* @param x translation (x axis)
* @param y translation (y axis)
* @param z translation (z axis)
*
* @return this transform
*/
public Transform translate(double x, double y, double z) {
double elemenents[] = {
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a translation operation to this transform.
*
* @param value translation (x axis)
*
* @return this transform
*/
public Transform translateX(double value) {
double elemenents[] = {
1, 0, 0, value,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a translation operation to this transform.
*
* @param value translation (y axis)
*
* @return this transform
*/
public Transform translateY(double value) {
double elemenents[] = {
1, 0, 0, 0,
0, 1, 0, value,
0, 0, 1, 0,
0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a translation operation to this transform.
*
* @param value translation (z axis)
*
* @return this transform
*/
public Transform translateZ(double value) {
double elemenents[] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, value,
0, 0, 0, 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a mirror operation to this transform.
*
* @param plane the plane that defines the mirror operation
*
* @return this transform
*/
public Transform mirror(Plane plane) {
System.err.println("WARNING: I'm too dumb to implement the mirror() operation correctly. Please fix me!");
double nx = plane.normal.x;
double ny = plane.normal.y;
double nz = plane.normal.z;
double w = plane.dist;
double elemenents[] = {
(1.0 - 2.0 * nx * nx), (-2.0 * ny * nx), (-2.0 * nz * nx), 0,
(-2.0 * nx * ny), (1.0 - 2.0 * ny * ny), (-2.0 * nz * ny), 0,
(-2.0 * nx * nz), (-2.0 * ny * nz), (1.0 - 2.0 * nz * nz), 0,
(-2.0 * nx * w), (-2.0 * ny * w), (-2.0 * nz * w), 1
};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation to this transform.
*
* @param vec vector that specifies scale (x,y,z)
*
* @return this transform
*/
public Transform scale(Vector3d vec) {
if (vec.x == 0 || vec.y == 0 || vec.z == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
vec.x, 0, 0, 0, 0, vec.y, 0, 0, 0, 0, vec.z, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation to this transform.
*
* @param x x scale value
* @param y y scale value
* @param z z scale value
*
* @return this transform
*/
public Transform scale(double x, double y, double z) {
if (x ==0 || y == 0 || z == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation to this transform.
*
* @param s s scale value (x, y and z)
*
* @return this transform
*/
public Transform scale(double s) {
if (s == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation (x axis) to this transform.
*
* @param s x scale value
*
* @return this transform
*/
public Transform scaleX(double s) {
if (s == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
s, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation (y axis) to this transform.
*
* @param s y scale value
*
* @return this transform
*/
public Transform scaleY(double s) {
if (s == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
1, 0, 0, 0, 0, s, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies a scale operation (z axis) to this transform.
*
* @param s z scale value
*
* @return this transform
*/
public Transform scaleZ(double s) {
if (s == 0) {
throw new IllegalArgumentException("scale by 0 not allowed!");
}
double elemenents[] = {
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, s, 0, 0, 0, 0, 1};
m.mul(new Matrix4d(elemenents));
return this;
}
/**
* Applies this transform to the specified vector.
*
* @param vec vector to transform
*
* @return the specified vector
*/
public Vector3d transform(Vector3d vec) {
double x, y;
x = m.m00 * vec.x + m.m01 * vec.y + m.m02 * vec.z + m.m03;
y = m.m10 * vec.x + m.m11 * vec.y + m.m12 * vec.z + m.m13;
vec.z = m.m20 * vec.x + m.m21 * vec.y + m.m22 * vec.z + m.m23;
vec.x = x;
vec.y = y;
return vec;
}
/**
* Applies this transform to the specified vector.
*
* @param vec vector to transform
* @param amount transform amount (0 = 0 %, 1 = 100%)
*
* @return the specified vector
*/
public Vector3d transform(Vector3d vec, double amount) {
double prevX = vec.x;
double prevY = vec.y;
double prevZ = vec.z;
final double x, y;
x = m.m00 * vec.x + m.m01 * vec.y + m.m02 * vec.z + m.m03;
y = m.m10 * vec.x + m.m11 * vec.y + m.m12 * vec.z + m.m13;
vec.z = m.m20 * vec.x + m.m21 * vec.y + m.m22 * vec.z + m.m23;
vec.x = x;
vec.y = y;
double diffX = vec.x-prevX;
double diffY = vec.y-prevY;
double diffZ = vec.z-prevZ;
vec.x = prevX + (diffX)*amount;
vec.y = prevY + (diffY)*amount;
vec.z = prevZ + (diffZ)*amount;
return vec;
}
// // Multiply a CSG.Vector3D (interpreted as 3 column, 1 row) by this matrix
// // (result = v*M)
// // Fourth element is taken as 1
// leftMultiply1x3Vector: function(v) {
// var v0 = v._x;
// var v1 = v._y;
// var v2 = v._z;
// var v3 = 1;
// var x = v0 * this.elements[0] + v1 * this.elements[4] + v2 * this.elements[8] + v3 * this.elements[12];
// var y = v0 * this.elements[1] + v1 * this.elements[5] + v2 * this.elements[9] + v3 * this.elements[13];
// var z = v0 * this.elements[2] + v1 * this.elements[6] + v2 * this.elements[10] + v3 * this.elements[14];
// var w = v0 * this.elements[3] + v1 * this.elements[7] + v2 * this.elements[11] + v3 * this.elements[15];
// // scale such that fourth element becomes 1:
// if(w != 1) {
// var invw = 1.0 / w;
// x *= invw;
// y *= invw;
// z *= invw;
// }
// return new CSG.Vector3D(x, y, z);
// },
/**
* Performs an SVD normalization of the underlying matrix to calculate and
* return the uniform scale factor. If the matrix has non-uniform scale
* factors, the largest of the x, y, and z scale factors distill be
* returned.
*
* Note: this transformation is not modified.
*
* @return the scale factor of this transformation
*/
public double getScale() {
return m.getScale();
}
/**
* Indicates whether this transform performs a mirror operation, i.e.,
* flips the orientation.
*
* @return true
if this transform performs a mirror operation;
* false
otherwise
*/
public boolean isMirror() {
return m.determinant() < 0;
}
/**
* Applies the specified transform to this transform.
*
* @param t transform to apply
*
* @return this transform
*/
public Transform apply(Transform t) {
m.mul(t.m);
return this;
}
@Override
public String toString() {
return m.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy