예제 #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SegmentNode"/> class.
 /// </summary>
 /// <param name="segString"></param>
 /// <param name="coord"></param>
 /// <param name="segmentIndex"></param>
 /// <param name="segmentOctant"></param>
 public SegmentNode(SegmentString segString, Coordinate coord, int segmentIndex, OctantDirection segmentOctant)
 {
     Coordinate = new Coordinate(coord);
     SegmentIndex = segmentIndex;
     _segmentOctant = segmentOctant;
     _isInterior = !coord.Equals2D(segString.GetCoordinate(segmentIndex));
 }
예제 #2
0
        public void Equals2D_ReturnsTrueForCoordinateWithTheSameOrdinates()
        {
            Coordinate target = new Coordinate(xCoordinate, yCoordinate, zCoordinate, mValue);
            Coordinate other = new Coordinate(xCoordinate, yCoordinate, zCoordinate, mValue);

            Assert.True(target.Equals2D(other));
        }
예제 #3
0
        public void Equals2D_ReturnsFalseForCoordinateWithDifferentXYOrdinates()
        {
            Coordinate target = new Coordinate(xCoordinate, yCoordinate, zCoordinate, mValue);
            Coordinate other = new Coordinate(xCoordinate + 1, yCoordinate + 1, zCoordinate, mValue);

            Assert.False(target.Equals2D(other));
        }
        /// <summary>
        ///  Compares two <see cref="Coordinate" />s for their relative position along a segment
        /// lying in the specified <see cref="Octant" />.
        /// </summary>
        /// <param name="octant"></param>
        /// <param name="p0"></param>
        /// <param name="p1"></param>
        /// <returns>
        /// -1 if node0 occurs first, or
        ///  0 if the two nodes are equal, or
        ///  1 if node1 occurs first.
        /// </returns>
        public static int Compare(Octants octant, Coordinate p0, Coordinate p1)
        {
            // nodes can only be equal if their coordinates are equal
            if (p0.Equals2D(p1)) 
                return 0;

            int xSign = RelativeSign(p0.X, p1.X);
            int ySign = RelativeSign(p0.Y, p1.Y);

            switch (octant)
            {
                case Octants.Zero: 
                    return CompareValue(xSign, ySign);
                case Octants.One:
                    return CompareValue(ySign, xSign);
                case Octants.Two:
                    return CompareValue(ySign, -xSign);
                case Octants.Three:
                    return CompareValue(-xSign, ySign);
                case Octants.Four:
                    return CompareValue(-xSign, -ySign);
                case Octants.Five:
                    return CompareValue(-ySign, -xSign);
                case Octants.Six:
                    return CompareValue(-ySign, xSign);
                case Octants.Seven:
                    return CompareValue(xSign, -ySign);
            }

            Assert.ShouldNeverReachHere("invalid octant value: " + octant);
            return 0;
        }
예제 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SegmentNode"/> class.
 /// </summary>
 /// <param name="segString"></param>
 /// <param name="coord"></param>
 /// <param name="segmentIndex"></param>
 /// <param name="segmentOctant"></param>
 public SegmentNode(SegmentString segString, Coordinate coord, int segmentIndex, Octants segmentOctant) 
 {
     this.segString = segString;
     this.Coordinate = new Coordinate(coord);
     this.SegmentIndex = segmentIndex;
     this.segmentOctant = segmentOctant;
     isInterior = !coord.Equals2D(segString.GetCoordinate(segmentIndex));
 }
예제 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SegmentNode"/> class.
 /// </summary>
 /// <param name="segString"></param>
 /// <param name="coord"></param>
 /// <param name="segmentIndex"></param>
 /// <param name="segmentOctant"></param>
 public SegmentNode(INodableSegmentString segString, Coordinate coord, int segmentIndex, Octants segmentOctant) 
 {
     Coord = null;
     _segString = segString;
     Coord = new Coordinate(coord.X, coord.Y, coord.Z);
     SegmentIndex = segmentIndex;
     _segmentOctant = segmentOctant;
     _isInterior = !coord.Equals2D(segString.Coordinates[segmentIndex]);
 }
        private static void PreciseCoordinateTester(IPrecisionModel pm,
            double x1, double y1,
            double x2, double y2)
        {
            var p = new Coordinate(x1, y1);
            pm.MakePrecise(p);

            var pPrecise = new Coordinate(x2, y2);
            Assert.IsTrue(p.Equals2D(pPrecise), "Expected {0}, but got {1}", pPrecise, p);
        }
