/* * Copyright (c) 2015 NOVA, All rights reserved. * This library is free software, licensed under GNU Lesser General Public License version 3 * * This file is part of NOVA. * * NOVA is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NOVA 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NOVA. If not, see <http://www.gnu.org/licenses/>. */package nova.core.util.math; import org.apache.commons.math3.geometry.euclidean.threed.Rotation; import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.linear.RealMatrix; import java.util.Stack; public class MatrixStack implements Transformer { private final Stack<RealMatrix> stack; private RealMatrix current = MatrixUtils.createRealIdentityMatrix(4); /** * Creates new MatrixStack. Constains no transfomation base matrix. */ public MatrixStack() { this.stack = new Stack<>(); } /** * Clone construcotr of MatrixStack * @param clone instance to be cloned */ public MatrixStack(MatrixStack clone) { //noinspection unchecked this.stack = (Stack<RealMatrix>) clone.stack.clone(); this.current = clone.current.copy(); } /** * Creates new MatrixStack with starting matrix. * @param current Transforation matrix to start from. */ public MatrixStack(RealMatrix current) { this.stack = new Stack<>(); this.current = current; } /** * Replaces current transformation matrix by an identity matrix. */ public void loadIdentity() { current = MatrixUtils.createRealIdentityMatrix(4); } /** * Replaces current transformation matrix by an identity current. * * @param matrix The new matrix to use. * @return this for chaining. */ public MatrixStack loadMatrix(RealMatrix matrix) { current = matrix; return this; } /** * Exposes current transformation matrix. * * @return current transformation matrix. */ public RealMatrix getMatrix() { return current; } /** * Transforms current matrix with give matrix. * * @param matrix to transform current matrix. * @return The transformed matrix */ public MatrixStack transform(RealMatrix matrix) { current = current.preMultiply(MatrixUtil.augmentWithIdentity(matrix, 4)); return this; } /** * Translates current transformation matrix. * * @param x translation. * @param y translation. * @param z translation. * @return The tranlated matrix */ public MatrixStack translate(double x, double y, double z) { current = current.preMultiply(TransformUtil.translationMatrix(x, y, z)); return this; } /** * Translates current transformation matrix. * * @param translateVector vector of translation. * @return The tranformed matrix */ public MatrixStack translate(Vector3D translateVector) { translate(translateVector.getX(), translateVector.getY(), translateVector.getZ()); return this; } /** * Rotates the current matrix * * @param rotation The rotation to aply * @return The rorated matrix */ public MatrixStack rotate(Rotation rotation) { RealMatrix rotMat = MatrixUtils.createRealMatrix(4, 4); rotMat.setSubMatrix(rotation.getMatrix(), 0, 0); rotMat.setEntry(3, 3, 1); current = current.preMultiply(rotMat); return this; } /** * Rotates transformation matrix around rotateVector axis by angle radians. * * @param rotateVector Vector serving as rotation axis. * @param angle in radians. * @return The rotated matrix */ public MatrixStack rotate(Vector3D rotateVector, double angle) { return rotate(new Rotation(rotateVector, angle)); } /** * Scales current transformation matrix. * * @param x scale. * @param y scale. * @param z scale. * @return this for chaining. */ public MatrixStack scale(double x, double y, double z) { current = current.preMultiply(TransformUtil.scaleMatrix(x, y, z)); return this; } /** * Scales current transformation matrix. * * @param scaleVector scale vector. * @return The current matrix */ public MatrixStack scale(Vector3D scaleVector) { scale(scaleVector.getX(), scaleVector.getY(), scaleVector.getZ()); return this; } /** * Pushes matrix onto the stack. Use it to save current state of MatrixStack in case of branching transformations. * @return this for chaining. */ public MatrixStack pushMatrix() { stack.add(current); return this; } /** * Pops matrix from stack. Use it to restore saved transformation. * @return this for chaining. */ public MatrixStack popMatrix() { current = stack.pop(); return this; } /** * Called to transform a vector. * @param vec - The vector being transformed * @return The transformed vector by current matrix. */ @Override public Vector3D apply(Vector3D vec) { return TransformUtil.transform(vec, current); } }