c2534ef08b
Replace three separate XML metadata files (info, drawing-info, plate-info) and per-plate G-code placement files with a single nest.json inside the ZIP archive. Programs remain as G-code text under a programs/ folder. This eliminates ~400 lines of hand-written XML read/write code and fragile ID-based dictionary linking. Now uses System.Text.Json with DTO records for clean serialization. Also adds Priority and Constraints fields to drawing serialization (previously omitted). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
135 lines
5.3 KiB
Markdown
135 lines
5.3 KiB
Markdown
# Nest File Format v2 Design
|
|
|
|
## Problem
|
|
|
|
The current nest file format stores metadata across three separate XML files (`info`, `drawing-info`, `plate-info`) plus per-plate G-code files for part placements inside a ZIP archive. This results in ~400 lines of hand-written XML read/write code, fragile dictionary-linking to reconnect drawings/plates by ID after parsing, and the overhead of running the full G-code parser just to extract part positions.
|
|
|
|
## Design
|
|
|
|
### File Structure
|
|
|
|
The nest file remains a ZIP archive. Contents:
|
|
|
|
```
|
|
nest.json
|
|
programs/
|
|
program-1
|
|
program-2
|
|
...
|
|
```
|
|
|
|
- **`nest.json`** — single JSON file containing all metadata and part placements.
|
|
- **`programs/program-N`** — G-code text for each drawing's CNC program (1-indexed, no zero-padding). Previously stored at the archive root as `program-NNN` (zero-padded). Parsed by `ProgramReader`, written by existing G-code serialization logic. Format unchanged.
|
|
|
|
Plate G-code files (`plate-NNN`) are removed. Part placements are stored inline in `nest.json`.
|
|
|
|
### JSON Schema
|
|
|
|
```json
|
|
{
|
|
"version": 2,
|
|
"name": "string",
|
|
"units": "Inches | Millimeters",
|
|
"customer": "string",
|
|
"dateCreated": "2026-03-12T10:30:00",
|
|
"dateLastModified": "2026-03-12T14:00:00",
|
|
"notes": "string (plain JSON, no URI-escaping)",
|
|
"plateDefaults": {
|
|
"size": { "width": 0.0, "height": 0.0 },
|
|
"thickness": 0.0,
|
|
"quadrant": 1,
|
|
"partSpacing": 0.0,
|
|
"material": { "name": "string", "grade": "string", "density": 0.0 },
|
|
"edgeSpacing": { "left": 0.0, "top": 0.0, "right": 0.0, "bottom": 0.0 }
|
|
},
|
|
"drawings": [
|
|
{
|
|
"id": 1,
|
|
"name": "string",
|
|
"customer": "string",
|
|
"color": { "a": 255, "r": 0, "g": 0, "b": 0 },
|
|
"quantity": { "required": 0 },
|
|
"priority": 0,
|
|
"constraints": {
|
|
"stepAngle": 0.0,
|
|
"startAngle": 0.0,
|
|
"endAngle": 0.0,
|
|
"allow180Equivalent": false
|
|
},
|
|
"material": { "name": "string", "grade": "string", "density": 0.0 },
|
|
"source": {
|
|
"path": "string",
|
|
"offset": { "x": 0.0, "y": 0.0 }
|
|
}
|
|
}
|
|
],
|
|
"plates": [
|
|
{
|
|
"id": 1,
|
|
"size": { "width": 0.0, "height": 0.0 },
|
|
"thickness": 0.0,
|
|
"quadrant": 1,
|
|
"quantity": 1,
|
|
"partSpacing": 0.0,
|
|
"material": { "name": "string", "grade": "string", "density": 0.0 },
|
|
"edgeSpacing": { "left": 0.0, "top": 0.0, "right": 0.0, "bottom": 0.0 },
|
|
"parts": [
|
|
{ "drawingId": 1, "x": 0.0, "y": 0.0, "rotation": 0.0 }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Key details:
|
|
- **Version**: `"version": 2` at the top level for future format migration.
|
|
- Drawing `id` values are 1-indexed, matching `programs/program-N` filenames.
|
|
- Part `rotation` is stored in **radians** (matches internal domain model, no conversion needed).
|
|
- Part `drawingId` references the drawing's `id` in the `drawings` array.
|
|
- **Dates**: local time, serialized via `DateTime.ToString("o")` (ISO 8601 round-trip format with timezone offset).
|
|
- **Notes**: stored as plain JSON strings. The v1 URI-escaping (`Uri.EscapeDataString`) is not needed since JSON handles special characters natively.
|
|
- `quantity.required` is the only quantity persisted; `nested` is computed at load time from part placements.
|
|
- **Units**: enum values match the domain model: `Inches` or `Millimeters`.
|
|
- **Size**: uses `width`/`height` matching the `OpenNest.Geometry.Size` struct.
|
|
- **Drawing.Priority** and **Drawing.Constraints** (stepAngle, startAngle, endAngle, allow180Equivalent) are now persisted (v1 omitted these).
|
|
- **Empty collections**: `drawings` and `plates` arrays are always present (may be empty `[]`). The `programs/` folder is empty when there are no drawings.
|
|
|
|
### Serialization Approach
|
|
|
|
Use `System.Text.Json` with small DTO (Data Transfer Object) classes for serialization. The DTOs map between the domain model and the JSON structure, keeping serialization concerns out of the domain classes.
|
|
|
|
### What Changes
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `NestWriter.cs` | Replace all XML writing and plate G-code writing with JSON serialization. Programs written to `programs/` folder. |
|
|
| `NestReader.cs` | Replace all XML parsing, plate G-code parsing, and dictionary-linking with JSON deserialization. Programs read from `programs/` folder. |
|
|
|
|
### What Stays the Same
|
|
|
|
| File | Reason |
|
|
|------|--------|
|
|
| `ProgramReader.cs` | G-code parsing for CNC programs is unchanged. |
|
|
| `NestWriter` G-code writing (`WriteDrawing`, `GetCodeString`) | G-code serialization for programs is unchanged. |
|
|
| `DxfImporter.cs`, `DxfExporter.cs`, `Extensions.cs` | Unrelated to nest file format. |
|
|
| Domain model classes | No changes needed. |
|
|
|
|
### Public API
|
|
|
|
The public API is unchanged:
|
|
- `NestReader(string file)` and `NestReader(Stream stream)` constructors preserved.
|
|
- `NestReader.Read()` returns `Nest`.
|
|
- `NestWriter(Nest nest)` constructor preserved.
|
|
- `NestWriter.Write(string file)` returns `bool`.
|
|
|
|
### Callers (no changes needed)
|
|
|
|
- `MainForm.cs:329` — `new NestReader(path)`
|
|
- `MainForm.cs:363` — `new NestReader(dlg.FileName)`
|
|
- `EditNestForm.cs:212` — `new NestWriter(Nest)`
|
|
- `EditNestForm.cs:223` — `new NestWriter(nst)`
|
|
- `Document.cs:27` — `new NestWriter(Nest)`
|
|
- `OpenNest.Console/Program.cs:94` — `new NestReader(nestFile)`
|
|
- `OpenNest.Console/Program.cs:190` — `new NestWriter(nest)`
|
|
- `OpenNest.Mcp/InputTools.cs:30` — `new NestReader(path)`
|