//Devillers & Guigue算法-判断2个三角形是否相交
class JudgeTwoTrianglesIntersect {
constructor() { }
//主函数
run (tri1, tri2) {
//设tri1所在的平面为p1,tri2所在的平面为p2
let p1Tri2Vertex1 = this.getVector4Det(tri1.vertex_1, tri1.vertex_2, tri1.vertex_3, tri2.vertex_1)
let p1Tri2Vertex2 = this.getVector4Det(tri1.vertex_1, tri1.vertex_2, tri1.vertex_3, tri2.vertex_2)
let p1Tri2Vertex3 = this.getVector4Det(tri1.vertex_1, tri1.vertex_3, tri1.vertex_3, tri2.vertex_3)
if (p1Tri2Vertex1 > 0 && p1Tri2Vertex2 > 0 && p1Tri2Vertex3 > 0) {
return 'NONINTERSECT'
}
if (p1Tri2Vertex1 < 0 && p1Tri2Vertex2 < 0 && p1Tri2Vertex3 < 0) {
return 'NONINTERSECT'
}
if (p1Tri2Vertex1 == 0 && p1Tri2Vertex2 == 0 && p1Tri2Vertex3 == 0) {
if (this.triangleIntersertInSamePlane(tri1, tri2)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
if (p1Tri2Vertex1 == 0 && p1Tri2Vertex2 * p1Tri2Vertex3 > 0) {
if (this.isPointWithinTriangle(tri1, tri2.vertex_1)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
} else if (p1Tri2Vertex2 == 0 && p1Tri2Vertex1 * p1Tri2Vertex3 > 0) {
if (this.isPointWithinTriangle(tri1, tri2.vertex_2)) {
return 'INTERSECT'
} else {
return 'NONINTERSECT'
}
} else if (p1Tri2Vertex3 == 0 && p1Tri2Vertex1 * p1Tri2Vertex2 > 0) {
if (this.isPointWithinTriangle(tri1, tri2.vertex_3)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
let p2Tri1Vertex1 = this.getVector4Det(tri2.vertex_1, tri2.vertex_2, tri2.vertex_3, tri1.vertex_1)
let p2Tri1Vertex2 = this.getVector4Det(tri2.vertex_1, tri2.vertex_2, tri2.vertex_3, tri1.vertex_2)
let p2Tri1Vertex3 = this.getVector4Det(tri2.vertex_1, tri2.vertex_2, tri2.vertex_3, tri1.vertex_3)
if (p2Tri1Vertex1 > 0 && p2Tri1Vertex2 > 0 && p2Tri1Vertex3 > 0) {
return 'NONINTERSECT'
}
if (p2Tri1Vertex1 < 0 && p2Tri1Vertex2 < 0 && p2Tri1Vertex3 < 0) {
return 'NONINTERSECT'
}
if (p2Tri1Vertex1 == 0 && p2Tri1Vertex2 * p2Tri1Vertex3 > 0) {
if (this.isPointWithinTriangle(tri2, tri1.vertex_1)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
if (p2Tri1Vertex2 == 0 && p2Tri1Vertex1 * p2Tri1Vertex3 > 0) {
if (this.isPointWithinTriangle(tri2, tri1.vertex_2)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
if (p2Tri1Vertex3 == 0 && p2Tri1Vertex1 * p2Tri1Vertex2 > 0) {
if (this.isPointWithinTriangle(tri2, tri1.vertex_3)) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
let tri1_a = tri1.vertex_1
let tri1_b = tri1.vertex_2
let tri1_c = tri1.vertex_3
let tri2_a = tri2.vertex_1
let tri2_b = tri2.vertex_2
let tri2_c = tri2.vertex_3
let m
let im
if (p2Tri1Vertex2 * p2Tri1Vertex3 >= 0 && p2Tri1Vertex1 != 0) {
if (p2Tri1Vertex1 < 0) {
m = tri2_b
tri2_b = tri2_c
tri2_c = m
im = p1Tri2Vertex2
p1Tri2Vertex2 = p1Tri2Vertex3
p1Tri2Vertex3 = im
}
} else if (p2Tri1Vertex1 * p2Tri1Vertex3 >= 0 && p2Tri1Vertex2 != 0) {
m = tri1_a
tri1_a = tri1_b
tri1_b = tri1_c
tri1_c = m
if (p2Tri1Vertex2 < 0) {
m = tri2_b
tri2_b = tri2_c
tri2_c = m
im = p1Tri2Vertex2
p1Tri2Vertex2 = p1Tri2Vertex3
p1Tri2Vertex3 = im
}
} else if (p2Tri1Vertex1 * p2Tri1Vertex2 >= 0 && p2Tri1Vertex3 != 0) {
m = tri1_a
tri1_a = tri1_c
tri1_c = tri1_b
tri1_b = m
if (p2Tri1Vertex3 < 0) {
m = tri2_b
tri2_b = tri2_c
tri2_c = m
im = p1Tri2Vertex2
p1Tri2Vertex2 = p1Tri2Vertex3
p1Tri2Vertex3 = im
}
}
if (p1Tri2Vertex2 * p1Tri2Vertex3 >= 0 && p1Tri2Vertex1 != 0) {
if (p1Tri2Vertex1 < 0) {
m = tri1_b
tri1_b = tri1_c
tri1_c = m
}
} else if (p1Tri2Vertex1 * p1Tri2Vertex3 >= 0 && p1Tri2Vertex2 != 0) {
m = tri2_a
tri2_a = tri2_b
tri2_b = tri2_c
tri2_c = m
if (p1Tri2Vertex2 < 0) {
m = tri1_b
tri1_b = tri1_c
tri1_c = m
}
} else if (p1Tri2Vertex1 * p1Tri2Vertex2 >= 0 && p1Tri2Vertex3 != 0) {
m = tri2_a
tri2_a = tri2_c
tri2_c = tri2_b
tri2_b = m
if (p1Tri2Vertex3 < 0) {
m = tri1_b
tri1_b = tri1_c
tri1_c = m
}
}
if (this.getVector4Det(tri1_a, tri1_b, tri2_a, tri2_b) <= 0 && this.getVector4Det(tri1_a, tri1_c, tri2_c, tri2_a) <= 0) {
return 'INTERSECT'
}
else {
return 'NONINTERSECT'
}
}
//判断同一平面的直线和三角形是否相交
lineTriangleIntersertInSamePlane (tri, f1, f2) {
const p1 = {}
const p2 = {}
const p3 = {}
const p4 = {}
p1.x = f1[0]
p1.y = f1[1]
p2.x = f2[0]
p2.y = f2[1]
p3.x = tri.vertex_1[0]
p3.y = tri.vertex_1[1]
p4.x = tri.vertex_2[0]
p4.y = tri.vertex_2[1]
if (this.segmentsIntersert(p1, p2, p3, p4)) {
return true
}
p3.x = tri.vertex_2[0]
p3.y = tri.vertex_2[1]
p4.x = tri.vertex_3[0]
p4.y = tri.vertex_3[1]
if (this.segmentsIntersert(p1, p2, p3, p4)) {
return true
}
p3.x = tri.vertex_1[0]
p3.y = tri.vertex_1[1]
p4.x = tri.vertex_3[0]
p4.y = tri.vertex_3[1]
if (this.segmentsIntersert(p1, p2, p3, p4)) {
return true
}
return false
}
//判断线段p1p2与线段p3p4是否相交
segmentsIntersert (p1, p2, p3, p4) {
const d1 = this.direction(p3, p4, p1)
const d2 = this.direction(p3, p4, p2)
const d3 = this.direction(p1, p2, p3)
const d4 = this.direction(p1, p2, p4)
if (d1 * d2 < 0 && d3 * d4 < 0) {
return 1
}
else if (d1 == 0 && this.onSegment(p3, p4, p1) == 1) {
return 1
}
else if (d2 == 0 && this.onSegment(p3, p4, p2) == 1) {
return 1
}
else if (d3 == 0 && this.onSegment(p1, p2, p3) == 1) {
return 1
}
else if (d4 == 0 && this.onSegment(p1, p2, p4) == 1) {
return 1
}
return 0
}
//确定与线段p1p2共线的点p是否在线段p1p2上
onSegment (p1, p2, p) {
const max = p1.x > p2.x ? p1.x : p2.x
const min = p1.x < p2.x ? p1.x : p2.x
const max1 = p1.y > p2.y ? p1.y : p2.y
const min1 = p1.y < p2.y ? p1.y : p2.y
if (p.x >= min && p.x <= max && p.y >= min1 && p.y <= max1) {
return 1
}
else {
return 0
}
}
//利用叉积计算点p相对线段p1p2的方位
direction (p1, p2, p) {
return (p.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p.y - p1.y)
}
//判断同一平面内的三角形是否相交
triangleIntersertInSamePlane (tri1, tri2) {
if (this.lineTriangleIntersertInSamePlane(tri2, tri1.vertex_1, tri1.vertex_2)) {
return true;
}
else if (this.lineTriangleIntersertInSamePlane(tri2, tri1.vertex_2, tri1.vertex_3)) {
return true;
}
else if (this.lineTriangleIntersertInSamePlane(tri2, tri1.vertex_1, tri1.vertex_3)) {
return true;
}
else {
const centralPoint1 = this.getCentralPoint(tri1)
const centralPoint2 = this.getCentralPoint(tri2)
if (this.isPointWithinTriangle(tri2, centralPoint1) || this.isPointWithinTriangle(tri1, centralPoint2)) {
return true;
}
return false;
}
}
//重心法判断点是否在三角形内部
isPointWithinTriangle (tri, point) {
const v0 = this.getVectorDiff(tri.vertex_1, tri.vertex_3)
const v1 = this.getVectorDiff(tri.vertex_1, tri.vertex_2)
const v2 = this.getVectorDiff(tri.vertex_1, point)
const dot00 = this.Dot(v0, v0)
const dot01 = this.Dot(v0, v1)
const dot02 = this.Dot(v0, v2)
const dot11 = this.Dot(v1, v1)
const dot12 = this.Dot(v1, v2)
const inverDeno = 1 / (dot00 * dot11 - dot01 * dot01)
const u = (dot11 * dot02 - dot01 * dot12) * inverDeno
if (u < 0 || u > 1) {
return false
}
const v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
if (v < 0 || v > 1) {
return false
}
return u + v <= 1
}
//向量内积
Dot (v1, v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
}
//向量之差
getVectorDiff (a, b) {
const aimV = []
aimV.push(b[0] - a[0])
aimV.push(b[1] - a[1])
aimV.push(b[2] - a[2])
return aimV
}
//获取三角形的中心点
getCentralPoint (tri) {
const centralPoint = []
centralPoint.push((tri.vertex_1[0] + tri.vertex_2[0] + tri.vertex_3[0]) / 3)
centralPoint.push((tri.vertex_1[1] + tri.vertex_2[1] + tri.vertex_3[1]) / 3)
centralPoint.push((tri.vertex_1[2] + tri.vertex_2[2] + tri.vertex_3[2]) / 3)
return centralPoint
}
//四点行列式
getVector4Det (v1, v2, v3, v4) {
let a = [[], [], []]
for (let i = 0; i < 3; i++) {
a[0].push(v1[i] - v4[i])
a[1].push(v2[i] - v4[i])
a[2].push(v3[i] - v4[i])
}
return a[0][0] * a[1][1] * a[2][2]
+ a[0][1] * a[1][2] * a[2][0]
+ a[0][2] * a[1][0] * a[2][1]
- a[0][2] * a[1][1] * a[2][0]
- a[0][1] * a[1][0] * a[2][2]
- a[0][0] * a[1][2] * a[2][1]
}
}
exports.JudgeTwoTrianglesIntersect = JudgeTwoTrianglesIntersect
调用方法:
const triA = {
vertex_1: [ -25.18, -6.06, 205.79 ],
vertex_2: [ -25.18, -6.07, 205.79 ],
vertex_3: [ -25.17, -6.07, 205.79 ]
}
const triB = {
vertex_1: [ -25.17, -6.06, 205.79 ],
vertex_2: [ -25.17, -6.05, 205.79 ],
vertex_3: [ -25.18, -6.05, 205.79 ]
}
const intersectSt = new JudgeTwoTrianglesIntersect()
const res = intersectSt.run(triA, triB)
console.log(res)
参考:
[1] https://www.cnblogs.com/lyggqm/p/5977129.html
[2] 《快速空间三角形对相交检测算法》邹益胜