/// <summary>
        /// Creates a new <c>FindPointContainerQuery</c> (and executes it). The result of the query
        /// can then be obtained through the <c>Result</c> property.
        /// </summary>
        /// <param name="index">The spatial index to search</param>
        /// <param name="point">The position you want the container for</param>
        internal FindPointContainerQuery(ISpatialIndex index, IPointGeometry p)
        {
            m_Point = p;
            m_Result = null;
            IWindow w = new Window(p, p);
            index.QueryWindow(w, SpatialType.Polygon, OnQueryHit);

            // If we didn't get a result, but we skipped some candidates, check them now.
            if (m_Result==null && m_Candidates!=null)
            {
                // If NONE of the polygon's islands enclose the search position, that's
                // the result we want.

                foreach (Polygon cand in m_Candidates)
                {
                    Debug.Assert(cand.HasAnyIslands);

                    if (!cand.HasIslandEnclosing(m_Point))
                    {
                        m_Result = cand;
                        return;
                    }
                }
            }
        }
 /// <summary>
 /// Creates a new <c>FindPointQuery</c> (and executes it). The result of the query
 /// can then be obtained through the <c>Result</c> property.
 /// </summary>
 /// <param name="index">The spatial index to search</param>
 /// <param name="point">The position of interest</param>
 internal FindPointQuery(ISpatialIndex index, IPointGeometry p)
 {
     m_Point = p;
     m_Result = null;
     IWindow w = new Window(p, p);
     index.QueryWindow(w, SpatialType.Point, OnQueryHit);
 }
 public CircularArcGeometry(ICircleGeometry circle, IPosition bc, IPosition ec, bool isClockwise)
 {
     m_Circle = circle;
     m_BC = PositionGeometry.Create(bc);
     m_EC = PositionGeometry.Create(ec);
     m_IsClockwise = isClockwise;
 }
 public CircularArcGeometry(ICircleGeometry circle, IPointGeometry bc, IPointGeometry ec, bool isClockwise)
 {
     m_Circle = circle;
     m_BC = bc;
     m_EC = ec;
     m_IsClockwise = isClockwise;
 }
Example #5
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="cc">Object for holding any displayed dialogs</param>
 /// <param name="action">The action that initiated this command</param>
 /// <param name="start">Point initially selected at start of command</param>
 internal NewLineUI(IControlContainer cc, IUserAction action, PointFeature start)
     : base(cc, action)
 {
     m_Start = start;
     m_End = null;
     m_CurrentPoint = start;
 }
        /// <summary>
        /// Creates new <c>LineStringGeometry</c> that corresponds to the supplied positions.
        /// </summary>
        /// <param name="data">The positions defining the line.</param>
        public LineStringGeometry(IPointGeometry[] data)
        {
            if (data==null || data.Length<2)
                throw new ArgumentException();

            m_Data = data;
        }
Example #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Annotation"/> class with the
 /// <see cref="FontStyle"/> property set to <see cref="System.Drawing.FontStyle.Regular"/>.
 /// </summary>
 /// <param name="text">The annotation text.</param>
 /// <param name="position">The position for the text (center-baseline aligned).</param>
 /// <param name="height">The height of the text (in meters on the ground).</param>
 /// <param name="rotation">The rotation (in radians clockwise from horizontal).</param>
 internal Annotation(string text, IPosition position, double height, double rotation)
 {
     m_Text = text;
     m_Position = PointGeometry.Create(position);
     m_Height = height;
     m_Rotation = new RadianValue(rotation);
     m_FontStyle = FontStyle.Regular;
 }
