/// <summary>
        /// A basic strategy for finding split points when nothing extra is known about the geometry of
        /// the situation.
        /// </summary>
        /// <param name="seg">the encroached segment</param>
        /// <param name="encroachPt">the encroaching point</param>
        /// <returns>the point at which to split the encroached segment</returns>
        public Coordinate FindSplitPoint(Segment seg, Coordinate encroachPt)
        {
            var lineSeg = seg.LineSegment;
            var segLen = lineSeg.Length;
            var midPtLen = segLen / 2;
            var splitSeg = new SplitSegment(lineSeg);

            var projPt = ProjectedSplitPoint(seg, encroachPt);
            /*
             * Compute the largest diameter (length) that will produce a split segment which is not
             * still encroached upon by the encroaching point (The length is reduced slightly by a
             * safety factor)
             */
            var nonEncroachDiam = projPt.Distance(encroachPt) * 2 * 0.8; // .99;
            var maxSplitLen = nonEncroachDiam;
            if (maxSplitLen > midPtLen) {
                maxSplitLen = midPtLen;
            }
            splitSeg.MinimumLength = maxSplitLen;

            splitSeg.SplitAt(projPt);

            return splitSeg.SplitPoint;
        }
        //    public static final String DEBUG_SEG_SPLIT = "C:\\proj\\CWB\\test\\segSplit.jml";
        /// <summary>
        /// Given a set of points stored in the kd-tree and a line segment defined by
        /// two points in this set, finds a <see cref="Coordinate"/> in the circumcircle of
        /// the line segment, if one exists. This is called the Gabriel point - if none
        /// exists then the segment is said to have the Gabriel condition. Uses the
        /// heuristic of finding the non-Gabriel point closest to the midpoint of the
        /// segment.
        /// </summary>
        /// <param name="seg">the line segment</param>
        /// <returns>
        /// A point which is non-Gabriel,
        /// or null if no point is non-Gabriel
        /// </returns>
        private Coordinate FindNonGabrielPoint(Segment seg)
        {
            Coordinate p = seg.Start;
            Coordinate q = seg.End;
            // Find the mid point on the line and compute the radius of enclosing circle
            Coordinate midPt = new Coordinate((p.X + q.X) / 2.0, (p.Y + q.Y) / 2.0);
            double segRadius = p.Distance(midPt);

            // compute envelope of circumcircle
            Envelope env = new Envelope(midPt);
            env.ExpandBy(segRadius);
            // Find all points in envelope
            ICollection<KdNode<Vertex>> result = _kdt.Query(env);

            // For each point found, test if it falls strictly in the circle
            // find closest point
            Coordinate closestNonGabriel = null;
            double minDist = Double.MaxValue;
            foreach (KdNode<Vertex> nextNode in result)
            {
                Coordinate testPt = nextNode.Coordinate;
                // ignore segment endpoints
                if (testPt.Equals2D(p) || testPt.Equals2D(q))
                    continue;

                double testRadius = midPt.Distance(testPt);
                if (testRadius < segRadius)
                {
                    // double testDist = seg.distance(testPt);
                    double testDist = testRadius;
                    if (closestNonGabriel == null || testDist < minDist)
                    {
                        closestNonGabriel = testPt;
                        minDist = testDist;
                    }
                }
            }
            return closestNonGabriel;
        }
        /*
         * private List findMissingConstraints() { List missingSegs = new ArrayList();
         * for (int i = 0; i < segments.size(); i++) { Segment s = (Segment)
         * segments.get(i); QuadEdge q = subdiv.locate(s.getStart(), s.getEnd()); if
         * (q == null) missingSegs.add(s); } return missingSegs; }
         */
        private int EnforceGabriel(ICollection<Segment> segsToInsert)
        {
            List<Segment> newSegments = new List<Segment>();
            int splits = 0;
            List<Segment> segsToRemove = new List<Segment>();

            /*
             * On each iteration must always scan all constraint (sub)segments, since
             * some constraints may be rebroken by Delaunay triangle flipping caused by
             * insertion of another constraint. However, this process must converge
             * eventually, with no splits remaining to find.
             */
            foreach (Segment seg in segsToInsert)
            {
                // System.out.println(seg);

                Coordinate encroachPt = FindNonGabrielPoint(seg);
                // no encroachment found - segment must already be in subdivision
                if (encroachPt == null)
                    continue;

                // compute split point
                _splitPt = _splitFinder.FindSplitPoint(seg, encroachPt);
                ConstraintVertex splitVertex = CreateVertex(_splitPt, seg);

                /*
                 * Check whether the inserted point still equals the split pt. This will
                 * not be the case if the split pt was too close to an existing site. If
                 * the point was snapped, the triangulation will not respect the inserted
                 * constraint - this is a failure. This can be caused by:
                 * <ul>
                 * <li>An initial site that lies very close to a constraint segment The
                 * cure for this is to remove any initial sites which are close to
                 * constraint segments in a preprocessing phase.
                 * <li>A narrow constraint angle which causing repeated splitting until
                 * the split segments are too small. The cure for this is to either choose
                 * better split points or "guard" narrow angles by cracking the segments
                 * equidistant from the corner.
                 * </ul>
                 */
                ConstraintVertex insertedVertex = InsertSite(splitVertex);
                //Debugging FObermaier
                //Console.WriteLine("inserted vertex: " + insertedVertex.ToString());

                if (!insertedVertex.Coordinate.Equals2D(_splitPt))
                {
                    Debug.WriteLine("Split pt snapped to: " + insertedVertex);
                    // throw new ConstraintEnforcementException("Split point snapped to
                    // existing point
                    // (tolerance too large or constraint interior narrow angle?)",
                    // splitPt);
                }

                // split segment and record the new halves
                Segment s1 = new Segment(seg.StartX, seg.StartY, seg.StartZ,
                                     splitVertex.X, splitVertex.Y, splitVertex.Z,
                                     seg.Data);
                Segment s2 = new Segment(splitVertex.X, splitVertex.Y, splitVertex.Z,
                                     seg.EndX, seg.EndY, seg.EndZ,
                                     seg.Data);

                //Debugging FObermaier
                //Console.WriteLine("Segment " + seg.ToString() + " splitted to \n\t" + s1.ToString() + "\n\t"+ s2.ToString());
                newSegments.Add(s1);
                newSegments.Add(s2);
                segsToRemove.Add(seg);

                splits = splits + 1;
            }
            foreach (Segment seg in segsToRemove)
            {
                segsToInsert.Remove(seg);
            }

            foreach (Segment seg in newSegments)
            {
                segsToInsert.Add(seg);
            }

            return splits;
        }
 /// <summary>
 /// Creates a vertex on a constraint segment
 /// </summary>
 /// <param name="p">the location of the vertex to create</param>
 /// <param name="seg">the constraint segment it lies on</param>
 /// <returns>the new constraint vertex</returns>
 private ConstraintVertex CreateVertex(Coordinate p, Segment seg)
 {
     ConstraintVertex v;
     if (_vertexFactory != null)
         v = _vertexFactory.CreateVertex(p, seg);
     else
         v = new ConstraintVertex(p);
     v.IsOnConstraint = true;
     return v;
 }
