public void CreateBoxOutline() { PolyLine Box = new PolyLine(); Box.MakeRectangle(BoundingBox.Width(), BoundingBox.Height()); Box.Translate(BoundingBox.TopLeft.X + BoundingBox.Width() / 2.0, BoundingBox.TopLeft.Y + BoundingBox.Height() / 2.0); Box.Hole = false; //Box.Close(); // Box.Vertices.Reverse(); ParsedGerber PLS = new ParsedGerber(); PLS.Name = "Generated BoundingBox"; PLS.DisplayShapes.Add(Box); PLS.OutlineShapes.Add(Box); PLS.Shapes.Add(Box); PLS.Layer = BoardLayer.Outline; PLS.Side = BoardSide.Both; // PLS.FixPolygonWindings(); PLS.CalcPathBounds(); PLSs.Add(PLS); }
private static int FindNextClosest(List <PathDefWithClosed> Paths) { QuadTreeNode Root = new QuadTreeNode(); PolyLineSet.Bounds B = new PolyLineSet.Bounds(); for (int i = 0; i < Paths.Count; i++) { if (Paths[i].Closed == false) { B.FitPoint(Paths[i].Vertices.First()); B.FitPoint(Paths[i].Vertices.Last()); } } Root.xstart = B.TopLeft.X - 10; Root.xend = B.BottomRight.X + 10; Root.ystart = B.TopLeft.Y - 10; Root.yend = B.BottomRight.Y + 10; for (int i = 0; i < Paths.Count; i++) { if (Paths[i].Closed == false) { Root.Insert(new SegmentEndContainer() { PathID = i, Point = Paths[i].Vertices.First(), Side = SideEnum.Start }, 5); Root.Insert(new SegmentEndContainer() { PathID = i, Point = Paths[i].Vertices.Last(), Side = SideEnum.End }, 5); } } RectangleF R = new RectangleF(); R.Width = 3; R.Height = 3; for (int i = 0; i < Paths.Count; i++) { var P = Paths[i]; if (P.Closed == false) { var PF = P.Vertices[0]; var PF2 = P.Vertices[1]; var PathDir = PF - PF2;// MathHelpers.Difference(PF, PF2); PathDir.Normalize(); R.X = (float)(P.Vertices.First().X - 1.5); R.Y = (float)(P.Vertices.First().Y - 1.5); int startmatch = -1; int endmatch = -1; double closestdistance = B.Width() + B.Height(); Root.CallBackInside(R, delegate(QuadTreeItem QI) { var S = QI as SegmentEndContainer; if (S.PathID == i) { return(true); } if (P.Width != Paths[S.PathID].Width) { return(true); } PointD Dir2; if (S.Side == SideEnum.Start) { var S2 = Paths[S.PathID].Vertices[1]; Dir2 = S2 - S.Point; Dir2.Normalize(); } else { var S2 = Paths[S.PathID].Vertices[Paths[S.PathID].Vertices.Count() - 2]; Dir2 = S2 - S.Point; Dir2.Normalize(); } double dotted = Dir2.Dot(PathDir); var D = PointD.Distance(S.Point, PF); if (D < 1.0) { // D -= dotted * 3.0; if (D < closestdistance) { closestdistance = D; if (S.Side == SideEnum.Start) { startmatch = S.PathID; } else { endmatch = S.PathID; } } } return(true); }); if (startmatch > -1 || endmatch > -1) { if (endmatch > -1) { if (closestdistance > 0) { Paths[endmatch].Vertices.Remove(Paths[endmatch].Vertices.Last()); } Paths[endmatch].Vertices.AddRange(Paths[i].Vertices); if (Paths[endmatch].Vertices.First() == Paths[endmatch].Vertices.Last()) { Console.WriteLine("closed path with {0} points during stage 4a", Paths[endmatch].Vertices.Count()); Paths[endmatch].Closed = true; } Paths.Remove(Paths[i]); // Console.WriteLine(" 4a"); return(1); } if (startmatch > -1) { Paths[i].Vertices.Reverse(); if (closestdistance > 0) { Paths[i].Vertices.Remove(Paths[i].Vertices.Last()); } Paths[i].Vertices.AddRange(Paths[startmatch].Vertices); if (Paths[i].Vertices.First() == Paths[i].Vertices.Last()) { Console.WriteLine("closed path with {0} points during stage 4b", Paths[i].Vertices.Count()); Paths[i].Closed = true; } Paths.Remove(Paths[startmatch]); //Console.WriteLine(" 4b"); return(1); } } PF = P.Vertices.Last(); R.X = (float)(P.Vertices.First().X - 1.5); R.Y = (float)(P.Vertices.First().Y - 1.5); startmatch = -1; endmatch = -1; closestdistance = B.Width() + B.Height(); Root.CallBackInside(R, delegate(QuadTreeItem QI) { var S = QI as SegmentEndContainer; if (S.PathID == i) { return(true); } if (P.Width != Paths[S.PathID].Width) { return(true); } var D = PointD.Distance(S.Point, PF); if (D < 1.0 && D < closestdistance) { closestdistance = D; if (S.Side == SideEnum.Start) { startmatch = S.PathID; } else { endmatch = S.PathID; } } return(true); }); if (startmatch > -1 || endmatch > -1) { if (endmatch > -1) { Paths[i].Vertices.Reverse(); if (closestdistance > 0) { Paths[endmatch].Vertices.Remove(Paths[endmatch].Vertices.Last()); } Paths[endmatch].Vertices.AddRange(Paths[i].Vertices); if (Paths[endmatch].Vertices.First() == Paths[endmatch].Vertices.Last()) { Console.WriteLine("closed path with {0} points during stage 4c", Paths[endmatch].Vertices.Count()); Paths[endmatch].Closed = true; } Paths.Remove(Paths[i]); // Console.WriteLine(" 4c"); return(1); } if (startmatch > -1) { if (closestdistance > 0) { Paths[i].Vertices.Remove(Paths[i].Vertices.Last()); } Paths[i].Vertices.AddRange(Paths[startmatch].Vertices); if (Paths[i].Vertices.First() == Paths[i].Vertices.Last()) { Console.WriteLine("closed path with {0} points during stage 4d", Paths[i].Vertices.Count()); Paths[i].Closed = true; } Paths.Remove(Paths[startmatch]); // Console.WriteLine(" 4d"); return(1); } } } } return(0); }
public static List <PathDefWithClosed> LineSegmentsToPolygons(List <PathDefWithClosed> input, bool joinclosest = true) { // return input; List <PathDefWithClosed> Paths = new List <PathDefWithClosed>(); List <PathDefWithClosed> FirstSweep = new List <PathDefWithClosed>(); List <PathDefWithClosed> LeftoverLines = new List <PathDefWithClosed>(); if (input.Count == 0) { return(LeftoverLines); } try { foreach (var p in input) { if (p.Vertices.Count() > 0) { FirstSweep.Add(Sanitize(p)); } } FirstSweep = StripOverlaps(FirstSweep); LeftoverLines.Add(FirstSweep[0]); for (int i = 1; i < FirstSweep.Count; i++) { var LastLeft = LeftoverLines.Last(); var LastLeftP = LastLeft.Vertices.Last(); if (FirstSweep[i].Vertices.First() == LastLeftP) { LastLeft.Vertices.AddRange(FirstSweep[i].Vertices.Skip(1)); } else { if (FirstSweep[i].Vertices.Last() == LastLeftP) { FirstSweep[i].Vertices.Reverse(); LastLeft.Vertices.AddRange(FirstSweep[i].Vertices.Skip(1)); } else { LeftoverLines.Add(FirstSweep[i]); } } } LeftoverLines = StripOverlaps(LeftoverLines); } catch (Exception E) { Console.WriteLine(E.Message); } while (LeftoverLines.Count > 0) { bool added = false; var a = LeftoverLines.Last(); LeftoverLines.Remove(a); if (added == false) { PathDefWithClosed P = new PathDefWithClosed(); P.Width = a.Width; foreach (var v in a.Vertices) { P.Vertices.Add(v); } //P.Points.Add(a.Last()); if (a.Vertices.First() == a.Vertices.Last()) { int matching = 0; for (int i = 0; i < a.Vertices.Count / 2; i++) { if (a.Vertices[i] == a.Vertices[a.Vertices.Count - 1 - i]) { matching++; } } if (matching > 1) { P.Vertices.Clear(); List <PointD> DebugN = new List <PointD>(); List <int> Kinks = new List <int>(); List <int> KinkEnd = new List <int>(); Kinks.Add(0); for (int i = 1; i < a.Vertices.Count; i++) { var N1 = MathHelpers.Normal(a.Vertices[(i - 1)], a.Vertices[i]); var N2 = MathHelpers.Normal(a.Vertices[i], a.Vertices[(i + 1) % a.Vertices.Count()]); if (N1.Dot(N2) < 0.8) { DebugN.Add(a.Vertices[i]); DebugN.Add(N1 * 4.0 + a.Vertices[i]); Kinks.Add(i); KinkEnd.Add(i); } } KinkEnd.Add(a.Vertices.Count - 1); double maxD = 0; int maxSeg = 0; for (int i = 0; i < Kinks.Count; i++) { double D = 0; for (int j = Kinks[i]; j < KinkEnd[i]; j++) { D += (a.Vertices[j] - a.Vertices[j + 1]).Length(); } if (D > maxD) { maxD = D; maxSeg = i; } } for (int i = Kinks[maxSeg]; i < KinkEnd[maxSeg]; i++) { P.Vertices.Add(a.Vertices[i]); } bool dumpdebugline = false; if (dumpdebugline) { PolyLineSet.Bounds Bbox = new PolyLineSet.Bounds(); foreach (var v in a.Vertices) { Bbox.FitPoint(v); Bbox.FitPoint(new PointD(v.X + 10, v.Y + 10)); Bbox.FitPoint(new PointD(v.X - 10, v.Y - 10)); } float Scaler = 50.0f; Bitmap OutB = new Bitmap((int)(Bbox.Width() * Scaler), (int)(Bbox.Height() * Scaler)); Graphics G = Graphics.FromImage(OutB); G.Clear(Color.White); GraphicsGraphicsInterface GGI = new GraphicsGraphicsInterface(G); GGI.TranslateTransform((float)-Bbox.TopLeft.X * Scaler, (float)-Bbox.TopLeft.Y * Scaler); GGI.DrawLines(new Pen(Color.Red, 0.1f), (from i in a.Vertices select(i * Scaler).ToF()).ToArray()); for (int i = 1; i < a.Vertices.Count; i++) { var N = MathHelpers.Normal(a.Vertices[i - 1], a.Vertices[i]); GGI.DrawString(i.ToString(), new Font("arial", 14), new SolidBrush(Color.FromArgb((i + 128) % 256, i % 256, i % 256)), (float)a.Vertices[i].X * Scaler + (float)N.X * 20.0f, (float)a.Vertices[i].Y * Scaler + (float)N.Y * 20.0f, new StringFormat()); } for (int i = 0; i < DebugN.Count; i += 2) { GGI.DrawLine(new Pen(Color.DarkGreen, 1.0f), (DebugN[i] * Scaler).ToF(), (DebugN[i + 1] * Scaler).ToF()); } OutB.Save("testout.png"); } } else { a.Vertices.Remove(a.Vertices.Last()); //Console.WriteLine("closed path with {0} points during stage 2: {1} reversematched", a.Vertices.Count(), matching); P.Closed = true; } } Paths.Add(P); } } Paths = StripOverlaps(Paths); // return Paths; int Merges = 1; int startat = 0; int lasthigh = 0; while (Merges > 0) { startat = lasthigh; Merges = FindNextMerge(Paths, out lasthigh, startat); } //return Paths; int ClosedCount = (from i in Paths where i.Closed == true select i).Count(); if (ClosedCount < Paths.Count) { //Console.WriteLine("{0}/{1} paths open - finding closest connections", Paths.Count - ClosedCount, Paths.Count); if (joinclosest) { Merges = 1; while (Merges > 0) { Merges = FindNextClosest(Paths); } int NewClosedCount = (from i in Paths where i.Closed == true select i).Count(); Console.WriteLine("remaining open: {0}", NewClosedCount); /* * var OpenPaths = (from i in Paths where i.Closed == false select i).ToArray(); * // foreach (var p in OpenPaths) * // { * // Paths.Remove(p); * // } * * while (OpenPaths.Count() > 1) * { * var P = OpenPaths[0]; * var V = P.Points.Last(); * double ClosestDistance = 1000000; * int closestindex = 0; * bool forward = true; * * double OwnDistance = (P.Points.First() - P.Points.Last()).Length(); * ClosestDistance = OwnDistance; * for (int i = 1; i < OpenPaths.Count(); i++) * { * double dx1 = OpenPaths[i].Points.First().X - V.X; * double dy1 = OpenPaths[i].Points.First().Y - V.Y; * * double dx2 = OpenPaths[i].Points.Last().X - V.X; * double dy2 = OpenPaths[i].Points.Last().Y - V.Y; * * float disttofirst = (float)Math.Sqrt(dx1 * dx1 + dy1 * dy1); * float disttolast = (float)Math.Sqrt(dx2 * dx2 + dy2 * dy2); * * if (disttofirst < ClosestDistance) * { * forward = true; * closestindex = i; * ClosestDistance = disttofirst; * } * * if (disttolast < ClosestDistance) * { * forward = false; * closestindex = i; * ClosestDistance = disttolast; * } * * } * if (OwnDistance == ClosestDistance) * { * P.Closed = true; * // Paths.Add(P); * } * else * { * if (forward) * { * var PJ = OpenPaths[closestindex]; * P.Points.AddRange(PJ.Points); * Paths.Remove(PJ); * } * else * { * var PJ = OpenPaths[closestindex]; * PJ.Points.Reverse(); * P.Points.AddRange(PJ.Points); * Paths.Remove(PJ); * } * if (P.Points.First() == P.Points.Last()) * { * P.Closed = true; * } * } * * * OpenPaths = (from i in Paths where i.Closed == false select i).ToArray(); * * }*/ } } List <PathDefWithClosed> Results = new List <PathDefWithClosed>(); foreach (var p in Paths) { Results.Add(Sanitize(p)); } return(Results); }
public void FixEagleDrillExportIssues(ProgressLog Logger) { List <ParsedGerber> DrillFiles = new List <ParsedGerber>(); List <Tuple <double, ParsedGerber> > DrillFilesToReload = new List <Tuple <double, ParsedGerber> >(); PolyLineSet.Bounds BB = new PolyLineSet.Bounds(); foreach (var a in PLSs) { if (a.Layer == BoardLayer.Drill) { DrillFiles.Add(a); } else { BB.AddBox(a.BoundingBox); } } foreach (var a in DrillFiles) { var b = a.BoundingBox; if (b.Width() > BB.Width() * 1.5 || b.Height() > BB.Height() * 1.5) { var MaxRatio = Math.Max(b.Width() / BB.Width(), b.Height() / BB.Height()); if (Logger != null) { Logger.AddString(String.Format("Note: Really large drillfile found({0})-fix your export scripts!", a.Name)); } Console.WriteLine("Note: Really large drillfile found ({0})- fix your export scripts!", a.Name); DrillFilesToReload.Add(new Tuple <double, ParsedGerber>(MaxRatio, a)); } } foreach (var a in DrillFilesToReload) { PLSs.Remove(a.Item2); var scale = 1.0; if (Double.IsInfinity(a.Item1) || Double.IsNaN(a.Item1)) { Errors.Add("Drill file size reached infinity - ignoring it"); if (Logger != null) { Logger.AddString("Drill file size reached infinity - ignoring it"); } } else { var R = a.Item1; while (R >= 1.5) { R /= 10; scale /= 10; } AddFileToSet(a.Item2.Name, Logger, scale); } } BoundingBox = new PolyLineSet.Bounds(); foreach (var a in PLSs) { //Console.WriteLine("Progress: Adding board {6} to box::{0:N2},{1:N2} - {2:N2},{3:N2} -> {4:N2},{5:N2}", a.BoundingBox.TopLeft.X, a.BoundingBox.TopLeft.Y, a.BoundingBox.BottomRight.X, a.BoundingBox.BottomRight.Y, a.BoundingBox.Width(), a.BoundingBox.Height(), Path.GetFileName( a.Name)); //Console.WriteLine("adding box for {0}:{1},{2}", a.Name, a.BoundingBox.Width(), a.BoundingBox.Height()); BoundingBox.AddBox(a.BoundingBox); } }