Example #8
0
        internal HorizontalRay(IPosition start, double distance)
        {
            if (distance < 0.0)
                throw new ArgumentOutOfRangeException();

            m_Start = PointGeometry.Create(start);
            m_EndX = start.X + distance;
        }
        /// <summary>
        /// Constructs a new <c>MultiSegmentGeometry</c>
        /// </summary>
        /// <param name="start">The point at the start of the connection.</param>
        /// <param name="end">The point at the end of the connection.</param>
        /// <param name="positions">The ground positions to pack. The first & last positions must exactly
        /// match the position of the supplied end points.</param>
        internal MultiSegmentGeometry(ITerminal start, ITerminal end, IPointGeometry[] positions)
            : base(start, end)
        {
            if (positions==null || positions.Length==0)
                throw new ArgumentNullException();

            if (positions.Length<=2)
                throw new ArgumentException("Not enough points for a multi-segment");

            if (!start.IsCoincident(positions[0]))
                throw new ArgumentException("Start point doesn't coincide with first position");

            if (!end.IsCoincident(positions[positions.Length-1]))
                throw new ArgumentException("End point doesn't coincide with last position");

            m_Data = positions;
            m_Extent = LineStringGeometry.GetExtent(this);
        }
        /// <summary>
        /// Creates a new <c>FindClosestQuery</c> (and executes it). The result of the query
        /// can then be obtained through the <c>Result</c> property.
        /// </summary>
        /// <param name="index">The spatial index to search</param>
        /// <param name="p">The search position.</param>
        /// <param name="radius">The search tolerance (expected to be greater than zero).</param>
        /// <param name="types">The type of objects to look for.</param>
        internal FindClosestQuery(ISpatialIndex index, IPosition p, ILength radius, SpatialType types)
        {
            if (types==0)
                throw new ArgumentNullException("Spatial type(s) not specified");

            // If the user hasn't been specific, ensure we don't search for polygons!
            SpatialType useTypes = (types==SpatialType.All ? SpatialType.Feature : types);
            Debug.Assert((useTypes & SpatialType.Polygon)==0);

            // It's important to round off to the nearest micron. Otherwise you might not
            // get the desired results in situations where the search radius is zero.
            m_Position = PositionGeometry.Create(p);

            m_Radius = radius;
            m_Types = types;
            m_Result = null;
            m_Distance = m_Radius.Meters;

            // The query will actually involve a square window, not a circle.
            IWindow x = new Window(m_Position, radius.Meters * 2.0);
            index.QueryWindow(x, useTypes, OnQueryHit);
        }
        /// <summary>
        /// Intersects this segment with another segment, where at least one end of the
        /// segment exactly coincides with one end of the other segment. 
        /// </summary>
        /// <param name="xsect">The intersection results.</param>
        /// <param name="start">The start of the other segment.</param>
        /// <param name="end">The end of the other segment.</param>
        /// <param name="xend">The end of THIS segment that coincides with one end
        /// of the other one (the geometry for either m_Start or m_End).</param>
        /// <param name="othend">The other end of THIS segment (may or may not coincide
        /// with one end of the other segment).</param>
        /// <returns>The number of intersections (always 1).</returns>
        static uint EndIntersect( IntersectionResult xsect
            , IPointGeometry start
            , IPointGeometry end
            , IPointGeometry xend
            , IPointGeometry othend)
        {
            // If the other end of this segment coincides with either end
            // of the other segment, we've got a total graze.
            if (othend.IsCoincident(start) || othend.IsCoincident(end))
            {
                xsect.Append(start, end);
                return 1;
            }

            // Get the locations that define the longer segment, together
            // with the location that is different from the exactly matching end.

            IPointGeometry startLong;
            IPointGeometry endLong;
            IPointGeometry test;

            if (Geom.DistanceSquared(xend, othend) < Geom.DistanceSquared(start, end))
            {
                test = othend;
                startLong = start;
                endLong = end;
            }
            else
            {
                startLong = xend;
                endLong = othend;

                if (xend.IsCoincident(start))
                    test = end;
                else
                    test = start;
            }

            // If it is coincident (to within the resolution) AND the
            // position ratio of the perpendicular point is ON this
            // segment, it's a graze.

            double tolsq = (Constants.XYRES * Constants.XYRES);

            if (PointGeometry.IsCoincidentWith(test, startLong, endLong, tolsq))
            {
                double prat = Geom.GetPositionRatio(test.X
                                                   , test.Y
                                                   , startLong.X
                                                   , startLong.Y
                                                   , endLong.X
                                                   , endLong.Y);

                if (prat>0.0 && prat<1.0)
                {
                    xsect.Append(xend, test);
                    return 1;
                }
            }

            // ONE intersection at the end that exactly matches.
            xsect.Append(xend);
            return 1;
        }
        /// <summary>
        /// Intersects a pair of clockwise arcs that sit on the same circle, and where ONE of
        /// the end points exactly matches.
        /// </summary>
        /// <param name="xsect">The intersection results.</param>
        /// <param name="circle">The circle the arcs coincide with</param>
        /// <param name="bc1">The BC of the 1st arc</param>
        /// <param name="ec1">The EC of the 1st arc</param>
        /// <param name="bc2">The BC of the 2nd arc -- the matching end</param>
        /// <param name="ec2">The EC of the 2nd arc</param>
        /// <param name="isStartMatch">Specify <c>true</c> if <paramref name="bc2"/> matches an end
        /// point of the 1st arc. Specify <c>false</c> if <paramref name="ec2"/> matches an end
        /// point of the 1st arc.</param>
        /// <returns>The number of intersections (always 1).</returns>
        static uint ArcEndIntersect( IntersectionResult xsect
            , ICircleGeometry circle
            , IPointGeometry bc1
            , IPointGeometry ec1
            , IPointGeometry bc2
            , IPointGeometry ec2
            , bool isStartMatch)
        {
            bool bmatch = bc1.IsCoincident(bc2);
            bool ematch = ec1.IsCoincident(ec2);

            // If the two curves share the same BC or same EC
            if (bmatch || ematch)
            {
                // We've got some sort of graze ...

                // Check for total graze.
                if (bmatch && ematch)
                    xsect.Append(bc1, ec1);
                else
                {
                    // We've therefore got a partial graze.

                    // If the length of this arc is longer than the other one, the graze is over the
                    // length of the other one, and vice versa. Since the two curves share the same
                    // radius and direction, the comparison just involves a comparison of the clockwise
                    // angles subtended by the arcs.

                    IPointGeometry centre = circle.Center;
                    double ang1 = new Turn(centre, bc1).GetAngleInRadians(ec1);
                    double ang2 = new Turn(centre, bc2).GetAngleInRadians(ec2);
                    bool isThisGraze = (ang1 < ang2);

                    if (isThisGraze)
                        xsect.Append(bc1, ec1);
                    else
                        xsect.Append(bc2, ec2);
                }
            }
            else
            {
                // The only intersection is at the common end.
                if (bc1.IsCoincident(bc2) || ec1.IsCoincident(bc2))
                    xsect.Append(bc2);
                else
                    xsect.Append(ec2);
            }

            return 1;
        }
        /// <summary>
        /// Intersects 2 clockwise arcs that coincide with the perimeter of a circle.
        /// </summary>
        /// <param name="xsect">Intersection results.</param>
        /// <param name="circle">The circle the arcs coincide with</param>
        /// <param name="bc1">BC for 1st arc.</param>
        /// <param name="ec1">EC for 1st arc.</param>
        /// <param name="bc2">BC for 2nd arc.</param>
        /// <param name="ec2">EC for 2nd arc.</param>
        /// <returns>The number of intersections (0, 1, or 2). If non-zero, the intersections
        /// will be grazes.</returns>
        static uint ArcIntersect( IntersectionResult xsect
            , ICircleGeometry circle
            , IPointGeometry bc1
            , IPointGeometry ec1
            , IPointGeometry bc2
            , IPointGeometry ec2)
        {
            // Define the start of the clockwise arc as a reference line,
            // and get the clockwise angle to it's EC.
            Turn reft = new Turn(circle.Center, bc1);
            double sector = reft.GetAngleInRadians(ec1);

            // Where do the BC and EC of the 2nd curve fall with respect
            // to the 1st curve's arc sector?
            double bcang = reft.GetAngleInRadians(bc2);
            double ecang = reft.GetAngleInRadians(ec2);

            if (bcang<sector)
            {
                if (ecang<bcang)
                {
                    xsect.Append(bc2, ec1);
                    xsect.Append(bc1, ec2);
                    return 2;
                }

                if (ecang<sector)
                    xsect.Append(bc2, ec2);
                else
                    xsect.Append(bc2, ec1);

                return 1;
            }

            // The BC of the 2nd curve falls beyond the sector of the 1st ...
            // so we can't have any graze if the EC is even further on.
            if (ecang>bcang)
                return 0;

            // One graze ...

            if (ecang<sector)
                xsect.Append(bc1, ec2);
            else
                xsect.Append(bc1, ec1);

            return 1;
        }
        /// <summary>
        /// Intersects a circle with a clockwise arc
        /// </summary>
        /// <param name="results"></param>
        /// <param name="c"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="arcCircle"></param>
        /// <returns></returns>
        static uint Intersect(IntersectionResult xsect, ICircleGeometry c, IPointGeometry start, IPointGeometry end, ICircleGeometry arcCircle)
        {
            // If the circles are IDENTICAL, we've got a graze.
            if (CircleGeometry.IsCoincident(c, arcCircle, Constants.XYRES))
            {
                xsect.Append(start, end);
                return 1;

            }

            // Intersect the 2 circles.
            IPosition x1, x2;
            uint nx = Intersect(c, arcCircle, out x1, out x2);

            // Return if no intersection.
            if (nx==0)
                return 0;

            // Remember the intersection(s) if they fall in the
            // curve's sector. Use a tolerance which is based on
            // the circle with the smaller radius (=> bigger angular
            // tolerance).

            IPointGeometry centre;
            double minrad;

            if (c.Radius < arcCircle.Radius)
            {
                minrad = c.Radius;
                centre = c.Center;
            }
            else
            {
                minrad = arcCircle.Radius;
                centre = arcCircle.Center;
            }

            //	const FLOAT8 angtol = XYTOL/minrad;
            //	const FLOAT8 angtol = 0.00002/minrad;	// 20 microns
            double angtol = 0.002/minrad;		// 2mm

            if (nx==1)
            {
                IPointGeometry loc = PointGeometry.Create(x1);
                if (Geom.IsInSector(loc, centre, start, end, angtol))
                {
                    xsect.Append(loc);
                    return 1;
                }

                return 0;
            }
            else
            {
                // Two intersections. They are valid if they fall within the curve's sector.
                IPointGeometry loc1 = PointGeometry.Create(x1);
                IPointGeometry loc2 = PointGeometry.Create(x2);
                uint nok=0;

                if (Geom.IsInSector(loc1, centre, start, end, angtol))
                {
                    xsect.Append(loc1);
                    nok++;
                }

                if (Geom.IsInSector(loc2, centre, start, end, angtol))
                {
                    xsect.Append(loc2);
                    nok++;
                }

                return nok;
            }
        }
        internal static uint Intersect( IntersectionResult results
            , IPointGeometry a
            , IPointGeometry b
            , IPointGeometry p
            , IPointGeometry q)
        {
            // 04-APR-2003: This isn't supposed to happen, but if we've somehow
            // got a null segment, it NEVER intersects anything.
            if (a.IsCoincident(b))
                return 0;

            // If the segment EXACTLY meets either end of the other segment,
            // it gets handled seperately.
            if (a.IsCoincident(p) || a.IsCoincident(q))
                return EndIntersect(results, p, q, a, b);

            if (b.IsCoincident(p) || b.IsCoincident(q))
                return EndIntersect(results, p, q, b, a);

            // Return if the windows don't overlap.
            Window winab = new Window(a, b);
            Window winpq = new Window(p, q);
            if (!winab.IsOverlap(winpq))
                return 0;

            // Check whether this line is completely coincident with the other one.
            // double tolsq = Constants.XYTOLSQ;
            double tolsq = (Constants.XYRES*Constants.XYRES);

            uint xcase = 0;
            if (PointGeometry.IsCoincidentWith(a, p, q, tolsq))
                xcase |= 0x08;
            if (PointGeometry.IsCoincidentWith(b, p, q, tolsq))
                xcase |= 0x04;

            if (xcase==12) // bits 1100
            {
                results.Append(a, b);
                return 1;
            }

            // Check the end points of the other line to this one.
            if (PointGeometry.IsCoincidentWith(p, a, b, tolsq))
                xcase |= 0x02;
            if (PointGeometry.IsCoincidentWith(q, a, b, tolsq))
                xcase |= 0x01;

            // Return intersections. Note that in cases 3,7,11, the intersections
            // are not necessarily ordered with respect to THIS segment.

            switch (xcase)
            {
                case 0:
                    {
                        // Try to get a simple intersection. Do not accept
                        // virtual intersections, since they should have been
                        // trapped via the calculation of the xcase.

                        double xi, yi;
                        int xcode = Geom.CalcIntersect(a.X, a.Y, b.X, b.Y, p.X, p.Y, q.X, q.Y, out xi, out yi, true);

                        if (xcode < 0)
                        {
                            results.Append(xi, yi, 0.0);
                            return 1;
                        }

                        return 0;
                    }

                case 1:
                    {
                        results.Append(q);
                        return 1;
                    }

                case 2:
                    {
                        results.Append(p);
                        return 1;
                    }

                case 3:
                    {
                        results.Append(p, q);	// order?
                        return 1;
                    }

                case 4:
                    {
                        results.Append(b);
                        return 1;
                    }

                case 5:
                    {
                        results.Append(q, b);
                        return 1;
                    }

                case 6:
                    {
                        results.Append(p, b);
                        return 1;
                    }

                case 7:
                    {
                        results.Append(p, q);	// order?
                        return 1;
                    }

                case 8:
                    {
                        results.Append(a);
                        return 1;
                    }

                case 9:
                    {
                        results.Append(a, q);
                        return 1;
                    }

                case 10:
                    {
                        results.Append(a, p);
                        return 1;
                    }

                case 11:
                    {
                        results.Append(p, q);	// order?
                        return 1;
                    }

            } // end switch

            throw new Exception("LineSegmentFeature.Intersect - Unexpected case");
        }
        /// <summary>
        /// Calculates an angle that is parallel to this line (suitable for adding text)
        /// </summary>
        /// <param name="p">A significant point on the line (not used).</param>
        /// <returns>The rotation (in radians, clockwise from horizontal). Always greater
        /// than or equal to 0.0</returns>
        internal override double GetRotation(IPointGeometry p)
        {
            double xs = Start.X;
            double ys = Start.Y;
            double xe = End.X;
            double ye = End.Y;
            double dx = xe - xs;
            double dy = ye - ys;

            // Horizontal (to nearest mm)
            double ady = Math.Abs(dy);
            if (ady < 0.001)
                return 0.0;

            // Vertical (to nearest mm)
            double adx = Math.Abs(dx);
            if (adx < 0.001)
                return MathConstants.PIDIV2;

            // Get result in range (0,PIDIV2)
            double rotation = Math.Atan(ady/adx);

            // Stuff in the NE and SW quadrants needs to be tweaked.
            if ((dx < 0.0 && dy < 0.0) || (dx > 0.0 && dy > 0.0))
            {
                rotation = -rotation;
                if (rotation < 0.0)
                    rotation += MathConstants.PIMUL2;
            }

            return rotation;
        }
        /// <summary>
        /// Intersects a line segment with a circle
        /// </summary>
        /// <param name="result"></param>
        /// <param name="a">The start of the line segment</param>
        /// <param name="b">The end  of the line segment</param>
        /// <param name="c">The center of the circle</param>
        /// <param name="r">The radius of the circle</param>
        /// <returns></returns>
        static uint Intersect(IntersectionResult result, IPointGeometry a, IPointGeometry b, IPointGeometry c, double r)
        {
            // Get intersections (if any). Return if nothing.
            IPosition x1, x2;
            bool isGraze;
            uint nx = GetXCircle(a, b, c, r, out x1, out x2, out isGraze);
            if (nx==0)
                return 0;

            // If we got just one intersection, it's a simple intersect (even
            // if it's a tangent to the circle).
            if (nx==1)
            {
                result.Append(x1);
                return 1;
            }

            // That leaves us with two intersections, which may or may
            // not be grazing the circle.

            if (isGraze)
            {
                result.Append(x1, x2);
                return 1;
            }

            result.Append(x1);
            result.Append(x2);
            return 2;
        }
 /// <summary>
 /// Gets the point on this line that is closest to a specified position.
 /// </summary>
 /// <param name="p">The position to search from.</param>
 /// <param name="tol">Maximum distance from line to the search position</param>
 /// <returns>The closest position (null if the line is further away than the specified
 /// max distance)</returns>
 internal override IPosition GetClosest(IPointGeometry p, ILength tol)
 {
     return Make().GetClosest(p, tol);
 }
 /// <summary>
 /// Calculates an angle that is parallel to this line (suitable for adding text)
 /// </summary>
 /// <param name="p">A significant point on the line. In the case of lines
 /// that are multi-segments, the individual line segment that contains this
 /// position should be used to obtain the angle.</param>
 /// <returns>The rotation (in radians, clockwise from horizontal)</returns>
 internal override double GetRotation(IPointGeometry p)
 {
     return Make().GetRotation(p);
 }
        /// <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));
        }
 /// <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)
 {
     return Make().GetCloser(s, ref e, out status);
 }
