package edu.berkeley.qfat.geom;
import javax.media.opengl.*;
-public class Plane {
+// FEATURE: represent a plane by the matrix that projects points onto that plane?
+public class Plane implements AffineConstraint {
- // FIXME: could be given by
// ax+by+cz=d
+ public final float a, b, c, d;
+ public final Point p;
- public final Vec norm;
- public final float dvalue;
+ public Vec norm() { return new Vec(a, b, c).norm(); }
public Plane(Point p, Vec norm) {
- this.norm = norm.norm();
- this.dvalue = p.x*this.norm.x+p.y*this.norm.y+p.z*this.norm.z;
+ norm = norm.norm();
+ this.a = norm.x;
+ this.b = norm.y;
+ this.c = norm.z;
+ this.d = p.x*norm.x+p.y*norm.y+p.z*norm.z;
+ this.p = p;
+ }
+
+ public Plane(float a, float b, float c, float d) {
+ // FIXME, what if c==0?
+ this(a, b, c, d, new Point(0, 0, d/c));
+ }
+
+ /** provided at least one of a,b,c is nonzero, return the Plane representing ax+by+cz=d */
+ public Plane(float a, float b, float c, float d, Point p) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.p = p;
}
public Point intersect(Plane p1, Plane p2) {
+ Vec norm = norm();
Plane p3 = this;
- float z = p1.norm.dot(p2.norm.cross(p3.norm));
+ float z = p1.norm().dot(p2.norm().cross(p3.norm()));
if (Math.abs(z) < 0.0001) return null; // planes do not intersect at a point
- Vec v1 = p2.norm.cross(p3.norm).times(-1 * p1.dvalue);
- Vec v2 = p3.norm.cross(p1.norm).times(-1 * p2.dvalue);
- Vec v3 = p1.norm.cross(p2.norm).times(-1 * p3.dvalue);
+ Vec v1 = p2.norm().cross(p3.norm()).times(-1 * p1.d);
+ Vec v2 = p3.norm().cross(p1.norm()).times(-1 * p2.d);
+ Vec v3 = p1.norm().cross(p2.norm()).times(-1 * p3.d);
return Point.ZERO.plus(v1.plus(v2).plus(v3).times(1/z));
}
+ public AffineConstraint intersect(AffineConstraint c, float epsilon) {
+ if (c instanceof Plane) {
+ Plane p = (Plane)c;
+
+ // same plane
+ if (Math.abs(p.a*this.d-this.a*p.d) <= epsilon &&
+ Math.abs(p.b*this.d-this.b*p.d) <= epsilon &&
+ Math.abs(p.c*this.d-this.c*p.d) <= epsilon &&
+ Math.abs(p.d*this.d-this.d*p.d) <= epsilon)
+ return this;
+
+ // parallel planes
+ if (Math.abs(p.norm().cross(norm()).mag()) <= epsilon)
+ return AffineConstraint.NONE;
+
+ Vec u = norm().cross(p.norm());
+ Point point = null;
+ if (Math.abs(u.z) >= Math.abs(u.y) && Math.abs(u.z) >= Math.abs(u.y)) {
+ point = new Point( (this.b*p.d - p.b*this.d)/(this.a*p.b - p.a*this.b),
+ (this.d*p.a - p.d*this.a)/(this.a*p.b - p.a*this.b),
+ 0);
+ } else if (Math.abs(u.y) >= Math.abs(u.z) && Math.abs(u.y) >= Math.abs(u.x)) {
+ point = new Point( (this.c*p.d - p.c*this.d)/(this.a*p.c - p.a*this.c),
+ 0,
+ (this.d*p.a - p.d*this.a)/(this.a*p.c - p.a*this.c));
+ } else {
+ point = new Point( 0,
+ (this.c*p.d - p.c*this.d)/(this.b*p.c - p.b*this.c),
+ (this.d*p.b - p.d*this.b)/(this.b*p.c - p.b*this.c));
+ }
+
+ return new Line(point, u);
+
+ } else if (c instanceof Line) {
+ Line l = (Line)c;
+ if (Math.abs(a + b*l.m + this.c*l.n) <= epsilon &&
+ Math.abs(b * l.c + this.c*l.d + d) <= epsilon)
+ return l;
+
+ // FIXME: parallel case
+
+ float x = (d - b*l.c - this.c*l.d) / (a + b*l.m + this.c*l.n);
+ float y = l.m*x+l.c;
+ float z = l.n*x+l.d;
+ return new Point(x,y,z);
+ //throw new RuntimeException("not yet implemented");
+
+ } else
+ return c.intersect(this, epsilon);
+ }
+
+ public AffineConstraint multiply(Matrix m) {
+ return new Plane( m.times(p), m.times(norm()).norm() );
+ }
+
+ public Point getProjection(Point p) {
+ Point ret = norm().times(p.minus(this.p).dot(norm())).times(-1).plus(p);
+ return ret;
+ }
+ public String toString() {
+ return "[plane "+a+"x+"+b+"y+"+c+"z="+d+"]";
+ }
}