/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2012 Ausenco Engineering Canada Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaamsim.math;
public class Plane {
/**
* The normal direction of the plane, should always be of unit length
*/
public final Vec3d normal = new Vec3d();
/**
* The shortest distance from the plane to the origin, by normal direction (affects sign)
*/
private double _dist;
/**
* Create a plane defined by a normal, and a closest distance to the origin
* This is the storage format and similar to the common mathematical definition for a plane
* @param norm
* @param distance
*/
public Plane(Vec3d norm, double distance) {
if (norm == null) {
normal.set3(0.0d, 0.0d, 1.0d);
_dist = distance;
return;
}
this.set(norm, distance);
}
/**
* By default return the XY plane
*/
public Plane() {
normal.set3(0.0d, 0.0d, 1.0d);
_dist = 0.0d;
}
/**
* Create a plane defined by 3 points
* @param p0
* @param p1
* @param p2
*/
public Plane(Vec3d p0, Vec3d p1, Vec3d p2) {
this.set(p0, p1, p2);
}
public void set(Vec3d norm, double distance) {
normal.normalize3(norm);
_dist = distance;
}
public void set(Vec3d p0, Vec3d p1, Vec3d p2) {
Vec3d v0 = new Vec3d();
v0.sub3(p1, p0);
Vec3d v1 = new Vec3d();
v1.sub3(p2, p1);
normal.cross3(v0, v1);
normal.normalize3();
_dist = normal.dot3(p0);
}
/**
* Get the shortest distance from the plane to this point, effectively just a convenient dot product
* @param point
* @return
*/
public double getNormalDist(Vec3d point) {
double dot = point.dot3(normal);
return dot - _dist;
}
/**
* Transform plane p by the coordinate transform and store the result in 'this'
* @param t - the Transform
* @param p - the plane to transform
*/
public void transform(Transform t, Plane p) {
transform(t.getMat4dRef(), t.getMat4dRef(), p);
}
/**
* Transform plane p by the coordinate transform matrix 'mat' and store the result in 'this'
* @param mat - the Transform matrix
* @param normalMat - the normal matrix, should be the inverse transpose of 'mat' or equal to 'mat' if there is no non-uniform scaling
* @param p - the plane to transform
*/
public void transform(Mat4d mat, Mat4d normalMat, Plane p) {
Vec3d closePoint = new Vec3d();
// The point closest to the origin (need any point on the plane
closePoint.scale3(p._dist, p.normal);
// Now close point is the transformed point
closePoint.multAndTrans3(mat, closePoint);
this.normal.mult3(normalMat, p.normal);
this.normal.normalize3();
this._dist = this.normal.dot3(closePoint);
}
public boolean near(Plane p) {
return normal.near3(p.normal) && MathUtils.near(_dist, p._dist);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Plane)) return false;
Plane p = (Plane)o;
return normal.equals3(p.normal) && MathUtils.near(_dist, p._dist);
}
@Override
public int hashCode() {
assert false : "hashCode not designed";
return 42; // any arbitrary constant will do
}
/**
* Get the distance along a ray that it collides with this plane, this can return
* infinity if the ray is parallel
* @param r
* @return
*/
public double collisionDist(Ray r) {
// cos = plane-Normal dot ray-direction
double cos = -1 * normal.dot3(r.getDirRef());
if (MathUtils.near(cos, 0.0)) {
// The ray is nearly parallel to the plane, so no collision
return Double.POSITIVE_INFINITY;
}
return ( normal.dot3(r.getStartRef()) - _dist ) / cos;
}
/**
* Returns if ray 'r' collides with the back of the plane
* @param r
* @return
*/
public boolean backFaceCollision(Ray r) {
return normal.dot3(r.getDirRef()) > 0;
}
} // class Plane