/// <summary> /// Decompose graph into simple polylines and polygons. /// </summary> public static CurveCollection ExtractCurves(DGraph2 graph) { CurveCollection c = new CurveCollection(); 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)); bool is_loop = false; while (true) { used.Add(eid); Index2i next = NextEdgeAndVtx(eid, vid, graph); eid = next.a; vid = next.b; if (vid == start_vid) { is_loop = true; break; } path.AppendVertex(graph.GetVertex(vid)); if (eid == int.MaxValue || junctions.Contains(vid)) { break; } } if (is_loop) { c.Loops.Add(new Polygon2d(path.Vertices)); } else { 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); }
public void Add(CurveCollection other) { Loops.AddRange(other.Loops); Paths.AddRange(other.Paths); }
public static void ChainOpenPaths(CurveCollection c, double epsilon = MathUtil.Epsilon) { List <PolyLine2d> to_process = new List <PolyLine2d>(c.Paths); c.Paths.Clear(); // first we separate out 'dangling' curves that have no match on at least one side List <PolyLine2d> dangling = new List <PolyLine2d>(); List <PolyLine2d> remaining = new List <PolyLine2d>(); bool bContinue = true; while (bContinue && to_process.Count > 0) { bContinue = false; foreach (PolyLine2d p in to_process) { var matches_start = find_connected_start(p, to_process, epsilon); var matches_end = find_connected_end(p, to_process, epsilon); if (matches_start.Count == 0 || matches_end.Count == 0) { dangling.Add(p); bContinue = true; } else { remaining.Add(p); } } to_process.Clear(); to_process.AddRange(remaining); remaining.Clear(); } //to_process.Clear(); to_process.AddRange(remaining); remaining.Clear(); // now incrementally merge together unique matches // [TODO] this will not match across junctions! bContinue = true; while (bContinue && to_process.Count > 0) { bContinue = false; restart_itr: foreach (PolyLine2d p in to_process) { var matches_start = find_connected_start(p, to_process, epsilon); var matches_end = find_connected_end(p, to_process, 2 * epsilon); if (matches_start.Count == 1 && matches_end.Count == 1 && matches_start[0] == matches_end[0]) { c.Loops.Add(to_loop(p, matches_start[0], epsilon)); to_process.Remove(p); to_process.Remove(matches_start[0]); remaining.Remove(matches_start[0]); bContinue = true; goto restart_itr; } else if (matches_start.Count == 1 && matches_end.Count < 2) { remaining.Add(merge_paths(matches_start[0], p, 2 * epsilon)); to_process.Remove(p); to_process.Remove(matches_start[0]); remaining.Remove(matches_start[0]); bContinue = true; goto restart_itr; } else if (matches_end.Count == 1 && matches_start.Count < 2) { remaining.Add(merge_paths(p, matches_end[0], 2 * epsilon)); to_process.Remove(p); to_process.Remove(matches_end[0]); remaining.Remove(matches_end[0]); bContinue = true; goto restart_itr; } else { remaining.Add(p); } } to_process.Clear(); to_process.AddRange(remaining); remaining.Clear(); } c.Paths.AddRange(to_process); // [TODO] now that we have found all loops, we can chain in dangling curves c.Paths.AddRange(dangling); }