コード例 #1
0
        public List <Segment2d> TrimSegment2d(Segment2d seg)
        {
            // Find points where the outer boundary and holes intersect the segment.
            var intersectionPoints = new List <Vector2d>();

            intersectionPoints.AddRange(outer.FindIntersections(seg));
            foreach (var hole in holes)
            {
                intersectionPoints.AddRange(hole.FindIntersections(seg));
            }

            // Handle the case where segment is fully contained
            if (intersectionPoints.Count == 0)
            {
                if (Contains(seg))
                {
                    return new List <Segment2d>()
                           {
                               new Segment2d(seg)
                           }
                }
            }
            ;

            // Add segment start & end points in case they lay within the polygon
            intersectionPoints.Add(seg.P0);
            intersectionPoints.Add(seg.P1);

            // Sort the points by their distance along the segment.
            var intersections = new List <Tuple <double, Vector2d> >();
            var line          = new Line2d(seg.Center, seg.Direction);

            foreach (var point in intersectionPoints)
            {
                intersections.Add(Tuple.Create(line.Project(point), point));
            }
            intersections.Sort((a, b) => a.Item1.CompareTo(b.Item1));

            // Add any segment with non-zero length that is contained in the polygon
            var containedSegments = new List <Segment2d>();

            for (int i = 1; i < intersections.Count; ++i)
            {
                var potentialSegment = new Segment2d(intersections[i - 1].Item2, intersections[i].Item2);

                if (potentialSegment.Length <= MathUtil.Epsilon)
                {
                    continue;
                }

                if (Contains(potentialSegment.Center))
                {
                    containedSegments.Add(potentialSegment);
                }
            }
            return(containedSegments);
        }
コード例 #2
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);
                }
            }
        }