Files
EtchBendLines/EtchBendLines/BendLineExtractor.cs

186 lines
5.5 KiB
C#

using netDxf;
using netDxf.Entities;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
namespace EtchBendLines
{
public class BendLineExtractor
{
public BendLineExtractor(string dxfFile)
{
DxfDocument = DxfDocument.Load(dxfFile);
}
public BendLineExtractor(DxfDocument dxfDocument)
{
DxfDocument = dxfDocument;
}
/// <summary>
/// Maximum bend radius to be considered. Anything beyond this number
/// is a center line for rolling.
/// </summary>
public double MaxBendRadius { get; set; } = 4;
public double SharpRadius { get; set; } = 0.001;
public bool ReplaceSharpRadius { get; set; } = true;
/// <summary>
/// The regular expression pattern the bend note must match
/// </summary>
static readonly Regex bendNoteRegex = new Regex(
@"\b(?<direction>UP|DOWN|DN)\s+(?<angle>\d+(\.\d+)?)°?\s*R\s*(?<radius>\d+(\.\d+)?)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase
);
public DxfDocument DxfDocument { get; private set; }
public List<Bend> GetBendLines()
{
var bends = new List<Bend>();
var bendNotes = GetBendNotes();
if (ReplaceSharpRadius)
FixSharpBends();
foreach (var line in DxfDocument.Lines)
{
if (!IsBendLine(line))
continue;
var bend = new Bend
{
Line = line,
Direction = BendDirection.Unknown
};
bends.Add(bend);
}
AssignBendDirections(bends, bendNotes);
return bends.Where(b => b.Radius <= MaxBendRadius).ToList();
}
private bool IsBendLine(Line line)
{
return line.Linetype.Name == "CENTERX2" && line.Layer.Name == "BEND";
}
private List<MText> GetBendNotes()
{
return DxfDocument.MTexts
.Where(t => GetBendDirection(t) != BendDirection.Unknown)
.ToList();
}
private void FixSharpBends()
{
var bendNotes = GetBendNotes();
foreach (var bendNote in bendNotes)
{
var text = bendNote.Value?.ToUpper();
if (text == null)
continue;
var index = text.IndexOf("SHARP");
if (index == -1)
continue;
bendNote.Value = bendNote.Value
.Remove(index, 5)
.Insert(index, $"R{SharpRadius}");
}
}
private static BendDirection GetBendDirection(MText mText)
{
if (mText == null || mText.Value == null)
return BendDirection.Unknown;
var text = mText.Value.ToUpper();
if (text.Contains("UP"))
return BendDirection.Up;
if (text.Contains("DOWN") || text.Contains("DN"))
return BendDirection.Down;
return BendDirection.Unknown;
}
private static void AssignBendDirections(IEnumerable<Bend> bendlines, IEnumerable<MText> bendNotes)
{
foreach (var bendline in bendlines)
{
var bendNote = FindBendNote(bendline.Line, bendNotes);
if (bendNote == null)
continue;
bendline.BendNote = bendNote;
bendline.Direction = GetBendDirection(bendNote);
var note = bendNote.Value.ToUpper().Replace("SHARP", "R0");
var match = bendNoteRegex.Match(note);
if (match.Success)
{
var radius = match.Groups["radius"].Value;
var angle = match.Groups["angle"].Value;
bendline.Radius = double.Parse(radius, CultureInfo.InvariantCulture);
bendline.Angle = double.Parse(angle, CultureInfo.InvariantCulture);
}
}
}
private static MText FindBendNote(Line bendLine, IEnumerable<MText> bendNotes)
{
var bendNotesList = bendNotes.ToList();
for (int i = bendNotesList.Count - 1; i >= 0; i--)
{
var note = bendNotesList[i];
var notePos = note.Position.ToVector2();
var perpendicularPoint = bendLine.PointPerpendicularTo(notePos);
var dist = notePos.DistanceTo(perpendicularPoint);
var maxAcceptableDist = note.Height * 2.0;
if (dist > maxAcceptableDist)
bendNotesList.RemoveAt(i);
}
if (bendNotesList.Count == 0)
return null;
var closestNote = bendNotesList.First();
var p1 = closestNote.Position.ToVector2();
var p2 = bendLine.ClosestPointOnLineTo(p1);
var dist2 = p1.DistanceTo(p2);
for (int i = 1; i < bendNotesList.Count; i++)
{
var note = bendNotesList[i];
var p3 = note.Position.ToVector2();
var p4 = bendLine.ClosestPointOnLineTo(p3);
var dist = p3.DistanceTo(p4);
if (dist < dist2)
{
dist2 = dist;
closestNote = note;
}
}
return closestNote;
}
}
}