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).
*/