Merge branch 'chore/csharpier-sweep'
# Conflicts: # OpenNest.Core/Geometry/ArcFit.cs # OpenNest.Core/Geometry/GeometrySimplifier.cs # OpenNest.Posts.GravographIS/GravographISWriter.cs # OpenNest.Posts.GravographIS/NestPolylineExtractor.cs
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
using ACadSharp;
|
||||
using OpenNest.Bending;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ACadSharp;
|
||||
using OpenNest.Bending;
|
||||
|
||||
namespace OpenNest.IO.Bending
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using ACadSharp;
|
||||
using OpenNest.Bending;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.IO.Bending
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using ACadSharp;
|
||||
using ACadSharp.Entities;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using ACadSharp;
|
||||
using ACadSharp.Entities;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.IO.Bending
|
||||
{
|
||||
@@ -18,15 +18,18 @@ namespace OpenNest.IO.Bending
|
||||
|
||||
private static readonly Regex BendNoteRegex = new Regex(
|
||||
@"(?<direction>UP|DOWN|DN)\s+(?<angle>\d+(\.\d+)?)[^A-Z\d]*R\s*(?<radius>\d+(\.\d+)?)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase
|
||||
);
|
||||
|
||||
private static readonly Regex MTextFormatRegex = new Regex(
|
||||
@"\\[fHCTQWASpOoLlKk][^;]*;|\\P|[{}]|%%[dDpPcC]",
|
||||
RegexOptions.Compiled);
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
private static readonly Regex UnicodeEscapeRegex = new Regex(
|
||||
@"\\U\+([0-9A-Fa-f]{4})",
|
||||
RegexOptions.Compiled);
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
public List<Bend> DetectBends(CadDocument document)
|
||||
{
|
||||
@@ -47,7 +50,7 @@ namespace OpenNest.IO.Bending
|
||||
{
|
||||
StartPoint = start,
|
||||
EndPoint = end,
|
||||
Direction = BendDirection.Unknown
|
||||
Direction = BendDirection.Unknown,
|
||||
};
|
||||
|
||||
var note = FindClosestBendNote(line, bendNotes);
|
||||
@@ -101,7 +104,12 @@ namespace OpenNest.IO.Bending
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AreCollinear(Bend a, Bend b, double angleTolerance, double distanceTolerance)
|
||||
private static bool AreCollinear(
|
||||
Bend a,
|
||||
Bend b,
|
||||
double angleTolerance,
|
||||
double distanceTolerance
|
||||
)
|
||||
{
|
||||
var angleA = a.StartPoint.AngleTo(a.EndPoint);
|
||||
var angleB = b.StartPoint.AngleTo(b.EndPoint);
|
||||
@@ -114,7 +122,8 @@ namespace OpenNest.IO.Bending
|
||||
// Perpendicular distance from midpoint of A to the infinite line through B
|
||||
var midA = new Vector(
|
||||
(a.StartPoint.X + a.EndPoint.X) / 2.0,
|
||||
(a.StartPoint.Y + a.EndPoint.Y) / 2.0);
|
||||
(a.StartPoint.Y + a.EndPoint.Y) / 2.0
|
||||
);
|
||||
|
||||
var dx = b.EndPoint.X - b.StartPoint.X;
|
||||
var dy = b.EndPoint.Y - b.StartPoint.Y;
|
||||
@@ -133,18 +142,22 @@ namespace OpenNest.IO.Bending
|
||||
|
||||
private List<ACadSharp.Entities.Line> FindBendLines(CadDocument document)
|
||||
{
|
||||
return document.Entities
|
||||
.OfType<ACadSharp.Entities.Line>()
|
||||
.Where(l => (l.Layer?.Name == "BEND" || l.Layer?.Name == "0")
|
||||
&& (l.LineType?.Name?.Contains("CENTER") == true
|
||||
|| l.LineType?.Name == "CENTERX2"))
|
||||
return document
|
||||
.Entities.OfType<ACadSharp.Entities.Line>()
|
||||
.Where(l =>
|
||||
(l.Layer?.Name == "BEND" || l.Layer?.Name == "0")
|
||||
&& (
|
||||
l.LineType?.Name?.Contains("CENTER") == true
|
||||
|| l.LineType?.Name == "CENTERX2"
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private List<MText> FindBendNotes(CadDocument document)
|
||||
{
|
||||
return document.Entities
|
||||
.OfType<MText>()
|
||||
return document
|
||||
.Entities.OfType<MText>()
|
||||
.Where(t => GetBendDirection(t.Value) != BendDirection.Unknown)
|
||||
.ToList();
|
||||
}
|
||||
@@ -172,10 +185,24 @@ namespace OpenNest.IO.Bending
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
if (double.TryParse(match.Groups["radius"].Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var radius))
|
||||
if (
|
||||
double.TryParse(
|
||||
match.Groups["radius"].Value,
|
||||
NumberStyles.Any,
|
||||
CultureInfo.InvariantCulture,
|
||||
out var radius
|
||||
)
|
||||
)
|
||||
bend.Radius = radius;
|
||||
|
||||
if (double.TryParse(match.Groups["angle"].Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var angle))
|
||||
if (
|
||||
double.TryParse(
|
||||
match.Groups["angle"].Value,
|
||||
NumberStyles.Any,
|
||||
CultureInfo.InvariantCulture,
|
||||
out var angle
|
||||
)
|
||||
)
|
||||
bend.Angle = angle;
|
||||
}
|
||||
}
|
||||
@@ -186,17 +213,27 @@ namespace OpenNest.IO.Bending
|
||||
return text;
|
||||
|
||||
// Convert \U+XXXX DXF unicode escapes to actual characters
|
||||
var result = UnicodeEscapeRegex.Replace(text, m =>
|
||||
{
|
||||
var codePoint = int.Parse(m.Groups[1].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
return char.ConvertFromUtf32(codePoint);
|
||||
});
|
||||
var result = UnicodeEscapeRegex.Replace(
|
||||
text,
|
||||
m =>
|
||||
{
|
||||
var codePoint = int.Parse(
|
||||
m.Groups[1].Value,
|
||||
NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture
|
||||
);
|
||||
return char.ConvertFromUtf32(codePoint);
|
||||
}
|
||||
);
|
||||
|
||||
// Replace known DXF special characters
|
||||
result = result
|
||||
.Replace("%%d", "°").Replace("%%D", "°")
|
||||
.Replace("%%p", "±").Replace("%%P", "±")
|
||||
.Replace("%%c", "⌀").Replace("%%C", "⌀");
|
||||
.Replace("%%d", "°")
|
||||
.Replace("%%D", "°")
|
||||
.Replace("%%p", "±")
|
||||
.Replace("%%P", "±")
|
||||
.Replace("%%c", "⌀")
|
||||
.Replace("%%C", "⌀");
|
||||
|
||||
// Strip MText formatting codes and braces
|
||||
result = MTextFormatRegex.Replace(result, " ");
|
||||
@@ -207,7 +244,8 @@ namespace OpenNest.IO.Bending
|
||||
|
||||
private MText FindClosestBendNote(ACadSharp.Entities.Line bendLine, List<MText> notes)
|
||||
{
|
||||
if (notes.Count == 0) return null;
|
||||
if (notes.Count == 0)
|
||||
return null;
|
||||
|
||||
MText closest = null;
|
||||
var closestDist = double.MaxValue;
|
||||
@@ -223,7 +261,8 @@ namespace OpenNest.IO.Bending
|
||||
var dist = notePos.DistanceTo(perpPoint);
|
||||
|
||||
var maxAcceptable = note.Height * 2.0;
|
||||
if (dist > maxAcceptable) continue;
|
||||
if (dist > maxAcceptable)
|
||||
continue;
|
||||
|
||||
if (dist < closestDist)
|
||||
{
|
||||
|
||||
@@ -62,8 +62,10 @@ namespace OpenNest.IO.Bom
|
||||
|
||||
var lookupName = item.FileName;
|
||||
|
||||
if (lookupName.EndsWith(".dxf", StringComparison.OrdinalIgnoreCase)
|
||||
|| lookupName.EndsWith(".dwg", StringComparison.OrdinalIgnoreCase))
|
||||
if (
|
||||
lookupName.EndsWith(".dxf", StringComparison.OrdinalIgnoreCase)
|
||||
|| lookupName.EndsWith(".dwg", StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
lookupName = Path.GetFileNameWithoutExtension(lookupName);
|
||||
|
||||
if (!folderExists)
|
||||
@@ -86,13 +88,13 @@ namespace OpenNest.IO.Bom
|
||||
.GroupBy(p => new
|
||||
{
|
||||
Material = (p.Item.Material ?? "").ToUpperInvariant(),
|
||||
Thickness = p.Item.Thickness.Value
|
||||
Thickness = p.Item.Thickness.Value,
|
||||
})
|
||||
.Select(g => new MaterialGroup
|
||||
{
|
||||
Material = g.First().Item.Material ?? "",
|
||||
Thickness = g.Key.Thickness,
|
||||
Parts = g.ToList()
|
||||
Parts = g.ToList(),
|
||||
})
|
||||
.OrderBy(g => g.Material)
|
||||
.ThenBy(g => g.Thickness)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using ClosedXML.Excel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace OpenNest.IO.Bom
|
||||
{
|
||||
@@ -20,7 +20,9 @@ namespace OpenNest.IO.Bom
|
||||
private IXLWorksheet GetPartsWorksheet()
|
||||
{
|
||||
if (!workbook.TryGetWorksheet("Parts", out var worksheet))
|
||||
throw new InvalidOperationException("BOM file does not contain a 'Parts' worksheet.");
|
||||
throw new InvalidOperationException(
|
||||
"BOM file does not contain a 'Parts' worksheet."
|
||||
);
|
||||
return worksheet;
|
||||
}
|
||||
|
||||
@@ -41,7 +43,8 @@ namespace OpenNest.IO.Bom
|
||||
for (var columnIndex = 1; columnIndex <= lastColumn; columnIndex++)
|
||||
{
|
||||
var cell = worksheet.Cell(1, columnIndex);
|
||||
if (cell.IsEmpty()) continue;
|
||||
if (cell.IsEmpty())
|
||||
continue;
|
||||
|
||||
var excelColumnName = cell.GetString().ToUpper();
|
||||
var isMatch = classColumnNames.Any(n => n == excelColumnName);
|
||||
|
||||
@@ -6,17 +6,23 @@ namespace OpenNest.IO.Bom
|
||||
{
|
||||
public static int? ToIntOrNull(this IXLCell cell)
|
||||
{
|
||||
if (cell.IsEmpty()) return null;
|
||||
if (cell.DataType == XLDataType.Number) return (int)cell.GetDouble();
|
||||
if (int.TryParse(cell.GetString(), out var i)) return i;
|
||||
if (cell.IsEmpty())
|
||||
return null;
|
||||
if (cell.DataType == XLDataType.Number)
|
||||
return (int)cell.GetDouble();
|
||||
if (int.TryParse(cell.GetString(), out var i))
|
||||
return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static double? ToDoubleOrNull(this IXLCell cell)
|
||||
{
|
||||
if (cell.IsEmpty()) return null;
|
||||
if (cell.DataType == XLDataType.Number) return cell.GetDouble();
|
||||
if (double.TryParse(cell.GetString(), out var result)) return result;
|
||||
if (cell.IsEmpty())
|
||||
return null;
|
||||
if (cell.DataType == XLDataType.Number)
|
||||
return cell.GetDouble();
|
||||
if (double.TryParse(cell.GetString(), out var result))
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace OpenNest.IO
|
||||
/// </summary>
|
||||
public List<Bend> Bends { get; set; } = new List<Bend>();
|
||||
|
||||
public List<Bending.BendRepairReport> BendRepairReports { get; set; } = new List<Bending.BendRepairReport>();
|
||||
public List<Bending.BendRepairReport> BendRepairReports { get; set; } =
|
||||
new List<Bending.BendRepairReport>();
|
||||
|
||||
/// <summary>
|
||||
/// Bounding box of <see cref="Entities"/> at import time. May be stale
|
||||
|
||||
+47
-22
@@ -26,8 +26,10 @@ namespace OpenNest.IO
|
||||
|
||||
var dxf = Dxf.Import(path, preserveRepairMarks: options.BendRepair != null);
|
||||
|
||||
var cleanup = options.BendRepair == null ? dxf.Entities : dxf.Entities
|
||||
.Where(e => !IsRepairMark(e)).ToList();
|
||||
var cleanup =
|
||||
options.BendRepair == null
|
||||
? dxf.Entities
|
||||
: dxf.Entities.Where(e => !IsRepairMark(e)).ToList();
|
||||
RemoveDuplicateArcs(cleanup);
|
||||
RemoveZeroSweepArcs(cleanup);
|
||||
if (options.BendRepair != null)
|
||||
@@ -36,11 +38,13 @@ namespace OpenNest.IO
|
||||
var bends = new List<Bend>();
|
||||
if (options.DetectBends && dxf.Document != null)
|
||||
{
|
||||
bends = options.BendDetectorName == null
|
||||
? BendDetectorRegistry.AutoDetect(dxf.Document)
|
||||
: BendDetectorRegistry.GetByName(options.BendDetectorName)
|
||||
?.DetectBends(dxf.Document)
|
||||
?? new List<Bend>();
|
||||
bends =
|
||||
options.BendDetectorName == null
|
||||
? BendDetectorRegistry.AutoDetect(dxf.Document)
|
||||
: BendDetectorRegistry
|
||||
.GetByName(options.BendDetectorName)
|
||||
?.DetectBends(dxf.Document)
|
||||
?? new List<Bend>();
|
||||
}
|
||||
|
||||
var repairReports = new List<BendRepairReport>();
|
||||
@@ -50,11 +54,23 @@ namespace OpenNest.IO
|
||||
{
|
||||
// Unitless DXFs require the explicit caller declaration. Never override a conflicting header.
|
||||
var headerUnits = (int)(dxf.Document?.Header.InsUnits ?? 0);
|
||||
var requestedUnits = options.BendRepair.DrawingUnits == BendRepairUnits.Inches ? 1 : 4;
|
||||
var requestedUnits =
|
||||
options.BendRepair.DrawingUnits == BendRepairUnits.Inches ? 1 : 4;
|
||||
if (headerUnits != 0 && headerUnits != requestedUnits)
|
||||
repairReports = bends.Select((b, i) => new BendRepairReport(i, "Skipped",
|
||||
"DXF insertion units conflict with the declared repair units or are unsupported.",
|
||||
b.StartPoint, b.EndPoint, b.StartPoint, b.EndPoint)).ToList();
|
||||
repairReports = bends
|
||||
.Select(
|
||||
(b, i) =>
|
||||
new BendRepairReport(
|
||||
i,
|
||||
"Skipped",
|
||||
"DXF insertion units conflict with the declared repair units or are unsupported.",
|
||||
b.StartPoint,
|
||||
b.EndPoint,
|
||||
b.StartPoint,
|
||||
b.EndPoint
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
else
|
||||
repairReports = BendRepair.Apply(dxf.Entities, bends, options.BendRepair);
|
||||
}
|
||||
@@ -85,7 +101,8 @@ namespace OpenNest.IO
|
||||
result.Bends,
|
||||
options.Quantity,
|
||||
options.Customer,
|
||||
editedProgram: null);
|
||||
editedProgram: null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +136,8 @@ namespace OpenNest.IO
|
||||
IEnumerable<Bend> bends,
|
||||
int quantity,
|
||||
string customer,
|
||||
OpenNest.CNC.Program editedProgram)
|
||||
OpenNest.CNC.Program editedProgram
|
||||
)
|
||||
{
|
||||
var visible = entities as IList<Entity> ?? new List<Entity>(entities);
|
||||
var bendList = bends as IList<Bend> ?? new List<Bend>(bends);
|
||||
@@ -128,7 +146,11 @@ namespace OpenNest.IO
|
||||
var pgm = ConvertGeometry.ToProgram(normalized);
|
||||
|
||||
var offset = Vector.Zero;
|
||||
if (pgm != null && pgm.Codes.Count > 0 && pgm[0].Type == OpenNest.CNC.CodeType.RapidMove)
|
||||
if (
|
||||
pgm != null
|
||||
&& pgm.Codes.Count > 0
|
||||
&& pgm[0].Type == OpenNest.CNC.CodeType.RapidMove
|
||||
)
|
||||
{
|
||||
var rapid = (OpenNest.CNC.RapidMove)pgm[0];
|
||||
offset = rapid.EndPoint;
|
||||
@@ -147,16 +169,18 @@ namespace OpenNest.IO
|
||||
drawing.Program = editedProgram ?? pgm;
|
||||
|
||||
var bendSources = new HashSet<Entity>(
|
||||
bendList.Where(b => b.SourceEntity != null).Select(b => b.SourceEntity));
|
||||
bendList.Where(b => b.SourceEntity != null).Select(b => b.SourceEntity)
|
||||
);
|
||||
|
||||
drawing.SourceEntities = result.Entities
|
||||
.Where(e => !bendSources.Contains(e))
|
||||
.ToList();
|
||||
drawing.SourceEntities = result.Entities.Where(e => !bendSources.Contains(e)).ToList();
|
||||
|
||||
drawing.SuppressedEntityIds = new HashSet<System.Guid>(
|
||||
drawing.SourceEntities
|
||||
.Where(e => !(e.Layer != null && e.Layer.IsVisible && e.IsVisible))
|
||||
.Select(e => e.Id));
|
||||
drawing
|
||||
.SourceEntities.Where(e =>
|
||||
!(e.Layer != null && e.Layer.IsVisible && e.IsVisible)
|
||||
)
|
||||
.Select(e => e.Id)
|
||||
);
|
||||
|
||||
return drawing;
|
||||
}
|
||||
@@ -168,7 +192,8 @@ namespace OpenNest.IO
|
||||
internal static void RemoveZeroSweepArcs(List<Entity> entities)
|
||||
{
|
||||
entities.RemoveAll(e =>
|
||||
e is Arc arc && arc.StartAngle.IsEqualTo(arc.EndAngle, Tolerance.ChainTolerance));
|
||||
e is Arc arc && arc.StartAngle.IsEqualTo(arc.EndAngle, Tolerance.ChainTolerance)
|
||||
);
|
||||
}
|
||||
|
||||
internal static void RemoveDuplicateArcs(List<Entity> entities)
|
||||
|
||||
+64
-19
@@ -42,7 +42,12 @@ namespace OpenNest.IO
|
||||
return width;
|
||||
}
|
||||
|
||||
public List<Entity> RenderText(string text, double height, Vector position, Layer layer = null)
|
||||
public List<Entity> RenderText(
|
||||
string text,
|
||||
double height,
|
||||
Vector position,
|
||||
Layer layer = null
|
||||
)
|
||||
{
|
||||
var scale = height / CapHeight;
|
||||
var entities = new List<Entity>();
|
||||
@@ -97,7 +102,8 @@ namespace OpenNest.IO
|
||||
while (i + 5 < data.Length)
|
||||
{
|
||||
var charCode = data[i] | (data[i + 1] << 8);
|
||||
var offset = data[i + 2] | (data[i + 3] << 8) | (data[i + 4] << 16) | (data[i + 5] << 24);
|
||||
var offset =
|
||||
data[i + 2] | (data[i + 3] << 8) | (data[i + 4] << 16) | (data[i + 5] << 24);
|
||||
|
||||
if (charCode < 0x20 || offset == 0 || offset >= data.Length)
|
||||
break;
|
||||
@@ -110,9 +116,10 @@ namespace OpenNest.IO
|
||||
{
|
||||
var (charCode, offset) = charTable[c];
|
||||
|
||||
var nextOffset = c + 1 < charTable.Count
|
||||
? FindNextOffset(charTable, offset, data.Length)
|
||||
: data.Length;
|
||||
var nextOffset =
|
||||
c + 1 < charTable.Count
|
||||
? FindNextOffset(charTable, offset, data.Length)
|
||||
: data.Length;
|
||||
|
||||
var glyph = ParseGlyph(data, offset, nextOffset);
|
||||
if (glyph != null)
|
||||
@@ -134,7 +141,11 @@ namespace OpenNest.IO
|
||||
return font;
|
||||
}
|
||||
|
||||
private static int FindNextOffset(List<(int charCode, int offset)> table, int currentOffset, int fileLength)
|
||||
private static int FindNextOffset(
|
||||
List<(int charCode, int offset)> table,
|
||||
int currentOffset,
|
||||
int fileLength
|
||||
)
|
||||
{
|
||||
var best = fileLength;
|
||||
foreach (var (_, off) in table)
|
||||
@@ -199,7 +210,8 @@ namespace OpenNest.IO
|
||||
private static int ReadBE16(byte[] data, int offset)
|
||||
{
|
||||
var val = (data[offset] << 8) | data[offset + 1];
|
||||
if (val > 32767) val -= 65536;
|
||||
if (val > 32767)
|
||||
val -= 65536;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -234,19 +246,26 @@ namespace OpenNest.IO
|
||||
|
||||
private const int ArcSamples = 16;
|
||||
|
||||
public List<Entity> ToEntities(double scale, double offsetX, double offsetY, Layer layer = null)
|
||||
public List<Entity> ToEntities(
|
||||
double scale,
|
||||
double offsetX,
|
||||
double offsetY,
|
||||
Layer layer = null
|
||||
)
|
||||
{
|
||||
var entities = new List<Entity>();
|
||||
layer ??= Layer.Default;
|
||||
|
||||
foreach (var stroke in Strokes)
|
||||
{
|
||||
if (stroke.Count < 2) continue;
|
||||
if (stroke.Count < 2)
|
||||
continue;
|
||||
|
||||
var segments = BuildSegments(stroke);
|
||||
foreach (var seg in segments)
|
||||
{
|
||||
if (seg.Points.Count < 2) continue;
|
||||
if (seg.Points.Count < 2)
|
||||
continue;
|
||||
|
||||
var scaled = new List<Vector>(seg.Points.Count);
|
||||
foreach (var pt in seg.Points)
|
||||
@@ -324,14 +343,23 @@ namespace OpenNest.IO
|
||||
public bool HasCurves;
|
||||
}
|
||||
|
||||
private static void SampleCircularArc(List<Vector> output, Vector p0, Vector pMid, Vector p1, int samples)
|
||||
private static void SampleCircularArc(
|
||||
List<Vector> output,
|
||||
Vector p0,
|
||||
Vector pMid,
|
||||
Vector p1,
|
||||
int samples
|
||||
)
|
||||
{
|
||||
if (output.Count == 0 || output[^1].DistanceTo(p0) > 0.01)
|
||||
output.Add(p0);
|
||||
|
||||
double ax = p0.X, ay = p0.Y;
|
||||
double bx = pMid.X, by = pMid.Y;
|
||||
double cx = p1.X, cy = p1.Y;
|
||||
double ax = p0.X,
|
||||
ay = p0.Y;
|
||||
double bx = pMid.X,
|
||||
by = pMid.Y;
|
||||
double cx = p1.X,
|
||||
cy = p1.Y;
|
||||
|
||||
var d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
|
||||
|
||||
@@ -342,8 +370,18 @@ namespace OpenNest.IO
|
||||
return;
|
||||
}
|
||||
|
||||
var ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
|
||||
var uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
|
||||
var ux =
|
||||
(
|
||||
(ax * ax + ay * ay) * (by - cy)
|
||||
+ (bx * bx + by * by) * (cy - ay)
|
||||
+ (cx * cx + cy * cy) * (ay - by)
|
||||
) / d;
|
||||
var uy =
|
||||
(
|
||||
(ax * ax + ay * ay) * (cx - bx)
|
||||
+ (bx * bx + by * by) * (ax - cx)
|
||||
+ (cx * cx + cy * cy) * (bx - ax)
|
||||
) / d;
|
||||
var radius = System.Math.Sqrt((ax - ux) * (ax - ux) + (ay - uy) * (ay - uy));
|
||||
|
||||
var a0 = System.Math.Atan2(ay - uy, ax - ux);
|
||||
@@ -351,10 +389,12 @@ namespace OpenNest.IO
|
||||
var a1 = System.Math.Atan2(cy - uy, cx - ux);
|
||||
|
||||
var ccwSweep = a1 - a0;
|
||||
while (ccwSweep <= 0) ccwSweep += 2 * System.Math.PI;
|
||||
while (ccwSweep <= 0)
|
||||
ccwSweep += 2 * System.Math.PI;
|
||||
|
||||
var midRel = am - a0;
|
||||
while (midRel < 0) midRel += 2 * System.Math.PI;
|
||||
while (midRel < 0)
|
||||
midRel += 2 * System.Math.PI;
|
||||
|
||||
var sweep = midRel < ccwSweep ? ccwSweep : ccwSweep - 2 * System.Math.PI;
|
||||
|
||||
@@ -362,7 +402,12 @@ namespace OpenNest.IO
|
||||
{
|
||||
var t = (double)i / samples;
|
||||
var angle = a0 + sweep * t;
|
||||
output.Add(new Vector(ux + radius * System.Math.Cos(angle), uy + radius * System.Math.Sin(angle)));
|
||||
output.Add(
|
||||
new Vector(
|
||||
ux + radius * System.Math.Cos(angle),
|
||||
uy + radius * System.Math.Sin(angle)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-26
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using ACadSharp;
|
||||
using ACadSharp.IO;
|
||||
using CSMath;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenNest.IO
|
||||
{
|
||||
@@ -35,14 +35,12 @@ namespace OpenNest.IO
|
||||
if (preserveRepairMarks)
|
||||
{
|
||||
// Keep source marks separate: optimization could merge two ticks or unrelated scribing.
|
||||
entities.AddRange(ConvertEntities(doc, name => !IsRepairMarkLayer(name), optimize: false));
|
||||
entities.AddRange(
|
||||
ConvertEntities(doc, name => !IsRepairMarkLayer(name), optimize: false)
|
||||
);
|
||||
}
|
||||
|
||||
return new DxfImportResult
|
||||
{
|
||||
Entities = entities,
|
||||
Document = doc
|
||||
};
|
||||
return new DxfImportResult { Entities = entities, Document = doc };
|
||||
}
|
||||
|
||||
public static List<Entity> GetGeometry(string path)
|
||||
@@ -167,7 +165,11 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Entity> ConvertEntities(CadDocument doc, Func<string, bool> layerFilter = null, bool optimize = true)
|
||||
private static List<Entity> ConvertEntities(
|
||||
CadDocument doc,
|
||||
Func<string, bool> layerFilter = null,
|
||||
bool optimize = true
|
||||
)
|
||||
{
|
||||
var entities = new List<Entity>();
|
||||
var lines = new List<Line>();
|
||||
@@ -197,8 +199,10 @@ namespace OpenNest.IO
|
||||
case ACadSharp.Entities.Spline spline:
|
||||
foreach (var e in spline.ToOpenNest())
|
||||
{
|
||||
if (e is Line l) lines.Add(l);
|
||||
else if (e is Arc a) arcs.Add(a);
|
||||
if (e is Line l)
|
||||
lines.Add(l);
|
||||
else if (e is Arc a)
|
||||
arcs.Add(a);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -213,8 +217,10 @@ namespace OpenNest.IO
|
||||
case ACadSharp.Entities.Ellipse ellipse:
|
||||
foreach (var e in ellipse.ToOpenNest())
|
||||
{
|
||||
if (e is Line l) lines.Add(l);
|
||||
else if (e is Arc a) arcs.Add(a);
|
||||
if (e is Line l)
|
||||
lines.Add(l);
|
||||
else if (e is Arc a)
|
||||
arcs.Add(a);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -276,14 +282,17 @@ namespace OpenNest.IO
|
||||
{
|
||||
StartPoint = start,
|
||||
EndPoint = end,
|
||||
Layer = layer
|
||||
Layer = layer,
|
||||
};
|
||||
Document.Entities.Add(ln);
|
||||
}
|
||||
|
||||
public void AddPlateOutline(Plate plate)
|
||||
{
|
||||
XYZ pt1, pt2, pt3, pt4;
|
||||
XYZ pt1,
|
||||
pt2,
|
||||
pt3,
|
||||
pt4;
|
||||
|
||||
switch (plate.Quadrant)
|
||||
{
|
||||
@@ -324,7 +333,11 @@ namespace OpenNest.IO
|
||||
AddLine(pt3, pt4, PlateLayer);
|
||||
AddLine(pt4, pt1, PlateLayer);
|
||||
|
||||
var m1 = new XYZ(pt1.X + plate.EdgeSpacing.Left, pt1.Y + plate.EdgeSpacing.Bottom, 0);
|
||||
var m1 = new XYZ(
|
||||
pt1.X + plate.EdgeSpacing.Left,
|
||||
pt1.Y + plate.EdgeSpacing.Bottom,
|
||||
0
|
||||
);
|
||||
var m2 = new XYZ(m1.X, pt2.Y - plate.EdgeSpacing.Top, 0);
|
||||
var m3 = new XYZ(pt3.X - plate.EdgeSpacing.Right, m2.Y, 0);
|
||||
var m4 = new XYZ(m3.X, m1.Y, 0);
|
||||
@@ -399,13 +412,9 @@ namespace OpenNest.IO
|
||||
center = new XYZ(center.X + CurPos.X, center.Y + CurPos.Y, 0);
|
||||
}
|
||||
|
||||
var startAngle = System.Math.Atan2(
|
||||
CurPos.Y - center.Y,
|
||||
CurPos.X - center.X);
|
||||
var startAngle = System.Math.Atan2(CurPos.Y - center.Y, CurPos.X - center.X);
|
||||
|
||||
var endAngle = System.Math.Atan2(
|
||||
endpt.Y - center.Y,
|
||||
endpt.X - center.X);
|
||||
var endAngle = System.Math.Atan2(endpt.Y - center.Y, endpt.X - center.X);
|
||||
|
||||
if (arc.Rotation == RotationType.CW)
|
||||
Generic.Swap(ref startAngle, ref endAngle);
|
||||
@@ -420,7 +429,7 @@ namespace OpenNest.IO
|
||||
{
|
||||
Center = center,
|
||||
Radius = radius,
|
||||
Layer = CutLayer
|
||||
Layer = CutLayer,
|
||||
};
|
||||
Document.Entities.Add(circle);
|
||||
}
|
||||
@@ -432,7 +441,7 @@ namespace OpenNest.IO
|
||||
Radius = radius,
|
||||
StartAngle = startAngle,
|
||||
EndAngle = endAngle,
|
||||
Layer = CutLayer
|
||||
Layer = CutLayer,
|
||||
};
|
||||
Document.Entities.Add(acadArc);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using ACadSharp;
|
||||
using OpenNest.Geometry;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenNest.IO
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenNest.Geometry;
|
||||
using static OpenNest.IO.NestFormat;
|
||||
|
||||
namespace OpenNest.IO
|
||||
@@ -13,7 +13,7 @@ namespace OpenNest.IO
|
||||
return new EntitySetDto
|
||||
{
|
||||
Entities = entities.Select(ToEntityDto).ToList(),
|
||||
Suppressed = suppressed.Select(id => id.ToString()).ToList()
|
||||
Suppressed = suppressed.Select(id => id.ToString()).ToList(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenNest.IO
|
||||
X1 = line.StartPoint.X,
|
||||
Y1 = line.StartPoint.Y,
|
||||
X2 = line.EndPoint.X,
|
||||
Y2 = line.EndPoint.Y
|
||||
Y2 = line.EndPoint.Y,
|
||||
};
|
||||
|
||||
case EntityType.Arc:
|
||||
@@ -55,7 +55,7 @@ namespace OpenNest.IO
|
||||
R = arc.Radius,
|
||||
StartAngle = arc.StartAngle,
|
||||
EndAngle = arc.EndAngle,
|
||||
Reversed = arc.IsReversed
|
||||
Reversed = arc.IsReversed,
|
||||
};
|
||||
|
||||
case EntityType.Circle:
|
||||
@@ -69,11 +69,13 @@ namespace OpenNest.IO
|
||||
CX = circle.Center.X,
|
||||
CY = circle.Center.Y,
|
||||
R = circle.Radius,
|
||||
Rotation = circle.Rotation == RotationType.CW ? "CW" : "CCW"
|
||||
Rotation = circle.Rotation == RotationType.CW ? "CW" : "CCW",
|
||||
};
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Entity type {entity.Type} is not supported for serialization.");
|
||||
throw new NotSupportedException(
|
||||
$"Entity type {entity.Type} is not supported for serialization."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +86,7 @@ namespace OpenNest.IO
|
||||
switch (dto.Type)
|
||||
{
|
||||
case "line":
|
||||
entity = new Line(
|
||||
new Vector(dto.X1, dto.Y1),
|
||||
new Vector(dto.X2, dto.Y2));
|
||||
entity = new Line(new Vector(dto.X1, dto.Y1), new Vector(dto.X2, dto.Y2));
|
||||
break;
|
||||
|
||||
case "arc":
|
||||
@@ -95,7 +95,8 @@ namespace OpenNest.IO
|
||||
dto.R,
|
||||
dto.StartAngle,
|
||||
dto.EndAngle,
|
||||
dto.Reversed);
|
||||
dto.Reversed
|
||||
);
|
||||
break;
|
||||
|
||||
case "circle":
|
||||
@@ -105,7 +106,9 @@ namespace OpenNest.IO
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException($"Entity type '{dto.Type}' is not supported for deserialization.");
|
||||
throw new NotSupportedException(
|
||||
$"Entity type '{dto.Type}' is not supported for deserialization."
|
||||
);
|
||||
}
|
||||
|
||||
entity.Id = Guid.Parse(dto.Id);
|
||||
|
||||
+73
-44
@@ -1,10 +1,10 @@
|
||||
using ACadSharp.Entities;
|
||||
using CSMath;
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using ACadSharp.Entities;
|
||||
using CSMath;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.IO
|
||||
{
|
||||
@@ -23,11 +23,14 @@ namespace OpenNest.IO
|
||||
public static Geometry.Arc ToOpenNest(this ACadSharp.Entities.Arc arc)
|
||||
{
|
||||
var result = new Geometry.Arc(
|
||||
arc.Center.X, arc.Center.Y, arc.Radius,
|
||||
arc.Center.X,
|
||||
arc.Center.Y,
|
||||
arc.Radius,
|
||||
arc.StartAngle,
|
||||
arc.EndAngle)
|
||||
arc.EndAngle
|
||||
)
|
||||
{
|
||||
Layer = arc.Layer.ToOpenNest()
|
||||
Layer = arc.Layer.ToOpenNest(),
|
||||
};
|
||||
result.ApplyDxfProperties(arc);
|
||||
return result;
|
||||
@@ -35,11 +38,9 @@ namespace OpenNest.IO
|
||||
|
||||
public static Geometry.Circle ToOpenNest(this ACadSharp.Entities.Circle circle)
|
||||
{
|
||||
var result = new Geometry.Circle(
|
||||
circle.Center.X, circle.Center.Y,
|
||||
circle.Radius)
|
||||
var result = new Geometry.Circle(circle.Center.X, circle.Center.Y, circle.Radius)
|
||||
{
|
||||
Layer = circle.Layer.ToOpenNest()
|
||||
Layer = circle.Layer.ToOpenNest(),
|
||||
};
|
||||
result.ApplyDxfProperties(circle);
|
||||
return result;
|
||||
@@ -48,10 +49,13 @@ namespace OpenNest.IO
|
||||
public static Geometry.Line ToOpenNest(this ACadSharp.Entities.Line line)
|
||||
{
|
||||
var result = new Geometry.Line(
|
||||
line.StartPoint.X, line.StartPoint.Y,
|
||||
line.EndPoint.X, line.EndPoint.Y)
|
||||
line.StartPoint.X,
|
||||
line.StartPoint.Y,
|
||||
line.EndPoint.X,
|
||||
line.EndPoint.Y
|
||||
)
|
||||
{
|
||||
Layer = line.Layer.ToOpenNest()
|
||||
Layer = line.Layer.ToOpenNest(),
|
||||
};
|
||||
result.ApplyDxfProperties(line);
|
||||
return result;
|
||||
@@ -115,25 +119,30 @@ namespace OpenNest.IO
|
||||
{
|
||||
var nextPoint = polyline.Vertices[i].Location.ToOpenNest();
|
||||
|
||||
lines.Add(new Geometry.Line(lastPoint, nextPoint)
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName
|
||||
});
|
||||
lines.Add(
|
||||
new Geometry.Line(lastPoint, nextPoint)
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName,
|
||||
}
|
||||
);
|
||||
|
||||
lastPoint = nextPoint;
|
||||
}
|
||||
|
||||
var isClosed = (polyline.Flags & PolylineFlags.ClosedPolylineOrClosedPolygonMeshInM) != 0;
|
||||
var isClosed =
|
||||
(polyline.Flags & PolylineFlags.ClosedPolylineOrClosedPolygonMeshInM) != 0;
|
||||
|
||||
if (isClosed)
|
||||
lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].Location.ToOpenNest())
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName
|
||||
});
|
||||
lines.Add(
|
||||
new Geometry.Line(lastPoint, polyline.Vertices[0].Location.ToOpenNest())
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName,
|
||||
}
|
||||
);
|
||||
|
||||
return lines;
|
||||
}
|
||||
@@ -154,12 +163,14 @@ namespace OpenNest.IO
|
||||
{
|
||||
var nextPoint = polyline.Vertices[i].ToOpenNest();
|
||||
|
||||
lines.Add(new Geometry.Line(lastPoint, nextPoint)
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName
|
||||
});
|
||||
lines.Add(
|
||||
new Geometry.Line(lastPoint, nextPoint)
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName,
|
||||
}
|
||||
);
|
||||
|
||||
lastPoint = nextPoint;
|
||||
}
|
||||
@@ -167,17 +178,22 @@ namespace OpenNest.IO
|
||||
var isClosed = (polyline.Flags & LwPolylineFlags.Closed) != 0;
|
||||
|
||||
if (isClosed)
|
||||
lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].ToOpenNest())
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName
|
||||
});
|
||||
lines.Add(
|
||||
new Geometry.Line(lastPoint, polyline.Vertices[0].ToOpenNest())
|
||||
{
|
||||
Layer = layer,
|
||||
Color = color,
|
||||
LineTypeName = lineTypeName,
|
||||
}
|
||||
);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static List<Geometry.Entity> ToOpenNest(this ACadSharp.Entities.Ellipse ellipse, double tolerance = 0.001)
|
||||
public static List<Geometry.Entity> ToOpenNest(
|
||||
this ACadSharp.Entities.Ellipse ellipse,
|
||||
double tolerance = 0.001
|
||||
)
|
||||
{
|
||||
var center = new Vector(ellipse.Center.X, ellipse.Center.Y);
|
||||
var majorAxis = new Vector(ellipse.MajorAxisEndPoint.X, ellipse.MajorAxisEndPoint.Y);
|
||||
@@ -201,8 +217,15 @@ namespace OpenNest.IO
|
||||
var color = ellipse.ResolveColor();
|
||||
var lineTypeName = ellipse.ResolveLineTypeName();
|
||||
|
||||
var entities = EllipseConverter.Convert(center, semiMajor, semiMinor, rotation,
|
||||
startParam, endParam, tolerance);
|
||||
var entities = EllipseConverter.Convert(
|
||||
center,
|
||||
semiMajor,
|
||||
semiMinor,
|
||||
rotation,
|
||||
startParam,
|
||||
endParam,
|
||||
tolerance
|
||||
);
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
@@ -220,7 +243,7 @@ namespace OpenNest.IO
|
||||
{
|
||||
Color = Color.FromArgb(layer.Color.R, layer.Color.G, layer.Color.B),
|
||||
IsVisible = layer.IsOn,
|
||||
LineTypeName = layer.LineType?.Name
|
||||
LineTypeName = layer.LineType?.Name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -238,13 +261,19 @@ namespace OpenNest.IO
|
||||
{
|
||||
var lt = entity.LineType;
|
||||
|
||||
if (lt == null || string.Equals(lt.Name, "ByLayer", System.StringComparison.OrdinalIgnoreCase))
|
||||
if (
|
||||
lt == null
|
||||
|| string.Equals(lt.Name, "ByLayer", System.StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
return entity.Layer.LineType?.Name ?? "Continuous";
|
||||
|
||||
return lt.Name;
|
||||
}
|
||||
|
||||
public static void ApplyDxfProperties(this Geometry.Entity target, ACadSharp.Entities.Entity source)
|
||||
public static void ApplyDxfProperties(
|
||||
this Geometry.Entity target,
|
||||
ACadSharp.Entities.Entity source
|
||||
)
|
||||
{
|
||||
target.Color = source.ResolveColor();
|
||||
target.LineTypeName = source.ResolveLineTypeName();
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace OpenNest.IO
|
||||
public static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true
|
||||
WriteIndented = true,
|
||||
};
|
||||
|
||||
public record NestDto
|
||||
|
||||
+102
-57
@@ -1,7 +1,3 @@
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@@ -9,6 +5,10 @@ using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using OpenNest.Geometry;
|
||||
using static OpenNest.IO.NestFormat;
|
||||
|
||||
namespace OpenNest.IO
|
||||
@@ -49,7 +49,8 @@ namespace OpenNest.IO
|
||||
|
||||
private string ReadEntry(string name)
|
||||
{
|
||||
var entry = zipArchive.GetEntry(name)
|
||||
var entry =
|
||||
zipArchive.GetEntry(name)
|
||||
?? throw new InvalidDataException($"Nest file is missing required entry '{name}'.");
|
||||
using var entryStream = entry.Open();
|
||||
using var reader = new StreamReader(entryStream);
|
||||
@@ -62,7 +63,8 @@ namespace OpenNest.IO
|
||||
for (var i = 1; i <= count; i++)
|
||||
{
|
||||
var entry = zipArchive.GetEntry($"programs/program-{i}");
|
||||
if (entry == null) continue;
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
using var entryStream = entry.Open();
|
||||
var memStream = new MemoryStream();
|
||||
@@ -120,7 +122,10 @@ namespace OpenNest.IO
|
||||
// Wire up SubProgramCall.Program references
|
||||
foreach (var code in parent.Codes)
|
||||
{
|
||||
if (code is SubProgramCall call && parent.SubPrograms.TryGetValue(call.Id, out var sub))
|
||||
if (
|
||||
code is SubProgramCall call
|
||||
&& parent.SubPrograms.TryGetValue(call.Id, out var sub)
|
||||
)
|
||||
call.Program = sub;
|
||||
}
|
||||
}
|
||||
@@ -133,13 +138,16 @@ namespace OpenNest.IO
|
||||
return reader.Read();
|
||||
}
|
||||
|
||||
private Dictionary<int, (List<Entity> entities, HashSet<Guid> suppressed)> ReadEntitySets(int count)
|
||||
private Dictionary<int, (List<Entity> entities, HashSet<Guid> suppressed)> ReadEntitySets(
|
||||
int count
|
||||
)
|
||||
{
|
||||
var result = new Dictionary<int, (List<Entity>, HashSet<Guid>)>();
|
||||
for (var i = 1; i <= count; i++)
|
||||
{
|
||||
var entry = zipArchive.GetEntry($"entities/entities-{i}");
|
||||
if (entry == null) continue;
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
using var entryStream = entry.Open();
|
||||
using var reader = new StreamReader(entryStream);
|
||||
@@ -150,8 +158,11 @@ namespace OpenNest.IO
|
||||
return result;
|
||||
}
|
||||
|
||||
private Dictionary<int, Drawing> BuildDrawings(NestDto dto, Dictionary<int, Program> programs,
|
||||
Dictionary<int, (List<Entity> entities, HashSet<Guid> suppressed)> entitySets)
|
||||
private Dictionary<int, Drawing> BuildDrawings(
|
||||
NestDto dto,
|
||||
Dictionary<int, Program> programs,
|
||||
Dictionary<int, (List<Entity> entities, HashSet<Guid> suppressed)> entitySets
|
||||
)
|
||||
{
|
||||
var map = new Dictionary<int, Drawing>();
|
||||
foreach (var d in dto.Drawings)
|
||||
@@ -165,7 +176,11 @@ namespace OpenNest.IO
|
||||
drawing.Constraints.StartAngle = d.Constraints.StartAngle;
|
||||
drawing.Constraints.EndAngle = d.Constraints.EndAngle;
|
||||
drawing.Constraints.Allow180Equivalent = d.Constraints.Allow180Equivalent;
|
||||
drawing.Material = new Material(d.Material.Name, d.Material.Grade, d.Material.Density);
|
||||
drawing.Material = new Material(
|
||||
d.Material.Name,
|
||||
d.Material.Grade,
|
||||
d.Material.Density
|
||||
);
|
||||
drawing.Source.Path = d.Source.Path;
|
||||
drawing.Source.Offset = new Vector(d.Source.Offset.X, d.Source.Offset.Y);
|
||||
|
||||
@@ -173,16 +188,23 @@ namespace OpenNest.IO
|
||||
{
|
||||
foreach (var b in d.Bends)
|
||||
{
|
||||
drawing.Bends.Add(new Bend
|
||||
{
|
||||
StartPoint = new Vector(b.StartX, b.StartY),
|
||||
EndPoint = new Vector(b.EndX, b.EndY),
|
||||
Direction = Enum.TryParse<BendDirection>(b.Direction, true, out var dir)
|
||||
? dir : BendDirection.Unknown,
|
||||
Angle = b.Angle,
|
||||
Radius = b.Radius,
|
||||
NoteText = b.NoteText
|
||||
});
|
||||
drawing.Bends.Add(
|
||||
new Bend
|
||||
{
|
||||
StartPoint = new Vector(b.StartX, b.StartY),
|
||||
EndPoint = new Vector(b.EndX, b.EndY),
|
||||
Direction = Enum.TryParse<BendDirection>(
|
||||
b.Direction,
|
||||
true,
|
||||
out var dir
|
||||
)
|
||||
? dir
|
||||
: BendDirection.Unknown,
|
||||
Angle = b.Angle,
|
||||
Radius = b.Radius,
|
||||
NoteText = b.NoteText,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,14 +227,16 @@ namespace OpenNest.IO
|
||||
foreach (var kvp in drawingMap)
|
||||
{
|
||||
var entry = zipArchive.GetEntry($"bestfits/bestfit-{kvp.Key}");
|
||||
if (entry == null) continue;
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
using var entryStream = entry.Open();
|
||||
using var reader = new StreamReader(entryStream);
|
||||
var json = reader.ReadToEnd();
|
||||
|
||||
var sets = JsonSerializer.Deserialize<List<BestFitSetDto>>(json, JsonOptions);
|
||||
if (sets == null) continue;
|
||||
if (sets == null)
|
||||
continue;
|
||||
|
||||
PopulateBestFitSets(kvp.Value, sets);
|
||||
}
|
||||
@@ -222,29 +246,37 @@ namespace OpenNest.IO
|
||||
{
|
||||
foreach (var set in sets)
|
||||
{
|
||||
var results = set.Results.Select(r => new BestFitResult
|
||||
{
|
||||
Candidate = new PairCandidate
|
||||
var results = set
|
||||
.Results.Select(r => new BestFitResult
|
||||
{
|
||||
Drawing = drawing,
|
||||
Part1Rotation = r.Part1Rotation,
|
||||
Part2Rotation = r.Part2Rotation,
|
||||
Part2Offset = new Vector(r.Part2OffsetX, r.Part2OffsetY),
|
||||
StrategyIndex = r.StrategyType,
|
||||
TestNumber = r.TestNumber,
|
||||
Spacing = r.CandidateSpacing
|
||||
},
|
||||
RotatedArea = r.RotatedArea,
|
||||
BoundingWidth = r.BoundingWidth,
|
||||
BoundingHeight = r.BoundingHeight,
|
||||
OptimalRotation = r.OptimalRotation,
|
||||
Keep = r.Keep,
|
||||
Reason = r.Reason,
|
||||
TrueArea = r.TrueArea,
|
||||
HullAngles = r.HullAngles
|
||||
}).ToList();
|
||||
Candidate = new PairCandidate
|
||||
{
|
||||
Drawing = drawing,
|
||||
Part1Rotation = r.Part1Rotation,
|
||||
Part2Rotation = r.Part2Rotation,
|
||||
Part2Offset = new Vector(r.Part2OffsetX, r.Part2OffsetY),
|
||||
StrategyIndex = r.StrategyType,
|
||||
TestNumber = r.TestNumber,
|
||||
Spacing = r.CandidateSpacing,
|
||||
},
|
||||
RotatedArea = r.RotatedArea,
|
||||
BoundingWidth = r.BoundingWidth,
|
||||
BoundingHeight = r.BoundingHeight,
|
||||
OptimalRotation = r.OptimalRotation,
|
||||
Keep = r.Keep,
|
||||
Reason = r.Reason,
|
||||
TrueArea = r.TrueArea,
|
||||
HullAngles = r.HullAngles,
|
||||
})
|
||||
.ToList();
|
||||
|
||||
BestFitCache.Populate(drawing, set.PlateWidth, set.PlateHeight, set.Spacing, results);
|
||||
BestFitCache.Populate(
|
||||
drawing,
|
||||
set.PlateWidth,
|
||||
set.PlateHeight,
|
||||
set.Spacing,
|
||||
results
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,18 +305,25 @@ namespace OpenNest.IO
|
||||
nest.PlateDefaults.Size = new OpenNest.Geometry.Size(pd.Size.Width, pd.Size.Length);
|
||||
nest.PlateDefaults.Quadrant = pd.Quadrant;
|
||||
nest.PlateDefaults.PartSpacing = pd.PartSpacing;
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(pd.EdgeSpacing.Left, pd.EdgeSpacing.Bottom, pd.EdgeSpacing.Right, pd.EdgeSpacing.Top);
|
||||
nest.PlateDefaults.EdgeSpacing = new Spacing(
|
||||
pd.EdgeSpacing.Left,
|
||||
pd.EdgeSpacing.Bottom,
|
||||
pd.EdgeSpacing.Right,
|
||||
pd.EdgeSpacing.Top
|
||||
);
|
||||
|
||||
// Plate optimizer settings
|
||||
nest.SalvageRate = dto.SalvageRate;
|
||||
if (dto.PlateOptions != null)
|
||||
{
|
||||
nest.PlateOptions = dto.PlateOptions.Select(o => new PlateOption
|
||||
{
|
||||
Width = o.Width,
|
||||
Length = o.Length,
|
||||
Cost = o.Cost,
|
||||
}).ToList();
|
||||
nest.PlateOptions = dto
|
||||
.PlateOptions.Select(o => new PlateOption
|
||||
{
|
||||
Width = o.Width,
|
||||
Length = o.Length,
|
||||
Cost = o.Cost,
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Drawings
|
||||
@@ -299,7 +338,12 @@ namespace OpenNest.IO
|
||||
plate.Quadrant = p.Quadrant;
|
||||
plate.Quantity = p.Quantity;
|
||||
plate.PartSpacing = p.PartSpacing;
|
||||
plate.EdgeSpacing = new Spacing(p.EdgeSpacing.Left, p.EdgeSpacing.Bottom, p.EdgeSpacing.Right, p.EdgeSpacing.Top);
|
||||
plate.EdgeSpacing = new Spacing(
|
||||
p.EdgeSpacing.Left,
|
||||
p.EdgeSpacing.Bottom,
|
||||
p.EdgeSpacing.Right,
|
||||
p.EdgeSpacing.Top
|
||||
);
|
||||
plate.GrainAngle = p.GrainAngle;
|
||||
|
||||
foreach (var partDto in p.Parts)
|
||||
@@ -318,13 +362,14 @@ namespace OpenNest.IO
|
||||
{
|
||||
foreach (var cutoffDto in p.CutOffs)
|
||||
{
|
||||
var axis = cutoffDto.Axis?.ToLowerInvariant() == "horizontal"
|
||||
? CutOffAxis.Horizontal
|
||||
: CutOffAxis.Vertical;
|
||||
var axis =
|
||||
cutoffDto.Axis?.ToLowerInvariant() == "horizontal"
|
||||
? CutOffAxis.Horizontal
|
||||
: CutOffAxis.Vertical;
|
||||
var cutoff = new CutOff(new Vector(cutoffDto.X, cutoffDto.Y), axis)
|
||||
{
|
||||
StartLimit = cutoffDto.StartLimit,
|
||||
EndLimit = cutoffDto.EndLimit
|
||||
EndLimit = cutoffDto.EndLimit,
|
||||
};
|
||||
plate.CutOffs.Add(cutoff);
|
||||
}
|
||||
|
||||
+215
-161
@@ -1,6 +1,3 @@
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -8,6 +5,9 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using static OpenNest.IO.NestFormat;
|
||||
|
||||
namespace OpenNest.IO
|
||||
@@ -85,17 +85,20 @@ namespace OpenNest.IO
|
||||
{
|
||||
Name = nest.Material.Name ?? "",
|
||||
Grade = nest.Material.Grade ?? "",
|
||||
Density = nest.Material.Density
|
||||
Density = nest.Material.Density,
|
||||
},
|
||||
PlateDefaults = BuildPlateDefaultsDto(),
|
||||
Drawings = BuildDrawingDtos(),
|
||||
Plates = BuildPlateDtos(),
|
||||
PlateOptions = nest.PlateOptions?.Select(o => new PlateOptionDto
|
||||
{
|
||||
Width = o.Width,
|
||||
Length = o.Length,
|
||||
Cost = o.Cost,
|
||||
}).ToList() ?? new(),
|
||||
PlateOptions =
|
||||
nest.PlateOptions?.Select(o => new PlateOptionDto
|
||||
{
|
||||
Width = o.Width,
|
||||
Length = o.Length,
|
||||
Cost = o.Cost,
|
||||
})
|
||||
.ToList()
|
||||
?? new(),
|
||||
SalvageRate = nest.SalvageRate,
|
||||
};
|
||||
}
|
||||
@@ -113,15 +116,15 @@ namespace OpenNest.IO
|
||||
{
|
||||
Name = nest.Material.Name ?? "",
|
||||
Grade = nest.Material.Grade ?? "",
|
||||
Density = nest.Material.Density
|
||||
Density = nest.Material.Density,
|
||||
},
|
||||
EdgeSpacing = new SpacingDto
|
||||
{
|
||||
Left = pd.EdgeSpacing.Left,
|
||||
Top = pd.EdgeSpacing.Top,
|
||||
Right = pd.EdgeSpacing.Right,
|
||||
Bottom = pd.EdgeSpacing.Bottom
|
||||
}
|
||||
Bottom = pd.EdgeSpacing.Bottom,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -131,44 +134,55 @@ namespace OpenNest.IO
|
||||
foreach (var kvp in drawingDict.OrderBy(k => k.Key))
|
||||
{
|
||||
var d = kvp.Value;
|
||||
list.Add(new DrawingDto
|
||||
{
|
||||
Id = kvp.Key,
|
||||
Name = d.Name ?? "",
|
||||
Customer = d.Customer ?? "",
|
||||
Color = new ColorDto { A = d.Color.A, R = d.Color.R, G = d.Color.G, B = d.Color.B },
|
||||
Quantity = new QuantityDto { Required = d.Quantity.Required },
|
||||
Priority = d.Priority,
|
||||
Constraints = new ConstraintsDto
|
||||
list.Add(
|
||||
new DrawingDto
|
||||
{
|
||||
StepAngle = d.Constraints.StepAngle,
|
||||
StartAngle = d.Constraints.StartAngle,
|
||||
EndAngle = d.Constraints.EndAngle,
|
||||
Allow180Equivalent = d.Constraints.Allow180Equivalent
|
||||
},
|
||||
Material = new MaterialDto
|
||||
{
|
||||
Name = d.Material.Name ?? "",
|
||||
Grade = d.Material.Grade ?? "",
|
||||
Density = d.Material.Density
|
||||
},
|
||||
Source = new SourceDto
|
||||
{
|
||||
Path = d.Source.Path ?? "",
|
||||
Offset = new OffsetDto { X = d.Source.Offset.X, Y = d.Source.Offset.Y }
|
||||
},
|
||||
Bends = d.Bends?.Select(b => new BendDto
|
||||
{
|
||||
StartX = b.StartPoint.X,
|
||||
StartY = b.StartPoint.Y,
|
||||
EndX = b.EndPoint.X,
|
||||
EndY = b.EndPoint.Y,
|
||||
Direction = b.Direction.ToString(),
|
||||
Angle = b.Angle,
|
||||
Radius = b.Radius,
|
||||
NoteText = b.NoteText ?? ""
|
||||
}).ToList() ?? new List<BendDto>()
|
||||
});
|
||||
Id = kvp.Key,
|
||||
Name = d.Name ?? "",
|
||||
Customer = d.Customer ?? "",
|
||||
Color = new ColorDto
|
||||
{
|
||||
A = d.Color.A,
|
||||
R = d.Color.R,
|
||||
G = d.Color.G,
|
||||
B = d.Color.B,
|
||||
},
|
||||
Quantity = new QuantityDto { Required = d.Quantity.Required },
|
||||
Priority = d.Priority,
|
||||
Constraints = new ConstraintsDto
|
||||
{
|
||||
StepAngle = d.Constraints.StepAngle,
|
||||
StartAngle = d.Constraints.StartAngle,
|
||||
EndAngle = d.Constraints.EndAngle,
|
||||
Allow180Equivalent = d.Constraints.Allow180Equivalent,
|
||||
},
|
||||
Material = new MaterialDto
|
||||
{
|
||||
Name = d.Material.Name ?? "",
|
||||
Grade = d.Material.Grade ?? "",
|
||||
Density = d.Material.Density,
|
||||
},
|
||||
Source = new SourceDto
|
||||
{
|
||||
Path = d.Source.Path ?? "",
|
||||
Offset = new OffsetDto { X = d.Source.Offset.X, Y = d.Source.Offset.Y },
|
||||
},
|
||||
Bends =
|
||||
d.Bends?.Select(b => new BendDto
|
||||
{
|
||||
StartX = b.StartPoint.X,
|
||||
StartY = b.StartPoint.Y,
|
||||
EndX = b.EndPoint.X,
|
||||
EndY = b.EndPoint.Y,
|
||||
Direction = b.Direction.ToString(),
|
||||
Angle = b.Angle,
|
||||
Radius = b.Radius,
|
||||
NoteText = b.NoteText ?? "",
|
||||
})
|
||||
.ToList()
|
||||
?? new List<BendDto>(),
|
||||
}
|
||||
);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -181,56 +195,67 @@ namespace OpenNest.IO
|
||||
{
|
||||
var plate = nest.Plates[i];
|
||||
|
||||
if (plate.Parts.Count(p => !p.BaseDrawing.IsCutOff) == 0 && plate.CutOffs.Count == 0)
|
||||
if (
|
||||
plate.Parts.Count(p => !p.BaseDrawing.IsCutOff) == 0
|
||||
&& plate.CutOffs.Count == 0
|
||||
)
|
||||
continue;
|
||||
|
||||
id++;
|
||||
var parts = new List<PartDto>();
|
||||
foreach (var part in plate.Parts.Where(p => !p.BaseDrawing.IsCutOff))
|
||||
{
|
||||
var match = drawingDict.Where(dwg => dwg.Value == part.BaseDrawing).FirstOrDefault();
|
||||
parts.Add(new PartDto
|
||||
{
|
||||
DrawingId = match.Key,
|
||||
X = part.Location.X,
|
||||
Y = part.Location.Y,
|
||||
Rotation = part.Rotation,
|
||||
HasManualLeadIns = part.HasManualLeadIns,
|
||||
LeadInsLocked = part.LeadInsLocked
|
||||
});
|
||||
var match = drawingDict
|
||||
.Where(dwg => dwg.Value == part.BaseDrawing)
|
||||
.FirstOrDefault();
|
||||
parts.Add(
|
||||
new PartDto
|
||||
{
|
||||
DrawingId = match.Key,
|
||||
X = part.Location.X,
|
||||
Y = part.Location.Y,
|
||||
Rotation = part.Rotation,
|
||||
HasManualLeadIns = part.HasManualLeadIns,
|
||||
LeadInsLocked = part.LeadInsLocked,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var cutoffs = new List<CutOffDto>();
|
||||
foreach (var cutoff in plate.CutOffs)
|
||||
{
|
||||
cutoffs.Add(new CutOffDto
|
||||
{
|
||||
X = cutoff.Position.X,
|
||||
Y = cutoff.Position.Y,
|
||||
Axis = cutoff.Axis == CutOffAxis.Vertical ? "vertical" : "horizontal",
|
||||
StartLimit = cutoff.StartLimit,
|
||||
EndLimit = cutoff.EndLimit
|
||||
});
|
||||
cutoffs.Add(
|
||||
new CutOffDto
|
||||
{
|
||||
X = cutoff.Position.X,
|
||||
Y = cutoff.Position.Y,
|
||||
Axis = cutoff.Axis == CutOffAxis.Vertical ? "vertical" : "horizontal",
|
||||
StartLimit = cutoff.StartLimit,
|
||||
EndLimit = cutoff.EndLimit,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
list.Add(new PlateDto
|
||||
{
|
||||
Id = id,
|
||||
Size = new SizeDto { Width = plate.Size.Width, Length = plate.Size.Length },
|
||||
Quadrant = plate.Quadrant,
|
||||
Quantity = plate.Quantity,
|
||||
PartSpacing = plate.PartSpacing,
|
||||
EdgeSpacing = new SpacingDto
|
||||
list.Add(
|
||||
new PlateDto
|
||||
{
|
||||
Left = plate.EdgeSpacing.Left,
|
||||
Top = plate.EdgeSpacing.Top,
|
||||
Right = plate.EdgeSpacing.Right,
|
||||
Bottom = plate.EdgeSpacing.Bottom
|
||||
},
|
||||
Parts = parts,
|
||||
CutOffs = cutoffs,
|
||||
GrainAngle = plate.GrainAngle
|
||||
});
|
||||
Id = id,
|
||||
Size = new SizeDto { Width = plate.Size.Width, Length = plate.Size.Length },
|
||||
Quadrant = plate.Quadrant,
|
||||
Quantity = plate.Quantity,
|
||||
PartSpacing = plate.PartSpacing,
|
||||
EdgeSpacing = new SpacingDto
|
||||
{
|
||||
Left = plate.EdgeSpacing.Left,
|
||||
Top = plate.EdgeSpacing.Top,
|
||||
Right = plate.EdgeSpacing.Right,
|
||||
Bottom = plate.EdgeSpacing.Bottom,
|
||||
},
|
||||
Parts = parts,
|
||||
CutOffs = cutoffs,
|
||||
GrainAngle = plate.GrainAngle,
|
||||
}
|
||||
);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -247,11 +272,13 @@ namespace OpenNest.IO
|
||||
|
||||
foreach (var kvp in allBestFits)
|
||||
{
|
||||
if (!plateSizes.Contains((kvp.Key.PlateWidth, kvp.Key.PlateHeight, kvp.Key.Spacing)))
|
||||
if (
|
||||
!plateSizes.Contains((kvp.Key.PlateWidth, kvp.Key.PlateHeight, kvp.Key.Spacing))
|
||||
)
|
||||
continue;
|
||||
|
||||
var results = kvp.Value
|
||||
.Where(r => r.Keep)
|
||||
var results = kvp
|
||||
.Value.Where(r => r.Keep)
|
||||
.Select(r => new BestFitResultDto
|
||||
{
|
||||
Part1Rotation = r.Candidate.Part1Rotation,
|
||||
@@ -268,16 +295,19 @@ namespace OpenNest.IO
|
||||
Keep = r.Keep,
|
||||
Reason = r.Reason ?? "",
|
||||
TrueArea = r.TrueArea,
|
||||
HullAngles = r.HullAngles ?? new List<double>()
|
||||
}).ToList();
|
||||
HullAngles = r.HullAngles ?? new List<double>(),
|
||||
})
|
||||
.ToList();
|
||||
|
||||
sets.Add(new BestFitSetDto
|
||||
{
|
||||
PlateWidth = kvp.Key.PlateWidth,
|
||||
PlateHeight = kvp.Key.PlateHeight,
|
||||
Spacing = kvp.Key.Spacing,
|
||||
Results = results
|
||||
});
|
||||
sets.Add(
|
||||
new BestFitSetDto
|
||||
{
|
||||
PlateWidth = kvp.Key.PlateWidth,
|
||||
PlateHeight = kvp.Key.PlateHeight,
|
||||
Spacing = kvp.Key.Spacing,
|
||||
Results = results,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return sets;
|
||||
@@ -319,7 +349,11 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteSubPrograms(ZipArchive zipArchive, int drawingId, Dictionary<int, Program> subPrograms)
|
||||
private void WriteSubPrograms(
|
||||
ZipArchive zipArchive,
|
||||
int drawingId,
|
||||
Dictionary<int, Program> subPrograms
|
||||
)
|
||||
{
|
||||
var entry = zipArchive.CreateEntry($"programs/program-{drawingId}-subs");
|
||||
using var entryStream = entry.Open();
|
||||
@@ -345,7 +379,10 @@ namespace OpenNest.IO
|
||||
if (drawing.SourceEntities == null || drawing.SourceEntities.Count == 0)
|
||||
continue;
|
||||
|
||||
var dto = EntitySerializer.ToDto(drawing.SourceEntities, drawing.SuppressedEntityIds);
|
||||
var dto = EntitySerializer.ToDto(
|
||||
drawing.SourceEntities,
|
||||
drawing.SuppressedEntityIds
|
||||
);
|
||||
var json = JsonSerializer.Serialize(dto, JsonOptions);
|
||||
|
||||
var entry = zipArchive.CreateEntry($"entities/entities-{kvp.Key}");
|
||||
@@ -365,8 +402,10 @@ namespace OpenNest.IO
|
||||
foreach (var v in program.Variables.Values)
|
||||
{
|
||||
var line = $"{v.Name} = {v.Expression}";
|
||||
if (v.Inline) line += " inline";
|
||||
if (v.Global) line += " global";
|
||||
if (v.Inline)
|
||||
line += " inline";
|
||||
if (v.Global)
|
||||
line += " global";
|
||||
writer.WriteLine(line);
|
||||
}
|
||||
|
||||
@@ -381,7 +420,11 @@ namespace OpenNest.IO
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
private string FormatCoord(double value, string axis, Dictionary<string, string> variableRefs)
|
||||
private string FormatCoord(
|
||||
double value,
|
||||
string axis,
|
||||
Dictionary<string, string> variableRefs
|
||||
)
|
||||
{
|
||||
if (variableRefs != null && variableRefs.TryGetValue(axis, out var varName))
|
||||
return $"${varName}";
|
||||
@@ -393,89 +436,100 @@ namespace OpenNest.IO
|
||||
switch (code.Type)
|
||||
{
|
||||
case CodeType.ArcMove:
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var arcMove = (ArcMove)code;
|
||||
var refs = arcMove.VariableRefs;
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var arcMove = (ArcMove)code;
|
||||
var refs = arcMove.VariableRefs;
|
||||
|
||||
var x = FormatCoord(arcMove.EndPoint.X, "X", refs);
|
||||
var y = FormatCoord(arcMove.EndPoint.Y, "Y", refs);
|
||||
var i = FormatCoord(arcMove.CenterPoint.X, "I", refs);
|
||||
var j = FormatCoord(arcMove.CenterPoint.Y, "J", refs);
|
||||
var x = FormatCoord(arcMove.EndPoint.X, "X", refs);
|
||||
var y = FormatCoord(arcMove.EndPoint.Y, "Y", refs);
|
||||
var i = FormatCoord(arcMove.CenterPoint.X, "I", refs);
|
||||
var j = FormatCoord(arcMove.CenterPoint.Y, "J", refs);
|
||||
|
||||
sb.Append(arcMove.Rotation == RotationType.CW
|
||||
sb.Append(
|
||||
arcMove.Rotation == RotationType.CW
|
||||
? $"G02X{x}Y{y}I{i}J{j}"
|
||||
: $"G03X{x}Y{y}I{i}J{j}");
|
||||
: $"G03X{x}Y{y}I{i}J{j}"
|
||||
);
|
||||
|
||||
if (arcMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(arcMove.Layer));
|
||||
if (arcMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(arcMove.Layer));
|
||||
|
||||
if (arcMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
if (arcMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
case CodeType.Comment:
|
||||
{
|
||||
var comment = (Comment)code;
|
||||
return ":" + comment.Value;
|
||||
}
|
||||
{
|
||||
var comment = (Comment)code;
|
||||
return ":" + comment.Value;
|
||||
}
|
||||
|
||||
case CodeType.LinearMove:
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var linearMove = (LinearMove)code;
|
||||
var refs = linearMove.VariableRefs;
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var linearMove = (LinearMove)code;
|
||||
var refs = linearMove.VariableRefs;
|
||||
|
||||
sb.Append($"G01X{FormatCoord(linearMove.EndPoint.X, "X", refs)}Y{FormatCoord(linearMove.EndPoint.Y, "Y", refs)}");
|
||||
sb.Append(
|
||||
$"G01X{FormatCoord(linearMove.EndPoint.X, "X", refs)}Y{FormatCoord(linearMove.EndPoint.Y, "Y", refs)}"
|
||||
);
|
||||
|
||||
if (linearMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(linearMove.Layer));
|
||||
if (linearMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(linearMove.Layer));
|
||||
|
||||
if (linearMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
if (linearMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
case CodeType.RapidMove:
|
||||
{
|
||||
var rapidMove = (RapidMove)code;
|
||||
var refs = rapidMove.VariableRefs;
|
||||
{
|
||||
var rapidMove = (RapidMove)code;
|
||||
var refs = rapidMove.VariableRefs;
|
||||
|
||||
return $"G00X{FormatCoord(rapidMove.EndPoint.X, "X", refs)}Y{FormatCoord(rapidMove.EndPoint.Y, "Y", refs)}";
|
||||
}
|
||||
return $"G00X{FormatCoord(rapidMove.EndPoint.X, "X", refs)}Y{FormatCoord(rapidMove.EndPoint.Y, "Y", refs)}";
|
||||
}
|
||||
|
||||
case CodeType.SetFeedrate:
|
||||
{
|
||||
var setFeedrate = (Feedrate)code;
|
||||
if (setFeedrate.VariableRef != null)
|
||||
return $"F${setFeedrate.VariableRef}";
|
||||
return "F" + setFeedrate.Value;
|
||||
}
|
||||
{
|
||||
var setFeedrate = (Feedrate)code;
|
||||
if (setFeedrate.VariableRef != null)
|
||||
return $"F${setFeedrate.VariableRef}";
|
||||
return "F" + setFeedrate.Value;
|
||||
}
|
||||
|
||||
case CodeType.SetKerf:
|
||||
{
|
||||
var setKerf = (Kerf)code;
|
||||
|
||||
switch (setKerf.Value)
|
||||
{
|
||||
var setKerf = (Kerf)code;
|
||||
|
||||
switch (setKerf.Value)
|
||||
{
|
||||
case KerfType.None: return "G40";
|
||||
case KerfType.Left: return "G41";
|
||||
case KerfType.Right: return "G42";
|
||||
}
|
||||
|
||||
break;
|
||||
case KerfType.None:
|
||||
return "G40";
|
||||
case KerfType.Left:
|
||||
return "G41";
|
||||
case KerfType.Right:
|
||||
return "G42";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CodeType.SubProgramCall:
|
||||
{
|
||||
var subProgramCall = (SubProgramCall)code;
|
||||
var x = System.Math.Round(subProgramCall.Offset.X, OutputPrecision).ToString(CoordinateFormat);
|
||||
var y = System.Math.Round(subProgramCall.Offset.Y, OutputPrecision).ToString(CoordinateFormat);
|
||||
return $"G65P{subProgramCall.Id}X{x}Y{y}";
|
||||
}
|
||||
{
|
||||
var subProgramCall = (SubProgramCall)code;
|
||||
var x = System
|
||||
.Math.Round(subProgramCall.Offset.X, OutputPrecision)
|
||||
.ToString(CoordinateFormat);
|
||||
var y = System
|
||||
.Math.Round(subProgramCall.Offset.Y, OutputPrecision)
|
||||
.ToString(CoordinateFormat);
|
||||
return $"G65P{subProgramCall.Id}X{x}Y{y}";
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
||||
+161
-87
@@ -1,12 +1,12 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
|
||||
namespace OpenNest.IO
|
||||
{
|
||||
@@ -31,15 +31,25 @@ namespace OpenNest.IO
|
||||
{
|
||||
// First pass: read all lines, collect variable definitions
|
||||
var allLines = new List<string>();
|
||||
var variableDefs = new Dictionary<string, (string expression, bool inline, bool global)>(
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
var variableDefs = new Dictionary<
|
||||
string,
|
||||
(string expression, bool inline, bool global)
|
||||
>(StringComparer.OrdinalIgnoreCase);
|
||||
var codeLines = new List<string>();
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
allLines.Add(line);
|
||||
if (TryParseVariableDefinition(line, out var name, out var expression, out var isInline, out var isGlobal))
|
||||
if (
|
||||
TryParseVariableDefinition(
|
||||
line,
|
||||
out var name,
|
||||
out var expression,
|
||||
out var isInline,
|
||||
out var isGlobal
|
||||
)
|
||||
)
|
||||
variableDefs[name] = (expression, isInline, isGlobal);
|
||||
else
|
||||
codeLines.Add(line);
|
||||
@@ -54,7 +64,13 @@ namespace OpenNest.IO
|
||||
var name = kvp.Key;
|
||||
var (expression, isInline, isGlobal) = kvp.Value;
|
||||
var value = resolvedVariables[name];
|
||||
program.Variables[name] = new VariableDefinition(name, expression, value, isInline, isGlobal);
|
||||
program.Variables[name] = new VariableDefinition(
|
||||
name,
|
||||
expression,
|
||||
value,
|
||||
isInline,
|
||||
isGlobal
|
||||
);
|
||||
}
|
||||
|
||||
// Second pass: parse G-code lines with variable substitution
|
||||
@@ -78,7 +94,10 @@ namespace OpenNest.IO
|
||||
{
|
||||
// Read the maximal variable name (letters, digits, underscores)
|
||||
var start = i + 1;
|
||||
while (start < line.Length && (char.IsLetterOrDigit(line[start]) || line[start] == '_'))
|
||||
while (
|
||||
start < line.Length
|
||||
&& (char.IsLetterOrDigit(line[start]) || line[start] == '_')
|
||||
)
|
||||
start++;
|
||||
var maxName = line.Substring(i + 1, start - i - 1);
|
||||
|
||||
@@ -89,8 +108,9 @@ namespace OpenNest.IO
|
||||
while (nameLen > 0)
|
||||
{
|
||||
var candidate = maxName.Substring(0, nameLen);
|
||||
lookupKey = resolvedVariables.Keys
|
||||
.FirstOrDefault(k => string.Equals(k, candidate, StringComparison.OrdinalIgnoreCase));
|
||||
lookupKey = resolvedVariables.Keys.FirstOrDefault(k =>
|
||||
string.Equals(k, candidate, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
if (lookupKey != null)
|
||||
break;
|
||||
nameLen--;
|
||||
@@ -98,7 +118,8 @@ namespace OpenNest.IO
|
||||
|
||||
if (lookupKey != null)
|
||||
{
|
||||
code.Value = resolvedVariables[lookupKey].ToString(CultureInfo.InvariantCulture);
|
||||
code.Value = resolvedVariables[lookupKey]
|
||||
.ToString(CultureInfo.InvariantCulture);
|
||||
code.VariableRef = lookupKey;
|
||||
i += nameLen; // advance past the matched variable name
|
||||
}
|
||||
@@ -211,7 +232,8 @@ namespace OpenNest.IO
|
||||
double y = 0;
|
||||
var layer = LayerType.Cut;
|
||||
var suppressed = false;
|
||||
string xRef = null, yRef = null;
|
||||
string xRef = null,
|
||||
yRef = null;
|
||||
|
||||
while (section == CodeSection.Line)
|
||||
{
|
||||
@@ -235,36 +257,36 @@ namespace OpenNest.IO
|
||||
break;
|
||||
|
||||
case ':':
|
||||
{
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
foreach (var tag in tags)
|
||||
switch (tag)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
section = CodeSection.Unknown;
|
||||
@@ -277,7 +299,14 @@ namespace OpenNest.IO
|
||||
if (isRapid)
|
||||
program.Codes.Add(new RapidMove(x, y) { VariableRefs = refs });
|
||||
else
|
||||
program.Codes.Add(new LinearMove(x, y) { Layer = layer, Suppressed = suppressed, VariableRefs = refs });
|
||||
program.Codes.Add(
|
||||
new LinearMove(x, y)
|
||||
{
|
||||
Layer = layer,
|
||||
Suppressed = suppressed,
|
||||
VariableRefs = refs,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void ReadArc(RotationType rotation)
|
||||
@@ -288,7 +317,10 @@ namespace OpenNest.IO
|
||||
double j = 0;
|
||||
var layer = LayerType.Cut;
|
||||
var suppressed = false;
|
||||
string xRef = null, yRef = null, iRef = null, jRef = null;
|
||||
string xRef = null,
|
||||
yRef = null,
|
||||
iRef = null,
|
||||
jRef = null;
|
||||
|
||||
while (section == CodeSection.Arc)
|
||||
{
|
||||
@@ -323,51 +355,58 @@ namespace OpenNest.IO
|
||||
break;
|
||||
|
||||
case ':':
|
||||
{
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
foreach (var tag in tags)
|
||||
switch (tag)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
section = CodeSection.Unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
program.Codes.Add(new ArcMove()
|
||||
{
|
||||
EndPoint = new Vector(x, y),
|
||||
CenterPoint = new Vector(i, j),
|
||||
Rotation = rotation,
|
||||
Layer = layer,
|
||||
Suppressed = suppressed,
|
||||
VariableRefs = BuildVariableRefs(("X", xRef), ("Y", yRef), ("I", iRef), ("J", jRef))
|
||||
});
|
||||
program.Codes.Add(
|
||||
new ArcMove()
|
||||
{
|
||||
EndPoint = new Vector(x, y),
|
||||
CenterPoint = new Vector(i, j),
|
||||
Rotation = rotation,
|
||||
Layer = layer,
|
||||
Suppressed = suppressed,
|
||||
VariableRefs = BuildVariableRefs(
|
||||
("X", xRef),
|
||||
("Y", yRef),
|
||||
("I", iRef),
|
||||
("J", jRef)
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void ReadSubProgram()
|
||||
@@ -411,12 +450,14 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
program.Codes.Add(new SubProgramCall
|
||||
{
|
||||
Id = p,
|
||||
Rotation = r,
|
||||
Offset = new Geometry.Vector(x, y)
|
||||
});
|
||||
program.Codes.Add(
|
||||
new SubProgramCall
|
||||
{
|
||||
Id = p,
|
||||
Rotation = r,
|
||||
Offset = new Geometry.Vector(x, y),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private Code GetNextCode()
|
||||
@@ -446,8 +487,13 @@ namespace OpenNest.IO
|
||||
return block[codeIndex];
|
||||
}
|
||||
|
||||
private static bool TryParseVariableDefinition(string line, out string name, out string expression,
|
||||
out bool isInline, out bool isGlobal)
|
||||
private static bool TryParseVariableDefinition(
|
||||
string line,
|
||||
out string name,
|
||||
out string expression,
|
||||
out bool isInline,
|
||||
out bool isGlobal
|
||||
)
|
||||
{
|
||||
name = null;
|
||||
expression = null;
|
||||
@@ -467,7 +513,22 @@ namespace OpenNest.IO
|
||||
if (trimmed.Length >= 2 && char.IsDigit(trimmed[1]))
|
||||
{
|
||||
var upper = char.ToUpper(firstChar);
|
||||
if (upper is 'G' or 'M' or 'N' or 'F' or 'X' or 'Y' or 'I' or 'J' or 'T' or 'S' or 'O' or 'P' or 'R')
|
||||
if (
|
||||
upper
|
||||
is 'G'
|
||||
or 'M'
|
||||
or 'N'
|
||||
or 'F'
|
||||
or 'X'
|
||||
or 'Y'
|
||||
or 'I'
|
||||
or 'J'
|
||||
or 'T'
|
||||
or 'S'
|
||||
or 'O'
|
||||
or 'P'
|
||||
or 'R'
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -515,8 +576,10 @@ namespace OpenNest.IO
|
||||
for (var i = flagStart; i < words.Length; i++)
|
||||
{
|
||||
var word = words[i].ToLowerInvariant();
|
||||
if (word == "inline") isInline = true;
|
||||
else if (word == "global") isGlobal = true;
|
||||
if (word == "inline")
|
||||
isInline = true;
|
||||
else if (word == "global")
|
||||
isGlobal = true;
|
||||
}
|
||||
|
||||
name = rawName;
|
||||
@@ -524,13 +587,16 @@ namespace OpenNest.IO
|
||||
}
|
||||
|
||||
private static Dictionary<string, double> ResolveVariables(
|
||||
Dictionary<string, (string expression, bool inline, bool global)> variableDefs)
|
||||
Dictionary<string, (string expression, bool inline, bool global)> variableDefs
|
||||
)
|
||||
{
|
||||
if (variableDefs.Count == 0)
|
||||
return new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Build dependency graph
|
||||
var dependencies = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
var dependencies = new Dictionary<string, List<string>>(
|
||||
StringComparer.OrdinalIgnoreCase
|
||||
);
|
||||
foreach (var kvp in variableDefs)
|
||||
{
|
||||
var deps = new List<string>();
|
||||
@@ -540,12 +606,16 @@ namespace OpenNest.IO
|
||||
if (expr[i] == '$')
|
||||
{
|
||||
var start = i + 1;
|
||||
while (start < expr.Length && (char.IsLetterOrDigit(expr[start]) || expr[start] == '_'))
|
||||
while (
|
||||
start < expr.Length
|
||||
&& (char.IsLetterOrDigit(expr[start]) || expr[start] == '_')
|
||||
)
|
||||
start++;
|
||||
var refName = expr.Substring(i + 1, start - i - 1);
|
||||
// Find the canonical name (case-insensitive match)
|
||||
var canonical = variableDefs.Keys
|
||||
.FirstOrDefault(k => string.Equals(k, refName, StringComparison.OrdinalIgnoreCase));
|
||||
var canonical = variableDefs.Keys.FirstOrDefault(k =>
|
||||
string.Equals(k, refName, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
if (canonical != null)
|
||||
deps.Add(canonical);
|
||||
i = start - 1;
|
||||
@@ -600,12 +670,16 @@ namespace OpenNest.IO
|
||||
}
|
||||
|
||||
if (order.Count != variableDefs.Count)
|
||||
throw new InvalidOperationException("Circular dependency detected among variables.");
|
||||
throw new InvalidOperationException(
|
||||
"Circular dependency detected among variables."
|
||||
);
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> BuildVariableRefs(params (string axis, string varRef)[] refs)
|
||||
private static Dictionary<string, string> BuildVariableRefs(
|
||||
params (string axis, string varRef)[] refs
|
||||
)
|
||||
{
|
||||
Dictionary<string, string> result = null;
|
||||
foreach (var (axis, varRef) in refs)
|
||||
@@ -671,7 +745,7 @@ namespace OpenNest.IO
|
||||
Unknown,
|
||||
Arc,
|
||||
Line,
|
||||
SubProgram
|
||||
SubProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ACadSharp;
|
||||
using ACadSharp.Entities;
|
||||
using ACadSharp.IO;
|
||||
@@ -6,9 +8,6 @@ using CSMath;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Geometry;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
// Disambiguate Entity — both ACadSharp.Entities and OpenNest.Geometry define it
|
||||
using GeoEntity = OpenNest.Geometry.Entity;
|
||||
|
||||
@@ -50,13 +49,21 @@ namespace OpenNest.IO
|
||||
writer.Write();
|
||||
}
|
||||
|
||||
private static void WriteProgramEntities(CadDocument doc, CNC.Program program, ACadSharp.Tables.Layer layer)
|
||||
private static void WriteProgramEntities(
|
||||
CadDocument doc,
|
||||
CNC.Program program,
|
||||
ACadSharp.Tables.Layer layer
|
||||
)
|
||||
{
|
||||
var geometry = ConvertProgram.ToGeometry(program);
|
||||
WriteGeometryEntities(doc, geometry, layer);
|
||||
}
|
||||
|
||||
private static void WriteGeometryEntities(CadDocument doc, List<GeoEntity> geometry, ACadSharp.Tables.Layer layer)
|
||||
private static void WriteGeometryEntities(
|
||||
CadDocument doc,
|
||||
List<GeoEntity> geometry,
|
||||
ACadSharp.Tables.Layer layer
|
||||
)
|
||||
{
|
||||
foreach (var entity in geometry)
|
||||
{
|
||||
@@ -67,12 +74,14 @@ namespace OpenNest.IO
|
||||
switch (entity)
|
||||
{
|
||||
case OpenNest.Geometry.Line line:
|
||||
doc.Entities.Add(new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(line.StartPoint.X, line.StartPoint.Y, 0),
|
||||
EndPoint = new XYZ(line.EndPoint.X, line.EndPoint.Y, 0),
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(line.StartPoint.X, line.StartPoint.Y, 0),
|
||||
EndPoint = new XYZ(line.EndPoint.X, line.EndPoint.Y, 0),
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case OpenNest.Geometry.Arc arc:
|
||||
@@ -81,23 +90,27 @@ namespace OpenNest.IO
|
||||
if (arc.IsReversed)
|
||||
OpenNest.Math.Generic.Swap(ref startAngle, ref endAngle);
|
||||
|
||||
doc.Entities.Add(new ACadSharp.Entities.Arc
|
||||
{
|
||||
Center = new XYZ(arc.Center.X, arc.Center.Y, 0),
|
||||
Radius = arc.Radius,
|
||||
StartAngle = startAngle,
|
||||
EndAngle = endAngle,
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Arc
|
||||
{
|
||||
Center = new XYZ(arc.Center.X, arc.Center.Y, 0),
|
||||
Radius = arc.Radius,
|
||||
StartAngle = startAngle,
|
||||
EndAngle = endAngle,
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case OpenNest.Geometry.Circle circle:
|
||||
doc.Entities.Add(new ACadSharp.Entities.Circle
|
||||
{
|
||||
Center = new XYZ(circle.Center.X, circle.Center.Y, 0),
|
||||
Radius = circle.Radius,
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Circle
|
||||
{
|
||||
Center = new XYZ(circle.Center.X, circle.Center.Y, 0),
|
||||
Radius = circle.Radius,
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case OpenNest.Geometry.Shape shape:
|
||||
@@ -107,14 +120,19 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteBendLine(CadDocument doc, Bend bend, ACadSharp.Tables.Layer layer, LineType lineType)
|
||||
private static void WriteBendLine(
|
||||
CadDocument doc,
|
||||
Bend bend,
|
||||
ACadSharp.Tables.Layer layer,
|
||||
LineType lineType
|
||||
)
|
||||
{
|
||||
var line = new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(bend.StartPoint.X, bend.StartPoint.Y, 0),
|
||||
EndPoint = new XYZ(bend.EndPoint.X, bend.EndPoint.Y, 0),
|
||||
Layer = layer,
|
||||
LineType = lineType
|
||||
LineType = lineType,
|
||||
};
|
||||
doc.Entities.Add(line);
|
||||
|
||||
@@ -128,7 +146,7 @@ namespace OpenNest.IO
|
||||
InsertPoint = new XYZ(midX, midY + 0.5, 0),
|
||||
Value = bend.NoteText,
|
||||
Height = 0.1,
|
||||
Layer = layer
|
||||
Layer = layer,
|
||||
};
|
||||
doc.Entities.Add(mtext);
|
||||
}
|
||||
@@ -145,12 +163,14 @@ namespace OpenNest.IO
|
||||
|
||||
if (length < EtchLength * 3.0)
|
||||
{
|
||||
doc.Entities.Add(new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(start.X, start.Y, 0),
|
||||
EndPoint = new XYZ(end.X, end.Y, 0),
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(start.X, start.Y, 0),
|
||||
EndPoint = new XYZ(end.X, end.Y, 0),
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,19 +178,23 @@ namespace OpenNest.IO
|
||||
var dx = System.Math.Cos(angle) * EtchLength;
|
||||
var dy = System.Math.Sin(angle) * EtchLength;
|
||||
|
||||
doc.Entities.Add(new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(start.X, start.Y, 0),
|
||||
EndPoint = new XYZ(start.X + dx, start.Y + dy, 0),
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(start.X, start.Y, 0),
|
||||
EndPoint = new XYZ(start.X + dx, start.Y + dy, 0),
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
|
||||
doc.Entities.Add(new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(end.X, end.Y, 0),
|
||||
EndPoint = new XYZ(end.X - dx, end.Y - dy, 0),
|
||||
Layer = layer
|
||||
});
|
||||
doc.Entities.Add(
|
||||
new ACadSharp.Entities.Line
|
||||
{
|
||||
StartPoint = new XYZ(end.X, end.Y, 0),
|
||||
EndPoint = new XYZ(end.X - dx, end.Y - dy, 0),
|
||||
Layer = layer,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user