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). */