/// <inheritdoc cref="ICoordinateSequenceFilter.Filter"/>
            public void Filter(CoordinateSequence seq, int index)
            {
                /*
                 * This logic also handles skipping Point geometries
                 */
                if (index < 1)
                {
                    return;
                }

                var p0 = seq.GetCoordinate(index - 1);
                var p1 = seq.GetCoordinate(index);

                double delx = (p1.X - p0.X) / _numSubSegs;
                double dely = (p1.Y - p0.Y) / _numSubSegs;

                for (int i = 0; i < _numSubSegs; i++)
                {
                    double x         = p0.X + i * delx;
                    double y         = p0.Y + i * dely;
                    var    pt        = new Coordinate(x, y);
                    var    minPtDist = new PointPairDistance();
                    DistanceToPoint.ComputeDistance(_geom, pt, minPtDist);
                    _maxPtDist.SetMaximum(minPtDist);
                }
            }
예제 #2
0
        /// <summary>
        /// Computes the distance from a point to a sequence of line segments.
        /// </summary>
        /// <param name="p">A point</param>
        /// <param name="line">A sequence of contiguous line segments defined by their vertices</param>
        /// <returns>The minimum distance between the point and the line segments</returns>
        public static double PointToSegmentString(Coordinate p, CoordinateSequence line)
        {
            if (line.Count == 0)
            {
                throw new ArgumentException(
                          "Line array must contain at least one vertex");
            }

            var lastStart  = line.GetCoordinate(0);
            var currentEnd = lastStart.Copy();

            // this handles the case of length = 1
            double minDistance = p.Distance(lastStart);

            for (int i = 1; i < line.Count; i++)
            {
                line.GetCoordinate(i, currentEnd);
                double dist = PointToSegment(p, lastStart, currentEnd);
                if (dist < minDistance)
                {
                    minDistance = dist;
                }
                lastStart.CoordinateValue = currentEnd;
            }
            return(minDistance);
        }
예제 #3
0
 public void Filter(CoordinateSequence seq, int i)
 {
     if (i == 0)
     {
         return;
     }
     seq.GetCoordinate(i - 1, p0);
     seq.GetCoordinate(i, p1);
     rcc.CountSegment(p0, p1);
 }
예제 #4
0
            public void Filter(CoordinateSequence seq, int i)
            {
                // compare to vertex
                CheckVertexDistance(seq.GetCoordinate(i));

                // compare to segment, if this is one
                if (i > 0)
                {
                    CheckSegmentDistance(seq.GetCoordinate(i - 1), seq.GetCoordinate(i));
                }
            }
