@iyulab/u-nesting 0.3.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 ADDED
@@ -0,0 +1,192 @@
1
+ # @iyulab/u-nesting
2
+
3
+ **2D/3D Spatial Optimization Engine** — High-performance nesting and bin packing via WebAssembly.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@iyulab/u-nesting.svg)](https://www.npmjs.com/package/@iyulab/u-nesting)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/iyulab/U-Nesting/blob/main/LICENSE-MIT)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @iyulab/u-nesting
12
+ ```
13
+
14
+ ## Functions
15
+
16
+ | Function | Description |
17
+ |----------|-------------|
18
+ | `solve_2d(json: string): string` | Solve a 2D nesting problem |
19
+ | `solve_3d(json: string): string` | Solve a 3D bin packing problem |
20
+ | `optimize_cutting_path(json: string): string` | Optimize cutting path for placed parts |
21
+ | `version(): string` | Get API version |
22
+ | `available_strategies(): string` | List available strategies |
23
+
24
+ All functions use **JSON string I/O**.
25
+
26
+ ## Usage
27
+
28
+ ### 2D Nesting
29
+
30
+ ```javascript
31
+ import init, { solve_2d } from '@iyulab/u-nesting';
32
+
33
+ await init();
34
+
35
+ const result = JSON.parse(solve_2d(JSON.stringify({
36
+ geometries: [
37
+ {
38
+ id: "part-A",
39
+ polygon: [[0,0], [100,0], [100,50], [0,50]],
40
+ quantity: 3,
41
+ allow_flip: false,
42
+ rotations: [0, 90, 180, 270]
43
+ },
44
+ {
45
+ id: "part-B",
46
+ polygon: [[0,0], [60,0], [60,80], [0,80]],
47
+ quantity: 2
48
+ }
49
+ ],
50
+ boundary: { width: 500, height: 300 },
51
+ config: {
52
+ spacing: 2.0,
53
+ strategy: "ga",
54
+ population_size: 50,
55
+ max_generations: 100,
56
+ time_limit_ms: 5000
57
+ }
58
+ })));
59
+
60
+ console.log(result);
61
+ // { success: true, placements: [...], utilization: 0.85, boundaries_used: 1, ... }
62
+ ```
63
+
64
+ ### 3D Bin Packing
65
+
66
+ ```javascript
67
+ import init, { solve_3d } from '@iyulab/u-nesting';
68
+
69
+ await init();
70
+
71
+ const result = JSON.parse(solve_3d(JSON.stringify({
72
+ geometries: [
73
+ { id: "box-1", dimensions: [10, 20, 15], quantity: 5 },
74
+ { id: "box-2", dimensions: [8, 12, 10], quantity: 3, mass: 2.5 }
75
+ ],
76
+ boundary: {
77
+ dimensions: [100, 100, 100],
78
+ max_mass: 50.0,
79
+ gravity: true,
80
+ stability: true
81
+ },
82
+ config: {
83
+ strategy: "ga",
84
+ time_limit_ms: 3000
85
+ }
86
+ })));
87
+ ```
88
+
89
+ ### Cutting Path Optimization
90
+
91
+ ```javascript
92
+ import init, { solve_2d, optimize_cutting_path } from '@iyulab/u-nesting';
93
+
94
+ await init();
95
+
96
+ // First solve the nesting problem
97
+ const solveResult = JSON.parse(solve_2d(JSON.stringify({ /* ... */ })));
98
+
99
+ // Then optimize cutting path
100
+ const cutting = JSON.parse(optimize_cutting_path(JSON.stringify({
101
+ geometries: [/* same geometries */],
102
+ solve_result: solveResult,
103
+ cutting_config: {
104
+ kerf_width: 0.5,
105
+ cut_speed: 100.0,
106
+ rapid_speed: 500.0,
107
+ exterior_direction: "cw",
108
+ interior_direction: "ccw"
109
+ }
110
+ })));
111
+ ```
112
+
113
+ ## Input Schemas
114
+
115
+ ### `solve_2d` Request
116
+
117
+ ```typescript
118
+ interface Request2D {
119
+ geometries: {
120
+ id: string;
121
+ polygon: [number, number][]; // Vertices (CCW)
122
+ quantity?: number; // Default: 1
123
+ allow_flip?: boolean; // Default: false
124
+ rotations?: number[]; // Allowed rotation angles in degrees
125
+ holes?: [number, number][][]; // Interior holes
126
+ }[];
127
+ boundary: {
128
+ width?: number; // Rectangle boundary
129
+ height?: number;
130
+ polygon?: [number, number][]; // Or custom polygon boundary
131
+ };
132
+ config?: {
133
+ spacing?: number; // Part spacing (default: 0)
134
+ margin?: number; // Boundary margin (default: 0)
135
+ strategy?: string; // See available strategies
136
+ population_size?: number; // GA/BRKGA population (default: 50)
137
+ max_generations?: number; // GA/BRKGA generations (default: 100)
138
+ crossover_rate?: number; // Crossover rate (default: 0.8)
139
+ mutation_rate?: number; // Mutation rate (default: 0.1)
140
+ time_limit_ms?: number; // Time limit in ms
141
+ target_utilization?: number; // Stop early if reached
142
+ };
143
+ }
144
+ ```
145
+
146
+ ### Available 2D Strategies
147
+
148
+ | Strategy | Description |
149
+ |----------|-------------|
150
+ | `blf` | Bottom-Left Fill (fast, deterministic) |
151
+ | `nfp` | NFP-Guided placement |
152
+ | `ga` | Genetic Algorithm |
153
+ | `brkga` | Biased Random-Key GA |
154
+ | `sa` | Simulated Annealing |
155
+ | `gdrr` | Guided Destroy-Repair-Refine |
156
+ | `alns` | Adaptive Large Neighborhood Search |
157
+
158
+ ### Available 3D Strategies
159
+
160
+ | Strategy | Description |
161
+ |----------|-------------|
162
+ | `blf` | Bottom-Left Fill |
163
+ | `ep` | Extreme Point |
164
+ | `ga` | Genetic Algorithm |
165
+ | `brkga` | Biased Random-Key GA |
166
+ | `sa` | Simulated Annealing |
167
+
168
+ ## Response Schema
169
+
170
+ ```typescript
171
+ interface SolveResponse {
172
+ version: string;
173
+ success: boolean;
174
+ error?: string;
175
+ placements: {
176
+ geometry_id: string;
177
+ instance: number;
178
+ position: { x: number; y: number; z?: number };
179
+ rotation: { angle?: number; rx?: number; ry?: number; rz?: number };
180
+ boundary_index: number;
181
+ }[];
182
+ boundaries_used: number;
183
+ utilization: number;
184
+ unplaced: string[];
185
+ computation_time_ms: number;
186
+ }
187
+ ```
188
+
189
+ ## Related
190
+
191
+ - [u-geometry](https://www.npmjs.com/package/@iyulab/u-geometry) — Computational geometry primitives
192
+ - [u-metaheur](https://crates.io/crates/u-metaheur) — Metaheuristic optimization framework
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@iyulab/u-nesting",
3
+ "type": "module",
4
+ "collaborators": [
5
+ "iyulab"
6
+ ],
7
+ "description": "WebAssembly bindings for U-Nesting spatial optimization engine",
8
+ "version": "0.3.0",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/iyulab/U-Nesting"
13
+ },
14
+ "files": [
15
+ "u_nesting_wasm_bg.wasm",
16
+ "u_nesting_wasm.js",
17
+ "u_nesting_wasm_bg.js",
18
+ "u_nesting_wasm.d.ts"
19
+ ],
20
+ "main": "u_nesting_wasm.js",
21
+ "types": "u_nesting_wasm.d.ts",
22
+ "sideEffects": [
23
+ "./u_nesting_wasm.js",
24
+ "./snippets/*"
25
+ ],
26
+ "keywords": [
27
+ "nesting",
28
+ "bin-packing",
29
+ "wasm",
30
+ "webassembly"
31
+ ]
32
+ }
@@ -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;
@@ -0,0 +1,9 @@
1
+ /* @ts-self-types="./u_nesting_wasm.d.ts" */
2
+
3
+ import * as wasm from "./u_nesting_wasm_bg.wasm";
4
+ import { __wbg_set_wasm } from "./u_nesting_wasm_bg.js";
5
+ __wbg_set_wasm(wasm);
6
+
7
+ export {
8
+ available_strategies, optimize_cutting_path, solve_2d, solve_3d, version
9
+ } from "./u_nesting_wasm_bg.js";
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Returns a JSON array of available strategy names for WASM builds.
3
+ *
4
+ * MILP and HybridExact are not available in WASM (requires native HiGHS solver).
5
+ * @returns {string}
6
+ */
7
+ export function available_strategies() {
8
+ let deferred1_0;
9
+ let deferred1_1;
10
+ try {
11
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
12
+ wasm.available_strategies(retptr);
13
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
14
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
15
+ deferred1_0 = r0;
16
+ deferred1_1 = r1;
17
+ return getStringFromWasm0(r0, r1);
18
+ } finally {
19
+ wasm.__wbindgen_add_to_stack_pointer(16);
20
+ wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Optimizes cutting path for placed 2D parts.
26
+ *
27
+ * Input must include geometries, a previous solve result, and optional cutting config.
28
+ * Returns a JSON string with the cutting path result.
29
+ * On error, returns `{ "success": false, "error": "..." }`.
30
+ * @param {string} request_json
31
+ * @returns {string}
32
+ */
33
+ export function optimize_cutting_path(request_json) {
34
+ let deferred2_0;
35
+ let deferred2_1;
36
+ try {
37
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
38
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
39
+ const len0 = WASM_VECTOR_LEN;
40
+ wasm.optimize_cutting_path(retptr, ptr0, len0);
41
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
42
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
43
+ deferred2_0 = r0;
44
+ deferred2_1 = r1;
45
+ return getStringFromWasm0(r0, r1);
46
+ } finally {
47
+ wasm.__wbindgen_add_to_stack_pointer(16);
48
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Solves a 2D nesting problem from a JSON request string.
54
+ *
55
+ * Returns a JSON string with the solve result.
56
+ * On error, returns `{ "success": false, "error": "..." }`.
57
+ * @param {string} request_json
58
+ * @returns {string}
59
+ */
60
+ export function solve_2d(request_json) {
61
+ let deferred2_0;
62
+ let deferred2_1;
63
+ try {
64
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
65
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
66
+ const len0 = WASM_VECTOR_LEN;
67
+ wasm.solve_2d(retptr, ptr0, len0);
68
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
69
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
70
+ deferred2_0 = r0;
71
+ deferred2_1 = r1;
72
+ return getStringFromWasm0(r0, r1);
73
+ } finally {
74
+ wasm.__wbindgen_add_to_stack_pointer(16);
75
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Solves a 3D bin packing problem from a JSON request string.
81
+ *
82
+ * Returns a JSON string with the solve result.
83
+ * On error, returns `{ "success": false, "error": "..." }`.
84
+ * @param {string} request_json
85
+ * @returns {string}
86
+ */
87
+ export function solve_3d(request_json) {
88
+ let deferred2_0;
89
+ let deferred2_1;
90
+ try {
91
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
92
+ const ptr0 = passStringToWasm0(request_json, wasm.__wbindgen_export3, wasm.__wbindgen_export4);
93
+ const len0 = WASM_VECTOR_LEN;
94
+ wasm.solve_3d(retptr, ptr0, len0);
95
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
96
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
97
+ deferred2_0 = r0;
98
+ deferred2_1 = r1;
99
+ return getStringFromWasm0(r0, r1);
100
+ } finally {
101
+ wasm.__wbindgen_add_to_stack_pointer(16);
102
+ wasm.__wbindgen_export2(deferred2_0, deferred2_1, 1);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Returns the API version string.
108
+ * @returns {string}
109
+ */
110
+ export function version() {
111
+ let deferred1_0;
112
+ let deferred1_1;
113
+ try {
114
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
115
+ wasm.version(retptr);
116
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
117
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
118
+ deferred1_0 = r0;
119
+ deferred1_1 = r1;
120
+ return getStringFromWasm0(r0, r1);
121
+ } finally {
122
+ wasm.__wbindgen_add_to_stack_pointer(16);
123
+ wasm.__wbindgen_export2(deferred1_0, deferred1_1, 1);
124
+ }
125
+ }
126
+ export function __wbg_getRandomValues_3f44b700395062e5() { return handleError(function (arg0, arg1) {
127
+ globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
128
+ }, arguments); }
129
+ export function __wbindgen_object_drop_ref(arg0) {
130
+ takeObject(arg0);
131
+ }
132
+ function addHeapObject(obj) {
133
+ if (heap_next === heap.length) heap.push(heap.length + 1);
134
+ const idx = heap_next;
135
+ heap_next = heap[idx];
136
+
137
+ heap[idx] = obj;
138
+ return idx;
139
+ }
140
+
141
+ function dropObject(idx) {
142
+ if (idx < 1028) return;
143
+ heap[idx] = heap_next;
144
+ heap_next = idx;
145
+ }
146
+
147
+ function getArrayU8FromWasm0(ptr, len) {
148
+ ptr = ptr >>> 0;
149
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
150
+ }
151
+
152
+ let cachedDataViewMemory0 = null;
153
+ function getDataViewMemory0() {
154
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
155
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
156
+ }
157
+ return cachedDataViewMemory0;
158
+ }
159
+
160
+ function getStringFromWasm0(ptr, len) {
161
+ ptr = ptr >>> 0;
162
+ return decodeText(ptr, len);
163
+ }
164
+
165
+ let cachedUint8ArrayMemory0 = null;
166
+ function getUint8ArrayMemory0() {
167
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
168
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
169
+ }
170
+ return cachedUint8ArrayMemory0;
171
+ }
172
+
173
+ function getObject(idx) { return heap[idx]; }
174
+
175
+ function handleError(f, args) {
176
+ try {
177
+ return f.apply(this, args);
178
+ } catch (e) {
179
+ wasm.__wbindgen_export(addHeapObject(e));
180
+ }
181
+ }
182
+
183
+ let heap = new Array(1024).fill(undefined);
184
+ heap.push(undefined, null, true, false);
185
+
186
+ let heap_next = heap.length;
187
+
188
+ function passStringToWasm0(arg, malloc, realloc) {
189
+ if (realloc === undefined) {
190
+ const buf = cachedTextEncoder.encode(arg);
191
+ const ptr = malloc(buf.length, 1) >>> 0;
192
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
193
+ WASM_VECTOR_LEN = buf.length;
194
+ return ptr;
195
+ }
196
+
197
+ let len = arg.length;
198
+ let ptr = malloc(len, 1) >>> 0;
199
+
200
+ const mem = getUint8ArrayMemory0();
201
+
202
+ let offset = 0;
203
+
204
+ for (; offset < len; offset++) {
205
+ const code = arg.charCodeAt(offset);
206
+ if (code > 0x7F) break;
207
+ mem[ptr + offset] = code;
208
+ }
209
+ if (offset !== len) {
210
+ if (offset !== 0) {
211
+ arg = arg.slice(offset);
212
+ }
213
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
214
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
215
+ const ret = cachedTextEncoder.encodeInto(arg, view);
216
+
217
+ offset += ret.written;
218
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
219
+ }
220
+
221
+ WASM_VECTOR_LEN = offset;
222
+ return ptr;
223
+ }
224
+
225
+ function takeObject(idx) {
226
+ const ret = getObject(idx);
227
+ dropObject(idx);
228
+ return ret;
229
+ }
230
+
231
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
232
+ cachedTextDecoder.decode();
233
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
234
+ let numBytesDecoded = 0;
235
+ function decodeText(ptr, len) {
236
+ numBytesDecoded += len;
237
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
238
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
239
+ cachedTextDecoder.decode();
240
+ numBytesDecoded = len;
241
+ }
242
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
243
+ }
244
+
245
+ const cachedTextEncoder = new TextEncoder();
246
+
247
+ if (!('encodeInto' in cachedTextEncoder)) {
248
+ cachedTextEncoder.encodeInto = function (arg, view) {
249
+ const buf = cachedTextEncoder.encode(arg);
250
+ view.set(buf);
251
+ return {
252
+ read: arg.length,
253
+ written: buf.length
254
+ };
255
+ };
256
+ }
257
+
258
+ let WASM_VECTOR_LEN = 0;
259
+
260
+
261
+ let wasm;
262
+ export function __wbg_set_wasm(val) {
263
+ wasm = val;
264
+ }
Binary file