1 #ifndef GEOFUNC_INTERNAL_INCLUDED
2 #define GEOFUNC_INTERNAL_INCLUDED
3
4 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
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 Foundation,
24 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
25
26
27 /**
28 @file
29
30 @brief
31 This file defines common build blocks of GIS functions.
32 */
33 #include "my_config.h"
34
35 #include <vector>
36 #include <algorithm>
37 #include <stdexcept>
38 #include <memory>
39
40 #include <m_ctype.h>
41 #include "item_geofunc.h"
42 #include "gis_bg_traits.h"
43
44 // Boost.Geometry
45 #include <boost/geometry/geometry.hpp>
46 #include <boost/geometry/index/rtree.hpp>
47 // Boost.Range
48 #include <boost/range.hpp>
49
50
51 // GCC requires typename whenever needing to access a type inside a template,
52 // but MSVC forbids this.
53 #ifdef HAVE_IMPLICIT_DEPENDENT_NAME_TYPING
54 #define TYPENAME
55 #else
56 #define TYPENAME typename
57 #endif
58
59
60 #define GIS_ZERO 0.00000000001
61
62 extern bool simplify_multi_geometry(String *str, String *result_buffer);
63
64 using std::auto_ptr;
65
66
67 /**
68 Handle a GIS exception of any type.
69
70 This function constitutes the exception handling barrier between
71 Boost.Geometry and MySQL code. It handles all exceptions thrown in
72 GIS code and raises the corresponding error in MySQL.
73
74 Pattern for use in other functions:
75
76 @code
77 try
78 {
79 something_that_throws();
80 }
81 catch (...)
82 {
83 handle_gis_exception("st_foo");
84 }
85 @endcode
86
87 Other exception handling code put into the catch block, before or
88 after the call to handle_gis_exception(), must not throw exceptions.
89
90 @param funcname Function name for use in error message
91 */
92 void handle_gis_exception(const char *funcname);
93
94
95 /// A wrapper and interface for all geometry types used here. Make these
96 /// types as localized as possible. It's used as a type interface.
97 /// @tparam CoordinateSystemType Coordinate system type, specified using
98 // those defined in boost::geometry::cs.
99 template<typename CoordinateSystemType>
100 class BG_models
101 {
102 public:
103 typedef Gis_point Point;
104 // An counter-clockwise, closed Polygon type. It can hold open Polygon data,
105 // but not clockwise ones, otherwise things can go wrong, e.g. intersection.
106 typedef Gis_polygon Polygon;
107 typedef Gis_line_string Linestring;
108 typedef Gis_multi_point Multipoint;
109 typedef Gis_multi_line_string Multilinestring;
110 typedef Gis_multi_polygon Multipolygon;
111
112 typedef double Coordinate_type;
113 typedef CoordinateSystemType Coordinate_system;
114 };
115
116
117 template<>
118 class BG_models<
119 boost::geometry::cs::spherical_equatorial<boost::geometry::degree> >
120 {
121 public:
122 typedef Gis_point_spherical Point;
123 // An counter-clockwise, closed Polygon type. It can hold open Polygon data,
124 // but not clockwise ones, otherwise things can go wrong, e.g. intersection.
125 typedef Gis_polygon_spherical Polygon;
126 typedef Gis_line_string_spherical Linestring;
127 typedef Gis_multi_point_spherical Multipoint;
128 typedef Gis_multi_line_string_spherical Multilinestring;
129 typedef Gis_multi_polygon_spherical Multipolygon;
130
131 typedef double Coordinate_type;
132 typedef boost::geometry::cs::spherical_equatorial<boost::geometry::degree>
133 Coordinate_system;
134 };
135
136
137 namespace bg= boost::geometry;
138 namespace bgm= boost::geometry::model;
139 namespace bgcs= boost::geometry::cs;
140 namespace bgi= boost::geometry::index;
141 namespace bgm= boost::geometry::model;
142
143 typedef bgm::point<double, 2, bgcs::cartesian> BG_point;
144 typedef bgm::box<BG_point> BG_box;
145 typedef std::pair<BG_box, size_t> BG_rtree_entry;
146 typedef std::vector<BG_rtree_entry> BG_rtree_entries;
147 typedef bgi::rtree<BG_rtree_entry, bgi::quadratic<64> > Rtree_index;
148 typedef std::vector<BG_rtree_entry> Rtree_result;
149
150
make_bg_box(const Geometry * g,BG_box * box)151 inline void make_bg_box(const Geometry *g, BG_box *box)
152 {
153 MBR mbr;
154 g->envelope(&mbr);
155 box->min_corner().set<0>(mbr.xmin);
156 box->min_corner().set<1>(mbr.ymin);
157 box->max_corner().set<0>(mbr.xmax);
158 box->max_corner().set<1>(mbr.ymax);
159 }
160
161
is_box_valid(const BG_box & box)162 inline bool is_box_valid(const BG_box &box)
163 {
164 return
165 !(!my_isfinite(box.min_corner().get<0>()) ||
166 !my_isfinite(box.min_corner().get<1>()) ||
167 !my_isfinite(box.max_corner().get<0>()) ||
168 !my_isfinite(box.max_corner().get<1>()) ||
169 box.max_corner().get<0>() < box.min_corner().get<0>() ||
170 box.max_corner().get<1>() < box.min_corner().get<1>());
171 }
172
173
174 /**
175 Build an rtree set using a geometry collection.
176 @param gl geometry object pointers container.
177 @param [out] rtree entries which can be used to build an rtree.
178 */
179 void
180 make_rtree(const BG_geometry_collection::Geometry_list &gl,
181 Rtree_index *rtree);
182
183
184 /**
185 Build an rtree set using array of Boost.Geometry objects, which are
186 components of a multi geometry.
187 @param mg the multi geometry.
188 @param rtree the rtree to build.
189 */
190 template <typename MultiGeometry>
191 void
192 make_rtree_bggeom(const MultiGeometry &mg,
193 Rtree_index *rtree);
194
195
196 inline Gis_geometry_collection *
empty_collection(String * str,uint32 srid)197 empty_collection(String *str, uint32 srid)
198 {
199 return new Gis_geometry_collection(srid, Geometry::wkb_invalid_type,
200 NULL, str);
201 }
202
203
204 /*
205 Check whether a geometry is an empty geometry collection, i.e. one that
206 doesn't contain any geometry component of [multi]point or [multi]linestring
207 or [multi]polygon type.
208 @param g the geometry to check.
209 @return true if g is such an empty geometry collection;
210 false otherwise.
211 */
212 bool is_empty_geocollection(const Geometry *g);
213
214
215 /*
216 Check whether wkbres is the data of an empty geometry collection, i.e. one
217 that doesn't contain any geometry component of [multi]point or
218 [multi]linestring or [multi]polygon type.
219
220 @param wkbres a piece of geometry data of GEOMETRY format, i.e. an SRID
221 prefixing a WKB.
222 @return true if wkbres contains such an empty geometry collection;
223 false otherwise.
224 */
225 bool is_empty_geocollection(const String &wkbres);
226
227
228 /**
229 Less than comparator for points used by BG.
230 */
231 struct bgpt_lt
232 {
233 template <typename Point>
operatorbgpt_lt234 bool operator ()(const Point &p1, const Point &p2) const
235 {
236 if (p1.template get<0>() != p2.template get<0>())
237 return p1.template get<0>() < p2.template get<0>();
238 else
239 return p1.template get<1>() < p2.template get<1>();
240 }
241 };
242
243
244 /**
245 Equals comparator for points used by BG.
246 */
247 struct bgpt_eq
248 {
249 template <typename Point>
operatorbgpt_eq250 bool operator ()(const Point &p1, const Point &p2) const
251 {
252 return p1.template get<0>() == p2.template get<0>() &&
253 p1.template get<1>() == p2.template get<1>();
254 }
255 };
256
257
258 /**
259 Utility class, reset specified variable 'valref' to specified 'oldval' when
260 val_resetter<valtype> instance is destroyed.
261 @tparam Valtype Variable type to reset.
262 */
263 template <typename Valtype>
264 class Var_resetter
265 {
266 private:
267 Valtype *valref;
268 Valtype oldval;
269
270 // Forbid use, to eliminate a warning: oldval may be used uninitialized.
271 Var_resetter(const Var_resetter &o);
272 Var_resetter &operator=(const Var_resetter&);
273 public:
Var_resetter()274 Var_resetter() : valref(NULL)
275 {
276 }
277
Var_resetter(Valtype * v,const Valtype & oval)278 Var_resetter(Valtype *v, const Valtype &oval) : valref(v), oldval(oval)
279 {
280 }
281
~Var_resetter()282 ~Var_resetter()
283 {
284 if (valref)
285 *valref= oldval;
286 }
287
set(Valtype * v,const Valtype & oldval)288 void set(Valtype *v, const Valtype &oldval)
289 {
290 valref= v;
291 this->oldval= oldval;
292 }
293 };
294
295
296 /**
297 For every Geometry object write-accessed by a boost geometry function, i.e.
298 those passed as out parameter into set operation functions, call this
299 function before using the result object's data.
300
301 @param resbuf_mgr tracks the result buffer
302 @return true if an error occurred or if the geometry is an empty
303 collection; false if no error occurred.
304 */
305 template <typename BG_geotype>
306 bool post_fix_result(BG_result_buf_mgr *resbuf_mgr,
307 BG_geotype &geout, String *res);
308
309
310
311 #endif
312