예제 #1
0
        private static CoordinateSequence CreateSequence(Ordinates ordinateFlags, double[] xy)
        {
            // get the number of dimension to verify size of provided ordinate values array
            int dimension = RequiredDimension(ordinateFlags);

            // inject additional values
            double[] ordinateValues = InjectZM(ordinateFlags, xy);

            // get the required size of the sequence
            int size = Math.DivRem(ordinateValues.Length, dimension, out int remainder);

            if (remainder != 0)
            {
                throw new ArgumentException("ordinateFlags and number of provided ordinate values don't match");
            }

            // create a sequence capable of storing all ordinate values.
            var res = GetCSFactory(ordinateFlags)
                      .Create(size, RequiredDimension(ordinateFlags), OrdinatesUtility.OrdinatesToMeasures(ordinateFlags));

            // fill in values
            int k = 0;

            for (int i = 0; i < ordinateValues.Length; i += dimension)
            {
                for (int j = 0; j < dimension; j++)
                {
                    res.SetOrdinate(k, j, ordinateValues[i + j]);
                }

                k++;
            }

            return(res);
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RawCoordinateSequenceFactory"/> class.
        /// </summary>
        /// <param name="ordinateGroups">
        /// A sequence of zero or more <see cref="Ordinates"/> flags representing ordinate values
        /// that should be allocated together.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when <paramref name="ordinateGroups"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when a given flag appears in more than one element of
        /// <paramref name="ordinateGroups"/>.
        /// </exception>
        /// <remarks>
        /// Any flags not represented in <paramref name="ordinateGroups"/>, and any spatial or
        /// measure dimensions beyond the 16th, will be allocated together, SoA-style.
        /// <para/>
        /// Elements without any bits set will be silently ignored.
        /// </remarks>
        public RawCoordinateSequenceFactory(IEnumerable <Ordinates> ordinateGroups)
        {
            if (ordinateGroups is null)
            {
                throw new ArgumentNullException(nameof(ordinateGroups));
            }

            var seenOrdinates      = Ordinates.None;
            var ordinateGroupsList = new List <Ordinates>();

            foreach (var ordinateGroup in ordinateGroups)
            {
                if ((ordinateGroup & seenOrdinates) != Ordinates.None)
                {
                    throw new ArgumentException("Each ordinate may show up in at most one group.", nameof(ordinateGroups));
                }

                seenOrdinates |= ordinateGroup;

                if (OrdinatesUtility.OrdinatesToDimension(ordinateGroup) < 2)
                {
                    // it would have been equally correct to omit this
                    continue;
                }

                _ordinatesInGroups |= ordinateGroup;
                ordinateGroupsList.Add(ordinateGroup);
            }

            _ordinateGroups = ordinateGroupsList.ToArray();
        }
예제 #3
0
        protected static ICoordinateSequence AddCoordinateToSequence(ICoordinateSequence sequence,
                                                                     ICoordinateSequenceFactory factory,
                                                                     double x, double y, double?z, double?m)
        {
            // Create a new sequence
            var newSequence = factory.Create(sequence.Count + 1, sequence.Ordinates);

            // Copy old values
            var ordinates = OrdinatesUtility.ToOrdinateArray(sequence.Ordinates);

            for (var i = 0; i < sequence.Count; i++)
            {
                foreach (var ordinate in ordinates)
                {
                    newSequence.SetOrdinate(i, ordinate, sequence.GetOrdinate(i, ordinate));
                }
            }

            // new coordinate
            newSequence.SetOrdinate(sequence.Count, Ordinate.X, x);
            newSequence.SetOrdinate(sequence.Count, Ordinate.Y, y);
            if (z.HasValue)
            {
                newSequence.SetOrdinate(sequence.Count, Ordinate.Z, z.Value);
            }
            if (m.HasValue)
            {
                newSequence.SetOrdinate(sequence.Count, Ordinate.M, m.Value);
            }

            return(newSequence);
        }
예제 #4
0
        /// <summary>
        /// Gets an array of <see cref="System.Double"/> ordinate values
        /// </summary>
        /// <param name="ordinate">The ordinate index</param>
        /// <returns>An array of ordinate values</returns>
        public override double[] GetOrdinates(Ordinate ordinate)
        {
            if (IsEmpty)
            {
                return(new double[0]);
            }

            var ordinateFlag = OrdinatesUtility.ToOrdinatesFlag(ordinate);

            if ((_shell.CoordinateSequence.Ordinates & ordinateFlag) != ordinateFlag)
            {
                return(CreateArray(NumPoints, Coordinate.NullOrdinate));
            }

            var result    = new double[NumPoints];
            var ordinates = _shell.GetOrdinates(ordinate);

            Array.Copy(ordinates, 0, result, 0, ordinates.Length);
            var offset = ordinates.Length;

            foreach (var linearRing in _holes)
            {
                ordinates = linearRing.GetOrdinates(ordinate);
                Array.Copy(ordinates, 0, result, offset, ordinates.Length);
                offset += ordinates.Length;
            }

            return(result);
        }
예제 #5
0
        /// <summary>
        /// Writes a binary encoded PostGIS of the given <paramref name="geometry"/> to to an array of bytes.
        /// </summary>
        /// <param name="geometry">The geometry</param>
        /// <param name="ordinates">The ordinates of each geometry's coordinate. <see cref="Ordinates.XY"/> area always written.</param>
        /// <returns>An array of bytes.</returns>
        private byte[] Write(IGeometry geometry, Ordinates ordinates)
        {
            var coordinateSpace = 8 * OrdinatesUtility.OrdinatesToDimension(ordinates);
            var bytes           = GetBytes(geometry, coordinateSpace);

            Write(geometry, ordinates, new MemoryStream(bytes));

            return(bytes);
        }
        /// <summary>
        /// Writes out a given <see cref="Geometry"/> to a byte array.
        /// </summary>
        /// <param name="geometry">The <see cref="Geometry"/> to write.</param>
        /// <returns>The byte array.</returns>
        public byte[] Write(Geometry geometry)
        {
            var maxCoords       = HandleOrdinates == Ordinates.None ? Ordinates.XYZM : HandleOrdinates;
            int coordinateSpace = 8 * OrdinatesUtility.OrdinatesToDimension(maxCoords & CheckOrdinates(geometry));

            byte[] bytes = GetBytes(geometry, coordinateSpace);
            Write(geometry, new MemoryStream(bytes));

            return(bytes);
        }
        /// <summary>
        /// Creates an instance of this class
        /// </summary>
        /// <param name="coordinates">The coordinates</param>
        /// <param name="ordinates"></param>
        public DotSpatialAffineCoordinateSequence(IReadOnlyCollection <Coordinate> coordinates, Ordinates ordinates)
            : base(coordinates?.Count ?? 0, OrdinatesUtility.OrdinatesToDimension(ordinates & Ordinates.XYZM), OrdinatesUtility.OrdinatesToMeasures(ordinates & Ordinates.XYZM))
        {
            coordinates = coordinates ?? Array.Empty <Coordinate>();

            _xy = new double[2 * coordinates.Count];
            if (HasZ)
            {
                _z = new double[coordinates.Count];
            }

            if (HasM)
            {
                _m = new double[coordinates.Count];
            }

            var xy = MemoryMarshal.Cast <double, XYStruct>(_xy);

            using (var coordinatesEnumerator = coordinates.GetEnumerator())
            {
                for (int i = 0; i < xy.Length; i++)
                {
                    if (!coordinatesEnumerator.MoveNext())
                    {
                        ThrowForInconsistentCount();
                    }

                    var coordinate = coordinatesEnumerator.Current;

                    xy[i].X = coordinate.X;
                    xy[i].Y = coordinate.Y;
                    if (_z != null)
                    {
                        _z[i] = coordinate.Z;
                    }

                    if (_m != null)
                    {
                        _m[i] = coordinate.M;
                    }
                }

                if (coordinatesEnumerator.MoveNext())
                {
                    ThrowForInconsistentCount();
                }
            }

            void ThrowForInconsistentCount() => throw new ArgumentException("IReadOnlyCollection<T>.Count is inconsistent with IEnumerable<T> implementation.", nameof(coordinates));
        }
예제 #8
0
            private static IGeometry CreatePoint(Ordinates ordinates, bool empty)
            {
                if (empty)
                {
                    return(Factory.CreatePoint((ICoordinateSequence)null));
                }

                var seq = CsFactory.Create(1, ordinates);

                foreach (var o in OrdinatesUtility.ToOrdinateArray(ordinates))
                {
                    seq.SetOrdinate(0, o, RandomOrdinate(o, Factory.PrecisionModel));
                }
                return(Factory.CreatePoint(seq));
            }
        /// <summary>
        /// Constructs a sequence of a given size, populated with new Coordinates.
        /// </summary>
        /// <param name="size">The size of the sequence to create.</param>
        /// <param name="ordinates">The kind of ordinates.</param>
        public DotSpatialAffineCoordinateSequence(int size, Ordinates ordinates)
            : base(size, OrdinatesUtility.OrdinatesToDimension(ordinates & Ordinates.XYZM), OrdinatesUtility.OrdinatesToMeasures(ordinates & Ordinates.XYZM))
        {
            _xy = new double[2 * size];

            if (HasZ)
            {
                _z = NullOrdinateArray(size);
            }

            if (HasM)
            {
                _m = NullOrdinateArray(size);
            }
        }
        private static Ordinate[] ToOrdinateArray(Ordinates ordinates)
        {
            var result    = new Ordinate[OrdinatesUtility.OrdinatesToDimension(ordinates)];
            int nextIndex = 0;

            for (int i = 0; i < 32; i++)
            {
                if (ordinates.HasFlag((Ordinates)(1 << i)))
                {
                    result[nextIndex++] = (Ordinate)i;
                }
            }

            return(result);
        }
예제 #11
0
        public override double[] GetOrdinates(Ordinate ordinate)
        {
            if (IsEmpty)
            {
                return(new double[0]);
            }

            var ordinateFlag = OrdinatesUtility.ToOrdinatesFlag(ordinate);

            if ((_points.Ordinates & ordinateFlag) != ordinateFlag)
            {
                return(CreateArray(_points.Count, Coordinate.NullOrdinate));
            }

            return(CreateArray(_points, ordinate));
        }
예제 #12
0
        /// <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 ICoordinateSequence EnsureClosedSequence(ICoordinateSequence sequence,
                                                                ICoordinateSequenceFactory 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);
            var 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.SetOrdinate(lastIndex, Ordinate.X, start.X);
                sequence.SetOrdinate(lastIndex, Ordinate.Y, start.Y);
                return(sequence);
            }

            // 2. Close the sequence by adding a new point, this is heavier
            var newSequence = factory.Create(sequence.Count + 1, sequence.Ordinates);
            var ordinates   = OrdinatesUtility.ToOrdinateArray(sequence.Ordinates);

            for (var i = 0; i < sequence.Count; i++)
            {
                foreach (var ordinate in ordinates)
                {
                    newSequence.SetOrdinate(i, ordinate, sequence.GetOrdinate(i, ordinate));
                }
            }
            foreach (var ordinate in ordinates)
            {
                newSequence.SetOrdinate(sequence.Count, ordinate, sequence.GetOrdinate(0, ordinate));
            }
            return(newSequence);
        }
        /// <summary>
        /// Creates a sequence based on the given coordinate sequence.
        /// </summary>
        /// <param name="coordSeq">The coordinate sequence.</param>
        /// <param name="ordinates">The ordinates to copy</param>
        public DotSpatialAffineCoordinateSequence(CoordinateSequence coordSeq, Ordinates ordinates)
            : base(coordSeq?.Count ?? 0, OrdinatesUtility.OrdinatesToDimension(ordinates & Ordinates.XYZM), OrdinatesUtility.OrdinatesToMeasures(ordinates & Ordinates.XYZM))
        {
            if (coordSeq is DotSpatialAffineCoordinateSequence dsCoordSeq)
            {
                _xy = (double[])dsCoordSeq._xy.Clone();

                if (HasZ)
                {
                    _z = ((double[])dsCoordSeq._z?.Clone()) ?? NullOrdinateArray(Count);
                }

                if (HasM)
                {
                    _m = ((double[])dsCoordSeq._m?.Clone()) ?? NullOrdinateArray(Count);
                }
            }
            else
            {
                _xy = new double[2 * Count];
                if (HasZ)
                {
                    _z = new double[Count];
                }

                if (HasM)
                {
                    _m = new double[Count];
                }

                var xy = MemoryMarshal.Cast <double, XYStruct>(_xy);
                for (int i = 0; i < xy.Length; i++)
                {
                    xy[i].X = coordSeq.GetX(i);
                    xy[i].Y = coordSeq.GetY(i);
                    if (_z != null)
                    {
                        _z[i] = coordSeq.GetZ(i);
                    }

                    if (_m != null)
                    {
                        _m[i] = coordSeq.GetM(i);
                    }
                }
            }
        }
