1 // Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License, version 2.0,
5 // as published by the Free Software Foundation.
6 //
7 // This program is also distributed with certain software (including
8 // but not limited to OpenSSL) that is licensed under separate terms,
9 // as designated in a particular file or component or in included license
10 // documentation.  The authors of MySQL hereby grant you an additional
11 // permission to link the program and your derivative works with the
12 // separately licensed software that they have included with MySQL.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License, version 2.0, for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
22 
23 #include "sql/gis/geometries.h"
24 
25 #include <utility>  // std::swap
26 
27 #include "my_dbug.h"
28 #include "sql/gis/geometries_cs.h"
29 #include "sql/gis/geometry_visitor.h"
30 
31 namespace gis {
32 
accept(Geometry_visitor * v)33 bool Point::accept(Geometry_visitor *v) { return v->visit(this); }
34 
35 template <>
get() const36 double Point::get<0>() const {
37   return m_x;
38 }
39 
40 template <>
get() const41 double Point::get<1>() const {
42   return m_y;
43 }
44 
x() const45 double Point::x() const { return get<0>(); }
46 
y() const47 double Point::y() const { return get<1>(); }
48 
49 template <>
set(double d)50 void Point::set<0>(double d) {
51   m_x = d;
52 }
53 
54 template <>
set(double d)55 void Point::set<1>(double d) {
56   m_y = d;
57 }
58 
x(double d)59 void Point::x(double d) { set<0>(d); }
60 
y(double d)61 void Point::y(double d) { set<1>(d); }
62 
accept(Geometry_visitor * v)63 bool Cartesian_linestring::accept(Geometry_visitor *v) {
64   if (!v->visit_enter(this) && m_points.size() > 0) {
65     if (m_points[0].accept(v)) return true;
66     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
67       if (v->visit(this) || m_points[i].accept(v)) return true;
68     }
69   }
70   return v->visit_leave(this);
71 }
72 
push_back(const Point & pt)73 void Cartesian_linestring::push_back(const Point &pt) {
74   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian);
75   m_points.push_back(static_cast<const Cartesian_point &>(pt));
76 }
77 
push_back(Point && pt)78 void Cartesian_linestring::push_back(Point &&pt) {
79   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian);
80   m_points.push_back(static_cast<Cartesian_point &&>(pt));
81 }
82 
empty() const83 bool Cartesian_linestring::empty() const { return m_points.empty(); }
84 
accept(Geometry_visitor * v)85 bool Geographic_linestring::accept(Geometry_visitor *v) {
86   if (!v->visit_enter(this) && m_points.size() > 0) {
87     if (m_points[0].accept(v)) return true;
88     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
89       if (v->visit(this) || m_points[i].accept(v)) return true;
90     }
91   }
92   return v->visit_leave(this);
93 }
94 
push_back(const Point & pt)95 void Geographic_linestring::push_back(const Point &pt) {
96   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic);
97   m_points.push_back(static_cast<const Geographic_point &>(pt));
98 }
99 
push_back(Point && pt)100 void Geographic_linestring::push_back(Point &&pt) {
101   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic);
102   m_points.push_back(static_cast<Geographic_point &&>(pt));
103 }
104 
empty() const105 bool Geographic_linestring::empty() const { return m_points.empty(); }
106 
accept(Geometry_visitor * v)107 bool Cartesian_linearring::accept(Geometry_visitor *v) {
108   if (!v->visit_enter(this) && m_points.size() > 0) {
109     if (m_points[0].accept(v)) return true;
110     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
111       if (v->visit(this) || m_points[i].accept(v)) return true;
112     }
113   }
114   return v->visit_leave(this);
115 }
116 
accept(Geometry_visitor * v)117 bool Geographic_linearring::accept(Geometry_visitor *v) {
118   if (!v->visit_enter(this) && m_points.size() > 0) {
119     if (m_points[0].accept(v)) return true;
120     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
121       if (v->visit(this) || m_points[i].accept(v)) return true;
122     }
123   }
124   return v->visit_leave(this);
125 }
126 
accept(Geometry_visitor * v)127 bool Cartesian_polygon::accept(Geometry_visitor *v) {
128   if (!v->visit_enter(this)) {
129     if (m_exterior_ring.accept(v)) return true;
130     for (auto &&ring : m_interior_rings) {
131       if (v->visit(this) || ring.accept(v)) return true;
132     }
133   }
134   return v->visit_leave(this);
135 }
136 
push_back(const Linearring & lr)137 void Cartesian_polygon::push_back(const Linearring &lr) {
138   DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kCartesian);
139   if (m_exterior_ring.empty() && m_interior_rings.empty())
140     m_exterior_ring = static_cast<const Cartesian_linearring &>(lr);
141   else
142     m_interior_rings.push_back(static_cast<const Cartesian_linearring &>(lr));
143 }
144 
push_back(Linearring && lr)145 void Cartesian_polygon::push_back(Linearring &&lr) {
146   DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kCartesian);
147   if (m_exterior_ring.empty() && m_interior_rings.empty())
148     m_exterior_ring = static_cast<Cartesian_linearring &&>(lr);
149   else
150     m_interior_rings.push_back(static_cast<Cartesian_linearring &&>(lr));
151 }
152 
empty() const153 bool Cartesian_polygon::empty() const {
154   return m_exterior_ring.empty() && m_interior_rings.empty();
155 }
156 
size() const157 std::size_t Cartesian_polygon::size() const {
158   std::size_t sz = m_interior_rings.size();
159   if (!m_exterior_ring.empty()) sz++;
160   return sz;
161 }
162 
interior_ring(std::size_t n)163 Linearring &Cartesian_polygon::interior_ring(std::size_t n) {
164   return m_interior_rings[n];
165 }
166 
accept(Geometry_visitor * v)167 bool Geographic_polygon::accept(Geometry_visitor *v) {
168   if (!v->visit_enter(this)) {
169     if (m_exterior_ring.accept(v)) return true;
170     for (auto &&ring : m_interior_rings) {
171       if (v->visit(this) || ring.accept(v)) return true;
172     }
173   }
174   return v->visit_leave(this);
175 }
176 
cartesian_exterior_ring() const177 Cartesian_linearring &Cartesian_polygon::cartesian_exterior_ring() const {
178   return const_cast<Cartesian_linearring &>(m_exterior_ring);
179 }
180 
181 // Doxygen doesn't understand decltype as it is used here.
182 #ifndef IN_DOXYGEN
183 
184 decltype(Cartesian_polygon::m_interior_rings) &
interior_rings()185 Cartesian_polygon::interior_rings() {
186   return m_interior_rings;
187 }
188 
189 decltype(Cartesian_polygon::m_interior_rings) const &
const_interior_rings() const190 Cartesian_polygon::const_interior_rings() const {
191   return m_interior_rings;
192 }
193 
194 #endif  // IN_DOXYGEN
195 
push_back(const Linearring & lr)196 void Geographic_polygon::push_back(const Linearring &lr) {
197   DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kGeographic);
198   if (m_exterior_ring.empty() && m_interior_rings.empty())
199     m_exterior_ring = static_cast<const Geographic_linearring &>(lr);
200   else
201     m_interior_rings.push_back(static_cast<const Geographic_linearring &>(lr));
202 }
203 
push_back(Linearring && lr)204 void Geographic_polygon::push_back(Linearring &&lr) {
205   DBUG_ASSERT(lr.coordinate_system() == Coordinate_system::kGeographic);
206   if (m_exterior_ring.empty() && m_interior_rings.empty())
207     m_exterior_ring = static_cast<Geographic_linearring &&>(lr);
208   else
209     m_interior_rings.push_back(static_cast<Geographic_linearring &&>(lr));
210 }
211 
empty() const212 bool Geographic_polygon::empty() const {
213   return m_exterior_ring.empty() && m_interior_rings.empty();
214 }
215 
size() const216 std::size_t Geographic_polygon::size() const {
217   std::size_t sz = m_interior_rings.size();
218   if (!m_exterior_ring.empty()) sz++;
219   return sz;
220 }
221 
geographic_exterior_ring() const222 Geographic_linearring &Geographic_polygon::geographic_exterior_ring() const {
223   return const_cast<Geographic_linearring &>(m_exterior_ring);
224 }
225 
interior_ring(std::size_t n)226 Linearring &Geographic_polygon::interior_ring(std::size_t n) {
227   return m_interior_rings[n];
228 }
229 
230 // Doxygen doesn't understand decltype as it is used here.
231 #ifndef IN_DOXYGEN
232 
233 decltype(Geographic_polygon::m_interior_rings) &
interior_rings()234 Geographic_polygon::interior_rings() {
235   return m_interior_rings;
236 }
237 
238 decltype(Geographic_polygon::m_interior_rings) const &
const_interior_rings() const239 Geographic_polygon::const_interior_rings() const {
240   return m_interior_rings;
241 }
242 
243 #endif  // IN_DOXYGEN
244 
Cartesian_geometrycollection(const Cartesian_geometrycollection & gc)245 Cartesian_geometrycollection::Cartesian_geometrycollection(
246     const Cartesian_geometrycollection &gc)
247     : m_geometries(
248           Malloc_allocator<Geometry *>(key_memory_Geometry_objects_data)) {
249   for (Geometry *g : gc.m_geometries) {
250     switch (g->type()) {
251       case Geometry_type::kPoint:
252         m_geometries.push_back(
253             new Cartesian_point(*static_cast<Cartesian_point *>(g)));
254         break;
255       case Geometry_type::kLinestring:
256         m_geometries.push_back(
257             new Cartesian_linestring(*static_cast<Cartesian_linestring *>(g)));
258         break;
259       case Geometry_type::kPolygon:
260         m_geometries.push_back(
261             new Cartesian_polygon(*static_cast<Cartesian_polygon *>(g)));
262         break;
263       case Geometry_type::kGeometrycollection:
264         m_geometries.push_back(new Cartesian_geometrycollection(
265             *static_cast<Cartesian_geometrycollection *>(g)));
266         break;
267       case Geometry_type::kMultipoint:
268         m_geometries.push_back(
269             new Cartesian_multipoint(*static_cast<Cartesian_multipoint *>(g)));
270         break;
271       case Geometry_type::kMultilinestring:
272         m_geometries.push_back(new Cartesian_multilinestring(
273             *static_cast<Cartesian_multilinestring *>(g)));
274         break;
275       case Geometry_type::kMultipolygon:
276         m_geometries.push_back(new Cartesian_multipolygon(
277             *static_cast<Cartesian_multipolygon *>(g)));
278         break;
279       default:
280         DBUG_ASSERT(false); /* purecov: inspected */
281     }
282   }
283 }
284 
accept(Geometry_visitor * v)285 bool Cartesian_geometrycollection::accept(Geometry_visitor *v) {
286   if (!v->visit_enter(this) && m_geometries.size() > 0) {
287     if (m_geometries[0]->accept(v)) return true;
288     for (decltype(m_geometries)::size_type i = 1; i < m_geometries.size();
289          i++) {
290       if (v->visit(this) || m_geometries[i]->accept(v)) return true;
291     }
292   }
293   return v->visit_leave(this);
294 }
295 
push_back(const Geometry & g)296 void Cartesian_geometrycollection::push_back(const Geometry &g) {
297   switch (g.type()) {
298     case Geometry_type::kPoint:
299       m_geometries.push_back(
300           new Cartesian_point(static_cast<const Cartesian_point &>(g)));
301       break;
302     case Geometry_type::kLinestring:
303       m_geometries.push_back(new Cartesian_linestring(
304           static_cast<const Cartesian_linestring &>(g)));
305       break;
306     case Geometry_type::kPolygon:
307       m_geometries.push_back(
308           new Cartesian_polygon(static_cast<const Cartesian_polygon &>(g)));
309       break;
310     case Geometry_type::kGeometrycollection:
311       m_geometries.push_back(new Cartesian_geometrycollection(
312           static_cast<const Cartesian_geometrycollection &>(g)));
313       break;
314     case Geometry_type::kMultipoint:
315       m_geometries.push_back(new Cartesian_multipoint(
316           static_cast<const Cartesian_multipoint &>(g)));
317       break;
318     case Geometry_type::kMultilinestring:
319       m_geometries.push_back(new Cartesian_multilinestring(
320           static_cast<const Cartesian_multilinestring &>(g)));
321       break;
322     case Geometry_type::kMultipolygon:
323       m_geometries.push_back(new Cartesian_multipolygon(
324           static_cast<const Cartesian_multipolygon &>(g)));
325       break;
326     default:
327       DBUG_ASSERT(false); /* purecov: inspected */
328   }
329 }
330 
push_back(Geometry && g)331 void Cartesian_geometrycollection::push_back(Geometry &&g) {
332   switch (g.type()) {
333     case Geometry_type::kPoint:
334       m_geometries.push_back(
335           new Cartesian_point(static_cast<Cartesian_point &&>(g)));
336       break;
337     case Geometry_type::kLinestring:
338       m_geometries.push_back(
339           new Cartesian_linestring(static_cast<Cartesian_linestring &&>(g)));
340       break;
341     case Geometry_type::kPolygon:
342       m_geometries.push_back(
343           new Cartesian_polygon(static_cast<Cartesian_polygon &&>(g)));
344       break;
345     case Geometry_type::kGeometrycollection:
346       m_geometries.push_back(new Cartesian_geometrycollection(
347           static_cast<Cartesian_geometrycollection &&>(g)));
348       break;
349     case Geometry_type::kMultipoint:
350       m_geometries.push_back(
351           new Cartesian_multipoint(static_cast<Cartesian_multipoint &&>(g)));
352       break;
353     case Geometry_type::kMultilinestring:
354       m_geometries.push_back(new Cartesian_multilinestring(
355           static_cast<Cartesian_multilinestring &&>(g)));
356       break;
357     case Geometry_type::kMultipolygon:
358       m_geometries.push_back(new Cartesian_multipolygon(
359           static_cast<Cartesian_multipolygon &&>(g)));
360       break;
361     default:
362       DBUG_ASSERT(false); /* purecov: inspected */
363   }
364 }
365 
empty() const366 bool Cartesian_geometrycollection::empty() const {
367   return m_geometries.empty();
368 }
369 
Geographic_geometrycollection(const Geographic_geometrycollection & gc)370 Geographic_geometrycollection::Geographic_geometrycollection(
371     const Geographic_geometrycollection &gc)
372     : m_geometries(
373           Malloc_allocator<Geometry *>(key_memory_Geometry_objects_data)) {
374   for (Geometry *g : gc.m_geometries) {
375     switch (g->type()) {
376       case Geometry_type::kPoint:
377         m_geometries.push_back(
378             new Geographic_point(*static_cast<Geographic_point *>(g)));
379         break;
380       case Geometry_type::kLinestring:
381         m_geometries.push_back(new Geographic_linestring(
382             *static_cast<Geographic_linestring *>(g)));
383         break;
384       case Geometry_type::kPolygon:
385         m_geometries.push_back(
386             new Geographic_polygon(*static_cast<Geographic_polygon *>(g)));
387         break;
388       case Geometry_type::kGeometrycollection:
389         m_geometries.push_back(new Geographic_geometrycollection(
390             *static_cast<Geographic_geometrycollection *>(g)));
391         break;
392       case Geometry_type::kMultipoint:
393         m_geometries.push_back(new Geographic_multipoint(
394             *static_cast<Geographic_multipoint *>(g)));
395         break;
396       case Geometry_type::kMultilinestring:
397         m_geometries.push_back(new Geographic_multilinestring(
398             *static_cast<Geographic_multilinestring *>(g)));
399         break;
400       case Geometry_type::kMultipolygon:
401         m_geometries.push_back(new Geographic_multipolygon(
402             *static_cast<Geographic_multipolygon *>(g)));
403         break;
404       default:
405         DBUG_ASSERT(false); /* purecov: inspected */
406     }
407   }
408 }
409 
accept(Geometry_visitor * v)410 bool Geographic_geometrycollection::accept(Geometry_visitor *v) {
411   if (!v->visit_enter(this) && m_geometries.size() > 0) {
412     if (m_geometries[0]->accept(v)) return true;
413     for (decltype(m_geometries)::size_type i = 1; i < m_geometries.size();
414          i++) {
415       if (v->visit(this) || m_geometries[i]->accept(v)) return true;
416     }
417   }
418   return v->visit_leave(this);
419 }
420 
push_back(const Geometry & g)421 void Geographic_geometrycollection::push_back(const Geometry &g) {
422   switch (g.type()) {
423     case Geometry_type::kPoint:
424       m_geometries.push_back(
425           new Geographic_point(static_cast<const Geographic_point &>(g)));
426       break;
427     case Geometry_type::kLinestring:
428       m_geometries.push_back(new Geographic_linestring(
429           static_cast<const Geographic_linestring &>(g)));
430       break;
431     case Geometry_type::kPolygon:
432       m_geometries.push_back(
433           new Geographic_polygon(static_cast<const Geographic_polygon &>(g)));
434       break;
435     case Geometry_type::kGeometrycollection:
436       m_geometries.push_back(new Geographic_geometrycollection(
437           static_cast<const Geographic_geometrycollection &>(g)));
438       break;
439     case Geometry_type::kMultipoint:
440       m_geometries.push_back(new Geographic_multipoint(
441           static_cast<const Geographic_multipoint &>(g)));
442       break;
443     case Geometry_type::kMultilinestring:
444       m_geometries.push_back(new Geographic_multilinestring(
445           static_cast<const Geographic_multilinestring &>(g)));
446       break;
447     case Geometry_type::kMultipolygon:
448       m_geometries.push_back(new Geographic_multipolygon(
449           static_cast<const Geographic_multipolygon &>(g)));
450       break;
451     default:
452       DBUG_ASSERT(false); /* purecov: inspected */
453   }
454 }
455 
push_back(Geometry && g)456 void Geographic_geometrycollection::push_back(Geometry &&g) {
457   switch (g.type()) {
458     case Geometry_type::kPoint:
459       m_geometries.push_back(
460           new Geographic_point(static_cast<Geographic_point &&>(g)));
461       break;
462     case Geometry_type::kLinestring:
463       m_geometries.push_back(
464           new Geographic_linestring(static_cast<Geographic_linestring &&>(g)));
465       break;
466     case Geometry_type::kPolygon:
467       m_geometries.push_back(
468           new Geographic_polygon(static_cast<Geographic_polygon &&>(g)));
469       break;
470     case Geometry_type::kGeometrycollection:
471       m_geometries.push_back(new Geographic_geometrycollection(
472           static_cast<Geographic_geometrycollection &&>(g)));
473       break;
474     case Geometry_type::kMultipoint:
475       m_geometries.push_back(
476           new Geographic_multipoint(static_cast<Geographic_multipoint &&>(g)));
477       break;
478     case Geometry_type::kMultilinestring:
479       m_geometries.push_back(new Geographic_multilinestring(
480           static_cast<Geographic_multilinestring &&>(g)));
481       break;
482     case Geometry_type::kMultipolygon:
483       m_geometries.push_back(new Geographic_multipolygon(
484           static_cast<Geographic_multipolygon &&>(g)));
485       break;
486     default:
487       DBUG_ASSERT(false); /* purecov: inspected */
488   }
489 }
490 
empty() const491 bool Geographic_geometrycollection::empty() const {
492   return m_geometries.empty();
493 }
494 
accept(Geometry_visitor * v)495 bool Cartesian_multipoint::accept(Geometry_visitor *v) {
496   if (!v->visit_enter(this) && m_points.size() > 0) {
497     if (m_points[0].accept(v)) return true;
498     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
499       if (v->visit(this) || m_points[i].accept(v)) return true;
500     }
501   }
502   return v->visit_leave(this);
503 }
504 
push_back(const Geometry & pt)505 void Cartesian_multipoint::push_back(const Geometry &pt) {
506   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian);
507   m_points.push_back(static_cast<const Cartesian_point &>(pt));
508 }
509 
push_back(Geometry && pt)510 void Cartesian_multipoint::push_back(Geometry &&pt) {
511   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kCartesian);
512   m_points.push_back(static_cast<Cartesian_point &&>(pt));
513 }
514 
empty() const515 bool Cartesian_multipoint::empty() const { return m_points.empty(); }
516 
accept(Geometry_visitor * v)517 bool Geographic_multipoint::accept(Geometry_visitor *v) {
518   if (!v->visit_enter(this) && m_points.size() > 0) {
519     if (m_points[0].accept(v)) return true;
520     for (decltype(m_points)::size_type i = 1; i < m_points.size(); i++) {
521       if (v->visit(this) || m_points[i].accept(v)) return true;
522     }
523   }
524   return v->visit_leave(this);
525 }
526 
push_back(const Geometry & pt)527 void Geographic_multipoint::push_back(const Geometry &pt) {
528   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic);
529   m_points.push_back(static_cast<const Geographic_point &>(pt));
530 }
531 
push_back(Geometry && pt)532 void Geographic_multipoint::push_back(Geometry &&pt) {
533   DBUG_ASSERT(pt.coordinate_system() == Coordinate_system::kGeographic);
534   m_points.push_back(static_cast<Geographic_point &&>(pt));
535 }
536 
empty() const537 bool Geographic_multipoint::empty() const { return m_points.empty(); }
538 
accept(Geometry_visitor * v)539 bool Cartesian_multilinestring::accept(Geometry_visitor *v) {
540   if (!v->visit_enter(this) && m_linestrings.size() > 0) {
541     if (m_linestrings[0].accept(v)) return true;
542     for (decltype(m_linestrings)::size_type i = 1; i < m_linestrings.size();
543          i++) {
544       if (v->visit(this) || m_linestrings[i].accept(v)) return true;
545     }
546   }
547   return v->visit_leave(this);
548 }
549 
push_back(const Geometry & ls)550 void Cartesian_multilinestring::push_back(const Geometry &ls) {
551   DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kCartesian);
552   m_linestrings.push_back(static_cast<const Cartesian_linestring &>(ls));
553 }
554 
push_back(Geometry && ls)555 void Cartesian_multilinestring::push_back(Geometry &&ls) {
556   DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kCartesian);
557   m_linestrings.push_back(static_cast<Cartesian_linestring &&>(ls));
558 }
559 
empty() const560 bool Cartesian_multilinestring::empty() const { return m_linestrings.empty(); }
561 
accept(Geometry_visitor * v)562 bool Geographic_multilinestring::accept(Geometry_visitor *v) {
563   if (!v->visit_enter(this) && m_linestrings.size() > 0) {
564     if (m_linestrings[0].accept(v)) return true;
565     for (decltype(m_linestrings)::size_type i = 1; i < m_linestrings.size();
566          i++) {
567       if (v->visit(this) || m_linestrings[i].accept(v)) return true;
568     }
569   }
570   return v->visit_leave(this);
571 }
572 
push_back(const Geometry & ls)573 void Geographic_multilinestring::push_back(const Geometry &ls) {
574   DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kGeographic);
575   m_linestrings.push_back(static_cast<const Geographic_linestring &>(ls));
576 }
577 
push_back(Geometry && ls)578 void Geographic_multilinestring::push_back(Geometry &&ls) {
579   DBUG_ASSERT(ls.coordinate_system() == Coordinate_system::kGeographic);
580   m_linestrings.push_back(static_cast<Geographic_linestring &&>(ls));
581 }
582 
empty() const583 bool Geographic_multilinestring::empty() const { return m_linestrings.empty(); }
584 
accept(Geometry_visitor * v)585 bool Cartesian_multipolygon::accept(Geometry_visitor *v) {
586   if (!v->visit_enter(this) && m_polygons.size() > 0) {
587     if (m_polygons[0].accept(v)) return true;
588     for (decltype(m_polygons)::size_type i = 1; i < m_polygons.size(); i++) {
589       if (v->visit(this) || m_polygons[i].accept(v)) return true;
590     }
591   }
592   return v->visit_leave(this);
593 }
594 
push_back(const Geometry & py)595 void Cartesian_multipolygon::push_back(const Geometry &py) {
596   DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kCartesian);
597   m_polygons.push_back(static_cast<const Cartesian_polygon &>(py));
598 }
599 
push_back(Geometry && py)600 void Cartesian_multipolygon::push_back(Geometry &&py) {
601   DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kCartesian);
602   m_polygons.push_back(static_cast<Cartesian_polygon &&>(py));
603 }
604 
empty() const605 bool Cartesian_multipolygon::empty() const { return m_polygons.empty(); }
606 
accept(Geometry_visitor * v)607 bool Geographic_multipolygon::accept(Geometry_visitor *v) {
608   if (!v->visit_enter(this) && m_polygons.size() > 0) {
609     if (m_polygons[0].accept(v)) return true;
610     for (decltype(m_polygons)::size_type i = 1; i < m_polygons.size(); i++) {
611       if (v->visit(this) || m_polygons[i].accept(v)) return true;
612     }
613   }
614   return v->visit_leave(this);
615 }
616 
push_back(const Geometry & py)617 void Geographic_multipolygon::push_back(const Geometry &py) {
618   DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kGeographic);
619   m_polygons.push_back(static_cast<const Geographic_polygon &>(py));
620 }
621 
push_back(Geometry && py)622 void Geographic_multipolygon::push_back(Geometry &&py) {
623   DBUG_ASSERT(py.coordinate_system() == Coordinate_system::kGeographic);
624   m_polygons.push_back(static_cast<Geographic_polygon &&>(py));
625 }
626 
empty() const627 bool Geographic_multipolygon::empty() const { return m_polygons.empty(); }
628 
type_to_name(Geometry_type type)629 const char *type_to_name(Geometry_type type) {
630   switch (type) {
631     case Geometry_type::kPoint:
632       return "POINT";
633     case Geometry_type::kLinestring:
634       return "LINESTRING";
635     case Geometry_type::kPolygon:
636       return "POLYGON";
637     case Geometry_type::kGeometrycollection:
638       return "GEOMCOLLECTION";
639     case Geometry_type::kMultipoint:
640       return "MULTIPOINT";
641     case Geometry_type::kMultilinestring:
642       return "MULTILINESTRING";
643     case Geometry_type::kMultipolygon:
644       return "MULTIPOLYGON";
645     default:
646       /* purecov: begin inspected */
647       DBUG_ASSERT(false);
648       return "UNKNOWN";
649       /* purecov: end */
650   }
651 }
652 
653 }  // namespace gis
654