Example #1
0
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // Express the end of the horizontal in a local system with
            // the same origin as the circle this arc lies on.
            IPosition  center = m_Circle.Center;
            QuadVertex pos    = new QuadVertex(center, hr.End);
            Quadrant   quad   = pos.Quadrant;

            // Assign the side code, assuming the arc is clockwise.
            Side result = (quad == Quadrant.NE || quad == Quadrant.SE ? Side.Right : Side.Left);

            // If the horizontal is apparently to the right of the curve,
            // but the location in question coincides with the extreme
            // north point of the circle, reverse the side (it's OK in
            // the extreme south).

            if (result == Side.Right)
            {
                double maxnorth = center.Y + Circle.Radius;
                if (Math.Abs(maxnorth - hr.Y) < Constants.TINY)
                {
                    result = Side.Left;
                }
            }

            // If the arc actually goes anti-clockwise, reverse the side.
            if (!m_IsClockwise)
            {
                result = (result == Side.Left ? Side.Right : Side.Left);
            }

            return(result);
        }
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Remember the initial end of segment
            PointGeometry initEnd = new PointGeometry(e);

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X - s.X);

            if (!hseg.IsValid)
            {
                status = 1;
                return(false);
            }

            IPointGeometry[] data = this.Data;

            // Get relative position code for the start of the line. If it's
            // somewhere on the horizontal segment, cut the line back.
            byte scode = Geom.GetPositionCode(data[0], s, e);

            if (scode == 0)
            {
                e = new PointGeometry(Start);
            }

            // Loop through each line segment, testing the end of each segment
            // against the horizontal segment.
            byte ecode;

            for (int i = 1; i < data.Length; scode = ecode, i++)
            {
                // Get the position code for the end of the line segment
                ecode = Geom.GetPositionCode(data[i], s, e);

                // If it's coincident with the horizontal segment, cut the
                // line back. Otherwise see whether there is any potential
                // intersection to cut back to.

                if (ecode == 0)
                {
                    e = new PointGeometry(data[i]);
                }
                else if ((scode & ecode) == 0)
                {
                    IPosition x = null;
                    if (hseg.Intersect(data[i - 1], data[i], ref x))
                    {
                        e = new PointGeometry(x);
                    }
                }
            }

            // Return flag to indicate whether we got closer or not.
            return(!e.IsCoincident(initEnd));
        }
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // Find the segment containing the end of the horizontal segment
            IPointGeometry[] data = Data;
            int seg = FindSegment(data, true, 0, hr.End);

            if (seg < 0)
            {
                return(Side.Unknown); // not found => big problem!
            }
            // What's the northing of the horizontal segment guy?
            double hy = hr.Y;

            // Scan the remainder of the line, looking for a point which is
            // off the horizontal. If below the horizontal, it's to the right
            // of the line (& above=>left).

            for (int i = seg + 1; i < data.Length; i++)
            {
                double y = data[i].Y;
                if ((hy - y) > Constants.TINY)    // y<hy
                {
                    return(Side.Right);
                }
                if ((y - hy) > Constants.TINY)    // y>hy
                {
                    return(Side.Left);
                }
            }

            // If we didn't find any suitable points, try traversing back down
            // the line, and adopt the reverse logic for figuring out the side.

            for (int i = seg; i >= 0; i--)
            {
                double y = data[i].Y;
                if ((y - hy) > Constants.TINY)    // y>hy
                {
                    return(Side.Right);
                }
                if ((hy - y) > Constants.TINY)    // y<hy
                {
                    return(Side.Left);
                }
            }

            // The line is completely horizontal, so we have an intersection
            // at the start or the end of the line. This should have already
            // been caught, so we're f****d now.

            return(Side.Unknown);
        }