예제 #14
0
        public override double[] GetOrdinates(Ordinate ordinate)
        {
            if (IsEmpty)
            {
                return(new double[0]);
            }

            var ordinateFlag = OrdinatesUtility.ToOrdinatesFlag(ordinate);

            if ((_coordinates.Ordinates & ordinateFlag) != ordinateFlag)
            {
                return new[] { Coordinate.NullOrdinate }
            }
            ;

            return(new [] { _coordinates.GetOrdinate(0, ordinate) });
        }
예제 #15
0
            private static IGeometry CreateMultiPoint(Ordinates ordinates, bool empty)
            {
                if (empty)
                {
                    return(Factory.CreateMultiPoint((ICoordinateSequence)null));
                }
                int numPoints = Rnd.Next(75, 101);
                var seq       = CsFactory.Create(numPoints, ordinates);

                for (int i = 0; i < numPoints; i++)
                {
                    foreach (var o in OrdinatesUtility.ToOrdinateArray(ordinates))
                    {
                        seq.SetOrdinate(i, o, RandomOrdinate(o, Factory.PrecisionModel));
                    }
                }

                return(Factory.CreateMultiPoint(seq));
            }
        /// <summary>
        /// Transforms a <see cref="MultiPoint" /> object.
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="points"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        public static IMultiPoint TransformMultiPoint(IGeometryFactory factory,
                                                      IMultiPoint points, IMathTransform transform)
        {
            //We assume the first point holds all the ordinates
            var ordinateFlags = ((IPoint)points.GetGeometryN(0)).CoordinateSequence.Ordinates;
            var ordinates     = OrdinatesUtility.ToOrdinateArray(ordinateFlags);
            var coordSequence = factory.CoordinateSequenceFactory.Create(points.NumPoints, ordinateFlags);

            for (var i = 0; i < points.NumGeometries; i++)
            {
                var seq = ((IPoint)points.GetGeometryN(i)).CoordinateSequence;
                foreach (var ordinate in ordinates)
                {
                    coordSequence.SetOrdinate(i, ordinate, seq.GetOrdinate(i, ordinate));
                }
            }
            var transPoints = transform.Transform(coordSequence);

            return(factory.CreateMultiPoint(transPoints));
        }
