/// <summary> /// insert new point into segment eid at parameter value t /// If t is within tol of endpoint of segment, we use that instead. /// </summary> protected Index2i split_segment_at_t(int eid, double t, double tol) { Index2i ev = Graph.GetEdgeV(eid); Segment2d seg = new Segment2d(Graph.GetVertex(ev.a), Graph.GetVertex(ev.b)); int use_vid = -1; int new_eid = -1; if (t < -(seg.Extent - tol)) { use_vid = ev.a; } else if (t > (seg.Extent - tol)) { use_vid = ev.b; } else { DGraph2.EdgeSplitInfo splitInfo; MeshResult result = Graph.SplitEdge(eid, out splitInfo); if (result != MeshResult.Ok) { throw new Exception("insert_into_segment: edge split failed?"); } use_vid = splitInfo.vNew; new_eid = splitInfo.eNewBN; Vector2d pt = seg.PointAt(t); Graph.SetVertex(use_vid, pt); PointHash.InsertPointUnsafe(splitInfo.vNew, pt); } return(new Index2i(use_vid, new_eid)); }
public void SplitToMaxEdgeLength(double fMaxLen) { var queue = new List <int>(); int NE = Graph.MaxEdgeID; for (int eid = 0; eid < NE; ++eid) { if (!Graph.IsEdge(eid)) { continue; } if (FixedEdgeFilterF(eid)) { continue; } Index2i ev = Graph.GetEdgeV(eid); double dist = Graph.GetVertex(ev.a).Distance(Graph.GetVertex(ev.b)); if (dist > fMaxLen) { DGraph2.EdgeSplitInfo splitInfo; if (Graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok && dist > 2 * fMaxLen) { queue.Add(eid); queue.Add(splitInfo.eNewBN); } } } while (queue.Count > 0) { int eid = queue[queue.Count - 1]; queue.RemoveAt(queue.Count - 1); if (!Graph.IsEdge(eid)) { continue; } Index2i ev = Graph.GetEdgeV(eid); double dist = Graph.GetVertex(ev.a).Distance(Graph.GetVertex(ev.b)); if (dist > fMaxLen) { DGraph2.EdgeSplitInfo splitInfo; if (Graph.SplitEdge(eid, out splitInfo) == MeshResult.Ok && dist > 2 * fMaxLen) { queue.Add(eid); queue.Add(splitInfo.eNewBN); } } } }
public static bool FindRayIntersection(Vector2d o, Vector2d d, out int hit_eid, out double hit_ray_t, DGraph2 graph) { Line2d line = new Line2d(o, d); Vector2d a = Vector2d.Zero, b = Vector2d.Zero; int near_eid = DGraph2.InvalidID; double near_t = double.MaxValue; IntrLine2Segment2 intr = new IntrLine2Segment2(line, new Segment2d(a, b)); foreach (int eid in graph.VertexIndices()) { graph.GetEdgeV(eid, ref a, ref b); intr.Segment = new Segment2d(a, b); if (intr.Find() && intr.IsSimpleIntersection && intr.Parameter > 0) { if (intr.Parameter < near_t) { near_eid = eid; near_t = intr.Parameter; } } } hit_eid = near_eid; hit_ray_t = near_t; return(hit_ray_t < double.MaxValue); }
/// <summary> /// If we are at edge eid, which as one vertex prev_vid, find 'other' vertex, and other edge connected to that vertex, /// and return pair [next_edge, shared_vtx] /// Returns [int.MaxValue, shared_vtx] if shared_vtx is not valence=2 (ie stops at boundaries and complex junctions) /// </summary> public static Index2i NextEdgeAndVtx(int eid, int prev_vid, DGraph2 graph) { Index2i ev = graph.GetEdgeV(eid); if (ev.a == DGraph2.InvalidID) { return(Index2i.Max); } int next_vid = (ev.a == prev_vid) ? ev.b : ev.a; if (graph.GetVtxEdgeCount(next_vid) != 2) { return(new Index2i(int.MaxValue, next_vid)); } foreach (int next_eid in graph.VtxEdgesItr(next_vid)) { if (next_eid != eid) { return(new Index2i(next_eid, next_vid)); } } return(Index2i.Max); }
public void AppendGraph(DGraph2 graph, int gid = -1) { int[] mapV = new int[graph.MaxVertexID]; foreach (int vid in graph.VertexIndices()) { mapV[vid] = this.AppendVertex(graph.GetVertex(vid)); } foreach (int eid in graph.EdgeIndices()) { Index2i ev = graph.GetEdgeV(eid); int use_gid = (gid == -1) ? graph.GetEdgeGroup(eid) : gid; this.AppendEdge(mapV[ev.a], mapV[ev.b], use_gid); } }
public void FindCells() { // First we construct "wedges", which are pairs of sequential edges around each vtx. // we then put all in a hash set, we will iterate until we use up all the available wedges. // Edges are sorted by positive angle, so they are in clockwise order // Hence, going from edge n to n+1 is a left-turn, and so "inside" cells are oriented clockwise int NV = Graph.MaxVertexID; var wedges = new Index2i[NV][]; var remaining = new HashSet <Index2i>(); foreach (int vid in Graph.VertexIndices()) { int[] sorted = Graph.SortedVtxEdges(vid); wedges[vid] = new Index2i[sorted.Length]; for (int k = 0; k < sorted.Length; ++k) { wedges[vid][k] = new Index2i(sorted[k], sorted[(k + 1) % sorted.Length]); remaining.Add(new Index2i(vid, k)); } } CellLoops = new List <int[]>(); var loopv = new List <int>(); while (remaining.Count > 0) { Index2i idx = remaining.First(); remaining.Remove(idx); int start_vid = idx.a; int wid = idx.b; int e0 = wedges[start_vid][wid].a; e0 = e0 + 1 - 1; // get rid of unused variable warning, want to keep this for debugging int e1 = wedges[start_vid][wid].b; loopv.Clear(); loopv.Add(start_vid); int cur_v = start_vid; int outgoing_e = e1; // walk around loop taking immediate left-turns bool done = false; while (!done) { // find outgoing edge and vtx at far end Index2i ev = Graph.GetEdgeV(outgoing_e); int next_v = (ev.a == cur_v) ? ev.b : ev.a; if (next_v == start_vid) { done = true; continue; } // now find wedge at that vtx where this is incoming edge Index2i[] next_wedges = wedges[next_v]; int use_wedge_idx = -1; for (int k = 0; k < next_wedges.Length; ++k) { if (next_wedges[k].a == outgoing_e) { use_wedge_idx = k; break; } } if (use_wedge_idx == -1) { throw new Exception("could not find next wedge?"); } remaining.Remove(new Index2i(next_v, use_wedge_idx)); loopv.Add(next_v); cur_v = next_v; outgoing_e = next_wedges[use_wedge_idx].b; } CellLoops.Add(loopv.ToArray()); } }
/// <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); }
protected virtual void do_split(Line2d line, bool insert_edges, int insert_gid) { if (EdgeSigns.Length < Graph.MaxVertexID) { EdgeSigns.resize(Graph.MaxVertexID); } foreach (int vid in Graph.VertexIndices()) { EdgeSigns[vid] = line.WhichSide(Graph.GetVertex(vid), OnVertexTol); } hits.Clear(); foreach (int eid in Graph.EdgeIndices()) { Index2i ev = Graph.GetEdgeV(eid); var signs = new Index2i(EdgeSigns[ev.a], EdgeSigns[ev.b]); if (signs.a * signs.b > 0) { continue; // both positive or negative, ignore } var hit = new edge_hit() { hit_eid = eid, vtx_signs = signs, hit_vid = -1 }; Vector2d a = Graph.GetVertex(ev.a); Vector2d b = Graph.GetVertex(ev.b); // parallel-edge case (both are zero) if (signs.a == signs.b) { if (a.DistanceSquared(b) > MathUtil.Epsilon) { // we need to somehow not insert a new segment for this span below. // so, insert two hit points for the ray-interval, with same eid. // This will result in this span being skipped by the same-eid test below // *however*, if other edges self-intersect w/ this segment, this will *not work* // and duplicate edges will be inserted hit.hit_vid = ev.a; hit.line_t = line.Project(a); hits.Add(hit); hit.hit_vid = ev.b; hit.line_t = line.Project(b); hits.Add(hit); } else { // degenerate edge - fall through to a == 0 case below signs.b = 1; } } if (signs.a == 0) { hit.hit_pos = a; hit.hit_vid = ev.a; hit.line_t = line.Project(a); } else if (signs.b == 0) { hit.hit_pos = b; hit.hit_vid = ev.b; hit.line_t = line.Project(b); } else { var intr = new IntrLine2Segment2(line, new Segment2d(a, b)); if (intr.Find() == false) { throw new Exception("GraphSplitter2d.Split: signs are different but ray did not it?"); } if (intr.IsSimpleIntersection) { hit.hit_pos = intr.Point; hit.line_t = intr.Parameter; } else { throw new Exception("GraphSplitter2d.Split: got parallel edge case!"); } } hits.Add(hit); } // sort by increasing ray-t hits.Sort((hit0, hit1) => { return(hit0.line_t.CompareTo(hit1.line_t)); }); // insert segments between successive intersection points int N = hits.Count; for (int i = 0; i < N - 1; ++i) { int j = i + 1; // note: skipping parallel segments depends on this eid == eid test (see above) if (hits[i].line_t == hits[j].line_t || hits[i].hit_eid == hits[j].hit_eid) { continue; } int vi = hits[i].hit_vid; int vj = hits[j].hit_vid; if (vi == vj && vi >= 0) { continue; } if (vi >= 0 && vj >= 0) { int existing = Graph.FindEdge(vi, vj); if (existing >= 0) { continue; } } if (vi == -1) { DGraph2.EdgeSplitInfo split; var result = Graph.SplitEdge(hits[i].hit_eid, out split); if (result != MeshResult.Ok) { throw new Exception("GraphSplitter2d.Split: first edge split failed!"); } vi = split.vNew; Graph.SetVertex(vi, hits[i].hit_pos); edge_hit tmp = hits[i]; tmp.hit_vid = vi; hits[i] = tmp; } if (vj == -1) { DGraph2.EdgeSplitInfo split; var result = Graph.SplitEdge(hits[j].hit_eid, out split); if (result != MeshResult.Ok) { throw new Exception("GraphSplitter2d.Split: second edge split failed!"); } vj = split.vNew; Graph.SetVertex(vj, hits[j].hit_pos); edge_hit tmp = hits[j]; tmp.hit_vid = vj; hits[j] = tmp; } // check if we actually want to add this segment if (InsideTestF != null) { Vector2d midpoint = 0.5 * (Graph.GetVertex(vi) + Graph.GetVertex(vj)); if (InsideTestF(midpoint) == false) { continue; } } if (insert_edges) { Graph.AppendEdge(vi, vj, insert_gid); } } }