Example #4
0
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Remember the initial end of segment
            PointGeometry initEnd = new PointGeometry(e);

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X - s.X);

            if (!hseg.IsValid)
            {
                status = 1;
                return(false);
            }

            // Get relative position code for the start of the line. If it's
            // somewhere on the horizontal segment, cut the line back.
            byte scode = Geom.GetPositionCode(Start, s, e);

            if (scode == 0)
            {
                e = new PointGeometry(Start);
            }

            // Get the position code for the end of the line segment
            byte ecode = Geom.GetPositionCode(End, s, e);

            // If it's coincident with the horizontal segment, cut the
            // line back. Otherwise see whether there is any potential
            // intersection to cut back to.

            if (ecode == 0)
            {
                e = new PointGeometry(End);
            }
            else if ((scode & ecode) == 0)
            {
                IPosition x = null;
                if (hseg.Intersect(Start, End, ref x))
                {
                    e = new PointGeometry(x);
                }
            }

            // Return flag to indicate whether we got closer or not.
            return(!e.IsCoincident(initEnd));
        }
Example #5
0
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // The end of the horizontal segment should be coincident with this segment.
            IPosition e = hr.End;

            if (this.Distance(e).Meters > Constants.XYTOL)
            {
                return(Side.Unknown);
            }

            // What's the northing of the horizontal segment guy?
            double hy = hr.Y;

            // Scan the remainder of the line, looking for a point which is
            // off the horizontal. If below the horizontal, it's to the right
            // of the line (& above=>left).

            double y = End.Y;

            if ((hy - y) > Constants.TINY) // y<hy
            {
                return(Side.Right);
            }
            if ((y - hy) > Constants.TINY) // y>hy
            {
                return(Side.Left);
            }

            // If we didn't find any suitable points, try traversing back down
            // the line, and adopt the reverse logic for figuring out the side.

            y = Start.Y;
            if ((y - hy) > Constants.TINY) // y>hy
            {
                return(Side.Right);
            }
            if ((hy - y) > Constants.TINY) // y<hy
            {
                return(Side.Left);
            }

            // The line is completely horizontal, so we have an intersection
            // at the start or the end of the line. This should have already
            // been caught, so we're f****d now.

            return(Side.Unknown);
        }
Example #6
0
        /// <summary>
        /// Creates new <c>Orientation</c> based on the supplied horizontal ray.
        /// </summary>
        /// <param name="hr"></param>
        internal Orientation(HorizontalRay hr)
        {
            // Remember the stuff we were supplied (since we are not starting
            // with a divider, it has to be null).

            m_Divider = null;
            m_IsStart = false;

            // The horizontal segment is ALWAYS at the very start of the
            // north-west quadrant.
            m_Quadrant = Quadrant.NW;

            // Convert the deltas into the IJ coordinate system for the
            // north-west quadrant (the angle defined with I/J should
            // evaluate to zero, since the horizontal segment is at the
            // start of the quadrant).

            m_DeltaI = 0.0;
            m_DeltaJ = hr.EndX - hr.StartX;
        }
Example #7
0
        /// <summary>
        /// Determines which side of a divider a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="id">The divider to process</param>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment.</param>
        /// <param name="od">The divider the side refers to. This usually refers to
        /// the supplied divider, but may refer to another divider in a situation where the
        /// horizontal segment passes directly through one end of <paramref name="d"/>.</param>
        /// <returns>Side.Left if the line is to the left of the divider, Side.Right
        /// if line to the right, Side.On if the end of the line is coincident with
        /// the divider, Side.Unknown if an error arose.</returns>
        /// <remarks>
        /// Rather than passing in 2 PointGeometry objects, it would be better to pass
        /// in a HorizontalRay object, since 2 arbitrary positions are not guaranteed
        /// to be horizontal.
        /// </remarks>
        internal static Side GetSide(IDivider id, IPointGeometry s, IPointGeometry e, out IDivider od)
        {
            // If the end of the horizontal segment hits the start or
            // the end of the specified divider, we have a situation where the divider
            // may not be the divider which is adjacent to the segment. In
            // that case, use special code to determine the side code.
            // Otherwise just convert the supplied divider into a line, and get the
            // side code by looking for a vertex which has a different
            // northing from that of the horizontal segment.

            Debug.Assert(s.Easting.Microns <= e.Easting.Microns);
            double d = e.Easting.Meters - s.Easting.Meters;
            Debug.Assert(d>=0.0);
            HorizontalRay hseg = new HorizontalRay(s, d);

            if (e.IsCoincident(id.From) || e.IsCoincident(id.To)) // e both times!
                return hseg.GetSide(id, e.IsCoincident(id.From), out od);
            else
            {
                od = id;
                return od.LineGeometry.GetSide(hseg);
            }
        }
