@ifc-lite/clash 1.2.0 → 1.4.0
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/dist/adapters/step.d.ts.map +1 -1
- package/dist/adapters/step.js +27 -1
- package/dist/adapters/step.js.map +1 -1
- package/dist/contact/aabb.d.ts +20 -0
- package/dist/contact/aabb.d.ts.map +1 -0
- package/dist/contact/aabb.js +88 -0
- package/dist/contact/aabb.js.map +1 -0
- package/dist/contact/bvh.d.ts +39 -0
- package/dist/contact/bvh.d.ts.map +1 -0
- package/dist/contact/bvh.js +173 -0
- package/dist/contact/bvh.js.map +1 -0
- package/dist/contact/index.d.ts +31 -0
- package/dist/contact/index.d.ts.map +1 -0
- package/dist/contact/index.js +33 -0
- package/dist/contact/index.js.map +1 -0
- package/dist/contact/mesh-bvh.d.ts +21 -0
- package/dist/contact/mesh-bvh.d.ts.map +1 -0
- package/dist/contact/mesh-bvh.js +96 -0
- package/dist/contact/mesh-bvh.js.map +1 -0
- package/dist/contact/narrow-phase.d.ts +37 -0
- package/dist/contact/narrow-phase.d.ts.map +1 -0
- package/dist/contact/narrow-phase.js +49 -0
- package/dist/contact/narrow-phase.js.map +1 -0
- package/dist/contact/plane.d.ts +38 -0
- package/dist/contact/plane.d.ts.map +1 -0
- package/dist/contact/plane.js +83 -0
- package/dist/contact/plane.js.map +1 -0
- package/dist/contact/polygon-clip.d.ts +27 -0
- package/dist/contact/polygon-clip.d.ts.map +1 -0
- package/dist/contact/polygon-clip.js +162 -0
- package/dist/contact/polygon-clip.js.map +1 -0
- package/dist/contact/shared-faces.d.ts +61 -0
- package/dist/contact/shared-faces.d.ts.map +1 -0
- package/dist/contact/shared-faces.js +251 -0
- package/dist/contact/shared-faces.js.map +1 -0
- package/dist/contact/tri-tri.d.ts +34 -0
- package/dist/contact/tri-tri.d.ts.map +1 -0
- package/dist/contact/tri-tri.js +195 -0
- package/dist/contact/tri-tri.js.map +1 -0
- package/dist/contact/triangle.d.ts +22 -0
- package/dist/contact/triangle.d.ts.map +1 -0
- package/dist/contact/triangle.js +60 -0
- package/dist/contact/triangle.js.map +1 -0
- package/dist/contact/types.d.ts +33 -0
- package/dist/contact/types.d.ts.map +1 -0
- package/dist/contact/types.js +5 -0
- package/dist/contact/types.js.map +1 -0
- package/dist/contact/vec3.d.ts +19 -0
- package/dist/contact/vec3.d.ts.map +1 -0
- package/dist/contact/vec3.js +50 -0
- package/dist/contact/vec3.js.map +1 -0
- package/dist/engine-ts/narrow.d.ts.map +1 -1
- package/dist/engine-ts/narrow.js +102 -6
- package/dist/engine-ts/narrow.js.map +1 -1
- package/dist/engine-ts/tri-mesh.d.ts +10 -0
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -1
- package/dist/engine-ts/tri-mesh.js +24 -0
- package/dist/engine-ts/tri-mesh.js.map +1 -1
- package/package.json +9 -5
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Triangle } from "./triangle.js";
|
|
2
|
+
import type { Mesh, Vec3 } from "./types.js";
|
|
3
|
+
export type TrianglePair = {
|
|
4
|
+
readonly triA: number;
|
|
5
|
+
readonly triB: number;
|
|
6
|
+
readonly a: Triangle;
|
|
7
|
+
readonly b: Triangle;
|
|
8
|
+
readonly kind: "coplanar";
|
|
9
|
+
} | {
|
|
10
|
+
readonly triA: number;
|
|
11
|
+
readonly triB: number;
|
|
12
|
+
readonly a: Triangle;
|
|
13
|
+
readonly b: Triangle;
|
|
14
|
+
readonly kind: "cross";
|
|
15
|
+
/** 3D endpoints of the intersection segment on the common line. */
|
|
16
|
+
readonly p0: Vec3;
|
|
17
|
+
readonly p1: Vec3;
|
|
18
|
+
};
|
|
19
|
+
export interface NarrowPhaseOptions {
|
|
20
|
+
/** AABB inflation (world units). Default 0.002 (2 mm). */
|
|
21
|
+
readonly epsilon?: number;
|
|
22
|
+
/** Plane-distance tolerance for coplanarity and Möller sign tests. */
|
|
23
|
+
readonly planeEps?: number;
|
|
24
|
+
/** BVH leaf size for per-mesh triangle BVHs. Default 8. */
|
|
25
|
+
readonly leafSize?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* For two meshes A and B, return every triangle pair whose triangles
|
|
29
|
+
* either strictly cross or are coplanar (and whose AABBs are within
|
|
30
|
+
* `epsilon` of each other).
|
|
31
|
+
*
|
|
32
|
+
* Coplanar pairs are emitted without further 2D-overlap testing —
|
|
33
|
+
* shared-face clustering (downstream) does that more robustly across
|
|
34
|
+
* a whole cluster of coplanar hits.
|
|
35
|
+
*/
|
|
36
|
+
export declare function narrowPhase(a: Mesh, b: Mesh, opts?: NarrowPhaseOptions): TrianglePair[];
|
|
37
|
+
//# sourceMappingURL=narrow-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrow-phase.d.ts","sourceRoot":"","sources":["../../src/contact/narrow-phase.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,MAAM,YAAY,GACpB;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;CACnB,CAAC;AAEN,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,GAAE,kBAAuB,GAAG,YAAY,EAAE,CAiC3F"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { buildMeshBvh, queryMeshCross } from "./mesh-bvh.js";
|
|
5
|
+
import { triTriIntersect } from "./tri-tri.js";
|
|
6
|
+
import { triangleAt, triangleCount } from "./triangle.js";
|
|
7
|
+
/**
|
|
8
|
+
* For two meshes A and B, return every triangle pair whose triangles
|
|
9
|
+
* either strictly cross or are coplanar (and whose AABBs are within
|
|
10
|
+
* `epsilon` of each other).
|
|
11
|
+
*
|
|
12
|
+
* Coplanar pairs are emitted without further 2D-overlap testing —
|
|
13
|
+
* shared-face clustering (downstream) does that more robustly across
|
|
14
|
+
* a whole cluster of coplanar hits.
|
|
15
|
+
*/
|
|
16
|
+
export function narrowPhase(a, b, opts = {}) {
|
|
17
|
+
const epsilon = opts.epsilon ?? 0.002;
|
|
18
|
+
const planeEps = opts.planeEps ?? 1e-6;
|
|
19
|
+
const leafSize = opts.leafSize ?? 8;
|
|
20
|
+
if (triangleCount(a) === 0 || triangleCount(b) === 0)
|
|
21
|
+
return [];
|
|
22
|
+
const bvhA = buildMeshBvh(a, leafSize);
|
|
23
|
+
const bvhB = buildMeshBvh(b, leafSize);
|
|
24
|
+
const candidates = queryMeshCross(bvhA, bvhB, epsilon);
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const [iA, iB] of candidates) {
|
|
27
|
+
const triA = triangleAt(a, iA);
|
|
28
|
+
const triB = triangleAt(b, iB);
|
|
29
|
+
const res = triTriIntersect(triA, triB, planeEps);
|
|
30
|
+
if (res.kind === "none")
|
|
31
|
+
continue;
|
|
32
|
+
if (res.kind === "coplanar") {
|
|
33
|
+
out.push({ triA: iA, triB: iB, a: triA, b: triB, kind: "coplanar" });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
out.push({
|
|
37
|
+
triA: iA,
|
|
38
|
+
triB: iB,
|
|
39
|
+
a: triA,
|
|
40
|
+
b: triB,
|
|
41
|
+
kind: "cross",
|
|
42
|
+
p0: res.p0,
|
|
43
|
+
p1: res.p1,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=narrow-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrow-phase.js","sourceRoot":"","sources":["../../src/contact/narrow-phase.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA+B1D;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,CAAO,EAAE,CAAO,EAAE,OAA2B,EAAE;IACzE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IAEpC,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhE,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAEvD,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClD,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAClC,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACvE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,EAAE;gBACR,CAAC,EAAE,IAAI;gBACP,CAAC,EAAE,IAAI;gBACP,IAAI,EAAE,OAAO;gBACb,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,EAAE,EAAE,GAAG,CAAC,EAAE;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plane utilities. A plane is stored as a unit normal + signed offset:
|
|
3
|
+
* normal · x = offset
|
|
4
|
+
* `canonicalPlane` produces a direction-independent key so that the pair
|
|
5
|
+
* (normal, -normal, offset, -offset) hashes identically.
|
|
6
|
+
*/
|
|
7
|
+
import type { Vec3 } from "./types.js";
|
|
8
|
+
export interface Plane {
|
|
9
|
+
readonly normal: Vec3;
|
|
10
|
+
readonly offset: number;
|
|
11
|
+
}
|
|
12
|
+
export interface PlaneBasis {
|
|
13
|
+
readonly origin: Vec3;
|
|
14
|
+
readonly u: Vec3;
|
|
15
|
+
readonly v: Vec3;
|
|
16
|
+
readonly normal: Vec3;
|
|
17
|
+
}
|
|
18
|
+
/** Build a plane from a normal (not required to be unit) and a point on it. */
|
|
19
|
+
export declare function planeFromNormalPoint(normal: Vec3, point: Vec3): Plane;
|
|
20
|
+
/**
|
|
21
|
+
* Direction-independent quantised plane key.
|
|
22
|
+
*
|
|
23
|
+
* The normal is reflected so its first nonzero component is positive,
|
|
24
|
+
* then rounded to `angleSnap` radians in spherical form. The offset is
|
|
25
|
+
* signed accordingly and rounded to `distSnap` world units.
|
|
26
|
+
*/
|
|
27
|
+
export declare function planeKey(plane: Plane, angleSnap?: number, distSnap?: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* Build an orthonormal basis `{u, v}` in the plane so 3D plane points can
|
|
30
|
+
* be projected to 2D and back. `origin` is chosen as the foot of the normal
|
|
31
|
+
* from the world origin.
|
|
32
|
+
*/
|
|
33
|
+
export declare function planeBasis(plane: Plane): PlaneBasis;
|
|
34
|
+
/** Project a 3D point onto the plane's 2D basis. */
|
|
35
|
+
export declare function projectTo2D(basis: PlaneBasis, p: Vec3): readonly [number, number];
|
|
36
|
+
/** Lift a 2D basis point back to 3D. */
|
|
37
|
+
export declare function liftTo3D(basis: PlaneBasis, p: readonly [number, number]): Vec3;
|
|
38
|
+
//# sourceMappingURL=plane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plane.d.ts","sourceRoot":"","sources":["../../src/contact/plane.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;CACvB;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,KAAK,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,SAAO,EAAE,QAAQ,SAAO,GAAG,MAAM,CAmBhF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAenD;AAED,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAQjF;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAM9E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { dot3, length3 } from "./vec3.js";
|
|
5
|
+
/** Build a plane from a normal (not required to be unit) and a point on it. */
|
|
6
|
+
export function planeFromNormalPoint(normal, point) {
|
|
7
|
+
const ln = length3(normal);
|
|
8
|
+
if (ln === 0)
|
|
9
|
+
return { normal: [0, 0, 1], offset: 0 };
|
|
10
|
+
const n = [normal[0] / ln, normal[1] / ln, normal[2] / ln];
|
|
11
|
+
return { normal: n, offset: dot3(n, point) };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Direction-independent quantised plane key.
|
|
15
|
+
*
|
|
16
|
+
* The normal is reflected so its first nonzero component is positive,
|
|
17
|
+
* then rounded to `angleSnap` radians in spherical form. The offset is
|
|
18
|
+
* signed accordingly and rounded to `distSnap` world units.
|
|
19
|
+
*/
|
|
20
|
+
export function planeKey(plane, angleSnap = 1e-3, distSnap = 1e-3) {
|
|
21
|
+
const n = plane.normal;
|
|
22
|
+
const ln = length3(n);
|
|
23
|
+
if (ln === 0)
|
|
24
|
+
return "0|0|0|0";
|
|
25
|
+
// Canonicalise direction: first nonzero coordinate must be positive.
|
|
26
|
+
let sign = 1;
|
|
27
|
+
if (Math.abs(n[0]) > 1e-9)
|
|
28
|
+
sign = n[0] > 0 ? 1 : -1;
|
|
29
|
+
else if (Math.abs(n[1]) > 1e-9)
|
|
30
|
+
sign = n[1] > 0 ? 1 : -1;
|
|
31
|
+
else
|
|
32
|
+
sign = n[2] > 0 ? 1 : -1;
|
|
33
|
+
const cx = (n[0] / ln) * sign;
|
|
34
|
+
const cy = (n[1] / ln) * sign;
|
|
35
|
+
const cz = (n[2] / ln) * sign;
|
|
36
|
+
const off = plane.offset * sign;
|
|
37
|
+
return [
|
|
38
|
+
Math.round(cx / angleSnap),
|
|
39
|
+
Math.round(cy / angleSnap),
|
|
40
|
+
Math.round(cz / angleSnap),
|
|
41
|
+
Math.round(off / distSnap),
|
|
42
|
+
].join("|");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build an orthonormal basis `{u, v}` in the plane so 3D plane points can
|
|
46
|
+
* be projected to 2D and back. `origin` is chosen as the foot of the normal
|
|
47
|
+
* from the world origin.
|
|
48
|
+
*/
|
|
49
|
+
export function planeBasis(plane) {
|
|
50
|
+
const n = plane.normal;
|
|
51
|
+
// origin = offset * n (foot of normal from world origin if |n|=1)
|
|
52
|
+
const origin = [n[0] * plane.offset, n[1] * plane.offset, n[2] * plane.offset];
|
|
53
|
+
// pick a helper not parallel to n
|
|
54
|
+
const helper = Math.abs(n[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
55
|
+
const u0 = [
|
|
56
|
+
helper[1] * n[2] - helper[2] * n[1],
|
|
57
|
+
helper[2] * n[0] - helper[0] * n[2],
|
|
58
|
+
helper[0] * n[1] - helper[1] * n[0],
|
|
59
|
+
];
|
|
60
|
+
const uLen = length3(u0);
|
|
61
|
+
const u = uLen === 0 ? [1, 0, 0] : [u0[0] / uLen, u0[1] / uLen, u0[2] / uLen];
|
|
62
|
+
const v = [n[1] * u[2] - n[2] * u[1], n[2] * u[0] - n[0] * u[2], n[0] * u[1] - n[1] * u[0]];
|
|
63
|
+
return { origin, u, v, normal: n };
|
|
64
|
+
}
|
|
65
|
+
/** Project a 3D point onto the plane's 2D basis. */
|
|
66
|
+
export function projectTo2D(basis, p) {
|
|
67
|
+
const dx = p[0] - basis.origin[0];
|
|
68
|
+
const dy = p[1] - basis.origin[1];
|
|
69
|
+
const dz = p[2] - basis.origin[2];
|
|
70
|
+
return [
|
|
71
|
+
dx * basis.u[0] + dy * basis.u[1] + dz * basis.u[2],
|
|
72
|
+
dx * basis.v[0] + dy * basis.v[1] + dz * basis.v[2],
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
/** Lift a 2D basis point back to 3D. */
|
|
76
|
+
export function liftTo3D(basis, p) {
|
|
77
|
+
return [
|
|
78
|
+
basis.origin[0] + basis.u[0] * p[0] + basis.v[0] * p[1],
|
|
79
|
+
basis.origin[1] + basis.u[1] * p[0] + basis.v[1] * p[1],
|
|
80
|
+
basis.origin[2] + basis.u[2] * p[0] + basis.v[2] * p[1],
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=plane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plane.js","sourceRoot":"","sources":["../../src/contact/plane.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2D polygon utilities: Sutherland–Hodgman clip of a subject polygon by
|
|
3
|
+
* a convex clip polygon, shoelace area, perimeter, centroid.
|
|
4
|
+
*
|
|
5
|
+
* Both polygons are arrays of `[x, y]` pairs. CCW winding gives positive
|
|
6
|
+
* area (standard convention).
|
|
7
|
+
*/
|
|
8
|
+
export type Point2 = readonly [number, number];
|
|
9
|
+
export type Polygon2 = readonly Point2[];
|
|
10
|
+
/** Shoelace-formula signed area (positive when CCW). */
|
|
11
|
+
export declare function polygonSignedArea(poly: Polygon2): number;
|
|
12
|
+
export declare const polygonArea: (poly: Polygon2) => number;
|
|
13
|
+
export declare function polygonPerimeter(poly: Polygon2): number;
|
|
14
|
+
/** Area-weighted centroid. Falls back to vertex mean for degenerate input. */
|
|
15
|
+
export declare function polygonCentroid(poly: Polygon2): Point2;
|
|
16
|
+
/**
|
|
17
|
+
* Sutherland–Hodgman polygon clip. `subject` may be any simple polygon;
|
|
18
|
+
* `clip` must be **convex** (CCW). Returns the intersection polygon, which
|
|
19
|
+
* can be empty (no overlap) or degenerate (collinear/point contact).
|
|
20
|
+
*/
|
|
21
|
+
export declare function sutherlandHodgman(subject: Polygon2, clip: Polygon2): Polygon2;
|
|
22
|
+
/**
|
|
23
|
+
* Convex polygon from (unordered) points: sort by angle around centroid
|
|
24
|
+
* and return CCW. For use as a Sutherland-Hodgman clip.
|
|
25
|
+
*/
|
|
26
|
+
export declare function convexHull2(points: Polygon2): Polygon2;
|
|
27
|
+
//# sourceMappingURL=polygon-clip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-clip.d.ts","sourceRoot":"","sources":["../../src/contact/polygon-clip.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,MAAM,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC/C,MAAM,MAAM,QAAQ,GAAG,SAAS,MAAM,EAAE,CAAC;AAEzC,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAUxD;AAED,eAAO,MAAM,WAAW,GAAI,MAAM,QAAQ,KAAG,MAA2C,CAAC;AAEzF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAYvD;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA2BtD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CA8B7E;AAsBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CA4BtD"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/** Shoelace-formula signed area (positive when CCW). */
|
|
5
|
+
export function polygonSignedArea(poly) {
|
|
6
|
+
const n = poly.length;
|
|
7
|
+
if (n < 3)
|
|
8
|
+
return 0;
|
|
9
|
+
let sum = 0;
|
|
10
|
+
for (let i = 0; i < n; i++) {
|
|
11
|
+
const a = poly[i];
|
|
12
|
+
const b = poly[(i + 1) % n];
|
|
13
|
+
sum += a[0] * b[1] - b[0] * a[1];
|
|
14
|
+
}
|
|
15
|
+
return sum / 2;
|
|
16
|
+
}
|
|
17
|
+
export const polygonArea = (poly) => Math.abs(polygonSignedArea(poly));
|
|
18
|
+
export function polygonPerimeter(poly) {
|
|
19
|
+
const n = poly.length;
|
|
20
|
+
if (n < 2)
|
|
21
|
+
return 0;
|
|
22
|
+
let sum = 0;
|
|
23
|
+
for (let i = 0; i < n; i++) {
|
|
24
|
+
const a = poly[i];
|
|
25
|
+
const b = poly[(i + 1) % n];
|
|
26
|
+
const dx = b[0] - a[0];
|
|
27
|
+
const dy = b[1] - a[1];
|
|
28
|
+
sum += Math.sqrt(dx * dx + dy * dy);
|
|
29
|
+
}
|
|
30
|
+
return sum;
|
|
31
|
+
}
|
|
32
|
+
/** Area-weighted centroid. Falls back to vertex mean for degenerate input. */
|
|
33
|
+
export function polygonCentroid(poly) {
|
|
34
|
+
const n = poly.length;
|
|
35
|
+
if (n === 0)
|
|
36
|
+
return [0, 0];
|
|
37
|
+
if (n === 1) {
|
|
38
|
+
const p0 = poly[0];
|
|
39
|
+
return [p0[0], p0[1]];
|
|
40
|
+
}
|
|
41
|
+
const a2 = polygonSignedArea(poly) * 2;
|
|
42
|
+
if (Math.abs(a2) < 1e-18) {
|
|
43
|
+
let mx = 0;
|
|
44
|
+
let my = 0;
|
|
45
|
+
for (const p of poly) {
|
|
46
|
+
mx += p[0];
|
|
47
|
+
my += p[1];
|
|
48
|
+
}
|
|
49
|
+
return [mx / n, my / n];
|
|
50
|
+
}
|
|
51
|
+
let cx = 0;
|
|
52
|
+
let cy = 0;
|
|
53
|
+
for (let i = 0; i < n; i++) {
|
|
54
|
+
const a = poly[i];
|
|
55
|
+
const b = poly[(i + 1) % n];
|
|
56
|
+
const cross = a[0] * b[1] - b[0] * a[1];
|
|
57
|
+
cx += (a[0] + b[0]) * cross;
|
|
58
|
+
cy += (a[1] + b[1]) * cross;
|
|
59
|
+
}
|
|
60
|
+
return [cx / (3 * a2), cy / (3 * a2)];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Sutherland–Hodgman polygon clip. `subject` may be any simple polygon;
|
|
64
|
+
* `clip` must be **convex** (CCW). Returns the intersection polygon, which
|
|
65
|
+
* can be empty (no overlap) or degenerate (collinear/point contact).
|
|
66
|
+
*/
|
|
67
|
+
export function sutherlandHodgman(subject, clip) {
|
|
68
|
+
if (subject.length === 0 || clip.length < 3)
|
|
69
|
+
return [];
|
|
70
|
+
// Enforce CCW clip — if the clip is CW we flip it.
|
|
71
|
+
const clipCCW = polygonSignedArea(clip) >= 0 ? clip : [...clip].reverse();
|
|
72
|
+
let output = subject.map((p) => [p[0], p[1]]);
|
|
73
|
+
for (let i = 0; i < clipCCW.length; i++) {
|
|
74
|
+
if (output.length === 0)
|
|
75
|
+
break;
|
|
76
|
+
const a = clipCCW[i];
|
|
77
|
+
const b = clipCCW[(i + 1) % clipCCW.length];
|
|
78
|
+
const input = output;
|
|
79
|
+
output = [];
|
|
80
|
+
for (let j = 0; j < input.length; j++) {
|
|
81
|
+
const current = input[j];
|
|
82
|
+
const prev = input[(j - 1 + input.length) % input.length];
|
|
83
|
+
const curIn = isLeftOrOn(a, b, current);
|
|
84
|
+
const prevIn = isLeftOrOn(a, b, prev);
|
|
85
|
+
if (curIn) {
|
|
86
|
+
if (!prevIn) {
|
|
87
|
+
const ip = segmentIntersection(prev, current, a, b);
|
|
88
|
+
if (ip)
|
|
89
|
+
output.push(ip);
|
|
90
|
+
}
|
|
91
|
+
output.push(current);
|
|
92
|
+
}
|
|
93
|
+
else if (prevIn) {
|
|
94
|
+
const ip = segmentIntersection(prev, current, a, b);
|
|
95
|
+
if (ip)
|
|
96
|
+
output.push(ip);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return output;
|
|
101
|
+
}
|
|
102
|
+
/** True when point `p` is to the left of, or on, directed edge `a → b`. */
|
|
103
|
+
function isLeftOrOn(a, b, p) {
|
|
104
|
+
const cross = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
|
|
105
|
+
return cross >= 0;
|
|
106
|
+
}
|
|
107
|
+
/** Intersection of segment `p1→p2` with infinite line through `a→b`. */
|
|
108
|
+
function segmentIntersection(p1, p2, a, b) {
|
|
109
|
+
const r0 = p2[0] - p1[0];
|
|
110
|
+
const r1 = p2[1] - p1[1];
|
|
111
|
+
const s0 = b[0] - a[0];
|
|
112
|
+
const s1 = b[1] - a[1];
|
|
113
|
+
const denom = r0 * s1 - r1 * s0;
|
|
114
|
+
if (Math.abs(denom) < 1e-15)
|
|
115
|
+
return null; // parallel
|
|
116
|
+
const qp0 = a[0] - p1[0];
|
|
117
|
+
const qp1 = a[1] - p1[1];
|
|
118
|
+
const t = (qp0 * s1 - qp1 * s0) / denom;
|
|
119
|
+
return [p1[0] + t * r0, p1[1] + t * r1];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Convex polygon from (unordered) points: sort by angle around centroid
|
|
123
|
+
* and return CCW. For use as a Sutherland-Hodgman clip.
|
|
124
|
+
*/
|
|
125
|
+
export function convexHull2(points) {
|
|
126
|
+
if (points.length < 3)
|
|
127
|
+
return points.map((p) => [p[0], p[1]]);
|
|
128
|
+
// Andrew's monotone chain
|
|
129
|
+
const pts = [...points].sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]));
|
|
130
|
+
const lower = [];
|
|
131
|
+
for (const p of pts) {
|
|
132
|
+
while (lower.length >= 2) {
|
|
133
|
+
const a = lower[lower.length - 2];
|
|
134
|
+
const b = lower[lower.length - 1];
|
|
135
|
+
if (cross2(a, b, p) <= 0)
|
|
136
|
+
lower.pop();
|
|
137
|
+
else
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
lower.push(p);
|
|
141
|
+
}
|
|
142
|
+
const upper = [];
|
|
143
|
+
for (let i = pts.length - 1; i >= 0; i--) {
|
|
144
|
+
const p = pts[i];
|
|
145
|
+
while (upper.length >= 2) {
|
|
146
|
+
const a = upper[upper.length - 2];
|
|
147
|
+
const b = upper[upper.length - 1];
|
|
148
|
+
if (cross2(a, b, p) <= 0)
|
|
149
|
+
upper.pop();
|
|
150
|
+
else
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
upper.push(p);
|
|
154
|
+
}
|
|
155
|
+
lower.pop();
|
|
156
|
+
upper.pop();
|
|
157
|
+
return [...lower, ...upper];
|
|
158
|
+
}
|
|
159
|
+
function cross2(o, a, b) {
|
|
160
|
+
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=polygon-clip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-clip.js","sourceRoot":"","sources":["../../src/contact/polygon-clip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared-face clustering.
|
|
3
|
+
*
|
|
4
|
+
* Inputs: TrianglePair[] emitted by narrowPhase() for a single pair of
|
|
5
|
+
* elements. Output: one or more SharedFaceCluster objects, each representing
|
|
6
|
+
* a distinct contact between the two elements, classified as
|
|
7
|
+
* surface / line / point.
|
|
8
|
+
*
|
|
9
|
+
* Coplanar pairs cluster by plane key. For each cluster we Sutherland-Hodgman
|
|
10
|
+
* every (A,B) triangle pair on the shared plane, sum polygon areas, build a
|
|
11
|
+
* 3D boundary polygon as the convex hull of the union of clip vertices.
|
|
12
|
+
*
|
|
13
|
+
* Cross pairs cluster by intersection-line key (direction + point on line).
|
|
14
|
+
* Length is the union length of the per-pair 3D segments projected onto
|
|
15
|
+
* the line direction.
|
|
16
|
+
*
|
|
17
|
+
* Remaining incidental contacts fall into either classification by
|
|
18
|
+
* magnitude against the thresholds.
|
|
19
|
+
*/
|
|
20
|
+
import type { TrianglePair } from "./narrow-phase.js";
|
|
21
|
+
import type { Plane } from "./plane.js";
|
|
22
|
+
import type { Vec3 } from "./types.js";
|
|
23
|
+
export interface SharedFaceCluster {
|
|
24
|
+
readonly kind: "surface" | "line" | "point";
|
|
25
|
+
/** Anchoring plane (for surface) or line (for line/point, where direction is the line dir). */
|
|
26
|
+
readonly plane?: Plane;
|
|
27
|
+
/** World-space centroid of the contact. */
|
|
28
|
+
readonly centroid: Vec3;
|
|
29
|
+
/** Outward normal (surface) or line direction (line/point). */
|
|
30
|
+
readonly normal: Vec3;
|
|
31
|
+
/** Shared-face area in m² (surface only — 0 otherwise). */
|
|
32
|
+
readonly area_m2: number;
|
|
33
|
+
/** Shared-line length in m (line only — 0 otherwise). */
|
|
34
|
+
readonly length_m: number;
|
|
35
|
+
/** Narrowest dimension of the contact patch in m. Distinguishes a broad
|
|
36
|
+
* face (layered wall) from a thin bearing strip / cap. Length for a line
|
|
37
|
+
* cluster is carried by `length_m`, so its `spanMin` is 0. */
|
|
38
|
+
readonly spanMin: number;
|
|
39
|
+
/** Widest dimension (diameter) of the contact patch in m. */
|
|
40
|
+
readonly spanMax: number;
|
|
41
|
+
/** Boundary polygon (3D) for surface contacts. Segment endpoints for line contacts. Empty for point. */
|
|
42
|
+
readonly boundary: readonly Vec3[];
|
|
43
|
+
/** Contributing triangle pairs. */
|
|
44
|
+
readonly pairs: readonly TrianglePair[];
|
|
45
|
+
}
|
|
46
|
+
export interface SharedFaceOptions {
|
|
47
|
+
/** Absolute tolerance for plane coincidence (unit: model-native length). Default 1e-3. */
|
|
48
|
+
readonly planeDistSnap?: number;
|
|
49
|
+
/** Angular snap for plane normal hashing (unitless, ~1 − cos). Default 1e-3. */
|
|
50
|
+
readonly planeAngleSnap?: number;
|
|
51
|
+
/** Area (m²) threshold: ≥ surface. Default 0.01. */
|
|
52
|
+
readonly surfaceAreaM2?: number;
|
|
53
|
+
/** Area (m²) below which a contact may still be line or point. Default 0.001. */
|
|
54
|
+
readonly pointAreaM2?: number;
|
|
55
|
+
/** Length (m) threshold: ≥ line. Default 0.05. */
|
|
56
|
+
readonly lineLengthM?: number;
|
|
57
|
+
/** Snap used when hashing intersection-line direction + base point. Default 1e-3. */
|
|
58
|
+
readonly lineSnap?: number;
|
|
59
|
+
}
|
|
60
|
+
export declare function clusterSharedFaces(pairs: readonly TrianglePair[], opts?: SharedFaceOptions): SharedFaceCluster[];
|
|
61
|
+
//# sourceMappingURL=shared-faces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-faces.d.ts","sourceRoot":"","sources":["../../src/contact/shared-faces.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKxC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5C,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;mEAE+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wGAAwG;IACxG,QAAQ,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC;IACnC,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,0FAA0F;IAC1F,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,gFAAgF;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,oDAAoD;IACpD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,iFAAiF;IACjF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,IAAI,GAAE,iBAAsB,GAC3B,iBAAiB,EAAE,CAiDrB"}
|