opengeometry 2.0.8 → 2.0.10
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 +24 -27
- package/index.js +448 -83
- package/index.js.map +1 -1
- package/opengeometry/pkg/opengeometry.d.ts +145 -145
- package/opengeometry/pkg/opengeometry.js +126 -53
- package/opengeometry/pkg/opengeometry_bg.wasm +0 -0
- package/opengeometry/pkg/opengeometry_bg.wasm.d.ts +144 -144
- package/opengeometry_bg.wasm +0 -0
- package/opengeometry_bg.wasm.d.ts +144 -144
- package/package.json +1 -2
- package/src/examples/wall-from-offsets.d.ts +30 -1
- package/src/operations/boolean-errors.d.ts +90 -0
- package/src/operations/boolean.d.ts +26 -2
- package/src/operations/chamfer.d.ts +10 -0
- package/src/operations/draft.d.ts +14 -0
- package/src/operations/fillet.d.ts +13 -0
- package/src/operations/index.d.ts +1 -0
- package/src/operations/loft.d.ts +16 -0
- package/src/operations/mirror.d.ts +21 -0
- package/src/operations/pattern-circular.d.ts +19 -0
- package/src/operations/pattern-linear.d.ts +15 -0
- package/src/operations/pipe.d.ts +17 -0
- package/src/operations/revolve.d.ts +29 -0
- package/src/operations/sweep.d.ts +13 -0
- package/src/primitives/helix.d.ts +31 -0
- package/src/shapes/cone.d.ts +64 -0
- package/src/shapes/ellipsoid.d.ts +86 -0
- package/src/shapes/frustum.d.ts +44 -0
- package/src/shapes/torus.d.ts +44 -0
package/index.js
CHANGED
|
@@ -77,20 +77,69 @@ function handleError(f, args) {
|
|
|
77
77
|
wasm.__wbindgen_exn_store(idx);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
function debugString(val) {
|
|
81
|
+
// primitive types
|
|
82
|
+
const type = typeof val;
|
|
83
|
+
if (type == 'number' || type == 'boolean' || val == null) {
|
|
84
|
+
return `${val}`;
|
|
85
|
+
}
|
|
86
|
+
if (type == 'string') {
|
|
87
|
+
return `"${val}"`;
|
|
88
|
+
}
|
|
89
|
+
if (type == 'symbol') {
|
|
90
|
+
const description = val.description;
|
|
91
|
+
if (description == null) {
|
|
92
|
+
return 'Symbol';
|
|
93
|
+
} else {
|
|
94
|
+
return `Symbol(${description})`;
|
|
95
|
+
}
|
|
86
96
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
if (type == 'function') {
|
|
98
|
+
const name = val.name;
|
|
99
|
+
if (typeof name == 'string' && name.length > 0) {
|
|
100
|
+
return `Function(${name})`;
|
|
101
|
+
} else {
|
|
102
|
+
return 'Function';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// objects
|
|
106
|
+
if (Array.isArray(val)) {
|
|
107
|
+
const length = val.length;
|
|
108
|
+
let debug = '[';
|
|
109
|
+
if (length > 0) {
|
|
110
|
+
debug += debugString(val[0]);
|
|
111
|
+
}
|
|
112
|
+
for (let i = 1; i < length; i++) {
|
|
113
|
+
debug += ', ' + debugString(val[i]);
|
|
114
|
+
}
|
|
115
|
+
debug += ']';
|
|
116
|
+
return debug;
|
|
117
|
+
}
|
|
118
|
+
// Test for built-in
|
|
119
|
+
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
|
|
120
|
+
let className;
|
|
121
|
+
if (builtInMatches && builtInMatches.length > 1) {
|
|
122
|
+
className = builtInMatches[1];
|
|
123
|
+
} else {
|
|
124
|
+
// Failed to match the standard '[object ClassName]'
|
|
125
|
+
return toString.call(val);
|
|
126
|
+
}
|
|
127
|
+
if (className == 'Object') {
|
|
128
|
+
// we're a user defined class or Object
|
|
129
|
+
// JSON.stringify avoids problems with cycles, and is generally much
|
|
130
|
+
// easier than looping through ownProperties of `val`.
|
|
131
|
+
try {
|
|
132
|
+
return 'Object(' + JSON.stringify(val) + ')';
|
|
133
|
+
} catch (_) {
|
|
134
|
+
return 'Object';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// errors
|
|
138
|
+
if (val instanceof Error) {
|
|
139
|
+
return `${val.name}: ${val.message}\n${val.stack}`;
|
|
140
|
+
}
|
|
141
|
+
// TODO we could test for more things here, like `Set`s and `Map`s.
|
|
142
|
+
return className;
|
|
94
143
|
}
|
|
95
144
|
let WASM_VECTOR_LEN = 0;
|
|
96
145
|
const cachedTextEncoder = typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : {
|
|
@@ -138,6 +187,28 @@ function passStringToWasm0(arg, malloc, realloc) {
|
|
|
138
187
|
WASM_VECTOR_LEN = offset;
|
|
139
188
|
return ptr;
|
|
140
189
|
}
|
|
190
|
+
let cachedDataViewMemory0 = null;
|
|
191
|
+
function getDataViewMemory0() {
|
|
192
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
|
|
193
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
194
|
+
}
|
|
195
|
+
return cachedDataViewMemory0;
|
|
196
|
+
}
|
|
197
|
+
const cachedTextDecoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', {
|
|
198
|
+
ignoreBOM: true,
|
|
199
|
+
fatal: true
|
|
200
|
+
}) : {
|
|
201
|
+
decode: () => {
|
|
202
|
+
throw Error('TextDecoder not available');
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
if (typeof TextDecoder !== 'undefined') {
|
|
206
|
+
cachedTextDecoder.decode();
|
|
207
|
+
}
|
|
208
|
+
function getStringFromWasm0(ptr, len) {
|
|
209
|
+
ptr = ptr >>> 0;
|
|
210
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
211
|
+
}
|
|
141
212
|
function _assertClass(instance, klass) {
|
|
142
213
|
if (!(instance instanceof klass)) {
|
|
143
214
|
throw new Error(`expected instance of ${klass.name}`);
|
|
@@ -159,13 +230,6 @@ function getArrayF64FromWasm0(ptr, len) {
|
|
|
159
230
|
ptr = ptr >>> 0;
|
|
160
231
|
return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
161
232
|
}
|
|
162
|
-
let cachedDataViewMemory0 = null;
|
|
163
|
-
function getDataViewMemory0() {
|
|
164
|
-
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
|
|
165
|
-
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
166
|
-
}
|
|
167
|
-
return cachedDataViewMemory0;
|
|
168
|
-
}
|
|
169
233
|
function passArrayJsValueToWasm0(array, malloc) {
|
|
170
234
|
const ptr = malloc(array.length * 4, 4) >>> 0;
|
|
171
235
|
for (let i = 0; i < array.length; i++) {
|
|
@@ -175,42 +239,6 @@ function passArrayJsValueToWasm0(array, malloc) {
|
|
|
175
239
|
WASM_VECTOR_LEN = array.length;
|
|
176
240
|
return ptr;
|
|
177
241
|
}
|
|
178
|
-
/**
|
|
179
|
-
* @param {string} local_brep_serialized
|
|
180
|
-
* @param {number} height
|
|
181
|
-
* @returns {string}
|
|
182
|
-
*/
|
|
183
|
-
function extrudeBrepFace$1(local_brep_serialized, height) {
|
|
184
|
-
let deferred3_0;
|
|
185
|
-
let deferred3_1;
|
|
186
|
-
try {
|
|
187
|
-
const ptr0 = passStringToWasm0(local_brep_serialized, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
188
|
-
const len0 = WASM_VECTOR_LEN;
|
|
189
|
-
const ret = wasm.extrudeBrepFace(ptr0, len0, height);
|
|
190
|
-
var ptr2 = ret[0];
|
|
191
|
-
var len2 = ret[1];
|
|
192
|
-
if (ret[3]) {
|
|
193
|
-
ptr2 = 0;
|
|
194
|
-
len2 = 0;
|
|
195
|
-
throw takeFromExternrefTable0(ret[2]);
|
|
196
|
-
}
|
|
197
|
-
deferred3_0 = ptr2;
|
|
198
|
-
deferred3_1 = len2;
|
|
199
|
-
return getStringFromWasm0(ptr2, len2);
|
|
200
|
-
} finally {
|
|
201
|
-
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
function getArrayJsValueFromWasm0(ptr, len) {
|
|
205
|
-
ptr = ptr >>> 0;
|
|
206
|
-
const mem = getDataViewMemory0();
|
|
207
|
-
const result = [];
|
|
208
|
-
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
|
209
|
-
result.push(wasm.__wbindgen_export_2.get(mem.getUint32(i, true)));
|
|
210
|
-
}
|
|
211
|
-
wasm.__externref_drop_slice(ptr, len);
|
|
212
|
-
return result;
|
|
213
|
-
}
|
|
214
242
|
function isLikeNone(x) {
|
|
215
243
|
return x === undefined || x === null;
|
|
216
244
|
}
|
|
@@ -297,6 +325,43 @@ function booleanSubtractionMany(lhs_brep_serialized, cutters_brep_serialized, op
|
|
|
297
325
|
}
|
|
298
326
|
return OGBooleanResult.__wrap(ret[0]);
|
|
299
327
|
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @param {string} local_brep_serialized
|
|
331
|
+
* @param {number} height
|
|
332
|
+
* @returns {string}
|
|
333
|
+
*/
|
|
334
|
+
function extrudeBrepFace$1(local_brep_serialized, height) {
|
|
335
|
+
let deferred3_0;
|
|
336
|
+
let deferred3_1;
|
|
337
|
+
try {
|
|
338
|
+
const ptr0 = passStringToWasm0(local_brep_serialized, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
339
|
+
const len0 = WASM_VECTOR_LEN;
|
|
340
|
+
const ret = wasm.extrudeBrepFace(ptr0, len0, height);
|
|
341
|
+
var ptr2 = ret[0];
|
|
342
|
+
var len2 = ret[1];
|
|
343
|
+
if (ret[3]) {
|
|
344
|
+
ptr2 = 0;
|
|
345
|
+
len2 = 0;
|
|
346
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
347
|
+
}
|
|
348
|
+
deferred3_0 = ptr2;
|
|
349
|
+
deferred3_1 = len2;
|
|
350
|
+
return getStringFromWasm0(ptr2, len2);
|
|
351
|
+
} finally {
|
|
352
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function getArrayJsValueFromWasm0(ptr, len) {
|
|
356
|
+
ptr = ptr >>> 0;
|
|
357
|
+
const mem = getDataViewMemory0();
|
|
358
|
+
const result = [];
|
|
359
|
+
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
|
360
|
+
result.push(wasm.__wbindgen_export_2.get(mem.getUint32(i, true)));
|
|
361
|
+
}
|
|
362
|
+
wasm.__externref_drop_slice(ptr, len);
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
300
365
|
const Matrix3Finalization = typeof FinalizationRegistry === 'undefined' ? {
|
|
301
366
|
register: () => {},
|
|
302
367
|
unregister: () => {}
|
|
@@ -5370,7 +5435,7 @@ class OGWedge {
|
|
|
5370
5435
|
* @returns {Vector3}
|
|
5371
5436
|
*/
|
|
5372
5437
|
get_anchor() {
|
|
5373
|
-
const ret = wasm.
|
|
5438
|
+
const ret = wasm.ogwedge_get_anchor(this.__wbg_ptr);
|
|
5374
5439
|
return Vector3.__wrap(ret);
|
|
5375
5440
|
}
|
|
5376
5441
|
}
|
|
@@ -5706,6 +5771,13 @@ function __wbg_get_imports() {
|
|
|
5706
5771
|
const ret = Vector3.__unwrap(arg0);
|
|
5707
5772
|
return ret;
|
|
5708
5773
|
};
|
|
5774
|
+
imports.wbg.__wbindgen_debug_string = function (arg0, arg1) {
|
|
5775
|
+
const ret = debugString(arg1);
|
|
5776
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
5777
|
+
const len1 = WASM_VECTOR_LEN;
|
|
5778
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
5779
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
5780
|
+
};
|
|
5709
5781
|
imports.wbg.__wbindgen_init_externref_table = function () {
|
|
5710
5782
|
const table = wasm.__wbindgen_export_2;
|
|
5711
5783
|
const offset = table.grow(4);
|
|
@@ -7516,6 +7588,160 @@ function serializeBrepLike$1(value) {
|
|
|
7516
7588
|
return typeof value === "string" ? value : JSON.stringify(value);
|
|
7517
7589
|
}
|
|
7518
7590
|
|
|
7591
|
+
/**
|
|
7592
|
+
* Typed error hierarchy for boolean operations.
|
|
7593
|
+
*
|
|
7594
|
+
* The Rust kernel emits a structured `BooleanError` as JSON across the WASM
|
|
7595
|
+
* boundary (see `main/opengeometry/src/booleans/error.rs`). This module parses
|
|
7596
|
+
* that JSON and re-throws it as a typed `BooleanError` (or a more specific
|
|
7597
|
+
* subclass) so app code can `instanceof`-discriminate without parsing message
|
|
7598
|
+
* strings.
|
|
7599
|
+
*
|
|
7600
|
+
* Cutter indices are **0-based** to match `Vec` / array indexing on both
|
|
7601
|
+
* sides of the boundary.
|
|
7602
|
+
*/
|
|
7603
|
+
/**
|
|
7604
|
+
* Base class for every typed boolean error. Carries the structured payload the
|
|
7605
|
+
* kernel emitted across WASM. Specialized subclasses (`OverlappingCuttersError`,
|
|
7606
|
+
* `CutterExceedsHostError`, `NonManifoldOutputError`, `CoincidentFacesError`)
|
|
7607
|
+
* narrow the payload for the variants that carry extra fields.
|
|
7608
|
+
*/
|
|
7609
|
+
class BooleanError extends Error {
|
|
7610
|
+
constructor(payload) {
|
|
7611
|
+
super(payload.message);
|
|
7612
|
+
this.name = "BooleanError";
|
|
7613
|
+
this.reason = payload.kind.code;
|
|
7614
|
+
this.phase = payload.phase;
|
|
7615
|
+
this.cutterIndex = payload.cutter_index;
|
|
7616
|
+
this.details = payload.details;
|
|
7617
|
+
this.edgeSamples = payload.edge_samples
|
|
7618
|
+
? payload.edge_samples.map(([a, b]) => [
|
|
7619
|
+
new THREE.Vector3(a.x, a.y, a.z),
|
|
7620
|
+
new THREE.Vector3(b.x, b.y, b.z),
|
|
7621
|
+
])
|
|
7622
|
+
: null;
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7625
|
+
/**
|
|
7626
|
+
* Two cutters overlap each other. `otherIndex` is the 0-based index of the
|
|
7627
|
+
* cutter that conflicts with the one at `cutterIndex`.
|
|
7628
|
+
*/
|
|
7629
|
+
class OverlappingCuttersError extends BooleanError {
|
|
7630
|
+
constructor(payload) {
|
|
7631
|
+
var _a;
|
|
7632
|
+
super(payload);
|
|
7633
|
+
this.name = "OverlappingCuttersError";
|
|
7634
|
+
this.otherIndex = (_a = payload.kind.other_index) !== null && _a !== void 0 ? _a : -1;
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
/**
|
|
7638
|
+
* A cutter extends past the host's hull along the named axis.
|
|
7639
|
+
*/
|
|
7640
|
+
class CutterExceedsHostError extends BooleanError {
|
|
7641
|
+
constructor(payload) {
|
|
7642
|
+
var _a, _b;
|
|
7643
|
+
super(payload);
|
|
7644
|
+
this.name = "CutterExceedsHostError";
|
|
7645
|
+
const axis = ((_a = payload.kind.axis) !== null && _a !== void 0 ? _a : "x").toLowerCase();
|
|
7646
|
+
this.axis = (axis === "y" || axis === "z" ? axis : "x");
|
|
7647
|
+
this.overshoot = (_b = payload.kind.overshoot) !== null && _b !== void 0 ? _b : 0;
|
|
7648
|
+
}
|
|
7649
|
+
}
|
|
7650
|
+
/**
|
|
7651
|
+
* Output mesh has open or over-shared edges after a boolean. `edgeSamples`
|
|
7652
|
+
* carries up to ~8 sample non-manifold edges to aid app-side debugging.
|
|
7653
|
+
*/
|
|
7654
|
+
class NonManifoldOutputError extends BooleanError {
|
|
7655
|
+
constructor(payload) {
|
|
7656
|
+
super(payload);
|
|
7657
|
+
this.name = "NonManifoldOutputError";
|
|
7658
|
+
}
|
|
7659
|
+
}
|
|
7660
|
+
/**
|
|
7661
|
+
* Cutter and host share a coplanar face. Distinct from
|
|
7662
|
+
* `DegenerateTriangleError` (zero-area input) — see `06a-snap-tolerance.md`.
|
|
7663
|
+
*/
|
|
7664
|
+
class CoincidentFacesError extends BooleanError {
|
|
7665
|
+
constructor(payload) {
|
|
7666
|
+
super(payload);
|
|
7667
|
+
this.name = "CoincidentFacesError";
|
|
7668
|
+
}
|
|
7669
|
+
}
|
|
7670
|
+
/**
|
|
7671
|
+
* Parses a WASM-thrown error and returns the appropriate typed `BooleanError`
|
|
7672
|
+
* subclass. If the error's message is not valid `BooleanError` JSON, returns a
|
|
7673
|
+
* fallback `BooleanError` with `reason: "kernel_failure"` carrying the original
|
|
7674
|
+
* string, so callers always get a typed error and never have to `try/catch`
|
|
7675
|
+
* twice.
|
|
7676
|
+
*/
|
|
7677
|
+
function parseBooleanError(raw) {
|
|
7678
|
+
var _a, _b, _c, _d, _e;
|
|
7679
|
+
const message = extractMessage(raw);
|
|
7680
|
+
let payload = null;
|
|
7681
|
+
try {
|
|
7682
|
+
const parsed = JSON.parse(message);
|
|
7683
|
+
if (parsed && typeof parsed === "object" && parsed.kind && typeof parsed.kind === "object") {
|
|
7684
|
+
payload = {
|
|
7685
|
+
kind: parsed.kind,
|
|
7686
|
+
phase: ((_a = parsed.phase) !== null && _a !== void 0 ? _a : "input_validation"),
|
|
7687
|
+
cutter_index: (_b = parsed.cutter_index) !== null && _b !== void 0 ? _b : null,
|
|
7688
|
+
message: (_c = parsed.message) !== null && _c !== void 0 ? _c : message,
|
|
7689
|
+
details: (_d = parsed.details) !== null && _d !== void 0 ? _d : null,
|
|
7690
|
+
edge_samples: (_e = parsed.edge_samples) !== null && _e !== void 0 ? _e : null,
|
|
7691
|
+
};
|
|
7692
|
+
}
|
|
7693
|
+
}
|
|
7694
|
+
catch (_f) {
|
|
7695
|
+
payload = null;
|
|
7696
|
+
}
|
|
7697
|
+
if (!payload) {
|
|
7698
|
+
payload = {
|
|
7699
|
+
kind: { code: "kernel_failure" },
|
|
7700
|
+
phase: "input_validation",
|
|
7701
|
+
cutter_index: null,
|
|
7702
|
+
message,
|
|
7703
|
+
details: null,
|
|
7704
|
+
edge_samples: null,
|
|
7705
|
+
};
|
|
7706
|
+
}
|
|
7707
|
+
switch (payload.kind.code) {
|
|
7708
|
+
case "overlapping_cutters":
|
|
7709
|
+
return new OverlappingCuttersError(payload);
|
|
7710
|
+
case "cutter_exceeds_host":
|
|
7711
|
+
return new CutterExceedsHostError(payload);
|
|
7712
|
+
case "non_manifold_edges":
|
|
7713
|
+
case "open_shell":
|
|
7714
|
+
return new NonManifoldOutputError(payload);
|
|
7715
|
+
case "coincident_faces":
|
|
7716
|
+
return new CoincidentFacesError(payload);
|
|
7717
|
+
default:
|
|
7718
|
+
return new BooleanError(payload);
|
|
7719
|
+
}
|
|
7720
|
+
}
|
|
7721
|
+
function extractMessage(raw) {
|
|
7722
|
+
if (raw === null || raw === undefined) {
|
|
7723
|
+
return "";
|
|
7724
|
+
}
|
|
7725
|
+
if (typeof raw === "string") {
|
|
7726
|
+
return raw;
|
|
7727
|
+
}
|
|
7728
|
+
if (raw instanceof Error) {
|
|
7729
|
+
return raw.message;
|
|
7730
|
+
}
|
|
7731
|
+
if (typeof raw === "object" && "message" in raw) {
|
|
7732
|
+
const message = raw.message;
|
|
7733
|
+
if (typeof message === "string") {
|
|
7734
|
+
return message;
|
|
7735
|
+
}
|
|
7736
|
+
}
|
|
7737
|
+
try {
|
|
7738
|
+
return String(raw);
|
|
7739
|
+
}
|
|
7740
|
+
catch (_a) {
|
|
7741
|
+
return "Unknown boolean error";
|
|
7742
|
+
}
|
|
7743
|
+
}
|
|
7744
|
+
|
|
7519
7745
|
var _BooleanResult_outlineMesh;
|
|
7520
7746
|
const BOOLEAN_CREASE_ANGLE = Math.PI / 5;
|
|
7521
7747
|
const BOOLEAN_OUTLINE_THRESHOLD_DEGREES = 26;
|
|
@@ -7523,7 +7749,7 @@ const BOOLEAN_OUTLINE_THRESHOLD_DEGREES = 26;
|
|
|
7523
7749
|
* Renderable result mesh returned by the kernel boolean helpers.
|
|
7524
7750
|
*/
|
|
7525
7751
|
class BooleanResult extends THREE.Mesh {
|
|
7526
|
-
constructor(kernelResult, options,
|
|
7752
|
+
constructor(kernelResult, options, host = null) {
|
|
7527
7753
|
var _a, _b;
|
|
7528
7754
|
super();
|
|
7529
7755
|
this.report = null;
|
|
@@ -7537,11 +7763,43 @@ class BooleanResult extends THREE.Mesh {
|
|
|
7537
7763
|
this.ogid = getUUID();
|
|
7538
7764
|
this._fatOutlines = (_a = options === null || options === void 0 ? void 0 : options.fatOutlines) !== null && _a !== void 0 ? _a : false;
|
|
7539
7765
|
this._outlineWidth = sanitizeOutlineWidth(options === null || options === void 0 ? void 0 : options.outlineWidth);
|
|
7540
|
-
|
|
7766
|
+
const metadata = resolveOperandMetadata(host);
|
|
7767
|
+
if (metadata.name) {
|
|
7768
|
+
this.name = metadata.name;
|
|
7769
|
+
}
|
|
7770
|
+
if (metadata.userData) {
|
|
7771
|
+
this.userData = Object.assign({}, metadata.userData);
|
|
7772
|
+
}
|
|
7773
|
+
this.applyKernelResult(kernelResult, options, metadata.material);
|
|
7541
7774
|
if ((_b = options === null || options === void 0 ? void 0 : options.outline) !== null && _b !== void 0 ? _b : false) {
|
|
7542
7775
|
this.outline = true;
|
|
7543
7776
|
}
|
|
7544
7777
|
}
|
|
7778
|
+
/**
|
|
7779
|
+
* Updates the result mesh's color in place without re-running the boolean
|
|
7780
|
+
* pipeline. Accepts any value Three.js accepts (`number`, hex string, css
|
|
7781
|
+
* color name, or `THREE.Color`). No-op for materials without a `color` field.
|
|
7782
|
+
*/
|
|
7783
|
+
set color(value) {
|
|
7784
|
+
const apply = (material) => {
|
|
7785
|
+
if ("color" in material) {
|
|
7786
|
+
material.color.set(value);
|
|
7787
|
+
}
|
|
7788
|
+
material.needsUpdate = true;
|
|
7789
|
+
};
|
|
7790
|
+
if (Array.isArray(this.material)) {
|
|
7791
|
+
this.material.forEach(apply);
|
|
7792
|
+
return;
|
|
7793
|
+
}
|
|
7794
|
+
apply(this.material);
|
|
7795
|
+
}
|
|
7796
|
+
get color() {
|
|
7797
|
+
const material = Array.isArray(this.material) ? this.material[0] : this.material;
|
|
7798
|
+
if (!material || !("color" in material)) {
|
|
7799
|
+
return null;
|
|
7800
|
+
}
|
|
7801
|
+
return material.color;
|
|
7802
|
+
}
|
|
7545
7803
|
/**
|
|
7546
7804
|
* Rebuilds the mesh, cached BRep payload, and outline geometry from the kernel output.
|
|
7547
7805
|
*/
|
|
@@ -7683,12 +7941,21 @@ function executeBooleanSubtractionMany(lhs, cutters, options) {
|
|
|
7683
7941
|
}
|
|
7684
7942
|
const kernelFunction = booleanExport;
|
|
7685
7943
|
const kernelOptions = serializeKernelOptions(options === null || options === void 0 ? void 0 : options.kernel);
|
|
7686
|
-
|
|
7687
|
-
|
|
7944
|
+
let kernelResult;
|
|
7945
|
+
try {
|
|
7946
|
+
kernelResult = kernelFunction(resolveOperandSerialized(lhs), JSON.stringify(cutters.map(resolveOperandPayload)), kernelOptions);
|
|
7947
|
+
}
|
|
7948
|
+
catch (error) {
|
|
7949
|
+
throw parseBooleanError(error);
|
|
7950
|
+
}
|
|
7951
|
+
return createBooleanResult(kernelResult, options, lhs);
|
|
7688
7952
|
}
|
|
7689
7953
|
/**
|
|
7690
7954
|
* Normalizes mixed wrapper/raw operands, invokes the wasm boolean export, and
|
|
7691
7955
|
* returns the renderable result wrapper.
|
|
7956
|
+
*
|
|
7957
|
+
* @throws {BooleanError} (or a subclass) when the kernel rejects the operation.
|
|
7958
|
+
* See `boolean-errors.ts` for the typed hierarchy.
|
|
7692
7959
|
*/
|
|
7693
7960
|
function executeBoolean(exportName, lhs, rhs, options) {
|
|
7694
7961
|
const booleanExport = OGKernel[exportName];
|
|
@@ -7697,8 +7964,14 @@ function executeBoolean(exportName, lhs, rhs, options) {
|
|
|
7697
7964
|
}
|
|
7698
7965
|
const kernelFunction = booleanExport;
|
|
7699
7966
|
const kernelOptions = serializeKernelOptions(options === null || options === void 0 ? void 0 : options.kernel);
|
|
7700
|
-
|
|
7701
|
-
|
|
7967
|
+
let kernelResult;
|
|
7968
|
+
try {
|
|
7969
|
+
kernelResult = kernelFunction(resolveOperandSerialized(lhs), resolveOperandSerialized(rhs), kernelOptions);
|
|
7970
|
+
}
|
|
7971
|
+
catch (error) {
|
|
7972
|
+
throw parseBooleanError(error);
|
|
7973
|
+
}
|
|
7974
|
+
return createBooleanResult(kernelResult, options, lhs);
|
|
7702
7975
|
}
|
|
7703
7976
|
/**
|
|
7704
7977
|
* Accepts wrapper objects, raw BRep data, or serialized JSON and normalizes
|
|
@@ -7754,33 +8027,40 @@ function serializeKernelOptions(options) {
|
|
|
7754
8027
|
merge_coplanar_faces: options.mergeCoplanarFaces,
|
|
7755
8028
|
});
|
|
7756
8029
|
}
|
|
7757
|
-
function createBooleanResult(kernelResult, options,
|
|
8030
|
+
function createBooleanResult(kernelResult, options, host = null) {
|
|
7758
8031
|
var _a;
|
|
7759
|
-
const result = new BooleanResult(kernelResult, options,
|
|
8032
|
+
const result = new BooleanResult(kernelResult, options, host);
|
|
7760
8033
|
if ((_a = options === null || options === void 0 ? void 0 : options.outline) !== null && _a !== void 0 ? _a : true) {
|
|
7761
8034
|
result.outline = true;
|
|
7762
8035
|
}
|
|
7763
8036
|
return result;
|
|
7764
8037
|
}
|
|
7765
8038
|
/**
|
|
7766
|
-
* Returns
|
|
7767
|
-
* subclass (Solid, Polygon, Cuboid, Opening, BooleanResult,
|
|
7768
|
-
*
|
|
7769
|
-
*
|
|
8039
|
+
* Returns the material, name, and userData carried on the operand when it is
|
|
8040
|
+
* a Three mesh subclass (Solid, Polygon, Cuboid, Opening, BooleanResult,
|
|
8041
|
+
* etc.) so the result mesh can drop into a scene graph as-is. Falls back to
|
|
8042
|
+
* empty metadata for serialized JSON, parsed BRep objects, or anything else
|
|
8043
|
+
* without a reachable host mesh.
|
|
7770
8044
|
*/
|
|
7771
|
-
function
|
|
7772
|
-
var _a;
|
|
7773
|
-
|
|
7774
|
-
|
|
8045
|
+
function resolveOperandMetadata(operand) {
|
|
8046
|
+
var _a, _b, _c;
|
|
8047
|
+
const empty = { material: null, name: "", userData: null };
|
|
8048
|
+
if (operand === null || typeof operand !== "object" || !(operand instanceof THREE.Mesh)) {
|
|
8049
|
+
return empty;
|
|
7775
8050
|
}
|
|
7776
|
-
|
|
7777
|
-
|
|
8051
|
+
const rawMaterial = operand.material;
|
|
8052
|
+
let material = null;
|
|
8053
|
+
if (Array.isArray(rawMaterial)) {
|
|
8054
|
+
material = (_a = rawMaterial[0]) !== null && _a !== void 0 ? _a : null;
|
|
7778
8055
|
}
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
return (_a = material[0]) !== null && _a !== void 0 ? _a : null;
|
|
8056
|
+
else if (rawMaterial instanceof THREE.Material) {
|
|
8057
|
+
material = rawMaterial;
|
|
7782
8058
|
}
|
|
7783
|
-
return
|
|
8059
|
+
return {
|
|
8060
|
+
material,
|
|
8061
|
+
name: (_b = operand.name) !== null && _b !== void 0 ? _b : "",
|
|
8062
|
+
userData: (_c = operand.userData) !== null && _c !== void 0 ? _c : null,
|
|
8063
|
+
};
|
|
7784
8064
|
}
|
|
7785
8065
|
/**
|
|
7786
8066
|
* Builds the boolean result mesh's material by cloning the host (LHS) material
|
|
@@ -7794,8 +8074,8 @@ function buildResultMaterial(sourceMaterial, options) {
|
|
|
7794
8074
|
? sourceMaterial.clone()
|
|
7795
8075
|
: new THREE.MeshStandardMaterial({
|
|
7796
8076
|
color: 0x2563eb,
|
|
7797
|
-
transparent:
|
|
7798
|
-
opacity:
|
|
8077
|
+
transparent: false,
|
|
8078
|
+
opacity: 1,
|
|
7799
8079
|
side: THREE.FrontSide,
|
|
7800
8080
|
});
|
|
7801
8081
|
if ((options === null || options === void 0 ? void 0 : options.color) !== undefined && "color" in material) {
|
|
@@ -10436,7 +10716,61 @@ function buildWallOutline(left, right) {
|
|
|
10436
10716
|
}
|
|
10437
10717
|
return outline;
|
|
10438
10718
|
}
|
|
10439
|
-
function
|
|
10719
|
+
function midpoint(a, b) {
|
|
10720
|
+
return new Vector3((a.x + b.x) * 0.5, (a.y + b.y) * 0.5, (a.z + b.z) * 0.5);
|
|
10721
|
+
}
|
|
10722
|
+
function buildDoorCutters(centerlinePoints, count, overshootMeters, wallThickness, doorHeight) {
|
|
10723
|
+
const cutters = [];
|
|
10724
|
+
const wallDepth = wallThickness + 2 * overshootMeters;
|
|
10725
|
+
const doorWidth = 0.6;
|
|
10726
|
+
const segments = centerlinePoints.length - 1;
|
|
10727
|
+
const stride = Math.max(1, Math.floor(segments / count));
|
|
10728
|
+
for (let doorIdx = 0; doorIdx < count; doorIdx++) {
|
|
10729
|
+
const segmentIdx = Math.min(segments - 1, doorIdx * stride);
|
|
10730
|
+
const a = centerlinePoints[segmentIdx];
|
|
10731
|
+
const b = centerlinePoints[segmentIdx + 1];
|
|
10732
|
+
const mid = midpoint(a, b);
|
|
10733
|
+
cutters.push(new Cuboid({
|
|
10734
|
+
width: doorWidth,
|
|
10735
|
+
height: doorHeight,
|
|
10736
|
+
depth: wallDepth,
|
|
10737
|
+
center: new Vector3(0, 0, 0),
|
|
10738
|
+
translation: new Vector3(mid.x, doorHeight * 0.5 + 0.001, mid.z),
|
|
10739
|
+
color: 0xef4444,
|
|
10740
|
+
}));
|
|
10741
|
+
}
|
|
10742
|
+
return cutters;
|
|
10743
|
+
}
|
|
10744
|
+
/**
|
|
10745
|
+
* Renders a human-readable description for a typed `BooleanError` (or any
|
|
10746
|
+
* other thrown value). Used by the example HTML to surface kernel failures
|
|
10747
|
+
* in a status panel without losing the structured payload.
|
|
10748
|
+
*/
|
|
10749
|
+
function describeWallSubtractError(error) {
|
|
10750
|
+
var _a, _b, _c, _d, _e;
|
|
10751
|
+
if (error instanceof OverlappingCuttersError) {
|
|
10752
|
+
return `OverlappingCuttersError @ cutter #${error.cutterIndex} (other #${error.otherIndex}): ${(_a = error.details) !== null && _a !== void 0 ? _a : error.message}`;
|
|
10753
|
+
}
|
|
10754
|
+
if (error instanceof CutterExceedsHostError) {
|
|
10755
|
+
return `CutterExceedsHostError: cutter overshoots ${error.axis} by ${error.overshoot.toExponential(3)}`;
|
|
10756
|
+
}
|
|
10757
|
+
if (error instanceof CoincidentFacesError) {
|
|
10758
|
+
return `CoincidentFacesError: ${(_b = error.details) !== null && _b !== void 0 ? _b : error.message}`;
|
|
10759
|
+
}
|
|
10760
|
+
if (error instanceof NonManifoldOutputError) {
|
|
10761
|
+
const samples = (_d = (_c = error.edgeSamples) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
10762
|
+
return `NonManifoldOutputError: ${samples} non-manifold edges sampled — ${(_e = error.details) !== null && _e !== void 0 ? _e : error.message}`;
|
|
10763
|
+
}
|
|
10764
|
+
if (error instanceof BooleanError) {
|
|
10765
|
+
return `BooleanError (${error.reason}, phase ${error.phase}): ${error.message}`;
|
|
10766
|
+
}
|
|
10767
|
+
if (error instanceof Error) {
|
|
10768
|
+
return `Untyped error: ${error.message}`;
|
|
10769
|
+
}
|
|
10770
|
+
return `Untyped error: ${String(error)}`;
|
|
10771
|
+
}
|
|
10772
|
+
function createWallFromOffsetsExample(scene, options = {}) {
|
|
10773
|
+
var _a, _b, _c, _d;
|
|
10440
10774
|
const centerline = new Polyline({
|
|
10441
10775
|
points: [
|
|
10442
10776
|
new Vector3(-2.6, 0.0, -1.9),
|
|
@@ -10452,6 +10786,7 @@ function createWallFromOffsetsExample(scene) {
|
|
|
10452
10786
|
const half = wallThickness * 0.5;
|
|
10453
10787
|
const acuteThreshold = 35.0;
|
|
10454
10788
|
const bevel = true;
|
|
10789
|
+
const wallHeight = (_a = options.height) !== null && _a !== void 0 ? _a : 2.6;
|
|
10455
10790
|
const leftOffset = centerline.getOffset(half, acuteThreshold, bevel);
|
|
10456
10791
|
const rightOffset = centerline.getOffset(-0.225, acuteThreshold, bevel);
|
|
10457
10792
|
const leftOffsetPolyline = new Polyline({
|
|
@@ -10475,6 +10810,34 @@ function createWallFromOffsetsExample(scene) {
|
|
|
10475
10810
|
scene.add(leftOffsetPolyline);
|
|
10476
10811
|
scene.add(rightOffsetPolyline);
|
|
10477
10812
|
scene.add(wallPolygon);
|
|
10813
|
+
let cutResult = null;
|
|
10814
|
+
let cutError = null;
|
|
10815
|
+
if (((_b = options.doorCount) !== null && _b !== void 0 ? _b : 0) > 0) {
|
|
10816
|
+
const overshootMeters = ((_c = options.overshootMm) !== null && _c !== void 0 ? _c : 1) * 0.001;
|
|
10817
|
+
const wallSolid = wallPolygon.extrude(wallHeight);
|
|
10818
|
+
const cutters = buildDoorCutters([
|
|
10819
|
+
new Vector3(-2.6, 0.0, -1.9),
|
|
10820
|
+
new Vector3(-1.2, 0.0, -1),
|
|
10821
|
+
new Vector3(-0.2, 0.0, 0.1),
|
|
10822
|
+
new Vector3(0.6, 0.0, 0.2),
|
|
10823
|
+
new Vector3(0.1, 0.0, 1.0),
|
|
10824
|
+
new Vector3(2.6, 0.0, 2.0),
|
|
10825
|
+
], (_d = options.doorCount) !== null && _d !== void 0 ? _d : 0, overshootMeters, wallThickness, 2.1);
|
|
10826
|
+
try {
|
|
10827
|
+
const cutWall = wallSolid.subtract(cutters, {
|
|
10828
|
+
color: 0x3b82f6,
|
|
10829
|
+
transparent: false,
|
|
10830
|
+
opacity: 1,
|
|
10831
|
+
});
|
|
10832
|
+
scene.add(cutWall);
|
|
10833
|
+
cutResult = { wall: cutWall, cutters };
|
|
10834
|
+
}
|
|
10835
|
+
catch (error) {
|
|
10836
|
+
cutError = error;
|
|
10837
|
+
scene.add(wallSolid);
|
|
10838
|
+
cutResult = { wall: wallSolid, cutters };
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10478
10841
|
return {
|
|
10479
10842
|
centerline,
|
|
10480
10843
|
leftOffsetPolyline,
|
|
@@ -10482,6 +10845,8 @@ function createWallFromOffsetsExample(scene) {
|
|
|
10482
10845
|
wallPolygon,
|
|
10483
10846
|
leftOffset,
|
|
10484
10847
|
rightOffset,
|
|
10848
|
+
cutResult,
|
|
10849
|
+
cutError,
|
|
10485
10850
|
};
|
|
10486
10851
|
}
|
|
10487
10852
|
|
|
@@ -10844,5 +11209,5 @@ class OpenGeometry {
|
|
|
10844
11209
|
OpenGeometry.version = OPEN_GEOMETRY_THREE_VERSION;
|
|
10845
11210
|
OpenGeometry.instance = null;
|
|
10846
11211
|
|
|
10847
|
-
export { Arc, BooleanResult, Cuboid, Curve, Cylinder, FreeformEditor, FreeformGeometry, Line, OGSceneManager, OpenGeometry, Opening, Polygon, Polyline, Rectangle, Solid, Sphere, SpotLabel, Sweep, Vector3, Wedge, booleanIntersection, booleanSubtraction, booleanUnion, clonePlacement, createBooleanExample, createEditorModesExample, createFreeformEditor, createFreeformGeometry, createOffsetExample, createParametricEditCapabilities, createPrimitivesExample, createShapesExample, createSweepExample, createWallFromOffsetsExample, executeBooleanSubtractionMany, extrudeBrepFace, toObjectTransformation$1 as toObjectTransformation };
|
|
11212
|
+
export { Arc, BooleanError, BooleanResult, CoincidentFacesError, Cuboid, Curve, CutterExceedsHostError, Cylinder, FreeformEditor, FreeformGeometry, Line, NonManifoldOutputError, OGSceneManager, OpenGeometry, Opening, OverlappingCuttersError, Polygon, Polyline, Rectangle, Solid, Sphere, SpotLabel, Sweep, Vector3, Wedge, booleanIntersection, booleanSubtraction, booleanUnion, clonePlacement, createBooleanExample, createEditorModesExample, createFreeformEditor, createFreeformGeometry, createOffsetExample, createParametricEditCapabilities, createPrimitivesExample, createShapesExample, createSweepExample, createWallFromOffsetsExample, describeWallSubtractError, executeBooleanSubtractionMany, extrudeBrepFace, parseBooleanError, toObjectTransformation$1 as toObjectTransformation };
|
|
10848
11213
|
//# sourceMappingURL=index.js.map
|