Example #8
0
        /// <summary>
        /// Creates new <c>Orientation</c> based on the supplied horizontal ray.
        /// </summary>
        /// <param name="hr"></param>
        internal Orientation(HorizontalRay hr)
        {
            // Remember the stuff we were supplied (since we are not starting
            // with a divider, it has to be null).

            m_Divider = null;
            m_IsStart = false;

            // The horizontal segment is ALWAYS at the very start of the
            // north-west quadrant.
            m_Quadrant = Quadrant.NW;

            // Convert the deltas into the IJ coordinate system for the
            // north-west quadrant (the angle defined with I/J should
            // evaluate to zero, since the horizontal segment is at the
            // start of the quadrant).

            m_DeltaI = 0.0;
            m_DeltaJ = hr.EndX - hr.StartX;
        }
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // The end of the horizontal segment should be coincident with this segment.
            IPosition e = hr.End;
            if (this.Distance(e).Meters > Constants.XYTOL)
                return Side.Unknown;

            // What's the northing of the horizontal segment guy?
            double hy = hr.Y;

            // Scan the remainder of the line, looking for a point which is
            // off the horizontal. If below the horizontal, it's to the right
            // of the line (& above=>left).

            double y = End.Y;
            if ((hy-y) > Constants.TINY) // y<hy
                return Side.Right;
            if ((y-hy) > Constants.TINY) // y>hy
                return Side.Left;

            // If we didn't find any suitable points, try traversing back down
            // the line, and adopt the reverse logic for figuring out the side.

            y = Start.Y;
            if ((y-hy) > Constants.TINY) // y>hy
                return Side.Right;
            if ((hy-y) > Constants.TINY) // y<hy
                return Side.Left;

            // The line is completely horizontal, so we have an intersection
            // at the start or the end of the line. This should have already
            // been caught, so we're f****d now.

            return Side.Unknown;
        }
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Remember the initial end of segment
            PointGeometry initEnd = new PointGeometry(e);

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X-s.X);
            if (!hseg.IsValid)
            {
                status = 1;
                return false;
            }

            // Get relative position code for the start of the line. If it's
            // somewhere on the horizontal segment, cut the line back.
            byte scode = Geom.GetPositionCode(Start, s, e);
            if (scode==0)
                e = new PointGeometry(Start);

            // Get the position code for the end of the line segment
            byte ecode = Geom.GetPositionCode(End, s, e);

            // If it's coincident with the horizontal segment, cut the
            // line back. Otherwise see whether there is any potential
            // intersection to cut back to.

            if (ecode==0)
                e = new PointGeometry(End);
            else if ((scode & ecode)==0)
            {
                IPosition x = null;
                if (hseg.Intersect(Start, End, ref x))
                    e = new PointGeometry(x);
            }

            // Return flag to indicate whether we got closer or not.
            return (!e.IsCoincident(initEnd));
        }
Example #11
0
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // Express the end of the horizontal in a local system with
            // the same origin as the circle this arc lies on.
            IPosition center = m_Circle.Center;
            QuadVertex pos = new QuadVertex(center, hr.End);
            Quadrant quad = pos.Quadrant;

            // Assign the side code, assuming the arc is clockwise.
            Side result = (quad==Quadrant.NE || quad==Quadrant.SE ? Side.Right : Side.Left);

            // If the horizontal is apparently to the right of the curve,
            // but the location in question coincides with the extreme
            // north point of the circle, reverse the side (it's OK in
            // the extreme south).

            if (result==Side.Right)
            {
                double maxnorth = center.Y + Circle.Radius;
                if (Math.Abs(maxnorth - hr.Y) < Constants.TINY)
                    result = Side.Left;
            }

            // If the arc actually goes anti-clockwise, reverse the side.
            if (!m_IsClockwise)
                result = (result==Side.Left ? Side.Right : Side.Left);

            return result;
        }
 /// <summary>
 /// Determines which side of a line a horizontal line segment lies on.
 /// Used in point in polygon.
 /// </summary>
 /// <param name="hr">The horizontal line segment</param>
 /// <returns>Code indicating the position of the horizontal segment with respect to this line.
 /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
 /// right of this line; Side.Unknown if the side cannot be determined (this line is
 /// horizontal).
 /// </returns>
 internal override Side GetSide(HorizontalRay hr)
 {
     return Make().GetSide(hr);
 }
