/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package automenta.spacenet.space.geom;
import automenta.spacenet.space.HasPosition3;
import automenta.spacenet.space.HasScale2;
import automenta.spacenet.space.Space;
import automenta.spacenet.space.WrapsMesh;
import automenta.spacenet.var.physical.Color;
import automenta.spacenet.var.scalar.DoubleVar;
import automenta.spacenet.var.scalar.DoubleVar.IfDoubleChanges;
import automenta.spacenet.var.vector.Quat;
import automenta.spacenet.var.vector.Quat.IfQuatChanges;
import automenta.spacenet.var.vector.V2;
import automenta.spacenet.var.vector.V2.IfV2Changes;
import automenta.spacenet.var.vector.V3;
import automenta.spacenet.var.vector.V3.IfV3Changes;
import com.ardor3d.bounding.OrientedBoundingBox;
import com.ardor3d.math.Ray3;
import com.ardor3d.math.Vector3;
import com.ardor3d.scenegraph.Mesh;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.scenegraph.shape.Disk;
import com.ardor3d.scenegraph.shape.Quad;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author seh
*/
public class Rect extends Space implements HasPosition3, HasScale2, WrapsMesh {
Mesh shapeSpatial;
private final V3 position;
private final V2 scale;
private final Quat ori;
private IfV3Changes positionChange;
private IfV2Changes scaleChange;
private RectShape currentShape;
private IfQuatChanges oriChange;
private final DoubleVar aspect = new DoubleVar(0);
private final Vector3 vA = new Vector3(); //temporary
private IfDoubleChanges aspectChange;
public Rect(Color fillColor) {
this(RectShape.Rect);
color(fillColor);
}
/** aspect ratio (y/x)
* @return if aspect=0, aspect ratio is not specified */
public DoubleVar getAspect() {
return aspect;
}
@Override
public Mesh getWrappedMesh() {
return shapeSpatial;
}
public static enum RectShape {
Empty, Rect, Ellipse
}
public Rect(RectShape shape) {
this(new V3(0), new V2(1), new Quat(), shape);
}
public Rect(V3 position, V2 scale, Quat orientation, RectShape shape) {
super();
this.position = position;
this.scale = scale;
this.ori = orientation;
setShape(shape);
}
protected void afterAttached(Spatial newParent) {
positionChange = position.add(new V3.IfV3Changes() {
@Override public void onV3Changed(V3 v) {
positionChanged();
}
});
scaleChange = scale.add(new IfV2Changes() {
@Override public void onV2Changed(V2 v) {
sizeChanged();
}
});
oriChange = ori.add(new IfQuatChanges() {
@Override public void onQuatChanged(Quat q) {
oriChanged();
}
});
aspectChange = aspect.add(new DoubleVar.IfDoubleChanges() {
@Override public void onDoubleChange(DoubleVar d) {
aspectChanged();
}
});
positionChanged();
sizeChanged();
oriChanged();
}
protected void beforeDetached(Spatial parent) {
//System.out.println(this + " detached from " + parent);
position.remove(positionChange);
scale.remove(scaleChange);
ori.remove(oriChange);
aspect.remove(aspectChange);
}
public Rect move(double x, double y) {
return move(x, y, 0);
}
public Rect span(double ulX, double ulY, double brX, double brY) {
double w = Math.abs(brX - ulX);
double h = Math.abs(brY - ulY);
double cx = 0.5 * (ulX + brX);
double cy = 0.5 * (ulY + brY);
move(cx, cy);
scale(w, h);
return this;
}
protected void positionChanged() {
setTranslation(position);
}
protected void sizeChanged() {
setScale(scale.getX(), scale.getY(), getZScale());
}
protected void oriChanged() {
setRotation(ori);
}
protected void aspectChanged() {
sizeChanged();
}
public void setShape(RectShape shape) {
if (this.currentShape == shape) {
return;
}
if (shapeSpatial != null) {
detachChild(shapeSpatial);
}
switch (shape) {
case Empty:
shapeSpatial = null;
break;
case Rect:
Quad s = new com.ardor3d.scenegraph.shape.Quad("", 1, 1);
s.setModelBound(new OrientedBoundingBox());
shapeSpatial = s;
break;
case Ellipse:
Disk d = new com.ardor3d.scenegraph.shape.Disk("", 2, 10, 0.5);
d.setModelBound(new OrientedBoundingBox());
shapeSpatial = d;
break;
}
this.currentShape = shape;
if (shapeSpatial != null) {
attachChild(shapeSpatial);
}
}
public Rect move(double px, double py, double pz) {
position.set(px, py, pz);
return this;
}
public Rect scale(double sx, double sy) {
scale.set(sx, sy);
return this;
}
public Rect scale(double d) {
return scale(d,d);
}
public Rect rotate(double heading, double attitude, double bank) {
ori.set(heading, attitude, bank);
return this;
}
// public ColorSurface add(ColorSurface cs) {
// //surfaces.add(cs);
// cs.apply(this);
// return cs;
// }
@Override public V3 getPosition() {
return position;
}
@Override public V2 getSize() {
return scale;
}
protected double getZScale() {
return 1.0;
}
@Override public void removeAll() {
List<Spatial> c = new LinkedList(getChildren());
c.remove(shapeSpatial);
for (Spatial s : c) {
remove(s);
}
}
public Rect moveDZ(double dz) {
move(getPosition().getX(), getPosition().getY(), getPosition().getZ() + dz);
return this;
}
public V3 getIntersectWorld(Ray3 ray, V3 result) {
if (result == null) {
result = new V3();
}
if (!(getWorldBound() instanceof OrientedBoundingBox))
return result;
OrientedBoundingBox obb = (OrientedBoundingBox) getWorldBound();
double cx = obb.getCenter().getX();
double cy = obb.getCenter().getY();
double cz = obb.getCenter().getZ();
//X basis vector
double xx = obb.getXAxis().getX() * obb.getExtent().getX();
double xy = obb.getXAxis().getY() * obb.getExtent().getX();
double xz = obb.getXAxis().getZ() * obb.getExtent().getX();
//Y basis vector
double yx = obb.getYAxis().getX() * obb.getExtent().getY();
double yy = obb.getYAxis().getY() * obb.getExtent().getY();
double yz = obb.getYAxis().getZ() * obb.getExtent().getY();
// Vector3[] corners = new Vector3[4];
// corners[0] = new Vector3(cx + xx + yx, cy + xy + yy, cz + xz + yz );
// corners[1] = new Vector3(cx + xx - yx, cy + xy - yy, cz + xz - yz );
// corners[2] = new Vector3(cx - xx - yx, cy - xy - yy, cz - xz - yz );
// corners[3] = new Vector3(cx - xx + yx, cy - xy + yy, cz - xz + yz );
Vector3[] corners = new Vector3[3];
corners[0] = new Vector3(cx + xx + yx, cy + xy + yy, cz + xz + yz );
corners[1] = new Vector3(cx + xx - yx, cy + xy - yy, cz + xz - yz );
corners[2] = new Vector3(cx - xx + yx, cy - xy + yy, cz - xz + yz );
if (ray.intersects(corners[0], corners[1], corners[2], result, false)) {
return result;
}
return null;
}
@Override public void updateWorldTransform(boolean recurse) {
super.updateWorldTransform(recurse);
//TODO alX and alY
applyAspectXY(((Vector3)getWorldScale()), ((Vector3)getWorldTranslation()), getWorldRotation(), aspect.d(), 0, 0, vA);
}
public Rect aspect(double newAspect) {
getAspect().set(newAspect);
return this;
}
}