Example #22
0
        /// <summary>
        /// Attempts to find a location that can act as a terminal for a polygon boundary.
        /// This either refers to a user-perceived point feature, or an intersection
        /// point (as added via a prior call to <see cref="AddIntersection"/>).
        /// </summary>
        /// <param name="p">The position of interest</param>
        /// <remarks>The corresponding terminal (null if nothing found). This should either
        /// be an instance of <see cref="PointFeature"/> or <see cref="Intersection"/>.</remarks>
        internal ITerminal FindTerminal(IPointGeometry p)
        {
            // Search the base index for a real point feature
            PointFeature pf = (base.QueryClosest(p, Length.Zero, SpatialType.Point) as PointFeature);
            if (pf!=null)
                return pf;

            // Search for an intersection
            return (m_ExtraData.QueryClosest(p, Length.Zero, SpatialType.Point) as Intersection);
        }
 // Segment
 internal uint Intersect(IPointGeometry start, IPointGeometry end)
 {
     ILineSegmentGeometry seg = new LineSegmentGeometry(start, end);
     return m_IntersectedObject.LineGeometry.IntersectSegment(this, seg);
 }
 // Circle
 internal uint Intersect(IPointGeometry center, double radius)
 {
     ICircleGeometry circle = new CircleGeometry(center, radius);
     return m_IntersectedObject.LineGeometry.IntersectCircle(this, circle);
 }
        /// <summary>
        /// Intersects a line segment with a clockwise arc, where at least one end of the
        /// segment exactly coincides with one end of the arc.
        /// </summary>
        /// <param name="xsect">The intersection results.</param>
        /// <param name="bc">The start of the clockwise arc.</param>
        /// <param name="ec">The end of the clockwise arc.</param>
        /// <param name="circle">The circle on which the arc lies.</param>
        /// <param name="xend">The end of the segment that coincides with one end of the arc.</param>
        /// <param name="othend">The other end of the segment (may or may not coincide
        /// with one end of the arc).</param>
        /// <returns>The number of intersections (either 1 or 2).</returns>
        static uint EndIntersect( IntersectionResult xsect
            , IPointGeometry bc
            , IPointGeometry ec
            , ICircleGeometry circle
            , IPointGeometry xend
            , IPointGeometry othend)
        {
            // If the other end is INSIDE the circle, the matching end
            // location is the one and only intersection. Allow a tolerance
            // that is consistent with the resolution of data (3 microns).
            IPointGeometry centre = circle.Center;
            double radius = circle.Radius;
            double minrad = (radius-Constants.XYTOL);
            double minrsq = (minrad*minrad);
            double othdsq = Geom.DistanceSquared(othend, centre);

            if (othdsq < minrsq)
            {
                xsect.Append(xend);
                return 1;
            }

            // If the other end of the segment also coincides with either
            // end of the curve, the segment is a chord of the circle that
            // the curve lies on. However, if it's REAL close, we need to
            // return it as a graze ...

            if (othend.IsCoincident(bc) || othend.IsCoincident(ec))
            {
                // Get the midpoint of the chord.
                IPosition midseg = Position.CreateMidpoint(xend, othend);

                // If the distance from the centre of the circle to the
                // midpoint is REAL close to the curve, we've got a graze.

                if (Geom.DistanceSquared(midseg, centre) > minrsq)
                {
                    xsect.Append(xend, othend);
                    return 1;
                }

                // Two distinct intersections.
                xsect.Append(xend);
                xsect.Append(othend);
                return 2;
            }

            // If the other end is within tolerance of the circle, project
            // it to the circle and see if it's within the curve's sector.
            // If not, it's not really an intersect.

            double maxrad = (radius+Constants.XYTOL);
            double maxrsq = (maxrad*maxrad);

            if ( othdsq < maxrsq )
            {
                // Check if the angle to the other end is prior to the EC.
                // If not, it's somewhere off the curve.
                Turn reft = new Turn(centre, bc);
                if (reft.GetAngleInRadians(othend) > reft.GetAngleInRadians(ec))
                {
                    xsect.Append(xend);
                    return 1;
                }

                // And, like above, see if the segment grazes or not ...

                // Get the midpoint of the chord.
                IPosition midseg = Position.CreateMidpoint(xend, othend);

                // If the distance from the centre of the circle to the
                // midpoint is REAL close to the curve, we've got a graze.

                if (Geom.DistanceSquared(midseg, centre) > minrsq)
                {
                    xsect.Append(xend, othend);
                    return 1;
                }

                // Two distinct intersections.
                xsect.Append(xend);
                xsect.Append(othend);
                return 2;
            }

            // That leaves us with the other end lying somewhere clearly
            // outside the circle. However, we could still have a graze.

            // Make sure the BC/EC are EXACTLY coincident with the circle (they
            // may have been rounded off if the curve has been intersected
            // with a location that's within tolerance of the circle).

            IPosition trueBC, trueEC;
            Position.GetCirclePosition(bc, centre, radius, out trueBC);
            Position.GetCirclePosition(ec, centre, radius, out trueEC);

            // As well as the end of the segment that meets the curve.
            IPosition trueXend = (xend.IsCoincident(bc) ? trueBC : trueEC);

            // Intersect the segment with the complete circle (this does
            // NOT return an intersection at the other end, even if it is
            // really close ... we took care of that above).

            // The intersection must lie ON the segment (not sure about this though).

            IPosition othvtx = othend;
            IPosition x1, x2;
            bool isTangent;
            uint nx = Geom.IntersectCircle(centre, radius, trueXend, othvtx, out x1, out x2, out isTangent, true);

            // If we got NOTHING, that's unexpected, since one end exactly coincides
            // with the circle. In that case, just return the matching end (NOT
            // projected to the true position).
            if (nx==0)
            {
                xsect.Append(xend);
                return 1;
            }

            // If we got 2 intersections, pick the one that's further away than the matching end.
            if (nx==2 && Geom.DistanceSquared(x2, trueXend) > Geom.DistanceSquared(x1, trueXend))
                x1 = x2;

            // That leaves us with ONE intersection with the circle ... now
            // confirm that it actually intersects the arc!

            Turn refbc = new Turn(centre, trueBC);
            double eangle = refbc.GetAngleInRadians(trueEC);
            double xangle = refbc.GetAngleInRadians(x1);

            if (xangle > eangle)
            {
                xsect.Append(xend);
                return 1;
            }

            // Get the midpoint of the segment that connects the intersection to the true end.
            IPosition midx = Position.CreateMidpoint(trueXend, x1);

            // If the midpoint does NOT graze the circle, we've got 2 distinct intersections.
            // 25-NOV-99: Be realistic about it (avoid meaningless sliver polygons that are
            // less than 0.1mm wide on the ground).

            // if ( midx.DistanceSquared(centre) < minrsq ) {
            double rdiff = Geom.Distance(midx, centre) - radius;
            if (Math.Abs(rdiff) > 0.0001)
            {
                xsect.Append(xend);
                xsect.Append(x1);
                return 2;
            }

            // We've got a graze, but possibly one that can be ignored(!). To
            // understand the reasoning here, bear in mind that lines get cut
            // only so that network topology can be formed. To do that, 2
            // orientation points are obtained for the lines incident on xend.
            // For the segment, the orientation point is the other end of the
            // segment. For the curve, it's a position 5 metres along the
            // curve (or the total curve length if it's not that long). So
            // if the graze is closer than the point that will be used to
            // get the orientation point, we can ignore the graze, since it
            // does not provide any useful info.

            // Given that it's a graze, assume that it's ok to work out
            // the arc distance as if it was straight.
            double dsqx = Geom.DistanceSquared(trueXend, x1);

            // If it's closer than 4m (allow some leeway, seeing how we've
            // just done an approximation), ignore the intersection. If it's
            // actually between 4 and 5 metres, it shouldn't do any harm
            // to make a split there (although it's kind of redundant).
            if (dsqx < 16.0)
            {
                xsect.Append(xend);
                return 1;
            }

            // It's a graze.
            //CeVertex vxend(xend);	// wants a vertex
            xsect.Append(xend, x1);
            return 1;
        }
        /// <summary>
        /// Intersects a line segment with the data describing a clockwise curve.
        /// </summary>
        /// <param name="result">The intersection results.</param>
        /// <param name="a">The start of the line segment</param>
        /// <param name="b">The end of the line segment</param>
        /// <param name="start">The start of the clockwise arc.</param>
        /// <param name="end">The end of the clockwise arc.</param>
        /// <param name="circle">The circle on which the arc lies.</param>
        /// <returns></returns>
        static uint Intersect( IntersectionResult result
            , IPointGeometry a
            , IPointGeometry b
            , IPointGeometry start
            , IPointGeometry end
            , ICircleGeometry circle)
        {
            // If the segment exactly meets either end of the curve, it gets handled seperately.
            if (a.IsCoincident(start) || a.IsCoincident(end))
                return EndIntersect(result, start, end, circle, a, b);

            if (b.IsCoincident(start) || b.IsCoincident(end))
                return EndIntersect(result, start, end, circle, b, a);

            // Get circle definition.
            IPointGeometry centre = circle.Center;
            double radius = circle.Radius;

            // Get up to 2 intersections with the circle.
            IPosition x1, x2;
            bool isGraze;
            uint nx = GetXCircle(a, b, centre, radius, out x1, out x2, out isGraze);

            // Return if no intersections with the circle.
            if (nx==0)
                return 0;

            // If an intersection is really close to the end of an arc, force it to be there.
            if (Geom.DistanceSquared(start, x1) < Constants.XYTOLSQ)
                x1 = start;
            else if (Geom.DistanceSquared(end, x1) < Constants.XYTOLSQ)
                x1 = end;

            if (nx==2)
            {
                if (Geom.DistanceSquared(start, x2) < Constants.XYTOLSQ)
                    x2 = start;
                else if (Geom.DistanceSquared(end, x2) < Constants.XYTOLSQ)
                    x2 = end;
            }

            // Determine whether the intersections fall within the sector
            // that's defined by the clockwise curve (grazes need a bit
            // more handling, so do that after we see how to do the non-
            // grazing case.

            if ( !isGraze )
            {
                PointGeometry xloc1 = PointGeometry.Create(x1);
                double lintol = Constants.XYTOL / radius;

                // If we only got one intersect, and it's out of sector, that's us done.
                if (nx==1)
                {
                    if (!BasicGeom.IsInSector(xloc1, centre, start, end, lintol))
                        return 0;

                    result.Append(x1);
                    return 1;
                }

                // Two intersections with the circle ...

                if (BasicGeom.IsInSector(xloc1, centre, start, end, lintol))
                    result.Append(x1);
                else
                    nx--;

                PointGeometry xloc2 = PointGeometry.Create(x2);

                if (BasicGeom.IsInSector(xloc2, centre, start, end, lintol))
                    result.Append(x2);
                else
                    nx--;

                return nx;
            }

            // That leaves us with the case where this segment grazes the
            // circle. GetXCircle is always supposed to return nx==2 in that
            // case (they're also supposed to be arranged in the same
            // direction as this segment).
            Debug.Assert(nx==2);

            // Get the clockwise angle subtended by the circular arc. Add
            // on a tiny bit to cover numerical comparison problems.
            Turn reft = new Turn(centre, start);
            double maxangle = reft.GetAngleInRadians(end) + Constants.TINY;

            // Get the clockwise angles to both intersections.
            double a1 = reft.GetAngleInRadians(x1);
            double a2 = reft.GetAngleInRadians(x2);

            // No graze if both are beyond the arc sector.
            if (a1>maxangle && a2>maxangle)
                return 0;

            // If both intersects are within sector, the only thing to watch
            // out for is a case where the graze apparently occupies more
            // than half a circle. In that case, we've actually got 2 grazes.

            if (a1<maxangle &&  a2<maxangle)
            {
                if (a2>a1 && (a2-a1)>Constants.PI)
                {
                    result.Append(x1, start);
                    result.Append(end, x2);
                    return 2;
                }

                if (a1>a2 && (a1-a2)>Constants.PI)
                {
                    result.Append(start, x2);
                    result.Append(x1, end);
                    return 2;
                }

                // So it's just a regular graze.
                result.Append(x1, x2);
                return 1;
            }

            // That's covered the cases where both intersects are either
            // both in sector, or both out. Return the intersection that's
            // in sector as a simple intersection (NOT a graze).

            // This is a cop-out. We should really try to figure out which
            // portion of the curve is grazing, but the logic for doing so
            // is surprisingly complex, being subject to a variety of special
            // cases. By returning the intersect as a simple intersect, I'm
            // hoping it covers most cases.

            if (a1 < maxangle)
                result.Append(x1);
            else
                result.Append(x2);

            return 1;
        }
