package edu.stanford.rsl.conrad.geometry.motion; import edu.stanford.rsl.conrad.geometry.Axis; import edu.stanford.rsl.conrad.geometry.Rotations; import edu.stanford.rsl.conrad.geometry.transforms.AffineTransform; import edu.stanford.rsl.conrad.geometry.transforms.ComboTransform; import edu.stanford.rsl.conrad.geometry.transforms.Transform; import edu.stanford.rsl.conrad.geometry.transforms.Translation; import edu.stanford.rsl.conrad.numerics.DoubleFunction; import edu.stanford.rsl.conrad.numerics.SimpleMatrix; import edu.stanford.rsl.conrad.numerics.SimpleOperators; import edu.stanford.rsl.conrad.numerics.SimpleVector; /** * MotionField to handle affine rotation and affine modulated translational motion. * The motion paramters, i.e. angle, axis, translation, can be given as lambda expressions or method references * * @author berger * */ public class AnalyticalAffineMotionFieldAxisAngle extends AnalyticalAffineMotionField { /** * */ private static final long serialVersionUID = 2402284037682473196L; /** * Creates a new rotational and translation MotionField. * It transforms points with a rotation around the given axis and center and translates them afterwards. * The translation is an affine motion field as well which gives further flexibility. * The angle is given in radians. * * @param transformationCenter * @param axis * @param angle */ public AnalyticalAffineMotionFieldAxisAngle() { } DoubleFunction[] transformationCenter; DoubleFunction[] axis; DoubleFunction angle; DoubleFunction[] translation; public AnalyticalAffineMotionFieldAxisAngle (DoubleFunction[] transformationCenter, DoubleFunction[] axis, DoubleFunction angle, DoubleFunction[] translation){ this.transformationCenter = transformationCenter; this.translation = translation; this.axis = axis; this.angle = angle; } /** * Returns the interpolated transform between initial time and time. * Here the lambda expressions are evaluated and the current transform is build * * @param initialTime * @param time * @return the transform * @throws Exception */ @Override public SimpleMatrix getAffineMatrix(double initialTime, double time) { // first get the current rotation center SimpleVector transformCenter = evaluateFunctionArray(transformationCenter,time); // now we determine the current rotation axis and the angle SimpleVector curAxis = evaluateFunctionArray(axis, time); double curAngle = angle.f(time); // finally we evaluate the current translation SimpleVector curTranslation = evaluateFunctionArray(translation, time); SimpleMatrix out = new SimpleMatrix(curAxis.getLen()+1,curAxis.getLen()+1); out.setElementValue(out.getRows()-1, out.getCols()-1, 1); SimpleMatrix rot = Rotations.createRotationMatrixAboutAxis(new Axis(curAxis), curAngle); out.setSubMatrixValue(0, 0, rot); // Translation is build by: currentTranslation + transformCenter - Rotation*transformCenter // Computed directly to avoid matrix multiplications! // Validity is easily tested by plugging i the transform Center, as the result should be the transform center curTranslation.add(transformCenter); curTranslation.subtract(SimpleOperators.multiply(rot, transformCenter)); out.setSubColValue(0, out.getCols()-1, curTranslation); return out; } public DoubleFunction[] getTransformationCenter() { return transformationCenter; } public void setTransformationCenter(DoubleFunction[] transformationCenter) { this.transformationCenter = transformationCenter; } public DoubleFunction[] getAxis() { return axis; } public void setAxis(DoubleFunction[] axis) { this.axis = axis; } public DoubleFunction getAngle() { return angle; } public void setAngle(DoubleFunction angle) { this.angle = angle; } public DoubleFunction[] getTranslation() { return translation; } public void setTranslation(DoubleFunction[] translation) { this.translation = translation; } } /* * Copyright (C) 2010-2014 Martin Berger * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */