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