package edu.stanford.rsl.conrad.geometry.motion; import Jama.EigenvalueDecomposition; import edu.stanford.rsl.conrad.geometry.Axis; import edu.stanford.rsl.conrad.geometry.Rotations; import edu.stanford.rsl.conrad.geometry.motion.timewarp.IdentityTimeWarper; import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND; import edu.stanford.rsl.conrad.geometry.transforms.AffineTransform; import edu.stanford.rsl.conrad.geometry.transforms.ComboTransform; import edu.stanford.rsl.conrad.geometry.transforms.ScaleRotate; import edu.stanford.rsl.conrad.geometry.transforms.Transform; import edu.stanford.rsl.conrad.geometry.transforms.Translation; import edu.stanford.rsl.conrad.numerics.SimpleMatrix; import edu.stanford.rsl.conrad.numerics.SimpleVector; /** * MotionField to handle affine rotation and translational motion. * * @author berger * */ public class AffineMotionField extends AbstractAffineMotionField { /** * */ private static final long serialVersionUID = 6748536919627679826L; protected Translation toCenter; protected Translation back; protected SimpleVector axis; protected double angle; protected PointND center; protected SimpleVector translation; protected SimpleMatrix rotationMat; /** * Creates a new rotational and translation MotionField. * It transforms points with a rotation around the given axis and center and translates them afterwards. * The angle is given in radians. * * @param transformationCenter * @param axis * @param angle */ public AffineMotionField (PointND transformationCenter, SimpleVector axis, double angle, SimpleVector translation){ back = new Translation(transformationCenter.getAbstractVector()); toCenter = back.inverse(); warp = new IdentityTimeWarper(); center = transformationCenter; this.axis = axis; this.angle = angle; this.rotationMat = null; this.translation = translation; } /** * Creates a new rotation motion field. * It transforms points with a rotation around the given axis and center and translates them afterwards. * The angle is given in radians. * * @param transformationCenter * @param axis * @param angle */ public AffineMotionField (PointND transformationCenter, SimpleVector axis, double angle){ this(transformationCenter, axis, angle, new SimpleVector(transformationCenter.getDimension())); } /** * Creates a new rotational and translation MotionField. * * @param transformationCenter the center point of the rotation * @param rotMat the rotation matrix * @param translation the translation */ public AffineMotionField (PointND transformationCenter, SimpleMatrix rotMat, SimpleVector translation){ back = new Translation(transformationCenter.getAbstractVector()); toCenter = back.inverse(); warp = new IdentityTimeWarper(); center = transformationCenter; this.axis = null; this.angle = 0; this.rotationMat = rotMat; this.translation = translation; } /** * Returns the interpolated transform between initial time and time. * @param initialTime * @param time * @return the transform * @throws Exception */ @Override public Transform getTransform(double initialTime, double time) { Transform affine = null; if (axis != null){ affine = new AffineTransform( Rotations.createRotationMatrixAboutAxis(new Axis(axis), angle * (warp.warpTime(time)-warp.warpTime(initialTime))), translation.multipliedBy(warp.warpTime(time)-warp.warpTime(initialTime)) ); } else{ // TODO: add support for rotation matrices (Use axis/angle representation) try { throw new Exception("Support for rotation matrices not yet implemented"); } catch (Exception e) { e.printStackTrace(); } } affine = new ComboTransform(toCenter,affine,back); return affine; } } /* * Copyright (C) 2010-2014 Martin Berger * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */