package edu.stanford.rsl.conrad.geometry;
import java.io.Serializable;
import java.util.ArrayList;
import edu.stanford.rsl.conrad.geometry.shapes.simple.Plane3D;
import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND;
import edu.stanford.rsl.conrad.geometry.shapes.simple.StraightLine;
import edu.stanford.rsl.conrad.geometry.transforms.Transform;
import edu.stanford.rsl.conrad.geometry.transforms.Transformable;
import edu.stanford.rsl.conrad.utils.CONRAD;
/**
* Class to model any kind of curve or surface.
* <br><br>
* <img alt="Saddle Surface" height="150" width="150" src="http://upload.wikimedia.org/wikipedia/commons/2/21/Saddle_pt.jpg"><BR>
* Example for a 3D surface.
* <br>
* @author akmaier
*
*/
public abstract class AbstractShape implements Serializable, Transformable {
private Plane3D [] boundingPlanes;
protected PointND min;
protected PointND max;
private String name;
public AbstractShape() {
}
/**
* Copy constructor (deep copy)
* @param shape
*/
public AbstractShape(AbstractShape shape){
min = (shape.min != null) ? shape.min.clone() : null;
max = (shape.max != null) ? shape.max.clone() : null;
name = (shape.name != null) ? new String(shape.name) : null;
if (shape.boundingPlanes!=null){
boundingPlanes = new Plane3D[shape.boundingPlanes.length];
for (int i = 0; i < boundingPlanes.length; i++) {
boundingPlanes[i] = (shape.boundingPlanes[i]!=null) ? new Plane3D(shape.boundingPlanes[i]) : null;
}
}
else
boundingPlanes=null;
}
/**
* Returns a deep copy of this shape
* @return Deep copy of this abstract shape
*/
public abstract AbstractShape clone();
/**
* Returns true if the shape is of limited space
* @return Boundedness of this shape.
*/
public abstract boolean isBounded();
/**
* Evaluates the bounding box and returns true if it is hit. If the object is not bounded, it returns true as default.
*
* @param curve the curve
* @return true, if the object is hit.
*/
public ArrayList<PointND> getHitsOnBoundingBox_slow(AbstractCurve curve){
if (isBounded()){
ArrayList<PointND> hits = new ArrayList<PointND>();
for(int i = 0; i< boundingPlanes.length; i++){
Plane3D p = boundingPlanes[i];
try{
ArrayList<PointND> points = p.intersect(curve);
for (PointND intersection : points){
//System.out.println(intersection);
boolean inBound = true;
for (int j=0; j < intersection.getDimension(); j++){
double coord = intersection.get(j);
if (coord > max.get(j) + CONRAD.SMALL_VALUE || coord < min.get(j) - CONRAD.SMALL_VALUE) {
inBound = false;
break;
}
}
if (inBound) {
hits.add(intersection);
}
}
} catch (RuntimeException e){
if (!e.getMessage().equals("Line is parallel to plane")) {
System.out.println(e.getLocalizedMessage());
} else {
}
} catch (Exception e){
e.printStackTrace();
}
}
return hits;
} else {
throw new RuntimeException("Object is not bounded");
}
}
protected void generateBoundingPlanes(PointND min, PointND max){
this.min = min;
this.max = max;
generateBoundingPlanes();
}
public ArrayList<PointND> getHitsOnBoundingBox(AbstractCurve curve){
if (isBounded()){
ArrayList<PointND> hits = null;
if (curve instanceof StraightLine) {
StraightLine line = (StraightLine) curve;
hits = General.intersectRayWithCuboid(line, min, max);
} else {
hits = new ArrayList<PointND>();
for(int i = 0; i< boundingPlanes.length; i++){
Plane3D p = boundingPlanes[i];
try{
ArrayList<PointND> points = p.intersect(curve);
for (PointND intersection : points){
//System.out.println(intersection);
boolean inBound = true;
for (int j=0; j < intersection.getDimension(); j++){
double coord = intersection.get(j);
if (coord > max.get(j) + CONRAD.SMALL_VALUE || coord < min.get(j) - CONRAD.SMALL_VALUE) {
inBound = false;
break;
}
}
if (inBound) {
hits.add(intersection);
}
}
} catch (RuntimeException e){
if (!e.getMessage().equals("Line is parallel to plane")) {
System.out.println(e.getLocalizedMessage());
} else {
}
} catch (Exception e){
e.printStackTrace();
}
}
}
return hits;
} else {
throw new RuntimeException("Object is not bounded");
}
}
protected void generateBoundingPlanes(){
boundingPlanes = new Plane3D[6];
//PointND e1 = new PointND(1, 0, 0);
//PointND e2 = new PointND(0, 1, 0);
//PointND e3 = new PointND(0, 0, 1);
//boundingPlanes[0] = new Plane3D(min, e1.getAbstractVector());
//boundingPlanes[1] = new Plane3D(min, e2.getAbstractVector());
//boundingPlanes[2] = new Plane3D(min, e3.getAbstractVector());
//boundingPlanes[3] = new Plane3D(max, e1.getAbstractVector());
//boundingPlanes[4] = new Plane3D(max, e2.getAbstractVector());
//boundingPlanes[5] = new Plane3D(max, e3.getAbstractVector());
}
/**
*
*/
private static final long serialVersionUID = 6333594201718418159L;
/**
* Returns the point on the shape at the internal position u. If the shape is a curve, u is of dimension 1, if the shape is a surface u is of dimension 2, etc.
* @param u the point in the internal parameter dimension
* @return the point on the shape at the internal dimension
*/
abstract public PointND evaluate(PointND u);
/**
* Returns the external dimension of the shape.
* @return the dimension
*/
abstract public int getDimension();
/**
* returns the internal dimension of the shape, i.e. 1 if it is a curve, 2 if it is a surface, etc.
* @return the internal dimension
*/
abstract public int getInternalDimension();
/**
* Returns the intersection points between the curve and the shape.
* Returns null, if the intersection is empty.
*
* @param other
* @return the intersection points.
*/
abstract public ArrayList<PointND> intersect(AbstractCurve other);
/**
* For most objects this method simply calls intersect(other);
* For triangles the orientation of the hit (scalar product of ray and triangle's normal vectors) is stored as an additional coordinate
*
* @param other
* @return the intersection points
*/
public ArrayList<PointND> intersectWithHitOrientation(AbstractCurve other) {
return intersect(other);
}
/**
* Rasters the shape with a given number of points or less. If the shape is not bounded null is returned.
* @param number the number of points
* @return the raster points
*/
abstract public PointND[] getRasterPoints(int number);
/**
* @return the minimal corner of the bounding box.
*/
public PointND getMin() {
return min;
}
/**
* @return the maximal corner of the bounding box.
*/
public PointND getMax() {
return max;
}
public abstract void applyTransform(Transform t);
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/