예제 #8
0
        public void TestEquals()
        {
            Coordinate c1 = new Coordinate(1, 2, 3);
            const string s = "Not a coordinate";
            Assert.IsFalse(c1.Equals(s));

            Coordinate c2 = new Coordinate(1, 2, 3);
            Assert.IsTrue(c1.Equals2D(c2));

            Coordinate c3 = new Coordinate(1, 22, 3);
            Assert.IsFalse(c1.Equals2D(c3));
        }
        /// <summary> 
        /// Computes the "edge distance" of an intersection point p along a segment.
        /// The edge distance is a metric of the point along the edge.
        /// The metric used is a robust and easy to compute metric function.
        /// It is not equivalent to the usual Euclidean metric.
        /// It relies on the fact that either the x or the y ordinates of the
        /// points in the edge are unique, depending on whether the edge is longer in
        /// the horizontal or vertical direction.
        /// NOTE: This function may produce incorrect distances
        /// for inputs where p is not precisely on p1-p2
        /// (E.g. p = (139,9) p1 = (139,10), p2 = (280,1) produces distanct 0.0, which is incorrect.
        /// My hypothesis is that the function is safe to use for points which are the
        /// result of rounding points which lie on the line, but not safe to use for truncated points.
        /// </summary>
        public static double ComputeEdgeDistance(Coordinate p, Coordinate p0, Coordinate p1)
        {
            var dx = Math.Abs(p1.X - p0.X);
            var dy = Math.Abs(p1.Y - p0.Y);

            var dist = -1.0;   // sentinel value
            if (p.Equals(p0)) 
                dist = 0.0;            
            else if (p.Equals(p1)) 
            {
                dist = dx > dy ? dx : dy;
            }
            else 
            {
                double pdx = Math.Abs(p.X - p0.X);
                double pdy = Math.Abs(p.Y - p0.Y);
                dist = dx > dy ? pdx : pdy;

                // <FIX>: hack to ensure that non-endpoints always have a non-zero distance
                if (dist == 0.0 && ! p.Equals2D(p0))                
                    dist = Math.Max(pdx, pdy);
                
            }
            Assert.IsTrue(!(dist == 0.0 && ! p.Equals(p0)), "Bad distance calculation");
            return dist;
        }
예제 #10
0
 private Arc(Circle circle, Coordinate p1, Coordinate p2, bool isClockwise)
 {
     this.p1 = p1;
     this.p2 = p2;
     clockwise = isClockwise;
     p1Angle = circle.GetAngle(p1);
     if (p1.Equals2D(p2))
     {
         p2Angle = TWO_PI + p1Angle;
     }
     else
     {
         p2Angle = circle.GetAngle(p2);
     }
     DetermineArcAngle();
 }
예제 #11
0
            private double arcAngle; // angle in radians

            internal Arc(Circle circle, Coordinate p1, Coordinate midPt, Coordinate p2)
            {
                this.circle = circle;
                this.p1 = p1;
                this.p2 = p2;
                p1Angle = circle.GetAngle(p1);
                // See if this arc covers the whole circle
                if (p1.Equals2D(p2))
                {
                    p2Angle = TWO_PI + p1Angle;
                    arcAngle = TWO_PI;
                }
                else
                {
                    p2Angle = circle.GetAngle(p2);
                    double midPtAngle = circle.GetAngle(midPt);

                    // determine the direction
                    double ccDegrees = SubtractAngles(p1Angle,
                                                      midPtAngle)
                                       + SubtractAngles(midPtAngle, p2Angle);

                    if (ccDegrees < TWO_PI)
                    {
                        clockwise = false;
                        arcAngle = ccDegrees;
                    }
                    else
                    {
                        clockwise = true;
                        arcAngle = TWO_PI - ccDegrees;
                    }
                }
            }