Example #27
0
        /// <summary>
        /// Sees whether the orientation of the new text should be altered. This
        /// occurs if the auto-angle capability is enabled, and the specified
        /// position is close to any visible line.
        /// </summary>
        /// <param name="refpos">The current mouse position (reference position
        /// for the new label)</param>
        /// <returns>True if the orientation angle got changed.</returns>
        bool CheckOrientation(IPointGeometry refpos)
        {
            // Return if the auto-angle function is disabled.
            if (!m_IsAutoAngle)
                return false;

            // Return if the auto-position function is enabled
            if (m_IsAutoPos)
                return false;

            // Try to get an orientation line
            LineFeature orient = GetOrientation(refpos);
            if (!Object.ReferenceEquals(orient, m_Orient))
                ErasePainting();

            m_Orient = null;
            if (orient == null)
                return false;

            // Locate the closest point on the line (we SHOULD find it,
            // but if we don't, just bail out)
            ISpatialDisplay display = ActiveDisplay;
            ILength tol = new Length(0.002 * display.MapScale);
            IPosition closest = orient.LineGeometry.GetClosest(refpos, tol);
            if (closest == null)
                return false;

            m_Orient = orient;
            if (m_Orient==null)
                return false;

            // Highlight the new orientation line
            m_Orient.Render(display, new HighlightStyle());

            // Get the rotation angle
            IPointGeometry cg = PointGeometry.Create(closest);
            double rot = m_Orient.LineGeometry.GetRotation(cg);
            SetRotation(rot);
            return true;
        }
        /// <summary>
        /// Gets the point on this line that is closest to a specified position.
        /// </summary>
        /// <param name="p">The position to search from.</param>
        /// <param name="tol">Maximum distance from line to the search position</param>
        /// <returns>The closest position (null if the line is further away than the specified
        /// max distance)</returns>
        internal override IPosition GetClosest(IPointGeometry p, ILength tol)
        {
            // Get the perpendicular point (or closest end)
            IPointGeometry s = Start;
            IPointGeometry e = End;
            double xp, yp;
            BasicGeom.GetPerpendicular(p.X, p.Y, s.X, s.Y, e.X, e.Y, out xp, out yp);

            // Ignore if point is too far away
            double t = tol.Meters;
            double dx = p.X - xp;
            if (dx > t)
                return null;

            double dy = p.Y - yp;
            if (dy > t)
                return null;

            double dsq = (dx*dx + dy*dy);
            if (dsq > t*t)
                return null;

            return new Position(xp, yp);
        }
