content: 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.bounds.HalfSpaceBoundingCondition;
  import edu.stanford.rsl.conrad.geometry.shapes.simple.Box;
  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 [Box: x=originX;  y=originY;  z=originZ;  dx=length;  dy=width;  dz= height] defines a box located at (originX,originY,originZ).</p>
   * 
   * @author Rotimi .X. Ojo
   */
  public class ForbildBox extends Box {
  
  	private static final long serialVersionUID = 4063615482635066034L;
  	 private PointND surfaceOrigin = new PointND(0,0,0);
  	 private ArrayList<Plane3D> boundingPlanes =  new ArrayList<Plane3D>();
  	 private double dx;
  	 private double dy;
  	 private double dz;
  	
  
  	public ForbildBox(String expression){
  		 parseExpression(expression);
  		 SimpleMatrix rot = new SimpleMatrix(3,3);
  		 rot.identity();
  		 transform = new AffineTransform(rot, new SimpleVector(3));
  		 correctAndAddBoundingConditions();
  		 surfaceOrigin.set(0, surfaceOrigin.get(0)-dx/2);
  		 surfaceOrigin.set(1, surfaceOrigin.get(1)-dy/2);
  		 surfaceOrigin.set(2, surfaceOrigin.get(2)-dz/2);
  		 super.init(surfaceOrigin, dx, dy , dz);
  	 }
  	
  	public ForbildBox(ForbildBox fb){
  		super(fb);
  		dx = fb.dx;
  		dy = fb.dy;
  		dz = fb.dz;
  		surfaceOrigin = (fb.surfaceOrigin != null) ? fb.surfaceOrigin.clone() : null;
  		if (fb.boundingPlanes != null){
  			boundingPlanes = new ArrayList<Plane3D>();
  			Iterator<Plane3D> it = fb.boundingPlanes.iterator();
  			while (it.hasNext()) {
  				Plane3D pl = it.next();
  				boundingPlanes.add((pl!=null) ? new Plane3D(pl) : null);
  			}
  		}
  		else{
  			boundingPlanes = null;
  		}
  	}
  
  	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.contains("r") && (currProp.contains(">") || currProp.contains("<"))){				
  				boundingPlanes.add(Evaluator.getPlane(currProp));
  			}
  		}
  	}
  	
  	/**
  	 * Moves bounding planes from world space to the space of the bounded object
  	 * Creates a bounding condition using this new plane and updates the superclass
  	 */
  	private void correctAndAddBoundingConditions() {
  		Iterator<Plane3D> it = boundingPlanes.iterator();
  		while(it.hasNext()){
  			Plane3D currPlane = it.next();
  			currPlane.applyTransform(transform.inverse());
  			addBoundingCondition(new HalfSpaceBoundingCondition(currPlane));
  		}		
  	}
  	
  	@Override
  	public AbstractShape clone() {
  		return new ForbildBox(this);
  	}
  }
  /*
   * Copyright (C) 2010-2014 Rotimi X Ojo
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */