/*
* This file is part of MoleculeViewer.
*
* MoleculeViewer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MoleculeViewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MoleculeViewer. If not, see <http://www.gnu.org/licenses/>.
*/
package astex;
import javax.vecmath.Matrix4d;
import javax.vecmath.Quat4d;
/* Copyright Astex Technology Ltd. 1999 */
/* Copyright David Hall, Boston University, 2011 */
/*
* 16-11-99 mjh
* created
*/
/**
* A class for storing and manipulating a 4x4 matrix.
*/
public class Matrix extends Matrix4d {
/** Default constructor. */
public Matrix(){
setIdentity();
}
public Matrix(Matrix m) {
super(m);
}
/** Apply non uniform scale. */
public void scale(double sx, double sy, double sz){
m00 *= sx; m01 *= sy; m02 *= sz;
m10 *= sx; m11 *= sy; m12 *= sz;
m20 *= sx; m21 *= sy; m22 *= sz;
m30 *= sx; m31 *= sy; m32 *= sz;
}
/** Translate the transformation matrix. */
public void translate(double tx, double ty, double tz){
m00 += m03*tx; m01 += m03*ty; m02 += m03*tz;
m10 += m13*tx; m11 += m13*ty; m12 += m13*tz;
m20 += m23*tx; m21 += m23*ty; m22 += m23*tz;
m30 += m33*tx; m31 += m33*ty; m32 += m33*tz;
}
/** Rotate around x in degrees. */
public void rotateXdegrees(double d){
double r = d*Math.PI / 180.0;
double c = Math.cos(r);
double s = Math.sin(r);
double t = 0.0;
t = m01; m01 = t*c - m02*s; m02 = t*s + m02*c;
t = m11; m11 = t*c - m12*s; m12 = t*s + m12*c;
t = m21; m21 = t*c - m22*s; m22 = t*s + m22*c;
t = m31; m31 = t*c - m32*s; m32 = t*s + m32*c;
}
/** Rotate around y in degrees. */
public void rotateYdegrees(double d){
double r = d*Math.PI / 180.0;
double c = Math.cos(r);
double s = Math.sin(r);
double t = 0.0;
t = m00; m00 = t*c + m02*s; m02 = m02*c - t*s;
t = m10; m10 = t*c + m12*s; m12 = m12*c - t*s;
t = m20; m20 = t*c + m22*s; m22 = m22*c - t*s;
t = m30; m30 = t*c + m32*s; m32 = m32*c - t*s;
}
/** Rotate around Z in degrees. */
public void rotateZdegrees(double d){
double r = d*Math.PI / 180.0;
Matrix m = new Matrix();
m.rotateAroundVector(0., 0., 1., r);
transform(m);
}
/** Transform by another matrix. */
public void transform(Matrix m){
double xx00 = m00, xx01 = m01, xx02 = m02, xx03 = m03;
double xx10 = m10, xx11 = m11, xx12 = m12, xx13 = m13;
double xx20 = m20, xx21 = m21, xx22 = m22, xx23 = m23;
double xx30 = m30, xx31 = m31, xx32 = m32, xx33 = m33;
m00 = xx00*m.m00 + xx01*m.m10 + xx02*m.m20 + xx03*m.m30;
m01 = xx00*m.m01 + xx01*m.m11 + xx02*m.m21 + xx03*m.m31;
m02 = xx00*m.m02 + xx01*m.m12 + xx02*m.m22 + xx03*m.m32;
m03 = xx00*m.m03 + xx01*m.m13 + xx02*m.m23 + xx03*m.m33;
m10 = xx10*m.m00 + xx11*m.m10 + xx12*m.m20 + xx13*m.m30;
m11 = xx10*m.m01 + xx11*m.m11 + xx12*m.m21 + xx13*m.m31;
m12 = xx10*m.m02 + xx11*m.m12 + xx12*m.m22 + xx13*m.m32;
m13 = xx10*m.m03 + xx11*m.m13 + xx12*m.m23 + xx13*m.m33;
m20 = xx20*m.m00 + xx21*m.m10 + xx22*m.m20 + xx23*m.m30;
m21 = xx20*m.m01 + xx21*m.m11 + xx22*m.m21 + xx23*m.m31;
m22 = xx20*m.m02 + xx21*m.m12 + xx22*m.m22 + xx23*m.m32;
m23 = xx20*m.m03 + xx21*m.m13 + xx22*m.m23 + xx23*m.m33;
m30 = xx30*m.m00 + xx31*m.m10 + xx32*m.m20 + xx33*m.m30;
m31 = xx30*m.m01 + xx31*m.m11 + xx32*m.m21 + xx33*m.m31;
m32 = xx30*m.m02 + xx31*m.m12 + xx32*m.m22 + xx33*m.m32;
m33 = xx30*m.m03 + xx31*m.m13 + xx32*m.m23 + xx33*m.m33;
}
/** Transform a point by the current matrix. */
public void transform(Point3d p){
double x = p.x, y = p.y, z = p.z;
p.x = x*m00 + y*m10 + z*m20 + m30;
p.y = x*m01 + y*m11 + z*m21 + m31;
p.z = x*m02 + y*m12 + z*m22 + m32;
}
/** Transform a point by the inverse matrix (assumes rotation matrix) */
public void transformByInverse(Point3d p){
double x = p.x, y = p.y, z = p.z;
// don't need translation part here.
p.x = x*m00 + y*m01 + z*m02;
p.y = x*m10 + y*m11 + z*m12;
p.z = x*m20 + y*m21 + z*m22;
}
/** Rotate around a line. */
public void rotateAroundVector(double x, double y, double z,
double theta){
double d = x*x + y*y + z*z;
if(d > 1.e-3){
d = Math.sqrt(d);
x /= d;
y /= d;
z /= d;
}else{
System.out.println("rotateAroundVector: direction is zero length");
return;
}
double s = Math.sin(theta);
double c = Math.cos(theta);
double t = 1.0 - c;
setIdentity();
m00 = t * x * x + c; /* leading diagonal */
m11 = t * y * y + c;
m22 = t * z * z + c;
m10 = t * x * y + s * z; /* off diagonal elements */
m20 = t * x * z - s * y;
m01 = t * x * y - s * z;
m21 = t * y * z + s * x;
m02 = t * x * z + s * y;
m12 = t * y * z - s * x;
}
/** A format object for printing matrices. */
private static Format f6 = new Format("%11.6f");
/** Print the matrix. */
public void print(String message){
System.out.println(message);
System.out.println(f6.format(m00) + " " + f6.format(m01) +
" " + f6.format(m02) + " " + f6.format(m03));
System.out.println(f6.format(m10) + " " + f6.format(m11) +
" " + f6.format(m12) + " " + f6.format(m13));
System.out.println(f6.format(m20) + " " + f6.format(m21) +
" " + f6.format(m22) + " " + f6.format(m23));
System.out.println(f6.format(m30) + " " + f6.format(m31) +
" " + f6.format(m32) + " " + f6.format(m33));
}
public String returnScript(){
StringBuilder command = new StringBuilder("matrix ");
command.append(String.format(" %g %g %g %g", m00, m01, m02, m03));
command.append(String.format(" %g %g %g %g", m10, m11, m12, m13));
command.append(String.format(" %g %g %g %g", m20, m21, m22, m23));
command.append(String.format(" %g %g %g %g", m30, m31, m32, m33));
command.append(";");
return command.toString();
}
public boolean isIdentity(double tol){
if(Math.abs(m00 - 1.0) > tol) return false;
if(Math.abs(m01) > tol) return false;
if(Math.abs(m02) > tol) return false;
if(Math.abs(m03) > tol) return false;
if(Math.abs(m10) > tol) return false;
if(Math.abs(m11 - 1.0) > tol) return false;
if(Math.abs(m12) > tol) return false;
if(Math.abs(m13) > tol) return false;
if(Math.abs(m20) > tol) return false;
if(Math.abs(m21) > tol) return false;
if(Math.abs(m22 - 1.0) > tol) return false;
if(Math.abs(m23) > tol) return false;
if(Math.abs(m30) > tol) return false;
if(Math.abs(m31) > tol) return false;
if(Math.abs(m32) > tol) return false;
if(Math.abs(m33 - 1.0) > tol) return false;
return true;
}
/** Interpolate a new matrix. */
public static Matrix interpolate(Matrix MS, Matrix MF, double frac){
Matrix MI = new Matrix();
interpolate(MS, MF, frac, MI);
return MI;
}
/** Interpolate a new matrix. */
private static void interpolate(Matrix MS, Matrix MF, double frac, Matrix MI){
Quat4d qS = new Quat4d();
Quat4d qF = new Quat4d();
qS.set(MS);
qF.set(MF);
qF.interpolate(qS, frac);
MI.set(qF);
}
}