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. euler angles, translation, can be given as lambda expressions or method references
*
* @author berger
*
*/
public class AnalyticalAffineMotionFieldEuler extends AnalyticalAffineMotionField {
/**
*
*/
private static final long serialVersionUID = -2928748290559062947L;
public AnalyticalAffineMotionFieldEuler() {
}
DoubleFunction[] transformationCenter;
DoubleFunction[] eulerAngles;
DoubleFunction[] translation;
/**
* Creates a new rotational and translation MotionField.
* It transforms points with a rotation around the given Euler angles 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 AnalyticalAffineMotionFieldEuler (DoubleFunction[] transformationCenter, DoubleFunction[] eulerAngles, DoubleFunction[] translation){
this.transformationCenter = transformationCenter;
this.translation = translation;
this.eulerAngles = eulerAngles;
}
/**
* 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 Transform getTransform(double initialTime, double time) {
// first get the current rotation center
SimpleVector backTrans = evaluateFunctionArray(transformationCenter,time);
Transform curBack = new Translation(backTrans);
Transform curToCenter = curBack.inverse();
// now we determine the current rotation axis and the angle
SimpleVector curAngles = evaluateFunctionArray(eulerAngles, time);
// finally we evaluate the current translation
SimpleVector curTranslation = evaluateFunctionArray(translation, time);
// lets build the full current affine transform
Transform curAffine = new AffineTransform(
Rotations.createRotationMatrix(curAngles.getElement(0),curAngles.getElement(1),curAngles.getElement(2)),
curTranslation);
return new ComboTransform(curToCenter,curAffine,curBack);
}
/**
* 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 angles
SimpleVector curAngles = evaluateFunctionArray(eulerAngles, time);
// finally we evaluate the current translation
SimpleVector curTranslation = evaluateFunctionArray(translation, time);
SimpleMatrix out = new SimpleMatrix(curAngles.getLen()+1,curAngles.getLen()+1);
out.setElementValue(out.getRows()-1, out.getCols()-1, 1);
SimpleMatrix rot = Rotations.createRotationMatrix(curAngles.getElement(0),curAngles.getElement(1),curAngles.getElement(2));
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 SimpleVector getEulerAngles(double initialTime, double time) {
return evaluateFunctionArray(eulerAngles, time);
}
public SimpleVector getTranslation(double initialTime, double time) {
return evaluateFunctionArray(translation, time);
}
public DoubleFunction[] getTransformationCenter() {
return transformationCenter;
}
public void setTransformationCenter(DoubleFunction[] transformationCenter) {
this.transformationCenter = transformationCenter;
}
public DoubleFunction[] getEulerAngles() {
return eulerAngles;
}
public void setEulerAngles(DoubleFunction[] eulerAngles) {
this.eulerAngles = eulerAngles;
}
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).
*/