Example #13
0
 /// <summary>
 /// Determines which side of a line a horizontal line segment lies on.
 /// Used in point in polygon.
 /// </summary>
 /// <param name="hr">The horizontal line segment</param>
 /// <returns>Code indicating the position of the horizontal segment with respect to this line.
 /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
 /// right of this line; Side.Unknown if the side cannot be determined (this line is
 /// horizontal).
 /// </returns>
 internal override Side GetSide(HorizontalRay hr)
 {
     return(Make().GetSide(hr));
 }
Example #14
0
 /// <summary>
 /// Determines which side of a line a horizontal line segment lies on.
 /// Used in point in polygon.
 /// </summary>
 /// <param name="hr">The horizontal line segment</param>
 /// <returns>Code indicating the position of the horizontal segment with respect to this line.
 /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
 /// right of this line; Side.Unknown if the side cannot be determined (this line is
 /// horizontal).
 /// </returns>
 internal abstract Side GetSide(HorizontalRay hr);
        /// <summary>
        /// Determines which side of a line a horizontal line segment lies on.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="hr">The horizontal line segment</param>
        /// <returns>Code indicating the position of the horizontal segment with respect to this line.
        /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
        /// right of this line; Side.Unknown if the side cannot be determined (this line is
        /// horizontal).
        /// </returns>
        internal override Side GetSide(HorizontalRay hr)
        {
            // Find the segment containing the end of the horizontal segment
            IPointGeometry[] data = Data;
            int seg = FindSegment(data, true, 0, hr.End);
            if (seg<0)
                return Side.Unknown; // not found => big problem!

            // What's the northing of the horizontal segment guy?
            double hy = hr.Y;

            // Scan the remainder of the line, looking for a point which is
            // off the horizontal. If below the horizontal, it's to the right
            // of the line (& above=>left).

            for (int i=seg+1; i<data.Length; i++)
            {
                double y = data[i].Y;
                if ((hy-y) > Constants.TINY)	// y<hy
                    return Side.Right;
                if ((y-hy) > Constants.TINY)	// y>hy
                    return Side.Left;
            }

            // If we didn't find any suitable points, try traversing back down
            // the line, and adopt the reverse logic for figuring out the side.

            for (int i=seg; i>=0; i--)
            {
                double y = data[i].Y;
                if ((y-hy) > Constants.TINY)	// y>hy
                    return Side.Right;
                if ((hy-y) > Constants.TINY)	// y<hy
                    return Side.Left;
            }

            // The line is completely horizontal, so we have an intersection
            // at the start or the end of the line. This should have already
            // been caught, so we're f****d now.

            return Side.Unknown;
        }
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Remember the initial end of segment
            PointGeometry initEnd = new PointGeometry(e);

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X-s.X);
            if (!hseg.IsValid)
            {
                status = 1;
                return false;
            }

            IPointGeometry[] data = this.Data;

            // Get relative position code for the start of the line. If it's
            // somewhere on the horizontal segment, cut the line back.
            byte scode = Geom.GetPositionCode(data[0], s, e);
            if (scode==0)
                e = new PointGeometry(Start);

            // Loop through each line segment, testing the end of each segment
            // against the horizontal segment.
            byte ecode;
            for (int i=1; i<data.Length; scode=ecode, i++)
            {
                // Get the position code for the end of the line segment
                ecode = Geom.GetPositionCode(data[i], s, e);

                // If it's coincident with the horizontal segment, cut the
                // line back. Otherwise see whether there is any potential
                // intersection to cut back to.

                if (ecode==0)
                    e = new PointGeometry(data[i]);
                else if ((scode & ecode)==0)
                {
                    IPosition x=null;
                    if (hseg.Intersect(data[i-1], data[i], ref x))
                        e = new PointGeometry(x);
                }
            }

            // Return flag to indicate whether we got closer or not.
            return (!e.IsCoincident(initEnd));
        }