예제 #12
0
 /// <summary>
 /// Tests whether either intersection point is an interior point of the specified input segment.
 /// </summary>
 /// <returns> 
 /// <c>true</c> if either intersection point is in the interior of the input segment.
 /// </returns>
 public virtual bool IsInteriorIntersection(int inputLineIndex)
 {
     Coordinate ptI;
     for (int i = 0; i < (int)_result; i++)
     {
         ptI = new Coordinate(_intPt[i]);
          if (!(ptI.Equals2D(_inputLines[inputLineIndex, 0]) || ptI.Equals2D(_inputLines[inputLineIndex, 1])))                                   
             return true;    
     }
     return false;
 }
        /// <summary>
        /// Calculates distance between a point and a line AB
        /// </summary>
        /// <param name="c">The coordinate to compute the distance for.</param>
        /// <param name="a">One point of the line.</param>
        /// <param name="b">Another point of the line.</param>
        /// <param name="mode">LineMode value that specifies whether AB should be treated as infinite line or as line segment.</param>
        /// <returns> The distance from C to line AB in coordinate's units.</returns>
        public double CalculateDistance(Coordinate c, Coordinate a, Coordinate b, LineMode mode)
        {
            if (a.Equals2D(b)) {
                return this.CalculateDistance(c, a);
            }

            double deltaX = b.X - a.X;
            double deltaY = b.Y - a.Y;

            if (mode == LineMode.LineSegment) {
                /*
                        Let P be the point of perpendicular projection of C on AB.  The parameter
                        r, which indicates P's position along AB, is computed by the dot product
                        of AC and AB divided by the square of the length of AB:

                                        AC dot AB
                                r = ---------
                                        ||AB||^2

                        r has the following meaning:

                                r=0      P = A
                                r=1      P = B
                                r<0      P is on the backward extension of AB
                                r>1      P is on the forward extension of AB
                                0<r<1    P is interior to AB
                */

                double r = ((c.X - a.X) * deltaX + (c.Y - a.Y) * deltaY) / (deltaX * deltaX + deltaY * deltaY);

                if (r <= 0.0) {
                    return this.CalculateDistance(c, a);
                }

                if (r >= 1.0) {
                    return this.CalculateDistance(c, b);
                }
            }

            /*
                    Use another parameter s to indicate the location along PC, with the  following meaning:
                             s<0      C is left of AB
                             s>0      C is right of AB
                             s=0      C is on AB

                    (principialy the same as r - only use perpendicular vector)

                    Compute s as follows:

                                (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
                        s = -----------------------------
                                                        L^2
            */

            double s = ((a.Y - c.Y) * deltaX - (a.X - c.X) * deltaY) / (deltaX * deltaX + deltaY * deltaY);

            /*
                    Then the distance from C to P = |s|*L.
            */

            return Math.Abs(s) * Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
        }
예제 #14
0
 private static Octants SafeOctant(Coordinate p0, Coordinate p1)
 {
     if (p0.Equals2D(p1)) return Octants.Zero;
       	        return Octant.GetOctant(p0, p1);
 }
예제 #15
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="intPt"></param>
        /// <param name="segmentIndex"></param>
        public void AddIntersection(Coordinate intPt, int segmentIndex)
        {
            var normalizedSegmentIndex = segmentIndex;
            // normalize the intersection point location
            var nextSegIndex = normalizedSegmentIndex + 1;
            if(nextSegIndex < _pts.Length)
            {
                var nextPt = _pts[nextSegIndex];

                // Normalize segment index if intPt falls on vertex
                // The check for point equality is 2D only - Z values are ignored
                if (intPt.Equals2D(nextPt))
                    normalizedSegmentIndex = nextSegIndex;
            }

            // Add the intersection point to edge intersection list.
            /*var ei = */_nodeList.Add(intPt, normalizedSegmentIndex);
        }
 private static bool IsSnapped(Coordinate v, Coordinate p0, Coordinate p1)
 {
     if (v.Equals2D(p0)) return true;
     if (v.Equals2D(p1)) return true;
     var seg = new LineSegment(p0, p1);
     var dist = seg.Distance(v);
     if (dist < SnapTolerance / 2.05) return false;
     return true;
 }
예제 #17
0
파일: Map.cs 프로젝트: lishxi/_SharpMap
        /// <summary>
        /// Zooms the map to fit a bounding box
        /// </summary>
        /// <remarks>
        /// NOTE: If the aspect ratio of the box and the aspect ratio of the mapsize
        /// isn't the same, the resulting map-envelope will be adjusted so that it contains
        /// the bounding box, thus making the resulting envelope larger!
        /// </remarks>
        /// <param name="bbox"></param>
        public void ZoomToBox(Envelope bbox)
        {
            if (bbox != null && !bbox.IsNull)
            {
                //Ensure aspect ratio
                var resX = Size.Width == 0 ? double.MaxValue : bbox.Width / Size.Width;
                var resY = Size.Height == 0 ? double.MaxValue : bbox.Height / Size.Height;
                var zoom = bbox.Width;
                if (resY > resX && resX > 0)
                {
                    zoom *= resY / resX;
                }

                var center = new Coordinate(bbox.Centre);

                zoom = _mapViewportGuard.VerifyZoom(zoom, center);
                var changed = false;
                if (zoom != _zoom)
                {
                    _zoom = zoom;
                    changed = true;
                }

                if (!center.Equals2D(_center))
                {
                    _center = center;
                    changed = true;
                }

                if (changed && MapViewOnChange != null)
                    MapViewOnChange();
            }
        }
예제 #18
0
        public void TestEquals2D()
        {
            Coordinate c1 = new Coordinate(1, 2, 3);
            Coordinate c2 = new Coordinate(1, 2, 3);
            Assert.IsTrue(c1.Equals2D(c2));

            Coordinate c3 = new Coordinate(1, 22, 3);
            Assert.IsFalse(c1.Equals2D(c3));
        }
