Exemplo n.º 1
0
        /// <summary>
        /// Confirms that a potential link is valid. For a link to be valid, the
        /// midpoint of the link must fall inside the specified polygon, and the
        /// line connecting the 2 points cannot intersect anything.
        /// </summary>
        /// <param name="other">The end of the proposed point to link to.</param>
        /// <param name="pol">The polygon the link must fall completely inside.</param>
        /// <returns>True if link is valid.</returns>
        internal bool IsLinkValid(PolygonLink other, Polygon pol)
        {
            // 22-MAR-00 There may be no point at a corner.
            if (m_Point == null || other.Point == null)
            {
                return(false);
            }

            // Get the midpoint of the link.
            IPosition mid = Geom.MidPoint(m_Point, other.Point);

            // Confirm the midpoint falls inside the right polygon.
            if (!pol.IsRingEnclosing(mid))
            {
                return(false);
            }

            // Locate any intersections formed by the proposed link (considering
            // only the currently active theme).
            LineGeometry       seg   = new SegmentGeometry(m_Point, other.m_Point);
            IntersectionFinder xsect = new IntersectionFinder(seg, true);

            // The proposed link is not valid if it intersects anything
            // along the length of the segment, or has any grazes.
            if (xsect.IsGrazing || xsect.IsSplitNeeded)
            {
                return(false);
            }

            return(true);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Returns the angle between the ideal bearing for this link, and the
        /// position of another link point. The caller can test the angle against
        /// an angular tolerance to see if a link is suitable.
        ///
        /// Note that this function only makes a one-way test, making use only of
        /// the POSITION of the other link point. The caller may also want to do the
        /// reverse test as well, to see if the link is within tolerance from the
        /// perspective of both link points.
        /// </summary>
        /// <param name="other">The other link point.</param>
        /// <returns>The angle between this link point's reference bearing, and a
        /// line radiating to the other link point. The angle will always be less
        /// (or equal to) PI radians.</returns>
        internal double GetAngle(PolygonLink other)
        {
            // 22-MAR-00 There may be no point at a corner.
            if (m_Point == null || other.Point == null)
            {
                return(Constants.PIDIV2);
            }

            // Treat the direction to the other link point as the reference direction.
            Turn reference = new Turn(this.Point, other.Point);

            // Get the clockwise angle formed by the reference direction and the
            // ideal bearing for this link point.
            double angle = reference.GetAngleInRadians(m_Bearing);

            // Force the angle to be less than 180 degrees.
            if (angle > Constants.PI)
            {
                angle = Constants.PIMUL2 - angle;
                if (angle < Constants.TINY)
                {
                    angle = 0.0;
                }
            }

            return(angle);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Returns the distance (squared) between 2 link points.
        /// </summary>
        /// <param name="other">The other link to get the distance to.</param>
        /// <returns></returns>
        internal double DistanceSquared(PolygonLink other)
        {
            // 22-MAR-00 There may be no point at a corner.

            if (m_Point == null || other.Point == null)
            {
                return(0.0);
            }
            else
            {
                return(Geom.DistanceSquared(m_Point, other.Point));
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Assigns initial values to everything
 /// </summary>
 void ResetContent()
 {
     m_Point        = null;
     m_Link         = null;
     m_SideNumber   = 0;
     m_Angle        = 0.0;
     m_Bearing      = 0.0;
     m_IsCurveEnd   = false;
     m_IsEnd        = false;
     m_IsRadial     = false;
     m_LinkAngle    = Constants.PIMUL2;
     m_NumIntersect = 0;
 }
Exemplo n.º 5
0
        /// <summary>
        /// Checks whether this link object intersects another one.
        /// </summary>
        /// <param name="other">The other link to check.</param>
        /// <returns>
        /// True if there is an intersection. False if:
        ///
        /// 1. The other link is THIS link.
        /// 2. This link is the end of a link.
        /// 3. This link has no link.
        /// 4. The other link is the end of any link.
        /// 5. The other link is not linked.
        /// 6. There is no intersection.
        /// </returns>
        internal bool IsIntersected(PolygonLink other)
        {
            // The other object can't be THIS object.
            if (Object.ReferenceEquals(other, this))
            {
                return(false);
            }

            // The other can't be linked to this.
            if (Object.ReferenceEquals(other, m_Link))
            {
                return(false);
            }

            // Both objects must be linked.
            if (m_Link == null || other.Link == null)
            {
                return(false);
            }

            // It must be the START of both links.
            if (m_IsEnd || other.IsEnd)
            {
                return(false);
            }

            // Get the position of this link.
            double xk = m_Point.X;
            double yk = m_Point.Y;
            double xl = m_Link.Point.X;
            double yl = m_Link.Point.Y;

            // Get the position of the other link.
            double xm = other.Point.X;
            double ym = other.Point.Y;
            double xn = other.Link.Point.X;
            double yn = other.Link.Point.Y;

            // Return if there is any intersection along the length of the test segments.
            double xi, yi;

            return(Geom.CalcIntersect(xk, yk, xl, yl,
                                      xm, ym, xn, yn,
                                      out xi, out yi, true) != 0);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Refers this object to another one. Once done, the <c>Link</c> function will
        /// return the link when called for THIS object (but not the other object).
        /// </summary>
        /// <param name="link">The object to link to. Must not point to this object. Note that
        /// if the object to link to already has a link, that link will be severed; you can
        /// only link to ONE other object.</param>
        /// <param name="thisdiff">The value to assign to <c>this.LinkAngle</c></param>
        /// <param name="othrdiff">The value to assign to <c>link.LinkAngle</c></param>
        internal void SetLink(PolygonLink link, double thisdiff, double othrdiff)
        {
            // CAN'T point to itself.
            if (Object.ReferenceEquals(link, this))
            {
                throw new ArgumentException("PolygonLink.SetLink: Attempt to form null connection");
            }

            // The link shouldn't have been made already.
            if (link != null && (Object.ReferenceEquals(m_Link, link) || Object.ReferenceEquals(link.Link, this)))
            {
                throw new ArgumentException("PolygonLink.SetLink: Attempt to re-form link");
            }

            // If this object already has a link, update the object that pointed back.
            if (m_Link != null)
            {
                m_Link.Link      = null;
                m_Link.IsEnd     = false;
                m_Link.LinkAngle = Constants.PIMUL2;
            }

            // If the object we are linking to has a link, break it too.
            if (link != null && link.Link != null)
            {
                link.SetLink(null);
            }

            // Define the link.
            m_Link      = link;
            m_IsEnd     = false;
            m_LinkAngle = thisdiff;

            // If the link is real, point the other object back, marking it as a back pointer.

            if (link != null)
            {
                link.Link      = this;
                link.IsEnd     = true;
                link.LinkAngle = othrdiff;
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Sets the number of intersections for one of the polygon link points.
        /// </summary>
        /// <param name="index">The array index of the link point to process.</param>
        /// <returns>The number of intersections assigned.</returns>
        uint SetIntersectionCount(uint index)
        {
            // No intersections so far
            uint nx = 0;

            //	Point to the thing we want to set the count for.
            PolygonLink link = m_Links[index];

            // Go through all link points searching for intersections.
            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (link.IsIntersected(m_Links[i]))
                {
                    nx++;
                }
            }

            // Set the intersect count.
            link.NumIntersect = nx;
            return(nx);
        }
Exemplo n.º 8
0
 internal void SetLink(PolygonLink link)
 {
     SetLink(link, Constants.PIMUL2, Constants.PIMUL2);
 }
Exemplo n.º 9
0
        /// <summary>
        /// Defines links for this face. A prior call to <c>SetLine</c> is required.
        /// </summary>
        /// <param name="prev">The preceding face (after it has been processed via a call to
        /// <c>SetLine</c>, Must refer to the same polygon as this face.</param>
        /// <returns>The links (the number of array elements will equal the value that came
        /// back from the <c>SetLine</c> call)</returns>
        internal PolygonLink[] CreateLinks(PolygonFace prev)
        {
            Debug.Assert(m_Polygon != null);
            Debug.Assert(m_Divider != null);
            Debug.Assert(prev.Divider != null);
            Debug.Assert(Object.ReferenceEquals(prev.Polygon, m_Polygon));

            // Try to obtain a point feature at the beginning of this face.
            ISpatialIndex index      = CadastralMapModel.Current.Index;
            PointFeature  beginPoint = new FindPointQuery(index, m_Begin).Result;

            // If the polygon to the left of the this face? (if so, curve-related
            // things may need to be reversed below)
            bool isPolLeft = (m_Divider.Left == m_Polygon);

            // Default geometric info we need to define
            bool   isCurveEnd = false;
            bool   isRadial   = false;
            double bearing    = 0.0;
            double angle      = 0.0;

            // Is the position at the beginning of this face the start
            // or end of a circular arc (points between 2 curves (on
            // compound curve) are NOT considered to be curve ends). Note
            // that the line could either be a CircularArc, or a topological
            // section based on a circular arc.

            ICircularArcGeometry prevArc = (prev.Divider.LineGeometry as ICircularArcGeometry);
            ICircularArcGeometry thisArc = (m_Divider.LineGeometry as ICircularArcGeometry);
            bool isPrevCurve             = (prevArc != null);
            bool isThisCurve             = (thisArc != null);

            isCurveEnd = (isPrevCurve != isThisCurve);

            // If we are dealing with a point between two curves try to
            // set the curve parameters and, if successful, we will treat
            // the point as a radial point.

            if (isPrevCurve && isThisCurve)
            {
                isRadial = true;

                // Get the curve parameters...

                IPosition prevcen = prevArc.Circle.Center;
                double    prevrad = prevArc.Circle.Radius;

                IPosition thiscen = thisArc.Circle.Center;
                double    thisrad = thisArc.Circle.Radius;

                // We only need to know the sense for one of the arcs
                bool iscw = thisArc.IsClockwise;

                // If the 2 curves do not have the same centre and radius,
                // see if they are really close (to the nearest centimeter
                // on the ground). In that case, use the average values for
                // the 2 curves. If they really are different curves, don't
                // treat this as a radial curve point -- treat it as a
                // curve end instead.

                IPosition centre = null;            // The centre to actually use

                if (!(prevcen == thiscen && Math.Abs(prevrad - thisrad) < Constants.TINY))
                {
                    double xc1 = prevcen.X;
                    double yc1 = prevcen.Y;
                    double xc2 = thiscen.X;
                    double yc2 = thiscen.Y;
                    double dxc = xc2 - xc1;
                    double dyc = yc2 - yc1;

                    if (Math.Abs(dxc) < 0.01 &&
                        Math.Abs(dyc) < 0.01 &&
                        Math.Abs(prevrad - thisrad) < 0.01)
                    {
                        // Close enough
                        centre = new Position(xc1 + dxc * 0.5, yc1 + dyc * 0.5);
                    }
                    else
                    {
                        isRadial   = false;
                        isCurveEnd = true;
                    }
                }
                else
                {
                    centre = prevcen;
                }

                // If the centre and radius were the same (or close enough),
                // define the radial bearing from the centre of the circle.
                // If the polygon is actually on the other side, reverse the
                // bearing so that it's directed INTO the polygon.

                if (isRadial)
                {
                    Debug.Assert(centre != null);
                    bearing = Geom.BearingInRadians(centre, m_Begin);
                    angle   = 0.0;
                    if (iscw != isPolLeft)
                    {
                        bearing += Constants.PI;
                    }
                }
            }

            // If we're not dealing with a radial curve (or we have curves that
            // don't appear to be radial)
            if (!isRadial)
            {
                // Get the clockwise angle from the last position of the
                // preceding face to the first position after the start
                // of this face. Since info is held in a clockwise cycle
                // around the polygon, this will always give us the exterior
                // angle.
                Turn reference = new Turn(m_Begin, prev.TailReference);
                angle = reference.GetAngleInRadians(this.HeadReference);

                // Define the bearing to use for projecting the point. It's
                // in the middle of the angle, but projected into the polygon.
                bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI;
            }

            // Initialize the link at the start of the face
            List <PolygonLink> links = new List <PolygonLink>();
            PolygonLink        link  = new PolygonLink(beginPoint, isCurveEnd, isRadial, bearing, angle);

            links.Add(link);

            // Initialize links for any extra points
            if (m_ExtraPoints != null)
            {
                // Intermediate points can never be curve ends
                isCurveEnd = false;

                // If the face is a curve, they're radial points
                isRadial = isThisCurve;

                // Note any curve info
                double    radius;
                IPosition centre = null;
                bool      iscw   = false;

                if (isRadial)
                {
                    Debug.Assert(m_Divider.Line.LineGeometry is ICircularArcGeometry);
                    ICircularArcGeometry arc = (m_Divider.Line.LineGeometry as ICircularArcGeometry);
                    centre = arc.Circle.Center;
                    radius = arc.Circle.Radius;
                    iscw   = arc.IsClockwise;
                    angle  = 0.0;
                }

                for (uint i = 0; i < m_ExtraPoints.Length; i++)
                {
                    //IPointGeometry loc = m_ExtraPoints[i].Geometry;
                    PointFeature loc = m_ExtraPoints[i];

                    // Figure out the orientation bearing for the point
                    if (isRadial)
                    {
                        Debug.Assert(centre != null);
                        bearing = Geom.BearingInRadians(centre, loc);
                        if (iscw != isPolLeft)
                        {
                            bearing += Constants.PI;
                        }
                    }
                    else
                    {
                        // Get the exterior clockwise angle

                        IPointGeometry back;
                        IPointGeometry fore;

                        if (i == 0)
                        {
                            back = m_Begin;
                        }
                        else
                        {
                            back = m_ExtraPoints[i - 1].Geometry;
                        }

                        if (i == (m_ExtraPoints.Length - 1))
                        {
                            fore = m_End;
                        }
                        else
                        {
                            fore = m_ExtraPoints[i + 1].Geometry;
                        }


                        Turn reference = new Turn(loc, back);
                        angle = reference.GetAngleInRadians(fore);

                        // Define the bearing to use for projecting the point. It's
                        // in the middle of the angle, but projected into the polygon.
                        bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI;
                    }

                    link = new PolygonLink(m_ExtraPoints[i], isCurveEnd, isRadial, bearing, angle);
                    links.Add(link);
                }
            }

            return(links.ToArray());
        }
Exemplo n.º 10
0
        /// <summary>
        /// Constructor (that does a lot of stuff)
        /// </summary>
        /// <param name="polygon">The polygon being subdivided.</param>
        internal PolygonSub(Polygon polygon)
        {
            m_Polygon = polygon;
            m_Faces   = null;
            m_Links   = null;

            // Get the boundaries defining the exterior edge of the polygon
            IDivider[] lines = polygon.Edge;
            if (lines == null || lines.Length == 0)
            {
                return;
            }

            // Allocate an array for holding info on each polygon face,
            // and associate each one with the divider that acts as the primary face.
            uint numLink = 0;

            m_Faces = new PolygonFace[lines.Length];
            for (int i = 0; i < lines.Length; i++)
            {
                m_Faces[i] = new PolygonFace();
                numLink   += m_Faces[i].SetDivider(m_Polygon, lines[i]);
            }

            // Create an array of link objects (one for each point)
            if (numLink == 0)
            {
                return;
            }

            m_Links = new PolygonLink[numLink];

            // Initialize the links for first face
            int nDone = 0;

            PolygonLink[] links = m_Faces[0].CreateLinks(m_Faces[m_Faces.Length - 1]);
            Array.Copy(links, m_Links, links.Length);
            nDone += links.Length;

            // Initialize links for each subsequent face
            for (int i = 1; i < m_Faces.Length; i++)
            {
                links = m_Faces[i].CreateLinks(m_Faces[i - 1]);
                for (int j = 0; j < links.Length; j++)
                {
                    m_Links[nDone + j] = links[j];
                }

                nDone += links.Length;
            }


            Debug.Assert(nDone == m_Links.Length);

            // Assign a side number to each link position

            uint nside = 0;               // No side number assigned so far.
            uint ncorn = 0;               // Number of corners

            for (int i = 0; i < m_Links.Length; i++)
            {
                // Skip if we are dealing with a corner.
                if (m_Links[i].IsCorner())
                {
                    ncorn++;
                    continue;
                }

                // Skip if the side number has already been assigned.
                if (m_Links[i].Side != 0)
                {
                    continue;
                }

                // Assign next side number.
                nside++;

                // Continue till we reach a corner, assigning intermediate
                // faces the same side number.
                for (int j = i; j < m_Links.Length; j++)
                {
                    if (m_Links[j].IsCorner())
                    {
                        break;
                    }
                    m_Links[j].Side = nside;
                }

                // If we just assigned a side number to the very first face,
                //  loop back from the end of the array.
                if (i == 0)
                {
                    for (int k = m_Links.Length - 1; k > 0; k--)
                    {
                        if (m_Links[k].IsCorner())
                        {
                            break;
                        }
                        m_Links[k].Side = nside;
                    }
                }
            }

            // Return if we only have one side (or less)
            // if ( nside<2 ) return;

            // Define the max angular difference (10 degrees, but in radians)
            double ANGTOL = (10.0 * Constants.DEGTORAD);

            // Process all the radial faces first.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (m_Links[i].IsRadial)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // For each point that is not a corner or a curve end, cycle
            // through all the subsequent points, looking for a point to
            // connect to. Don't try to do curve end points just yet.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (!m_Links[i].IsRadial && !m_Links[i].IsCurveEnd)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // Process any points at the end of curves.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (m_Links[i].IsCurveEnd)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // Eliminate self-intersections ...

            // Start by counting the number of intersections each link has.
            uint maxnx = 0;

            for (uint i = 0; i < m_Links.Length; i++)
            {
                uint nx = this.SetIntersectionCount(i);
                maxnx = Math.Max(maxnx, nx);
            }

            uint nloop = 0;               // Number of loops (just in case of infinite loop).

            while (maxnx > 0)
            {
                // Find a link with the max number of intersections.
                int rem = -1;
                for (int i = 0; i < m_Links.Length; i++)
                {
                    if (m_Links[i].NumIntersect == maxnx)
                    {
                        rem = i;
                        break;
                    }
                }

                // We SHOULD have found something.
                if (rem < 0)
                {
                    throw new Exception("PolygonSub: Unexpected intersection count");
                }

                // If the count was greater than one, just remove the link. Otherwise get the
                // thing that was intersected. If one is a radial or a curve end, & the other isn't,
                // drop the radial. Otherwise drop the one with the poorer link angle.

                if (maxnx > 1)
                {
                    m_Links[rem].SetLink(null);
                }
                else
                {
                    PolygonLink pLink1 = m_Links[rem];
                    PolygonLink pLink2 = null;
                    for (int i = 0; pLink2 != null && i < m_Links.Length; i++)
                    {
                        if (pLink1.IsIntersected(m_Links[i]))
                        {
                            pLink2 = m_Links[i];
                        }
                    }

                    if (pLink2 == null)
                    {
                        throw new Exception("PolygonSub: Intersection not found");
                    }

                    // Check if radial.
                    bool rad1 = pLink1.IsRadial || pLink1.Link.IsRadial;
                    bool rad2 = pLink2.IsRadial || pLink2.Link.IsRadial;

                    // Check if end of curves.
                    bool end1 = pLink1.IsCurveEnd || pLink1.Link.IsCurveEnd;
                    bool end2 = pLink2.IsCurveEnd || pLink2.Link.IsCurveEnd;

                    // We treat radials and end of curves the same.
                    bool curve1 = (rad1 || end1);
                    bool curve2 = (rad2 || end2);

                    // If one is a curve-related and the other isn't, drop
                    // the one that's curve-related.
                    if (curve1 != curve2)
                    {
                        if (curve1)
                        {
                            pLink1.SetLink(null);
                        }
                        else
                        {
                            pLink2.SetLink(null);
                        }
                    }
                    else
                    {
                        // Neither is curve related, or both are. Drop the
                        // one with the poorer link angle.

                        if (pLink1.LinkAngle > pLink2.LinkAngle)
                        {
                            pLink1.SetLink(null);
                        }
                        else
                        {
                            pLink2.SetLink(null);
                        }
                    }
                }

                // Rework the intersect counts where necessary.

                maxnx = 0;
                for (uint i = 0; i < m_Links.Length; i++)
                {
                    if (m_Links[i].NumIntersect > 0)
                    {
                        maxnx = Math.Max(maxnx, this.SetIntersectionCount(i));
                    }
                }

                // Make sure we don't go into an infinite loop.
                nloop++;
                if (nloop > m_Links.Length)
                {
                    throw new Exception("PolygonSub: Breaking from infinite loop");
                }
            } // end while
        }
Exemplo n.º 11
0
        /// <summary>
        /// Tries to set the link for one of the link points.
        /// </summary>
        /// <param name="start">The array index of the link point to process.</param>
        /// <param name="angtol">Angular tolerance (in radians) for seeing if a link
        /// candidate has a bearing that's close enough to the desired bearing.</param>
        /// <returns>True if a link was set.</returns>
        bool SetLink(uint start, double angtol)
        {
            // Note our lucky contestant and it's side number.
            PolygonLink from     = m_Links[start];
            uint        fromside = from.Side;

            // Nothing to do if no side number (corner point).
            if (fromside == 0)
            {
                return(false);
            }

            // Skip if already linked.
            if (from.IsLinked)
            {
                return(false);
            }

            // Are we doing a connection for a radial point? In that case, we are
            // allowed to connect to corner points. We do radial points FIRST.
            bool radial = from.IsRadial;


            // Are we doing a curve end point? We do curve end points LAST.
            bool curveend = from.IsCurveEnd;

            // Initialize info on best link so far.
            PolygonLink to        = null;
            double      bestangle = Constants.PIMUL2;
            double      thisdiff  = Constants.PIMUL2;
            double      othrdiff  = Constants.PIMUL2;

            double MINDSQ = 4.0;                // Min distance (squared) between points.

            // Loop through every link point, looking for a match.
            for (uint j = 0; j < m_Links.Length; j++)
            {
                // Skip if this is the main candidate.
                if (j == start)
                {
                    continue;
                }

                // Skip if no side number (corners), or it's the same side
                // as the main candidate. We do permit an extension to a corner
                // if we're doing a radial link.
                uint curside = m_Links[j].Side;
                //	if ( curside==0 || curside==fromside ) continue;
                if (curside == 0 && !radial)
                {
                    continue;
                }

                // Skip if already linked.
                // if (m_Links[j].IsLinked) continue;

                // Only consider curve end points if the main candidate is a
                // curve end point too, or a radial.
                if (m_Links[j].IsCurveEnd && !(curveend || radial))
                {
                    continue;
                }

                // Skip if the distance to the other point is smaller
                // than 2 meters (squared) on the ground (the number's just a stab)
                if (from.DistanceSquared(m_Links[j]) < MINDSQ)
                {
                    continue;
                }

                // Get the angle formed between the candidate's reference
                // bearing, and the position of the current link point. If
                // it exceeds the angular tolerance, skip to next.
                double angle1 = from.GetAngle(m_Links[j]);
                if (angle1 > angtol)
                {
                    continue;
                }

                // Do the reverse test so long as the main candidate is
                // not a radial (when a radial hits a straight edge, the
                // ideal bearing for that point is likely to be close to
                // a perpendicular to the straight edge, so it probably
                // won't be within tolerance of the radial).

                double angle2;

                if (radial || m_Links[j].IsRadial)
                {
                    angle2 = angle1;
                }
                else
                {
                    angle2 = m_Links[j].GetAngle(from);
                }

                if (angle2 > angtol)
                {
                    continue;
                }

                // Skip if the candidate was previously linked, and the angle
                // we have now is worse.
                if (m_Links[j].IsLinked && angle2 > m_Links[j].LinkAngle)
                {
                    continue;
                }

                // If we are NOT doing a radial link, confirm that the proposed
                // link does not cross any radial links we may have formed	(we
                // did all radial links first).

                // If the main candidate is a curve end point, it can't intersect
                // ANYTHING else. If it's not a curve end point or a radial, all
                // we should check are radials. We process data in the order:
                // 1. radials
                // 2. not radials or curve ends
                // 3. curve ends

                // if ( curveend ) {
                //   if ( this->IsIntersected(*pFrom,m_Links[j],FALSE) ) continue;
                // }
                // else if ( !radial ) {
                //   if ( this->IsIntersected(*pFrom,m_Links[j],TRUE) ) continue;
                // }

                // Use the best angular deviation.
                double angle = Math.Min(angle1, angle2);

                // If the deviation is better than anything we already have,
                // and the link is valid, remember the current link point
                // as the best one so far.

                if (angle < bestangle && from.IsLinkValid(m_Links[j], m_Polygon))
                {
                    bestangle = angle;
                    thisdiff  = angle1;
                    othrdiff  = angle2;
                    to        = m_Links[j];
                }
            } // next point

            // Set the link if we got one.
            if (to != null)
            {
                from.SetLink(to, thisdiff, othrdiff);
                return(true);
            }

            return(false);
        }