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>
5.3 KiB
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 asprogram-NNN(zero-padded). Parsed byProgramReader, 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
{
"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": 2at the top level for future format migration. - Drawing
idvalues are 1-indexed, matchingprograms/program-Nfilenames. - Part
rotationis stored in radians (matches internal domain model, no conversion needed). - Part
drawingIdreferences the drawing'sidin thedrawingsarray. - 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.requiredis the only quantity persisted;nestedis computed at load time from part placements.- Units: enum values match the domain model:
InchesorMillimeters. - Size: uses
width/heightmatching theOpenNest.Geometry.Sizestruct. - Drawing.Priority and Drawing.Constraints (stepAngle, startAngle, endAngle, allow180Equivalent) are now persisted (v1 omitted these).
- Empty collections:
drawingsandplatesarrays are always present (may be empty[]). Theprograms/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)andNestReader(Stream stream)constructors preserved.NestReader.Read()returnsNest.NestWriter(Nest nest)constructor preserved.NestWriter.Write(string file)returnsbool.
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)