예제 #5
0
        private static CoordinateSequence InsertTopologyExceptionPoint(Coordinate coord, CoordinateSequence seq, CoordinateSequenceFactory factory)
        {
            var res = factory.Create(2 * seq.Count, seq.Ordinates);

            if (Replace(seq.GetCoordinate(0), coord))
            {
                res.SetOrdinate(0, Ordinate.X, coord.X);
                res.SetOrdinate(0, Ordinate.Y, coord.Y);
                res.SetOrdinate(0, Ordinate.Z, coord.Z);
            }
            else
            {
                res.SetOrdinate(0, Ordinate.X, seq.GetOrdinate(0, Ordinate.X));
                res.SetOrdinate(0, Ordinate.Y, seq.GetOrdinate(0, Ordinate.Y));
                res.SetOrdinate(0, Ordinate.Z, seq.GetOrdinate(0, Ordinate.Z));
            }

            var last = res.GetCoordinate(0);
            int off  = 0;

            for (int i = 1; i < seq.Count; i++)
            {
                var  curr = seq.GetCoordinate(i);
                bool add  = true;
                if (Replace(curr, coord))
                {
                    res.SetOrdinate(i + off, Ordinate.X, coord.X);
                    res.SetOrdinate(i + off, Ordinate.Y, coord.Y);
                    res.SetOrdinate(i + off, Ordinate.Z, coord.Z);
                    add = false;
                }
                else if (last.Distance(coord) + coord.Distance(curr) <= 1.000000000000000000001 * last.Distance(curr))
                {
                    res.SetOrdinate(i + off, Ordinate.X, coord.X);
                    res.SetOrdinate(i + off, Ordinate.Y, coord.Y);
                    res.SetOrdinate(i + off, Ordinate.Z, coord.Z);
                    off += 1;
                }

                if (add)
                {
                    res.SetOrdinate(i + off, Ordinate.X, seq.GetOrdinate(i, Ordinate.X));
                    res.SetOrdinate(i + off, Ordinate.Y, seq.GetOrdinate(i, Ordinate.Y));
                    res.SetOrdinate(i + off, Ordinate.Z, seq.GetOrdinate(i, Ordinate.Z));
                }
                last = curr;
            }

            var tmp = factory.Create(seq.Count + off, seq.Ordinates);

            CoordinateSequences.Copy(res, 0, tmp, 0, tmp.Count);
            return(tmp);
        }
        /// <summary>
        /// Function to return a coordinate sequence that is ensured to be closed.
        /// </summary>
        /// <param name="sequence">The base sequence</param>
        /// <param name="factory">The factory to use in case we need to create a new sequence</param>
        /// <returns>A closed coordinate sequence</returns>
        private static CoordinateSequence EnsureClosedSequence(CoordinateSequence sequence,
                                                               CoordinateSequenceFactory factory)
        {
            //This sequence won't serve a valid linear ring
            if (sequence.Count < 3)
            {
                return(null);
            }

            //The sequence is closed
            var start     = sequence.GetCoordinate(0);
            int lastIndex = sequence.Count - 1;
            var end       = sequence.GetCoordinate(lastIndex);

            if (start.Equals2D(end))
            {
                return(sequence);
            }

            // The sequence is not closed
            // 1. Test for a little offset, in that case simply correct x- and y- ordinate values
            const double eps = 1E-7;

            if (start.Distance(end) < eps)
            {
                sequence.SetX(lastIndex, start.X);
                sequence.SetY(lastIndex, start.Y);
                return(sequence);
            }

            // 2. Close the sequence by adding a new point, this is heavier
            var newSequence = factory.Create(sequence.Count + 1, sequence.Dimension, sequence.Measures);
            int maxDim      = sequence.Dimension;

            for (int i = 0; i < sequence.Count; i++)
            {
                for (int dim = 0; dim < maxDim; dim++)
                {
                    newSequence.SetOrdinate(i, dim, sequence.GetOrdinate(i, dim));
                }
            }

            for (int dim = 0; dim < maxDim; dim++)
            {
                newSequence.SetOrdinate(sequence.Count, dim, sequence.GetOrdinate(0, dim));
            }

            return(newSequence);
        }