Example #29
0
        /// <summary>
        /// Returns a code indicating the relative position of a location with respect to
        /// a rectangular window (the Cohen & Sutherland clipping algorithm).
        /// </summary>
        /// <param name="p">The position of interest</param>
        /// <param name="sw">South-west corner of window</param>
        /// <param name="ne">North-east corner of window</param>
        /// <returns></returns>
        internal static byte GetPositionCode(IPointGeometry p, IPointGeometry sw, IPointGeometry ne)
        {
            byte code = 0;
            long e = p.Easting.Microns;

            if (e < sw.Easting.Microns) // p west of sw
                code |= 0x01;
            else if (e > ne.Easting.Microns) // p east of ne
                code |= 0x02;

            long n = p.Northing.Microns;
            if (n < sw.Northing.Microns) // p south of sw
                code |= 0x04;
            else if (n > ne.Northing.Microns) // p north of ne
                code |= 0x08;

            return code;
        }
Example #30
0
        /// <summary>
        /// Sees whether the orientation of the new text should be altered. This
        /// occurs if the auto-orient capability is enabled, and the specified
        /// position is close to any visible lne.
        /// </summary>
        /// <param name="posn">The position to use for making the check.</param>
        /// <returns></returns>
        LineFeature GetOrientation(IPointGeometry posn)
        {
            // The ground tolerance is 2mm at the draw scale.
            ISpatialDisplay display = ActiveDisplay;
            double tol = 0.002 * display.MapScale;

            // If we previously selected something, see if the search point
            // lies within tolerance. If so, there's no change.
            if (m_Orient != null)
            {
                double dist = m_Orient.Distance(posn).Meters;
                if (dist < tol)
                    return m_Orient;
            }

            // Get the map to find the closest line
            CadastralMapModel map = CadastralMapModel.Current;
            ISpatialIndex index = map.Index;
            return (index.QueryClosest(posn, new Length(tol), SpatialType.Line) as LineFeature);
        }