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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "gdal_unit_test.h"
15 :
16 : #include "ogr_api.h"
17 : #include "ogrsf_frmts.h"
18 :
19 : #ifdef HAVE_GEOS
20 : #include <geos_c.h>
21 : #endif
22 :
23 : #include <string>
24 :
25 : #include "gtest_include.h"
26 :
27 : namespace
28 : {
29 : using namespace tut; // for CheckEqualGeometries
30 :
31 : // Common fixture with test data
32 : struct test_ogr_geos : public ::testing::Test
33 : {
34 : OGRErr err_ = OGRERR_NONE;
35 : OGRGeometryH g1_ = nullptr;
36 : OGRGeometryH g2_ = nullptr;
37 : OGRGeometryH g3_ = nullptr;
38 :
39 14 : void SetUp() override
40 : {
41 : #ifndef HAVE_GEOS
42 : GTEST_SKIP() << "GEOS support is not available";
43 : #endif
44 14 : }
45 :
46 14 : void TearDown() override
47 : {
48 14 : OGR_G_DestroyGeometry(g1_);
49 14 : g1_ = nullptr;
50 14 : OGR_G_DestroyGeometry(g2_);
51 14 : g2_ = nullptr;
52 14 : OGR_G_DestroyGeometry(g3_);
53 14 : g3_ = nullptr;
54 14 : }
55 : };
56 :
57 : // Test export OGR geometry to GEOS using GDAL C++ API
58 4 : TEST_F(test_ogr_geos, exportToGEOS)
59 : {
60 : #ifdef HAVE_GEOS
61 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))";
62 1 : OGRPolygon geom;
63 1 : err_ = geom.importFromWkt(&wkt);
64 1 : ASSERT_EQ(OGRERR_NONE, err_);
65 :
66 1 : GEOSContextHandle_t ctxt = OGRGeometry::createGEOSContext();
67 1 : GEOSGeom geosGeom = geom.exportToGEOS(ctxt);
68 1 : OGRGeometry::freeGEOSContext(ctxt);
69 1 : ASSERT_TRUE(nullptr != geosGeom);
70 :
71 1 : GEOSGeom_destroy_r(ctxt, geosGeom);
72 : #endif
73 : }
74 :
75 : // Test OGR_G_Contains function
76 4 : TEST_F(test_ogr_geos, OGR_G_Contains)
77 : {
78 1 : char *wktOuter =
79 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
80 1 : err_ = OGR_G_CreateFromWkt(&wktOuter, nullptr, &g1_);
81 1 : ASSERT_EQ(OGRERR_NONE, err_);
82 1 : ASSERT_TRUE(nullptr != g1_);
83 :
84 1 : char *wktInner = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
85 1 : err_ = OGR_G_CreateFromWkt(&wktInner, nullptr, &g2_);
86 1 : ASSERT_EQ(OGRERR_NONE, err_);
87 1 : ASSERT_TRUE(nullptr != g2_);
88 :
89 1 : ASSERT_EQ(OGR_G_Contains(g1_, g2_), TRUE);
90 1 : ASSERT_EQ(OGR_G_Contains(g2_, g1_), FALSE);
91 : }
92 :
93 : // Test OGR_G_Crosses function
94 4 : TEST_F(test_ogr_geos, OGR_G_Crosses)
95 : {
96 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
97 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
98 1 : ASSERT_EQ(OGRERR_NONE, err_);
99 1 : ASSERT_TRUE(nullptr != g1_);
100 :
101 1 : char *wkt2 = const_cast<char *>("LINESTRING(10 0, 0 10)");
102 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
103 1 : ASSERT_EQ(OGRERR_NONE, err_);
104 1 : ASSERT_TRUE(nullptr != g2_);
105 :
106 1 : ASSERT_EQ(OGR_G_Crosses(g1_, g2_), TRUE);
107 :
108 1 : char *wkt3 = const_cast<char *>("LINESTRING(0 0, 0 10)");
109 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
110 1 : ASSERT_EQ(OGRERR_NONE, err_);
111 1 : ASSERT_TRUE(nullptr != g3_);
112 :
113 1 : ASSERT_EQ(OGR_G_Crosses(g1_, g3_), FALSE);
114 : }
115 :
116 : // Test OGR_G_Disjoint function
117 4 : TEST_F(test_ogr_geos, OGR_G_Disjoint)
118 : {
119 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
120 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
121 1 : ASSERT_EQ(OGRERR_NONE, err_);
122 1 : ASSERT_TRUE(nullptr != g1_);
123 :
124 1 : char *wkt2 = const_cast<char *>("LINESTRING(10 0, 0 10)");
125 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
126 1 : ASSERT_EQ(OGRERR_NONE, err_);
127 1 : ASSERT_TRUE(nullptr != g2_);
128 :
129 1 : ASSERT_EQ(OGR_G_Disjoint(g1_, g2_), FALSE);
130 :
131 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
132 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
133 1 : ASSERT_EQ(OGRERR_NONE, err_);
134 1 : ASSERT_TRUE(nullptr != g3_);
135 :
136 1 : ASSERT_EQ(OGR_G_Disjoint(g1_, g3_), TRUE);
137 : }
138 :
139 : // Test OGR_G_Equals function
140 4 : TEST_F(test_ogr_geos, OGR_G_Equals)
141 : {
142 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
143 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
144 1 : ASSERT_EQ(OGRERR_NONE, err_);
145 1 : ASSERT_TRUE(nullptr != g1_);
146 :
147 1 : char *wkt2 = const_cast<char *>("LINESTRING(0 0, 10 10)");
148 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
149 1 : ASSERT_EQ(OGRERR_NONE, err_);
150 1 : ASSERT_TRUE(nullptr != g2_);
151 :
152 1 : ASSERT_EQ(OGR_G_Equals(g1_, g2_), TRUE);
153 :
154 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
155 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
156 1 : ASSERT_EQ(OGRERR_NONE, err_);
157 1 : ASSERT_TRUE(nullptr != g3_);
158 :
159 1 : ASSERT_EQ(OGR_G_Equals(g1_, g3_), FALSE);
160 : }
161 :
162 : // Test OGR_G_Intersects function
163 4 : TEST_F(test_ogr_geos, OGR_G_Intersects)
164 : {
165 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
166 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
167 1 : ASSERT_EQ(OGRERR_NONE, err_);
168 1 : ASSERT_TRUE(nullptr != g1_);
169 :
170 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
171 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
172 1 : ASSERT_EQ(OGRERR_NONE, err_);
173 1 : ASSERT_TRUE(nullptr != g2_);
174 :
175 1 : ASSERT_EQ(OGR_G_Intersects(g1_, g2_), TRUE);
176 :
177 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 40 20, 40 40, 20 20))");
178 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
179 1 : ASSERT_EQ(OGRERR_NONE, err_);
180 1 : ASSERT_TRUE(nullptr != g3_);
181 :
182 1 : ASSERT_EQ(OGR_G_Intersects(g1_, g3_), FALSE);
183 : }
184 :
185 : // Test OGR_G_Overlaps function
186 4 : TEST_F(test_ogr_geos, OGR_G_Overlaps)
187 : {
188 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
189 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
190 1 : ASSERT_EQ(OGRERR_NONE, err_);
191 1 : ASSERT_TRUE(nullptr != g1_);
192 :
193 1 : char *wkt2 =
194 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
195 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
196 1 : ASSERT_EQ(OGRERR_NONE, err_);
197 1 : ASSERT_TRUE(nullptr != g2_);
198 :
199 1 : ASSERT_EQ(OGR_G_Overlaps(g1_, g2_), FALSE);
200 : }
201 :
202 : // Test OGR_G_Touches function
203 4 : TEST_F(test_ogr_geos, OGR_G_Touches)
204 : {
205 1 : char *wkt1 = const_cast<char *>("LINESTRING(0 0, 10 10)");
206 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
207 1 : ASSERT_EQ(OGRERR_NONE, err_);
208 1 : ASSERT_TRUE(nullptr != g1_);
209 :
210 1 : char *wkt2 = const_cast<char *>("LINESTRING(0 0, 0 10)");
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_Touches(g1_, g2_), TRUE);
216 :
217 1 : char *wkt3 = const_cast<char *>("POLYGON((20 20, 20 30, 30 20, 20 20))");
218 1 : err_ = OGR_G_CreateFromWkt(&wkt3, nullptr, &g3_);
219 1 : ASSERT_EQ(OGRERR_NONE, err_);
220 1 : ASSERT_TRUE(nullptr != g3_);
221 :
222 1 : ASSERT_EQ(OGR_G_Touches(g1_, g3_), FALSE);
223 : }
224 :
225 : // Test OGR_G_Within function
226 4 : TEST_F(test_ogr_geos, OGR_G_Within)
227 : {
228 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
229 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
230 1 : ASSERT_EQ(OGRERR_NONE, err_);
231 1 : ASSERT_TRUE(nullptr != g1_);
232 :
233 1 : char *wkt2 =
234 : const_cast<char *>("POLYGON((-90 -90, -90 90, 190 -90, -90 -90))");
235 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
236 1 : ASSERT_EQ(OGRERR_NONE, err_);
237 1 : ASSERT_TRUE(nullptr != g2_);
238 :
239 1 : ASSERT_EQ(OGR_G_Within(g1_, g2_), TRUE);
240 :
241 1 : ASSERT_EQ(OGR_G_Within(g2_, g1_), FALSE);
242 : }
243 :
244 : // Test OGR_G_Union function
245 4 : TEST_F(test_ogr_geos, OGR_G_Union)
246 : {
247 1 : char *wkt1 = const_cast<char *>("POINT(10 20)");
248 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
249 1 : ASSERT_EQ(OGRERR_NONE, err_);
250 1 : ASSERT_TRUE(nullptr != g1_);
251 :
252 1 : char *wkt2 = const_cast<char *>("POINT(30 20)");
253 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
254 1 : ASSERT_EQ(OGRERR_NONE, err_);
255 1 : ASSERT_TRUE(nullptr != g2_);
256 :
257 1 : g3_ = OGR_G_Union(g1_, g2_);
258 1 : ASSERT_TRUE(nullptr != g3_);
259 :
260 1 : OGRGeometryH expect = nullptr;
261 1 : char *wktExpect = const_cast<char *>("MULTIPOINT (10 20,30 20)");
262 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
263 1 : ASSERT_EQ(OGRERR_NONE, err_);
264 1 : ASSERT_TRUE(nullptr != expect);
265 :
266 : // Compare operation result against expected geometry
267 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
268 :
269 1 : OGR_G_DestroyGeometry(expect);
270 : }
271 :
272 : // Test OGR_G_UnaryUnion function
273 4 : TEST_F(test_ogr_geos, OGR_G_UnaryUnion)
274 : {
275 1 : char *wkt = const_cast<char *>("GEOMETRYCOLLECTION(POINT(0.5 0.5),"
276 : "POLYGON((0 0,0 1,1 1,1 0,0 0)),"
277 : "POLYGON((1 0,1 1,2 1,2 0,1 0)))");
278 1 : err_ = OGR_G_CreateFromWkt(&wkt, nullptr, &g1_);
279 :
280 1 : g3_ = OGR_G_UnaryUnion(g1_);
281 1 : ASSERT_TRUE(nullptr != g3_);
282 :
283 1 : OGRGeometryH expect = nullptr;
284 1 : char *wktExpect =
285 : const_cast<char *>("POLYGON ((0 1,1 1,2 1,2 0,1 0,0 0,0 1))");
286 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
287 1 : ASSERT_EQ(OGRERR_NONE, err_);
288 1 : ASSERT_TRUE(nullptr != expect);
289 :
290 1 : OGREnvelope sEnvelopeIn;
291 1 : OGREnvelope sEnvelopeOut;
292 1 : OGR_G_GetEnvelope(g1_, &sEnvelopeIn);
293 1 : OGR_G_GetEnvelope(g3_, &sEnvelopeOut);
294 :
295 : // CheckEqualGeometries() doesn't work with GEOS 3.6 with the above
296 : // expected polygon, because of the order of the nodes, and for some
297 : // reason OGR_G_Normalize() in CheckEqualGeometries() doesn't fix this,
298 : // so just fallback to bounding box and area comparison
299 1 : EXPECT_EQ(sEnvelopeIn.MinX, sEnvelopeOut.MinX);
300 1 : EXPECT_EQ(sEnvelopeIn.MinY, sEnvelopeOut.MinY);
301 1 : EXPECT_EQ(sEnvelopeIn.MaxX, sEnvelopeOut.MaxX);
302 1 : EXPECT_EQ(sEnvelopeIn.MaxY, sEnvelopeOut.MaxY);
303 1 : EXPECT_EQ(OGR_G_Area(g1_), OGR_G_Area(g3_));
304 :
305 1 : OGR_G_DestroyGeometry(expect);
306 : }
307 :
308 : // Test OGR_G_Intersection function
309 4 : TEST_F(test_ogr_geos, OGR_G_Intersection)
310 : {
311 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
312 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
313 1 : ASSERT_EQ(OGRERR_NONE, err_);
314 1 : ASSERT_TRUE(nullptr != g1_);
315 :
316 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
317 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
318 1 : ASSERT_EQ(OGRERR_NONE, err_);
319 1 : ASSERT_TRUE(nullptr != g2_);
320 :
321 1 : g3_ = OGR_G_Intersection(g1_, g2_);
322 1 : ASSERT_TRUE(nullptr != g3_);
323 :
324 1 : OGRGeometryH expect = nullptr;
325 1 : char *wktExpect = const_cast<char *>("POLYGON ((0 0,5 5,10 0,0 0))");
326 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
327 1 : ASSERT_EQ(OGRERR_NONE, err_);
328 1 : ASSERT_TRUE(nullptr != expect);
329 :
330 : // Compare operation result against expected geometry
331 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
332 :
333 1 : OGR_G_DestroyGeometry(expect);
334 : }
335 :
336 : // Test OGR_G_Difference function
337 4 : TEST_F(test_ogr_geos, OGR_G_Difference)
338 : {
339 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
340 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
341 1 : ASSERT_EQ(OGRERR_NONE, err_);
342 1 : ASSERT_TRUE(nullptr != g1_);
343 :
344 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
345 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
346 1 : ASSERT_EQ(OGRERR_NONE, err_);
347 1 : ASSERT_TRUE(nullptr != g2_);
348 :
349 1 : g3_ = OGR_G_Difference(g1_, g2_);
350 1 : ASSERT_TRUE(nullptr != g3_);
351 :
352 1 : OGRGeometryH expect = nullptr;
353 1 : char *wktExpect = const_cast<char *>("POLYGON ((5 5,10 10,10 0,5 5))");
354 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
355 1 : ASSERT_EQ(OGRERR_NONE, err_);
356 1 : ASSERT_TRUE(nullptr != expect);
357 :
358 : // Compare operation result against expected geometry
359 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
360 :
361 1 : OGR_G_DestroyGeometry(expect);
362 : }
363 :
364 : // Test OGR_G_SymDifference function
365 4 : TEST_F(test_ogr_geos, OGR_G_SymDifference)
366 : {
367 1 : char *wkt1 = const_cast<char *>("POLYGON((0 0, 10 10, 10 0, 0 0))");
368 1 : err_ = OGR_G_CreateFromWkt(&wkt1, nullptr, &g1_);
369 1 : ASSERT_EQ(OGRERR_NONE, err_);
370 1 : ASSERT_TRUE(nullptr != g1_);
371 :
372 1 : char *wkt2 = const_cast<char *>("POLYGON((0 0, 0 10, 10 0, 0 0))");
373 1 : err_ = OGR_G_CreateFromWkt(&wkt2, nullptr, &g2_);
374 1 : ASSERT_EQ(OGRERR_NONE, err_);
375 1 : ASSERT_TRUE(nullptr != g2_);
376 :
377 1 : g3_ = OGR_G_SymDifference(g1_, g2_);
378 1 : ASSERT_TRUE(nullptr != g3_);
379 :
380 1 : OGRGeometryH expect = nullptr;
381 1 : char *wktExpect = const_cast<char *>(
382 : "MULTIPOLYGON (((5 5,0 0,0 10,5 5)),((5 5,10 10,10 0,5 5)))");
383 1 : err_ = OGR_G_CreateFromWkt(&wktExpect, nullptr, &expect);
384 1 : ASSERT_EQ(OGRERR_NONE, err_);
385 1 : ASSERT_TRUE(nullptr != expect);
386 :
387 : // Compare operation result against expected geometry
388 1 : EXPECT_TRUE(CheckEqualGeometries(g3_, expect, 0.0001));
389 :
390 1 : OGR_G_DestroyGeometry(expect);
391 : }
392 : } // namespace
|