package edu.stanford.rsl.conrad.geometry.shapes.simple;
import edu.stanford.rsl.conrad.geometry.AbstractShape;
import edu.stanford.rsl.conrad.geometry.Axis;
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;
/**
* Creates a Sphere.
* @author Rotimi X Ojo
*/
public class Sphere extends QuadricSurface {
private static final long serialVersionUID = 7869742887570580304L;
private Axis principalAxis = new Axis(new SimpleVector(1,0,0));
public Sphere(){
}
public Sphere(double radius, PointND surfaceOrigin){
init(radius, surfaceOrigin);
}
public Sphere(double radius){
init(radius, new PointND(0,0,0));
}
public Sphere(Sphere s){
super(s);
principalAxis = (s.principalAxis != null) ? s.principalAxis.clone() : null;
}
protected void init(double radius, PointND surfaceOrigin){
SimpleMatrix mat = new SimpleMatrix(3,3);
mat.identity();
transform = new AffineTransform(mat, surfaceOrigin.getAbstractVector());
double cons = 1/(radius*radius);
double constArray[][] = {{cons,0,0},{0,cons,0},{0,0,cons}};
super.constMatrix = new SimpleMatrix(constArray);
super.constant = 1;
this.min = new PointND(surfaceOrigin.get(0) - radius, surfaceOrigin.get(1) - radius, surfaceOrigin.get(2) - radius);
this.max = new PointND(surfaceOrigin.get(0) + radius, surfaceOrigin.get(1) + radius, surfaceOrigin.get(2) + radius);
}
@Override
public boolean isBounded() {
return true;
}
@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 center = (new PointND((min.get(0)+max.get(0))/2, (min.get(1)+max.get(1))/2,(min.get(2)+max.get(2))/2));
double radius = (max.get(0)-min.get(0))/2;
int pointsOnCurve = (int) (accuracy * 50);
int nextCurve = pointsOnCurve + 1;
double angle;
double angleIncrement = (2*Math.PI)/pointsOnCurve;
int slices = (int) (accuracy*40);
if (slices%2 != 0) slices++; //uneven number of slices to include equator curve
double curveDistance = (radius*2)/(slices);
PointND[] curve = new PointND[(pointsOnCurve+1)*(slices + 1)]; //last value of each slice's curve equals first value. Total number of curves is number of slices + 1.
/*
* Create all layers
*/
CompoundShape shape = new CompoundShape();
double scalingCurve;
for (int z = 0; z <= slices; z++) {
scalingCurve = Math.sqrt(Math.pow(radius, 2) - Math.pow((radius-z*curveDistance), 2));
angle = 0;
for (int i = 0+z*nextCurve; i < pointsOnCurve+z*nextCurve; i++) {
curve[i] = (new PointND(center.get(0)+scalingCurve*Math.cos(angle), center.get(1)+scalingCurve*Math.sin(angle), center.get(2)+radius-z*curveDistance));
angle += angleIncrement;
}
curve[pointsOnCurve+z*nextCurve] = curve[0+z*nextCurve];
}
for (int z = 0; z < slices; z++) {
for (int i = 0+z*nextCurve; i < pointsOnCurve+z*nextCurve; i++) {
if (i > pointsOnCurve) shape.add(new Triangle(curve[i], curve[i+nextCurve], curve[i+1]));
if (i < pointsOnCurve+(slices-2)*nextCurve) shape.add(new Triangle(curve[i+nextCurve], curve[i+1+nextCurve], curve[i+1]));
}
}
return shape;
}
public double getRadius(){
return (max.get(0)-min.get(0))/2;
}
public PointND getCenter(){
return new PointND((min.get(0)+max.get(0))/2, (min.get(1)+max.get(1))/2,(min.get(2)+max.get(2))/2);
}
@Override
public float[] getRasterPoints(int elementCountU, int elementCountV) {
if (elementCountU < 2){
System.out.println("Error! valuesU has to be higher than 1");
return null;
}
PointND center = (new PointND((min.get(0)+max.get(0))/2, (min.get(1)+max.get(1))/2,(min.get(2)+max.get(2))/2));
double radius = (max.get(0)-min.get(0))/2;
int pointsOnCurve = elementCountU;
double angle;
double angleIncrement = (2*Math.PI)/(pointsOnCurve-1);
int numberOfCurves = elementCountV;
double curveDistance = (radius*2)/(numberOfCurves-1);
float[] curve = new float[(pointsOnCurve)*(numberOfCurves)*3];
double scalingCurve;
for (int i = 0; i < pointsOnCurve; i++) {
//for (int j = 0+i*nextCurve; j < pointsOnCurve+i*nextCurve; j++) {
for (int j = 0; j < numberOfCurves; j++){
angle = i * angleIncrement;
scalingCurve = Math.sqrt(Math.pow(radius, 2) - Math.pow((radius-j*curveDistance), 2));
curve[(j*pointsOnCurve+i)*3] = (float) (center.get(0)+scalingCurve*Math.cos(angle));
curve[(j*pointsOnCurve+i)*3+1] = (float) (center.get(1)+scalingCurve*Math.sin(angle));
curve[(j*pointsOnCurve+i)*3+2] = (float) (center.get(2)-radius+j*curveDistance);
}
}
return curve;
}
@Override
public AbstractShape clone() {
return new Sphere(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).
*/