1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
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 "my_config.h"
24 #include <gtest/gtest.h>
25
26 #include "my_global.h"
27 #include "gstream.h"
28 #include "spatial.h"
29
30 namespace gis_algo_unittest {
31
32 /*
33 Testing Gis_polygon_ring::set_ring_order function.
34 */
35 class SetRingOrderTest : public ::testing::Test
36 {
37 public:
SetRingOrderTest()38 SetRingOrderTest() :my_flags(Geometry::wkb_linestring, 0)
39 {
40 latincc= &my_charset_latin1;
41 }
42 Geometry *geometry_from_text(const String &wkt, String *wkb,
43 Geometry_buffer *geobuf);
44 void set_order_and_compare(const std::string &str, const std::string &str2,
45 bool want_ccw= true);
46
47
48 const static uint32 srid= 0;
49 CHARSET_INFO *latincc;
50 String str, str2, wkt, wkt2;
51 Geometry_buffer buffer, buffer2;
52 Geometry::Flags_t my_flags;
53 };
54
55
geometry_from_text(const String & wkt,String * wkb,Geometry_buffer * geobuf)56 Geometry *SetRingOrderTest::geometry_from_text(const String &wkt, String *wkb,
57 Geometry_buffer *geobuf)
58 {
59 Gis_read_stream trs(wkt.charset(), wkt.ptr(), wkt.length());
60
61 wkb->set_charset(&my_charset_bin);
62 wkb->length(0);
63 return Geometry::create_from_wkt(geobuf, &trs, wkb, 1);
64 }
65
set_order_and_compare(const std::string & s1,const std::string & s2,bool want_ccw)66 void SetRingOrderTest::set_order_and_compare(const std::string &s1,
67 const std::string &s2,
68 bool want_ccw)
69 {
70 wkt.set(s1.c_str(), s1.length(), latincc);
71 wkt2.set(s2.c_str(), s2.length(), latincc);
72
73 Gis_polygon_ring *ringp= static_cast<Gis_polygon_ring *>
74 (geometry_from_text(wkt, &str, &buffer));
75 assert(ringp->get_geotype() == Geometry::wkb_linestring);
76 Gis_polygon_ring ring(ringp->get_ptr(),
77 ringp->get_nbytes(), my_flags, 0U);
78 EXPECT_EQ(ring.set_ring_order(want_ccw), false);
79
80
81 ringp= static_cast<Gis_polygon_ring *>(geometry_from_text(wkt2, &str2,
82 &buffer2));
83 assert(ringp->get_geotype() == Geometry::wkb_linestring);
84 Gis_polygon_ring ring2(ringp->get_ptr(),
85 ringp->get_nbytes(), my_flags, 0U);
86 EXPECT_EQ(ring2.set_ring_order(want_ccw), false);
87
88 EXPECT_EQ(str.length(), str2.length());
89 EXPECT_EQ(memcmp(str.ptr(), str2.ptr(), str.length()), 0);
90 }
91
TEST_F(SetRingOrderTest,SetRingOrderCCW)92 TEST_F(SetRingOrderTest, SetRingOrderCCW)
93 {
94 SCOPED_TRACE("SetRingOrderCCW");
95 std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0)");
96 std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0)");
97 set_order_and_compare(geom1, geom2);
98 }
99
TEST_F(SetRingOrderTest,SetRingOrderCW)100 TEST_F(SetRingOrderTest, SetRingOrderCW)
101 {
102 SCOPED_TRACE("SetRingOrderCW");
103 std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0)");
104 std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0)");
105 set_order_and_compare(geom1, geom2, false);
106 }
107
TEST_F(SetRingOrderTest,SetRingOrder2CCW)108 TEST_F(SetRingOrderTest, SetRingOrder2CCW)
109 {
110 SCOPED_TRACE("SetRingOrder2CCW");
111 std::string geom3("linestring(0 0, 0 1, 1 0, 0 0)");
112 std::string geom4("linestring(0 0, 1 0, 0 1, 0 0)");
113 set_order_and_compare(geom3, geom4);
114 }
115
TEST_F(SetRingOrderTest,SetRingOrder2CW)116 TEST_F(SetRingOrderTest, SetRingOrder2CW)
117 {
118 SCOPED_TRACE("SetRingOrder2CW");
119 std::string geom3("linestring(0 0, 0 1, 1 0, 0 0)");
120 std::string geom4("linestring(0 0, 1 0, 0 1, 0 0)");
121 set_order_and_compare(geom3, geom4, false);
122 }
123
TEST_F(SetRingOrderTest,DuplicateMinPointBeforeCCW)124 TEST_F(SetRingOrderTest, DuplicateMinPointBeforeCCW)
125 {
126 SCOPED_TRACE("DuplicateMinPointBeforeCCW");
127 std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0, 0 0, 0 0)");
128 std::string geom2("linestring(0 0, 0 0, 0 0, 1 0, 1 1, 0 1, 0 0)");
129 set_order_and_compare(geom1, geom2);
130 }
131
TEST_F(SetRingOrderTest,DuplicateMinPointBeforeCW)132 TEST_F(SetRingOrderTest, DuplicateMinPointBeforeCW)
133 {
134 SCOPED_TRACE("DuplicateMinPointBeforeCW");
135 std::string geom1("linestring(0 0, 0 1, 1 1, 1 0, 0 0, 0 0, 0 0)");
136 std::string geom2("linestring(0 0, 0 0, 0 0, 1 0, 1 1, 0 1, 0 0)");
137 set_order_and_compare(geom1, geom2, false);
138 }
139
TEST_F(SetRingOrderTest,DuplicateMinPointAfterCCW)140 TEST_F(SetRingOrderTest, DuplicateMinPointAfterCCW)
141 {
142 SCOPED_TRACE("DuplicateMinPointAfterCCW");
143 std::string geom1("linestring(0 0, 0 0, 0 0, 0 1, 1 1, 1 0, 0 0)");
144 std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0, 0 0, 0 0)");
145 set_order_and_compare(geom1, geom2);
146 }
147
TEST_F(SetRingOrderTest,DuplicateMinPointAfterCW)148 TEST_F(SetRingOrderTest, DuplicateMinPointAfterCW)
149 {
150 SCOPED_TRACE("DuplicateMinPointAfterCW");
151 std::string geom1("linestring(0 0, 0 0, 0 0, 0 1, 1 1, 1 0, 0 0)");
152 std::string geom2("linestring(0 0, 1 0, 1 1, 0 1, 0 0, 0 0, 0 0)");
153 set_order_and_compare(geom1, geom2, false);
154 }
155
TEST_F(SetRingOrderTest,RingDegradedToPointTest)156 TEST_F(SetRingOrderTest, RingDegradedToPointTest)
157 {
158 SCOPED_TRACE("RingDegradedToPointTest");
159 std::string s1("linestring(0 0, 0 0, 0 0, 0 0, 0 0)");
160 wkt.set(s1.c_str(), s1.length(), latincc);
161
162 Gis_polygon_ring *ringp= static_cast<Gis_polygon_ring *>
163 (geometry_from_text(wkt, &str, &buffer));
164 assert(ringp->get_geotype() == Geometry::wkb_linestring);
165 Gis_polygon_ring ring(ringp->get_ptr(),
166 ringp->get_nbytes(), my_flags, 0U);
167 EXPECT_EQ(ring.set_ring_order(true/*CCW*/), true);
168 }
169
170
171 /*
172 Testing functions in Geometry and its children classes that are not covered
173 by current BG functionalities.
174 */
175 class GeometryManipulationTest : public SetRingOrderTest
176 {
177 public:
assign_multipolygon_back(Gis_multi_polygon & mpl2,const Gis_polygon & pl)178 void assign_multipolygon_back(Gis_multi_polygon &mpl2, const Gis_polygon &pl)
179 {
180 for (size_t i = 0; i < pl.outer().size(); i++)
181 mpl2.back().outer().push_back(pl.outer()[i]);
182 for (size_t i = 0; i < pl.inners().size(); i+=2)
183 {
184 mpl2.back().inners().push_back(pl.inners()[i]);
185 if (i + 1 < pl.inners().size())
186 {
187 mpl2.back().inners().resize(mpl2.back().inners().size() + 1);
188 for (size_t j = 0; j < pl.inners()[i+1].size(); j++)
189 mpl2.back().inners().back().push_back(pl.inners()[i+1][j]);
190 }
191 }
192 }
193 };
194
195
TEST_F(GeometryManipulationTest,PolygonCopyTest)196 TEST_F(GeometryManipulationTest, PolygonCopyTest)
197 {
198 SCOPED_TRACE("PolygonCopyTest");
199 std::string s1("polygon((0 0, 1 0, 1 1, 0 1, 0 0))");
200 wkt.set(s1.c_str(), s1.length(), latincc);
201
202 Gis_polygon *plgn=
203 static_cast<Gis_polygon *>(geometry_from_text(wkt, &str, &buffer));
204 Gis_polygon plgn1(plgn->get_data_ptr(), plgn->get_data_size(),
205 plgn->get_flags(), plgn->get_srid());
206 Gis_polygon plgn2(plgn1);
207 Gis_polygon plgn3;
208
209 plgn3= plgn2;
210
211 String wkb3, wkb4, wkb5;
212 plgn3.as_wkb(&wkb3, false);
213 plgn3.to_wkb_unparsed();
214 plgn3.as_wkb(&wkb5, true);
215 EXPECT_EQ(wkb3.length(), wkb5.length());
216 EXPECT_EQ(memcmp(((char *)wkb3.ptr()) + WKB_HEADER_SIZE,
217 ((char *)wkb5.ptr()) + WKB_HEADER_SIZE,
218 wkb5.length() - WKB_HEADER_SIZE), 0);
219
220 plgn2.as_geometry(&wkb4, false);
221 EXPECT_EQ(wkb3.length() + 4, wkb4.length());
222 EXPECT_EQ(memcmp(GEOM_HEADER_SIZE + ((char *)wkb4.ptr()),
223 ((char *)wkb3.ptr()) + WKB_HEADER_SIZE,
224 wkb3.length() - WKB_HEADER_SIZE), 0);
225
226 // Check they have identical data. Can only do so in wkb form.
227 plgn1.to_wkb_unparsed();
228 plgn2.to_wkb_unparsed();
229 EXPECT_EQ(plgn1.get_data_size(), plgn2.get_data_size());
230 EXPECT_EQ(memcmp(plgn->get_data_ptr(), plgn2.get_data_ptr(),
231 plgn2.get_data_size()), 0);
232
233 EXPECT_EQ(plgn3.get_data_size(), plgn2.get_data_size());
234 EXPECT_EQ(memcmp(plgn3.get_data_ptr(), plgn2.get_data_ptr(),
235 plgn2.get_data_size()), 0);
236 }
237
TEST_F(GeometryManipulationTest,PolygonManipulationTest)238 TEST_F(GeometryManipulationTest, PolygonManipulationTest)
239 {
240 SCOPED_TRACE("PolygonManipulationTest");
241 std::string s1("polygon((0 0, 1 0, 1 1, 0 1, 0 0))");
242 std::string s2("multipolygon(((0 0, 1 0, 1 1, 0 1, 0 0)))");
243 std::string s3("linestring(0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)");
244 std::string s4("multipolygon(((0 0, 1 0, 1 1, 0 1, 0 0)), \
245 ((0 0, 1 0, 1 1, 0 1, 0 0), (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)),\
246 ((0 0, 1 0, 1 1, 0 1, 0 0), (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25)))");
247 std::string s5("polygon((0 0, 1 0, 1 1, 0 1, 0 0),\
248 (0.5 0.25, 0.5 0.75, 0.75 0.75, 0.5 0.25))");
249 wkt.set(s1.c_str(), s1.length(), latincc);
250 wkt2.set(s3.c_str(), s3.length(), latincc);
251
252 Gis_polygon *plgn0=
253 static_cast<Gis_polygon *>(geometry_from_text(wkt, &str, &buffer));
254 Gis_line_string *ls0=
255 static_cast<Gis_line_string *>(geometry_from_text(wkt2, &str2, &buffer2));
256 Gis_polygon plgn(plgn0->get_data_ptr(), plgn0->get_data_size(),
257 plgn0->get_flags(), plgn0->get_srid());
258 Gis_line_string ls(ls0->get_data_ptr(), ls0->get_data_size(),
259 ls0->get_flags(), ls0->get_srid());
260 Gis_line_string ls00(*ls0);
261
262 Geometry_buffer buffer3;
263 String wkt3, str3;
264
265 wkt3.set(s2.c_str(), s2.length(), latincc);
266 Gis_multi_polygon *pmplgn= (static_cast<Gis_multi_polygon *>
267 (geometry_from_text(wkt3, &str3, &buffer3)));
268 Gis_multi_polygon mplgn0(pmplgn->get_data_ptr(), pmplgn->get_data_size(),
269 pmplgn->get_flags(), pmplgn->get_srid());
270 EXPECT_EQ(mplgn0.size(), 1U);
271 Gis_multi_polygon mplgn= mplgn0;
272
273 plgn.inners().resize(1);
274 for (int i= 0; i < 4; i++)
275 (plgn.inners())[0].push_back(ls[i]);
276 mplgn.push_back(plgn);
277 plgn.to_wkb_unparsed();
278
279 Geometry_buffer buffer5;
280 String wkt5, str5;
281 wkt5.set(s5.c_str(), s5.length(), latincc);
282
283 Gis_polygon *plgn20=
284 static_cast<Gis_polygon *>(geometry_from_text(wkt5, &str5, &buffer5));
285 Gis_polygon plgn2(plgn20->get_data_ptr(), plgn20->get_data_size(),
286 plgn20->get_flags(), plgn20->get_srid());
287 EXPECT_EQ(plgn.get_data_size(), plgn2.get_nbytes());
288
289 mplgn.push_back(plgn2);
290
291 plgn2.to_wkb_unparsed();
292 EXPECT_EQ(memcmp(plgn.get_data_ptr(), plgn2.get_data_ptr(),
293 plgn2.get_data_size()), 0);
294
295
296 Geometry_buffer buffer4;
297 String wkt4, str4;
298 wkt4.set(s4.c_str(), s4.length(), latincc);
299
300 Gis_multi_polygon *mplgn2=
301 static_cast<Gis_multi_polygon *>(geometry_from_text(wkt4, &str4, &buffer4));
302
303 EXPECT_EQ(mplgn.get_data_size(), mplgn2->get_data_size());
304 EXPECT_EQ(memcmp(mplgn.get_data_ptr(), mplgn2->get_data_ptr(),
305 mplgn2->get_data_size()), 0);
306 }
307
308
TEST_F(GeometryManipulationTest,ResizeAssignmentTest)309 TEST_F(GeometryManipulationTest, ResizeAssignmentTest)
310 {
311 Gis_polygon_ring ring1;
312 Gis_line_string ls4, ls5, ls6, ls7, ls8;
313 for (int i = 0; i < 5; i++)
314 {
315 Gis_point pt;
316 pt.set<0>(i);
317 pt.set<1>(i);
318 ring1.push_back(pt);
319 ls4.push_back(pt);
320 ls6.push_back(pt);
321 ls7.push_back(pt);
322 if (i != 4)
323 ls8.push_back(pt);
324 }
325 Gis_point pt;
326 pt.set<0>(0);
327 pt.set<1>(0);
328 ls7.push_back(pt);
329
330
331 Gis_polygon plgn3, plgn4, plgn5;
332 plgn3.outer() = ring1;
333 plgn3.inners().push_back(ring1);
334 plgn3.inners().resize(plgn3.inners().size());
335
336 plgn5.outer() = *((Gis_polygon_ring *)(&ls8));
337 plgn5.inners().push_back(*((Gis_polygon_ring *)(&ls7)));
338 plgn5.inners().push_back(*((Gis_polygon_ring *)(&ls6)));
339
340 Gis_multi_polygon mplgn3, mplgn4;
341 mplgn3.push_back(plgn3);
342 mplgn3.resize(2);
343 assign_multipolygon_back(mplgn3, plgn5);
344 mplgn3.push_back(plgn3);
345 mplgn3.resize(4);
346 assign_multipolygon_back(mplgn3, plgn5);
347
348 mplgn4.resize(1);
349 assign_multipolygon_back(mplgn4, plgn3);
350 mplgn4.push_back(plgn5);
351 mplgn4.resize(3);
352 assign_multipolygon_back(mplgn4, plgn3);
353 mplgn4.push_back(plgn5);
354 mplgn3.reassemble();
355 mplgn4.reassemble();
356 EXPECT_EQ(mplgn3.get_ptr() != mplgn4.get_ptr() &&
357 mplgn3.get_nbytes() == mplgn4.get_nbytes() &&
358 memcmp(mplgn3.get_ptr(), mplgn4.get_ptr(),
359 mplgn3.get_nbytes()) == 0, true);
360
361
362 Gis_multi_line_string mls1, mls2;
363 mls1.resize(1);
364 for (size_t i= 0; i < ls4.size(); i++)
365 mls1.back().push_back(ls4[i]);
366 mls1.push_back(ls6);
367 mls1.resize(3);
368 for (size_t i= 0; i < ls7.size(); i++)
369 mls1.back().push_back(ls7[i]);
370 mls1.push_back(ls8);
371
372 mls2.push_back(ls4);
373 mls2.resize(2);
374 for (size_t i= 0; i < ls6.size(); i++)
375 mls2.back().push_back(ls6[i]);
376
377 mls2.push_back(ls7);
378 mls2.resize(4);
379 for (size_t i= 0; i < ls8.size(); i++)
380 mls2.back().push_back(ls8[i]);
381
382 mls1.reassemble();
383 mls2.reassemble();
384 EXPECT_EQ(mls1.get_ptr() != mls2.get_ptr() &&
385 mls1.get_nbytes() == mls2.get_nbytes() &&
386 memcmp(mls1.get_ptr(), mls2.get_ptr(), mls1.get_nbytes()) == 0,
387 true);
388 String str1, str2;
389 str1.append(mls1.get_cptr(), mls1.get_nbytes(), &my_charset_bin);
390 Gis_geometry_collection geocol(0, Geometry::wkb_multipolygon, &str1, &str2);
391
392 ls4= ls5;
393 EXPECT_EQ(ls4.get_ptr() == NULL && ls4.get_nbytes() == 0, true);
394 EXPECT_EQ(ls5.get_ptr() == NULL && ls5.get_nbytes() == 0, true);
395 plgn3= plgn4;
396 plgn3.to_wkb_unparsed();
397 EXPECT_EQ(plgn3.get_ptr() == NULL && plgn3.get_nbytes() == 0, true);
398
399 ls4= ls6;
400 EXPECT_EQ(ls4.get_ptr() != ls6.get_ptr() &&
401 ls4.get_nbytes() == ls6.get_nbytes() &&
402 memcmp(ls4.get_ptr(), ls6.get_ptr(), ls6.get_nbytes()) == 0, true);
403
404 ls4= ls7;
405 EXPECT_EQ(ls4.get_ptr() != ls7.get_ptr() &&
406 ls4.get_nbytes() == ls7.get_nbytes() &&
407 memcmp(ls4.get_ptr(), ls7.get_ptr(), ls7.get_nbytes()) == 0, true);
408
409 ls4= ls6;
410 EXPECT_EQ(ls4.get_ptr() != ls6.get_ptr() &&
411 ls4.get_nbytes() == ls6.get_nbytes() &&
412 memcmp(ls4.get_ptr(), ls6.get_ptr(), ls6.get_nbytes()) == 0, true);
413
414 void *buf= gis_wkb_alloc(ls8.get_nbytes() + 32);
415 memcpy(buf, ls8.get_ptr(), ls8.get_nbytes());
416 char *cbuf= static_cast<char *>(buf);
417 memset(cbuf + ls8.get_nbytes(), 0xff, 32);
418 cbuf[ls8.get_nbytes() + 31] = '\0';
419
420 ls4.set_ptr(buf, ls8.get_nbytes());
421 EXPECT_EQ(ls4.get_ptr() != ls8.get_ptr() &&
422 ls4.get_nbytes() == ls8.get_nbytes() &&
423 memcmp(ls4.get_ptr(), ls8.get_ptr(), ls8.get_nbytes()) == 0, true);
424
425 for (size_t i= ls4.size() + 1; i < 64; i++)
426 {
427 ls4.resize(i);
428 ls4.back().set<0>(i);
429 ls4.back().set<1>(i);
430 }
431 }
432
433
434 /*
435 Tests of miscellineous GIS functionalities.
436 */
437 class GisMiscTests : public ::testing::Test
438 {
439 public:
440 };
441
TEST_F(GisMiscTests,PointxyDistanceTest)442 TEST_F(GisMiscTests, PointxyDistanceTest)
443 {
444 const point_xy pt1(1.0, 1.0);
445 const point_xy pt2(1e300, -1e300);
446 const point_xy pt3(1e300, 1);
447 const point_xy pt4(1, 1e300);
448 const point_xy pt5(pt2);
449
450 EXPECT_FALSE(my_isfinite(pt1.distance(pt2)));
451 EXPECT_FALSE(my_isfinite(pt1.distance(pt3)));
452 EXPECT_FALSE(my_isfinite(pt1.distance(pt4)));
453 EXPECT_FALSE(my_isfinite(pt2.distance(pt3)));
454 EXPECT_FALSE(my_isfinite(pt2.distance(pt4)));
455 EXPECT_FALSE(my_isfinite(pt3.distance(pt4)));
456 EXPECT_FLOAT_EQ(0.0, pt2.distance(pt5));
457 }
458
459 }
460