content: package edu.stanford.rsl.conrad.geometry.shapes.simple;
  
  import java.util.ArrayList;
  
  import edu.stanford.rsl.apps.gui.opengl.PointCloudViewer;
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.geometry.Axis;
  import edu.stanford.rsl.conrad.geometry.bounds.HalfSpaceBoundingCondition;
  import edu.stanford.rsl.conrad.geometry.transforms.AffineTransform;
  import edu.stanford.rsl.conrad.geometry.transforms.Transform;
  import edu.stanford.rsl.conrad.numerics.SimpleMatrix;
  import edu.stanford.rsl.conrad.numerics.SimpleVector;
  
  /**
   * Creates a Cone.
   */
  public class Cone extends QuadricSurface {
  
  	private static final long serialVersionUID = 6986546973890638795L;
  	private Axis principalAxis = new Axis(new SimpleVector(0,0,1));
  	
  	public Cone() {
  	}
  	
  	/**
  	 * @param dx
  	 * @param dy
  	 * @param dz
  	 */
  	public Cone(double dx, double dy, double dz){
  		init(dx, dy, dz, null);
  	}
  	
  	/**
  	 * @param c
  	 */
  	public Cone(Cone c){
  		super(c);
  		principalAxis = (c.principalAxis != null) ? c.principalAxis.clone() : null; 
  		min = c.min != null ? c.min.clone() : null;
  		max = c.max != null ? c.max.clone() : null;
  	}
  	
  	protected void init(double dx, double dy, double dz,Transform transform) {
  		if(transform == null){
      		SimpleMatrix mat = new SimpleMatrix(3,3);
      		mat.identity();
      		transform = new AffineTransform(mat, new SimpleVector(3));
      	}
      	this.transform = transform;
  		Plane3D topPlane = new Plane3D(new PointND(0,0,0), new SimpleVector(0,0,-1));
  		Plane3D bottomPlane = new Plane3D(new PointND(0,0,-dz), new SimpleVector(0,0,1));
  		addBoundingCondition(new HalfSpaceBoundingCondition(topPlane));
  		addBoundingCondition(new HalfSpaceBoundingCondition(bottomPlane));
  		
  		double constArray[][] = {{dz/dx,0,0},{0,dz/dy,0},{0,0,-1}};
  		super.constMatrix = new SimpleMatrix(constArray);
  		super.constant = 0;
  		
  		this.min = new PointND(-dx, -dy, -dz);
  		this.min = this.transform.transform(this.min);
  		this.max = new PointND(dx, dy, 0);
  		this.max = this.transform.transform(this.max);
  	}
  
  	@Override
  	public boolean isBounded() {
  		return true;
  	}
  
  	@Override
  	public int getDimension() {
  		throw new UnsupportedOperationException();
  	}
  
  	public double interpolate(double factor){      // how to add some weight to make it non-uniform distribution along z axis???
  		double first = min.get(2);
  		double second = max.get(2);
  		
  		return (first*(1.0 - factor) + second*factor);
  	}
  	
  	public float[] getRasterPoints(int elementCountU, int elementCountV) {
  
  		if (elementCountV < 2 || elementCountV < 3){
  			System.out.println("Error! elementCounts too small.");
  			return null;
  		}
  		
  		int numberOfCurves = elementCountU;
  		int pointsOnCurve = elementCountV;
  		float[] curve = new float[numberOfCurves*pointsOnCurve*3]; 
  		
  		double a = 0.5*(max.get(0) - min.get(0))/(max.get(2) - min.get(2));
  		double b = 0.5*(max.get(1) - min.get(1))/(max.get(2) - min.get(2));
  		
  		double angleIncrement = (2*Math.PI)/(pointsOnCurve);
  		double angle;
  		double height;
  		double factor;
  		
  		for (int j = 0; j < numberOfCurves; j++){
  			for (int i = 0; i < pointsOnCurve; i++) {
  				angle = i*angleIncrement;
  				height = (double)(j*(max.get(2) - min.get(2))/(numberOfCurves - 1));
  				factor = (double)(j/(numberOfCurves -1));
  				
  				float coorZ = (float) (min.get(2) + height);
  				//float coorZ = (float) (interpolate(height));  // ?? the input of interpolate() should be factor, but error. why???
  				
  				curve[(i*numberOfCurves+j)*3] = (float) (((min.get(0) + max.get(0))/2) + a*coorZ*Math.cos(angle));
  				curve[(i*numberOfCurves+j)*3+1] = (float) (((min.get(1) + max.get(1))/2) + b*coorZ*Math.sin(angle));
  				curve[(i*numberOfCurves+j)*3+2] = coorZ;
  			}
  		}
  		
  		return curve;
  	}
  	
  	@Override
  	public Axis getPrincipalAxis() {
  		return principalAxis;
  	}
  
  	@Override
  	public void applyTransform(Transform t) {
  		super.applyTransform(t);
  		this.min = t.transform(this.min);
  		this.max = t.transform(this.max);
  	}
  	@Override
  	public AbstractShape tessellate(double accuracy) {
  		// TODO Auto-generated method stub
  		return null;
  	}
  
  	@Override
  	public AbstractShape clone() {
  		return new Cone(this);
  	}
  	
  	public ArrayList<PointND> getPointCloud(int u, int v){
  		float[] rasterPoints = this.getRasterPoints(u, v);
  		//PointND[] points = box.getRasterPoints(256);
  		
  	    ArrayList<PointND> pointsList= new ArrayList<PointND>();
  		
  	    for (int i= 0; i < rasterPoints.length/3; i++){
  
  			PointND point = new PointND(rasterPoints[(i*3)],rasterPoints[(i*3)+1],rasterPoints[(i*3)+2]);
  			//	PointND point = new PointND(points[i].get(0),points[i].get(1),points[i].get(2));
  
  	    		pointsList.add(point);
  	    	
  		}
  	    return pointsList;
  	}
  	
  	public static void main(String [] args){
  		Cone cone = new Cone (10,10,10);
  		
  		int u = 2;
  		int v = 10;
  		
  		ArrayList<PointND> pointsList = new ArrayList<PointND>();
  		pointsList = cone.getPointCloud(u, v);
  		
  		PointCloudViewer pcv = new PointCloudViewer("Cone Visualization", pointsList);
  		pcv.setVisible(true);
  	}
  	
  }
  /*
   * Copyright (C) 2010-2014 Andreas Maier, Rotimi X Ojo, Zijia Guo 
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */