diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0481ea5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,160 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**deepnest** is an Electron-based desktop application for nesting parts for CNC tools, laser cutters, and plotters. It's a fork of the original SVGNest and deepnest projects with performance improvements and new features. + +Key technologies: +- **Electron** with Node.js backend +- **TypeScript** for type safety (compiled to JavaScript) +- **Custom nesting engine** with C/C++ components via native modules +- **Web-based UI** with SVG rendering +- **Genetic algorithm** for optimization +- **Clipper library** for polygon operations + +## Common Development Commands + +### Building and Running +```bash +# Install dependencies +npm install + +# Build TypeScript to JavaScript +npm run build + +# Start the application +npm run start + +# Clean build artifacts +npm run clean + +# Full clean including node_modules +npm run clean-all +``` + +### Testing +```bash +# Run Playwright tests (requires one-time setup) +npx playwright install chromium +npm run test + +# Generate new tests interactively +npm run pw:codegen +``` + +### Code Quality +```bash +# Lint and format code (runs automatically via pre-commit hooks) +prettier --write **/*.{ts,html,css,scss,less,json} +eslint --fix **/*.{ts,html,css,scss,less,json} +``` + +### Distribution +```bash +# Create distribution package +npm run dist + +# Build everything and create distribution +npm run dist-all +``` + +## Architecture + +### Application Structure +- **main.js** - Electron main process entry point +- **main/** - Core application code + - **deepnest.js** - Main nesting algorithm and genetic optimization + - **background.js** - Background worker for intensive calculations + - **index.html** - Main UI + - **util/** - Utility modules (geometry, matrix operations, etc.) + +### Key Components + +1. **Main Process (main.js)** + - Creates Electron windows + - Handles IPC communication + - Manages background workers + - Handles file operations and settings + +2. **Nesting Engine (deepnest.js)** + - `DeepNest` class - Main nesting logic + - `GeneticAlgorithm` class - Optimization algorithm + - SVG parsing and polygon processing + - Clipper library integration for geometry operations + +3. **Background Workers** + - Separate renderer processes for CPU-intensive tasks + - Communicates via IPC with main process + - Prevents UI blocking during calculations + +4. **TypeScript Utilities (main/util/)** + - Geometry operations + - Point, Vector, Matrix classes + - Polygon hull calculations + - SVG parsing utilities + +### Key Algorithms +- **Genetic Algorithm** for part placement optimization +- **No-Fit Polygon (NFP)** calculation for collision detection +- **Polygon offsetting** using Clipper library +- **Curve simplification** with Douglas-Peucker algorithm + +## Development Notes + +### TypeScript Configuration +- Strict mode enabled with comprehensive type checking +- Outputs to `./build` directory +- Targets ES2023 with DOM and Node.js types + +### Electron Configuration +- Uses `@electron/remote` for renderer process access +- Context isolation disabled for legacy compatibility +- Node integration enabled in renderers + +### Testing +- Uses Playwright for end-to-end testing +- Headless mode disabled by default for debugging +- Screenshots and videos captured on test failure + +### Native Dependencies +- Requires C++ build tools (Visual Studio on Windows) +- Uses `@deepnest/calculate-nfp` for performance-critical calculations +- Electron rebuild required after native module changes + +### Environment Variables +- `deepnest_debug=1` - Opens dev tools +- `SAVE_PLACEMENTS_PATH` - Custom export directory +- `DEEPNEST_LONGLIST` - Keep more nesting results + +## Important File Locations + +- **Entry point**: `main.js` +- **Main UI**: `main/index.html` +- **Core logic**: `main/deepnest.js` +- **Background worker**: `main/background.js` +- **TypeScript source**: `main/util/*.ts` +- **Tests**: `tests/` +- **Build output**: `build/` + +## Performance Considerations + +- Nesting calculations run in background processes to prevent UI freezing +- Polygon simplification reduces complexity for better performance +- Genetic algorithm parameters can be tuned via configuration +- Native modules handle computationally intensive operations + +## Debugging + +Set `deepnest_debug=1` environment variable to enable Chrome DevTools in all Electron windows. + +## Known Issues and Recent Fixes + +### Boundary Condition Bug (Fixed) +- **Issue**: A 100mm x 100mm part could not be placed in a 100mm x 100mm bin +- **Root Cause**: The `noFitPolygonRectangle` function was never called from `noFitPolygon`, and exact-fit cases created degenerate polygons +- **Fix**: + - Added rectangle detection check in `noFitPolygon` function (`main/util/geometryutil.js:1594-1599`) + - Added special handling for exact-fit cases in `noFitPolygonRectangle` (`main/util/geometryutil.js:1581-1592`) +- **Files Modified**: `main/util/geometryutil.js` \ No newline at end of file diff --git a/debug_placement_1752156063846.log b/debug_placement_1752156063846.log new file mode 100644 index 0000000..f72cc34 --- /dev/null +++ b/debug_placement_1752156063846.log @@ -0,0 +1,884 @@ +=== DEBUG LOG STARTED 2025-07-10T14:01:03.846Z === +[2025-07-10T14:01:03.846Z] Debug logging initialized +[2025-07-10T14:01:05.670Z] Background-start event received, processing data... +[2025-07-10T14:01:05.670Z] Data contains: 1 parts +[2025-07-10T14:01:05.671Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:05.671Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:05.672Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:05.672Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.672Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.673Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:05.674Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:05.674Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:05.674Z] WATCH +[2025-07-10T14:01:05.674Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:05.675Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:05.675Z] placeParts completed, placement result: success +[2025-07-10T14:01:05.762Z] Background-start event received, processing data... +[2025-07-10T14:01:05.763Z] Data contains: 1 parts +[2025-07-10T14:01:05.763Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:05.763Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:05.763Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:05.763Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.763Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.764Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:05.764Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:05.764Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:05.764Z] WATCH +[2025-07-10T14:01:05.764Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:05.764Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:05.764Z] placeParts completed, placement result: success +[2025-07-10T14:01:05.869Z] Background-start event received, processing data... +[2025-07-10T14:01:05.869Z] Data contains: 1 parts +[2025-07-10T14:01:05.869Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:05.869Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:05.869Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:05.869Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.869Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.870Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:05.870Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:05.870Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:05.870Z] WATCH +[2025-07-10T14:01:05.870Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:05.870Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:05.870Z] placeParts completed, placement result: success +[2025-07-10T14:01:05.961Z] Background-start event received, processing data... +[2025-07-10T14:01:05.961Z] Data contains: 1 parts +[2025-07-10T14:01:05.961Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:05.961Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:05.961Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:05.961Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.961Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:05.962Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:05.962Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:05.962Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:05.962Z] WATCH +[2025-07-10T14:01:05.962Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:05.962Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:05.963Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.061Z] Background-start event received, processing data... +[2025-07-10T14:01:06.061Z] Data contains: 1 parts +[2025-07-10T14:01:06.061Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.062Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.062Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.062Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.062Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.062Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.062Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.063Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.063Z] WATCH +[2025-07-10T14:01:06.063Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.063Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.063Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.161Z] Background-start event received, processing data... +[2025-07-10T14:01:06.162Z] Data contains: 1 parts +[2025-07-10T14:01:06.162Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.162Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.162Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.162Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.163Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.163Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.163Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.163Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.163Z] WATCH +[2025-07-10T14:01:06.164Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.164Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.164Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.262Z] Background-start event received, processing data... +[2025-07-10T14:01:06.262Z] Data contains: 1 parts +[2025-07-10T14:01:06.262Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.262Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.262Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.262Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.263Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.263Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.263Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.263Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.263Z] WATCH +[2025-07-10T14:01:06.263Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.263Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.264Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.361Z] Background-start event received, processing data... +[2025-07-10T14:01:06.361Z] Data contains: 1 parts +[2025-07-10T14:01:06.361Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.362Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.362Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.362Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.362Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.362Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.362Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.362Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.363Z] WATCH +[2025-07-10T14:01:06.363Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.363Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.363Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.462Z] Background-start event received, processing data... +[2025-07-10T14:01:06.462Z] Data contains: 1 parts +[2025-07-10T14:01:06.462Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.462Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.463Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.463Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.463Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.463Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.463Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.463Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.463Z] WATCH +[2025-07-10T14:01:06.464Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.464Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.464Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.565Z] Background-start event received, processing data... +[2025-07-10T14:01:06.565Z] Data contains: 1 parts +[2025-07-10T14:01:06.565Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.565Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.565Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.565Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.566Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.566Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.566Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.566Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.566Z] WATCH +[2025-07-10T14:01:06.566Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.566Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.567Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.668Z] Background-start event received, processing data... +[2025-07-10T14:01:06.668Z] Data contains: 1 parts +[2025-07-10T14:01:06.669Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.669Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.669Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.669Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.669Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.669Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.669Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.670Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.670Z] WATCH +[2025-07-10T14:01:06.670Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.670Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.670Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.768Z] Background-start event received, processing data... +[2025-07-10T14:01:06.769Z] Data contains: 1 parts +[2025-07-10T14:01:06.769Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.769Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.769Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.769Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.769Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.770Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.770Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.770Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.770Z] WATCH +[2025-07-10T14:01:06.770Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.770Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.770Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.868Z] Background-start event received, processing data... +[2025-07-10T14:01:06.869Z] Data contains: 1 parts +[2025-07-10T14:01:06.869Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.869Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.869Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.869Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.869Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.870Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.870Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.870Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.870Z] WATCH +[2025-07-10T14:01:06.870Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.870Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.870Z] placeParts completed, placement result: success +[2025-07-10T14:01:06.961Z] Background-start event received, processing data... +[2025-07-10T14:01:06.961Z] Data contains: 1 parts +[2025-07-10T14:01:06.961Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:06.961Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:06.962Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:06.962Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.962Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:06.962Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:06.962Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:06.962Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:06.963Z] WATCH +[2025-07-10T14:01:06.963Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:06.963Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:06.963Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.061Z] Background-start event received, processing data... +[2025-07-10T14:01:07.061Z] Data contains: 1 parts +[2025-07-10T14:01:07.061Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.061Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.061Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.062Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.062Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.062Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.062Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.062Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.062Z] WATCH +[2025-07-10T14:01:07.062Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.063Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.063Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.161Z] Background-start event received, processing data... +[2025-07-10T14:01:07.161Z] Data contains: 1 parts +[2025-07-10T14:01:07.161Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.161Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.161Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.162Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.162Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.162Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.162Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.162Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.162Z] WATCH +[2025-07-10T14:01:07.162Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.163Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.163Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.266Z] Background-start event received, processing data... +[2025-07-10T14:01:07.266Z] Data contains: 1 parts +[2025-07-10T14:01:07.267Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.267Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.267Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.267Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.267Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.267Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.267Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.267Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.268Z] WATCH +[2025-07-10T14:01:07.268Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.268Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.268Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.361Z] Background-start event received, processing data... +[2025-07-10T14:01:07.361Z] Data contains: 1 parts +[2025-07-10T14:01:07.361Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.362Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.362Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.362Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.362Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.362Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.362Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.362Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.362Z] WATCH +[2025-07-10T14:01:07.363Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.363Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.363Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.469Z] Background-start event received, processing data... +[2025-07-10T14:01:07.469Z] Data contains: 1 parts +[2025-07-10T14:01:07.469Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.469Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.469Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.469Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.470Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.470Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.470Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.470Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.470Z] WATCH +[2025-07-10T14:01:07.470Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.470Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.470Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.562Z] Background-start event received, processing data... +[2025-07-10T14:01:07.562Z] Data contains: 1 parts +[2025-07-10T14:01:07.562Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.562Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.562Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.563Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.563Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.563Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.563Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.563Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.563Z] WATCH +[2025-07-10T14:01:07.563Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.564Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.564Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.669Z] Background-start event received, processing data... +[2025-07-10T14:01:07.669Z] Data contains: 1 parts +[2025-07-10T14:01:07.669Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.669Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.669Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.669Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.670Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.670Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.670Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.670Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.670Z] WATCH +[2025-07-10T14:01:07.670Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.670Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.670Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.761Z] Background-start event received, processing data... +[2025-07-10T14:01:07.761Z] Data contains: 1 parts +[2025-07-10T14:01:07.761Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.761Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.761Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.762Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.762Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.762Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.762Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.762Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.762Z] WATCH +[2025-07-10T14:01:07.762Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.762Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.763Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.862Z] Background-start event received, processing data... +[2025-07-10T14:01:07.862Z] Data contains: 1 parts +[2025-07-10T14:01:07.862Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.862Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.862Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.863Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.863Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.863Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.863Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.863Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.863Z] WATCH +[2025-07-10T14:01:07.863Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.864Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.864Z] placeParts completed, placement result: success +[2025-07-10T14:01:07.961Z] Background-start event received, processing data... +[2025-07-10T14:01:07.961Z] Data contains: 1 parts +[2025-07-10T14:01:07.962Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:07.962Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:07.962Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:07.962Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.962Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:07.962Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:07.962Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:07.962Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:07.963Z] WATCH +[2025-07-10T14:01:07.963Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:07.963Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:07.963Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.062Z] Background-start event received, processing data... +[2025-07-10T14:01:08.062Z] Data contains: 1 parts +[2025-07-10T14:01:08.062Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.062Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.063Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.063Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.063Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.063Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.063Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.063Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.063Z] WATCH +[2025-07-10T14:01:08.064Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.064Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.064Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.169Z] Background-start event received, processing data... +[2025-07-10T14:01:08.169Z] Data contains: 1 parts +[2025-07-10T14:01:08.169Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.169Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.169Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.169Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.170Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.170Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.170Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.170Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.170Z] WATCH +[2025-07-10T14:01:08.170Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.170Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.171Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.268Z] Background-start event received, processing data... +[2025-07-10T14:01:08.269Z] Data contains: 1 parts +[2025-07-10T14:01:08.269Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.269Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.269Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.269Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.269Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.269Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.269Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.270Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.270Z] WATCH +[2025-07-10T14:01:08.270Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.270Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.270Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.361Z] Background-start event received, processing data... +[2025-07-10T14:01:08.361Z] Data contains: 1 parts +[2025-07-10T14:01:08.362Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.362Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.362Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.362Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.362Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.362Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.362Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.362Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.362Z] WATCH +[2025-07-10T14:01:08.363Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.363Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.363Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.469Z] Background-start event received, processing data... +[2025-07-10T14:01:08.469Z] Data contains: 1 parts +[2025-07-10T14:01:08.469Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.469Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.469Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.470Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.470Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.470Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.470Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.470Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.470Z] WATCH +[2025-07-10T14:01:08.470Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.470Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.470Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.561Z] Background-start event received, processing data... +[2025-07-10T14:01:08.561Z] Data contains: 1 parts +[2025-07-10T14:01:08.561Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.561Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.561Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.562Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.562Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.562Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.562Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.562Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.562Z] WATCH +[2025-07-10T14:01:08.562Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.562Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.563Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.661Z] Background-start event received, processing data... +[2025-07-10T14:01:08.661Z] Data contains: 1 parts +[2025-07-10T14:01:08.661Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.661Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.661Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.661Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.662Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.662Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.662Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.662Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.662Z] WATCH +[2025-07-10T14:01:08.662Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.662Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.662Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.766Z] Background-start event received, processing data... +[2025-07-10T14:01:08.767Z] Data contains: 1 parts +[2025-07-10T14:01:08.767Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.767Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.767Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.767Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.767Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.767Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.768Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.768Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.768Z] WATCH +[2025-07-10T14:01:08.768Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.768Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.768Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.868Z] Background-start event received, processing data... +[2025-07-10T14:01:08.869Z] Data contains: 1 parts +[2025-07-10T14:01:08.869Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.869Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.869Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.869Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.869Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.869Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.870Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.870Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.870Z] WATCH +[2025-07-10T14:01:08.870Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.870Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.870Z] placeParts completed, placement result: success +[2025-07-10T14:01:08.968Z] Background-start event received, processing data... +[2025-07-10T14:01:08.968Z] Data contains: 1 parts +[2025-07-10T14:01:08.968Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:08.969Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:08.969Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:08.969Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.969Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:08.969Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:08.969Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:08.969Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:08.970Z] WATCH +[2025-07-10T14:01:08.970Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:08.970Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:08.970Z] placeParts completed, placement result: success +[2025-07-10T14:01:09.061Z] Background-start event received, processing data... +[2025-07-10T14:01:09.061Z] Data contains: 1 parts +[2025-07-10T14:01:09.061Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:09.061Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:09.061Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:09.062Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:09.062Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:09.062Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:09.062Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:09.062Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:09.062Z] WATCH +[2025-07-10T14:01:09.062Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:09.062Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:09.062Z] placeParts completed, placement result: success +[2025-07-10T14:01:10.061Z] Background-start event received, processing data... +[2025-07-10T14:01:10.061Z] Data contains: 1 parts +[2025-07-10T14:01:10.062Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:10.062Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:10.062Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:10.062Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:10.062Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:10.062Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:10.062Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:10.063Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:10.063Z] WATCH +[2025-07-10T14:01:10.063Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:10.063Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:10.063Z] placeParts completed, placement result: success +[2025-07-10T14:01:11.055Z] Background-start event received, processing data... +[2025-07-10T14:01:11.055Z] Data contains: 1 parts +[2025-07-10T14:01:11.056Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:11.056Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:11.056Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:11.056Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:11.056Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:11.056Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:11.056Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:11.057Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:11.057Z] WATCH +[2025-07-10T14:01:11.057Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:11.057Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:11.057Z] placeParts completed, placement result: success +[2025-07-10T14:01:12.053Z] Background-start event received, processing data... +[2025-07-10T14:01:12.053Z] Data contains: 1 parts +[2025-07-10T14:01:12.053Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:12.053Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:12.054Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:12.054Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:12.054Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:12.054Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:12.054Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:12.054Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:12.054Z] WATCH +[2025-07-10T14:01:12.054Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:12.054Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:12.055Z] placeParts completed, placement result: success +[2025-07-10T14:01:13.060Z] Background-start event received, processing data... +[2025-07-10T14:01:13.060Z] Data contains: 1 parts +[2025-07-10T14:01:13.060Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:13.060Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:13.060Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:13.060Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.061Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.061Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:13.061Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:13.061Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:13.061Z] WATCH +[2025-07-10T14:01:13.061Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:13.061Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:13.061Z] placeParts completed, placement result: success +[2025-07-10T14:01:13.858Z] Background-start event received, processing data... +[2025-07-10T14:01:13.858Z] Data contains: 1 parts +[2025-07-10T14:01:13.858Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:13.858Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:13.858Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:13.858Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.858Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.859Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:13.859Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:13.859Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:13.859Z] WATCH +[2025-07-10T14:01:13.859Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:13.859Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:13.859Z] placeParts completed, placement result: success +[2025-07-10T14:01:13.961Z] Background-start event received, processing data... +[2025-07-10T14:01:13.961Z] Data contains: 1 parts +[2025-07-10T14:01:13.962Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:13.962Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:13.962Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:13.962Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.962Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:13.962Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:13.962Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:13.963Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:13.963Z] WATCH +[2025-07-10T14:01:13.963Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:13.963Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:13.963Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.061Z] Background-start event received, processing data... +[2025-07-10T14:01:14.061Z] Data contains: 1 parts +[2025-07-10T14:01:14.061Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.062Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.062Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.062Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.062Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.062Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.062Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.062Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.063Z] WATCH +[2025-07-10T14:01:14.063Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.063Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.063Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.164Z] Background-start event received, processing data... +[2025-07-10T14:01:14.164Z] Data contains: 1 parts +[2025-07-10T14:01:14.164Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.164Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.165Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.165Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.165Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.165Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.165Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.165Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.165Z] WATCH +[2025-07-10T14:01:14.166Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.166Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.166Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.269Z] Background-start event received, processing data... +[2025-07-10T14:01:14.269Z] Data contains: 1 parts +[2025-07-10T14:01:14.269Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.269Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.270Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.270Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.270Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.270Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.270Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.270Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.271Z] WATCH +[2025-07-10T14:01:14.271Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.271Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.271Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.361Z] Background-start event received, processing data... +[2025-07-10T14:01:14.361Z] Data contains: 1 parts +[2025-07-10T14:01:14.362Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.362Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.362Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.362Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.362Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.362Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.362Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.362Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.363Z] WATCH +[2025-07-10T14:01:14.363Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.363Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.363Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.463Z] Background-start event received, processing data... +[2025-07-10T14:01:14.463Z] Data contains: 1 parts +[2025-07-10T14:01:14.464Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.464Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.464Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.464Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.464Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.464Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.464Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.464Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.464Z] WATCH +[2025-07-10T14:01:14.465Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.465Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.465Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.561Z] Background-start event received, processing data... +[2025-07-10T14:01:14.561Z] Data contains: 1 parts +[2025-07-10T14:01:14.561Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.561Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.562Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.562Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.562Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.562Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.562Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.562Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.562Z] WATCH +[2025-07-10T14:01:14.563Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.563Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.563Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.661Z] Background-start event received, processing data... +[2025-07-10T14:01:14.662Z] Data contains: 1 parts +[2025-07-10T14:01:14.662Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.662Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.662Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.662Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.662Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.662Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.662Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.663Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.663Z] WATCH +[2025-07-10T14:01:14.663Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.663Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.663Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.769Z] Background-start event received, processing data... +[2025-07-10T14:01:14.769Z] Data contains: 1 parts +[2025-07-10T14:01:14.769Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.769Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.769Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.769Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.770Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.770Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.770Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.770Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.770Z] WATCH +[2025-07-10T14:01:14.770Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.770Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.770Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.861Z] Background-start event received, processing data... +[2025-07-10T14:01:14.861Z] Data contains: 1 parts +[2025-07-10T14:01:14.862Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.862Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.862Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.862Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.862Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.862Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.862Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.862Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.863Z] WATCH +[2025-07-10T14:01:14.863Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.863Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.863Z] placeParts completed, placement result: success +[2025-07-10T14:01:14.969Z] Background-start event received, processing data... +[2025-07-10T14:01:14.969Z] Data contains: 1 parts +[2025-07-10T14:01:14.969Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:14.969Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:14.969Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:14.970Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.970Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:14.970Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:14.970Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:14.970Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:14.970Z] WATCH +[2025-07-10T14:01:14.970Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:14.971Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:14.971Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.063Z] Background-start event received, processing data... +[2025-07-10T14:01:15.063Z] Data contains: 1 parts +[2025-07-10T14:01:15.064Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.064Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.064Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.064Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.064Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.064Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.064Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.064Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.065Z] WATCH +[2025-07-10T14:01:15.065Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.065Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.065Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.161Z] Background-start event received, processing data... +[2025-07-10T14:01:15.161Z] Data contains: 1 parts +[2025-07-10T14:01:15.161Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.161Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.162Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.162Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.162Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.162Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.162Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.162Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.162Z] WATCH +[2025-07-10T14:01:15.163Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.163Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.163Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.264Z] Background-start event received, processing data... +[2025-07-10T14:01:15.264Z] Data contains: 1 parts +[2025-07-10T14:01:15.265Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.265Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.265Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.265Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.265Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.265Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.265Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.265Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.265Z] WATCH +[2025-07-10T14:01:15.266Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.266Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.266Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.369Z] Background-start event received, processing data... +[2025-07-10T14:01:15.369Z] Data contains: 1 parts +[2025-07-10T14:01:15.369Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.370Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.370Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.370Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.370Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.370Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.370Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.370Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.370Z] WATCH +[2025-07-10T14:01:15.371Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.371Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.371Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.467Z] Background-start event received, processing data... +[2025-07-10T14:01:15.467Z] Data contains: 1 parts +[2025-07-10T14:01:15.467Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.467Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.467Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.468Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.468Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.468Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.468Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.468Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.468Z] WATCH +[2025-07-10T14:01:15.468Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.469Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.469Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.569Z] Background-start event received, processing data... +[2025-07-10T14:01:15.569Z] Data contains: 1 parts +[2025-07-10T14:01:15.569Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.569Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.570Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.570Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.570Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.570Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.570Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.570Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.570Z] WATCH +[2025-07-10T14:01:15.570Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.570Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.571Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.669Z] Background-start event received, processing data... +[2025-07-10T14:01:15.669Z] Data contains: 1 parts +[2025-07-10T14:01:15.669Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.669Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.670Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.670Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.670Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.670Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.670Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.670Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.670Z] WATCH +[2025-07-10T14:01:15.671Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.671Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.671Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.763Z] Background-start event received, processing data... +[2025-07-10T14:01:15.764Z] Data contains: 1 parts +[2025-07-10T14:01:15.764Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.764Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.764Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.764Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.764Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.764Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.764Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.764Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.765Z] WATCH +[2025-07-10T14:01:15.765Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.765Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.765Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.869Z] Background-start event received, processing data... +[2025-07-10T14:01:15.869Z] Data contains: 1 parts +[2025-07-10T14:01:15.870Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.870Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.870Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.870Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.870Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.870Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.871Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.871Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.871Z] WATCH +[2025-07-10T14:01:15.871Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.871Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.871Z] placeParts completed, placement result: success +[2025-07-10T14:01:15.964Z] Background-start event received, processing data... +[2025-07-10T14:01:15.964Z] Data contains: 1 parts +[2025-07-10T14:01:15.965Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:15.965Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:15.965Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:15.965Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.965Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:15.965Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:15.965Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:15.965Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:15.965Z] WATCH +[2025-07-10T14:01:15.966Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:15.966Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:15.966Z] placeParts completed, placement result: success +[2025-07-10T14:01:16.069Z] Background-start event received, processing data... +[2025-07-10T14:01:16.069Z] Data contains: 1 parts +[2025-07-10T14:01:16.069Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:16.069Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:16.070Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:16.070Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:16.070Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:16.070Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:16.070Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:16.070Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:16.070Z] WATCH +[2025-07-10T14:01:16.071Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:16.071Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:16.071Z] placeParts completed, placement result: success +[2025-07-10T14:01:16.165Z] Background-start event received, processing data... +[2025-07-10T14:01:16.165Z] Data contains: 1 parts +[2025-07-10T14:01:16.165Z] Created 0 NFP pairs for processing +[2025-07-10T14:01:16.165Z] About to call placeParts with 1 parts and 1 sheets +[2025-07-10T14:01:16.166Z] PlaceParts started with 1 parts and 1 sheets +[2025-07-10T14:01:16.166Z] First part dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:16.166Z] First sheet dimensions: 2834.6456693 x 2834.6456693 +[2025-07-10T14:01:16.166Z] === PROCESSING SHEET 0 bounds: {"x":0,"y":0,"width":2834.6456693,"height":2834.6456693} area: 8035216.070481245 +[2025-07-10T14:01:16.166Z] Processing new sheet, current parts remaining: 0 +[2025-07-10T14:01:16.166Z] UNPLACED PARTS 0 of 1 +[2025-07-10T14:01:16.166Z] WATCH +[2025-07-10T14:01:16.166Z] Utilisation of the sheet(s): 0.00% +[2025-07-10T14:01:16.167Z] Fitness calculation resulted in NaN, using fallback value +[2025-07-10T14:01:16.167Z] placeParts completed, placement result: success diff --git a/main/background.js b/main/background.js index 7c61d22..8c71f2f 100755 --- a/main/background.js +++ b/main/background.js @@ -11,6 +11,27 @@ window.onload = function () { window.path = require('path') window.url = require('url') window.fs = require('graceful-fs'); + + // Create debug log file + const debugLogPath = window.path.join(process.cwd(), `debug_placement_${Date.now()}.log`); + window.debugLog = function(...message) { + const timestamp = new Date().toISOString(); + const logEntry = `[${timestamp}] ${message.join(' ')}\n`; + console.log(...message); // Still log to console + try { + window.fs.appendFileSync(debugLogPath, logEntry); + } catch (e) { + console.error('Failed to write to debug log:', e); + } + }; + + // Clear previous log at start + try { + window.fs.writeFileSync(debugLogPath, `=== DEBUG LOG STARTED ${new Date().toISOString()} ===\n`); + window.debugLog('Debug logging initialized'); + } catch (e) { + console.error('Failed to initialize debug log:', e); + } /* add package 'filequeue 0.5.0' if you enable this window.FileQueue = require('filequeue'); @@ -19,6 +40,9 @@ window.onload = function () { window.db = new NfpCache(); ipcRenderer.on('background-start', (event, data) => { + window.debugLog('Background-start event received, processing data...'); + window.debugLog('Data contains: ' + data.individual.placement.length + ' parts'); + var index = data.index; var individual = data.individual; @@ -81,13 +105,32 @@ window.onload = function () { } } - // console.log('pairs: ', pairs.length); + window.debugLog('Created ' + pairs.length + ' NFP pairs for processing'); + if (pairs.length > 1000) { + window.debugLog('Very large number of NFP pairs - this will take a long time!'); + } var process = function (pair) { + window.debugLog(' PAIR: A=' + pair.Asource + ' B=' + pair.Bsource + ' Arot=' + pair.Arotation + ' Brot=' + pair.Brotation); + var A = rotatePolygon(pair.A, pair.Arotation); var B = rotatePolygon(pair.B, pair.Brotation); + // TEMPORARILY DISABLE rectangle optimization to test + if (false && GeometryUtil.isRectangle(pair.A) && !pair.inside) { + var rectangleNfp = GeometryUtil.noFitPolygonRectangle(A, B); + if (rectangleNfp && rectangleNfp.length > 0) { + return { + Asource: pair.Asource, + Bsource: pair.Bsource, + Arotation: pair.Arotation, + Brotation: pair.Brotation, + nfp: rectangleNfp + }; + } + } + var clipper = new ClipperLib.Clipper(); var Ac = toClipperCoordinates(A); @@ -116,10 +159,14 @@ window.onload = function () { clipperNfp[i].y += B[0].y; } - pair.A = null; - pair.B = null; - pair.nfp = clipperNfp; - return pair; + window.debugLog(' NFP RESULT for A=' + pair.Asource + ' rotation=' + pair.Arotation + ': ' + JSON.stringify(clipperNfp)); + return { + Asource: pair.Asource, + Bsource: pair.Bsource, + Arotation: pair.Arotation, + Brotation: pair.Brotation, + nfp: clipperNfp + }; function toClipperCoordinates(polygon) { var clone = []; @@ -163,13 +210,16 @@ window.onload = function () { // run the placement synchronously function sync() { - //console.log('starting synchronous calculations', Object.keys(window.nfpCache).length); - // console.log('in sync'); + //window.debugLog('starting synchronous calculations', Object.keys(window.nfpCache).length); + // window.debugLog('in sync'); var c = window.db.getStats(); - // console.log('nfp cached:', c); - // console.log() + // window.debugLog('nfp cached:', c); + // window.debugLog() + window.debugLog('About to call placeParts with ' + parts.length + ' parts and ' + data.sheets.length + ' sheets'); ipcRenderer.send('test', [data.sheets, parts, data.config, index]); + var placement = placeParts(data.sheets, parts, data.config, index); + window.debugLog('placeParts completed, placement result: ' + (placement ? 'success' : 'null')); placement.index = data.index; ipcRenderer.send('background-response', placement); @@ -179,6 +229,7 @@ window.onload = function () { if (pairs.length > 0) { + window.debugLog('Starting parallel NFP processing for', pairs.length, 'pairs'); var p = new Parallel(pairs, { evalPath: '../build/util/eval.js', synchronous: false @@ -195,65 +246,95 @@ window.onload = function () { p.require('../../main/util/clipper.js'); p.require('../../main/util/geometryutil.js'); + window.debugLog('Starting p.map processing...'); + + // Add timeout for parallel processing + var parallelTimeout = setTimeout(function () { + console.error('Parallel processing timeout after 60 seconds, continuing with sync'); + sync(); + }, 60000); + p.map(process).then(function (processed) { - function getPart(source) { - for (let k = 0; k < parts.length; k++) { - if (parts[k].source == source) { - return parts[k]; + clearTimeout(parallelTimeout); + window.debugLog('Parallel processing completed, got', processed.length, 'results'); + window.debugLog('Processed NFPs:', processed); + try { + function getPart(source) { + for (let k = 0; k < parts.length; k++) { + if (parts[k].source == source) { + return parts[k]; + } } + return null; } - return null; - } - // store processed data in cache - for (let i = 0; i < processed.length; i++) { - // returned data only contains outer nfp, we have to account for any holes separately in the synchronous portion - // this is because the c++ addon which can process interior nfps cannot run in the worker thread - var A = getPart(processed[i].Asource); - var B = getPart(processed[i].Bsource); - - var Achildren = []; - - var j; - if (A.children) { - for (let j = 0; j < A.children.length; j++) { - Achildren.push(rotatePolygon(A.children[j], processed[i].Arotation)); + + // store processed data in cache + for (let i = 0; i < processed.length; i++) { + window.debugLog('Processing NFP result', i, 'Asource:', processed[i].Asource, 'Bsource:', processed[i].Bsource); + + // returned data only contains outer nfp, we have to account for any holes separately in the synchronous portion + // this is because the c++ addon which can process interior nfps cannot run in the worker thread + var A = getPart(processed[i].Asource); + var B = getPart(processed[i].Bsource); + + // Add null checks for A and B + if (!A || !B) { + window.debugLog('Skipping NFP result', i, 'due to null parts. A:', A, 'B:', B, 'Asource:', processed[i].Asource, 'Bsource:', processed[i].Bsource); + continue; } - } - if (Achildren.length > 0) { - var Brotated = rotatePolygon(B, processed[i].Brotation); - var bbounds = GeometryUtil.getPolygonBounds(Brotated); - var cnfp = []; + var Achildren = []; + + var j; + if (A.children && A.children.length > 0) { + for (let j = 0; j < A.children.length; j++) { + Achildren.push(rotatePolygon(A.children[j], processed[i].Arotation)); + } + } - for (let j = 0; j < Achildren.length; j++) { - var cbounds = GeometryUtil.getPolygonBounds(Achildren[j]); - if (cbounds.width > bbounds.width && cbounds.height > bbounds.height) { - var n = getInnerNfp(Achildren[j], Brotated, data.config); - if (n && n.length > 0) { - cnfp = cnfp.concat(n); + var cnfp = []; + if (Achildren.length > 0) { + var Brotated = rotatePolygon(B, processed[i].Brotation); + var bbounds = GeometryUtil.getPolygonBounds(Brotated); + + for (let j = 0; j < Achildren.length; j++) { + var cbounds = GeometryUtil.getPolygonBounds(Achildren[j]); + if (cbounds.width > bbounds.width && cbounds.height > bbounds.height) { + var n = getInnerNfp(Achildren[j], Brotated, data.config); + if (n && n.length > 0) { + cnfp = cnfp.concat(n); + } } } + + processed[i].nfp.children = cnfp; } - processed[i].nfp.children = cnfp; - } + // Only cache if we have valid sources + if (processed[i].Asource !== undefined && processed[i].Bsource !== undefined) { + var doc = { + A: processed[i].Asource, + B: processed[i].Bsource, + Arotation: processed[i].Arotation, + Brotation: processed[i].Brotation, + nfp: processed[i].nfp + }; + window.db.insert(doc); + } else { + window.debugLog('Skipping cache insert due to undefined sources:', processed[i].Asource, processed[i].Bsource); + } - var doc = { - A: processed[i].Asource, - B: processed[i].Bsource, - Arotation: processed[i].Arotation, - Brotation: processed[i].Brotation, - nfp: processed[i].nfp - }; - window.db.insert(doc); + } + } catch (e) { + console.error('Error processing NFP results:', e); } // console.timeEnd('Total'); - // console.log('before sync'); + // window.debugLog('before sync'); + window.debugLog('About to call sync after parallel processing'); sync(); }); - } - else { + } else { sync(); } }); @@ -482,23 +563,23 @@ function toNestCoordinates(polygon, scale) { }; function getHull(polygon) { - // Convert the polygon points to proper Point objects for HullPolygon - var points = []; - for (let i = 0; i < polygon.length; i++) { - points.push({ - x: polygon[i].x, - y: polygon[i].y - }); - } - - var hullpoints = HullPolygon.hull(points); - - // If hull calculation failed, return original polygon - if (!hullpoints) { - return polygon; - } - - return hullpoints; + // Convert the polygon points to proper Point objects for HullPolygon + var points = []; + for (let i = 0; i < polygon.length; i++) { + points.push({ + x: polygon[i].x, + y: polygon[i].y + }); + } + + var hullpoints = HullPolygon.hull(points); + + // If hull calculation failed, return original polygon + if (!hullpoints) { + return polygon; + } + + return hullpoints; } function rotatePolygon(polygon, degrees) { @@ -545,22 +626,33 @@ function getOuterNfp(A, B, inside) { return doc; } + // TEMPORARILY DISABLE rectangle optimization to test + if (false && !inside && GeometryUtil.isRectangle(A) && !A.children) { + var rectangleNfp = GeometryUtil.noFitPolygonRectangle(A, B); + if (rectangleNfp && rectangleNfp.length > 0) { + nfp = rectangleNfp; + // Save to cache + window.db.insert({ A: A.source, B: B.source, Arotation: A.rotation, Brotation: B.rotation, nfp: nfp }); + return nfp; + } + } + // not found in cache if (inside || (A.children && A.children.length > 0)) { - //console.log('computing minkowski: ',A.length, B.length); + //window.debugLog('computing minkowski: ',A.length, B.length); if (!A.children) { A.children = []; } if (!B.children) { B.children = []; } - //console.log('computing minkowski: ', JSON.stringify(Object.assign({}, {A:Object.assign({},A)},{B:Object.assign({},B)}))); + //window.debugLog('computing minkowski: ', JSON.stringify(Object.assign({}, {A:Object.assign({},A)},{B:Object.assign({},B)}))); //console.time('addon'); nfp = addon.calculateNFP({ A: A, B: B }); //console.timeEnd('addon'); } else { - // console.log('minkowski', A.length, B.length, A.source, B.source); + // window.debugLog('minkowski', A.length, B.length, A.source, B.source); // console.time('clipper'); var Ac = toClipperCoordinates(A); @@ -572,7 +664,7 @@ function getOuterNfp(A, B, inside) { Bc[i].Y *= -1; } var solution = ClipperLib.Clipper.MinkowskiSum(Ac, Bc, true); - //console.log(solution.length, solution); + //window.debugLog(solution.length, solution); //var clipperNfp = toNestCoordinates(solution[0], 10000000); var clipperNfp; @@ -592,12 +684,12 @@ function getOuterNfp(A, B, inside) { } nfp = [clipperNfp]; - //console.log('clipper nfp', JSON.stringify(nfp)); + //window.debugLog('clipper nfp', JSON.stringify(nfp)); // console.timeEnd('clipper'); } if (!nfp || nfp.length == 0) { - //console.log('holy shit', nfp, A, B, JSON.stringify(A), JSON.stringify(B)); + //window.debugLog('holy shit', nfp, A, B, JSON.stringify(A), JSON.stringify(B)); return null } @@ -649,11 +741,48 @@ function getInnerNfp(A, B, config) { var doc = window.db.find({ A: A.source, B: B.source, Arotation: 0, Brotation: B.rotation }, true); if (doc) { - //console.log('fetch inner', A.source, B.source, doc); + //window.debugLog('fetch inner', A.source, B.source, doc); return doc; } } + // Check for exact-fit or near-exact-fit case + // Only apply this optimization if A has no children (i.e., it's an empty sheet) + if (GeometryUtil.isRectangle(A) && GeometryUtil.isRectangle(B) && (!A.children || A.children.length === 0)) { + var ABounds = GeometryUtil.getPolygonBounds(A); + var BBounds = GeometryUtil.getPolygonBounds(B); + + var widthDiff = Math.abs(ABounds.width - BBounds.width); + var heightDiff = Math.abs(ABounds.height - BBounds.height); + + // If part is very close to sheet size (within tolerance, accounting for scale) + var tolerance = Math.max(0.001, Math.max(ABounds.width, ABounds.height) * 0.0001); // Dynamic tolerance + if (widthDiff < tolerance && heightDiff < tolerance) { + window.debugLog('Exact-fit detected for empty sheet:', A.source, 'and part:', B.source); + // For exact-fit, return a single point NFP + // The NFP point should be where the part's reference point needs to be + // to place the part at the sheet's top-left corner + var result = [[{ + x: A[0].x + (ABounds.width - BBounds.width) / 2, + y: A[0].y + (ABounds.height - BBounds.height) / 2 + }]]; + + // Cache the result + if (typeof A.source !== 'undefined' && typeof B.source !== 'undefined') { + var doc = { + A: A.source, + B: B.source, + Arotation: 0, + Brotation: B.rotation, + nfp: result + }; + window.db.insert(doc, true); + } + + return result; + } + } + var frame = getFrame(A); var nfp = getOuterNfp(frame, B, true); @@ -700,7 +829,7 @@ function getInnerNfp(A, B, config) { if (typeof A.source !== 'undefined' && typeof B.source !== 'undefined') { // insert into db - // console.log('inserting inner: ', A.source, B.source, B.rotation, f); + // window.debugLog('inserting inner: ', A.source, B.source, B.rotation, f); var doc = { A: A.source, B: B.source, @@ -719,10 +848,36 @@ function placeParts(sheets, parts, config, nestindex) { return null; } + window.debugLog('PlaceParts started with ' + parts.length + ' parts and ' + sheets.length + ' sheets'); + + // Log part and sheet dimensions for debugging + if (parts.length > 0) { + var partBounds = GeometryUtil.getPolygonBounds(parts[0]); + window.debugLog('First part dimensions: ' + partBounds.width + ' x ' + partBounds.height); + } + if (sheets.length > 0) { + var sheetBounds = GeometryUtil.getPolygonBounds(sheets[0]); + window.debugLog('First sheet dimensions: ' + sheetBounds.width + ' x ' + sheetBounds.height); + } + + // Check if we have too many parts for efficient processing + if (parts.length > 50) { + window.debugLog('Processing ' + parts.length + ' parts - this may take a long time'); + + // Check if all parts are identical (same source) + var firstSource = parts[0].source; + var allIdentical = parts.every(function (part) { return part.source === firstSource; }); + + if (allIdentical) { + window.debugLog('All parts are identical - consider using batch processing optimization'); + } + } + var i, j, k, m, n, part; var totalnum = parts.length; var totalsheetarea = 0; + var totalPlacedPartArea = 0; // Track total area of placed parts // total length of merged lines var totalMerged = 0; @@ -749,49 +904,67 @@ function placeParts(sheets, parts, config, nestindex) { // Pre-analyze holes in all sheets const sheetHoleAnalysis = analyzeSheetHoles(sheets); - // Analyze all parts to identify those with holes and potential fits - const { mainParts, holeCandidates } = analyzeParts(parts, sheetHoleAnalysis.averageHoleArea, config); - - // console.log(`Analyzed parts: ${mainParts.length} main parts, ${holeCandidates.length} hole candidates`); - + // TEMPORARILY DISABLE hole analysis to test + window.debugLog('Skipping hole analysis - using all parts as main parts'); + window.debugLog('Parts before hole analysis: ' + parts.length); + var allplacements = []; var fitness = 0; - // Now continue with the original placeParts logic, but use our sorted parts - - // Combine main parts and hole candidates back into a single array - // mainParts first since we want to place them first - parts = [...mainParts, ...holeCandidates]; + // Skip hole analysis - use all parts as-is + window.debugLog('After skipping hole analysis: ' + parts.length + ' total parts for placement'); // Continue with the original placeParts logic // var binarea = Math.abs(GeometryUtil.polygonArea(self.binPolygon)); var key, nfp; var part; - +var p = 0; while (parts.length > 0) { - + var part = parts.shift(); var placed = []; var placements = []; // open a new sheet var sheet = sheets.shift(); + + // Check if we have a valid sheet + if (!sheet) { + window.debugLog('No more sheets available, but', parts.length, 'parts remaining'); + break; // Exit the loop if no more sheets are available + } + var sheetarea = Math.abs(GeometryUtil.polygonArea(sheet)); + var sheetBounds = GeometryUtil.getPolygonBounds(sheet); totalsheetarea += sheetarea; fitness += sheetarea; // add 1 for each new sheet opened (lower fitness is better) var clipCache = []; - //console.log('new sheet'); + window.debugLog('=== PROCESSING SHEET ' + p + ' bounds: ' + JSON.stringify(sheetBounds) + ' area: ' + sheetarea); + window.debugLog('Processing new sheet, current parts remaining: ' + parts.length); for (let i = 0; i < parts.length; i++) { // console.time('placement'); part = parts[i]; + window.debugLog('Attempting to place part ' + i + ' with source: ' + part.source); + + // Add timeout for NFP calculation to prevent infinite loops + var nfpStartTime = Date.now(); + var NFP_TIMEOUT = 30000; // 30 seconds timeout per part // inner NFP var sheetNfp = null; // try all possible rotations until it fits // (only do this for the first part of each sheet, to ensure that all parts that can be placed are, even if we have to to open a lot of sheets) for (let j = 0; j < config.rotations; j++) { + // Check timeout + if (Date.now() - nfpStartTime > NFP_TIMEOUT) { + window.debugLog('NFP calculation timeout for part ' + part.source + ' rotation ' + j); + break; + } + + window.debugLog('Getting NFP for part ' + part.source + ' rotation ' + j + ' current part rotation: ' + part.rotation); sheetNfp = getInnerNfp(sheet, part, config); + window.debugLog('NFP result for part ' + part.source + ' rotation ' + part.rotation + ': ' + JSON.stringify(sheetNfp)); if (sheetNfp) { break; @@ -822,10 +995,13 @@ function placeParts(sheets, parts, config, nestindex) { // first placement, put it on the top left corner for (let j = 0; j < sheetNfp.length; j++) { for (let k = 0; k < sheetNfp[j].length; k++) { - if (position === null || sheetNfp[j][k].x - part[0].x < position.x || (GeometryUtil.almostEqual(sheetNfp[j][k].x - part[0].x, position.x) && sheetNfp[j][k].y - part[0].y < position.y)) { + var candidateX = sheetNfp[j][k].x - part[0].x; + var candidateY = sheetNfp[j][k].y - part[0].y; + window.debugLog('FIRST PLACEMENT DEBUG: NFP point ' + JSON.stringify(sheetNfp[j][k]) + ' part[0] ' + JSON.stringify(part[0]) + ' candidate position ' + candidateX + ',' + candidateY); + if (position === null || candidateX < position.x || (GeometryUtil.almostEqual(candidateX, position.x) && candidateY < position.y)) { position = { - x: sheetNfp[j][k].x - part[0].x, - y: sheetNfp[j][k].y - part[0].y, + x: candidateX, + y: candidateY, id: part.id, rotation: part.rotation, source: part.source, @@ -835,11 +1011,16 @@ function placeParts(sheets, parts, config, nestindex) { } } if (position === null) { - // console.log(sheetNfp); + // window.debugLog(sheetNfp); } + + window.debugLog('SELECTED POSITION for part ' + part.id + ' rotation ' + part.rotation + ': ' + JSON.stringify(position)); placements.push(position); placed.push(part); + // Track placed part area for utilisation calculation + totalPlacedPartArea += Math.abs(GeometryUtil.polygonArea(part)); + continue; } @@ -977,7 +1158,7 @@ function placeParts(sheets, parts, config, nestindex) { } } } catch (e) { - // console.log('Error processing hole:', e); + // window.debugLog('Error processing hole:', e); // Continue with next hole } } @@ -985,7 +1166,7 @@ function placeParts(sheets, parts, config, nestindex) { } } } catch (e) { - // console.log('Error in hole detection:', e); + // window.debugLog('Error in hole detection:', e); // Continue with normal placement, ignoring holes } @@ -1004,11 +1185,11 @@ function placeParts(sheets, parts, config, nestindex) { validHolePositions.push(holePositions[j]); } } catch (e) { - // console.log('Error validating hole position:', e); + // window.debugLog('Error validating hole position:', e); } } holePositions = validHolePositions; - // console.log(`Found ${holePositions.length} valid hole positions for part ${part.source}`); + // window.debugLog(`Found ${holePositions.length} valid hole positions for part ${part.source}`); } var clipperSheetNfp = innerNfpToClipperCoordinates(sheetNfp, config); @@ -1052,7 +1233,7 @@ function placeParts(sheets, parts, config, nestindex) { } if (error || !clipper.Execute(ClipperLib.ClipType.ctUnion, combinedNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)) { - // console.log('clipper error', error); + // window.debugLog('clipper error', error); continue; } @@ -1060,7 +1241,7 @@ function placeParts(sheets, parts, config, nestindex) { nfp: combinedNfp, index: placed.length - 1 }; - // console.log('save cache', placed.length - 1); + // window.debugLog('save cache', placed.length - 1); // difference with sheet polygon var finalNfp = new ClipperLib.Paths(); @@ -1172,7 +1353,7 @@ function placeParts(sheets, parts, config, nestindex) { } if (!combinedHull) { - // console.warn("Failed to calculate convex hull"); + // window.debugLog("Failed to calculate convex hull"); continue; } @@ -1312,7 +1493,7 @@ function placeParts(sheets, parts, config, nestindex) { return 0; }); - // console.log(`Sorted hole positions. Prioritizing distribution across ${holeUtilization.size} used holes out of ${new Set(holePositions.map(h => `${h.parentIndex}_${h.holeIndex}`)).size} total holes`); + // window.debugLog(`Sorted hole positions. Prioritizing distribution across ${holeUtilization.size} used holes out of ${new Set(holePositions.map(h => `${h.parentIndex}_${h.holeIndex}`)).size} total holes`); for (let j = 0; j < holePositions.length; j++) { let holeShift = holePositions[j]; @@ -1351,7 +1532,7 @@ function placeParts(sheets, parts, config, nestindex) { // Apply a small bonus for unused holes (just enough to break ties) if (partsInThisHole === 0) { area *= 0.99; // 1% bonus for prioritizing empty holes - // console.log(`Small priority bonus for unused hole ${holeKey}`); + // window.debugLog(`Small priority bonus for unused hole ${holeKey}`); } } else if (config.placementType == 'convexhull') { @@ -1434,7 +1615,7 @@ function placeParts(sheets, parts, config, nestindex) { var partArea = Math.abs(ClipperLib.Clipper.Area(clipperPart)); if (Math.abs(intersectionArea - partArea) > (partArea * 0.01)) { // 1% tolerance isValidHolePlacement = false; - // console.log(`Part not fully contained in hole: ${part.source}`); + // window.debugLog(`Part not fully contained in hole: ${part.source}`); } } else { isValidHolePlacement = false; @@ -1463,7 +1644,7 @@ function placeParts(sheets, parts, config, nestindex) { if (dx < proximityThreshold || dy < proximityThreshold) { // This placement uses contour of another part - give it a bonus contourScore += 5.0; // This value can be tuned - // console.log(`Found contour alignment in hole between ${part.source} and ${placed[m].source}`); + // window.debugLog(`Found contour alignment in hole between ${part.source} and ${placed[m].source}`); } } } @@ -1484,15 +1665,15 @@ function placeParts(sheets, parts, config, nestindex) { // if (fillRatio > 0.6) { // // Very large parts (60%+ of hole) get maximum benefit // area *= 0.4; // 60% reduction - // // console.log(`Large part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying maximum packing bonus`); + // // window.debugLog(`Large part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying maximum packing bonus`); // } else if (fillRatio > 0.3) { // // Medium parts (30-60% of hole) get significant benefit // area *= 0.5; // 50% reduction - // // console.log(`Medium part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying major packing bonus`); + // // window.debugLog(`Medium part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying major packing bonus`); // } else if (fillRatio > 0.1) { // // Smaller parts (10-30% of hole) get moderate benefit // area *= 0.6; // 40% reduction - // // console.log(`Small part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying standard packing bonus`); + // // window.debugLog(`Small part ${part.source} fills ${Math.round(fillRatio*100)}% of hole - applying standard packing bonus`); // } // Now apply standard sheet-like placement optimization for parts already in the hole const partsInSameHole = []; @@ -1558,7 +1739,7 @@ function placeParts(sheets, parts, config, nestindex) { // Better alignments get lower multipliers (better scores) const qualityMultiplier = Math.max(0.7, 0.9 - (bestAlignment / 100) - (alignmentCount * 0.05)); area *= qualityMultiplier; - // console.log(`Applied sheet-like alignment strategy in hole with quality ${(1-qualityMultiplier)*100}%`); + // window.debugLog(`Applied sheet-like alignment strategy in hole with quality ${(1-qualityMultiplier)*100}%`); } } } @@ -1580,17 +1761,17 @@ function placeParts(sheets, parts, config, nestindex) { ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)) { if (clipSolution.length > 0) { isValidHolePlacement = false; - // console.log(`Part overlaps with other part: ${part.source} with ${placed[m].source}`); + // window.debugLog(`Part overlaps with other part: ${part.source} with ${placed[m].source}`); break; } } } } if (isValidHolePlacement) { - // console.log(`Valid hole placement found for part ${part.source} in hole of ${parentPart.source}`); + // window.debugLog(`Valid hole placement found for part ${part.source} in hole of ${parentPart.source}`); } } catch (e) { - // console.log('Error in hole containment check:', e); + // window.debugLog('Error in hole containment check:', e); isValidHolePlacement = false; } @@ -1613,30 +1794,34 @@ function placeParts(sheets, parts, config, nestindex) { } } } catch (e) { - // console.log('Error processing hole positions:', e); + // window.debugLog('Error processing hole positions:', e); } // Continue with best non-hole position if available if (position) { // Debug placement with less verbose logging if (position.inHole) { - // console.log(`Placed part ${position.source} in hole of part ${placed[position.parentIndex].source}`); + // window.debugLog(`Placed part ${position.source} in hole of part ${placed[position.parentIndex].source}`); // Adjust the part placement specifically for hole placement // This prevents the part from being considered as overlapping with its parent var parentPart = placed[position.parentIndex]; - // console.log(`Hole placement - Parent: ${parentPart.source}, Child: ${part.source}`); + // window.debugLog(`Hole placement - Parent: ${parentPart.source}, Child: ${part.source}`); // Mark the relationship to prevent overlap checks between them in future placements position.parentId = parentPart.id; } placed.push(part); placements.push(position); + + // Track placed part area for utilisation calculation + totalPlacedPartArea += Math.abs(GeometryUtil.polygonArea(part)); + if (position.mergedLength) { totalMerged += position.mergedLength; } } else { // Just log part source without additional details - // console.log(`No placement for part ${part.source}`); + // window.debugLog(`No placement for part ${part.source}`); } // send placement progress signal @@ -1644,14 +1829,18 @@ function placeParts(sheets, parts, config, nestindex) { for (let j = 0; j < allplacements.length; j++) { placednum += allplacements[j].sheetplacements.length; } - //console.log(placednum, totalnum); + //window.debugLog(placednum, totalnum); ipcRenderer.send('background-progress', { index: nestindex, progress: 0.5 + 0.5 * (placednum / totalnum) }); // console.timeEnd('placement'); } - //if(minwidth){ - fitness += (minwidth / sheetarea) + minarea; - //} + // Add fitness components, protecting against NaN from division by zero + if (minwidth !== null && minarea !== null && sheetarea > 0) { + fitness += (minwidth / sheetarea) + minarea; + } else if (minwidth !== null && minarea !== null) { + // If sheetarea is 0 or very small, just add the minarea component + fitness += minarea; + } for (let i = 0; i < placed.length; i++) { var index = parts.indexOf(placed[i]); @@ -1670,17 +1859,23 @@ function placeParts(sheets, parts, config, nestindex) { if (sheets.length == 0) { break; } + + p++; } // there were parts that couldn't be placed // scale this value high - we really want to get all the parts in, even at the cost of opening new sheets - console.log('UNPLACED PARTS', parts.length, 'of', totalnum); + window.debugLog('UNPLACED PARTS', parts.length, 'of', totalnum); for (let i = 0; i < parts.length; i++) { - // console.log(`Fitness before unplaced penalty: ${fitness}`); - const penalty = 100000000 * ((Math.abs(GeometryUtil.polygonArea(parts[i])) * 100) / totalsheetarea); - // console.log(`Penalty for unplaced part ${parts[i].source}: ${penalty}`); + // window.debugLog(`Fitness before unplaced penalty: ${fitness}`); + const partArea = Math.abs(GeometryUtil.polygonArea(parts[i])); + // Protect against division by zero + const penalty = totalsheetarea > 0 ? + 100000000 * ((partArea * 100) / totalsheetarea) : + 100000000 * partArea; // Use partArea as base penalty when totalsheetarea is 0 + // window.debugLog(`Penalty for unplaced part ${parts[i].source}: ${penalty}`); fitness += penalty; - // console.log(`Fitness after unplaced penalty: ${fitness}`); + // window.debugLog(`Fitness after unplaced penalty: ${fitness}`); } // Enhance fitness calculation to encourage more efficient hole usage @@ -1702,8 +1897,8 @@ function placeParts(sheets, parts, config, nestindex) { area: Math.abs(GeometryUtil.polygonArea(placed[partIndex])) * 2 }); // Base reward for any part placed in a hole - // console.log(`Part ${placed[partIndex].source} placed in hole of part ${placed[placements[j].parentIndex].source}`); - // console.log(`Part area: ${Math.abs(GeometryUtil.polygonArea(placed[partIndex]))}, Hole area: ${Math.abs(GeometryUtil.polygonArea(placed[placements[j].parentIndex]))}`); + // window.debugLog(`Part ${placed[partIndex].source} placed in hole of part ${placed[placements[j].parentIndex].source}`); + // window.debugLog(`Part area: ${Math.abs(GeometryUtil.polygonArea(placed[partIndex]))}, Hole area: ${Math.abs(GeometryUtil.polygonArea(placed[placements[j].parentIndex]))}`); fitness -= (Math.abs(GeometryUtil.polygonArea(placed[partIndex])) / totalsheetarea / 100); } } @@ -1740,12 +1935,27 @@ function placeParts(sheets, parts, config, nestindex) { // send finish progress signal ipcRenderer.send('background-progress', { index: nestindex, progress: -1 }); - console.log('WATCH', allplacements); + window.debugLog('WATCH', allplacements); + + // Use the tracked total placed part area for utilisation calculation + const utilisation = totalsheetarea > 0 && !isNaN(totalPlacedPartArea) ? + (totalPlacedPartArea / totalsheetarea) * 100 : 0; + window.debugLog(`Utilisation of the sheet(s): ${utilisation.toFixed(2)}%`); - const utilisation = totalsheetarea > 0 ? (area / totalsheetarea) * 100 : 0; - console.log(`Utilisation of the sheet(s): ${utilisation.toFixed(2)}%`); + // Ensure fitness is never NaN - this would break the genetic algorithm + if (isNaN(fitness)) { + window.debugLog('Fitness calculation resulted in NaN, using fallback value'); + fitness = 1000000; // High penalty value as fallback + } + + // Ensure utilisation is never NaN + let finalUtilisation = utilisation; + if (isNaN(utilisation)) { + window.debugLog('Utilisation calculation resulted in NaN, using 0'); + finalUtilisation = 0; + } - return { placements: allplacements, fitness: fitness, area: sheetarea, totalarea: totalsheetarea, mergedLength: totalMerged, utilisation: utilisation }; + return { placements: allplacements, fitness: fitness, area: sheetarea, totalarea: totalsheetarea, mergedLength: totalMerged, utilisation: finalUtilisation }; } // New helper function to analyze sheet holes @@ -1827,7 +2037,7 @@ function analyzeParts(parts, averageHoleArea, config) { }; } - // console.log(`Found ${partsWithHoles.length} parts with holes`); + // window.debugLog(`Found ${partsWithHoles.length} parts with holes`); // Second pass: check which parts fit into other parts' holes for (let i = 0; i < parts.length; i++) { @@ -1917,5 +2127,5 @@ function analyzeParts(parts, averageHoleArea, config) { // clipperjs uses alerts for warnings function alert(message) { - console.log('alert: ', message); + window.debugLog('alert: ', message); } diff --git a/main/deepnest.js b/main/deepnest.js index b63896f..e4c67d4 100755 --- a/main/deepnest.js +++ b/main/deepnest.js @@ -1289,7 +1289,7 @@ export class DeepNest { filenames[j] = filename; } - this.eventEmitter.send("background-start", { + let send = { index: i, sheets: sheets, sheetids: sheetids, @@ -1301,7 +1301,9 @@ export class DeepNest { sources: sources, children: children, filenames: filenames, - }); + } + console.log("background-start", send); + this.eventEmitter.send("background-start", send); running++; } } diff --git a/main/util/geometryutil.js b/main/util/geometryutil.js index 95a4315..a85c97b 100644 --- a/main/util/geometryutil.js +++ b/main/util/geometryutil.js @@ -1572,12 +1572,31 @@ return null; } + // Calculate NFP corners + var nfpMinX = minAx - minBx + B[0].x; + var nfpMaxX = maxAx - maxBx + B[0].x; + var nfpMinY = minAy - minBy + B[0].y; + var nfpMaxY = maxAy - maxBy + B[0].y; + + // Handle exact fit case where NFP would be degenerate + if (_almostEqual(nfpMinX, nfpMaxX) && _almostEqual(nfpMinY, nfpMaxY)) { + // Part exactly fits - return a single point NFP + return [ + [ + { x: nfpMinX, y: nfpMinY }, + { x: nfpMinX + TOL, y: nfpMinY }, + { x: nfpMinX + TOL, y: nfpMinY + TOL }, + { x: nfpMinX, y: nfpMinY + TOL }, + ], + ]; + } + return [ [ - { x: minAx - minBx + B[0].x, y: minAy - minBy + B[0].y }, - { x: maxAx - maxBx + B[0].x, y: minAy - minBy + B[0].y }, - { x: maxAx - maxBx + B[0].x, y: maxAy - maxBy + B[0].y }, - { x: minAx - minBx + B[0].x, y: maxAy - maxBy + B[0].y }, + { x: nfpMinX, y: nfpMinY }, + { x: nfpMaxX, y: nfpMinY }, + { x: nfpMaxX, y: nfpMaxY }, + { x: nfpMinX, y: nfpMaxY }, ], ]; }, @@ -1590,6 +1609,14 @@ return null; } + // Use optimized rectangle algorithm for rectangular bins (interior NFP only) + if (!inside && this.isRectangle(A)) { + var rectangleNfp = this.noFitPolygonRectangle(A, B); + if (rectangleNfp) { + return rectangleNfp; + } + } + A.offsetx = 0; A.offsety = 0; diff --git a/package-lock.json b/package-lock.json index 9dd688f..7f9ae91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@electron/rebuild": "4.0.1", "@eslint/js": "^9.26.0", "@playwright/test": "1.52.0", - "@types/node": "22.15.17", + "@types/node": "^22.15.17", "cross-replace": "0.2.0", "electron": "34.5.5", "electron-builder": "26.0.15", diff --git a/package.json b/package.json index c5e57ce..860dac1 100644 --- a/package.json +++ b/package.json @@ -50,13 +50,13 @@ ], "devDependencies": { "@electron/packager": "18.3.6", - "electron-builder": "26.0.15", "@electron/rebuild": "4.0.1", "@eslint/js": "^9.26.0", "@playwright/test": "1.52.0", - "@types/node": "22.15.17", + "@types/node": "^22.15.17", "cross-replace": "0.2.0", "electron": "34.5.5", + "electron-builder": "26.0.15", "eslint": "^9.26.0", "husky": "^9.1.7", "lint-staged": "^15.5.2", diff --git a/test_cases/failed_1000x1000_1000x1000.svg b/test_cases/failed_1000x1000_1000x1000.svg new file mode 100644 index 0000000..69fcf85 --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/failed_1000x1000_1000x1000_2.svg b/test_cases/failed_1000x1000_1000x1000_2.svg new file mode 100644 index 0000000..f45cca8 --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/failed_1000x1000_1000x1000_3.svg b/test_cases/failed_1000x1000_1000x1000_3.svg new file mode 100644 index 0000000..9be27a6 --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000_3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/failed_1000x1000_1000x1000_4.svg b/test_cases/failed_1000x1000_1000x1000_4.svg new file mode 100644 index 0000000..54e36c9 --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000_4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/failed_1000x1000_1000x1000_5.svg b/test_cases/failed_1000x1000_1000x1000_5.svg new file mode 100644 index 0000000..3323f3c --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000_5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/failed_1000x1000_1000x1000_6.svg b/test_cases/failed_1000x1000_1000x1000_6.svg new file mode 100644 index 0000000..945ff6a --- /dev/null +++ b/test_cases/failed_1000x1000_1000x1000_6.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/success_1000x1000_1000x1000.svg b/test_cases/success_1000x1000_1000x1000.svg new file mode 100644 index 0000000..aea5a04 --- /dev/null +++ b/test_cases/success_1000x1000_1000x1000.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test_cases/success_1000x1000_1000x1000_2.svg b/test_cases/success_1000x1000_1000x1000_2.svg new file mode 100644 index 0000000..20dec1f --- /dev/null +++ b/test_cases/success_1000x1000_1000x1000_2.svg @@ -0,0 +1 @@ + \ No newline at end of file