Example #17
0
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Get the window of the circle that this curve lies on.
            IWindow cwin = m_Circle.Extent;

            // Get a window for the horizontal segment.
            IWindow segwin = new Window(s, e);

            // Return if the windows don't overlap.
            if (!cwin.IsOverlap(segwin))
            {
                return(false);
            }

            // Return if the the segment is to the west of the circle's window.
            if (segwin.Max.X < cwin.Min.X)
            {
                return(false);
            }

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X - s.X);

            if (!hseg.IsValid)
            {
                status = 1;
                return(false);
            }

            // Locate up to two intersections of the horizontal segment with the circle.
            IPosition x1 = null;
            IPosition x2 = null;
            uint      nx = hseg.Intersect(m_Circle, ref x1, ref x2);

            // Return if no intersections
            if (nx == 0)
            {
                return(false);
            }

            // Return if this arc curve is a complete circle.
            if (this.IsCircle)
            {
                return(false);
            }

            // Check whether the first intersection lies on this arc. If
            // so, update the end of segment, and return.
            if (CircularArcGeometry.IsInSector(this, x1, 0.0))
            {
                e = new PointGeometry(x1);
                return(true);
            }

            // If we got two intersections with the circle, check the
            // second intersection as well.
            if (nx == 2 && CircularArcGeometry.IsInSector(this, x2, 0.0))
            {
                e = new PointGeometry(x2);
                return(true);
            }

            return(false);
        }
Example #18
0
 /// <summary>
 /// Determines which side of a line a horizontal line segment lies on.
 /// Used in point in polygon.
 /// </summary>
 /// <param name="hr">The horizontal line segment</param>
 /// <returns>Code indicating the position of the horizontal segment with respect to this line.
 /// Side.Left if the horizontal segment is to the left of this line; Side.Right if to the
 /// right of this line; Side.Unknown if the side cannot be determined (this line is
 /// horizontal).
 /// </returns>
 abstract internal Side GetSide(HorizontalRay hr);