Example #5
0
 /// <summary>
 /// Computes the intersection point between this segment and another one.
 /// </summary>
 /// <param name="s">a segment</param>
 /// <returns>the intersection point, or <code>null</code> if there is none</returns>
 public Coordinate Intersection(Segment s)
 {
     return _ls.Intersection(s.LineSegment);
 }
Example #6
0
 /// <summary>
 /// Determines whether two segments are topologically equal.
 /// I.e. equal up to orientation.
 /// </summary>
 /// <param name="s">a segment</param>
 /// <returns>true if the segments are topologically equal</returns>
 public bool EqualsTopologically(Segment s)
 {
     return _ls.EqualsTopologically(s.LineSegment);
 }
 /// <summary>
 /// Computes a split point which is the projection of the encroaching point on the segment
 /// </summary>
 /// <param name="seg">The segment</param>
 /// <param name="encroachPt">The enchroaching point</param>
 /// <returns>A split point on the segment</returns>
 public static Coordinate ProjectedSplitPoint(Segment seg, Coordinate encroachPt)
 {
     LineSegment lineSeg = seg.LineSegment;
     Coordinate projPt = lineSeg.Project(encroachPt);
     return projPt;
 }
 /// <summary>
 /// Gets the midpoint of the split segment
 /// </summary>
 public Coordinate FindSplitPoint(Segment seg, Coordinate encroachPt)
 {
     Coordinate p0 = seg.Start;
     Coordinate p1 = seg.End;
     return new Coordinate((p0.X + p1.X) / 2, (p0.Y + p1.Y) / 2);
 }