示例#1
0
        /// <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);
                    }
                }
            }
        }
示例#3
0
        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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
 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);
     }
 }
示例#6
0
        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());
            }
        }
示例#7
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);
        }
示例#8
0
        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);
                }
            }
        }