LCOV - code coverage report
Current view: top level - autotest/cpp - test_ogr_geos.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 219 219 100.0 %
Date: 2024-11-21 22:18:42 Functions: 58 58 100.0 %

          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

Generated by: LCOV version 1.14