0, 0, 0, 1);
}
+ /** a reflection matrix across the plane passing through the origin with the specified normal */
public static Matrix reflect(Vec v) {
Vec reflectionPlaneNormal = v.norm();
float a = reflectionPlaneNormal.x;
0, 0, 0, 1);
}
- public Vec getTranslationalComponent() {
- return new Vec(d, h, l);
- }
+ /** returns the translational component of this matrix */
+ public Vec getTranslationalComponent() { return this.times(Point.ZERO).minus(Point.ZERO); }
public Matrix plus(Matrix x) {
return new Matrix(a+x.a, b+x.b, c+x.c, d+x.d, e+x.e, f+x.f, g+x.g, h+x.h, i+x.i, j+x.j, k+x.k, l+x.l, m+x.m, n+x.n, o+x.o, p+x.p);
return ret;
}
- /** discards bottom row */
public Point times(Point p) {
- // discards bottom row
double x = a*p.x + b*p.y + c*p.z + d;
double y = e*p.x + f*p.y + g*p.z + h;
double z = i*p.x + j*p.y + k*p.z + l;
return new Point(x/q, y/q, z/q);
}
- /** discards bottom row */
public Vec times(Vec p) {
- return new Vec(a*p.x + b*p.y + c*p.z + d,
- e*p.x + f*p.y + g*p.z + h,
- i*p.x + j*p.y + k*p.z + l);
- }
-
- public Matrix preMultiplyTranslationalComponentBy(Matrix mm) {
- Vec v = mm.times(getTranslationalComponent());
- return new Matrix(a, b, c, v.x,
- e, f, g, v.y,
- i, j, k, v.z,
- m, n, o, 1);
+ return this.times(Matrix.translate(p)).getTranslationalComponent();
}
/** multiply by another matrix */
if (!(oo instanceof Matrix)) return false;
Matrix z = (Matrix)oo;
return
- near(a,z.a) &&
- near(b,z.b) &&
- near(c,z.c) &&
- near(d,z.d) &&
- near(e,z.e) &&
- near(f,z.f) &&
- near(g,z.g) &&
- near(h,z.h) &&
- near(i,z.i) &&
- near(j,z.j) &&
- near(k,z.k) &&
- near(l,z.l) &&
- near(m,z.m) &&
- near(n,z.n) &&
- near(o,z.o) &&
- near(p,z.p);
+ (a==z.a) &&
+ (b==z.b) &&
+ (c==z.c) &&
+ (d==z.d) &&
+ (e==z.e) &&
+ (f==z.f) &&
+ (g==z.g) &&
+ (h==z.h) &&
+ (i==z.i) &&
+ (j==z.j) &&
+ (k==z.k) &&
+ (l==z.l) &&
+ (m==z.m) &&
+ (n==z.n) &&
+ (o==z.o) &&
+ (p==z.p);
+ }
+
+ public boolean equalsModuloEpsilon(Matrix z, float epsilon) {
+ return
+ Math.abs(a-z.a)<epsilon &&
+ Math.abs(b-z.b)<epsilon &&
+ Math.abs(c-z.c)<epsilon &&
+ Math.abs(d-z.d)<epsilon &&
+ Math.abs(e-z.e)<epsilon &&
+ Math.abs(f-z.f)<epsilon &&
+ Math.abs(g-z.g)<epsilon &&
+ Math.abs(h-z.h)<epsilon &&
+ Math.abs(i-z.i)<epsilon &&
+ Math.abs(j-z.j)<epsilon &&
+ Math.abs(k-z.k)<epsilon &&
+ Math.abs(l-z.l)<epsilon &&
+ Math.abs(m-z.m)<epsilon &&
+ Math.abs(n-z.n)<epsilon &&
+ Math.abs(o-z.o)<epsilon &&
+ Math.abs(p-z.p)<epsilon;
}
- private static final float EPSILON = 0.001f;
- private static boolean near(float a, float b) { return Math.abs(a-b)<EPSILON; }
public int hashCode() {
return
Float.floatToIntBits(p);
}
+ /** retrieves the current objectspace-to-windowspace projection matrix from the GL context */
public static Matrix getProjectionMatrix(GL gl) {
int view[] = new int[4];
double mvmatrix[] = new double[16];
return z.times(p).times(m);
}
+ /** returns the constraint-conjunction "(forall v)Mv=v" */
+ public AffineConstraint getAffineConstraint(float epsilon) {
+ AffineConstraint c1 = getAffineConstraint(a-1, b, c, d , epsilon);
+ AffineConstraint c2 = getAffineConstraint(e, f-1, g, h , epsilon);
+ AffineConstraint c3 = getAffineConstraint(i, j, k-1, l , epsilon);
+ // FIXME: bottom row constraint?
+ return c1.intersect(c2.intersect(c3, epsilon), epsilon);
+ }
+
+ /** the AffineConstraint representing ax+by+cz+d=0 */
+ private static AffineConstraint getAffineConstraint(float a, float b, float c, float d, float epsilon) {
+ a = Math.abs(a) <= epsilon ? 0 : a;
+ b = Math.abs(b) <= epsilon ? 0 : b;
+ c = Math.abs(c) <= epsilon ? 0 : c;
+ d = Math.abs(d) <= epsilon ? 0 : d;
+ if (a!=0 || b!=0 || c!=0) return new Plane(a, b, c, d);
+ if (d==0) return AffineConstraint.ALL;
+ return AffineConstraint.NONE;
+ }
}