Example #19
0
        /// <summary>
        /// Creates a new <c>ConnectionFinder</c> at a specific end of a divider.
        /// Defines the next divider in the nodal cycle (reckoned anticlockwise),
        /// along with a flag to indicate whether it is the start or end of the divider.
        /// <para/>
        /// If the parameters supplied refer to a dangling divider, the result will
        /// be the SAME as the supplied info.
        /// <para/>
        /// This constructor is normally used during polygon formation. It is also used
        /// to resolve a special case in point in polygon tests, where the directed
        /// line (a <c>HorizontalRay</c> object) intersects at a node. In that case,
        /// the supplied divider refers to any one of the dividers incident on the
        /// node, and the connection to be formed is actually the connection for
        /// the <c>HorizontalRay</c> object.
        /// </summary>
        /// <param name="from">The divider entering the node.</param>
        /// <param name="isFromStart">True if it's the start of the divider.</param>
        /// <param name="ray">Optional reference line (used when doing special point
        /// in polygon tests).</param>
        internal ConnectionFinder(IDivider from, bool isFromStart, HorizontalRay ray)
        {
            Debug.Assert(from != null);

            // Initialize with default values
            m_Next    = null;
            m_IsStart = false;

            // Get the location involved
            ITerminal loc = (isFromStart ? from.From : from.To);

            // Get the dividers incident on the terminal.
            IDivider[] da = loc.IncidentDividers();

            // Get orientation info for each divider (the list could conceivably
            // grow if dividers start at the terminal, then loop round to also
            // finish at the same terminal).
            List <Orientation> orient = new List <Orientation>(da.Length);

            // If we are doing special stuff for point in polygon, add an extra orientation
            // object to refer to the HorizontalRay object.
            if (ray != null)
            {
                Orientation o = new Orientation(ray);
                orient.Add(o);
            }

            foreach (IDivider d in da)
            {
                // 03-APR-2003: Try ignoring boundaries that have zero-length
                //if (!b.HasLength)
                //    continue;

                // Check if the start of the divider is incident on the node.
                // If so, append the orientation info to the list.
                if (d.From.IsCoincident(loc))
                {
                    orient.Add(new Orientation(d, true));
                }

                // Likewise for the end of the divider (it could start AND end at the node).
                if (d.To.IsCoincident(loc))
                {
                    orient.Add(new Orientation(d, false));
                }
            }

            // We MUST have at least one orientation point (two if a horizontal ray is also included)
            Debug.Assert(orient.Count > (ray == null ? 0 : 1));

            // If we have only one orientation point, we have a dangle,
            // so return the information we were supplied.
            if (ray == null && orient.Count == 1)
            {
                m_Next    = from;
                m_IsStart = isFromStart;
                return;
            }

            // Get a reference to the orientation info for the source divider (if
            // we are doing point in polygon stuff, we stashed the reference
            // segment in the first slot).

            Orientation source = null;

            if (ray != null)
            {
                source = orient[0];
            }
            else
            {
                source = orient.Find(o => (o.Divider == from && o.IsStart == isFromStart));
                Debug.Assert(source != null);
            }

            // If we have only two orientation points, the one we want
            // if the one which does not match the source.
            if (orient.Count == 2)
            {
                Orientation o = (source == orient[0] ? orient[1] : orient[0]);
                m_Next    = o.Divider;
                m_IsStart = o.IsStart;
                return;
            }

            // Handle any curves.
            if (HasAnyCurves(orient))
            {
                source.SetCurves(orient);
            }

            // If there are any other boundaries in the source quadrant,
            // try to find an anticlockwise divider (with the highest
            // orientation angle which is less than that of the source).
            Orientation next = FindPrevMax(source, orient);

            // If we got something, we're all done.
            if (next != null)
            {
                m_Next    = next.Divider;
                m_IsStart = next.IsStart;
                return;
            }

            // Loop through the quadrants, looking for the next divider. We
            // scan the quadrants anticlockwise, including the source
            // quadrant we may have just processing (possibility that the
            // next divider is further on in the source quadrant).

            Quadrant search = NextQuadrant(source.Quadrant);

            for (int i = 0; i < 4; i++, search = NextQuadrant(search))
            {
                next = FindMax(search, source, orient);
                if (next != null)
                {
                    m_Next    = next.Divider;
                    m_IsStart = next.IsStart;
                    return;
                }
            }

            throw new Exception("ConnectionFinder: network error");
        }
Example #20
0
        /// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Get the window of the circle that this curve lies on.
            IWindow cwin = m_Circle.Extent;

            // Get a window for the horizontal segment.
            IWindow segwin = new Window(s, e);

            // Return if the windows don't overlap.
            if (!cwin.IsOverlap(segwin))
                return false;

            // Return if the the segment is to the west of the circle's window.
            if (segwin.Max.X < cwin.Min.X)
                return false;

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X-s.X);
            if (!hseg.IsValid)
            {
                status = 1;
                return false;
            }

            // Locate up to two intersections of the horizontal segment with the circle.
            IPosition x1=null;
            IPosition x2=null;
            uint nx = hseg.Intersect(m_Circle, ref x1, ref x2);

            // Return if no intersections
            if (nx==0)
                return false;

            // Return if this arc curve is a complete circle.
            if (this.IsCircle)
                return false;

            // Check whether the first intersection lies on this arc. If
            // so, update the end of segment, and return.
            if (CircularArcGeometry.IsInSector(this, x1, 0.0))
            {
                e = new PointGeometry(x1);
                return true;
            }

            // If we got two intersections with the circle, check the
            // second intersection as well.
            if (nx==2 && CircularArcGeometry.IsInSector(this, x2, 0.0))
            {
                e = new PointGeometry(x2);
                return true;
            }

            return false;
        }