package com.vitco.util.graphic;
import com.threed.jpct.SimpleVector;
/**
* Helper class to perform 3D calculation tasks
*/
public final class Util3D {
public static SimpleVector nearestPoint(SimpleVector[] line, SimpleVector point) {
SimpleVector a = new SimpleVector(line[0]);
a.sub(point);
SimpleVector b = new SimpleVector(line[1]);
b.sub(line[0]);
float top = a.calcDot(b);
double t = - top / Math.pow(line[1].distance(line[0]),2.0);
return new SimpleVector(
line[0].x + (line[1].x - line[0].x) * t,
line[0].y + (line[1].y - line[0].y) * t,
line[0].z + (line[1].z - line[0].z) * t
);
}
public static SimpleVector[] nearestLinePoints(SimpleVector[] line1, SimpleVector[] line2) {
SimpleVector d21 = new SimpleVector(line1[0]);
d21.sub(line1[1]); // 3 sub x 3
SimpleVector d34 = new SimpleVector(line2[1]);
d34.sub(line2[0]);
SimpleVector d13 = new SimpleVector(line2[0]);
d13.sub(line1[0]);
// m * u = x
float a = d21.calcDot(d21); // (3 mul + 3 add ) x 5
float b = d21.calcDot(d34);
float c = d34.calcDot(d34);
float d = -d13.calcDot(d21);
float e = -d13.calcDot(d34);
// Solve for u1 & u2
float[] u = new float[2];
u[0] = (d*c-e*b)/(c*a-b*b); // 4 mul, 2 sub, 1 div
u[1] = (e - b * u[0]) / c; // 1 mul, 1 sub, 1 div
return new SimpleVector[] {
new SimpleVector(
line1[0].x + (line1[1].x - line1[0].x) * u[0],
line1[0].y + (line1[1].y - line1[0].y) * u[0],
line1[0].z + (line1[1].z - line1[0].z) * u[0]
),
new SimpleVector(
line2[0].x + (line2[1].x - line2[0].x) * u[1],
line2[0].y + (line2[1].y - line2[0].y) * u[1],
line2[0].z + (line2[1].z - line2[0].z) * u[1]
)
};
}
// test if a ray intersects a triangle (single sided parameter indicates
// whether only testing from the front should be performed)
// Note: This assumes that the direction is normalized (!)
// returns null if no hit is detected, otherwise the hit position is returned
public static SimpleVector rayTriangleIntersects(
SimpleVector v0, SimpleVector v1, SimpleVector v2,
SimpleVector origin, SimpleVector dir,
boolean isSingledSided
) {
assert Math.abs(1 - dir.length()) < 0.0001;
SimpleVector v0v1 = v1.calcSub(v0);
SimpleVector v0v2 = v2.calcSub(v0);
SimpleVector N = v0v1.calcCross(v0v2);
float nDotRay = N.calcDot(dir);
// ray parallel to triangle or hit from the back
if (nDotRay == 0 || (isSingledSided && nDotRay > 0)) return null;
float d = N.calcDot(v0);
float t = -(N.calcDot(origin) + d) / nDotRay;
if (t < 0) return null; // ray behind triangle
// inside-out test
SimpleVector dist = new SimpleVector(dir);
dist.scalarMul(t);
SimpleVector pos = origin.calcAdd(dist);
// inside-out test edge0
SimpleVector v0p = pos.calcSub(v0);
float v = N.calcDot(v0v1.calcCross(v0p));
if (v < 0) return null; // P outside triangle
// inside-out test edge1
SimpleVector v1p = pos.calcSub(v1);
SimpleVector v1v2 = v2.calcSub(v1);
float w = N.calcDot(v1v2.calcCross(v1p));
if (w < 0) return null; // P outside triangle
// inside-out test edge2
SimpleVector v2p = pos.calcSub(v2);
SimpleVector v2v0 = v0.calcSub(v2);
float u = N.calcDot(v2v0.calcCross(v2p));
if (u < 0) return null; // P outside triangle
// Note: t contains the distance
return pos;
}
}