content: package edu.stanford.rsl.conrad.phantom;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.geometry.motion.AbstractAffineMotionField;
  import edu.stanford.rsl.conrad.geometry.motion.AffineMotionField;
  import edu.stanford.rsl.conrad.geometry.motion.MotionField;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.CombinedTimeWarper;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.ConstantTimeWarper;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.HarmonicTimeWarper;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.PeriodicTimeWarper;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.SigmoidTimeWarper;
  import edu.stanford.rsl.conrad.geometry.motion.timewarp.TimeWarper;
  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.Transform;
  import edu.stanford.rsl.conrad.geometry.transforms.Translation;
  import edu.stanford.rsl.conrad.numerics.SimpleOperators;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  import edu.stanford.rsl.conrad.physics.PhysicalObject;
  import edu.stanford.rsl.conrad.rendering.PrioritizableScene;
  import edu.stanford.rsl.conrad.utils.CONRAD;
  import edu.stanford.rsl.conrad.utils.UserUtil;
  
  public class AffineMotionPhantom extends AnalyticPhantom4D {
  
  	private static final long serialVersionUID = -255412548002793134L;
  
  	private AnalyticPhantom staticPhantom = null;
  	private AbstractAffineMotionField mf = null;
  
  
  	@Override
  	public void configure() throws Exception {
  		staticPhantom = UserUtil.queryPhantom("Select Phantom", "Select Phantom");
  		staticPhantom.setBackground(this.getBackgroundMaterial());
  		staticPhantom.configure();
  		staticPhantom.setConfigured(true);
  
  		SimpleVector rotAxis = new SimpleVector(UserUtil.queryArray("Please provide rotation axis...", new double[]{1,0,0}));
  		double rotAngle = UserUtil.queryDouble("Please provide rotation angle (degree)", 0) * Math.PI / 180.0;
  		SimpleVector translation = new SimpleVector(UserUtil.queryArray("Please provide translation vector...", new double[]{1,1,1}));	
  		mf = new AffineMotionField(new PointND(0,0,0), rotAxis, rotAngle, translation);
  
  		double rep = UserUtil.queryDouble("Please provide No. of harmonic repetitions", 1);
  		warper = new CombinedTimeWarper(new HarmonicTimeWarper(rep),  new PeriodicTimeWarper(), new SigmoidTimeWarper());
  
  		max = staticPhantom.getMax();
  		min = staticPhantom.getMin();
  		this.setConfigured(true);
  	}
  
  	public void setStaticAnalyticPhantom(AnalyticPhantom phantom){
  		staticPhantom = phantom;
  		if (isConfigured() && !staticPhantom.isConfigured()) {
  			try {
  				staticPhantom.configure();
  				staticPhantom.setConfigured(true);
  			} catch (Exception e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
  			}
  		}
  	}
  
  	public AnalyticPhantom getStaticAnalyticPhantom(){
  		return staticPhantom;
  	}
  
  
  
  	@Override
  	public PointND getPosition(PointND initialPosition, double initialTime,
  			double time) {
  		double t = warper.warpTime(time);
  		return mf.getPosition(initialPosition, initialTime, t);
  	}
  
  	@Override
  	public ArrayList<PointND> getPositions(PointND initialPosition,
  			double initialTime, double... times) {
  		ArrayList<PointND> list = new ArrayList<PointND>();
  		for (int i=0; i< times.length; i++){
  			list.add(getPosition(initialPosition, initialTime, times[i]));
  		}
  		return list;
  	}
  
  	@Override
  	public String getBibtexCitation() {
  		return CONRAD.CONRADBibtex;
  	}
  
  	@Override
  	public String getMedlineCitation() {
  		return CONRAD.CONRADMedline;
  	}
  
  	@Override
  	public PrioritizableScene getScene(double time) {
  
  		PrioritizableScene scene = new PrioritizableScene();
  
  		double t = warper.warpTime(time);
  		//System.out.print(t);
  		//System.out.print(", ");
  
  		// apply motion to all physical object in static phantom and add to current scene
  		if (staticPhantom instanceof AffineMotionPhantom){
  			Iterator<PhysicalObject> objIt = ((AffineMotionPhantom) staticPhantom).getScene(t).iterator();
  			Transform tform = mf.getTransform(0, t);
  			tform = new AffineTransform(tform.getRotation(3), tform.getTranslation(3));
  			while (objIt.hasNext()) {
  				PhysicalObject obj = new PhysicalObject((PhysicalObject) objIt.next());
  				AbstractShape shape = obj.getShape().clone();
  				obj.setShape(shape);
  				obj.applyTransform(tform);
  				scene.add(obj);
  			}
  		}
  		else{	
  			Iterator<PhysicalObject> objIt = staticPhantom.iterator();
  			Transform tform = mf.getTransform(0, t);
  			tform = new AffineTransform(tform.getRotation(3), tform.getTranslation(3));
  			while (objIt.hasNext()) {
  				PhysicalObject obj = new PhysicalObject((PhysicalObject) objIt.next());
  				AbstractShape shape = obj.getShape().clone();
  				obj.setShape(shape);
  				obj.applyTransform(tform);
  				scene.add(obj);
  			}
  		}
  
  		scene.setBackground(staticPhantom.getBackgroundMaterial());
  
  		// set scene limits
  		scene.setMin(min);
  		scene.setMax(max);
  
  		return scene;
  	}
  
  	@Override
  	public String getName() {
  		return "Affine Motion Phantom";
  	}
  
  	public void setMotionField(AbstractAffineMotionField mf) {
  		this.mf = mf;
  	}
  
  	@Override
  	public MotionField getMotionField() {
  		return mf;
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Martin Berger
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
   */
  