package edu.stanford.rsl.conrad.geometry.shapes.simple; import java.util.ArrayList; import edu.stanford.rsl.conrad.geometry.AbstractCurve; import edu.stanford.rsl.conrad.geometry.AbstractShape; import edu.stanford.rsl.conrad.geometry.Axis; import edu.stanford.rsl.conrad.geometry.General; import edu.stanford.rsl.conrad.geometry.bounds.HalfSpaceBoundingCondition; import edu.stanford.rsl.conrad.geometry.shapes.compound.CompoundShape; 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; import edu.stanford.rsl.conrad.utils.CONRAD; /** * Creates a Cylinder. * @author Rotimi X Ojo */ public class Cylinder extends QuadricSurface { private static final long serialVersionUID = 6986546973890638795L; private Axis principalAxis = new Axis(new SimpleVector(0,0,1)); public double dz, dx, dy; public Cylinder(){ } /** * Creates a new cylinder around (0,0,0) with radii dx, dy, and height dz. * @param dx radius in x direction * @param dy radius in y direction * @param dz height */ public Cylinder(double dx, double dy, double dz){ init(dx, dy, dz, null); } public Cylinder(Cylinder fc) { super(fc); principalAxis = (fc.principalAxis != null) ? fc.principalAxis.clone() : null; dx = fc.dx; dy = fc.dy; dz = fc.dz; } 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.dz = dz; this.dx = dx; this.dy = dy; this.transform = transform; Plane3D top = new Plane3D(new PointND(0,0,dz/2), new SimpleVector(0,0,-1)); Plane3D but = new Plane3D(new PointND(0,0,-dz/2), new SimpleVector(0,0,1)); addBoundingCondition(new HalfSpaceBoundingCondition(top)); addBoundingCondition(new HalfSpaceBoundingCondition(but)); double constArray[][] = {{1/(dx*dx),0,0},{0,1/(dy*dy),0},{0,0,0}}; super.constMatrix = new SimpleMatrix(constArray); super.constant = 1; this.min = new PointND(-dx, -dy, -dz/2); //this.min = this.transform.transform(this.min); this.max = new PointND(dx, dy, dz/2); //this.max = this.transform.transform(this.max); } @Override public ArrayList<PointND> getHits (AbstractCurve other){ ArrayList<PointND> results = super.getHits(other); SimpleVector dir = new SimpleVector(0, 0 ,1); StraightLine line = (StraightLine)other; SimpleVector lineOrigin = line.getPoint().getAbstractVector(); SimpleVector direction = line.getDirection(); //if (results.size() == 0){ if (General.areColinear(direction, dir, CONRAD.FLOAT_EPSILON)){ // This is done redundantly --> Just add a dummy variable that is out of bounds! double first = Math.pow(lineOrigin.getElement(0) / dx,2); double second = Math.pow(lineOrigin.getElement(1) / dy,2); if (first + second < 1){ results.clear(); //results.add(new PointND(lineOrigin.getElement(0), lineOrigin.getElement(1), -dz/2)); //results.add(new PointND(lineOrigin.getElement(0), lineOrigin.getElement(1), dz/2)); results.add(new PointND(0, 0, dz)); } } //} return results; } @Override public boolean isBounded() { return true; } @Override public int getDimension() { return 3; } @Override public PointND[] getRasterPoints(int number) { // TODO Auto-generated method stub return null; } @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) { PointND centerTop = (new PointND((min.get(0)+max.get(0))/2, (min.get(1)+max.get(1))/2, max.get(2))); PointND centerBottom = (new PointND((min.get(0)+max.get(0))/2, (min.get(1)+max.get(1))/2, min.get(2))); int pointsOnCurve = (int) (accuracy * 60); PointND[] upperCurve = new PointND[pointsOnCurve+1]; //last value equals first value PointND[] lowerCurve = new PointND[pointsOnCurve+1]; //last value equals first value double angleIncrement = (2*Math.PI)/pointsOnCurve; double angle; for (int i = 0; i < pointsOnCurve; i++) { angle = i*angleIncrement; upperCurve[i] = (new PointND(((min.get(0)+ max.get(0))/2)+0.5*(max.get(0)-min.get(0))*Math.cos(angle), ((min.get(1)+ max.get(1))/2)+0.5*(max.get(1)-min.get(1))*Math.sin(angle), max.get(2))); lowerCurve[i] = (new PointND(((min.get(0)+ max.get(0))/2)+0.5*(max.get(0)-min.get(0))*Math.cos(angle), ((min.get(1)+ max.get(1))/2)+0.5*(max.get(1)-min.get(1))*Math.sin(angle), min.get(2))); } upperCurve[pointsOnCurve] = upperCurve[0]; lowerCurve[pointsOnCurve] = lowerCurve[0]; CompoundShape shape = new CompoundShape(); for (int i = 0; i < pointsOnCurve; i++) { /* * Create cylinder top and bottom plane */ shape.add(new Triangle(centerTop, upperCurve[i], upperCurve[i+1])); shape.add(new Triangle(centerBottom, lowerCurve[i+1], lowerCurve[i])); /* * Create lateral surface */ shape.add(new Triangle(upperCurve[i], lowerCurve[i], upperCurve[i+1])); shape.add(new Triangle(lowerCurve[i], upperCurve[i+1], lowerCurve[i+1])); } return shape; } @Override 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 angleIncrement = (2*Math.PI)/(pointsOnCurve-1); double angle; for (int j = 0; j < numberOfCurves; j++){ for (int i = 0; i < pointsOnCurve; i++) { angle = i*angleIncrement; curve[(i*numberOfCurves+j)*3] = (float) (((min.get(0)+ max.get(0))/2)+0.5*(max.get(0)-min.get(0))*Math.cos(angle)); curve[(i*numberOfCurves+j)*3+1] = (float) (((min.get(1)+ max.get(1))/2)+0.5*(max.get(1)-min.get(1))*Math.sin(angle)); curve[(i*numberOfCurves+j)*3+2] = (float) (max.get(2)- (max.get(2)-min.get(2)) * ((float) j/(numberOfCurves-1)) ); //curve[i] = (new PointND(((min.get(0)+ max.get(0))/2)+0.5*(max.get(0)-min.get(0))*Math.cos(angle), ((min.get(1)+ max.get(1))/2)+0.5*(max.get(1)-min.get(1))*Math.sin(angle), max.get(2))); //lowerCurve[i] = (new PointND(((min.get(0)+ max.get(0))/2)+0.5*(max.get(0)-min.get(0))*Math.cos(angle), ((min.get(1)+ max.get(1))/2)+0.5*(max.get(1)-min.get(1))*Math.sin(angle), min.get(2))); } } return curve; } @Override public AbstractShape clone() { return new Cylinder(this); } } /* * Copyright (C) 2010-2014 Andreas Maier, Rotimi X Ojo * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */