Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////////
2 : //
3 : // Project: C++ Test Suite for GDAL/OGR
4 : // Purpose: Test GEOS integration in OGR - geometric operations.
5 : // Ported from ogr/ogr_geos.py.
6 : // Author: Mateusz Loskot <mateusz@loskot.net>
7 : //
8 : ///////////////////////////////////////////////////////////////////////////////
9 : // Copyright (c) 2006, Mateusz Loskot <mateusz@loskot.net>
10 : /*
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_unit_test.h"
31 :
32 : #include "ogr_api.h"
33 : #include "ogrsf_frmts.h"
34 :
35 : #ifdef HAVE_GEOS
36 : #include <geos_c.h>
37 : #endif
38 :
39 : #include <string>
40 :
41 : #include "gtest_include.h"
42 :
43 : namespace
44 : {
45 : using namespace tut; // for CheckEqualGeometries
46 :
47 : // Common fixture with test data
48 : struct test_ogr_geos : public ::testing::Test
49 : {
50 : OGRErr err_ = OGRERR_NONE;
51 : OGRGeometryH g1_ = nullptr;
52 : OGRGeometryH g2_ = nullptr;
53 : OGRGeometryH g3_ = nullptr;
54 :
55 14 : void SetUp() override
56 : {
57 : #ifndef HAVE_GEOS
58 : GTEST_SKIP() << "GEOS support is not available";
59 : #endif
60 14 : }
61 :
62 14 : void TearDown() override
63 : {
64 14 : OGR_G_DestroyGeometry(g1_);
65 14 : g1_ = nullptr;
66 14 : OGR_G_DestroyGeometry(g2_);
67 14 : g2_ = nullptr;
68 14 : OGR_G_DestroyGeometry(g3_);
69 14 : g3_ = nullptr;
70 14 : }
71 : };
72 :
73 : // Test export OGR geometry to GEOS using GDAL C++ API
74 4 : TEST_F(test_ogr_geos, exportToGEOS)
75 : {
76 : #ifdef HAVE_GEOS
77 1 : const char *wkt = "POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))";
78 1 : OGRPolygon geom;
79 1 : err_ = geom.importFromWkt(&wkt);
80 1 : ASSERT_EQ(OGRERR_NONE, err_);
81 :
82 1 : GEOSContextHandle_t ctxt = OGRGeometry::createGEOSContext();
83 1 : GEOSGeom geosGeom = geom.exportToGEOS(ctxt);
84 1 : OGRGeometry::freeGEOSContext(ctxt);
85 1 : ASSERT_TRUE(nullptr != geosGeom);
86 :
87 1 : GEOSGeom_destroy_r(ctxt, geosGeom);
88 : #endif
89 : }
90 :
91 : // Test OGR_G_Contains function
92 4 : TEST_F(test_ogr_geos, OGR_G_Contains)
93 : {
94 1 : char *wktOuter =
95 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
96 1 : err_ = OGR_G_CreateFromWkt(&wktOuter, nullptr, &g1_);
97 1 : ASSERT_EQ(OGRERR_NONE, err_);
98 1 : ASSERT_TRUE(nullptr != g1_);
99 :
100 1 : char *wktInner = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
101 1 : err_ = OGR_G_CreateFromWkt(&wktInner, nullptr, &g2_);
102 1 : ASSERT_EQ(OGRERR_NONE, err_);
103 1 : ASSERT_TRUE(nullptr != g2_);
104 :
105 1 : ASSERT_EQ(OGR_G_Contains(g1_, g2_), TRUE);
106 1 : ASSERT_EQ(OGR_G_Contains(g2_, g1_), FALSE);
107 : }
108 :
109 : // Test OGR_G_Crosses function
110 4 : TEST_F(test_ogr_geos, OGR_G_Crosses)
111 : {
112 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
113 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
114 1 : ASSERT_EQ(OGRERR_NONE, err_);
115 1 : ASSERT_TRUE(nullptr != g1_);
116 :
117 1 : char *wkt2 = const_cast<char *>("LINESTRING(10 0, 0 10)");
118 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
119 1 : ASSERT_EQ(OGRERR_NONE, err_);
120 1 : ASSERT_TRUE(nullptr != g2_);
121 :
122 1 : ASSERT_EQ(OGR_G_Crosses(g1_, g2_), TRUE);
123 :
124 1 : char *wkt3 = const_cast<char *>("LINESTRING(0 0, 0 10)");
125 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
126 1 : ASSERT_EQ(OGRERR_NONE, err_);
127 1 : ASSERT_TRUE(nullptr != g3_);
128 :
129 1 : ASSERT_EQ(OGR_G_Crosses(g1_, g3_), FALSE);
130 : }
131 :
132 : // Test OGR_G_Disjoint function
133 4 : TEST_F(test_ogr_geos, OGR_G_Disjoint)
134 : {
135 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
136 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
137 1 : ASSERT_EQ(OGRERR_NONE, err_);
138 1 : ASSERT_TRUE(nullptr != g1_);
139 :
140 1 : char *wkt2 = const_cast<char *>("LINESTRING(10 0, 0 10)");
141 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
142 1 : ASSERT_EQ(OGRERR_NONE, err_);
143 1 : ASSERT_TRUE(nullptr != g2_);
144 :
145 1 : ASSERT_EQ(OGR_G_Disjoint(g1_, g2_), FALSE);
146 :
147 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
148 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
149 1 : ASSERT_EQ(OGRERR_NONE, err_);
150 1 : ASSERT_TRUE(nullptr != g3_);
151 :
152 1 : ASSERT_EQ(OGR_G_Disjoint(g1_, g3_), TRUE);
153 : }
154 :
155 : // Test OGR_G_Equals function
156 4 : TEST_F(test_ogr_geos, OGR_G_Equals)
157 : {
158 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
159 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
160 1 : ASSERT_EQ(OGRERR_NONE, err_);
161 1 : ASSERT_TRUE(nullptr != g1_);
162 :
163 1 : char *wkt2 = const_cast<char *>("LINESTRING(0 0, 10 10)");
164 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
165 1 : ASSERT_EQ(OGRERR_NONE, err_);
166 1 : ASSERT_TRUE(nullptr != g2_);
167 :
168 1 : ASSERT_EQ(OGR_G_Equals(g1_, g2_), TRUE);
169 :
170 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
171 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
172 1 : ASSERT_EQ(OGRERR_NONE, err_);
173 1 : ASSERT_TRUE(nullptr != g3_);
174 :
175 1 : ASSERT_EQ(OGR_G_Equals(g1_, g3_), FALSE);
176 : }
177 :
178 : // Test OGR_G_Intersects function
179 4 : TEST_F(test_ogr_geos, OGR_G_Intersects)
180 : {
181 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
182 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
183 1 : ASSERT_EQ(OGRERR_NONE, err_);
184 1 : ASSERT_TRUE(nullptr != g1_);
185 :
186 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
187 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
188 1 : ASSERT_EQ(OGRERR_NONE, err_);
189 1 : ASSERT_TRUE(nullptr != g2_);
190 :
191 1 : ASSERT_EQ(OGR_G_Intersects(g1_, g2_), TRUE);
192 :
193 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 40 20, 40 40, 20 20))");
194 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
195 1 : ASSERT_EQ(OGRERR_NONE, err_);
196 1 : ASSERT_TRUE(nullptr != g3_);
197 :
198 1 : ASSERT_EQ(OGR_G_Intersects(g1_, g3_), FALSE);
199 : }
200 :
201 : // Test OGR_G_Overlaps function
202 4 : TEST_F(test_ogr_geos, OGR_G_Overlaps)
203 : {
204 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
205 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
206 1 : ASSERT_EQ(OGRERR_NONE, err_);
207 1 : ASSERT_TRUE(nullptr != g1_);
208 :
209 1 : char *wkt2 =
210 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
211 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
212 1 : ASSERT_EQ(OGRERR_NONE, err_);
213 1 : ASSERT_TRUE(nullptr != g2_);
214 :
215 1 : ASSERT_EQ(OGR_G_Overlaps(g1_, g2_), FALSE);
216 : }
217 :
218 : // Test OGR_G_Touches function
219 4 : TEST_F(test_ogr_geos, OGR_G_Touches)
220 : {
221 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
222 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
223 1 : ASSERT_EQ(OGRERR_NONE, err_);
224 1 : ASSERT_TRUE(nullptr != g1_);
225 :
226 1 : char *wkt2 = const_cast<char *>("LINESTRING(0 0, 0 10)");
227 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
228 1 : ASSERT_EQ(OGRERR_NONE, err_);
229 1 : ASSERT_TRUE(nullptr != g2_);
230 :
231 1 : ASSERT_EQ(OGR_G_Touches(g1_, g2_), TRUE);
232 :
233 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
234 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
235 1 : ASSERT_EQ(OGRERR_NONE, err_);
236 1 : ASSERT_TRUE(nullptr != g3_);
237 :
238 1 : ASSERT_EQ(OGR_G_Touches(g1_, g3_), FALSE);
239 : }
240 :
241 : // Test OGR_G_Within function
242 4 : TEST_F(test_ogr_geos, OGR_G_Within)
243 : {
244 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
245 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
246 1 : ASSERT_EQ(OGRERR_NONE, err_);
247 1 : ASSERT_TRUE(nullptr != g1_);
248 :
249 1 : char *wkt2 =
250 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
251 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
252 1 : ASSERT_EQ(OGRERR_NONE, err_);
253 1 : ASSERT_TRUE(nullptr != g2_);
254 :
255 1 : ASSERT_EQ(OGR_G_Within(g1_, g2_), TRUE);
256 :
257 1 : ASSERT_EQ(OGR_G_Within(g2_, g1_), FALSE);
258 : }
259 :
260 : // Test OGR_G_Union function
261 4 : TEST_F(test_ogr_geos, OGR_G_Union)
262 : {
263 1 : char *wkt1 = const_cast<char *>("POINT(10 20)");
264 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
265 1 : ASSERT_EQ(OGRERR_NONE, err_);
266 1 : ASSERT_TRUE(nullptr != g1_);
267 :
268 1 : char *wkt2 = const_cast<char *>("POINT(30 20)");
269 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
270 1 : ASSERT_EQ(OGRERR_NONE, err_);
271 1 : ASSERT_TRUE(nullptr != g2_);
272 :
273 1 : g3_ = OGR_G_Union(g1_, g2_);
274 1 : ASSERT_TRUE(nullptr != g3_);
275 :
276 1 : OGRGeometryH expect = nullptr;
277 1 : char *wktExpect = const_cast<char *>("MULTIPOINT (10 20,30 20)");
278 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
279 1 : ASSERT_EQ(OGRERR_NONE, err_);
280 1 : ASSERT_TRUE(nullptr != expect);
281 :
282 : // Compare operation result against expected geometry
283 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
284 :
285 1 : OGR_G_DestroyGeometry(expect);
286 : }
287 :
288 : // Test OGR_G_UnaryUnion function
289 4 : TEST_F(test_ogr_geos, OGR_G_UnaryUnion)
290 : {
291 1 : char *wkt = const_cast<char *>("GEOMETRYCOLLECTION(POINT(0.5 0.5),"
292 : "POLYGON((0 0,0 1,1 1,1 0,0 0)),"
293 : "POLYGON((1 0,1 1,2 1,2 0,1 0)))");
294 1 : err_ = OGR_G_CreateFromWkt(&wkt, nullptr, &g1_);
295 :
296 1 : g3_ = OGR_G_UnaryUnion(g1_);
297 1 : ASSERT_TRUE(nullptr != g3_);
298 :
299 1 : OGRGeometryH expect = nullptr;
300 1 : char *wktExpect =
301 : const_cast<char *>("POLYGON ((0 1,1 1,2 1,2 0,1 0,0 0,0 1))");
302 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
303 1 : ASSERT_EQ(OGRERR_NONE, err_);
304 1 : ASSERT_TRUE(nullptr != expect);
305 :
306 1 : OGREnvelope sEnvelopeIn;
307 1 : OGREnvelope sEnvelopeOut;
308 1 : OGR_G_GetEnvelope(g1_, &sEnvelopeIn);
309 1 : OGR_G_GetEnvelope(g3_, &sEnvelopeOut);
310 :
311 : // CheckEqualGeometries() doesn't work with GEOS 3.6 with the above
312 : // expected polygon, because of the order of the nodes, and for some
313 : // reason OGR_G_Normalize() in CheckEqualGeometries() doesn't fix this,
314 : // so just fallback to bounding box and area comparison
315 1 : EXPECT_EQ(sEnvelopeIn.MinX, sEnvelopeOut.MinX);
316 1 : EXPECT_EQ(sEnvelopeIn.MinY, sEnvelopeOut.MinY);
317 1 : EXPECT_EQ(sEnvelopeIn.MaxX, sEnvelopeOut.MaxX);
318 1 : EXPECT_EQ(sEnvelopeIn.MaxY, sEnvelopeOut.MaxY);
319 1 : EXPECT_EQ(OGR_G_Area(g1_), OGR_G_Area(g3_));
320 :
321 1 : OGR_G_DestroyGeometry(expect);
322 : }
323 :
324 : // Test OGR_G_Intersection function
325 4 : TEST_F(test_ogr_geos, OGR_G_Intersection)
326 : {
327 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
328 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
329 1 : ASSERT_EQ(OGRERR_NONE, err_);
330 1 : ASSERT_TRUE(nullptr != g1_);
331 :
332 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
333 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
334 1 : ASSERT_EQ(OGRERR_NONE, err_);
335 1 : ASSERT_TRUE(nullptr != g2_);
336 :
337 1 : g3_ = OGR_G_Intersection(g1_, g2_);
338 1 : ASSERT_TRUE(nullptr != g3_);
339 :
340 1 : OGRGeometryH expect = nullptr;
341 1 : char *wktExpect = const_cast<char *>("POLYGON ((0 0,5 5,10 0,0 0))");
342 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
343 1 : ASSERT_EQ(OGRERR_NONE, err_);
344 1 : ASSERT_TRUE(nullptr != expect);
345 :
346 : // Compare operation result against expected geometry
347 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
348 :
349 1 : OGR_G_DestroyGeometry(expect);
350 : }
351 :
352 : // Test OGR_G_Difference function
353 4 : TEST_F(test_ogr_geos, OGR_G_Difference)
354 : {
355 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
356 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
357 1 : ASSERT_EQ(OGRERR_NONE, err_);
358 1 : ASSERT_TRUE(nullptr != g1_);
359 :
360 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
361 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
362 1 : ASSERT_EQ(OGRERR_NONE, err_);
363 1 : ASSERT_TRUE(nullptr != g2_);
364 :
365 1 : g3_ = OGR_G_Difference(g1_, g2_);
366 1 : ASSERT_TRUE(nullptr != g3_);
367 :
368 1 : OGRGeometryH expect = nullptr;
369 1 : char *wktExpect = const_cast<char *>("POLYGON ((5 5,10 10,10 0,5 5))");
370 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
371 1 : ASSERT_EQ(OGRERR_NONE, err_);
372 1 : ASSERT_TRUE(nullptr != expect);
373 :
374 : // Compare operation result against expected geometry
375 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
376 :
377 1 : OGR_G_DestroyGeometry(expect);
378 : }
379 :
380 : // Test OGR_G_SymDifference function
381 4 : TEST_F(test_ogr_geos, OGR_G_SymDifference)
382 : {
383 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
384 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
385 1 : ASSERT_EQ(OGRERR_NONE, err_);
386 1 : ASSERT_TRUE(nullptr != g1_);
387 :
388 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
389 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
390 1 : ASSERT_EQ(OGRERR_NONE, err_);
391 1 : ASSERT_TRUE(nullptr != g2_);
392 :
393 1 : g3_ = OGR_G_SymDifference(g1_, g2_);
394 1 : ASSERT_TRUE(nullptr != g3_);
395 :
396 1 : OGRGeometryH expect = nullptr;
397 1 : char *wktExpect = const_cast<char *>(
398 : "MULTIPOLYGON (((5 5,0 0,0 10,5 5)),((5 5,10 10,10 0,5 5)))");
399 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
400 1 : ASSERT_EQ(OGRERR_NONE, err_);
401 1 : ASSERT_TRUE(nullptr != expect);
402 :
403 : // Compare operation result against expected geometry
404 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
405 :
406 1 : OGR_G_DestroyGeometry(expect);
407 : }
408 : } // namespace
|