public static PathDefWithClosed Sanitize(PathDefWithClosed inp) { PathDefWithClosed R = new PathDefWithClosed(); R.Width = inp.Width; R.Closed = inp.Closed; PointD last = new PointD(double.NaN, double.NaN); foreach (var v in inp.Vertices) { if (v != last) { R.Vertices.Add(v); last = v.Copy(); } } return(R); }
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 static List <List <PointD> > LineSegmentsToPolygons(List <List <PointD> > input, bool joinclosest = true) { List <PathDefWithClosed> Paths = new List <PathDefWithClosed>(); List <List <PointD> > FirstSweep = new List <List <PointD> >(); List <List <PointD> > LeftoverLines = new List <List <PointD> >(); if (input.Count == 0) { return(LeftoverLines); } try { foreach (var p in input) { if (p.Count > 0) { FirstSweep.Add(Sanitize(p)); } } LeftoverLines.Add(FirstSweep[0]); for (int i = 1; i < FirstSweep.Count; i++) { var LastLeft = LeftoverLines.Last(); var LastLeftP = LastLeft.Last(); if (FirstSweep[i].First() == LastLeftP) { LastLeft.AddRange(FirstSweep[i].Skip(1)); } else { if (FirstSweep[i].Last() == LastLeftP) { FirstSweep[i].Reverse(); LastLeft.AddRange(FirstSweep[i].Skip(1)); } else { LeftoverLines.Add(FirstSweep[i]); } } } } catch (Exception E) { Console.WriteLine(E.Message); } while (LeftoverLines.Count > 0) { bool added = false; var a = LeftoverLines.Last(); LeftoverLines.Remove(a); #region oldcode //foreach (var P in Paths) //{ // if (added == false && P.Closed == false) // { // if (P.Points[0] == a.First()) // { // if (P.Points.Last() == a.Last()) // { // P.Closed = true; // } // else // { // P.Points.Insert(0, a.First()); // } // added = true; // } // else // if (P.Points[0] == a.Last()) // { // P.Points.Insert(0, a.First()); // added = true; // } // else // if (P.Points.Last() == a.First()) // { // P.Points.Add(a.Last()); // added = true; // } // else // if (P.Points.Last() == a.Last()) // { // P.Points.Add(a.First()); // added = true; // } // else // { // } // } //} #endregion if (added == false) { PathDefWithClosed P = new PathDefWithClosed(); foreach (var v in a) { P.Points.Add(v); } //P.Points.Add(a.Last()); if (a.First() == a.Last()) { int matching = 0; for (int i = 0; i < a.Count / 2; i++) { if (a[i] == a[a.Count - 1 - i]) { matching++; } } if (matching > 1) { P.Points.Clear(); for (int i = 0; i < (a.Count + 1) / 2; i++) { P.Points.Add(a[i]); } } else { a.Remove(a.Last()); // Console.WriteLine("closed path with {0} points during stage 2: {1} reversematched", a.Count(), matching); P.Closed = true; } } Paths.Add(P); } } int Merges = 1; int startat = 0; int lasthigh = 0; while (Merges > 0) { startat = lasthigh; Merges = FindNextMerge(Paths, out lasthigh, startat); } 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); } /* * 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 <List <PointD> > Results = new List <List <PointD> >(); foreach (var p in Paths) { Results.Add(Sanitize(p.Points)); } return(Results); }