content: package edu.stanford.rsl.conrad.phantom;
  
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.geometry.Rotations;
  import edu.stanford.rsl.conrad.geometry.shapes.compound.CompoundShape;
  import edu.stanford.rsl.conrad.geometry.shapes.simple.Box;
  import edu.stanford.rsl.conrad.geometry.shapes.simple.Cylinder;
  import edu.stanford.rsl.conrad.geometry.shapes.simple.Sphere;
  import edu.stanford.rsl.conrad.geometry.transforms.ScaleRotate;
  import edu.stanford.rsl.conrad.geometry.transforms.Translation;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  import edu.stanford.rsl.conrad.physics.PhysicalObject;
  import edu.stanford.rsl.conrad.physics.materials.database.MaterialsDB;
  
  /**
   * MTF phantom defined by Lars Wigstroem. The phantom is a simple elipsoid torso with two high contrast bone-like objects in it. Furthermore, there are three high-beads in the phantom that can be exploited to measure the MTF. 
   * 
   * @author akmaier
   *
   */
  public class CatphanCTP528 extends AnalyticPhantom {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = -3843719205362984060L;
  
  	@Override
  	public String getName(){
  		return "Catphan Module CTP 528";
  	}
  	
  	@Override
  	public String getMedlineCitation(){
  		return "David J. Goodenough. Catphan® 500 and 600 Manual. The Phantom Laboratory. 2009.";
  	}
  	
  	@Override
  	public String getBibtexCitation(){
  		return "@book{Goodenough09-C56,\n" +
  				"  author={Goodenough DJ},\n" +
  				"  title={Catphan® 500 and 600 Manual},\n" +
  				"  publisher={The Phantom Laboratory},\n" +
  				"  year={2009}" +
  				"}";
  	}
  	
  	public static CompoundShape generateLP(double gapSize){
  		int blocks = 5;
  		if (gapSize >= 1) blocks = 4;
  		if (gapSize >= 2.5) blocks = 3;
  		if (gapSize >= 5) blocks = 2;
  		double width = blocks * gapSize + (blocks-1) * gapSize;
  		double height = 5;
  		double centerX = width / 2;
  		double centerY = height / 2;
  		CompoundShape lp = new CompoundShape();
  		for (int i = 0; i < blocks; i++){
  			Box block = new Box(gapSize, height, height);
  			block.applyTransform(new Translation((-centerX)+(i*(2*gapSize)), -centerY, -centerY));
  			lp.add(block);
  		}
  		return lp;
  	}
  	
  	public static double lp [] = {5, 2.5, 1.67, 1.25, 1.0, 0.83, 0.71, 0.63, 0.56, 0.5, 0.45, 0.42, 0.38, 0.36, 0.33, 0.31, 0.29, 0.28, 0.26, 0.25, 0.24};
  	
  	/**
  	 * Construtor which creates the phnatom. Internally the simple geometric objects are created and converted into physical objects by adding material to the geometry. 
  	 */
  	public CatphanCTP528 () {
  		// Body of the phantom.
  		Cylinder mainCylinder = new Cylinder(150.49/2.0, 150.49/2.0, 30);
  		PhysicalObject po = new PhysicalObject();
  		po.setMaterial(MaterialsDB.getMaterialWithFormula("H2O")); //D = 1
  		po.setShape(mainCylinder);
  		add(po);
  		// high contrast bone-like structures
  		Sphere top = new Sphere(0.28);
  		top.applyTransform(new Translation(new SimpleVector(0,20,-2.5)));
  		po = new PhysicalObject();
  		po.setMaterial(MaterialsDB.getMaterialWithName("aluminium"));//D = 2.5
  		po.setShape(top);
  		add(po);
  		Sphere right = new Sphere(0.28);
  		right.applyTransform(new Translation(new SimpleVector(0,-20,-10)));
  		po = new PhysicalObject();
  		po.setMaterial(MaterialsDB.getMaterialWithName("aluminium"));//D = 2.5
  		po.setShape(right);
  		add(po);
  		double radius = 45;
  		double delta = 2 * Math.PI / 23;
  		for (int i=0; i < lp.length; i++){
  			double angle = (delta*(1+0.7*(((double)lp.length-i)/lp.length)))*(i+1);
  			ScaleRotate r = new ScaleRotate(Rotations.createBasicZRotationMatrix(Math.PI/2 +angle));
  			PhysicalObject lps = new PhysicalObject();
  			lps.setMaterial(MaterialsDB.getMaterialWithName("aluminium"));
  			AbstractShape shape = generateLP(lp[i]);
  			shape.applyTransform(r);
  			double x = -Math.cos(angle)*radius;
  			double y = -Math.sin(angle)*radius;
  			Translation t = new Translation(new SimpleVector(x, y, 0));
  			shape.applyTransform(t);
  			lps.setShape(shape);
  			add(lps);
  		}
  	}
  	
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */