Compare commits
3 Commits
1c994718fb
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 53988acefc | |||
| a8d90be2ea | |||
| c25b6bc23a |
@@ -93,6 +93,9 @@ namespace OpenNest.Geometry
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFullCircle() =>
|
||||
SweepAngle() >= Angle.TwoPI - Tolerance.Epsilon;
|
||||
|
||||
/// <summary>
|
||||
/// Angle in radians between start and end angles.
|
||||
/// </summary>
|
||||
|
||||
@@ -17,6 +17,38 @@ namespace OpenNest.Geometry
|
||||
(list, item, i) => list.GetCollinearLines(item, i),
|
||||
(Line a, Line b, out Line joined) => TryJoinLines(a, b, out joined));
|
||||
|
||||
public static void Deduplicate(IList<Circle> circles)
|
||||
{
|
||||
for (var i = circles.Count - 1; i >= 1; i--)
|
||||
{
|
||||
for (var j = i - 1; j >= 0; j--)
|
||||
{
|
||||
if (circles[i].Center.DistanceTo(circles[j].Center) <= Tolerance.Epsilon
|
||||
&& circles[i].Radius.IsEqualTo(circles[j].Radius))
|
||||
{
|
||||
circles.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Deduplicate(IList<Circle> circles, IList<Arc> arcs)
|
||||
{
|
||||
for (var i = circles.Count - 1; i >= 0; i--)
|
||||
{
|
||||
for (var j = arcs.Count - 1; j >= 0; j--)
|
||||
{
|
||||
if (arcs[j].Center.DistanceTo(circles[i].Center) <= Tolerance.Epsilon
|
||||
&& arcs[j].Radius.IsEqualTo(circles[i].Radius)
|
||||
&& arcs[j].IsFullCircle())
|
||||
{
|
||||
arcs.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private delegate bool TryJoin<T>(T a, T b, out T joined);
|
||||
|
||||
private static void MergePass<T>(IList<T> items,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using ACadSharp;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
@@ -38,5 +39,11 @@ namespace OpenNest.IO
|
||||
/// Default drawing name (filename without extension, unless overridden).
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw CAD document from the source file. Available for callers
|
||||
/// that need access to non-geometry entities (e.g., text annotations).
|
||||
/// </summary>
|
||||
public CadDocument Document { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace OpenNest.IO
|
||||
Bounds = dxf.Entities.GetBoundingBox(),
|
||||
SourcePath = path,
|
||||
Name = options.Name ?? Path.GetFileNameWithoutExtension(path),
|
||||
Document = dxf.Document,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+38
-3
@@ -65,6 +65,36 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Entity> GetGeometry(string path, Func<string, bool> layerFilter)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var reader = new DxfReader(path);
|
||||
var doc = reader.Read();
|
||||
return ConvertEntities(doc, layerFilter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
return new List<Entity>();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Entity> GetGeometry(Stream stream, Func<string, bool> layerFilter)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var reader = new DxfReader(stream);
|
||||
var doc = reader.Read();
|
||||
return ConvertEntities(doc, layerFilter);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
return new List<Entity>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Export
|
||||
@@ -128,15 +158,17 @@ namespace OpenNest.IO
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Entity> ConvertEntities(CadDocument doc)
|
||||
private static List<Entity> ConvertEntities(CadDocument doc, Func<string, bool> layerFilter = null)
|
||||
{
|
||||
var entities = new List<Entity>();
|
||||
var lines = new List<Line>();
|
||||
var arcs = new List<Arc>();
|
||||
var circles = new List<Circle>();
|
||||
var filter = layerFilter ?? IsNonCutLayer;
|
||||
|
||||
foreach (var entity in doc.Entities)
|
||||
{
|
||||
if (IsNonCutLayer(entity.Layer?.Name))
|
||||
if (filter(entity.Layer?.Name))
|
||||
continue;
|
||||
|
||||
switch (entity)
|
||||
@@ -150,7 +182,7 @@ namespace OpenNest.IO
|
||||
break;
|
||||
|
||||
case ACadSharp.Entities.Circle circle:
|
||||
entities.Add(circle.ToOpenNest());
|
||||
circles.Add(circle.ToOpenNest());
|
||||
break;
|
||||
|
||||
case ACadSharp.Entities.Spline spline:
|
||||
@@ -181,7 +213,10 @@ namespace OpenNest.IO
|
||||
|
||||
GeometryOptimizer.Optimize(lines);
|
||||
GeometryOptimizer.Optimize(arcs);
|
||||
GeometryOptimizer.Deduplicate(circles);
|
||||
GeometryOptimizer.Deduplicate(circles, arcs);
|
||||
|
||||
entities.AddRange(circles);
|
||||
entities.AddRange(lines);
|
||||
entities.AddRange(arcs);
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Drawing;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Controls
|
||||
{
|
||||
public class CadText
|
||||
{
|
||||
public Vector Position { get; set; }
|
||||
public string Value { get; set; }
|
||||
public double Height { get; set; }
|
||||
public double Rotation { get; set; }
|
||||
public string LayerName { get; set; }
|
||||
public StringAlignment HAlign { get; set; }
|
||||
public StringAlignment VAlign { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,14 @@ namespace OpenNest.Controls
|
||||
public List<Entity> SimplifierToleranceRight { get; set; }
|
||||
public List<Entity> OriginalEntities { get; set; }
|
||||
public bool ShowEntityLabels { get; set; }
|
||||
public List<CadText> Texts { get; set; } = new List<CadText>();
|
||||
|
||||
private readonly Pen gridPen = new Pen(Color.FromArgb(70, 70, 70));
|
||||
private readonly Dictionary<int, Pen> penCache = new Dictionary<int, Pen>();
|
||||
private readonly Font labelFont = new Font("Segoe UI", 7f);
|
||||
private readonly SolidBrush labelBrush = new SolidBrush(Color.FromArgb(220, 255, 255, 200));
|
||||
private readonly SolidBrush labelBackBrush = new SolidBrush(Color.FromArgb(33, 40, 48));
|
||||
private readonly SolidBrush textBrush = new SolidBrush(Color.FromArgb(180, 200, 200, 200));
|
||||
|
||||
public event EventHandler<Line> LinePicked;
|
||||
public event EventHandler PickCancelled;
|
||||
@@ -116,6 +118,8 @@ namespace OpenNest.Controls
|
||||
DrawEntity(e.Graphics, entity, pen);
|
||||
}
|
||||
|
||||
DrawTexts(e.Graphics);
|
||||
|
||||
if (ShowEntityLabels)
|
||||
DrawEntityLabels(e.Graphics);
|
||||
|
||||
@@ -408,6 +412,7 @@ namespace OpenNest.Controls
|
||||
labelFont.Dispose();
|
||||
labelBrush.Dispose();
|
||||
labelBackBrush.Dispose();
|
||||
textBrush.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -474,6 +479,34 @@ namespace OpenNest.Controls
|
||||
diameter);
|
||||
}
|
||||
|
||||
private void DrawTexts(Graphics g)
|
||||
{
|
||||
if (Texts == null || Texts.Count == 0)
|
||||
return;
|
||||
|
||||
using var sf = new StringFormat();
|
||||
|
||||
foreach (var text in Texts)
|
||||
{
|
||||
var pos = PointWorldToGraph(text.Position);
|
||||
var fontSize = LengthWorldToGui(text.Height);
|
||||
if (fontSize < 2f) continue;
|
||||
|
||||
var state = g.Save();
|
||||
g.TranslateTransform(pos.X, pos.Y);
|
||||
|
||||
if (text.Rotation != 0)
|
||||
g.RotateTransform((float)OpenNest.Math.Angle.ToDegrees(text.Rotation));
|
||||
|
||||
sf.Alignment = text.HAlign;
|
||||
sf.LineAlignment = text.VAlign;
|
||||
|
||||
using var font = new Font("Segoe UI", fontSize, GraphicsUnit.Pixel);
|
||||
g.DrawString(text.Value, font, textBrush, 0, 0, sf);
|
||||
g.Restore(state);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPoint(Graphics g, Vector pt, Pen pen)
|
||||
{
|
||||
var pt1 = PointWorldToGraph(pt);
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenNest.Controls
|
||||
public HashSet<Guid> SuppressedEntityIds { get; set; }
|
||||
public Box Bounds { get; set; }
|
||||
public int EntityCount { get; set; }
|
||||
public List<CadText> Texts { get; set; } = new();
|
||||
}
|
||||
|
||||
public class FileListControl : Control
|
||||
|
||||
@@ -92,7 +92,8 @@ namespace OpenNest.Forms
|
||||
Customer = string.Empty,
|
||||
Bends = result.Bends,
|
||||
Bounds = result.Bounds,
|
||||
EntityCount = result.Entities.Count
|
||||
EntityCount = result.Entities.Count,
|
||||
Texts = ExtractTexts(result.Document),
|
||||
};
|
||||
|
||||
if (InvokeRequired)
|
||||
@@ -152,6 +153,7 @@ namespace OpenNest.Forms
|
||||
entityView1.Entities.Clear();
|
||||
entityView1.Entities.AddRange(item.Entities);
|
||||
entityView1.Bends = item.Bends ?? new List<Bend>();
|
||||
entityView1.Texts = item.Texts ?? new List<CadText>();
|
||||
|
||||
item.Entities.ForEach(e => e.IsVisible = true);
|
||||
if (item.Entities.Any(e => e.Layer != null))
|
||||
@@ -804,6 +806,102 @@ namespace OpenNest.Forms
|
||||
|
||||
#endregion
|
||||
|
||||
private static List<CadText> ExtractTexts(ACadSharp.CadDocument doc)
|
||||
{
|
||||
var texts = new List<CadText>();
|
||||
if (doc == null) return texts;
|
||||
|
||||
foreach (var entity in doc.Entities)
|
||||
{
|
||||
switch (entity)
|
||||
{
|
||||
case ACadSharp.Entities.MText mtext:
|
||||
var (mh, mv) = MapAttachmentPoint(mtext.AttachmentPoint);
|
||||
texts.Add(new CadText
|
||||
{
|
||||
Position = new Vector(mtext.InsertPoint.X, mtext.InsertPoint.Y),
|
||||
Value = ReplaceControlCodes(StripMTextFormatting(mtext.Value)),
|
||||
Height = mtext.Height,
|
||||
Rotation = mtext.Rotation,
|
||||
LayerName = mtext.Layer?.Name,
|
||||
HAlign = mh,
|
||||
VAlign = mv,
|
||||
});
|
||||
break;
|
||||
|
||||
case ACadSharp.Entities.TextEntity text:
|
||||
var useAlignment = text.HorizontalAlignment != 0
|
||||
|| text.VerticalAlignment != 0;
|
||||
var pt = useAlignment ? text.AlignmentPoint : text.InsertPoint;
|
||||
var ha = text.HorizontalAlignment switch
|
||||
{
|
||||
ACadSharp.Entities.TextHorizontalAlignment.Center => System.Drawing.StringAlignment.Center,
|
||||
ACadSharp.Entities.TextHorizontalAlignment.Right => System.Drawing.StringAlignment.Far,
|
||||
_ => System.Drawing.StringAlignment.Near,
|
||||
};
|
||||
texts.Add(new CadText
|
||||
{
|
||||
Position = new Vector(pt.X, pt.Y),
|
||||
Value = ReplaceControlCodes(text.Value),
|
||||
Height = text.Height,
|
||||
Rotation = text.Rotation,
|
||||
LayerName = text.Layer?.Name,
|
||||
HAlign = ha,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return texts;
|
||||
}
|
||||
|
||||
private static (System.Drawing.StringAlignment h, System.Drawing.StringAlignment v) MapAttachmentPoint(
|
||||
ACadSharp.Entities.AttachmentPointType apt)
|
||||
{
|
||||
var h = apt switch
|
||||
{
|
||||
ACadSharp.Entities.AttachmentPointType.TopCenter
|
||||
or ACadSharp.Entities.AttachmentPointType.MiddleCenter
|
||||
or ACadSharp.Entities.AttachmentPointType.BottomCenter => System.Drawing.StringAlignment.Center,
|
||||
ACadSharp.Entities.AttachmentPointType.TopRight
|
||||
or ACadSharp.Entities.AttachmentPointType.MiddleRight
|
||||
or ACadSharp.Entities.AttachmentPointType.BottomRight => System.Drawing.StringAlignment.Far,
|
||||
_ => System.Drawing.StringAlignment.Near,
|
||||
};
|
||||
var v = apt switch
|
||||
{
|
||||
ACadSharp.Entities.AttachmentPointType.MiddleLeft
|
||||
or ACadSharp.Entities.AttachmentPointType.MiddleCenter
|
||||
or ACadSharp.Entities.AttachmentPointType.MiddleRight => System.Drawing.StringAlignment.Center,
|
||||
ACadSharp.Entities.AttachmentPointType.BottomLeft
|
||||
or ACadSharp.Entities.AttachmentPointType.BottomCenter
|
||||
or ACadSharp.Entities.AttachmentPointType.BottomRight => System.Drawing.StringAlignment.Far,
|
||||
_ => System.Drawing.StringAlignment.Near,
|
||||
};
|
||||
return (h, v);
|
||||
}
|
||||
|
||||
private static string StripMTextFormatting(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return text;
|
||||
var result = System.Text.RegularExpressions.Regex.Replace(text, @"\\[A-Za-z][^;]*;", "");
|
||||
result = result.Replace("{", "").Replace("}", "");
|
||||
return result.Trim();
|
||||
}
|
||||
|
||||
private static string ReplaceControlCodes(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return text;
|
||||
return text
|
||||
.Replace("%%p", "±")
|
||||
.Replace("%%P", "±")
|
||||
.Replace("%%d", "°")
|
||||
.Replace("%%D", "°")
|
||||
.Replace("%%c", "⌀")
|
||||
.Replace("%%C", "⌀")
|
||||
.Replace("%%%", "%");
|
||||
}
|
||||
|
||||
private void filterPanel_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user