@jgphilpott/polytree 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -10
- package/{polytree.js → polytree.bundle.js} +672 -3
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgphilpott/polytree",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "A Constructive Solid Geometry (CSG) library using Octree data structure.",
|
|
5
5
|
"funding": "https://github.com/sponsors/jgphilpott",
|
|
6
|
-
"main": "polytree.js",
|
|
6
|
+
"main": "polytree.bundle.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"require": "./polytree.js"
|
|
9
|
+
"require": "./polytree.bundle.js"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"polytree.js",
|
|
14
|
-
"triangle.intersection.js",
|
|
13
|
+
"polytree.bundle.js",
|
|
15
14
|
"README.md",
|
|
16
15
|
"LICENSE"
|
|
17
16
|
],
|
|
@@ -23,7 +22,7 @@
|
|
|
23
22
|
"pretest": "npm run compile",
|
|
24
23
|
"compile": "coffee -cb .",
|
|
25
24
|
"compile:watch": "coffee -cbw . &",
|
|
26
|
-
"build": "npm run compile &&
|
|
25
|
+
"build": "npm run compile && cat app/polytree.js app/triangle.intersection.js > polytree.bundle.js",
|
|
27
26
|
"prepare": "npm run build",
|
|
28
27
|
"prepublishOnly": "npm run build"
|
|
29
28
|
},
|
|
@@ -31,7 +30,7 @@
|
|
|
31
30
|
"type": "git",
|
|
32
31
|
"url": "https://github.com/jgphilpott/polytree"
|
|
33
32
|
},
|
|
34
|
-
"keywords": ["
|
|
33
|
+
"keywords": ["Polytree","Octree","CSG","BVH"],
|
|
35
34
|
"author": { "name": "Jacob Philpott", "email": "jacob.philpott@gmx.com" },
|
|
36
35
|
"license": "MIT",
|
|
37
36
|
"bugs": { "url": "https://github.com/jgphilpott/polytree/issues" },
|
|
@@ -40,8 +39,7 @@
|
|
|
40
39
|
"coffeescript": "^2.7.0",
|
|
41
40
|
"jest": "^30.1.3"
|
|
42
41
|
},
|
|
43
|
-
"
|
|
42
|
+
"dependencies": {
|
|
44
43
|
"three": "^0.180.0"
|
|
45
|
-
}
|
|
46
|
-
"dependencies": {}
|
|
44
|
+
}
|
|
47
45
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
// Generated by CoffeeScript 2.7.0
|
|
2
|
-
var BACK, Box3, BufferAttribute, BufferGeometry, COPLANAR, CSG_Rules, DoubleSide, EPSILON, FRONT, Matrix3, Mesh, OctreeCSG, Plane, Polygon, RAY_EPSILON, Ray, Raycaster, SPANNING, Triangle, Vector2, Vector3, Vertex, _asyncUnionArrayID, _asyncUnionID, _box3$1, _matrix3, _normal1, _polygonID, _ray, _rayDirection, _raycaster1, _v1, _v2, _wP, _wP_EPS_ARR, _wP_EPS_ARR_COUNT, _wV1, _wV2, _wV3, calcWindingNumber_buffer, disposeOctree, edge1, edge2, h, handleIntersectingOctrees, handleObjectForOp, handleObjectForOp_async, isUniqueTriangle, isValidTriangle, nbuf2, nbuf3, pointRounding, polyInside_WindingNumber_buffer, prepareTriangleBuffer, q, rayIntersectsTriangle, raycastIntersectAscSort, returnXYZ, s, splitPolygonArr, splitPolygonByPlane, tmpm3,
|
|
2
|
+
var BACK, Box3, BufferAttribute, BufferGeometry, COPLANAR, CSG_Rules, DoubleSide, EPSILON, FRONT, Matrix3, Mesh, OctreeCSG, Plane, Polygon, RAY_EPSILON, Ray, Raycaster, SPANNING, Triangle, Vector2, Vector3, Vertex, _asyncUnionArrayID, _asyncUnionID, _box3$1, _matrix3, _normal1, _polygonID, _ray, _rayDirection, _raycaster1, _v1, _v2, _wP, _wP_EPS_ARR, _wP_EPS_ARR_COUNT, _wV1, _wV2, _wV3, calcWindingNumber_buffer, disposeOctree, edge1, edge2, h, handleIntersectingOctrees, handleObjectForOp, handleObjectForOp_async, isUniqueTriangle, isValidTriangle, nbuf2, nbuf3, pointRounding, polyInside_WindingNumber_buffer, prepareTriangleBuffer, q, rayIntersectsTriangle, raycastIntersectAscSort, returnXYZ, s, splitPolygonArr, splitPolygonByPlane, tmpm3, ttvv0, tv0, tv1, wNPI;
|
|
3
3
|
|
|
4
4
|
({Vector2, Vector3, Box3, DoubleSide, Matrix3, Ray, Triangle, BufferGeometry, BufferAttribute, Mesh, Raycaster} = require("three"));
|
|
5
5
|
|
|
6
|
-
({triangleIntersectsTriangle} = require("./app/triangle.intersection.js"));
|
|
7
|
-
|
|
8
6
|
_v1 = new Vector3();
|
|
9
7
|
|
|
10
8
|
_v2 = new Vector3();
|
|
@@ -2936,3 +2934,674 @@ module.exports = {
|
|
|
2936
2934
|
Vertex: Vertex,
|
|
2937
2935
|
rayIntersectsTriangle: rayIntersectsTriangle
|
|
2938
2936
|
};
|
|
2937
|
+
// Generated by CoffeeScript 2.7.0
|
|
2938
|
+
|
|
2939
|
+
/* Determines the intersection segment (if any) between two triangles in 3D space.
|
|
2940
|
+
If an intersection segment exists, its endpoints are written to `additions.source` and `additions.target`.
|
|
2941
|
+
|
|
2942
|
+
@param {Vector3} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
2943
|
+
@param {Vector3} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
2944
|
+
|
|
2945
|
+
@param {Object} additions - Data object used for storing extra intersection info:
|
|
2946
|
+
|
|
2947
|
+
- coplanar {Boolean} whether the triangles lie in the same plane.
|
|
2948
|
+
- source {Vector3} intersection segment start (if applicable).
|
|
2949
|
+
- target {Vector3} intersection segment end (if applicable).
|
|
2950
|
+
- normal1 {Vector3} normal of Triangle A (used in coplanar case).
|
|
2951
|
+
- normal2 {Vector3} normal of Triangle B (used in coplanar case).
|
|
2952
|
+
|
|
2953
|
+
@return {Boolean} True if intersection segment exists, false otherwise. */
|
|
2954
|
+
/* Checks for edge intersection between two triangles in 2D.
|
|
2955
|
+
|
|
2956
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
2957
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
2958
|
+
|
|
2959
|
+
@return {Boolean} True if an edge intersection is found, false otherwise. */
|
|
2960
|
+
/* Checks for vertex intersection between two triangles in 2D.
|
|
2961
|
+
|
|
2962
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
2963
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
2964
|
+
|
|
2965
|
+
@return {Boolean} True if a vertex intersection is found, false otherwise. */
|
|
2966
|
+
/* Resolves intersection between two coplanar triangles in 3D space.
|
|
2967
|
+
Since the triangles lie in the same plane, the problem is reduced from 3D to 2D.
|
|
2968
|
+
By projecting both triangles onto the axis-aligned plane (XY, YZ, or XZ) that maximizes the projected area.
|
|
2969
|
+
This minimizes numerical errors when working in 2D. The function then delegates the overlap test to `trianglesOverlap2D`.
|
|
2970
|
+
|
|
2971
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
2972
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
2973
|
+
|
|
2974
|
+
@param {Vector3} normalTriangleA - Normal vector of Triangle A.
|
|
2975
|
+
@param {Vector3} normalTriangleB - Normal vector of Triangle B.
|
|
2976
|
+
|
|
2977
|
+
@returns {Boolean} - True if the coplanar triangles overlap in 2D, false otherwise. */
|
|
2978
|
+
/* Determines the intersection between two 3D triangles given their vertices and the signed distances of Triangle B’s vertices to the plane of Triangle A.
|
|
2979
|
+
Goal: Always pass to `constructIntersection` the triangles arranged so the first vertex of each lies alone on one side of the other triangle’s plane (or is on the plane), and the remaining two share the opposite side.
|
|
2980
|
+
This function chooses one of several vertex orderings based on the sign pattern of (distanceVertex1B, distanceVertex2B, distanceVertex3B).
|
|
2981
|
+
If all three distances for Triangle B are zero → triangles are coplanar and handled by `resolveCoplanarTriangleIntersection`.
|
|
2982
|
+
|
|
2983
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
2984
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
2985
|
+
|
|
2986
|
+
@param {Number} distanceVertex1B - Signed distance of vertex1TriangleB to Triangle A’s plane.
|
|
2987
|
+
@param {Number} distanceVertex2B - Signed distance of vertex2TriangleB to Triangle A’s plane.
|
|
2988
|
+
@param {Number} distanceVertex3B - Signed distance of vertex3TriangleB to Triangle A’s plane.
|
|
2989
|
+
|
|
2990
|
+
@param {Object} additions - Data object used for storing extra intersection info:
|
|
2991
|
+
|
|
2992
|
+
- coplanar {Boolean} whether the triangles lie in the same plane.
|
|
2993
|
+
- source {Vector3} intersection segment start (if applicable).
|
|
2994
|
+
- target {Vector3} intersection segment end (if applicable).
|
|
2995
|
+
- normal1 {Vector3} normal of Triangle A (used in coplanar case).
|
|
2996
|
+
- normal2 {Vector3} normal of Triangle B (used in coplanar case).
|
|
2997
|
+
|
|
2998
|
+
@returns {Boolean} - True if an intersection is found, false otherwise. */
|
|
2999
|
+
/* Determines if two counter-clockwise (CCW) triangles in 2D overlap.
|
|
3000
|
+
The function checks the relative orientation of triangle B's vertices with respect to triangle A.
|
|
3001
|
+
Then recursively tests for edge or vertex intersection depending on the configuration.
|
|
3002
|
+
|
|
3003
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A (CCW order)
|
|
3004
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B (CCW order)
|
|
3005
|
+
|
|
3006
|
+
@return {Boolean} True if triangles overlap, false otherwise. */
|
|
3007
|
+
/* Checks whether two triangles in 3D space intersect.
|
|
3008
|
+
|
|
3009
|
+
@param {Object} triangleA - First triangle, with properties {a, b, c} (Vector3 vertices).
|
|
3010
|
+
@param {Object} triangleB - Second triangle, with properties {a, b, c} (Vector3 vertices).
|
|
3011
|
+
|
|
3012
|
+
@param {Object} additions - Optional data object used for storing extra intersection info:
|
|
3013
|
+
|
|
3014
|
+
- coplanar {Boolean} whether the triangles lie in the same plane.
|
|
3015
|
+
- source {Vector3} intersection segment start (if applicable).
|
|
3016
|
+
- target {Vector3} intersection segment end (if applicable).
|
|
3017
|
+
|
|
3018
|
+
@returns {Boolean} - True if the triangles intersect, false otherwise. */
|
|
3019
|
+
/* Computes the orientation (signed area) of a 2D triangle defined by three vertices.
|
|
3020
|
+
The result indicates whether the points are arranged clockwise (CW), counter-clockwise (CCW), or collinear.
|
|
3021
|
+
|
|
3022
|
+
Note: This returns the raw signed area (twice the triangle area), without applying an epsilon threshold.
|
|
3023
|
+
Callers should compare against a small EPS (e.g., EPS2D) when classifying near-collinear inputs.
|
|
3024
|
+
|
|
3025
|
+
Formula: orientation(a, b, c) = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x)
|
|
3026
|
+
|
|
3027
|
+
- If result > 0 → counter-clockwise (CCW).
|
|
3028
|
+
- If result < 0 → clockwise (CW).
|
|
3029
|
+
- If result = 0 → points are collinear.
|
|
3030
|
+
|
|
3031
|
+
@param {Vector2} a - First vertex.
|
|
3032
|
+
@param {Vector2} b - Second vertex.
|
|
3033
|
+
@param {Vector2} c - Third vertex.
|
|
3034
|
+
|
|
3035
|
+
@returns {Number} - Positive if CCW, negative if CW, zero if collinear. */
|
|
3036
|
+
/* Determines whether two triangles in 2D overlap.
|
|
3037
|
+
|
|
3038
|
+
Behavior and notes:
|
|
3039
|
+
|
|
3040
|
+
- Orientation: Triangles may be CW or CCW; inputs are normalized to CCW before testing.
|
|
3041
|
+
- Inclusivity: Overlap is inclusive of shared edges and shared vertices.
|
|
3042
|
+
- Degenerate handling:
|
|
3043
|
+
|
|
3044
|
+
- If one triangle degenerates to a point, returns whether that point lies in (or on) the other triangle.
|
|
3045
|
+
- If both degenerate to points, returns true only if the points coincide within EPS2D.
|
|
3046
|
+
- Degenerate line triangles are handled by the main CCW intersection routine and by point/segment checks where applicable.
|
|
3047
|
+
|
|
3048
|
+
@param {Vector2} vertex1TriangleA, vertex2TriangleA, vertex3TriangleA - Vertices of triangle A
|
|
3049
|
+
@param {Vector2} vertex1TriangleB, vertex2TriangleB, vertex3TriangleB - Vertices of triangle B
|
|
3050
|
+
|
|
3051
|
+
@returns {Boolean} - True if the triangles overlap in 2D, false otherwise. */
|
|
3052
|
+
var EPS2D, constructIntersection, intersectionTestEdge2D, intersectionTestVertex2D, pointInTriangleInclusive2D, pointOnSegmentInclusive2D, pointsEqual2D, resolveCoplanarTriangleIntersection, resolveTriangleIntersection, tempVector1, tempVector2, tempVector3, triangleIntersectionCCW2D, triangleIntersectsTriangle, triangleOrientation2D, trianglesOverlap2D;
|
|
3053
|
+
|
|
3054
|
+
EPS2D = 1e-10;
|
|
3055
|
+
|
|
3056
|
+
tempVector1 = new Vector3();
|
|
3057
|
+
|
|
3058
|
+
tempVector2 = new Vector3();
|
|
3059
|
+
|
|
3060
|
+
tempVector3 = new Vector3();
|
|
3061
|
+
|
|
3062
|
+
// Epsilon-aware 2D point equality.
|
|
3063
|
+
pointsEqual2D = function(p, q, eps = EPS2D) {
|
|
3064
|
+
return Math.abs(p.x - q.x) <= eps && Math.abs(p.y - q.y) <= eps;
|
|
3065
|
+
};
|
|
3066
|
+
|
|
3067
|
+
// Inclusive point-on-segment check for collinear points.
|
|
3068
|
+
pointOnSegmentInclusive2D = function(p, a, b, eps = EPS2D) {
|
|
3069
|
+
var maxX, maxY, minX, minY;
|
|
3070
|
+
if (pointsEqual2D(a, b, eps)) {
|
|
3071
|
+
return pointsEqual2D(p, a, eps) || pointsEqual2D(p, b, eps);
|
|
3072
|
+
}
|
|
3073
|
+
if (Math.abs(triangleOrientation2D(p, a, b)) > eps) {
|
|
3074
|
+
return false;
|
|
3075
|
+
}
|
|
3076
|
+
minX = Math.min(a.x, b.x) - eps;
|
|
3077
|
+
maxX = Math.max(a.x, b.x) + eps;
|
|
3078
|
+
minY = Math.min(a.y, b.y) - eps;
|
|
3079
|
+
maxY = Math.max(a.y, b.y) + eps;
|
|
3080
|
+
return p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY;
|
|
3081
|
+
};
|
|
3082
|
+
|
|
3083
|
+
// Inclusive point-in-triangle test using orientations.
|
|
3084
|
+
// - Works for CW or CCW input (auto-detects orientation).
|
|
3085
|
+
// - Inclusive of edges/vertices.
|
|
3086
|
+
// - Handles degenerate triangles (point or segment) robustly.
|
|
3087
|
+
pointInTriangleInclusive2D = function(p, a, b, c, eps = EPS2D) {
|
|
3088
|
+
var o, s1, s2, s3;
|
|
3089
|
+
o = triangleOrientation2D(a, b, c);
|
|
3090
|
+
if (o > eps) {
|
|
3091
|
+
s1 = triangleOrientation2D(p, a, b);
|
|
3092
|
+
s2 = triangleOrientation2D(p, b, c);
|
|
3093
|
+
s3 = triangleOrientation2D(p, c, a);
|
|
3094
|
+
return (s1 >= -eps) && (s2 >= -eps) && (s3 >= -eps);
|
|
3095
|
+
} else if (o < -eps) {
|
|
3096
|
+
s1 = triangleOrientation2D(p, a, b);
|
|
3097
|
+
s2 = triangleOrientation2D(p, b, c);
|
|
3098
|
+
s3 = triangleOrientation2D(p, c, a);
|
|
3099
|
+
return (s1 <= eps) && (s2 <= eps) && (s3 <= eps);
|
|
3100
|
+
} else {
|
|
3101
|
+
// Degenerate triangle: either a point (all equal) or a segment (collinear).
|
|
3102
|
+
if (pointsEqual2D(a, b, eps) && pointsEqual2D(b, c, eps)) {
|
|
3103
|
+
return pointsEqual2D(p, a, eps);
|
|
3104
|
+
}
|
|
3105
|
+
// Reduce to the non-degenerate segment and test inclusively.
|
|
3106
|
+
if (pointsEqual2D(a, b, eps)) {
|
|
3107
|
+
return pointOnSegmentInclusive2D(p, b, c, eps);
|
|
3108
|
+
}
|
|
3109
|
+
if (pointsEqual2D(b, c, eps)) {
|
|
3110
|
+
return pointOnSegmentInclusive2D(p, a, b, eps);
|
|
3111
|
+
}
|
|
3112
|
+
if (pointsEqual2D(c, a, eps)) {
|
|
3113
|
+
return pointOnSegmentInclusive2D(p, a, b, eps);
|
|
3114
|
+
}
|
|
3115
|
+
// All three distinct but collinear: test against hull segments.
|
|
3116
|
+
return pointOnSegmentInclusive2D(p, a, b, eps) || pointOnSegmentInclusive2D(p, b, c, eps) || pointOnSegmentInclusive2D(p, c, a, eps);
|
|
3117
|
+
}
|
|
3118
|
+
};
|
|
3119
|
+
|
|
3120
|
+
triangleIntersectsTriangle = function(triangleA, triangleB, additions = {
|
|
3121
|
+
coplanar: false,
|
|
3122
|
+
source: new Vector3(),
|
|
3123
|
+
target: new Vector3()
|
|
3124
|
+
}) {
|
|
3125
|
+
var distanceVertex1A, distanceVertex1B, distanceVertex2A, distanceVertex2B, distanceVertex3A, distanceVertex3B, normal1, normal2, vertex1TriangleA, vertex1TriangleB, vertex2TriangleA, vertex2TriangleB, vertex3TriangleA, vertex3TriangleB;
|
|
3126
|
+
// Extract vertices of triangle A.
|
|
3127
|
+
vertex1TriangleA = triangleA.a;
|
|
3128
|
+
vertex2TriangleA = triangleA.b;
|
|
3129
|
+
vertex3TriangleA = triangleA.c;
|
|
3130
|
+
// Extract vertices of triangle B.
|
|
3131
|
+
vertex1TriangleB = triangleB.a;
|
|
3132
|
+
vertex2TriangleB = triangleB.b;
|
|
3133
|
+
vertex3TriangleB = triangleB.c;
|
|
3134
|
+
// Step 1: Compute signed distances of Triangle A’s vertices relative to the plane defined by Triangle B.
|
|
3135
|
+
tempVector1.copy(vertex1TriangleB).sub(vertex3TriangleB);
|
|
3136
|
+
tempVector2.copy(vertex2TriangleB).sub(vertex3TriangleB);
|
|
3137
|
+
normal2 = (new Vector3()).copy(tempVector1).cross(tempVector2);
|
|
3138
|
+
tempVector1.copy(vertex1TriangleA).sub(vertex3TriangleB);
|
|
3139
|
+
distanceVertex1A = tempVector1.dot(normal2);
|
|
3140
|
+
tempVector1.copy(vertex2TriangleA).sub(vertex3TriangleB);
|
|
3141
|
+
distanceVertex2A = tempVector1.dot(normal2);
|
|
3142
|
+
tempVector1.copy(vertex3TriangleA).sub(vertex3TriangleB);
|
|
3143
|
+
distanceVertex3A = tempVector1.dot(normal2);
|
|
3144
|
+
if (((distanceVertex1A * distanceVertex2A) > 0) && ((distanceVertex1A * distanceVertex3A) > 0)) {
|
|
3145
|
+
return false; // All vertices of Triangle A are on the same side of Triangle B’s plane.
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
// Step 2: Compute signed distances of Triangle B’s vertices relative to the plane defined by Triangle A.
|
|
3149
|
+
tempVector1.copy(vertex2TriangleA).sub(vertex1TriangleA);
|
|
3150
|
+
tempVector2.copy(vertex3TriangleA).sub(vertex1TriangleA);
|
|
3151
|
+
normal1 = (new Vector3()).copy(tempVector1).cross(tempVector2);
|
|
3152
|
+
tempVector1.copy(vertex1TriangleB).sub(vertex3TriangleA);
|
|
3153
|
+
distanceVertex1B = tempVector1.dot(normal1);
|
|
3154
|
+
tempVector1.copy(vertex2TriangleB).sub(vertex3TriangleA);
|
|
3155
|
+
distanceVertex2B = tempVector1.dot(normal1);
|
|
3156
|
+
tempVector1.copy(vertex3TriangleB).sub(vertex3TriangleA);
|
|
3157
|
+
distanceVertex3B = tempVector1.dot(normal1);
|
|
3158
|
+
if (((distanceVertex1B * distanceVertex2B) > 0) && ((distanceVertex1B * distanceVertex3B) > 0)) {
|
|
3159
|
+
return false; // All vertices of Triangle B are on the same side of Triangle A’s plane.
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
// Step 3: At this point, neither triangle is fully on one side of the other’s plane. This means the triangles potentially intersect.
|
|
3163
|
+
// Next, we use the vertex signed distances to decide which configuration applies and call `resolveTriangleIntersection` (or `resolveCoplanarTriangleIntersection` if the triangles are coplanar).
|
|
3164
|
+
additions.normal1 = normal1;
|
|
3165
|
+
additions.normal2 = normal2;
|
|
3166
|
+
// Decide how to proceed by looking at the signs of distanceVertex1A, distanceVertex2A and distanceVertex3A.
|
|
3167
|
+
// These numbers tell us whether each vertex of Triangle A sits above the flat surface of Triangle B (positive), below it (negative), or exactly on it (zero).
|
|
3168
|
+
// We then pass the vertices to the resolver in a stable order: the single “different-side” vertex first, followed by the two vertices that are on the same side.
|
|
3169
|
+
if (distanceVertex1A > 0) {
|
|
3170
|
+
// If distanceVertex1A is positive (the first vertex of Triangle A is above Triangle B's surface):
|
|
3171
|
+
if (distanceVertex2A > 0) {
|
|
3172
|
+
// Then distanceVertex2A is also positive, while distanceVertex3A is zero or negative.
|
|
3173
|
+
// In plain terms: the third vertex of Triangle A lies on the other side of Triangle B’s surface (or exactly on it).
|
|
3174
|
+
return resolveTriangleIntersection(vertex3TriangleA, vertex1TriangleA, vertex2TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3175
|
+
} else if (distanceVertex3A > 0) {
|
|
3176
|
+
// Then distanceVertex3A is positive, while distanceVertex2A is zero or negative.
|
|
3177
|
+
// That means the second vertex of Triangle A is the one on the other side (or exactly on the surface).
|
|
3178
|
+
return resolveTriangleIntersection(vertex2TriangleA, vertex3TriangleA, vertex1TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3179
|
+
} else {
|
|
3180
|
+
// Here only the first vertex is above the surface; the second and third are on or below it.
|
|
3181
|
+
return resolveTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3182
|
+
}
|
|
3183
|
+
} else if (distanceVertex1A < 0) {
|
|
3184
|
+
// If distanceVertex1A is negative (the first vertex of Triangle A is below Triangle B's surface):
|
|
3185
|
+
if (distanceVertex2A < 0) {
|
|
3186
|
+
// Then distanceVertex2A is also negative, while distanceVertex3A is zero or positive.
|
|
3187
|
+
// In other words: the third vertex of Triangle A is on the other side (or exactly on the surface).
|
|
3188
|
+
return resolveTriangleIntersection(vertex3TriangleA, vertex1TriangleA, vertex2TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3189
|
+
} else if (distanceVertex3A < 0) {
|
|
3190
|
+
// Then distanceVertex3A is negative, while distanceVertex2A is zero or positive.
|
|
3191
|
+
// So the second vertex is the one on the other side (or exactly on the surface).
|
|
3192
|
+
return resolveTriangleIntersection(vertex2TriangleA, vertex3TriangleA, vertex1TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3193
|
+
} else {
|
|
3194
|
+
// Only the first vertex is below the surface; the second and third are on or above it.
|
|
3195
|
+
// Note: We also swap the order of Triangle B’s vertices here to keep a consistent “one different, two the same” pattern for the resolver.
|
|
3196
|
+
return resolveTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3197
|
+
}
|
|
3198
|
+
} else {
|
|
3199
|
+
// Then the first vertex of Triangle A lies exactly on Triangle B’s surface (distanceVertex1A is zero).
|
|
3200
|
+
// We look at distanceVertex2A and distanceVertex3A to decide which side the other vertices are on.
|
|
3201
|
+
if (distanceVertex2A < 0) {
|
|
3202
|
+
if (distanceVertex3A >= 0) {
|
|
3203
|
+
// The second vertex is below the surface, while the third is on or above it.
|
|
3204
|
+
return resolveTriangleIntersection(vertex2TriangleA, vertex3TriangleA, vertex1TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3205
|
+
} else {
|
|
3206
|
+
// Both the second and third vertices are below the surface.
|
|
3207
|
+
return resolveTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3208
|
+
}
|
|
3209
|
+
} else if (distanceVertex2A > 0) {
|
|
3210
|
+
if (distanceVertex3A > 0) {
|
|
3211
|
+
// Both the second and third vertices are above the surface.
|
|
3212
|
+
return resolveTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3213
|
+
} else {
|
|
3214
|
+
// The second vertex is above the surface, while the third is on or below it.
|
|
3215
|
+
return resolveTriangleIntersection(vertex2TriangleA, vertex3TriangleA, vertex1TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3216
|
+
}
|
|
3217
|
+
} else {
|
|
3218
|
+
if (distanceVertex3A > 0) {
|
|
3219
|
+
// The second vertex is exactly on the surface, and the third is above it.
|
|
3220
|
+
return resolveTriangleIntersection(vertex3TriangleA, vertex1TriangleA, vertex2TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions);
|
|
3221
|
+
} else if (distanceVertex3A < 0) {
|
|
3222
|
+
// The second vertex is exactly on the surface, and the third is below it.
|
|
3223
|
+
return resolveTriangleIntersection(vertex3TriangleA, vertex1TriangleA, vertex2TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB, distanceVertex1B, distanceVertex3B, distanceVertex2B, additions);
|
|
3224
|
+
} else {
|
|
3225
|
+
additions.coplanar = true; // All three vertices of Triangle A lie in Triangle B's plane.
|
|
3226
|
+
return resolveCoplanarTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, normal1, normal2);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
};
|
|
3231
|
+
|
|
3232
|
+
resolveTriangleIntersection = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, distanceVertex1B, distanceVertex2B, distanceVertex3B, additions) {
|
|
3233
|
+
// Early exit → If all B's distances are strictly positive (totally outside/above) or negative (totally outside/below), there's no intersection.
|
|
3234
|
+
if ((distanceVertex1B > 0 && distanceVertex2B > 0 && distanceVertex3B > 0) || (distanceVertex1B < 0 && distanceVertex2B < 0 && distanceVertex3B < 0)) {
|
|
3235
|
+
return false;
|
|
3236
|
+
}
|
|
3237
|
+
if (distanceVertex1B > 0) { // First vertex of Triangle B is above (positive side of) Triangle A's plane.
|
|
3238
|
+
if (distanceVertex2B > 0) { // First two vertices of B are positive, third is zero or negative.
|
|
3239
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB, additions); // Reorder B as (C, A, B) so differing vertex is last.
|
|
3240
|
+
} else if (distanceVertex3B > 0) { // First and third vertices of B are positive, second is zero or negative.
|
|
3241
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB, additions); // Reorder B as (B, C, A).
|
|
3242
|
+
// Only first vertex of B is positive.
|
|
3243
|
+
} else {
|
|
3244
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions); // Pass original B ordering.
|
|
3245
|
+
}
|
|
3246
|
+
} else if (distanceVertex1B < 0) { // First vertex of Triangle B is below (negative side of) Triangle A's plane.
|
|
3247
|
+
if (distanceVertex2B < 0) { // First two vertices of B are negative, third is zero or positive.
|
|
3248
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB, additions); // Reorder B as (C, A, B) so differing vertex is last.
|
|
3249
|
+
} else if (distanceVertex3B < 0) { // First and third vertices of B are negative, second is zero or positive.
|
|
3250
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB, additions); // Reorder B as (B, C, A).
|
|
3251
|
+
// Only first vertex of B is negative.
|
|
3252
|
+
} else {
|
|
3253
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions); // Pass A, reordered B.
|
|
3254
|
+
// First vertex of Triangle B is exactly on the plane (distance zero).
|
|
3255
|
+
}
|
|
3256
|
+
} else {
|
|
3257
|
+
if (distanceVertex2B < 0) { // Second vertex is negative, third will decide.
|
|
3258
|
+
if (distanceVertex3B >= 0) { // Second negative, third zero or positive.
|
|
3259
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB, additions); // Mixed across the plane.
|
|
3260
|
+
// Second & third negative.
|
|
3261
|
+
} else {
|
|
3262
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions); // Only first on the plane.
|
|
3263
|
+
}
|
|
3264
|
+
} else if (distanceVertex2B > 0) { // Second vertex is positive.
|
|
3265
|
+
if (distanceVertex3B > 0) { // Both second and third are positive.
|
|
3266
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions); // Both above the plane.
|
|
3267
|
+
// Second positive, third zero or negative.
|
|
3268
|
+
} else {
|
|
3269
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB, additions); // Mixed, split across plane.
|
|
3270
|
+
// Second vertex is exactly on the plane (zero).
|
|
3271
|
+
}
|
|
3272
|
+
} else {
|
|
3273
|
+
if (distanceVertex3B > 0) { // Only third is positive.
|
|
3274
|
+
return constructIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB, additions); // Third above, first/second on plane.
|
|
3275
|
+
} else if (distanceVertex3B < 0) { // Only third is negative.
|
|
3276
|
+
return constructIntersection(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB, additions); // Third below plane.
|
|
3277
|
+
// All three B vertices are exactly on the plane (coplanar).
|
|
3278
|
+
} else {
|
|
3279
|
+
additions.coplanar = true; // Mark coplanar.
|
|
3280
|
+
return resolveCoplanarTriangleIntersection(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions.normal1, additions.normal2);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
};
|
|
3285
|
+
|
|
3286
|
+
resolveCoplanarTriangleIntersection = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, normalTriangleA, normalTriangleB) {
|
|
3287
|
+
var normalAbsX, normalAbsY, normalAbsZ, vertex1TriangleA2D, vertex1TriangleB2D, vertex2TriangleA2D, vertex2TriangleB2D, vertex3TriangleA2D, vertex3TriangleB2D;
|
|
3288
|
+
// Prepare 2D projected vertices.
|
|
3289
|
+
vertex1TriangleA2D = new Vector2();
|
|
3290
|
+
vertex2TriangleA2D = new Vector2();
|
|
3291
|
+
vertex3TriangleA2D = new Vector2();
|
|
3292
|
+
vertex1TriangleB2D = new Vector2();
|
|
3293
|
+
vertex2TriangleB2D = new Vector2();
|
|
3294
|
+
vertex3TriangleB2D = new Vector2();
|
|
3295
|
+
// Absolute values of the triangle's normal components.
|
|
3296
|
+
// Used to determine the dominant axis, which we drop during 2D projection.
|
|
3297
|
+
normalAbsX = Math.abs(normalTriangleA.x);
|
|
3298
|
+
normalAbsY = Math.abs(normalTriangleA.y);
|
|
3299
|
+
normalAbsZ = Math.abs(normalTriangleA.z);
|
|
3300
|
+
// Project triangles into 2D by dropping the dominant axis of the normal.
|
|
3301
|
+
if ((normalAbsX > normalAbsZ) && (normalAbsX >= normalAbsY)) { // Project onto YZ plane.
|
|
3302
|
+
vertex1TriangleA2D.set(vertex1TriangleA.y, vertex1TriangleA.z);
|
|
3303
|
+
vertex2TriangleA2D.set(vertex2TriangleA.y, vertex2TriangleA.z);
|
|
3304
|
+
vertex3TriangleA2D.set(vertex3TriangleA.y, vertex3TriangleA.z);
|
|
3305
|
+
vertex1TriangleB2D.set(vertex1TriangleB.y, vertex1TriangleB.z);
|
|
3306
|
+
vertex2TriangleB2D.set(vertex2TriangleB.y, vertex2TriangleB.z);
|
|
3307
|
+
vertex3TriangleB2D.set(vertex3TriangleB.y, vertex3TriangleB.z);
|
|
3308
|
+
} else if ((normalAbsY > normalAbsZ) && (normalAbsY >= normalAbsX)) { // Project onto XZ plane.
|
|
3309
|
+
vertex1TriangleA2D.set(vertex1TriangleA.x, vertex1TriangleA.z);
|
|
3310
|
+
vertex2TriangleA2D.set(vertex2TriangleA.x, vertex2TriangleA.z);
|
|
3311
|
+
vertex3TriangleA2D.set(vertex3TriangleA.x, vertex3TriangleA.z);
|
|
3312
|
+
vertex1TriangleB2D.set(vertex1TriangleB.x, vertex1TriangleB.z);
|
|
3313
|
+
vertex2TriangleB2D.set(vertex2TriangleB.x, vertex2TriangleB.z);
|
|
3314
|
+
vertex3TriangleB2D.set(vertex3TriangleB.x, vertex3TriangleB.z); // Project onto XY plane
|
|
3315
|
+
} else {
|
|
3316
|
+
vertex1TriangleA2D.set(vertex1TriangleA.x, vertex1TriangleA.y);
|
|
3317
|
+
vertex2TriangleA2D.set(vertex2TriangleA.x, vertex2TriangleA.y);
|
|
3318
|
+
vertex3TriangleA2D.set(vertex3TriangleA.x, vertex3TriangleA.y);
|
|
3319
|
+
vertex1TriangleB2D.set(vertex1TriangleB.x, vertex1TriangleB.y);
|
|
3320
|
+
vertex2TriangleB2D.set(vertex2TriangleB.x, vertex2TriangleB.y);
|
|
3321
|
+
vertex3TriangleB2D.set(vertex3TriangleB.x, vertex3TriangleB.y);
|
|
3322
|
+
}
|
|
3323
|
+
return trianglesOverlap2D(vertex1TriangleA2D, vertex2TriangleA2D, vertex3TriangleA2D, vertex1TriangleB2D, vertex2TriangleB2D, vertex3TriangleB2D);
|
|
3324
|
+
};
|
|
3325
|
+
|
|
3326
|
+
trianglesOverlap2D = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) {
|
|
3327
|
+
// Early handle point-degenerate cases explicitly and efficiently.
|
|
3328
|
+
if (pointsEqual2D(vertex1TriangleB, vertex2TriangleB, EPS2D) && pointsEqual2D(vertex2TriangleB, vertex3TriangleB, EPS2D)) {
|
|
3329
|
+
return pointInTriangleInclusive2D(vertex1TriangleB, vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, EPS2D);
|
|
3330
|
+
}
|
|
3331
|
+
if (pointsEqual2D(vertex1TriangleA, vertex2TriangleA, EPS2D) && pointsEqual2D(vertex2TriangleA, vertex3TriangleA, EPS2D)) {
|
|
3332
|
+
return pointInTriangleInclusive2D(vertex1TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, EPS2D);
|
|
3333
|
+
}
|
|
3334
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA) < 0) { // If triangle A is CW.
|
|
3335
|
+
if (triangleOrientation2D(vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) < 0) { // If both A and B are CW → reorder both.
|
|
3336
|
+
return triangleIntersectionCCW2D(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB); // Only A is CW → reorder A.
|
|
3337
|
+
} else {
|
|
3338
|
+
return triangleIntersectionCCW2D(vertex1TriangleA, vertex3TriangleA, vertex2TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB); // Triangle A is CCW.
|
|
3339
|
+
}
|
|
3340
|
+
} else {
|
|
3341
|
+
if (triangleOrientation2D(vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) < 0) { // If only B is CW → reorder B.
|
|
3342
|
+
return triangleIntersectionCCW2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex3TriangleB, vertex2TriangleB); // Both A and B are CCW → no reordering.
|
|
3343
|
+
} else {
|
|
3344
|
+
return triangleIntersectionCCW2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
};
|
|
3348
|
+
|
|
3349
|
+
triangleOrientation2D = function(a, b, c) {
|
|
3350
|
+
// Compute the signed area of the triangle (a, b, c).
|
|
3351
|
+
return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
|
|
3352
|
+
};
|
|
3353
|
+
|
|
3354
|
+
triangleIntersectionCCW2D = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) {
|
|
3355
|
+
// If vertex1TriangleB is on or to the left of edge vertex1TriangleA-vertex2TriangleA-vertex3TriangleA.
|
|
3356
|
+
if (triangleOrientation2D(vertex1TriangleB, vertex2TriangleB, vertex1TriangleA) >= 0) {
|
|
3357
|
+
// If vertex2TriangleB is on or to the left of edge vertex2TriangleA-vertex3TriangleA-vertex1TriangleA.
|
|
3358
|
+
if (triangleOrientation2D(vertex2TriangleB, vertex3TriangleB, vertex1TriangleA) >= 0) {
|
|
3359
|
+
// If vertex3TriangleB is on or to the left of edge vertex3TriangleA-vertex1TriangleA-vertex1TriangleA.
|
|
3360
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex1TriangleA) >= 0) {
|
|
3361
|
+
return true; // All vertices of B are inside A.
|
|
3362
|
+
// Then vertex3TriangleB is outside, test edge intersection.
|
|
3363
|
+
} else {
|
|
3364
|
+
return intersectionTestEdge2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB); // Then vertex2TriangleB is outside.
|
|
3365
|
+
}
|
|
3366
|
+
} else {
|
|
3367
|
+
|
|
3368
|
+
// If vertex3TriangleB is on or to the left of edge vertex3TriangleA-vertex1TriangleA-vertex1TriangleA, test edge intersection.
|
|
3369
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex1TriangleA) >= 0) {
|
|
3370
|
+
return intersectionTestEdge2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB); // Then both vertex2TriangleB and vertex3TriangleB are outside, test vertex intersection.
|
|
3371
|
+
} else {
|
|
3372
|
+
return intersectionTestVertex2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB); // Then vertex2TriangleB is on or to the left of edge vertex2TriangleA-vertex3TriangleA-vertex1TriangleA.
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
} else {
|
|
3376
|
+
|
|
3377
|
+
// If vertex2TriangleB is on or to the left of edge vertex2TriangleA-vertex3TriangleA-vertex1TriangleA.
|
|
3378
|
+
if (triangleOrientation2D(vertex2TriangleB, vertex3TriangleB, vertex1TriangleA) >= 0) {
|
|
3379
|
+
// If vertex3TriangleB is on or to the left of edge vertex3TriangleA-vertex1TriangleA-vertex1TriangleA, test edge intersection.
|
|
3380
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex1TriangleA) >= 0) {
|
|
3381
|
+
return intersectionTestEdge2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB); // Then vertex3TriangleB is outside, test vertex intersection.
|
|
3382
|
+
} else {
|
|
3383
|
+
return intersectionTestVertex2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex2TriangleB, vertex3TriangleB, vertex1TriangleB); // Then both vertex1TriangleB and vertex2TriangleB are outside, test vertex intersection.
|
|
3384
|
+
}
|
|
3385
|
+
} else {
|
|
3386
|
+
return intersectionTestVertex2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex3TriangleB, vertex1TriangleB, vertex2TriangleB);
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
|
|
3391
|
+
intersectionTestEdge2D = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) {
|
|
3392
|
+
// If vertex3TriangleB is on or to the left of edge vertex1TriangleB-vertex2TriangleA.
|
|
3393
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex2TriangleA) >= 0) {
|
|
3394
|
+
// If vertex1TriangleA is on or to the left of edge vertex1TriangleB-vertex2TriangleA.
|
|
3395
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex1TriangleB, vertex2TriangleA) >= 0) {
|
|
3396
|
+
// If vertex1TriangleA is on or to the left of edge vertex2TriangleA-vertex3TriangleB.
|
|
3397
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex2TriangleA, vertex3TriangleB) >= 0) {
|
|
3398
|
+
return true; // Then vertex1TriangleA is outside edge vertex2TriangleA-vertex3TriangleB.
|
|
3399
|
+
} else {
|
|
3400
|
+
return false; // Then vertex1TriangleA is outside edge vertex1TriangleB-vertex2TriangleA.
|
|
3401
|
+
}
|
|
3402
|
+
} else {
|
|
3403
|
+
|
|
3404
|
+
// If vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex1TriangleB.
|
|
3405
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex1TriangleB) >= 0) {
|
|
3406
|
+
// If vertex3TriangleA is on or to the left of edge vertex1TriangleA-vertex1TriangleB.
|
|
3407
|
+
if (triangleOrientation2D(vertex3TriangleA, vertex1TriangleA, vertex1TriangleB) >= 0) {
|
|
3408
|
+
return true; // Then vertex3TriangleA is outside edge vertex1TriangleA-vertex1TriangleB.
|
|
3409
|
+
} else {
|
|
3410
|
+
return false; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex1TriangleB.
|
|
3411
|
+
}
|
|
3412
|
+
} else {
|
|
3413
|
+
return false; // Then vertex3TriangleB is outside edge vertex1TriangleB-vertex2TriangleA.
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
} else {
|
|
3417
|
+
|
|
3418
|
+
// If vertex3TriangleB is on or to the left of edge vertex1TriangleB-vertex3TriangleA.
|
|
3419
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex3TriangleA) >= 0) {
|
|
3420
|
+
// If vertex1TriangleA is on or to the left of edge vertex1TriangleB-vertex3TriangleA.
|
|
3421
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex1TriangleB, vertex3TriangleA) >= 0) {
|
|
3422
|
+
// If vertex1TriangleA is on or to the left of edge vertex3TriangleA-vertex3TriangleB.
|
|
3423
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex3TriangleA, vertex3TriangleB) >= 0) {
|
|
3424
|
+
return true;
|
|
3425
|
+
} else {
|
|
3426
|
+
// Then vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex3TriangleB.
|
|
3427
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex3TriangleB) >= 0) {
|
|
3428
|
+
return true; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex3TriangleB.
|
|
3429
|
+
} else {
|
|
3430
|
+
return false; // Then vertex1TriangleA is outside edge vertex1TriangleB-vertex3TriangleA.
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
} else {
|
|
3434
|
+
return false; // Then vertex3TriangleB is outside edge vertex1TriangleB-vertex3TriangleA.
|
|
3435
|
+
}
|
|
3436
|
+
} else {
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3441
|
+
|
|
3442
|
+
intersectionTestVertex2D = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB) {
|
|
3443
|
+
// If vertex3TriangleB is on or to the left of edge vertex1TriangleB-vertex2TriangleA.
|
|
3444
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex2TriangleA) >= 0) {
|
|
3445
|
+
// If vertex3TriangleB is on or to the right of edge vertex2TriangleB-vertex2TriangleA.
|
|
3446
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex2TriangleB, vertex2TriangleA) <= 0) {
|
|
3447
|
+
// If vertex1TriangleA is on the right of edge vertex1TriangleB-vertex2TriangleA.
|
|
3448
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex1TriangleB, vertex2TriangleA) > 0) {
|
|
3449
|
+
// If vertex1TriangleA is on or to the left of edge vertex2TriangleB-vertex2TriangleA.
|
|
3450
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex2TriangleB, vertex2TriangleA) <= 0) {
|
|
3451
|
+
return true; // Then vertex1TriangleA is outside edge vertex2TriangleB-vertex2TriangleA.
|
|
3452
|
+
} else {
|
|
3453
|
+
return false; // Then vertex1TriangleA is on or to the left of edge vertex1TriangleB-vertex2TriangleA.
|
|
3454
|
+
}
|
|
3455
|
+
} else {
|
|
3456
|
+
|
|
3457
|
+
// If vertex1TriangleA is on or to the left of edge vertex1TriangleB-vertex3TriangleA.
|
|
3458
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex1TriangleB, vertex3TriangleA) >= 0) {
|
|
3459
|
+
// If vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex1TriangleB.
|
|
3460
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex1TriangleB) >= 0) {
|
|
3461
|
+
return true; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex1TriangleB.
|
|
3462
|
+
} else {
|
|
3463
|
+
return false; // Then vertex1TriangleA is outside edge vertex1TriangleB-vertex3TriangleA.
|
|
3464
|
+
}
|
|
3465
|
+
} else {
|
|
3466
|
+
return false; // Then vertex3TriangleB is on the left of edge vertex2TriangleB-vertex2TriangleA.
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
} else {
|
|
3470
|
+
|
|
3471
|
+
// If vertex1TriangleA is on or to the left of edge vertex2TriangleB-vertex2TriangleA.
|
|
3472
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex2TriangleB, vertex2TriangleA) <= 0) {
|
|
3473
|
+
// If vertex3TriangleB is on or to the left of edge vertex2TriangleB-vertex3TriangleA.
|
|
3474
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex2TriangleB, vertex3TriangleA) <= 0) {
|
|
3475
|
+
// If vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex2TriangleB.
|
|
3476
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex2TriangleB) >= 0) {
|
|
3477
|
+
return true; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex2TriangleB.
|
|
3478
|
+
} else {
|
|
3479
|
+
return false; // Then vertex3TriangleB is outside edge vertex2TriangleB-vertex3TriangleA.
|
|
3480
|
+
}
|
|
3481
|
+
} else {
|
|
3482
|
+
return false; // Then vertex1TriangleA is outside edge vertex2TriangleB-vertex2TriangleA.
|
|
3483
|
+
}
|
|
3484
|
+
} else {
|
|
3485
|
+
return false; // Then vertex3TriangleB is outside edge vertex1TriangleB-vertex2TriangleA.
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
} else {
|
|
3489
|
+
|
|
3490
|
+
// If vertex3TriangleB is on or to the left of edge vertex1TriangleB-vertex3TriangleA.
|
|
3491
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex1TriangleB, vertex3TriangleA) >= 0) {
|
|
3492
|
+
// If vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex3TriangleB.
|
|
3493
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex3TriangleB) >= 0) {
|
|
3494
|
+
// If vertex1TriangleA is on or to the left of edge vertex1TriangleB-vertex3TriangleA.
|
|
3495
|
+
if (triangleOrientation2D(vertex1TriangleA, vertex1TriangleB, vertex3TriangleA) >= 0) {
|
|
3496
|
+
return true; // Then vertex1TriangleA is outside edge vertex1TriangleB-vertex3TriangleA.
|
|
3497
|
+
} else {
|
|
3498
|
+
return false; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex3TriangleB.
|
|
3499
|
+
}
|
|
3500
|
+
} else {
|
|
3501
|
+
|
|
3502
|
+
// If vertex2TriangleA is on or to the left of edge vertex3TriangleA-vertex2TriangleB.
|
|
3503
|
+
if (triangleOrientation2D(vertex2TriangleA, vertex3TriangleA, vertex2TriangleB) >= 0) {
|
|
3504
|
+
// If vertex3TriangleB is on or to the left of edge vertex3TriangleA-vertex2TriangleB.
|
|
3505
|
+
if (triangleOrientation2D(vertex3TriangleB, vertex3TriangleA, vertex2TriangleB) >= 0) {
|
|
3506
|
+
return true; // Then vertex3TriangleB is outside edge vertex3TriangleA-vertex2TriangleB.
|
|
3507
|
+
} else {
|
|
3508
|
+
return false; // Then vertex2TriangleA is outside edge vertex3TriangleA-vertex2TriangleB.
|
|
3509
|
+
}
|
|
3510
|
+
} else {
|
|
3511
|
+
return false; // Then vertex3TriangleB is outside edge vertex1TriangleB-vertex3TriangleA.
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
} else {
|
|
3515
|
+
return false;
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
};
|
|
3519
|
+
|
|
3520
|
+
constructIntersection = function(vertex1TriangleA, vertex2TriangleA, vertex3TriangleA, vertex1TriangleB, vertex2TriangleB, vertex3TriangleB, additions) {
|
|
3521
|
+
var alpha, crossNormal;
|
|
3522
|
+
alpha = void 0;
|
|
3523
|
+
crossNormal = new Vector3();
|
|
3524
|
+
// Compute cross product for triangle orientation.
|
|
3525
|
+
tempVector1.subVectors(vertex2TriangleA, vertex1TriangleA);
|
|
3526
|
+
tempVector2.subVectors(vertex3TriangleB, vertex1TriangleA);
|
|
3527
|
+
crossNormal.copy(tempVector1).cross(tempVector2);
|
|
3528
|
+
tempVector3.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3529
|
+
if (tempVector3.dot(crossNormal) > 0) {
|
|
3530
|
+
// Check orientation with triangle A's third vertex.
|
|
3531
|
+
tempVector1.subVectors(vertex3TriangleA, vertex1TriangleA);
|
|
3532
|
+
crossNormal.copy(tempVector1).cross(tempVector2);
|
|
3533
|
+
if (tempVector3.dot(crossNormal) <= 0) {
|
|
3534
|
+
// Check orientation with triangle B's second vertex.
|
|
3535
|
+
tempVector2.subVectors(vertex2TriangleB, vertex1TriangleA);
|
|
3536
|
+
crossNormal.copy(tempVector1).cross(tempVector2);
|
|
3537
|
+
if (tempVector3.dot(crossNormal) > 0) {
|
|
3538
|
+
// Compute intersection segment endpoints (case 1).
|
|
3539
|
+
tempVector1.subVectors(vertex1TriangleA, vertex1TriangleB);
|
|
3540
|
+
tempVector2.subVectors(vertex1TriangleA, vertex3TriangleA);
|
|
3541
|
+
alpha = tempVector1.dot(additions.normal2) / tempVector2.dot(additions.normal2);
|
|
3542
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3543
|
+
additions.source.subVectors(vertex1TriangleA, tempVector1);
|
|
3544
|
+
tempVector1.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3545
|
+
tempVector2.subVectors(vertex1TriangleB, vertex3TriangleB);
|
|
3546
|
+
alpha = tempVector1.dot(additions.normal1) / tempVector2.dot(additions.normal1);
|
|
3547
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3548
|
+
additions.target.subVectors(vertex1TriangleB, tempVector1);
|
|
3549
|
+
return true;
|
|
3550
|
+
} else {
|
|
3551
|
+
// Compute intersection segment endpoints (case 2).
|
|
3552
|
+
tempVector1.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3553
|
+
tempVector2.subVectors(vertex1TriangleB, vertex2TriangleB);
|
|
3554
|
+
alpha = tempVector1.dot(additions.normal1) / tempVector2.dot(additions.normal1);
|
|
3555
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3556
|
+
additions.source.subVectors(vertex1TriangleB, tempVector1);
|
|
3557
|
+
tempVector1.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3558
|
+
tempVector2.subVectors(vertex1TriangleB, vertex3TriangleB);
|
|
3559
|
+
alpha = tempVector1.dot(additions.normal1) / tempVector2.dot(additions.normal1);
|
|
3560
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3561
|
+
additions.target.subVectors(vertex1TriangleB, tempVector1);
|
|
3562
|
+
return true;
|
|
3563
|
+
}
|
|
3564
|
+
} else {
|
|
3565
|
+
return false; // No intersection, orientation test failed.
|
|
3566
|
+
}
|
|
3567
|
+
} else {
|
|
3568
|
+
tempVector2.subVectors(vertex2TriangleB, vertex1TriangleA);
|
|
3569
|
+
crossNormal.copy(tempVector1).cross(tempVector2);
|
|
3570
|
+
if (tempVector3.dot(crossNormal) < 0) {
|
|
3571
|
+
return false; // No intersection, orientation test failed.
|
|
3572
|
+
} else {
|
|
3573
|
+
tempVector1.subVectors(vertex3TriangleA, vertex1TriangleA);
|
|
3574
|
+
crossNormal.copy(tempVector1).cross(tempVector2);
|
|
3575
|
+
if (tempVector3.dot(crossNormal) < 0) {
|
|
3576
|
+
// Compute intersection segment endpoints (case 3).
|
|
3577
|
+
tempVector1.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3578
|
+
tempVector2.subVectors(vertex1TriangleB, vertex2TriangleB);
|
|
3579
|
+
alpha = tempVector1.dot(additions.normal1) / tempVector2.dot(additions.normal1);
|
|
3580
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3581
|
+
additions.source.subVectors(vertex1TriangleB, tempVector1);
|
|
3582
|
+
tempVector1.subVectors(vertex1TriangleB, vertex1TriangleA);
|
|
3583
|
+
tempVector2.subVectors(vertex1TriangleB, vertex3TriangleB);
|
|
3584
|
+
alpha = tempVector1.dot(additions.normal1) / tempVector2.dot(additions.normal1);
|
|
3585
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3586
|
+
additions.target.subVectors(vertex1TriangleB, tempVector1);
|
|
3587
|
+
return true;
|
|
3588
|
+
} else {
|
|
3589
|
+
// Compute intersection segment endpoints (case 4).
|
|
3590
|
+
tempVector1.subVectors(vertex1TriangleA, vertex1TriangleB);
|
|
3591
|
+
tempVector2.subVectors(vertex1TriangleA, vertex3TriangleA);
|
|
3592
|
+
alpha = tempVector1.dot(additions.normal2) / tempVector2.dot(additions.normal2);
|
|
3593
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3594
|
+
additions.source.subVectors(vertex1TriangleA, tempVector1);
|
|
3595
|
+
tempVector1.subVectors(vertex1TriangleA, vertex1TriangleB);
|
|
3596
|
+
tempVector2.subVectors(vertex1TriangleA, vertex2TriangleA);
|
|
3597
|
+
alpha = tempVector1.dot(additions.normal2) / tempVector2.dot(additions.normal2);
|
|
3598
|
+
tempVector1.copy(tempVector2).multiplyScalar(alpha);
|
|
3599
|
+
additions.target.subVectors(vertex1TriangleA, tempVector1);
|
|
3600
|
+
return true;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
return false; // If none of the above, no intersection found.
|
|
3605
|
+
};
|
|
3606
|
+
|
|
3607
|
+
module.exports = {triangleIntersectsTriangle, resolveTriangleIntersection, resolveCoplanarTriangleIntersection, trianglesOverlap2D, triangleOrientation2D, triangleIntersectionCCW2D, intersectionTestEdge2D, intersectionTestVertex2D, constructIntersection};
|