1 #ifndef SQL_GIS_GEOMETRIES_H_INCLUDED
2 #define SQL_GIS_GEOMETRIES_H_INCLUDED
3 
4 // Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License, version 2.0,
8 // as published by the Free Software Foundation.
9 //
10 // This program is also distributed with certain software (including
11 // but not limited to OpenSSL) that is licensed under separate terms,
12 // as designated in a particular file or component or in included license
13 // documentation.  The authors of MySQL hereby grant you an additional
14 // permission to link the program and your derivative works with the
15 // separately licensed software that they have included with MySQL.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License, version 2.0, for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
25 
26 /// @file
27 ///
28 /// This file declares the geometry class hierarchy used by the server as the
29 /// internal representation of geometries.
30 ///
31 /// The hierarchy is closely modelled after the hierarchy in SFA-CA
32 /// (OGC 06-103r4), but since Boost.Geometry depends on type traits to
33 /// know if a geometry is in a Cartesian or geographic SRS, there are
34 /// Cartesian and geographic specializations of each instantiable type
35 /// in the SFA-CA. These are defined in geometries_cs.h.
36 ///
37 /// Because of Boost.Geometry, iterators have to be of coordinate system
38 /// specific types. It is therefore not possible to have the standard begin()
39 /// and end() iterators in the common superclass. Instead, operator[] is
40 /// provided as a coordinate system agnostic option.
41 ///
42 /// @see geometries_cs.h
43 
44 #include <cmath>
45 #include <cstdint>
46 
47 namespace gis {
48 
49 /// Types of geometry objects. Not all are instantiable.
50 ///
51 /// The values and the storage type are the same as used in WKB.
52 enum class Geometry_type : std::uint32_t {
53   kGeometry = 0,
54   kPoint = 1,
55   kLinestring = 2,
56   kPolygon = 3,
57   kMultipoint = 4,
58   kMultilinestring = 5,
59   kMultipolygon = 6,
60   kGeometrycollection = 7
61   // kMulticurve = 11,
62   // kMultisurface = 12,
63   // kCurve = 13,
64   // kSurface = 14,
65 };
66 
67 /// Types of coordinate systems.
68 enum class Coordinate_system {
69   /// A Cartesian plane with the same unit in both directions.
70   kCartesian = 0,
71   /// An ellipsoidal system with longitude and latitude coordinates,
72   /// both in the same unit.
73   kGeographic = 1
74 };
75 
76 /// Direction of a ring.
77 enum class Ring_direction {
78   /// Clockwise.
79   kCW = 0,
80   /// Counterclockwise.
81   kCCW = 1,
82   /// Unknown.
83   ///
84   /// Used only as an output value when the function is unable to determine the
85   /// ring direction, e.g., if the ring contains only repetitions of the same
86   /// point, or if there is a spike in the ring.
87   kUnknown = 2
88 };
89 
90 class Geometry_visitor;
91 
92 /// Abstract superclass for all geometric objects.
93 ///
94 /// Geometry is a non-instantiable type in SQL.
95 ///
96 /// The hierarchy is first divided into abstract classes according to the SFA-CA
97 /// geometry type hierarchy, and then divided into concrete subclasses for each
98 /// coordinate system.
99 class Geometry {
100  public:
101   Geometry() = default;
102   virtual ~Geometry() = default;
103   Geometry(const Geometry &) = default;
104   Geometry &operator=(const Geometry &) = default;
105 
106   /// Gets the geometry type of the object.
107   ///
108   /// @return The type of this object
109   virtual Geometry_type type() const = 0;
110 
111   /// Gets the coordinate system.
112   ///
113   /// @return The coordiante system type.
114   virtual Coordinate_system coordinate_system() const = 0;
115 
116   /// Applies a hierarchical visitor to this geometry.
117   ///
118   /// @see gis::Geometry_visitor
119   ///
120   /// @param v A hierarchical visitor.
121   ///
122   /// @retval true The execution was aborted by the visitor.
123   /// @retval false The execution completed.
124   virtual bool accept(Geometry_visitor *v) = 0;
125 
126   /// Check if this is an empty geometry.
127   ///
128   /// The definition of empty geometries is the one in SFA-CA (OGC 06-103r4,
129   /// Sect. 6.1.2.2), i.e., an empty point set.
130   ///
131   /// @note This is different from the function "empty", which returns true if a
132   /// geometry contains no subgeometries. E.g., a geometry collection may
133   /// contain another geometry collection which is empty. In this case, the
134   /// "empty" function would return false on the outermost geometry collection,
135   /// while "is_empty" would return true.
136   ///
137   /// @retval true The geometry represents the empty point set.
138   /// @retval false The geometry represent a non-empty point set.
139   virtual bool is_empty() const = 0;
140 };
141 
142 /// A 2d point.
143 ///
144 /// Point is an instantiable type in SQL.
145 class Point : public Geometry {
146  public:
Point()147   Point() : m_x(std::nan("")), m_y(std::nan("")) {}
Point(double x,double y)148   Point(double x, double y) : m_x(x), m_y(y) {}
type()149   Geometry_type type() const override { return Geometry_type::kPoint; }
150   bool accept(Geometry_visitor *v) override;
is_empty()151   bool is_empty() const override {
152     return (std::isnan(m_x) || std::isnan(m_y));
153   }
154 
155   /// Gets a coordinate value.
156   ///
157   /// This function signature must match the expectations of Boost.Geometry.
158   ///
159   /// @tparam K Coordinate number, zero indexed.
160   /// @return The coordinate value.
161   template <std::size_t K>
162   double get() const;
163 
164   /// Gets the first coordinate value.
165   ///
166   /// For geographic points, the first coordinate is longitude.
167   ///
168   /// @return The first coordinate value.
169   double x() const;
170 
171   /// Gets the second coordinate value.
172   ///
173   /// For geographic points, the second coordinate is latitude.
174   ///
175   /// @return The second coordinate value.
176   double y() const;
177 
178   /// Sets a coordinate.
179   ///
180   /// This function signature must match the expectations of Boost.Geometry.
181   ///
182   /// @tparam K Coordinate number, zero indexed.
183   /// @param d The coordinate value.
184   template <std::size_t K>
185   void set(double d);
186 
187   /// Sets the first coordinate value.
188   ///
189   /// For geographic points, the first coordinate is longitude.
190   ///
191   /// @param d The coordinate value.
192   void x(double d);
193 
194   /// Sets the second coordinate value.
195   ///
196   /// For geographic points, the second coordinate is latitude.
197   ///
198   /// @param d The coordinate value.
199   void y(double d);
200 
201  private:
202   /// First coordinate (X or longitude).
203   ///
204   /// Geographic coordinates are in radians, positive to the East of
205   /// Greenwich. Cartesian coordinates are in the SRSs length unit.
206   double m_x;
207 
208   /// Second coordinate (Y or latitude).
209   ///
210   /// Geographic coordinates are in radians, positive to the North of the
211   /// Equator. Cartesian coordinates are in the SRSs length unit.
212   double m_y;
213 };
214 
215 /// Compares two points.
216 ///
217 /// The point with the lowest X coordinate is the smaller point. If X
218 /// coordinates are equal, the point with the lowest Y coordinate is the
219 /// smaller.
220 ///
221 /// @param lhs Left hand side.
222 /// @param rhs Right hand side.
223 ///
224 /// @retval true Left hand side sorts before right hand side.
225 /// @retval false Left hand side does not sort before right hand side.
226 inline bool operator<(const Point &lhs, const Point &rhs) {
227   return (lhs.x() < rhs.x()) || (lhs.x() == rhs.x() && lhs.y() < rhs.y());
228 }
229 
230 /// An abstract 2d curve.
231 ///
232 /// Curve is a non-instantiable type in SQL.
233 class Curve : public Geometry {
234  public:
235   Geometry_type type() const override = 0;
236   bool accept(Geometry_visitor *v) override = 0;
237 };
238 
239 /// A string of connected line segments.
240 ///
241 /// Linestring is an instantiable type in SQL.
242 ///
243 /// According to the SFA-CA, linestrings have a linear interpolation between
244 /// points. In MySQL, a linestring represents the geodesic. On a plane, this is
245 /// linear interpolation, but on an ellipsoid, it's the shortest path along the
246 /// ellipsoid surface.
247 class Linestring : public Curve {
248  public:
type()249   Geometry_type type() const override { return Geometry_type::kLinestring; }
250   bool accept(Geometry_visitor *v) override = 0;
is_empty()251   bool is_empty() const override { return empty(); }
252 
253   /// Adds a point to the end of the linestring.
254   ///
255   /// @param pt The point to add.
256   virtual void push_back(const Point &pt) = 0;
257   virtual void push_back(Point &&pt) = 0;
258 
259   /// Checks if the linestring is empty.
260   ///
261   /// Here, the definition of empty is that the linestring does not contain any
262   /// points. An invalid linestring with only one coordinate is not empty.
263   ///
264   /// @retval true The linestring is empty.
265   /// @retval false The linestring is not empty.
266   virtual bool empty() const = 0;
267 
268   /// Returns the size of (number of points in) the linestring.
269   ///
270   /// @return Number of points in the linestring.
271   virtual std::size_t size() const = 0;
272 
273   /// Removes all points from the linestring.
274   virtual void clear() noexcept = 0;
275 
276   virtual Point &operator[](std::size_t i) = 0;
277   virtual const Point &operator[](std::size_t i) const = 0;
278 };
279 
280 /// A ring-shaped linestring.
281 ///
282 /// Linearring is a non-instantiable type in SQL. It is used to represent
283 /// polygon rings.
284 ///
285 /// The start and end point of the linestring must be the same (assumed, but not
286 /// enforced, by the implementation).
287 class Linearring : public Linestring {
288  public:
289   bool accept(Geometry_visitor *v) override = 0;
290 };
291 
292 /// An abstract 2d surface.
293 ///
294 /// Surface is a non-instantiable type in SQL.
295 class Surface : public Geometry {
296  public:
297   bool accept(Geometry_visitor *v) override = 0;
298 
299   Geometry_type type() const override = 0;
300 };
301 
302 /// A polygon consisting of an outer ring and zero or more interior rings
303 /// defining holes in the polygon.
304 ///
305 /// Polygon is an instantiable type in SQL.
306 ///
307 /// The interior rings must be inside the exterior ring (not enforced by the
308 /// implementation).
309 class Polygon : public Surface {
310  public:
type()311   Geometry_type type() const override { return Geometry_type::kPolygon; }
312   bool accept(Geometry_visitor *v) override = 0;
is_empty()313   bool is_empty() const override { return empty(); }
314 
315   /// Adds a linear ring to the polygon.
316   ///
317   /// The first ring will become the exterior ring. All following rings will be
318   /// interior rings (holes).
319   ///
320   /// @param lr The linear ring to add.
321   virtual void push_back(const Linearring &lr) = 0;
322   virtual void push_back(Linearring &&lr) = 0;
323 
324   /// Checks if the polygon is empty.
325   ///
326   /// The polygon is considered empty if it has no rings.
327   ///
328   /// @retval true The polygon is empty.
329   /// @retval false The polygon is not empty.
330   virtual bool empty() const = 0;
331 
332   /// Returns the size of the polygon.
333   ///
334   /// @return Number of rings in the polygon (exterior + interior).
335   virtual std::size_t size() const = 0;
336 
337   /// Returns the exterior ring of the polygon.
338   ///
339   /// @note If the polygon currently has no exterior ring, an empty one is
340   /// added.
341   ///
342   /// @return The exterior ring.
343   virtual Linearring &exterior_ring() = 0;
344 
345   /// Returns an interior ring of the polygon.
346   ///
347   /// @param n Ring number, zero indexed.
348   ///
349   /// @return The interior ring.
350   virtual Linearring &interior_ring(std::size_t n) = 0;
351 };
352 
353 /// A collection of geometries.
354 ///
355 /// Geometrycollection is an instantiable type in SQL. It is the only
356 /// instantiable non-leaf geometry type.
357 ///
358 /// The Geometrycollection class places no restrictions on type, overlapping,
359 /// etc. Subclasses do.
360 class Geometrycollection : public Geometry {
361  public:
type()362   Geometry_type type() const override {
363     return Geometry_type::kGeometrycollection;
364   }
365   bool accept(Geometry_visitor *v) override = 0;
366 
367   /// Adds a geometry to the collection.
368   ///
369   /// @param g The geometry to add.
370   virtual void push_back(const Geometry &g) = 0;
371   virtual void push_back(Geometry &&g) = 0;
372 
373   /// Checks if the collection is empty.
374   ///
375   /// @retval true The polygon is empty.
376   /// @retval false The polygon is not empty.
377   virtual bool empty() const = 0;
378 
379   /// Returns the size of the geometrycollection.
380   ///
381   /// @return Number of geometries in the geometrycollection.
382   virtual std::size_t size() const = 0;
383 
384   /// Resizes the geometrycollection to contain a given number of elements.
385   ///
386   /// If the new size is smaller than the current size, the remaining geometries
387   /// are discarded.
388   ///
389   /// @param[in] count The new number of geometries.
390   virtual void resize(std::size_t count) = 0;
391 
392   /// Removes all geometries from the geometrycollection.
393   virtual void clear() noexcept = 0;
394 
395   virtual Geometry &operator[](std::size_t i) = 0;
396   virtual const Geometry &operator[](std::size_t i) const = 0;
397 };
398 
399 /// A collection of points.
400 ///
401 /// Multipoint is an instantiable type in SQL.
402 class Multipoint : public Geometrycollection {
403  public:
type()404   Geometry_type type() const override { return Geometry_type::kMultipoint; }
405 
406   bool accept(Geometry_visitor *v) override = 0;
407 };
408 
409 /// An abstract collection of curves.
410 ///
411 /// Multicurve is a non-instantiable type in SQL.
412 class Multicurve : public Geometrycollection {
413  public:
414   Geometry_type type() const override = 0;
415   bool accept(Geometry_visitor *v) override = 0;
416 };
417 
418 /// A colletion of linestrings.
419 ///
420 /// Multilinestring is an instantiable type in SQL.
421 class Multilinestring : public Multicurve {
422  public:
type()423   Geometry_type type() const override {
424     return Geometry_type::kMultilinestring;
425   }
426   bool accept(Geometry_visitor *v) override = 0;
427 };
428 
429 /// An abstract collection of surfaces.
430 ///
431 /// Multisurface is a non-instantiable type in SQL.
432 class Multisurface : public Geometrycollection {
433  public:
434   Geometry_type type() const override = 0;
435   bool accept(Geometry_visitor *v) override = 0;
436 };
437 
438 /// A collection of polygons.
439 ///
440 /// Multipolygon is an instantiable type in SQL.
441 class Multipolygon : public Multisurface {
442  public:
type()443   Geometry_type type() const override { return Geometry_type::kMultipolygon; }
444   bool accept(Geometry_visitor *v) override = 0;
445 };
446 
447 /// Get the type name string corresponding to a geometry type.
448 ///
449 /// @param type The geometry type.
450 ///
451 /// @return A string containing the type name (in uppercase).
452 const char *type_to_name(Geometry_type type);
453 
454 }  // namespace gis
455 
456 #endif  // SQL_GIS_GEOMETRIES_H_INCLUDED
457