1 /**********************************************************************
2  *
3  * GEOS - Geometry Engine Open Source
4  * http://geos.osgeo.org
5  *
6  * Copyright (C) 2006 Refractions Research Inc.
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU Lesser General Public Licence as published
10  * by the Free Software Foundation.
11  * See the COPYING file for more information.
12  *
13  **********************************************************************/
14 
15 #ifndef GEOS_GEOM_COORDINATESEQUENCE_H
16 #define GEOS_GEOM_COORDINATESEQUENCE_H
17 
18 #include <geos/export.h>
19 #include <geos/inline.h>
20 
21 #include <geos/geom/Coordinate.h> // for applyCoordinateFilter
22 
23 #include <vector>
24 #include <iosfwd> // ostream
25 #include <memory> // for unique_ptr typedef
26 
27 // Forward declarations
28 namespace geos {
29 namespace geom {
30 class Envelope;
31 class CoordinateFilter;
32 class Coordinate;
33 }
34 }
35 
36 namespace geos {
37 namespace geom { // geos::geom
38 
39 /**
40  * \class CoordinateSequence geom.h geos.h
41  *
42  * \brief
43  * The internal representation of a list of coordinates inside a Geometry.
44  *
45  * There are some cases in which you might want Geometries to store their
46  * points using something other than the GEOS Coordinate class. For example, you
47  * may want to experiment with another implementation, such as an array of Xs
48  * and an array of Ys. or you might want to use your own coordinate class, one
49  * that supports extra attributes like M-values.
50  *
51  * You can do this by implementing the CoordinateSequence and
52  * CoordinateSequenceFactory interfaces. You would then create a
53  * GeometryFactory parameterized by your CoordinateSequenceFactory, and use
54  * this GeometryFactory to create new Geometries. All of these new Geometries
55  * will use your CoordinateSequence implementation.
56  *
57  */
58 class GEOS_DLL CoordinateSequence {
59 
60 protected:
61 
CoordinateSequence()62     CoordinateSequence() {}
63 
CoordinateSequence(const CoordinateSequence &)64     CoordinateSequence(const CoordinateSequence&) {}
65 
66 public:
67 
68     typedef std::unique_ptr<CoordinateSequence> Ptr;
69 
70     virtual
~CoordinateSequence()71     ~CoordinateSequence() {}
72 
73     /** \brief
74      * Returns a deep copy of this collection.
75      */
76     virtual std::unique_ptr<CoordinateSequence> clone() const = 0;
77 
78     /** \brief
79      * Returns a read-only reference to Coordinate at position i.
80      *
81      * Whether or not the Coordinate returned is the actual underlying
82      * Coordinate or merely a copy depends on the implementation.
83      */
84     virtual const Coordinate& getAt(std::size_t i) const = 0;
85 
86     /// Return last Coordinate in the sequence
87     const Coordinate&
back()88     back() const
89     {
90         return getAt(size() - 1);
91     }
92 
93     /// Return first Coordinate in the sequence
94     const Coordinate&
front()95     front() const
96     {
97         return getAt(0);
98     }
99 
100     const Coordinate&
101     operator[](std::size_t i) const
102     {
103         return getAt(i);
104     }
105 
106     virtual Envelope getEnvelope() const;
107 
108     /** \brief
109      * Write Coordinate at position i to given Coordinate.
110      */
111     virtual void getAt(std::size_t i, Coordinate& c) const = 0;
112 
113     /** \brief
114      * Returns the number of Coordinates (actual or otherwise, as
115      * this implementation may not store its data in Coordinate objects).
116      */
117     virtual std::size_t getSize() const = 0;
118 
119     size_t
size()120     size() const
121     {
122         return getSize();
123     }
124 
125     /// Pushes all Coordinates of this sequence into the provided vector.
126     ///
127     /// This method is a port of the toCoordinateArray() method of JTS.
128     ///
129     virtual void toVector(std::vector<Coordinate>& coords) const = 0;
130 
131     /// Returns <code>true</code> it list contains no coordinates.
132     virtual bool isEmpty() const = 0;
133 
134     /// Copy Coordinate c to position pos
135     virtual void setAt(const Coordinate& c, std::size_t pos) = 0;
136 
137     /// Get a string representation of CoordinateSequence
138     std::string toString() const;
139 
140     /// Substitute Coordinate list with a copy of the given vector
141     virtual void setPoints(const std::vector<Coordinate>& v) = 0;
142 
143     /// Returns true if contains any two consecutive points
144     bool hasRepeatedPoints() const;
145 
146     /// Returns lower-left Coordinate in list
147     const Coordinate* minCoordinate() const;
148 
149     /** \brief
150      *  Returns true if given CoordinateSequence contains
151      *  any two consecutive Coordinate
152      */
153     static bool hasRepeatedPoints(const CoordinateSequence* cl);
154 
155     /** \brief
156      *  Returns either the given CoordinateSequence if its length
157      *  is greater than the given amount, or an empty CoordinateSequence.
158      */
159     static CoordinateSequence* atLeastNCoordinatesOrNothing(std::size_t n,
160             CoordinateSequence* c);
161 
162     /// Return position of a Coordinate, or -1 if not found
163     ///
164     /// FIXME: return std::size_t, using numeric_limits<std::size_t>::max
165     /// as 'not found' value.
166     ///
167     static size_t indexOf(const Coordinate* coordinate,
168                           const CoordinateSequence* cl);
169 
170     /**
171      * \brief
172      * Returns true if the two arrays are identical, both null,
173      * or pointwise equal
174      */
175     static bool equals(const CoordinateSequence* cl1,
176                        const CoordinateSequence* cl2);
177 
178     /// Scroll given CoordinateSequence so to start with given Coordinate.
179     static void scroll(CoordinateSequence* cl, const Coordinate* firstCoordinate);
180 
181     /** \brief
182      * Determines which orientation of the {@link Coordinate} array
183      * is (overall) increasing.
184      *
185      * In other words, determines which end of the array is "smaller"
186      * (using the standard ordering on {@link Coordinate}).
187      * Returns an integer indicating the increasing direction.
188      * If the sequence is a palindrome, it is defined to be
189      * oriented in a positive direction.
190      *
191      * @param pts the array of Coordinates to test
192      * @return <code>1</code> if the array is smaller at the start
193      * or is a palindrome,
194      * <code>-1</code> if smaller at the end
195      *
196      * NOTE: this method is found in CoordinateArrays class for JTS
197      */
198     static int increasingDirection(const CoordinateSequence& pts);
199 
200 
201     /** \brief
202     * Tests whether an array of {@link Coordinate}s forms a ring,
203     * by checking length and closure.
204     * Self-intersection is not checked.
205     *
206     * @param pts an array of Coordinates
207     * @return true if the coordinate form a ring.
208     */
209     static bool isRing(const CoordinateSequence *pts);
210 
211     /// Reverse Coordinate order in given CoordinateSequence
212     static void reverse(CoordinateSequence* cl);
213 
214     /// Standard ordinate index values
215     enum { X, Y, Z, M };
216 
217     /**
218      * Returns the dimension (number of ordinates in each coordinate)
219      * for this sequence.
220      *
221      * @return the dimension of the sequence.
222      */
223     virtual std::size_t getDimension() const = 0;
224 
hasZ()225     bool hasZ() const {
226         return getDimension() > 2;
227     }
228 
229     /**
230      * Returns the ordinate of a coordinate in this sequence.
231      * Ordinate indices 0 and 1 are assumed to be X and Y.
232      * Ordinates indices greater than 1 have user-defined semantics
233      * (for instance, they may contain other dimensions or measure values).
234      *
235      * @param index  the coordinate index in the sequence
236      * @param ordinateIndex the ordinate index in the coordinate
237      *                      (in range [0, dimension-1])
238      */
239     virtual double getOrdinate(std::size_t index, std::size_t ordinateIndex) const;
240 
241     /**
242      * Returns ordinate X (0) of the specified coordinate.
243      *
244      * @param index
245      * @return the value of the X ordinate in the index'th coordinate
246      */
247     virtual double
getX(std::size_t index)248     getX(std::size_t index) const
249     {
250         return getOrdinate(index, X);
251     }
252 
253     /**
254      * Returns ordinate Y (1) of the specified coordinate.
255      *
256      * @param index
257      * @return the value of the Y ordinate in the index'th coordinate
258      */
259     virtual double
getY(std::size_t index)260     getY(std::size_t index) const
261     {
262         return getOrdinate(index, Y);
263     }
264 
265 
266     /**
267      * Sets the value for a given ordinate of a coordinate in this sequence.
268      *
269      * @param index  the coordinate index in the sequence
270      * @param ordinateIndex the ordinate index in the coordinate
271      *                      (in range [0, dimension-1])
272      * @param value  the new ordinate value
273      */
274     virtual void setOrdinate(std::size_t index, std::size_t ordinateIndex, double value) = 0;
275 
276     /**
277      * Expands the given Envelope to include the coordinates in the
278      * sequence.
279      * Allows implementing classes to optimize access to coordinate values.
280      *
281      * @param env the envelope to expand
282      */
283     virtual void expandEnvelope(Envelope& env) const;
284 
285     virtual void apply_rw(const CoordinateFilter* filter) = 0; //Abstract
286     virtual void apply_ro(CoordinateFilter* filter) const = 0; //Abstract
287 
288     /** \brief
289      * Apply a filter to each Coordinate of this sequence.
290      * The filter is expected to provide a .filter(Coordinate&)
291      * method.
292      *
293      * TODO: accept a Functor instead, will be more flexible.
294      *       actually, define iterators on Geometry
295      */
296     template <class T>
297     void
applyCoordinateFilter(T & f)298     applyCoordinateFilter(T& f)
299     {
300         Coordinate c;
301         for(std::size_t i = 0, n = size(); i < n; ++i) {
302             getAt(i, c);
303             f.filter(c);
304             setAt(c, i);
305         }
306     }
307 
308 };
309 
310 GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateSequence& cs);
311 
312 GEOS_DLL bool operator== (const CoordinateSequence& s1, const CoordinateSequence& s2);
313 
314 GEOS_DLL bool operator!= (const CoordinateSequence& s1, const CoordinateSequence& s2);
315 
316 } // namespace geos::geom
317 } // namespace geos
318 
319 //#ifdef GEOS_INLINE
320 //# include "geos/geom/CoordinateSequence.inl"
321 //#endif
322 
323 #endif // ndef GEOS_GEOM_COORDINATESEQUENCE_H
324