content: package edu.stanford.rsl.conrad.geometry.shapes.compound;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Iterator;
  
  import edu.stanford.rsl.conrad.geometry.AbstractCurve;
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND;
  import edu.stanford.rsl.conrad.geometry.transforms.Transform;
  
  public class CompoundShape extends AbstractShape implements Collection<AbstractShape> {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = 4296470814160586436L;
  	private ArrayList<AbstractShape> list;
  	protected boolean dirty = true;
  
  	public CompoundShape(){
  		list = new ArrayList<AbstractShape>();
  	}
  	
  	public CompoundShape(CompoundShape cs){
  		super(cs);
  		dirty = cs.dirty;
  		
  		if(cs.list != null){
  			Iterator<AbstractShape> it = cs.list.iterator();
  			list = new ArrayList<AbstractShape>();
  			while (it.hasNext()) {
  				AbstractShape shape = it.next();
  				list.add((shape!=null) ? shape.clone() : null);
  			}
  		}
  		else
  			list = null;
  	}
  
  	
  	@Override
  	public int getDimension() {
  		return list.get(0).getDimension();
  	}
  
  	public AbstractShape get(int i){
  		return list.get(i);
  	}
  
  	protected synchronized void init(){
  		if (dirty){
  			min = new PointND(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
  			max = new PointND(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE);
  			for (AbstractShape t: list){
  				min.updateIfLower(t.getMin());
  				max.updateIfHigher(t.getMax());
  			}
  			super.generateBoundingPlanes();
  			dirty = false;
  		}
  	}
  
  	@Override
  	public ArrayList<PointND> getHitsOnBoundingBox(AbstractCurve curve){
  		if (dirty){
  			init();
  		}
  		return super.getHitsOnBoundingBox(curve);
  	}
  
  	protected static ArrayList<PointND> intersect(AbstractShape t, AbstractCurve other){
  		ArrayList<PointND> pts = null;
  		if (t instanceof CompoundShape){
  			CompoundShape compound = (CompoundShape) t;
  			if (compound.getHitsOnBoundingBox(other).size() > 0){
  				pts = compound.intersect(other);
  			} else {
  				pts = new ArrayList<PointND>();
  			}
  		} else {
  			 pts = t.intersect(other);
  		}
  		return pts;
  	}
  	
  	protected static ArrayList<PointND> intersectWithHitOrientation(AbstractShape t, AbstractCurve other){
  		ArrayList<PointND> pts = null;
  		if (t instanceof CompoundShape){
  			CompoundShape compound = (CompoundShape) t;
  			if (compound.getHitsOnBoundingBox(other).size() > 0){
  				pts = compound.intersectWithHitOrientation(other);
  			} else {
  				pts = new ArrayList<PointND>();
  			}
  		} else {
  			 pts = t.intersectWithHitOrientation(other);
  		}
  		return pts;
  	}
  
  	@Override
  	public ArrayList<PointND> intersect(AbstractCurve other) {
  		if (dirty){
  			init();
  		}
  		ArrayList <PointND> hits = new ArrayList<PointND>();
  		for(AbstractShape t: list){
  			hits.addAll(intersect(t,other));
  		}
  		return hits;
  	}
  	
  	
  
  	@Override
  	public ArrayList<PointND> intersectWithHitOrientation(AbstractCurve other) {
  		if (dirty){
  			init();
  		}
  		ArrayList <PointND> hits = new ArrayList<PointND>();
  		for(AbstractShape t: list){
  			hits.addAll(intersectWithHitOrientation(t, other));
  		}
  		return hits;
  	}
  
  	@Override
  	public boolean isBounded() {
  		return true;
  	}
  
  	@Override
  	public PointND getMax(){
  		if (dirty){
  			init();
  		}
  		return super.getMax();
  	}
  
  	@Override
  	public PointND getMin(){
  		if (dirty){
  			init();
  		}
  		return super.getMin();
  	}
  
  	public boolean add(AbstractShape shape){
  		boolean revan = list.add(shape);
  		dirty = true;
  		return revan;
  	}
  
  	public PointND[] getRasterPoints(int number){
  		ArrayList<PointND[]> lists = new ArrayList<PointND[]>();
  		int sum = 0;
  		for (AbstractShape t : list){
  			PointND [] pts = t.getRasterPoints(number/ list.size());
  			sum += pts.length;
  			lists.add(pts);
  		}
  		PointND [] points = new PointND[sum];
  		int increment = 0;
  		for (PointND [] pts : lists){
  			System.arraycopy(pts, 0, points, increment, pts.length);
  			increment += pts.length;
  		}
  		return points;
  	}
  
  	@Override
  	public void applyTransform(Transform t) {
  		for (AbstractShape s: list){
  			//System.out.println("CompundShape: applying Transform to " + s.toString());
  			s.applyTransform(t);
  			//System.out.println("CompundShape: applied Transform to " + s.toString());
  		}
  		dirty = true;
  	}
  
  	@Override
  	public PointND evaluate(PointND u) {
  		return null;
  	}
  
  	@Override
  	public int getInternalDimension() {
  		return list.size();
  	}
  
  	@Override
  	public boolean addAll(Collection<? extends AbstractShape> c) {
  		dirty = true;
  		return list.addAll(c);
  	}
  
  	@Override
  	public void clear() {
  		list.clear();
  		dirty = true;
  	}
  
  	@Override
  	public boolean contains(Object o) {
  		return list.contains(o);
  	}
  
  	@Override
  	public boolean containsAll(Collection<?> c) {
  		return list.containsAll(c);
  	}
  
  	@Override
  	public boolean isEmpty() {
  		return list.isEmpty();
  	}
  
  	@Override
  	public Iterator<AbstractShape> iterator() {
  		return list.iterator();
  	}
  
  	@Override
  	public boolean remove(Object o) {
  		dirty = true;
  		return list.remove(o);
  	}
  
  	@Override
  	public boolean removeAll(Collection<?> c) {
  		dirty =true;
  		return removeAll(c);
  	}
  
  	@Override
  	public boolean retainAll(Collection<?> c) {
  		dirty = true;
  		return list.retainAll(c);
  	}
  
  	@Override
  	public int size() {
  		int size = 0;
  		for (AbstractShape s: list){
  			if (s instanceof Collection<?>){
  				size += ((Collection<?>) s).size();
  			} else {
  				size ++;
  			}
  		}
  		return size;
  	}
  
  	@Override
  	public Object[] toArray() {
  		return list.toArray();
  	}
  
  	@Override
  	public <T> T[] toArray(T[] a) {
  		return list.toArray(a);
  	}
  
  	@Override
  	public String toString(){
  		return "CompoundShape with " + size() + " elements";
  	}
  
  	@Override
  	public AbstractShape clone() {
  		return new CompoundShape(this);
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier 
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */