/// <summary> /// Remove vertices that are colinear w/ their two neighbours, within angle tolerance /// </summary> public void CollapseFlatVertices(double fMaxDeviationDeg = 5) { bool done = false; int max_passes = 200; int pass_count = 0; while (done == false && pass_count++ < max_passes) { done = true; // [RMS] do modulo-indexing here to avoid pathological cases where we do things like // continually collapse a short edge adjacent to a long edge (which will result in crazy over-collapse) int N = Graph.MaxVertexID; const int nPrime = 31337; // any prime will do... int cur_vid = 0; do { int vid = cur_vid; cur_vid = (cur_vid + nPrime) % N; if (!Graph.IsVertex(vid)) { continue; } if (Graph.GetVtxEdgeCount(vid) != 2) { continue; } double open = Math.Abs(Graph.OpeningAngle(vid)); if (open < 180 - fMaxDeviationDeg) { continue; } var edges = Graph.GetVtxEdges(vid); int eid = edges.First(); int eid2 = edges.Last(); if (FixedEdgeFilterF(eid) || FixedEdgeFilterF(eid2)) { continue; } Index2i ev = Graph.GetEdgeV(eid); int other_v = (ev.a == vid) ? ev.b : ev.a; DGraph2.EdgeCollapseInfo collapseInfo; MeshResult result = Graph.CollapseEdge(other_v, vid, out collapseInfo); if (result == MeshResult.Ok) { done = false; } else { throw new Exception("DGraph2Resampler.CollapseFlatVertices: failed!"); } } while (cur_vid != 0); } }
/// <summary> /// Decompose graph into simple polylines and polygons. /// </summary> public static Curves ExtractCurves(DGraph2 graph) { Curves c = new Curves(); c.Loops = new List <Polygon2d>(); c.Paths = new List <PolyLine2d>(); HashSet <int> used = new HashSet <int>(); // find boundary and junction vertices HashSet <int> boundaries = new HashSet <int>(); HashSet <int> junctions = new HashSet <int>(); foreach (int vid in graph.VertexIndices()) { if (graph.IsBoundaryVertex(vid)) { boundaries.Add(vid); } if (graph.IsJunctionVertex(vid)) { junctions.Add(vid); } } // walk paths from boundary vertices foreach (int start_vid in boundaries) { int vid = start_vid; int eid = graph.GetVtxEdges(vid)[0]; if (used.Contains(eid)) { continue; } PolyLine2d path = new PolyLine2d(); path.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (boundaries.Contains(vid) || junctions.Contains(vid)) { break; // done! } } c.Paths.Add(path); } // ok we should be done w/ boundary verts now... boundaries.Clear(); foreach (int start_vid in junctions) { foreach (int outgoing_eid in graph.VtxEdgesItr(start_vid)) { if (used.Contains(outgoing_eid)) { continue; } int vid = start_vid; int eid = outgoing_eid; PolyLine2d path = new PolyLine2d(); path.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; path.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { break; // done! } } c.Paths.Add(path); } } // all that should be left are continuous loops... foreach (int start_eid in graph.EdgeIndices()) { if (used.Contains(start_eid)) { continue; } int eid = start_eid; Index2i ev = graph.GetEdgeV(eid); int vid = ev.a; Polygon2d poly = new Polygon2d(); poly.AppendVertex(graph.GetVertex(vid)); while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; poly.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { throw new Exception("how did this happen??"); } if (used.Contains(eid)) { break; } } poly.RemoveVertex(poly.VertexCount - 1); c.Loops.Add(poly); } return(c); }