@iyulab/u-nesting 0.4.0 → 0.5.1

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 CHANGED
@@ -11,6 +11,13 @@
11
11
  npm install @iyulab/u-nesting
12
12
  ```
13
13
 
14
+ The package resolves per environment via a conditional `exports` map:
15
+
16
+ | Environment | Entry |
17
+ |---|---|
18
+ | Bundlers (webpack, Vite, …) | ESM + WebAssembly ESM-integration (`default` condition) |
19
+ | Node.js — `require()`, ESM `import`, CJS TS runners (`tsx`, `ts-node`) | CJS glue loading the wasm from the filesystem (`node` condition) — no loader hooks or flags |
20
+
14
21
  ## Functions
15
22
 
16
23
  | Function | Description |
@@ -28,9 +35,7 @@ All functions use **JSON string I/O**.
28
35
  ### 2D Nesting
29
36
 
30
37
  ```javascript
31
- import init, { solve_2d } from '@iyulab/u-nesting';
32
-
33
- await init();
38
+ import { solve_2d } from '@iyulab/u-nesting';
34
39
 
35
40
  const result = JSON.parse(solve_2d(JSON.stringify({
36
41
  geometries: [
@@ -64,9 +69,7 @@ console.log(result);
64
69
  ### 3D Bin Packing
65
70
 
66
71
  ```javascript
67
- import init, { solve_3d } from '@iyulab/u-nesting';
68
-
69
- await init();
72
+ import { solve_3d } from '@iyulab/u-nesting';
70
73
 
71
74
  const result = JSON.parse(solve_3d(JSON.stringify({
72
75
  geometries: [
@@ -89,9 +92,7 @@ const result = JSON.parse(solve_3d(JSON.stringify({
89
92
  ### Cutting Path Optimization
90
93
 
91
94
  ```javascript
92
- import init, { solve_2d, optimize_cutting_path } from '@iyulab/u-nesting';
93
-
94
- await init();
95
+ import { solve_2d, optimize_cutting_path } from '@iyulab/u-nesting';
95
96
 
96
97
  // First solve the nesting problem
97
98
  const solveResult = JSON.parse(solve_2d(JSON.stringify({ /* ... */ })));
@@ -139,10 +140,32 @@ interface Request2D {
139
140
  mutation_rate?: number; // Mutation rate (default: 0.1)
140
141
  time_limit_ms?: number; // Time limit in ms
141
142
  target_utilization?: number; // Stop early if reached
143
+ multi_sheet?: boolean; // Spill overflow onto extra sheets (default: false)
142
144
  };
143
145
  }
144
146
  ```
145
147
 
148
+ ### Multi-Sheet Nesting
149
+
150
+ By default `solve_2d` packs into a **single** sheet; parts that do not fit become
151
+ `unplaced`. Set `config.multi_sheet: true` to spill overflow onto **additional
152
+ sheets**. Then:
153
+
154
+ - `sheets_used` reports how many sheets were needed.
155
+ - each placement's `sheet_index` selects its sheet.
156
+ - placement `x`/`y` are **sheet-local** — relative to that sheet's own origin —
157
+ so you can render one panel per sheet without subtracting any offset.
158
+
159
+ ```javascript
160
+ const res = JSON.parse(solve_2d(JSON.stringify({
161
+ geometries: [{ id: "part", polygon: [[0,0],[100,0],[100,100],[0,100]], quantity: 20 }],
162
+ boundary: { width: 300, height: 300 },
163
+ config: { strategy: "blf", multi_sheet: true }
164
+ })));
165
+ // res.sheets_used === 3, res.placements.length === 20, res.unplaced === []
166
+ // group placements by sheet_index to draw each sheet
167
+ ```
168
+
146
169
  ### Available 2D Strategies
147
170
 
148
171
  | Strategy | Description |
@@ -180,12 +203,15 @@ interface SolveResponse {
180
203
  x: number;
181
204
  y: number;
182
205
  rotation: number; // degrees
183
- sheet_index: number; // 0-based sheet/bin index
206
+ sheet_index: number; // 0-based sheet/bin index (see config.multi_sheet)
184
207
  flipped: boolean; // mirrored
185
208
  }[];
186
- sheets_used: number;
209
+ sheets_used: number; // >1 only when config.multi_sheet is true
187
210
  utilization: number;
188
- unplaced: string[];
211
+ total_requested: number; // Σ of every geometry's quantity (instance-level).
212
+ // unplaced instances = total_requested - placements.length
213
+ unplaced: string[]; // deduplicated geometry ids (NOT per-instance), so
214
+ // unplaced.length under-reports the failed-instance count
189
215
  elapsed_ms: number;
190
216
  }
191
217
  ```
@@ -208,7 +234,10 @@ interface Pack3DResponse {
208
234
  }[];
209
235
  bins_used: number;
210
236
  utilization: number;
211
- unplaced: string[];
237
+ total_requested: number; // Σ of every geometry's quantity (instance-level).
238
+ // unplaced instances = total_requested - placements.length
239
+ unplaced: string[]; // deduplicated geometry ids (NOT per-instance), so
240
+ // unplaced.length under-reports the failed-instance count
212
241
  elapsed_ms: number;
213
242
  }
214
243
  ```
@@ -0,0 +1,311 @@
1
+ /* @ts-self-types="./u_nesting_wasm.d.cts" */
2
+
3
+ /**
4
+ * Returns a JSON array of available strategy names for WASM builds.
5
+ *
6
+ * MILP and HybridExact are not available in WASM (requires native HiGHS solver).
7
+ * @returns {string}
8
+ */
9
+ function available_strategies() {
10
+ let deferred1_0;
11
+ let deferred1_1;
12
+ try {
13
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
14
+ wasm.available_strategies(retptr);
15
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
16
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
17
+ deferred1_0 = r0;
18
+ deferred1_1 = r1;
19
+ return getStringFromWasm0(r0, r1);
20
+ } finally {
21
+ wasm.__wbindgen_add_to_stack_pointer(16);
22
+ wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
23
+ }
24
+ }
25
+ exports.available_strategies = available_strategies;
26
+
27
+ /**
28
+ * Optimizes cutting path for placed 2D parts.
29
+ *
30
+ * Input must include geometries, a previous solve result, and optional cutting config.
31
+ * Returns a JSON string with the cutting path result.
32
+ * On error, returns `{ "success": false, "error": "..." }`.
33
+ * @param {string} request_json
34
+ * @returns {string}
35
+ */
36
+ function optimize_cutting_path(request_json) {
37
+ let deferred2_0;
38
+ let deferred2_1;
39
+ try {
40
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
41
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
42
+ const len0 = WASM_VECTOR_LEN;
43
+ wasm.optimize_cutting_path(retptr, ptr0, len0);
44
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
45
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
46
+ deferred2_0 = r0;
47
+ deferred2_1 = r1;
48
+ return getStringFromWasm0(r0, r1);
49
+ } finally {
50
+ wasm.__wbindgen_add_to_stack_pointer(16);
51
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
52
+ }
53
+ }
54
+ exports.optimize_cutting_path = optimize_cutting_path;
55
+
56
+ /**
57
+ * Solves a 2D nesting problem from a JSON request string.
58
+ *
59
+ * Returns a JSON string with the solve result.
60
+ * On error, returns `{ "success": false, "error": "..." }`.
61
+ * @param {string} request_json
62
+ * @returns {string}
63
+ */
64
+ function solve_2d(request_json) {
65
+ let deferred2_0;
66
+ let deferred2_1;
67
+ try {
68
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
69
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
70
+ const len0 = WASM_VECTOR_LEN;
71
+ wasm.solve_2d(retptr, ptr0, len0);
72
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
73
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
74
+ deferred2_0 = r0;
75
+ deferred2_1 = r1;
76
+ return getStringFromWasm0(r0, r1);
77
+ } finally {
78
+ wasm.__wbindgen_add_to_stack_pointer(16);
79
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
80
+ }
81
+ }
82
+ exports.solve_2d = solve_2d;
83
+
84
+ /**
85
+ * Solves a 3D bin packing problem from a JSON request string.
86
+ *
87
+ * Returns a JSON string with the solve result.
88
+ * On error, returns `{ "success": false, "error": "..." }`.
89
+ * @param {string} request_json
90
+ * @returns {string}
91
+ */
92
+ function solve_3d(request_json) {
93
+ let deferred2_0;
94
+ let deferred2_1;
95
+ try {
96
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
97
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
98
+ const len0 = WASM_VECTOR_LEN;
99
+ wasm.solve_3d(retptr, ptr0, len0);
100
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
101
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
102
+ deferred2_0 = r0;
103
+ deferred2_1 = r1;
104
+ return getStringFromWasm0(r0, r1);
105
+ } finally {
106
+ wasm.__wbindgen_add_to_stack_pointer(16);
107
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
108
+ }
109
+ }
110
+ exports.solve_3d = solve_3d;
111
+
112
+ /**
113
+ * Returns the API version string.
114
+ * @returns {string}
115
+ */
116
+ function version() {
117
+ let deferred1_0;
118
+ let deferred1_1;
119
+ try {
120
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
121
+ wasm.version(retptr);
122
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
123
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
124
+ deferred1_0 = r0;
125
+ deferred1_1 = r1;
126
+ return getStringFromWasm0(r0, r1);
127
+ } finally {
128
+ wasm.__wbindgen_add_to_stack_pointer(16);
129
+ wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
130
+ }
131
+ }
132
+ exports.version = version;
133
+ function __wbg_get_imports() {
134
+ const import0 = {
135
+ __proto__: null,
136
+ __wbg___wbindgen_is_undefined_c05833b95a3cf397: function(arg0) {
137
+ const ret = getObject(arg0) === undefined;
138
+ return ret;
139
+ },
140
+ __wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
141
+ throw new Error(getStringFromWasm0(arg0, arg1));
142
+ },
143
+ __wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
144
+ globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
145
+ }, arguments); },
146
+ __wbg_now_e7c6795a7f81e10f: function(arg0) {
147
+ const ret = getObject(arg0).now();
148
+ return ret;
149
+ },
150
+ __wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
151
+ const ret = getObject(arg0).performance;
152
+ return addHeapObject(ret);
153
+ },
154
+ __wbg_static_accessor_GLOBAL_4ef717fb391d88b7: function() {
155
+ const ret = typeof global === 'undefined' ? null : global;
156
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
157
+ },
158
+ __wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4: function() {
159
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
160
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
161
+ },
162
+ __wbg_static_accessor_SELF_146583524fe1469b: function() {
163
+ const ret = typeof self === 'undefined' ? null : self;
164
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
165
+ },
166
+ __wbg_static_accessor_WINDOW_f2829a2234d7819e: function() {
167
+ const ret = typeof window === 'undefined' ? null : window;
168
+ return isLikeNone(ret) ? 0 : addHeapObject(ret);
169
+ },
170
+ __wbindgen_object_clone_ref: function(arg0) {
171
+ const ret = getObject(arg0);
172
+ return addHeapObject(ret);
173
+ },
174
+ __wbindgen_object_drop_ref: function(arg0) {
175
+ takeObject(arg0);
176
+ },
177
+ };
178
+ return {
179
+ __proto__: null,
180
+ "./u_nesting_wasm_bg.js": import0,
181
+ };
182
+ }
183
+
184
+ function addHeapObject(obj) {
185
+ if (heap_next === heap.length) heap.push(heap.length + 1);
186
+ const idx = heap_next;
187
+ heap_next = heap[idx];
188
+
189
+ heap[idx] = obj;
190
+ return idx;
191
+ }
192
+
193
+ function dropObject(idx) {
194
+ if (idx < 1028) return;
195
+ heap[idx] = heap_next;
196
+ heap_next = idx;
197
+ }
198
+
199
+ function getArrayU8FromWasm0(ptr, len) {
200
+ ptr = ptr >>> 0;
201
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
202
+ }
203
+
204
+ let cachedDataViewMemory0 = null;
205
+ function getDataViewMemory0() {
206
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
207
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
208
+ }
209
+ return cachedDataViewMemory0;
210
+ }
211
+
212
+ function getStringFromWasm0(ptr, len) {
213
+ return decodeText(ptr >>> 0, len);
214
+ }
215
+
216
+ let cachedUint8ArrayMemory0 = null;
217
+ function getUint8ArrayMemory0() {
218
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
219
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
220
+ }
221
+ return cachedUint8ArrayMemory0;
222
+ }
223
+
224
+ function getObject(idx) { return heap[idx]; }
225
+
226
+ function handleError(f, args) {
227
+ try {
228
+ return f.apply(this, args);
229
+ } catch (e) {
230
+ wasm.__wbindgen_export(addHeapObject(e));
231
+ }
232
+ }
233
+
234
+ let heap = new Array(1024).fill(undefined);
235
+ heap.push(undefined, null, true, false);
236
+
237
+ let heap_next = heap.length;
238
+
239
+ function isLikeNone(x) {
240
+ return x === undefined || x === null;
241
+ }
242
+
243
+ function passStringToWasm0(arg, malloc, realloc) {
244
+ if (realloc === undefined) {
245
+ const buf = cachedTextEncoder.encode(arg);
246
+ const ptr = malloc(buf.length, 1) >>> 0;
247
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
248
+ WASM_VECTOR_LEN = buf.length;
249
+ return ptr;
250
+ }
251
+
252
+ let len = arg.length;
253
+ let ptr = malloc(len, 1) >>> 0;
254
+
255
+ const mem = getUint8ArrayMemory0();
256
+
257
+ let offset = 0;
258
+
259
+ for (; offset < len; offset++) {
260
+ const code = arg.charCodeAt(offset);
261
+ if (code > 0x7F) break;
262
+ mem[ptr + offset] = code;
263
+ }
264
+ if (offset !== len) {
265
+ if (offset !== 0) {
266
+ arg = arg.slice(offset);
267
+ }
268
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
269
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
270
+ const ret = cachedTextEncoder.encodeInto(arg, view);
271
+
272
+ offset += ret.written;
273
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
274
+ }
275
+
276
+ WASM_VECTOR_LEN = offset;
277
+ return ptr;
278
+ }
279
+
280
+ function takeObject(idx) {
281
+ const ret = getObject(idx);
282
+ dropObject(idx);
283
+ return ret;
284
+ }
285
+
286
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
287
+ cachedTextDecoder.decode();
288
+ function decodeText(ptr, len) {
289
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
290
+ }
291
+
292
+ const cachedTextEncoder = new TextEncoder();
293
+
294
+ if (!('encodeInto' in cachedTextEncoder)) {
295
+ cachedTextEncoder.encodeInto = function (arg, view) {
296
+ const buf = cachedTextEncoder.encode(arg);
297
+ view.set(buf);
298
+ return {
299
+ read: arg.length,
300
+ written: buf.length
301
+ };
302
+ };
303
+ }
304
+
305
+ let WASM_VECTOR_LEN = 0;
306
+
307
+ const wasmPath = `${__dirname}/u_nesting_wasm_bg.wasm`;
308
+ const wasmBytes = require('fs').readFileSync(wasmPath);
309
+ const wasmModule = new WebAssembly.Module(wasmBytes);
310
+ let wasmInstance = new WebAssembly.Instance(wasmModule, __wbg_get_imports());
311
+ let wasm = wasmInstance.exports;
@@ -0,0 +1,39 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Returns a JSON array of available strategy names for WASM builds.
6
+ *
7
+ * MILP and HybridExact are not available in WASM (requires native HiGHS solver).
8
+ */
9
+ export function available_strategies(): string;
10
+
11
+ /**
12
+ * Optimizes cutting path for placed 2D parts.
13
+ *
14
+ * Input must include geometries, a previous solve result, and optional cutting config.
15
+ * Returns a JSON string with the cutting path result.
16
+ * On error, returns `{ "success": false, "error": "..." }`.
17
+ */
18
+ export function optimize_cutting_path(request_json: string): string;
19
+
20
+ /**
21
+ * Solves a 2D nesting problem from a JSON request string.
22
+ *
23
+ * Returns a JSON string with the solve result.
24
+ * On error, returns `{ "success": false, "error": "..." }`.
25
+ */
26
+ export function solve_2d(request_json: string): string;
27
+
28
+ /**
29
+ * Solves a 3D bin packing problem from a JSON request string.
30
+ *
31
+ * Returns a JSON string with the solve result.
32
+ * On error, returns `{ "success": false, "error": "..." }`.
33
+ */
34
+ export function solve_3d(request_json: string): string;
35
+
36
+ /**
37
+ * Returns the API version string.
38
+ */
39
+ export function version(): string;
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "iyulab"
6
6
  ],
7
7
  "description": "WebAssembly bindings for U-Nesting spatial optimization engine",
8
- "version": "0.4.0",
8
+ "version": "0.5.1",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",
@@ -15,18 +15,30 @@
15
15
  "u_nesting_wasm_bg.wasm",
16
16
  "u_nesting_wasm.js",
17
17
  "u_nesting_wasm_bg.js",
18
- "u_nesting_wasm.d.ts"
18
+ "u_nesting_wasm.d.ts",
19
+ "node"
19
20
  ],
20
21
  "main": "u_nesting_wasm.js",
21
22
  "types": "u_nesting_wasm.d.ts",
22
23
  "sideEffects": [
23
24
  "./u_nesting_wasm.js",
24
- "./snippets/*"
25
+ "./snippets/*",
26
+ "./node/u_nesting_wasm.cjs"
25
27
  ],
26
28
  "keywords": [
27
29
  "nesting",
28
30
  "bin-packing",
29
31
  "wasm",
30
32
  "webassembly"
31
- ]
32
- }
33
+ ],
34
+ "exports": {
35
+ ".": {
36
+ "node": {
37
+ "types": "./node/u_nesting_wasm.d.cts",
38
+ "default": "./node/u_nesting_wasm.cjs"
39
+ },
40
+ "types": "./u_nesting_wasm.d.ts",
41
+ "default": "./u_nesting_wasm.js"
42
+ }
43
+ }
44
+ }
@@ -123,11 +123,11 @@ export function version() {
123
123
  wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
124
124
  }
125
125
  }
126
- export function __wbg___wbindgen_is_undefined_4410e3c20a99fa97(arg0) {
126
+ export function __wbg___wbindgen_is_undefined_c05833b95a3cf397(arg0) {
127
127
  const ret = getObject(arg0) === undefined;
128
128
  return ret;
129
129
  }
130
- export function __wbg___wbindgen_throw_bbadd78c1bac3a77(arg0, arg1) {
130
+ export function __wbg___wbindgen_throw_344f42d3211c4765(arg0, arg1) {
131
131
  throw new Error(getStringFromWasm0(arg0, arg1));
132
132
  }
133
133
  export function __wbg_getRandomValues_3f44b700395062e5() { return handleError(function (arg0, arg1) {
@@ -141,19 +141,19 @@ export function __wbg_performance_3fcf6e32a7e1ed0a(arg0) {
141
141
  const ret = getObject(arg0).performance;
142
142
  return addHeapObject(ret);
143
143
  }
144
- export function __wbg_static_accessor_GLOBAL_60a4124bab7dcc9a() {
144
+ export function __wbg_static_accessor_GLOBAL_4ef717fb391d88b7() {
145
145
  const ret = typeof global === 'undefined' ? null : global;
146
146
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
147
147
  }
148
- export function __wbg_static_accessor_GLOBAL_THIS_95ca6460658b5d13() {
148
+ export function __wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4() {
149
149
  const ret = typeof globalThis === 'undefined' ? null : globalThis;
150
150
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
151
151
  }
152
- export function __wbg_static_accessor_SELF_4c95f759a91e9aae() {
152
+ export function __wbg_static_accessor_SELF_146583524fe1469b() {
153
153
  const ret = typeof self === 'undefined' ? null : self;
154
154
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
155
155
  }
156
- export function __wbg_static_accessor_WINDOW_44b435597f9e9ee7() {
156
+ export function __wbg_static_accessor_WINDOW_f2829a2234d7819e() {
157
157
  const ret = typeof window === 'undefined' ? null : window;
158
158
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
159
159
  }
Binary file