fix: correct Size width/length ordering and add CLI docs to README
Size.Parse and ToString now use WxL format (width first) matching the natural convention. Fixed the Plate(w,l) constructor which was swapping args when creating Size. Fixed PlateView.DrawPlate and DrawControl ZoomToArea which had width/length mapped to the wrong screen axes. Simplified Console --size parsing to use Size.TryParse instead of manual split with confusing PlateHeight/PlateWidth fields. Added Command-Line Interface section to README documenting all console options. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -96,12 +96,8 @@ static class NestConsole
|
||||
o.Spacing = double.Parse(args[++i]);
|
||||
break;
|
||||
case "--size" when i + 1 < args.Length:
|
||||
var parts = args[++i].Split('x');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
o.PlateHeight = double.Parse(parts[0]);
|
||||
o.PlateWidth = double.Parse(parts[1]);
|
||||
}
|
||||
if (Size.TryParse(args[++i], out var sz))
|
||||
o.PlateSize = sz;
|
||||
break;
|
||||
case "--check-overlaps":
|
||||
o.CheckOverlaps = true;
|
||||
@@ -198,14 +194,14 @@ static class NestConsole
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!options.PlateWidth.HasValue || !options.PlateHeight.HasValue)
|
||||
if (!options.PlateSize.HasValue)
|
||||
{
|
||||
Console.Error.WriteLine("Error: --size WxH is required when importing DXF files without a nest");
|
||||
Console.Error.WriteLine("Error: --size WxL is required when importing DXF files without a nest");
|
||||
return null;
|
||||
}
|
||||
|
||||
var newNest = new Nest { Name = "DXF Import" };
|
||||
var plate = new Plate { Size = new Size(options.PlateWidth.Value, options.PlateHeight.Value) };
|
||||
var plate = new Plate { Size = options.PlateSize.Value };
|
||||
newNest.Plates.Add(plate);
|
||||
|
||||
foreach (var dxf in dxfFiles)
|
||||
@@ -278,8 +274,8 @@ static class NestConsole
|
||||
// Only apply size override when it wasn't already used to create the plate.
|
||||
var hasDxfOnly = !options.InputFiles.Any(f => f.EndsWith(".zip", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (options.PlateWidth.HasValue && options.PlateHeight.HasValue && !hasDxfOnly)
|
||||
plate.Size = new Size(options.PlateWidth.Value, options.PlateHeight.Value);
|
||||
if (options.PlateSize.HasValue && !hasDxfOnly)
|
||||
plate.Size = options.PlateSize.Value;
|
||||
}
|
||||
|
||||
static Drawing ResolveDrawing(Nest nest, Options options)
|
||||
@@ -302,7 +298,7 @@ static class NestConsole
|
||||
{
|
||||
Console.WriteLine($"Nest: {nest.Name}");
|
||||
var wa = plate.WorkArea();
|
||||
Console.WriteLine($"Plate: {options.PlateIndex} ({plate.Size.Length:F1} x {plate.Size.Width:F1}), spacing={plate.PartSpacing:F2}, edge=({plate.EdgeSpacing.Left},{plate.EdgeSpacing.Bottom},{plate.EdgeSpacing.Right},{plate.EdgeSpacing.Top}), workArea={wa.Length:F1}x{wa.Width:F1}");
|
||||
Console.WriteLine($"Plate: {options.PlateIndex} ({plate.Size.Width:F1} x {plate.Size.Length:F1}), spacing={plate.PartSpacing:F2}, edge=({plate.EdgeSpacing.Left},{plate.EdgeSpacing.Bottom},{plate.EdgeSpacing.Right},{plate.EdgeSpacing.Top}), workArea={wa.Width:F1}x{wa.Length:F1}");
|
||||
Console.WriteLine($"Drawing: {drawing.Name}");
|
||||
Console.WriteLine(options.KeepParts
|
||||
? $"Keeping {existingCount} existing parts"
|
||||
@@ -392,7 +388,7 @@ static class NestConsole
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Modes:");
|
||||
Console.Error.WriteLine(" <nest.zip> Load nest and fill (existing behavior)");
|
||||
Console.Error.WriteLine(" <part.dxf> --size LxW Import DXF, create plate, and fill");
|
||||
Console.Error.WriteLine(" <part.dxf> --size WxL Import DXF, create plate, and fill");
|
||||
Console.Error.WriteLine(" <nest.zip> <part.dxf> Load nest and add imported DXF drawings");
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Options:");
|
||||
@@ -400,7 +396,7 @@ static class NestConsole
|
||||
Console.Error.WriteLine(" --plate <index> Plate index to fill (default: 0)");
|
||||
Console.Error.WriteLine(" --quantity <n> Max parts to place (default: 0 = unlimited)");
|
||||
Console.Error.WriteLine(" --spacing <value> Override part spacing");
|
||||
Console.Error.WriteLine(" --size <LxW> Override plate size (e.g. 120x60); required for DXF-only mode");
|
||||
Console.Error.WriteLine(" --size <WxL> Override plate size (e.g. 60x120); required for DXF-only mode");
|
||||
Console.Error.WriteLine(" --output <path> Output nest file path (default: <input>-result.zip)");
|
||||
Console.Error.WriteLine(" --template <path> Nest template for plate defaults (thickness, quadrant, material, spacing)");
|
||||
Console.Error.WriteLine(" --autonest Use NFP-based mixed-part autonesting instead of linear fill");
|
||||
@@ -419,8 +415,7 @@ static class NestConsole
|
||||
public string OutputFile;
|
||||
public int Quantity;
|
||||
public double? Spacing;
|
||||
public double? PlateWidth;
|
||||
public double? PlateHeight;
|
||||
public Size? PlateSize;
|
||||
public bool CheckOverlaps;
|
||||
public bool NoSave;
|
||||
public bool NoLog;
|
||||
|
||||
@@ -6,14 +6,14 @@ namespace OpenNest.Geometry
|
||||
{
|
||||
public Size(double width, double length)
|
||||
{
|
||||
Length = length;
|
||||
Width = width;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public double Length;
|
||||
|
||||
public double Width;
|
||||
|
||||
public double Length;
|
||||
|
||||
public static Size Parse(string size)
|
||||
{
|
||||
var a = size.ToUpper().Split('X');
|
||||
@@ -21,8 +21,8 @@ namespace OpenNest.Geometry
|
||||
if (a.Length > 2)
|
||||
throw new FormatException("Invalid size format.");
|
||||
|
||||
var length = double.Parse(a[0]);
|
||||
var width = double.Parse(a[1]);
|
||||
var width = double.Parse(a[0]);
|
||||
var length = double.Parse(a[1]);
|
||||
|
||||
return new Size(width, length);
|
||||
}
|
||||
@@ -42,14 +42,8 @@ namespace OpenNest.Geometry
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} x {1}", Length, Width);
|
||||
}
|
||||
|
||||
public string ToString(int decimalPlaces)
|
||||
{
|
||||
return string.Format("{0} x {1}", System.Math.Round(Length, decimalPlaces), System.Math.Round(Width, decimalPlaces));
|
||||
}
|
||||
public override string ToString() => $"{Width} x {Length}";
|
||||
|
||||
public string ToString(int decimalPlaces) => $"{System.Math.Round(Width, decimalPlaces)} x {System.Math.Round(Length, decimalPlaces)}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenNest
|
||||
}
|
||||
|
||||
public Plate(double width, double length)
|
||||
: this(new Size(length, width))
|
||||
: this(new Size(width, length))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace OpenNest.Controls
|
||||
|
||||
public virtual void ZoomToArea(Box box, bool redraw = true)
|
||||
{
|
||||
ZoomToArea(box.X, box.Y, box.Width, box.Length, redraw);
|
||||
ZoomToArea(box.X, box.Y, box.Length, box.Width, redraw);
|
||||
}
|
||||
|
||||
public virtual void ZoomToArea(double x, double y, double width, double height, bool redraw = true)
|
||||
|
||||
@@ -415,14 +415,14 @@ namespace OpenNest.Controls
|
||||
{
|
||||
var plateRect = new RectangleF
|
||||
{
|
||||
Width = LengthWorldToGui(Plate.Size.Width),
|
||||
Height = LengthWorldToGui(Plate.Size.Length)
|
||||
Width = LengthWorldToGui(Plate.Size.Length),
|
||||
Height = LengthWorldToGui(Plate.Size.Width)
|
||||
};
|
||||
|
||||
var edgeSpacingRect = new RectangleF
|
||||
{
|
||||
Width = LengthWorldToGui(Plate.Size.Width - Plate.EdgeSpacing.Left - Plate.EdgeSpacing.Right),
|
||||
Height = LengthWorldToGui(Plate.Size.Length - Plate.EdgeSpacing.Top - Plate.EdgeSpacing.Bottom)
|
||||
Width = LengthWorldToGui(Plate.Size.Length - Plate.EdgeSpacing.Left - Plate.EdgeSpacing.Right),
|
||||
Height = LengthWorldToGui(Plate.Size.Width - Plate.EdgeSpacing.Top - Plate.EdgeSpacing.Bottom)
|
||||
};
|
||||
|
||||
switch (Plate.Quadrant)
|
||||
|
||||
48
README.md
48
README.md
@@ -53,6 +53,51 @@ Or open `OpenNest.sln` in Visual Studio and run the `OpenNest` project.
|
||||
|
||||
<!-- TODO: Add screenshots for each step -->
|
||||
|
||||
## Command-Line Interface
|
||||
|
||||
OpenNest includes a CLI for batch nesting without the GUI — useful for automation, scripting, and CI pipelines.
|
||||
|
||||
```bash
|
||||
dotnet run --project OpenNest.Console/OpenNest.Console.csproj -- <input-files> [options]
|
||||
```
|
||||
|
||||
**Import DXF files and nest onto a plate:**
|
||||
|
||||
```bash
|
||||
# Import a DXF and fill a 60x120 plate
|
||||
dotnet run --project OpenNest.Console/OpenNest.Console.csproj -- part.dxf --size 60x120
|
||||
|
||||
# Import multiple DXFs with NFP-based auto-nesting
|
||||
dotnet run --project OpenNest.Console/OpenNest.Console.csproj -- part1.dxf part2.dxf --size 60x120 --autonest
|
||||
```
|
||||
|
||||
**Work with existing nest files:**
|
||||
|
||||
```bash
|
||||
# Re-fill an existing nest file
|
||||
dotnet run --project OpenNest.Console/OpenNest.Console.csproj -- project.zip
|
||||
|
||||
# Add a new DXF to an existing nest and auto-nest
|
||||
dotnet run --project OpenNest.Console/OpenNest.Console.csproj -- project.zip extra-part.dxf --autonest
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--size <WxL>` | Plate size (e.g. `60x120`). Required for DXF-only mode. |
|
||||
| `--autonest` | Use NFP-based mixed-part nesting instead of linear fill |
|
||||
| `--drawing <name>` | Select which drawing to fill with (default: first) |
|
||||
| `--quantity <n>` | Max parts to place (default: unlimited) |
|
||||
| `--spacing <value>` | Override part spacing |
|
||||
| `--template <path>` | Load plate defaults (thickness, quadrant, material, spacing) from a nest file |
|
||||
| `--output <path>` | Output file path (default: `<input>-result.zip`) |
|
||||
| `--keep-parts` | Keep existing parts instead of clearing before fill |
|
||||
| `--check-overlaps` | Run overlap detection after fill (exits with code 1 if found) |
|
||||
| `--engine <name>` | Select a registered nesting engine |
|
||||
| `--no-save` | Skip saving the output file |
|
||||
| `--no-log` | Skip writing the debug log |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
@@ -68,11 +113,12 @@ OpenNest.sln
|
||||
└── OpenNest.Tests/ # Unit tests
|
||||
```
|
||||
|
||||
For most users, only the first four matter:
|
||||
For most users, only these matter:
|
||||
|
||||
| Project | What it does |
|
||||
|---------|-------------|
|
||||
| **OpenNest** | The app you run. WinForms UI with plate viewer, drawing list, and dialogs. |
|
||||
| **OpenNest.Console** | Command-line interface for batch nesting, scripting, and automation. |
|
||||
| **OpenNest.Core** | The building blocks — parts, plates, drawings, geometry, G-code representation. |
|
||||
| **OpenNest.Engine** | The brains — algorithms that decide where parts go on a plate. |
|
||||
| **OpenNest.IO** | Reads and writes files — DXF (via ACadSharp), G-code, and the `.nest` ZIP format. |
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 55 KiB |
Reference in New Issue
Block a user