예제 #17
0
        private static void TestCoordinateSequences(ICoordinateSequence orig, ICoordinateSequence trans)
        {
            Assert.AreNotSame(orig, trans, "Seqences are same");

            Assert.AreEqual(orig.Count, trans.Count, "Sequences have different lengths");
            Assert.AreEqual(orig.Ordinates, trans.Ordinates, "Sequences provide different ordinates");

            var ordinates = OrdinatesUtility.ToOrdinateArray(orig.Ordinates);

            for (var i = 0; i < orig.Count; i++)
            {
                foreach (var ordinate in ordinates)
                {
                    var v1 = orig.GetOrdinate(i, ordinate);
                    var v2 = trans.GetOrdinate(i, ordinate);

                    if (double.IsNaN(v1))
                    {
                        Assert.IsTrue(double.IsNaN(v2));
                        continue;
                    }

                    if (double.IsPositiveInfinity(v1))
                    {
                        Assert.IsTrue(double.IsPositiveInfinity(v2));
                        continue;
                    }
                    if (double.IsNegativeInfinity(v1))
                    {
                        Assert.IsTrue(double.IsNegativeInfinity(v2));
                        continue;
                    }

                    Assert.AreNotEqual(v1, v2, "Sequences provide equal value for '{0}'", ordinate);
                }
            }
        }
        private static void DoTest(ICoordinateSequence forward, ICoordinateSequence 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 = OrdinatesUtility.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");
            }
        }
 /// <summary>
 /// Creates a <see cref="ICoordinateSequence" /> of the specified size and ordinates.
 /// For this to be useful, the <see cref="ICoordinateSequence" /> implementation must be mutable.
 /// </summary>
 /// <param name="size">The number of coordinates</param>
 /// <param name="ordinates">
 /// The ordinates each coordinate has. <see cref="Ordinates.XY"/> is fix, <see cref="Ordinates.Z"/> and <see cref="Ordinates.M"/> can be set.
 /// </param>
 /// <returns></returns>
 public ICoordinateSequence Create(int size, Ordinates ordinates)
 {
     return(Create(size, OrdinatesUtility.OrdinatesToDimension(ordinates)));
 }
예제 #20
0
 private static bool HasOrdinate(ICoordinateSequence seq, Ordinate ordinate)
 {
     return((seq.Ordinates & OrdinatesUtility.ToOrdinatesFlag(new[] { ordinate })) != Ordinates.None);
 }
 /// <summary>
 /// Creates a <see cref="ICoordinateSequence" /> of the specified size and dimension.
 /// For this to be useful, the <see cref="ICoordinateSequence" /> implementation must be mutable.
 /// </summary>
 /// <param name="size"></param>
 /// <param name="dimension">the dimension of the coordinates in the sequence
 /// (if user-specifiable, otherwise ignored)</param>
 /// <returns>A coordinate sequence</returns>
 public ICoordinateSequence Create(int size, int dimension)
 {
     return(new DotSpatialAffineCoordinateSequence(size, OrdinatesUtility.DimensionToOrdinates(dimension)));
 }