예제 #19
0
        public void Equals2D_ReturnsTrueForNaNCoordinates()
        {
            Coordinate target = new Coordinate(double.NaN, double.NaN, double.NaN, double.NaN);
            Coordinate other = new Coordinate(double.NaN, double.NaN, double.NaN, double.NaN);

            Assert.True(target.Equals2D(other));
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="pt"></param>
 /// <param name="snapPts"></param>
 /// <returns></returns>
 private Coordinate FindSnapForVertex(Coordinate pt, Coordinate[] snapPts)
 {
     foreach (Coordinate coord in snapPts)
     {
         // if point is already equal to a src pt, don't snap
         if (pt.Equals2D(coord))
             return null;
         if (pt.Distance(coord) < _snapTolerance)
             return coord;
     }
     return null;
 }
예제 #21
0
		/// <summary>
        /// Computes whether a ring defined by an array of <see cref="Coordinate" />s is oriented counter-clockwise.
        /// The list of points is assumed to have the first and last points equal.
        /// This will handle coordinate lists which contain repeated points.
        /// This algorithm is only guaranteed to work with valid rings.
        /// If the ring is invalid (e.g. self-crosses or touches),
        /// the computed result may not be correct.
		/// </summary>>
        /// <param name="ring"></param>
        /// <returns></returns>
        public static bool IsCounterClockwise(IList<Coordinate> ring) 
        {
            // # of points without closing endpoint
            int nPts = ring.Count - 1;

            // find highest point
            Coordinate hiPt = ring[0];
            int hiIndex = 0;
            for (int i = 1; i <= nPts; i++)
            {
                Coordinate p = ring[i];
                if (p.Y > hiPt.Y)
                {
                    hiPt = p;
                    hiIndex = i;
                }
            }

            // find distinct point before highest point
            int iPrev = hiIndex;
            do
            {
                iPrev = iPrev - 1;
                if (iPrev < 0) iPrev = nPts;
            } 
            while (ring[iPrev].Equals2D(hiPt) && iPrev != hiIndex);

            // find distinct point after highest point
            int iNext = hiIndex;
            do
                iNext = (iNext + 1) % nPts;
            while (ring[iNext].Equals2D(hiPt) && iNext != hiIndex);

            Coordinate prev = new Coordinate(ring[iPrev]);
            Coordinate next = new Coordinate(ring[iNext]);

            /*
             * This check catches cases where the ring contains an A-B-A configuration of points.
             * This can happen if the ring does not contain 3 distinct points
             * (including the case where the input array has fewer than 4 elements),
             * or it contains coincident line segments.
             */
            if (prev.Equals2D(hiPt) || next.Equals2D(hiPt) || prev.Equals2D(next))
                return false;

            int disc = ComputeOrientation(prev, new Coordinate(hiPt), next);

            /*
             *  If disc is exactly 0, lines are collinear.  There are two possible cases:
             *  (1) the lines lie along the x axis in opposite directions
             *  (2) the lines lie on top of one another
             *
             *  (1) is handled by checking if next is left of prev ==> CCW
             *  (2) will never happen if the ring is valid, so don't check for it
             *  (Might want to assert this)
             */
            bool isCCW;
            if (disc == 0)            
                // poly is CCW if prev x is right of next x
                isCCW = (prev.X > next.X);            
            else
                // if area is positive, points are ordered CCW
                isCCW = (disc > 0);
            return isCCW;
        }
예제 #22
0
        /// <summary>
        /// Add an EdgeIntersection for intersection intIndex.
        /// An intersection that falls exactly on a vertex of the edge is normalized
        /// to use the higher of the two possible segmentIndexes.
        /// </summary>
        /// <param name="li"></param>
        /// <param name="segmentIndex"></param>
        /// <param name="geomIndex"></param>
        /// <param name="intIndex"></param>
        public virtual void AddIntersection(LineIntersector li, int segmentIndex, int geomIndex, int intIndex)
        {
            Coordinate intPt = new Coordinate(li.GetIntersection(intIndex));
            int normalizedSegmentIndex = segmentIndex;
            double dist = li.GetEdgeDistance(geomIndex, intIndex);        
            
            // normalize the intersection point location
            int nextSegIndex = normalizedSegmentIndex + 1;
            if (nextSegIndex < Points.Count) 
            {
                Coordinate nextPt = Points[nextSegIndex];        

                // Normalize segment index if intPt falls on vertex
                // The check for point equality is 2D only - Z values are ignored
                if (intPt.Equals2D(nextPt)) 
                {       
                    normalizedSegmentIndex = nextSegIndex;
                    dist = 0.0;
                }
                // Add the intersection point to edge intersection list.                
                EdgeIntersectionList.Add(intPt, normalizedSegmentIndex, dist);
            }            
        }
예제 #23
0
 public void TestEquals2DWithinTolerance()
 {
     Coordinate c = new Coordinate(100.0, 200.0, 50.0);
     Coordinate aBitOff = new Coordinate(100.1, 200.1, 50.0);
     Assert.IsTrue(c.Equals2D(aBitOff, 0.2));
 }