Example #1
0
        /// <summary>
        /// Find and remove any junction (ie valence>2) vertices of the graph.
        /// At a junction, the pair of best-aligned (ie straightest) edges are left
        /// connected, and all the other edges are disconnected
        ///
        /// [TODO] currently there is no DGraph2.SetEdge(), so the 'other' edges
        /// are deleted and new edges inserted. Hence, edge IDs are not preserved.
        /// </summary>
        public static int DisconnectJunctions(DGraph2 graph)
        {
            var junctions = new List <int>();

            // find all junctions
            foreach (int vid in graph.VertexIndices())
            {
                if (graph.IsJunctionVertex(vid))
                {
                    junctions.Add(vid);
                }
            }


            foreach (int vid in junctions)
            {
                Vector2d v         = graph.GetVertex(vid);
                int[]    nbr_verts = graph.VtxVerticesItr(vid).ToArray();

                // find best-aligned pair of edges connected to vid
                Index2i best_aligned = Index2i.Max; double max_angle = 0;
                for (int i = 0; i < nbr_verts.Length; ++i)
                {
                    for (int j = i + 1; j < nbr_verts.Length; ++j)
                    {
                        double angle = Vector2d.AngleD(
                            (graph.GetVertex(nbr_verts[i]) - v).Normalized,
                            (graph.GetVertex(nbr_verts[j]) - v).Normalized);
                        angle = Math.Abs(angle);
                        if (angle > max_angle)
                        {
                            max_angle    = angle;
                            best_aligned = new Index2i(nbr_verts[i], nbr_verts[j]);
                        }
                    }
                }

                // for nbr verts that are not part of the best_aligned edges,
                // we remove those edges and add a new one connected to a new vertex
                for (int k = 0; k < nbr_verts.Length; ++k)
                {
                    if (nbr_verts[k] == best_aligned.a || nbr_verts[k] == best_aligned.b)
                    {
                        continue;
                    }

                    int eid = graph.FindEdge(vid, nbr_verts[k]);
                    graph.RemoveEdge(eid, true);
                    if (graph.IsVertex(nbr_verts[k]))
                    {
                        var newpos = Vector2d.Lerp(graph.GetVertex(nbr_verts[k]), v, 0.99);
                        int newv   = graph.AppendVertex(newpos);
                        graph.AppendEdge(nbr_verts[k], newv);
                    }
                }
            }

            return(junctions.Count);
        }
