feat: improve DXF export and cross-platform file handling
- PepSettings: add DrawingsDirectory property for DXF endpoint config - DrawingDxfExporter: support subprogram calls, skip non-cut linear moves, remove spurious radians-to-degrees conversion on arc angles, set AC1018 DXF version - DrawingReader: handle .loop-info/.cadsnapshot entries gracefully, derive DrawingInfo from loop names when .info entry is absent, use FileShare.Read - DrawingInfoReader: use TryParse instead of Parse for material number - Drawing: make GetLoopName public (used by DrawingDxfExporter) - ZipHelper: use FileShare.Read to allow concurrent readers on Windows/Linux - NestFilterData: skip status filter when value is "All" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using ACadSharp;
|
||||
using ACadSharp;
|
||||
using ACadSharp.IO;
|
||||
using ACadSharp.Tables;
|
||||
using CSMath;
|
||||
@@ -17,76 +17,29 @@ public static class DrawingDxfExporter
|
||||
public static Stream Export(Drawing drawing)
|
||||
{
|
||||
var doc = new CadDocument();
|
||||
doc.Header.Version = ACadVersion.AC1018;
|
||||
|
||||
// Collect loop IDs that are called as subprograms so we skip drawing them as top-level
|
||||
var subprogramIds = new HashSet<int>();
|
||||
foreach (var loop in drawing.Loops)
|
||||
{
|
||||
foreach (var code in loop)
|
||||
{
|
||||
if (code.CodeType() == CodeType.SubProgramCall)
|
||||
subprogramIds.Add(((SubProgramCall)code).LoopId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var loop in drawing.Loops)
|
||||
{
|
||||
var loopNumber = GetLoopNumber(loop.Name);
|
||||
if (subprogramIds.Contains(loopNumber))
|
||||
continue; // drawn inline at SubProgramCall positions
|
||||
|
||||
var layer = new Layer(loop.Name);
|
||||
doc.Layers.Add(layer);
|
||||
|
||||
var pos = new Vector();
|
||||
|
||||
foreach (var code in loop)
|
||||
{
|
||||
switch (code.CodeType())
|
||||
{
|
||||
case CodeType.RapidMove:
|
||||
pos = Advance(pos, ((RapidMove)code).EndPoint, loop.Mode);
|
||||
break;
|
||||
|
||||
case CodeType.LinearMove:
|
||||
var lm = (LinearMove)code;
|
||||
var lineEnd = Advance(pos, lm.EndPoint, loop.Mode);
|
||||
doc.Entities.Add(new AcadLine
|
||||
{
|
||||
StartPoint = ToXYZ(pos),
|
||||
EndPoint = ToXYZ(lineEnd),
|
||||
Layer = layer
|
||||
});
|
||||
pos = lineEnd;
|
||||
break;
|
||||
|
||||
case CodeType.CircularMove:
|
||||
var cm = (CircularMove)code;
|
||||
var arcEnd = Advance(pos, cm.EndPoint, loop.Mode);
|
||||
var arcCenter = Advance(pos, cm.CenterPoint, loop.Mode);
|
||||
|
||||
var dx = pos.X - arcCenter.X;
|
||||
var dy = pos.Y - arcCenter.Y;
|
||||
var radius = Math.Sqrt(dx * dx + dy * dy);
|
||||
|
||||
var startAngle = Math.Atan2(pos.Y - arcCenter.Y, pos.X - arcCenter.X);
|
||||
var endAngle = Math.Atan2(arcEnd.Y - arcCenter.Y, arcEnd.X - arcCenter.X);
|
||||
|
||||
if (cm.Rotation == RotationType.CW)
|
||||
{
|
||||
(startAngle, endAngle) = (endAngle, startAngle);
|
||||
}
|
||||
|
||||
if (Math.Abs(startAngle - endAngle) < 1e-10) // full circle
|
||||
{
|
||||
doc.Entities.Add(new AcadCircle
|
||||
{
|
||||
Center = ToXYZ(arcCenter),
|
||||
Radius = radius,
|
||||
Layer = layer
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
doc.Entities.Add(new AcadArc
|
||||
{
|
||||
Center = ToXYZ(arcCenter),
|
||||
Radius = radius,
|
||||
StartAngle = startAngle * (180.0 / Math.PI),
|
||||
EndAngle = endAngle * (180.0 / Math.PI),
|
||||
Layer = layer
|
||||
});
|
||||
}
|
||||
|
||||
pos = arcEnd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DrawLoop(doc, drawing, loop, layer, new Vector());
|
||||
}
|
||||
|
||||
var buffer = new MemoryStream();
|
||||
@@ -95,8 +48,97 @@ public static class DrawingDxfExporter
|
||||
writer.Write();
|
||||
}
|
||||
|
||||
var stream = new MemoryStream(buffer.ToArray());
|
||||
return stream;
|
||||
return new MemoryStream(buffer.ToArray());
|
||||
}
|
||||
|
||||
private static Vector DrawLoop(CadDocument doc, Drawing drawing, Loop loop, Layer layer, Vector startPos)
|
||||
{
|
||||
var pos = startPos;
|
||||
|
||||
foreach (var code in loop)
|
||||
{
|
||||
switch (code.CodeType())
|
||||
{
|
||||
case CodeType.RapidMove:
|
||||
pos = Advance(pos, ((RapidMove)code).EndPoint, loop.Mode);
|
||||
break;
|
||||
|
||||
case CodeType.LinearMove:
|
||||
var lm = (LinearMove)code;
|
||||
if (lm.Type == EntityType.Cut)
|
||||
{
|
||||
var lineEnd = Advance(pos, lm.EndPoint, loop.Mode);
|
||||
doc.Entities.Add(new AcadLine
|
||||
{
|
||||
StartPoint = ToXYZ(pos),
|
||||
EndPoint = ToXYZ(lineEnd),
|
||||
Layer = layer
|
||||
});
|
||||
pos = lineEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = Advance(pos, lm.EndPoint, loop.Mode);
|
||||
}
|
||||
break;
|
||||
|
||||
case CodeType.CircularMove:
|
||||
var cm = (CircularMove)code;
|
||||
var arcEnd = Advance(pos, cm.EndPoint, loop.Mode);
|
||||
var arcCenter = Advance(pos, cm.CenterPoint, loop.Mode);
|
||||
|
||||
var dx = pos.X - arcCenter.X;
|
||||
var dy = pos.Y - arcCenter.Y;
|
||||
var radius = Math.Sqrt(dx * dx + dy * dy);
|
||||
|
||||
var startAngle = Math.Atan2(pos.Y - arcCenter.Y, pos.X - arcCenter.X);
|
||||
var endAngle = Math.Atan2(arcEnd.Y - arcCenter.Y, arcEnd.X - arcCenter.X);
|
||||
|
||||
if (cm.Rotation == RotationType.CW)
|
||||
(startAngle, endAngle) = (endAngle, startAngle);
|
||||
|
||||
if (Math.Abs(startAngle - endAngle) < 1e-10)
|
||||
{
|
||||
doc.Entities.Add(new AcadCircle
|
||||
{
|
||||
Center = ToXYZ(arcCenter),
|
||||
Radius = radius,
|
||||
Layer = layer
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
doc.Entities.Add(new AcadArc
|
||||
{
|
||||
Center = ToXYZ(arcCenter),
|
||||
Radius = radius,
|
||||
StartAngle = startAngle,
|
||||
EndAngle = endAngle,
|
||||
Layer = layer
|
||||
});
|
||||
}
|
||||
|
||||
pos = arcEnd;
|
||||
break;
|
||||
|
||||
case CodeType.SubProgramCall:
|
||||
var call = (SubProgramCall)code;
|
||||
var subLoop = drawing.Loops.FirstOrDefault(l => l.Name == drawing.GetLoopName(call.LoopId));
|
||||
if (subLoop != null)
|
||||
DrawLoop(doc, drawing, subLoop, layer, pos);
|
||||
// pos unchanged — subprograms are closed shapes that return to start
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static int GetLoopNumber(string loopName)
|
||||
{
|
||||
var idx = loopName.LastIndexOf(".loop-", StringComparison.OrdinalIgnoreCase);
|
||||
if (idx < 0) return -1;
|
||||
return int.TryParse(loopName.Substring(idx + 6), out var n) ? n : -1;
|
||||
}
|
||||
|
||||
private static Vector Advance(Vector current, Vector offset, ProgrammingMode mode) =>
|
||||
@@ -104,4 +146,3 @@ public static class DrawingDxfExporter
|
||||
|
||||
private static XYZ ToXYZ(Vector v) => new XYZ(v.X, v.Y, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user