package edu.stanford.rsl.conrad.phantom.forbild.shapes; import java.util.ArrayList; import java.util.Iterator; import java.util.Scanner; import edu.stanford.rsl.conrad.geometry.AbstractShape; import edu.stanford.rsl.conrad.geometry.Axis; import edu.stanford.rsl.conrad.geometry.CoordinateSystem; import edu.stanford.rsl.conrad.geometry.General; import edu.stanford.rsl.conrad.geometry.Rotations; import edu.stanford.rsl.conrad.geometry.bounds.HalfSpaceBoundingCondition; import edu.stanford.rsl.conrad.geometry.shapes.StandardCoordinateSystem; import edu.stanford.rsl.conrad.geometry.shapes.simple.Ellipsoid; import edu.stanford.rsl.conrad.geometry.shapes.simple.Plane3D; import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND; import edu.stanford.rsl.conrad.geometry.transforms.AffineTransform; import edu.stanford.rsl.conrad.numerics.SimpleMatrix; import edu.stanford.rsl.conrad.numerics.SimpleVector; import edu.stanford.rsl.conrad.numerics.mathexpressions.Evaluator; /** * <p>This class creates a surface from a <a href = "http://www.imp.uni-erlangen.de/forbild/english/forbild/index.htm">forbild</a>definition.</p> * <p>The expression [Ellipsoid: x=originX; y=originY; z=originZ; dx = dx; dz=dz, dz= dy; axis(a_x, a_y, a_z)] defines a uniform ellipsoid with axis (a_x, a_y, a_z) with center of mass at (originX,originY,originZ),.</p> * * @author Rotimi .X. Ojo */ public class ForbildEllipsoid extends Ellipsoid { public static final long serialVersionUID = -5672890761680090611L; private PointND surfaceOrigin = new PointND(0,0,0); private SimpleVector axis = new SimpleVector(1,0,0); private double dx,dy,dz; private SimpleVector a_x,a_y,a_z; private ArrayList<Plane3D> boundingPlanes = new ArrayList<Plane3D>(); public ForbildEllipsoid(String expression){ parseExpression(expression); correctAxis(expression); InitializeEllipsoid(); correctBoundingConditions(); } public ForbildEllipsoid(ForbildEllipsoid fe){ super(fe); dx = fe.dx; dy = fe.dy; dz = fe.dz; surfaceOrigin = (fe.surfaceOrigin != null) ? fe.surfaceOrigin.clone() : null; axis = (fe.axis != null) ? fe.axis.clone() : null; if (fe.boundingPlanes != null){ boundingPlanes = new ArrayList<Plane3D>(); Iterator<Plane3D> it = fe.boundingPlanes.iterator(); while (it.hasNext()) { Plane3D pl = it.next(); boundingPlanes.add((pl!=null) ? new Plane3D(pl) : null); } } else{ boundingPlanes = null; } a_x = (fe.a_x != null) ? fe.a_x.clone() : null; a_y = (fe.a_y != null) ? fe.a_y.clone() : null; a_z = (fe.a_z != null) ? fe.a_z.clone() : null; } private void InitializeEllipsoid() { SimpleMatrix scaleRotate= null; SimpleVector translate = surfaceOrigin.getAbstractVector().clone(); if(a_x != null || a_y != null || a_z != null){ CoordinateSystem oldSystem = new StandardCoordinateSystem(getDimension()); CoordinateSystem newSystem = createNewCoodSystem(); scaleRotate = Rotations.create3DChangeOfAxesMatrix(oldSystem, newSystem); //scaleRotate = createNewCoodSystem(); }else{ scaleRotate = getChangeOfAxisMatrix(new Axis(axis)); } AffineTransform tr = new AffineTransform(scaleRotate,translate); super.init(dx, dy, dz, tr); } private void correctBoundingConditions() { Iterator<Plane3D> it = boundingPlanes.iterator(); while(it.hasNext()){ Plane3D currPlane = it.next(); currPlane.applyTransform(transform.inverse()); addBoundingCondition(new HalfSpaceBoundingCondition(currPlane)); } } private CoordinateSystem createNewCoodSystem() { completeTriaxis(); /*SimpleMatrix rot = new SimpleMatrix(3,3); rot.setRowValue(0, a_x.getSubVec(0, a_x.getLen())); rot.setRowValue(1, a_y.getSubVec(0, a_y.getLen())); rot.setRowValue(2, a_z.getSubVec(0, a_z.getLen())); rot.transpose(); return rot;*/ return new CoordinateSystem(new Axis(a_x), new Axis(a_y), new Axis(a_z)); } /*private CoordinateSystem createNewCoodSystem() { completeTriaxis(); return new CoordinateSystem(new Axis(a_x),new Axis(a_y),new Axis(a_z)); }*/ private void completeTriaxis() { if (a_x != null && a_y != null) a_z = General.crossProduct(a_x, a_y); else if(a_x != null && a_z != null) a_y = General.crossProduct(a_x, a_z); else if(a_y != null && a_z != null) a_x = General.crossProduct(a_y, a_z); else throw new RuntimeException(); } /** * Determines the subclass of forbild cylinder and corrects axis information appropriately * @param objectType */ private void correctAxis(String expression) { String objectType = expression.substring(0, expression.indexOf(':')) .trim().toLowerCase(); int length = objectType.length(); if(objectType.charAt(length-2)== '_' && objectType.charAt(length - 1)=='x'){ axis = new SimpleVector(1,0,0); }else if(objectType.charAt(length-2)== '_' && objectType.charAt(length - 1)=='y'){ axis = new SimpleVector(0,1,0); }else if(objectType.charAt(length-2)== '_' && objectType.charAt(length - 1)=='z'){ axis = new SimpleVector(0,0,1); } } private void parseExpression(String expression) { expression = expression.trim(); if(expression.charAt(0)=='(' && expression.charAt(expression.length()-1)==')'){ expression = expression.substring(1,expression.length()-1); } String props = expression.substring(expression.indexOf(':')+ 1).trim(); Scanner sc = new Scanner(props); sc.useDelimiter(";"); while(sc.hasNext()){ String currProp = sc.next().trim(); if(currProp.charAt(0)== 'x'&& currProp.contains("=")){ surfaceOrigin.set(0,Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1))); }else if(currProp.charAt(0)== 'y'&& currProp.contains("=")){ surfaceOrigin.set(1,Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1))); }else if(currProp.charAt(0)== 'z' && currProp.contains("=")){ surfaceOrigin.set(2,Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1))); }else if(currProp.indexOf("dx")==0){ dx = Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1)); }else if(currProp.indexOf("dy")==0){ dy = Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1)); }else if(currProp.indexOf("dz")==0){ dz = Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1)); }else if(currProp.charAt(0)== 'r' && !(currProp.contains(">") || currProp.contains("<"))){ double radius = Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1)); dx = radius; dy = radius; }else if(currProp.charAt(0)== 'l'){ dz = Evaluator.getValue(currProp.substring(currProp.indexOf('=')+1)); }else if(currProp.contains("axis")){ axis = Evaluator.getVectorValue(currProp.substring(currProp.indexOf('('), currProp.length())); }else if(currProp.contains("r") && (currProp.contains(">") || currProp.contains("<"))){ boundingPlanes.add(Evaluator.getPlane(currProp)); }else if(currProp.indexOf("a_x")==0){ a_x = Evaluator.getVectorValue(currProp.substring(currProp.indexOf('('), currProp.length())); }else if(currProp.indexOf("a_y")==0){ a_y = Evaluator.getVectorValue(currProp.substring(currProp.indexOf('('), currProp.length())); }else if(currProp.indexOf("a_z")==0){ a_z = Evaluator.getVectorValue(currProp.substring(currProp.indexOf('('), currProp.length())); }else if(currProp.contains("x") && (currProp.contains(">") || currProp.contains("<"))){ String newProp = ""; if(currProp.contains(">") ){ newProp = "r ( -1 , 0 , 0 )"+currProp.substring(currProp.indexOf(">")); }else{ newProp = "r ( 1 , 0 , 0 )"+currProp.substring(currProp.indexOf("<")); } boundingPlanes.add(Evaluator.getPlane(newProp)); }else if(currProp.contains("y") && (currProp.contains(">") || currProp.contains("<"))){ String newProp = ""; if(currProp.contains(">") ){ newProp = "r ( 0 , -1 , 0 )"+currProp.substring(currProp.indexOf(">")); }else{ newProp = "r ( 0 , 1 , 0 )"+currProp.substring(currProp.indexOf("<")); } boundingPlanes.add(Evaluator.getPlane(newProp)); }else if(currProp.contains("z") && (currProp.contains(">") || currProp.contains("<"))){ String newProp = ""; if(currProp.contains(">") ){ newProp = "r ( 0 , 0 , -1 )"+currProp.substring(currProp.indexOf(">")); }else{ newProp = "r ( 0 , 0 , 1 )"+currProp.substring(currProp.indexOf("<")); } boundingPlanes.add(Evaluator.getPlane(newProp)); } } correctAxis(expression); } @Override public AbstractShape clone() { return new ForbildEllipsoid(this); } } /* * Copyright (C) 2010-2014 Rotimi X Ojo * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */