@ifc-lite/clash 1.7.0 → 1.9.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/README.md +18 -0
- package/dist/adapters/ifcx.d.ts.map +1 -1
- package/dist/adapters/ifcx.js +22 -36
- package/dist/adapters/ifcx.js.map +1 -1
- package/dist/adapters/shared.d.ts +61 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +143 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/step.d.ts +62 -3
- package/dist/adapters/step.d.ts.map +1 -1
- package/dist/adapters/step.js +180 -89
- package/dist/adapters/step.js.map +1 -1
- package/dist/analysis.d.ts +10 -1
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +20 -0
- package/dist/analysis.js.map +1 -1
- package/dist/contact/index.d.ts +14 -0
- package/dist/contact/index.d.ts.map +1 -1
- package/dist/contact/index.js +14 -0
- package/dist/contact/index.js.map +1 -1
- package/dist/contact/min-distance.d.ts +87 -0
- package/dist/contact/min-distance.d.ts.map +1 -0
- package/dist/contact/min-distance.js +255 -0
- package/dist/contact/min-distance.js.map +1 -0
- package/dist/contact/narrow-phase.d.ts +3 -2
- package/dist/contact/narrow-phase.d.ts.map +1 -1
- package/dist/contact/narrow-phase.js +32 -14
- package/dist/contact/narrow-phase.js.map +1 -1
- package/dist/contact/shared-faces.js +10 -1
- package/dist/contact/shared-faces.js.map +1 -1
- package/dist/contact/tri-tri.d.ts +33 -7
- package/dist/contact/tri-tri.d.ts.map +1 -1
- package/dist/contact/tri-tri.js +37 -14
- package/dist/contact/tri-tri.js.map +1 -1
- package/dist/duplicate-metric.d.ts +26 -8
- package/dist/duplicate-metric.d.ts.map +1 -1
- package/dist/duplicate-metric.js +26 -8
- package/dist/duplicate-metric.js.map +1 -1
- package/dist/duplicates.d.ts +9 -0
- package/dist/duplicates.d.ts.map +1 -1
- package/dist/duplicates.js +53 -18
- package/dist/duplicates.js.map +1 -1
- package/dist/engine-ts/broad.js +20 -2
- package/dist/engine-ts/broad.js.map +1 -1
- package/dist/engine-ts/depth.d.ts +99 -0
- package/dist/engine-ts/depth.d.ts.map +1 -0
- package/dist/engine-ts/depth.js +172 -0
- package/dist/engine-ts/depth.js.map +1 -0
- package/dist/engine-ts/kernel.d.ts +3 -1
- package/dist/engine-ts/kernel.d.ts.map +1 -1
- package/dist/engine-ts/narrow.d.ts +7 -1
- package/dist/engine-ts/narrow.d.ts.map +1 -1
- package/dist/engine-ts/narrow.js +53 -95
- package/dist/engine-ts/narrow.js.map +1 -1
- package/dist/engine-ts/obb.d.ts +116 -0
- package/dist/engine-ts/obb.d.ts.map +1 -0
- package/dist/engine-ts/obb.js +331 -0
- package/dist/engine-ts/obb.js.map +1 -0
- package/dist/engine-ts/orchestrator.d.ts.map +1 -1
- package/dist/engine-ts/orchestrator.js +3 -13
- package/dist/engine-ts/orchestrator.js.map +1 -1
- package/dist/engine-ts/tri-mesh.d.ts +88 -22
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -1
- package/dist/engine-ts/tri-mesh.js +155 -48
- package/dist/engine-ts/tri-mesh.js.map +1 -1
- package/dist/engine-ts/ts-kernel.d.ts.map +1 -1
- package/dist/engine-ts/ts-kernel.js +1 -0
- package/dist/engine-ts/ts-kernel.js.map +1 -1
- package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -1
- package/dist/engine-wasm/wasm-kernel.js +7 -0
- package/dist/engine-wasm/wasm-kernel.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/math/aabb.d.ts +10 -1
- package/dist/math/aabb.d.ts.map +1 -1
- package/dist/math/aabb.js +33 -13
- package/dist/math/aabb.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +20 -4
- package/dist/selectors.js.map +1 -1
- package/dist/triage.d.ts.map +1 -1
- package/dist/triage.js +11 -3
- package/dist/triage.js.map +1 -1
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -9
|
@@ -0,0 +1,172 @@
|
|
|
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 { isThroughPenetration, obbPenetrationDepth } from './obb.js';
|
|
5
|
+
export function boxPenetration(small, large) {
|
|
6
|
+
const oa = small.getObb();
|
|
7
|
+
const ob = large.getObb();
|
|
8
|
+
if (!oa || !ob)
|
|
9
|
+
return null;
|
|
10
|
+
const mtd = obbPenetrationDepth(oa, ob);
|
|
11
|
+
if (mtd == null)
|
|
12
|
+
return null;
|
|
13
|
+
return { mtd, through: isThroughPenetration(oa, ob) };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* f32-ULP scale factor for a "worst-case" single-precision coordinate: for a
|
|
17
|
+
* value with magnitude in `[2, 4)` the true float32 ULP is `2^-22`, and for
|
|
18
|
+
* larger magnitudes the ULP only grows. Same `2^-22` term (and reasoning) as
|
|
19
|
+
* `near_band_from_extent` in `rust/geometry/src/kernel/mesh_bridge.rs` — see
|
|
20
|
+
* that function's doc for the derivation; kept here rather than shared
|
|
21
|
+
* because the two live in different language runtimes.
|
|
22
|
+
*/
|
|
23
|
+
const F32_ULP_SCALE = 1 / 4_194_304; // 2^-22
|
|
24
|
+
/**
|
|
25
|
+
* Penetration-depth floor below which a computed overlap cannot be
|
|
26
|
+
* distinguished from float32 rounding noise, scaled to the pair's own
|
|
27
|
+
* coordinate magnitude (not a fixed constant — infra models sit far from the
|
|
28
|
+
* origin, where a fixed epsilon would be far too tight, and small models sit
|
|
29
|
+
* near it, where a fixed epsilon would be far too loose).
|
|
30
|
+
*
|
|
31
|
+
* `rust/clash/src/tri_mesh.rs` ingests geometry from f32 buffers and stores/
|
|
32
|
+
* queries it in f64, so f64 arithmetic cannot recover precision the source
|
|
33
|
+
* data never had: two surfaces authored to be flush round to adjacent f32
|
|
34
|
+
* values, and the resulting "penetration" is bit-noise at the ULP of
|
|
35
|
+
* whichever operand coordinate is largest, not a measured overlap. Extent is
|
|
36
|
+
* the max abs coordinate over both elements' AABBs (world space, matching
|
|
37
|
+
* `near_band_from_extent`'s use of the actual compared coordinates) with a
|
|
38
|
+
* floor of 1.0 so a model near the origin still gets the single-unit ULP,
|
|
39
|
+
* not zero.
|
|
40
|
+
*
|
|
41
|
+
* The floor grows linearly with the pair's distance from the origin — that
|
|
42
|
+
* is the point, since f32 precision itself degrades the same way. The
|
|
43
|
+
* consequence: on a georeferenced model whose elements sit at real map
|
|
44
|
+
* coordinates (hundreds of kilometres out, which real IFC files do), the
|
|
45
|
+
* floor reaches decimetre scale, and a genuine clash below that threshold
|
|
46
|
+
* reclassifies as `touch`. That is not a bug in this function — at those
|
|
47
|
+
* magnitudes f32 genuinely cannot represent a finer distinction, so the
|
|
48
|
+
* "penetration" is not reliably measurable either way — but it means the
|
|
49
|
+
* floor tracks a limitation of the source data, not of clash detection.
|
|
50
|
+
* The fix for a model in that position is ingesting geometry closer to the
|
|
51
|
+
* origin (or in f64), not lowering this floor.
|
|
52
|
+
*/
|
|
53
|
+
function precisionFloor(elA, elB) {
|
|
54
|
+
let extent = 1.0;
|
|
55
|
+
for (const b of [elA.bounds, elB.bounds]) {
|
|
56
|
+
for (const v of [b.min, b.max]) {
|
|
57
|
+
for (const c of v) {
|
|
58
|
+
const a = Math.abs(c);
|
|
59
|
+
if (a > extent)
|
|
60
|
+
extent = a;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return extent * F32_ULP_SCALE;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Deepest penetration of `mesh`'s crossing-triangle VERTICES into `other`:
|
|
68
|
+
* the maximum distance-to-surface of `other` over the vertices of the
|
|
69
|
+
* triangles flagged in `crossFlags` (the pairs the narrow phase saw
|
|
70
|
+
* genuinely crossing `other`) that lie inside `other`. Each vertex is
|
|
71
|
+
* visited once (deduped by vertex index, in index order — bit-identical to
|
|
72
|
+
* the Rust `crossing_vertex_penetration`). Returns 0 when no flagged vertex
|
|
73
|
+
* is inside.
|
|
74
|
+
*
|
|
75
|
+
* This is NOT a depth metric and must never be reported as one — it is the
|
|
76
|
+
* sampling probe PR #2536 was held over (`maxPenetrationInto`): its value is
|
|
77
|
+
* an O(edge length) artifact that converges to 0 under retessellation
|
|
78
|
+
* instead of to the true depth. It survives with exactly one client: the
|
|
79
|
+
* f32 noise-floor gate for a CONTAINED pair (`depthClashResult`), where the
|
|
80
|
+
* question is not "how deep?" but "is any mesh-level penetration measurably
|
|
81
|
+
* above the floor at all?" — sub-floor here means every crossing vertex sits
|
|
82
|
+
* within f32 rounding noise of the other surface, i.e. surfaces authored
|
|
83
|
+
* flush, which no amount of retessellation turns into a real overlap. For
|
|
84
|
+
* that yes/no question the probe's underestimation is harmless:
|
|
85
|
+
* underestimating can only keep a pair BELOW the floor, and the floor is
|
|
86
|
+
* the very thing being tested.
|
|
87
|
+
*/
|
|
88
|
+
export function crossingVertexPenetration(mesh, other, crossFlags) {
|
|
89
|
+
const seen = new Uint8Array(mesh.vertexCount());
|
|
90
|
+
let depth = 0;
|
|
91
|
+
for (let t = 0; t < mesh.count; t += 1) {
|
|
92
|
+
if (crossFlags[t] === 0)
|
|
93
|
+
continue;
|
|
94
|
+
for (const vi of mesh.triIndices(t)) {
|
|
95
|
+
if (seen[vi] === 1)
|
|
96
|
+
continue;
|
|
97
|
+
seen[vi] = 1;
|
|
98
|
+
const v = mesh.vertex(vi);
|
|
99
|
+
if (!other.containsPoint(v))
|
|
100
|
+
continue;
|
|
101
|
+
const d = other.distanceToSurface(v);
|
|
102
|
+
if (d > depth)
|
|
103
|
+
depth = d;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return depth;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Turns the candidate penetration depths into the final `(status,
|
|
110
|
+
* distanceKind, distance)` triple. This is the ONLY place in the narrow
|
|
111
|
+
* phase allowed to build a `'mesh'`- or `'estimate'`-labelled `hard` result
|
|
112
|
+
* off a depth number — every branch in `narrow.ts` that can label a result
|
|
113
|
+
* `'mesh'` off `boxPenetration` (or its AABB-estimate fallback) MUST route
|
|
114
|
+
* through here rather than building the `NarrowResult` literal itself. That
|
|
115
|
+
* is what makes the f32 floor apply to all of them, and what enforces its
|
|
116
|
+
* precedence.
|
|
117
|
+
*
|
|
118
|
+
* THE FLOOR WINS (#2536 rebase decision): a pair below the f32 noise floor
|
|
119
|
+
* is `touch` regardless of how its depth was derived — at that magnitude the
|
|
120
|
+
* number is not measurable either way — so the floor is tested against EVERY
|
|
121
|
+
* candidate depth the pair has, not against whichever one the estimate-vs-
|
|
122
|
+
* mesh selection would report. Three candidates exist:
|
|
123
|
+
*
|
|
124
|
+
* - the AABB `estimate` (always present);
|
|
125
|
+
* - the box MTD, when both elements are certified boxes (`box`);
|
|
126
|
+
* - the crossing-vertex penetration, for a CONTAINED pair with a crossing
|
|
127
|
+
* vertex inside the other solid (`meshEvidence`) — evidence for this gate
|
|
128
|
+
* only, never a reported depth (see `crossingVertexPenetration`).
|
|
129
|
+
*
|
|
130
|
+
* The pair is `hard` only when the SMALLEST available candidate clears the
|
|
131
|
+
* floor. That is what makes the floor unreachable by depth-source selection:
|
|
132
|
+
* a sub-floor box MTD cannot be promoted by the through-penetration guard
|
|
133
|
+
* swapping in a larger AABB estimate; a sub-floor crossing-vertex
|
|
134
|
+
* penetration on a contained pair (surfaces authored flush — the eight
|
|
135
|
+
* Infra-Bridge pairs that moved #2594's 50-hard-clash pin to 58 when this
|
|
136
|
+
* PR's depth rework replaced their noise-scale mesh depth with the
|
|
137
|
+
* fabricated 4 m AABB estimate) cannot be promoted by that estimate; and a
|
|
138
|
+
* sub-floor AABB estimate cannot be promoted by a larger MTD (a through-
|
|
139
|
+
* penetration far from the origin, where the MTD is inflated by the
|
|
140
|
+
* piercing member's own extent). Only a pair already above the floor
|
|
141
|
+
* reaches the selection below, which then merely picks WHICH above-floor
|
|
142
|
+
* reportable number is used and how it is labelled — so a `hard` result's
|
|
143
|
+
* distance clears the floor by construction, whichever quantity it came
|
|
144
|
+
* from.
|
|
145
|
+
*/
|
|
146
|
+
export function depthClashResult(box, estimate, meshEvidence, elA, elB, rule, point, bounds) {
|
|
147
|
+
let floorDepth = estimate;
|
|
148
|
+
if (box != null && box.mtd < floorDepth)
|
|
149
|
+
floorDepth = box.mtd;
|
|
150
|
+
if (meshEvidence != null && meshEvidence < floorDepth)
|
|
151
|
+
floorDepth = meshEvidence;
|
|
152
|
+
if (floorDepth <= precisionFloor(elA, elB)) {
|
|
153
|
+
if (!rule.reportTouch)
|
|
154
|
+
return null;
|
|
155
|
+
// distance is exactly 0 here (the classification, not a measurement, is
|
|
156
|
+
// what changed), so `mesh` — consistent with the other exact-distance
|
|
157
|
+
// `touch` result.
|
|
158
|
+
return { status: 'touch', distance: 0, distanceKind: 'mesh', point, bounds };
|
|
159
|
+
}
|
|
160
|
+
// Estimate-vs-mesh selection, reachable only above the floor: the box MTD
|
|
161
|
+
// is certified (`mesh`) unless the pair is a through-penetration, where
|
|
162
|
+
// the AABB estimate is the honest number (see `boxPenetration`).
|
|
163
|
+
const measured = box != null && !box.through;
|
|
164
|
+
return {
|
|
165
|
+
status: 'hard',
|
|
166
|
+
distance: -(measured ? box.mtd : estimate),
|
|
167
|
+
distanceKind: measured ? 'mesh' : 'estimate',
|
|
168
|
+
point,
|
|
169
|
+
bounds,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=depth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth.js","sourceRoot":"","sources":["../../src/engine-ts/depth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
1
|
+
import type { AABB, ClashDistanceKind, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* One detected clash, in kernel terms: a pair of GLOBAL element indices plus the
|
|
4
4
|
* geometric verdict. The orchestrator turns this into a `Clash` (identity,
|
|
@@ -12,6 +12,8 @@ export interface NarrowRecord {
|
|
|
12
12
|
b: number;
|
|
13
13
|
status: ClashStatus;
|
|
14
14
|
distance: number;
|
|
15
|
+
/** Whether `distance` was measured on the meshes or estimated from the AABBs. */
|
|
16
|
+
distanceKind: ClashDistanceKind;
|
|
15
17
|
point: Vec3;
|
|
16
18
|
bounds: AABB;
|
|
17
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/engine-ts/kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/engine-ts/kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEvG;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IACV,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,YAAY,EAAE,iBAAiB,CAAC;IAChC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IACxC;;;;OAIG;IACH,UAAU,CACR,QAAQ,EAAE,YAAY,EAAE,EACxB,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EACvB,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM;IAChB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,WAAW;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1C,6DAA6D;IAC7D,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
1
|
+
import type { AABB, ClashDistanceKind, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
2
2
|
import type { TriMesh } from './tri-mesh.js';
|
|
3
3
|
export interface NarrowResult {
|
|
4
4
|
status: ClashStatus;
|
|
5
5
|
distance: number;
|
|
6
|
+
/**
|
|
7
|
+
* Whether `distance` was measured on the meshes or estimated from the AABBs.
|
|
8
|
+
* Set on every result, so a caller never has to guess which of the two very
|
|
9
|
+
* different quantities it is holding.
|
|
10
|
+
*/
|
|
11
|
+
distanceKind: ClashDistanceKind;
|
|
6
12
|
point: Vec3;
|
|
7
13
|
bounds: AABB;
|
|
8
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrow.d.ts","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"narrow.d.ts","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAKvG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;CACd;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,GAChB,YAAY,GAAG,IAAI,CA8PrB"}
|
package/dist/engine-ts/narrow.js
CHANGED
|
@@ -5,57 +5,7 @@ import { aabbContains, boundsOfPoints, center, inflate, overlapBounds, signedGap
|
|
|
5
5
|
import { centroid, mid } from '../math/vec3.js';
|
|
6
6
|
import { triTriIntersect } from '../math/triangle-intersect.js';
|
|
7
7
|
import { triTriDistance } from '../math/triangle-distance.js';
|
|
8
|
-
|
|
9
|
-
* f32-ULP scale factor for a "worst-case" single-precision coordinate: for a
|
|
10
|
-
* value with magnitude in `[2, 4)` the true float32 ULP is `2^-22`, and for
|
|
11
|
-
* larger magnitudes the ULP only grows. Same `2^-22` term (and reasoning) as
|
|
12
|
-
* `near_band_from_extent` in `rust/geometry/src/kernel/mesh_bridge.rs` — see
|
|
13
|
-
* that function's doc for the derivation; kept here rather than shared
|
|
14
|
-
* because the two live in different language runtimes.
|
|
15
|
-
*/
|
|
16
|
-
const F32_ULP_SCALE = 1 / 4_194_304; // 2^-22
|
|
17
|
-
/**
|
|
18
|
-
* Penetration-depth floor below which a computed overlap cannot be
|
|
19
|
-
* distinguished from float32 rounding noise, scaled to the pair's own
|
|
20
|
-
* coordinate magnitude (not a fixed constant — infra models sit far from the
|
|
21
|
-
* origin, where a fixed epsilon would be far too tight, and small models sit
|
|
22
|
-
* near it, where a fixed epsilon would be far too loose).
|
|
23
|
-
*
|
|
24
|
-
* `rust/clash/src/tri_mesh.rs` ingests geometry from f32 buffers and stores/
|
|
25
|
-
* queries it in f64, so f64 arithmetic cannot recover precision the source
|
|
26
|
-
* data never had: two surfaces authored to be flush round to adjacent f32
|
|
27
|
-
* values, and the resulting "penetration" is bit-noise at the ULP of
|
|
28
|
-
* whichever operand coordinate is largest, not a measured overlap. Extent is
|
|
29
|
-
* the max abs coordinate over both elements' AABBs (world space, matching
|
|
30
|
-
* `near_band_from_extent`'s use of the actual compared coordinates) with a
|
|
31
|
-
* floor of 1.0 so a model near the origin still gets the single-unit ULP,
|
|
32
|
-
* not zero.
|
|
33
|
-
*
|
|
34
|
-
* The floor grows linearly with the pair's distance from the origin — that
|
|
35
|
-
* is the point, since f32 precision itself degrades the same way. The
|
|
36
|
-
* consequence: on a georeferenced model whose elements sit at real map
|
|
37
|
-
* coordinates (hundreds of kilometres out, which real IFC files do), the
|
|
38
|
-
* floor reaches decimetre scale, and a genuine clash below that threshold
|
|
39
|
-
* reclassifies as `touch`. That is not a bug in this function — at those
|
|
40
|
-
* magnitudes f32 genuinely cannot represent a finer distinction, so the
|
|
41
|
-
* "penetration" is not reliably measurable either way — but it means the
|
|
42
|
-
* floor tracks a limitation of the source data, not of clash detection.
|
|
43
|
-
* The fix for a model in that position is ingesting geometry closer to the
|
|
44
|
-
* origin (or in f64), not lowering this floor.
|
|
45
|
-
*/
|
|
46
|
-
function precisionFloor(elA, elB) {
|
|
47
|
-
let extent = 1.0;
|
|
48
|
-
for (const b of [elA.bounds, elB.bounds]) {
|
|
49
|
-
for (const v of [b.min, b.max]) {
|
|
50
|
-
for (const c of v) {
|
|
51
|
-
const a = Math.abs(c);
|
|
52
|
-
if (a > extent)
|
|
53
|
-
extent = a;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return extent * F32_ULP_SCALE;
|
|
58
|
-
}
|
|
8
|
+
import { boxPenetration, crossingVertexPenetration, depthClashResult } from './depth.js';
|
|
59
9
|
/**
|
|
60
10
|
* Narrow-phase test for one candidate element pair.
|
|
61
11
|
*
|
|
@@ -75,10 +25,14 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
75
25
|
const aSmaller = triA.count <= triB.count;
|
|
76
26
|
const small = aSmaller ? triA : triB;
|
|
77
27
|
const large = aSmaller ? triB : triA;
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
// collect the crossing triangles
|
|
28
|
+
// A CONTAINED pair (one element's AABB wholly inside the other's) is the
|
|
29
|
+
// one class whose AABB estimate is fabricated — the signed gap reads the
|
|
30
|
+
// small element's own extent, not anything about the overlap (#1866) — so
|
|
31
|
+
// for such pairs collect the crossing triangles: their vertices are the
|
|
32
|
+
// mesh-level evidence `depthClashResult`'s f32 noise-floor gate needs (see
|
|
33
|
+
// `crossingVertexPenetration` — evidence for the floor test only, never a
|
|
34
|
+
// reported depth). Allocated only for contained pairs; every other pair
|
|
35
|
+
// has a genuine AABB overlap bound to floor-test instead.
|
|
82
36
|
const contained = aabbContains(elB.bounds, elA.bounds) || aabbContains(elA.bounds, elB.bounds);
|
|
83
37
|
const crossSmall = contained ? new Uint8Array(small.count) : null;
|
|
84
38
|
const crossLarge = contained ? new Uint8Array(large.count) : null;
|
|
@@ -198,33 +152,30 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
198
152
|
const point = contactN > 0
|
|
199
153
|
? [contactSumX / contactN, contactSumY / contactN, contactSumZ / contactN]
|
|
200
154
|
: center(overlap);
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
155
|
+
// Exact box-box penetration depth when both elements are rectangular
|
|
156
|
+
// boxes (see `boxPenetration`); otherwise fall back to the AABB overlap,
|
|
157
|
+
// i.e. the smallest overlapping box dimension. That fallback is an
|
|
158
|
+
// estimate, not a measured depth — for a non-box shape it can report a
|
|
159
|
+
// dimension of one of the elements rather than how far they interpenetrate.
|
|
160
|
+
// `depthClashResult` applies the f32 floor to EVERY candidate depth
|
|
161
|
+
// before any estimate-vs-mesh selection, so a pair below the floor
|
|
162
|
+
// reports `touch` regardless of which quantity would have been reported.
|
|
163
|
+
// For a contained pair the crossing-vertex penetration is that third
|
|
164
|
+
// candidate: the estimate is fabricated there (the small element's own
|
|
165
|
+
// extent), so without it a flush contained pair — whose only measurable
|
|
166
|
+
// penetration is f32 noise — would be promoted to `hard` at a number
|
|
167
|
+
// that measures nothing (the eight Infra-Bridge pairs, see
|
|
168
|
+
// `depthClashResult`).
|
|
169
|
+
let meshEvidence = null;
|
|
209
170
|
if (crossSmall !== null && crossLarge !== null) {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// cannot be distinguished from rounding noise (see `precisionFloor`),
|
|
217
|
-
// so it is not a measured overlap. Reclassify as `touch` rather than
|
|
218
|
-
// `hard` — the crossing still means the surfaces are in contact, which
|
|
219
|
-
// is real information (and this codebase already distinguishes touching
|
|
220
|
-
// from overlapping, e.g. the viewer's `clashHideTouching` toggle) —
|
|
221
|
-
// rather than silently dropping the pair or reporting a fabricated depth.
|
|
222
|
-
if (penetration <= precisionFloor(elA, elB)) {
|
|
223
|
-
if (!rule.reportTouch)
|
|
224
|
-
return null;
|
|
225
|
-
return { status: 'touch', distance: 0, point, bounds: contactBounds };
|
|
171
|
+
const d = Math.max(crossingVertexPenetration(small, large, crossSmall), crossingVertexPenetration(large, small, crossLarge));
|
|
172
|
+
// 0 means "no crossing vertex inside at all" (e.g. a thin member
|
|
173
|
+
// piercing straight through) — no evidence either way, not evidence
|
|
174
|
+
// of a sub-floor contact.
|
|
175
|
+
if (d > 0)
|
|
176
|
+
meshEvidence = d;
|
|
226
177
|
}
|
|
227
|
-
return
|
|
178
|
+
return depthClashResult(boxPenetration(small, large), Math.max(0, -signedGap(elA.bounds, elB.bounds)), meshEvidence, elA, elB, rule, point, contactBounds);
|
|
228
179
|
}
|
|
229
180
|
// Fully-enclosed solid: no surface crossing, but one element's AABB is wholly
|
|
230
181
|
// inside the other's, so it may be buried (e.g. equipment inside a slab). With
|
|
@@ -234,15 +185,18 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
234
185
|
// correctly returns "outside" when the inner sits in a concave notch.
|
|
235
186
|
// Test B-contains-A first, then A-contains-B, so the inner pick is
|
|
236
187
|
// deterministic (and identical to the Rust kernel) on equal AABBs.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
188
|
+
// Either way there is no surface crossing. When both elements are boxes the
|
|
189
|
+
// exact box-box depth is available (see `boxPenetration`) and is reported
|
|
190
|
+
// as measured; otherwise the AABB gap is an estimate, not a measured depth.
|
|
191
|
+
const enclosed = aabbContains(elB.bounds, elA.bounds)
|
|
192
|
+
? triA.count > 0 && triB.containsPoint(triA.tri(0)[0])
|
|
193
|
+
: aabbContains(elA.bounds, elB.bounds) && triB.count > 0 && triA.containsPoint(triB.tri(0)[0]);
|
|
194
|
+
if (enclosed) {
|
|
195
|
+
// `depthClashResult` may return `null` here (below the f32 floor and
|
|
196
|
+
// `!rule.reportTouch`) — that is a suppressed touch, not "no clash",
|
|
197
|
+
// so return it as-is rather than falling through to the coincide check
|
|
198
|
+
// below.
|
|
199
|
+
return depthClashResult(boxPenetration(small, large), -signedGap(elA.bounds, elB.bounds), null, elA, elB, rule, center(overlap), overlap);
|
|
246
200
|
}
|
|
247
201
|
if (minDist === Infinity) {
|
|
248
202
|
// Broad-phase candidate with no triangle-level proximity — not a clash.
|
|
@@ -270,12 +224,13 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
270
224
|
// actually coincide), clamped to the element overlap — not the whole-
|
|
271
225
|
// element AABB intersection, which for angled members spans nearly the
|
|
272
226
|
// full member length and sits away from the real contact (#1362/#1402).
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
227
|
+
// When both elements are boxes the exact box-box depth is available
|
|
228
|
+
// (see `boxPenetration`) and is reported as measured, not estimated.
|
|
229
|
+
// `depthClashResult` may return `null` (below the f32 floor and
|
|
230
|
+
// `!rule.reportTouch`) — a suppressed touch, not "no shared volume",
|
|
231
|
+
// so return it as-is rather than falling through to the face-touch
|
|
232
|
+
// handling meant for the "probes failed" case below.
|
|
233
|
+
return depthClashResult(boxPenetration(small, large), -gap, null, elA, elB, rule, mid(closestA, closestB), contactBounds);
|
|
279
234
|
}
|
|
280
235
|
// Only a face touch (no shared volume): fall through to the touch handling
|
|
281
236
|
// below, which suppresses it unless reportTouch is set.
|
|
@@ -288,6 +243,8 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
288
243
|
return {
|
|
289
244
|
status: 'clearance',
|
|
290
245
|
distance: minDist,
|
|
246
|
+
// `minDist` is an exact triangle-to-triangle distance.
|
|
247
|
+
distanceKind: 'mesh',
|
|
291
248
|
point: mid(closestA, closestB),
|
|
292
249
|
bounds: boundsOfPoints(closestA, closestB),
|
|
293
250
|
};
|
|
@@ -300,6 +257,7 @@ export function testPair(elA, triA, elB, triB, rule, tolerance) {
|
|
|
300
257
|
return {
|
|
301
258
|
status: 'touch',
|
|
302
259
|
distance: minDist,
|
|
260
|
+
distanceKind: 'mesh',
|
|
303
261
|
point: mid(closestA, closestB),
|
|
304
262
|
bounds: boundsOfPoints(closestA, closestB),
|
|
305
263
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrow.js","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAG/D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC1G,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"narrow.js","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact penetration depth for the one shape family it can be exact for:
|
|
3
|
+
* rectangular boxes. `maxPenetrationInto` (removed) measured the distance from
|
|
4
|
+
* the nearest crossing-triangle VERTEX to the other surface — an O(edge
|
|
5
|
+
* length) sampling artifact that converges to 0 as a mesh is retessellated,
|
|
6
|
+
* the opposite of what a depth metric should do (see the analytic-oracle
|
|
7
|
+
* fixtures in `obb.test.ts`).
|
|
8
|
+
*
|
|
9
|
+
* This module instead detects when both meshes ARE (within tolerance)
|
|
10
|
+
* axis-independent rectangular boxes and, only then, reports the minimum
|
|
11
|
+
* translation distance along a separating axis — the classical two-OBB
|
|
12
|
+
* penetration depth, which for boxes is provably exact and, because it is
|
|
13
|
+
* derived from the box's face-plane geometry rather than its triangulation,
|
|
14
|
+
* provably unchanged by retessellation. When either mesh is not confirmed to
|
|
15
|
+
* be a box, the caller falls back to the AABB estimate (never a wrong 'mesh'
|
|
16
|
+
* label) — a smaller true thing rather than a large wrong one.
|
|
17
|
+
*/
|
|
18
|
+
import type { Vec3 } from '../types.js';
|
|
19
|
+
/** Tolerance for normal-direction dedup and offset-plane clustering. Same
|
|
20
|
+
* literal in the Rust kernel — see `rust/clash/src/obb.rs`. */
|
|
21
|
+
export declare const OBB_EPS = 0.000001;
|
|
22
|
+
export interface Obb {
|
|
23
|
+
center: Vec3;
|
|
24
|
+
/** Three mutually orthogonal unit axes. */
|
|
25
|
+
axes: [Vec3, Vec3, Vec3];
|
|
26
|
+
/** Half-extent along each axis, matching `axes` by index. */
|
|
27
|
+
half: [number, number, number];
|
|
28
|
+
}
|
|
29
|
+
/** Minimal structural view of `TriMesh` this module needs — avoids a
|
|
30
|
+
* circular import between `obb.ts` and `tri-mesh.ts`. */
|
|
31
|
+
export interface MeshLike {
|
|
32
|
+
readonly count: number;
|
|
33
|
+
tri(t: number): [Vec3, Vec3, Vec3];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Detect whether `mesh` is a rectangular box: every (non-degenerate)
|
|
37
|
+
* triangle's normal falls into exactly 3 mutually orthogonal canonical
|
|
38
|
+
* directions, and every vertex of the triangles in a direction group lies on
|
|
39
|
+
* one of exactly two offset planes along that direction. That combination —
|
|
40
|
+
* 3 orthogonal face families, 2 planes each — forces the mesh to be a closed
|
|
41
|
+
* rectangular box (it rejects, for example, an axis-aligned L-shape, whose
|
|
42
|
+
* notch adds a third offset plane on two of the axes). Triangulation-
|
|
43
|
+
* independent: subdividing a box's faces adds triangles but never a new
|
|
44
|
+
* canonical direction or a third offset plane, so the detection (and the
|
|
45
|
+
* resulting `Obb`) is identical at any tessellation.
|
|
46
|
+
*
|
|
47
|
+
* Returns `null` — not a best-effort guess — when the check fails, so a
|
|
48
|
+
* caller that only trusts a non-null result never certifies a shape this
|
|
49
|
+
* function could not confirm.
|
|
50
|
+
*/
|
|
51
|
+
export declare function detectObb(mesh: MeshLike): Obb | null;
|
|
52
|
+
/**
|
|
53
|
+
* Bound, in f64 ulps, on the absolute error of one component of the cross
|
|
54
|
+
* product of two UNIT vectors (each component is a product-difference of
|
|
55
|
+
* magnitude-<=1 terms: ~2 ulps), with headroom for the normalisation and the
|
|
56
|
+
* per-projection dot rounding it feeds. Shared by the axis noise bound in
|
|
57
|
+
* {@link obbPenetrationDepth}; same literal in the Rust kernel.
|
|
58
|
+
*/
|
|
59
|
+
export declare const AXIS_NOISE_ULPS = 8;
|
|
60
|
+
/**
|
|
61
|
+
* Exact penetration depth between two oriented boxes: the minimum overlap
|
|
62
|
+
* over the 15 canonical OBB-OBB separating-axis candidates (each box's 3 face
|
|
63
|
+
* normals, plus the 9 pairwise cross products of one box's axes with the
|
|
64
|
+
* other's) — the standard result (Gottschalk, "Collision Queries using
|
|
65
|
+
* Oriented Bounding Boxes") that the minimum-translation-distance axis for two
|
|
66
|
+
* boxes is always among these 15.
|
|
67
|
+
*
|
|
68
|
+
* Cross-product candidates are conditioned by their length: both operands are
|
|
69
|
+
* unit axes, so `|L| = sin(angle between them)`, and normalising amplifies
|
|
70
|
+
* the ~ulp-level absolute error of the cross product into a direction error
|
|
71
|
+
* of up to `AXIS_NOISE_ULPS * EPS / |L|` radians. Each candidate's verdict
|
|
72
|
+
* therefore carries a SCALE-RELATIVE noise bound (see `testAxis`), and a
|
|
73
|
+
* verdict inside its own noise band is skipped — not trusted to separate,
|
|
74
|
+
* not trusted as a depth (review: #2536; the same
|
|
75
|
+
* tolerance-from-the-wrong-quantity class as #2598/#2600/#2529 — an earlier
|
|
76
|
+
* ABSOLUTE `len > 1e-6` guard here both divided by lengths whose noise
|
|
77
|
+
* dwarfs a thin overlap at large operand scale, and hard-dropped axes that
|
|
78
|
+
* were fine: for kilometre-scale near-parallel beams the dropped common
|
|
79
|
+
* normal IS the
|
|
80
|
+
* minimum-translation axis, and the min over the remaining axes over-reported
|
|
81
|
+
* a 0.02 m edge contact as a certified 0.45 m depth — see `obb.test.ts`).
|
|
82
|
+
*
|
|
83
|
+
* Returns `null` if any candidate axis reports, beyond its noise band, zero
|
|
84
|
+
* or negative overlap — the boxes would be separated along it, contradicting
|
|
85
|
+
* the caller's own crossing test — so a numerical edge case degrades to
|
|
86
|
+
* `null` (caller falls back to the AABB estimate) rather than reporting a
|
|
87
|
+
* wrong depth.
|
|
88
|
+
*/
|
|
89
|
+
export declare function obbPenetrationDepth(a: Obb, b: Obb): number | null;
|
|
90
|
+
/**
|
|
91
|
+
* Whether `a` and `b` are in a THROUGH-PENETRATION configuration: one box's
|
|
92
|
+
* cross-section, in the plane perpendicular to one of ITS OWN axes, is fully
|
|
93
|
+
* inside the other's footprint there, while along that axis it extends
|
|
94
|
+
* beyond the other and out the far side — a thin member piercing clean
|
|
95
|
+
* through a wall/slab, not a partial overlap. The relation is checked BOTH
|
|
96
|
+
* ways, so it also holds for the MUTUAL case: two walls crossing at an
|
|
97
|
+
* X-junction, each piercing the other clean through in thickness.
|
|
98
|
+
*
|
|
99
|
+
* This matters because {@link obbPenetrationDepth} reports the minimum
|
|
100
|
+
* TRANSLATION distance to separate the pair, which for this shape is
|
|
101
|
+
* dominated by the piercing member's own extent along the piercing axis, not
|
|
102
|
+
* by how much material it actually crossed (review: #2536 — a 2 m duct
|
|
103
|
+
* through a 200 mm wall reported 1.1 m, not 0.2 m). Detecting the shape lets
|
|
104
|
+
* the caller decline to certify that number as a measured depth.
|
|
105
|
+
*
|
|
106
|
+
* Tests containment against EACH box's own axes independently (via
|
|
107
|
+
* {@link piercesAlong}'s general per-axis projection, the same projection
|
|
108
|
+
* {@link obbPenetrationDepth} already computes for its 15 SAT candidates) —
|
|
109
|
+
* unlike an earlier version restricted to a frame shared by both boxes'
|
|
110
|
+
* axes up to sign, this also catches a member piercing through at a generic
|
|
111
|
+
* relative rotation (e.g. a duct crossing a wall at 15 degrees, review:
|
|
112
|
+
* #2536 follow-up — the earlier version measured -1.1177 there, `'mesh'`-
|
|
113
|
+
* labelled, against a true ~0.207 m).
|
|
114
|
+
*/
|
|
115
|
+
export declare function isThroughPenetration(a: Obb, b: Obb): boolean;
|
|
116
|
+
//# sourceMappingURL=obb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obb.d.ts","sourceRoot":"","sources":["../../src/engine-ts/obb.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC;+DAC+D;AAC/D,eAAO,MAAM,OAAO,WAAO,CAAC;AAE5B,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,IAAI,CAAC;IACb,2CAA2C;IAC3C,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACzB,6DAA6D;IAC7D,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;yDACyD;AACzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;CACpC;AAqBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,GAAG,IAAI,CA4EpD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAoEjE;AAkED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAK5D"}
|