예제 #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="geom"></param>
        protected override void Visit(Geometry geom)
        {
            if (!(geom is Polygon))
            {
                return;
            }

            var elementEnv = geom.EnvelopeInternal;

            if (!_rectEnv.Intersects(elementEnv))
            {
                return;
            }

            // test each corner of rectangle for inclusion
            var rectPt = _rectSeq.CreateCoordinate();

            for (int i = 0; i < 4; i++)
            {
                _rectSeq.GetCoordinate(i, rectPt);
                if (!elementEnv.Contains(rectPt))
                {
                    continue;
                }

                // check rect point in poly (rect is known not to touch polygon at this point)
                if (SimplePointInAreaLocator.ContainsPointInPolygon(rectPt, (Polygon)geom))
                {
                    ContainsPoint = true;
                    return;
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Computes the signed area for a ring. The signed area is positive if the
        /// <list type="Table">
        /// <listheader>
        /// <term>value</term>
        /// <description>meaning</description>
        /// </listheader>
        /// <item><term>&gt; 0</term>
        /// <description>The ring is oriented clockwise (CW)</description></item>
        /// <item><term>&lt; 0</term>
        /// <description>The ring is oriented counter clockwise (CCW)</description></item>
        /// <item><term>== 0</term>
        /// <description>The ring is degenerate or flat</description></item>
        /// </list>
        /// ring is oriented CW, negative if the ring is oriented CCW, and zero if the
        /// ring is degenerate or flat.
        /// </summary>
        /// <param name="ring">The coordinates forming the ring</param>
        /// <returns>The signed area of the ring</returns>
        public static double OfRingSigned(CoordinateSequence ring)
        {
            int n = ring.Count;

            if (n < 3)
            {
                return(0.0);
            }

            /**
             * Based on the Shoelace formula.
             * http://en.wikipedia.org/wiki/Shoelace_formula
             */
            var    p1 = ring.GetCoordinateCopy(0);
            var    p2 = ring.GetCoordinateCopy(1);
            double x0 = p1.X;

            p2.X -= x0;
            double sum = 0.0;

            for (int i = 1; i < n - 1; i++)
            {
                double p0Y = p1.Y;
                p1.X = p2.X;
                p1.Y = p2.Y;
                ring.GetCoordinate(i + 1, p2);
                p2.X -= x0;
                sum  += p1.X * (p0Y - p2.Y);
            }
            return(sum / 2.0);
        }
예제 #9
0
 /// <summary>
 /// Converts sequence
 /// </summary>
 /// <param name="cs"></param>
 /// <returns></returns>
 public static IEnumerable <PPoint> ToPPoints(this CoordinateSequence cs)
 {
     for (int i = 0; i < cs.Count; i++)
     {
         yield return(cs.GetCoordinate(i).ToPPoint());
     }
 }
예제 #10
0
        /// <summary>
        /// Computes the length of a <c>LineString</c> specified by a sequence of points.
        /// </summary>
        /// <param name="pts">The points specifying the <c>LineString</c></param>
        /// <returns>The length of the <c>LineString</c></returns>
        public static double OfLine(CoordinateSequence pts)
        {
            // optimized for processing CoordinateSequences
            int n = pts.Count;

            if (n <= 1)
            {
                return(0.0);
            }

            double len = 0.0;

            var    p  = pts.GetCoordinateCopy(0);
            double x0 = p.X;
            double y0 = p.Y;

            for (int i = 1; i < n; i++)
            {
                pts.GetCoordinate(i, p);
                double x1 = p.X;
                double y1 = p.Y;
                double dx = x1 - x0;
                double dy = y1 - y0;

                len += Math.Sqrt(dx * dx + dy * dy);

                x0 = x1;
                y0 = y1;
            }
            return(len);
        }
예제 #11
0
            public void Filter(CoordinateSequence seq, int index)
            {
                if (index == 0)
                {
                    return;
                }

                var p0    = seq.GetCoordinate(index - 1);
                var p1    = seq.GetCoordinate(index);
                var midPt = new Coordinate(
                    (p0.X + p1.X) / 2,
                    (p0.Y + p1.Y) / 2);

                minPtDist.Initialize();
                DistanceToPointFinder.ComputeDistance(geom, midPt, minPtDist);
                maxPtDist.SetMaximum(minPtDist);
            }
예제 #12
0
            public void Filter(CoordinateSequence seq, int i)
            {
                if (i <= 0)
                {
                    return;
                }

                // extract LineSegment
                var  p0       = seq.GetCoordinate(i - 1);
                var  p1       = seq.GetCoordinate(i);
                bool isBorder = Intersects(_envelope, p0, p1) && !ContainsProperly(_envelope, p0, p1);

                if (isBorder)
                {
                    var seg = new LineSegment(p0, p1);
                    _segments.Add(seg);
                }
            }
예제 #13
0
        /// <summary>
        /// Tests whether a point lies on the line defined by a list of
        /// coordinates.
        /// </summary>
        /// <param name="p">The point to test</param>
        /// <param name="line">The line coordinates</param>
        /// <returns>
        /// <c>true</c> if the point is a vertex of the line or lies in the interior
        /// of a line segment in the line
        /// </returns>
        public static bool IsOnLine(Coordinate p, CoordinateSequence line)
        {
            var lineIntersector = new RobustLineIntersector();
            var p0 = line.CreateCoordinate();
            var p1 = p0.Copy();
            int n  = line.Count;

            for (int i = 1; i < n; i++)
            {
                line.GetCoordinate(i - 1, p0);
                line.GetCoordinate(i, p1);
                lineIntersector.ComputeIntersection(p, p0, p1);
                if (lineIntersector.HasIntersection)
                {
                    return(true);
                }
            }
            return(false);
        }
 private void gatherDim4(CoordinateSequence cs, Dictionary <Coordinate, Double> map)
 {
     if (cs.Dimension == 4)
     {
         for (int i = 0; i < cs.Count; i++)
         {
             map.TryAdd(cs.GetCoordinate(i), cs.GetOrdinate(i, 3));
         }
     }
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="seq0"></param>
 /// <param name="seq1"></param>
 /// <returns></returns>
 public bool HasIntersection(CoordinateSequence seq0, CoordinateSequence seq1)
 {
     for (int i = 1; i < seq0.Count && !_hasIntersection; i++)
     {
         seq0.GetCoordinate(i - 1, pt00);
         seq0.GetCoordinate(i, pt01);
         for (int j = 1; j < seq1.Count && !_hasIntersection; j++)
         {
             seq1.GetCoordinate(j - 1, pt10);
             seq1.GetCoordinate(j, pt11);
             li.ComputeIntersection(pt00, pt01, pt10, pt11);
             if (li.HasIntersection)
             {
                 _hasIntersection = true;
             }
         }
     }
     return(_hasIntersection);
 }
        /// <summary>
        /// Determines the <see cref="Geometries.Location"/> of a point in a ring.
        /// </summary>
        /// <param name="p">The point to test</param>
        /// <param name="ring">A coordinate sequence forming a ring</param>
        /// <returns>The location of the point in the ring</returns>
        public static Location LocatePointInRing(Coordinate p, CoordinateSequence ring)
        {
            var counter = new RayCrossingCounter(p);

            var p1    = ring.CreateCoordinate();
            var p2    = ring.CreateCoordinate();
            int count = ring.Count;

            for (int i = 1; i < count; i++)
            {
                ring.GetCoordinate(i, p1);
                ring.GetCoordinate(i - 1, p2);
                counter.CountSegment(p1, p2);
                if (counter.IsOnSegment)
                {
                    return(counter.Location);
                }
            }
            return(counter.Location);
        }
예제 #17
0
        /**
         * Computes an average normal vector from a list of polygon coordinates.
         * Uses Newell's method, which is based
         * on the fact that the vector with components
         * equal to the areas of the projection of the polygon onto
         * the Cartesian axis planes is normal.
         *
         * @param seq the sequence of coordinates for the polygon
         * @return a normal vector
         */
        private static Vector3D AverageNormal(CoordinateSequence seq)
        {
            int n   = seq.Count;
            var sum = new CoordinateZ(0, 0, 0);
            var p1  = new CoordinateZ(0, 0, 0);
            var p2  = new CoordinateZ(0, 0, 0);

            for (int i = 0; i < n - 1; i++)
            {
                seq.GetCoordinate(i, p1);
                seq.GetCoordinate(i + 1, p2);
                sum.X += (p1.Y - p2.Y) * (p1.Z + p2.Z);
                sum.Y += (p1.Z - p2.Z) * (p1.X + p2.X);
                sum.Z += (p1.X - p2.X) * (p1.Y + p2.Y);
            }
            sum.X /= n;
            sum.Y /= n;
            sum.Z /= n;
            var norm = Vector3D.Create(sum).Normalize();

            return(norm);
        }
        private Coordinate[] ReducePointwise(CoordinateSequence coordinates)
        {
            var coordReduce = new Coordinate[coordinates.Count];

            // copy coordinates and reduce
            for (int i = 0; i < coordinates.Count; i++)
            {
                var coord = coordinates.GetCoordinate(i).Copy();
                _targetPm.MakePrecise(coord);
                coordReduce[i] = coord;
            }

            return(coordReduce);
        }
        // Use map to restore M values on the coordinate array
        private CoordinateSequence restoreDim4(CoordinateSequence cs, Dictionary <Coordinate, Double> map)
        {
            CoordinateSequence seq = new PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.PackedType.Double).Create(cs.Count, 4);

            for (int i = 0; i < cs.Count; i++)
            {
                seq.SetOrdinate(i, 0, cs.GetOrdinate(i, 0));
                seq.SetOrdinate(i, 1, cs.GetOrdinate(i, 1));
                seq.SetOrdinate(i, 2, cs.GetOrdinate(i, 2));
                Double d = map[cs.GetCoordinate(i)];
                seq.SetOrdinate(i, 3, d == null ? Double.NaN : d);
            }
            return(seq);
        }
예제 #20
0
        protected bool IsAllCoordsEqual(CoordinateSequence seq, Coordinate coord)
        {
            for (int i = 0; i < seq.Count; i++)
            {
                if (!coord.Equals(seq.GetCoordinate(i)))
                {
                    return(false);
                }

                if (coord.X != seq.GetOrdinate(i, 0))
                {
                    return(false);
                }
                if (coord.Y != seq.GetOrdinate(i, 1))
                {
                    return(false);
                }
                if (seq.HasZ)
                {
                    if (coord.Z != seq.GetZ(i))
                    {
                        return(false);
                    }
                }
                if (seq.HasM)
                {
                    if (coord.M != seq.GetM(i))
                    {
                        return(false);
                    }
                }
                if (seq.Dimension > 2)
                {
                    if (coord[2] != seq.GetOrdinate(i, 2))
                    {
                        return(false);
                    }
                }
                if (seq.Dimension > 3)
                {
                    if (coord[3] != seq.GetOrdinate(i, 3))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
        private Coordinate[] ReduceCompress(CoordinateSequence coordinates)
        {
            var noRepeatCoordList = new CoordinateList();

            // copy coordinates and reduce
            for (int i = 0; i < coordinates.Count; i++)
            {
                var coord = coordinates.GetCoordinate(i).Copy();
                _targetPm.MakePrecise(coord);
                noRepeatCoordList.Add(coord, false);
            }

            // remove repeated points, to simplify returned geometry as much as possible
            var noRepeatCoords = noRepeatCoordList.ToCoordinateArray();

            return(noRepeatCoords);
        }
예제 #22
0
                public void Filter(CoordinateSequence seq, int i)
                {
                    if (seq == null)
                    {
                        throw new ArgumentNullException();
                    }

                    if (seq.Count == 1)
                    {
                        return;
                    }

                    if (i > seq.Count - 2)
                    {
                        return;
                    }

                    LineSegment currentSegment;
                    SpikeFix    spikeFix;
                    int         index;

                    if (i == 0)
                    {
                        currentSegment = new LineSegment(seq.GetCoordinate(0), seq.GetCoordinate(1));
                        if (IsClosed(seq))
                        {
                            _lastSegment = new LineSegment(seq.GetCoordinate(seq.Count - 2), seq.GetCoordinate(0));
                            spikeFix     = CheckSpike(_lastSegment, currentSegment);
                            if (spikeFix != SpikeFix.NoSpike)
                            {
                                index = spikeFix == SpikeFix.First ? seq.Count - 2 : 1;
                                FixSpike(seq, seq.Count - 1, index);
                                FixSpike(seq, 0, index);
                                _changed = true;
                            }
                        }
                        _lastSegment = currentSegment;
                        return;
                    }

                    currentSegment = new LineSegment(_lastSegment.P1, seq.GetCoordinate(i + 1));

                    spikeFix = CheckSpike(_lastSegment, currentSegment);
                    if (spikeFix != SpikeFix.NoSpike)
                    {
                        index = i + (int)spikeFix;
                        FixSpike(seq, i, index);

                        _changed = true;
                    }
                    _lastSegment = new LineSegment(seq.GetCoordinate(i), seq.GetCoordinate(i + 1));
                }
        private static void DoTest(CoordinateSequence forward, CoordinateSequence reversed)
        {
            const double eps = 1e-12;

            Assert.AreEqual(forward.Count, reversed.Count, "Coordinate sequences don't have same size");
            Assert.AreEqual(forward.Ordinates, reversed.Ordinates, "Coordinate sequences don't serve same ordinate values");

            var ordinates = ToOrdinateArray(forward.Ordinates);
            int j         = forward.Count;

            for (int i = 0; i < forward.Count; i++)
            {
                j--;
                foreach (var ordinate in ordinates)
                {
                    Assert.AreEqual(forward.GetOrdinate(i, ordinate), reversed.GetOrdinate(j, ordinate), eps, string.Format("{0} values are not within tolerance", ordinate));
                }
                var cf = forward.GetCoordinate(i);
                var cr = reversed.GetCoordinate(j);

                Assert.IsFalse(ReferenceEquals(cf, cr), "Coordinate sequences deliver same coordinate instances");
                Assert.IsTrue(cf.Equals(cr), "Coordinate sequences do not provide equal coordinates");
            }
        }
예제 #24
0
        /// <summary>
        /// Computes whether a ring defined by an <see cref="CoordinateSequence"/> is
        /// oriented counter-clockwise.
        /// <list type="Bullet">
        /// <item>The list of points is assumed to have the first and last points equal.</item>
        /// <item>This will handle coordinate lists which contain repeated points.</item>
        /// </list>
        /// This algorithm is <b>only</b> 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">A <c>CoordinateSequence</c>s forming a ring.</param>
        /// <returns><c>true</c> if the ring is oriented counter-clockwise.</returns>
        /// <exception cref="ArgumentException">Thrown if there are too few points to determine orientation (&lt; 4)</exception>
        public static bool IsCCW(CoordinateSequence ring)
        {
            // # of points without closing endpoint
            int nPts = ring.Count - 1;

            // sanity check
            if (nPts < 3)
            {
                throw new ArgumentException(
                          "Ring has fewer than 4 points, so orientation cannot be determined",
                          nameof(ring));
            }

            // find highest point
            var hiPt    = ring.GetCoordinate(0);
            int hiIndex = 0;

            for (int i = 1; i <= nPts; i++)
            {
                var p = ring.GetCoordinate(i);
                if (p.Y > hiPt.Y)
                {
                    hiPt    = ring.GetCoordinate(i);
                    hiIndex = i;
                }
            }

            // find distinct point before highest point
            Coordinate prev;
            int        iPrev = hiIndex;

            do
            {
                iPrev = iPrev - 1;
                if (iPrev < 0)
                {
                    iPrev = nPts;
                }
                prev = ring.GetCoordinate(iPrev);
            } while (prev.Equals2D(hiPt) && iPrev != hiIndex);

            // find distinct point after highest point
            Coordinate next;
            int        iNext = hiIndex;

            do
            {
                iNext = (iNext + 1) % nPts;
                next  = ring.GetCoordinate(iNext);
            } while (next.Equals2D(hiPt) && iNext != hiIndex);

            /**
             * 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);
            }

            var disc = Index(prev, 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 == OrientationIndex.Collinear)
            {
                // polygon is CCW if previous 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);
        }
        /**
         * Returns a coordinateSequence free of Coordinates with X or Y NaN value,
         * and if desired, free of duplicated coordinates. makeSequenceValid keeps
         * the original dimension of input sequence.
         *
         * @param sequence input sequence of coordinates
         * @param preserveDuplicateCoord if duplicate coordinates must be preserved
         * @param close if the sequence must be closed
         * @return a new CoordinateSequence with valid XY values
         */
        private static CoordinateSequence makeSequenceValid(CoordinateSequence sequence,
                                                            bool preserveDuplicateCoord, bool close)
        {
            int dim = sequence.Dimension;

            // we Add 1 to the sequence size for the case where we have to close the linear ring
            double[] array    = new double[(sequence.Count + 1) * sequence.Dimension];
            bool     modified = false;
            int      count    = 0;

            // Iterate through coordinates, skip points with x=NaN, y=NaN or duplicate
            for (int i = 0; i < sequence.Count; i++)
            {
                if (Double.IsNaN(sequence.GetOrdinate(i, 0)) || Double.IsNaN(sequence.GetOrdinate(i, 1)))
                {
                    modified = true;
                    continue;
                }
                if (!preserveDuplicateCoord && count > 0 && sequence.GetCoordinate(i).Equals(sequence.GetCoordinate(i - 1)))
                {
                    modified = true;
                    continue;
                }
                for (int j = 0; j < dim; j++)
                {
                    array[count * dim + j] = sequence.GetOrdinate(i, j);
                    if (j == dim - 1)
                    {
                        count++;
                    }
                }
            }
            // Close the sequence if it is not closed and there is already 3 distinct coordinates
            if (close && count > 2 && (array[0] != array[(count - 1) * dim] || array[1] != array[(count - 1) * dim + 1]))
            {
                System.Array.Copy(array, 0, array, count * dim, dim);
                modified = true;
                count++;
            }
            // Close z, m dimension if needed
            if (close && count > 3 && dim > 2)
            {
                for (int d = 2; d < dim; d++)
                {
                    if (array[(count - 1) * dim + d] != array[d])
                    {
                        modified = true;
                    }
                    array[(count - 1) * dim + d] = array[d];
                }
            }
            if (modified)
            {
                double[] shrinkedArray = new double[count * dim];
                System.Array.Copy(array, 0, shrinkedArray, 0, count * dim);
                return(PackedCoordinateSequenceFactory.DoubleFactory.Create(shrinkedArray, dim));
            }
            else
            {
                return(sequence);
            }
        }
예제 #26
0
 /// <summary>
 /// Gets the coordinate at the given index
 /// </summary>
 /// <param name="index">The index</param>
 /// <returns>The coordinate at the given index</returns>
 public Coordinate GetCoordinate(int index)
 {
     return(_pts.GetCoordinate(_start + index));
 }
예제 #27
0
        /// <summary>
        /// Tests for equality using all supported accessors,
        /// to provides test coverage for them.
        /// </summary>
        /// <param name="seq"></param>
        /// <param name="coords"></param>
        /// <returns></returns>
        protected bool IsEqual(CoordinateSequence seq, Coordinate[] coords)
        {
            if (seq.Count != coords.Length)
            {
                return(false);
            }

            // carefully get coordinate of the same type as the sequence
            var p = seq.CreateCoordinate();

            for (int i = 0; i < seq.Count; i++)
            {
                if (!coords[i].Equals(seq.GetCoordinate(i)))
                {
                    return(false);
                }

                // Ordinate named getters
                if (!coords[i].X.Equals(seq.GetX(i)))
                {
                    return(false);
                }
                if (!coords[i].Y.Equals(seq.GetY(i)))
                {
                    return(false);
                }
                if (seq.HasZ)
                {
                    if (!coords[i].Z.Equals(seq.GetZ(i)))
                    {
                        return(false);
                    }
                }
                if (seq.HasM)
                {
                    if (!coords[i].M.Equals(seq.GetM(i)))
                    {
                        return(false);
                    }
                }

                // Ordinate indexed getters
                if (!coords[i].X.Equals(seq.GetOrdinate(i, 0)))
                {
                    return(false);
                }
                if (!coords[i].Y.Equals(seq.GetOrdinate(i, 1)))
                {
                    return(false);
                }
                if (seq.Dimension > 2)
                {
                    if (!coords[i][2].Equals(seq.GetOrdinate(i, 2)))
                    {
                        return(false);
                    }
                }
                if (seq.Dimension > 3)
                {
                    if (!coords[i][3].Equals(seq.GetOrdinate(i, 3)))
                    {
                        return(false);
                    }
                }

                // Coordinate getter
                seq.GetCoordinate(i, p);
                if (!coords[i].X.Equals(p.X))
                {
                    return(false);
                }
                if (!coords[i].Y.Equals(p.Y))
                {
                    return(false);
                }
                if (seq.HasZ)
                {
                    if (!coords[i].Z.Equals(p.Z))
                    {
                        return(false);
                    }
                }
                if (seq.HasM)
                {
                    if (!coords[i].M.Equals(p.M))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
예제 #28
0
 private static bool IsClosed(CoordinateSequence seq)
 {
     return(seq.GetCoordinate(seq.Count - 1).Equals2D(seq.GetCoordinate(0)));
 }
예제 #29
0
        /// <summary>
        /// Tests if a ring defined by a <see cref="CoordinateSequence"/> is
        /// oriented counter-clockwise.
        /// <list type="bullet">
        /// <item><description>The list of points is assumed to have the first and last points equal.</description></item>
        /// <item><description>This handles coordinate lists which contain repeated points.</description></item>
        /// <item><description>This handles rings which contain collapsed segments (in particular, along the top of the ring).</description></item>
        /// </list>
        /// This algorithm is guaranteed to work with valid rings.
        /// It also works with "mildly invalid" rings
        /// which contain collapsed(coincident) flat segments along the top of the ring.
        /// If the ring is "more" invalid (e.g.self-crosses or touches),
        /// the computed result may not be correct.
        /// </summary>
        /// <param name="ring">A <c>CoordinateSequence</c>s forming a ring (with first and last point identical).</param>
        /// <returns><c>true</c> if the ring is oriented counter-clockwise.</returns>
        /// <exception cref="ArgumentException">Thrown if there are too few points to determine orientation (&lt; 4)</exception>
        public static bool IsCCW(CoordinateSequence ring)
        {
            // # of points without closing endpoint
            int nPts = ring.Count - 1;

            // sanity check
            if (nPts < 3)
            {
                throw new ArgumentException(
                          "Ring has fewer than 4 points, so orientation cannot be determined", nameof(ring));
            }

            /*
             * Find first highest point after a lower point, if one exists
             * (e.g. a rising segment)
             * If one does not exist, hiIndex will remain 0
             * and the ring must be flat.
             * Note this relies on the convention that
             * rings have the same start and end point.
             */
            var        upHiPt  = ring.GetCoordinate(0);
            double     prevY   = upHiPt.Y;
            Coordinate upLowPt = null;
            int        iUpHi   = 0;

            for (int i = 1; i <= nPts; i++)
            {
                double py = ring.GetOrdinate(i, Ordinate.Y);

                /*
                 * If segment is upwards and endpoint is higher, record it
                 */
                if (py > prevY && py >= upHiPt.Y)
                {
                    upHiPt  = ring.GetCoordinate(i);
                    iUpHi   = i;
                    upLowPt = ring.GetCoordinate(i - 1);
                }
                prevY = py;
            }

            /*
             * Check if ring is flat and return default value if so
             */
            if (iUpHi == 0)
            {
                return(false);
            }

            /*
             * Find the next lower point after the high point
             * (e.g. a falling segment).
             * This must exist since ring is not flat.
             */
            int iDownLow = iUpHi;

            do
            {
                iDownLow = (iDownLow + 1) % nPts;
            } while (iDownLow != iUpHi && ring.GetOrdinate(iDownLow, Ordinate.Y) == upHiPt.Y);

            var downLowPt = ring.GetCoordinate(iDownLow);
            int iDownHi   = iDownLow > 0 ? iDownLow - 1 : nPts - 1;
            var downHiPt  = ring.GetCoordinate(iDownHi);

            /*
             * Two cases can occur:
             * 1) the hiPt and the downPrevPt are the same.
             *    This is the general position case of a "pointed cap".
             *    The ring orientation is determined by the orientation of the cap
             * 2) The hiPt and the downPrevPt are different.
             *    In this case the top of the cap is flat.
             *    The ring orientation is given by the direction of the flat segment
             */
            if (upHiPt.Equals2D(downHiPt))
            {
                /*
                 * Check for the case where the cap has configuration A-B-A.
                 * 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 (upLowPt.Equals2D(upHiPt) || downLowPt.Equals2D(upHiPt) || upLowPt.Equals2D(downLowPt))
                {
                    return(false);
                }

                /*
                 * It can happen that the top segments are coincident.
                 * This is an invalid ring, which cannot be computed correctly.
                 * In this case the orientation is 0, and the result is false.
                 */
                var index = Index(upLowPt, upHiPt, downLowPt);
                return(index == OrientationIndex.CounterClockwise);
            }
            else
            {
                /*
                 * Flat cap - direction of flat top determines orientation
                 */
                double delX = downHiPt.X - upHiPt.X;
                return(delX < 0);
            }
        }