Example #2
0
        /// <summary>
        /// foreach edge [vid,b] connected to junction vertex vid, remove, add new vertex c,
        /// and then add new edge [b,c]. Optionally move c a bit back along edge from vid.
        /// </summary>
        public static void DisconnectJunction(DGraph2 graph, int vid, double shrinkFactor = 1.0)
        {
            Vector2d v = graph.GetVertex(vid);

            int[] nbr_verts = graph.VtxVerticesItr(vid).ToArray();
            for (int k = 0; k < nbr_verts.Length; ++k)
            {
                int eid = graph.FindEdge(vid, nbr_verts[k]);
                graph.RemoveEdge(eid, true);
                if (graph.IsVertex(nbr_verts[k]))
                {
                    Vector2d newpos = Vector2d.Lerp(graph.GetVertex(nbr_verts[k]), v, shrinkFactor);
                    int      newv   = graph.AppendVertex(newpos);
                    graph.AppendEdge(nbr_verts[k], newv);
                }
            }
        }
        /// <summary>
        /// insert edge [a,b] into the arrangement, splitting existing edges as necessary
        /// </summary>
        protected bool insert_segment(ref Vector2d a, ref Vector2d b, int gid = -1, double tol = 0)
        {
            // handle degenerate edges
            int a_idx = find_existing_vertex(a);
            int b_idx = find_existing_vertex(b);

            if (a_idx == b_idx && a_idx >= 0)
            {
                return(false);
            }

            // ok find all intersections
            List <Intersection> hits = new List <Intersection>();

            find_intersecting_edges(ref a, ref b, hits, tol);
            int N = hits.Count;

            // we are going to construct a list of <t,vertex_id> values along segment AB
            List <SegmentPoint> points = new List <SegmentPoint>();
            Segment2d           segAB  = new Segment2d(a, b);

            // insert intersections into existing segments
            for (int i = 0; i < N; ++i)
            {
                Intersection intr = hits[i];
                int          eid = intr.eid;
                double       t0 = intr.intr.Parameter0, t1 = intr.intr.Parameter1;

                // insert first point at t0
                int new_eid = -1;
                if (intr.intr.Type == IntersectionType.Point || intr.intr.Type == IntersectionType.Segment)
                {
                    Index2i new_info = split_segment_at_t(eid, t0, VertexSnapTol);
                    new_eid = new_info.b;
                    Vector2d v = Graph.GetVertex(new_info.a);
                    points.Add(new SegmentPoint()
                    {
                        t = segAB.Project(v), vid = new_info.a
                    });
                }

                // if intersection was on-segment, then we have a second point at t1
                if (intr.intr.Type == IntersectionType.Segment)
                {
                    if (new_eid == -1)
                    {
                        // did not actually split edge for t0, so we can still use eid
                        Index2i  new_info = split_segment_at_t(eid, t1, VertexSnapTol);
                        Vector2d v        = Graph.GetVertex(new_info.a);
                        points.Add(new SegmentPoint()
                        {
                            t = segAB.Project(v), vid = new_info.a
                        });
                    }
                    else
                    {
                        // find t1 was in eid, rebuild in new_eid
                        Segment2d new_seg = Graph.GetEdgeSegment(new_eid);
                        Vector2d  p1      = intr.intr.Segment1.PointAt(t1);
                        double    new_t1  = new_seg.Project(p1);
                        Util.gDevAssert(new_t1 <= Math.Abs(new_seg.Extent));

                        Index2i  new_info = split_segment_at_t(new_eid, new_t1, VertexSnapTol);
                        Vector2d v        = Graph.GetVertex(new_info.a);
                        points.Add(new SegmentPoint()
                        {
                            t = segAB.Project(v), vid = new_info.a
                        });
                    }
                }
            }

            // find or create start and end points
            if (a_idx == -1)
            {
                a_idx = find_existing_vertex(a);
            }
            if (a_idx == -1)
            {
                a_idx = Graph.AppendVertex(a);
                PointHash.InsertPointUnsafe(a_idx, a);
            }
            if (b_idx == -1)
            {
                b_idx = find_existing_vertex(b);
            }
            if (b_idx == -1)
            {
                b_idx = Graph.AppendVertex(b);
                PointHash.InsertPointUnsafe(b_idx, b);
            }

            // add start/end to points list. These may be duplicates but we will sort that out after
            points.Add(new SegmentPoint()
            {
                t = segAB.Project(a), vid = a_idx
            });
            points.Add(new SegmentPoint()
            {
                t = segAB.Project(b), vid = b_idx
            });
            // sort by t
            points.Sort((pa, pb) => { return((pa.t < pb.t) ? -1 : ((pa.t > pb.t) ? 1 : 0)); });

            // connect sequential points, as long as they aren't the same point,
            // and the segment doesn't already exist
            for (int k = 0; k < points.Count - 1; ++k)
            {
                int v0 = points[k].vid;
                int v1 = points[k + 1].vid;
                if (v0 == v1)
                {
                    continue;
                }
                if (Math.Abs(points[k].t - points[k + 1].t) < MathUtil.Epsilonf)
                {
                    System.Console.WriteLine("insert_segment: different points with same t??");
                }

                if (Graph.FindEdge(v0, v1) == DGraph2.InvalidID)
                {
                    Graph.AppendEdge(v0, v1, gid);
                }
            }

            return(true);
        }
        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);
                }
            }
        }