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

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Test OGRGeometryFactory::organizePolygons
       5             :  * Author:   Daniel Baston <dbaston at gmail.com>
       6             :  *
       7             :  **********************************************************************
       8             :  * Copyright (c) 2023, ISciences LLC
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal_unit_test.h"
      14             : #include "cpl_string.h"
      15             : #include "ogr_geometry.h"
      16             : #include "gtest_include.h"
      17             : 
      18             : #include <vector>
      19             : 
      20             : static std::unique_ptr<OGRGeometry>
      21          33 : organizePolygons(std::vector<OGRGeometry *> &polygons,
      22             :                  const std::string &method)
      23             : {
      24          66 :     CPLStringList options;
      25          33 :     options.AddNameValue("METHOD", method.c_str());
      26             : 
      27             :     return std::unique_ptr<OGRGeometry>(OGRGeometryFactory::organizePolygons(
      28          33 :         polygons.data(), static_cast<int>(polygons.size()), nullptr,
      29          99 :         (const char **)options.List()));
      30             : }
      31             : 
      32          70 : static OGRGeometry *readWKT(const std::string &wkt)
      33             : {
      34             :     OGRGeometry *g;
      35          70 :     auto err = OGRGeometryFactory::createFromWkt(wkt.c_str(), nullptr, &g);
      36             : 
      37          70 :     if (err != OGRERR_NONE)
      38             :     {
      39           0 :         throw std::runtime_error("Failed to parse WKT");
      40             :     }
      41             : 
      42          70 :     return g;
      43             : }
      44             : 
      45             : class OrganizePolygonsTest : public testing::TestWithParam<std::string>
      46             : {
      47             : };
      48             : 
      49          88 : INSTANTIATE_TEST_SUITE_P(
      50             :     test_gdal, OrganizePolygonsTest,
      51             :     ::testing::Values("DEFAULT", "ONLY_CCW", "SKIP"),
      52             :     [](const ::testing::TestParamInfo<std::string> &param_info) -> std::string
      53             :     { return param_info.param; });
      54             : 
      55           7 : TEST_P(OrganizePolygonsTest, EmptyInputVector)
      56             : {
      57           3 :     std::vector<OGRGeometry *> polygons;
      58             : 
      59           3 :     const auto &method = GetParam();
      60           3 :     auto result = organizePolygons(polygons, method);
      61             : 
      62           3 :     ASSERT_NE(result, nullptr);
      63           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
      64           3 :     ASSERT_TRUE(result->IsEmpty());
      65             : }
      66             : 
      67           7 : TEST_P(OrganizePolygonsTest, SinglePolygonInput)
      68             : {
      69           3 :     std::vector<OGRGeometry *> polygons;
      70           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))"));
      71             : 
      72           3 :     std::unique_ptr<OGRGeometry> expected(polygons.front()->clone());
      73             : 
      74           3 :     const auto &method = GetParam();
      75           3 :     auto result = organizePolygons(polygons, method);
      76             : 
      77           3 :     ASSERT_NE(result, nullptr);
      78           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
      79           3 :     ASSERT_TRUE(result->Equals(expected.get()));
      80             : }
      81             : 
      82           7 : TEST_P(OrganizePolygonsTest, SingleCurvePolygonInput)
      83             : {
      84           3 :     std::vector<OGRGeometry *> polygons;
      85           3 :     polygons.push_back(readWKT("CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0))"));
      86             : 
      87           3 :     std::unique_ptr<OGRGeometry> expected(polygons.front()->clone());
      88             : 
      89           3 :     const auto &method = GetParam();
      90           3 :     auto result = organizePolygons(polygons, method);
      91             : 
      92           3 :     ASSERT_NE(result, nullptr);
      93           3 :     ASSERT_EQ(result->getGeometryType(), wkbCurvePolygon);
      94           3 :     ASSERT_TRUE(result->Equals(expected.get()));
      95             : }
      96             : 
      97           7 : TEST_P(OrganizePolygonsTest, SinglePointInput)
      98             : {
      99           3 :     std::vector<OGRGeometry *> polygons;
     100           3 :     polygons.push_back(readWKT("POINT (0 0)"));
     101             : 
     102           3 :     const auto &method = GetParam();
     103           3 :     auto result = organizePolygons(polygons, method);
     104             : 
     105           3 :     ASSERT_NE(result, nullptr);
     106           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
     107           3 :     ASSERT_TRUE(result->IsEmpty());
     108             : }
     109             : 
     110           7 : TEST_P(OrganizePolygonsTest, MixedPolygonCurvePolygonInput)
     111             : {
     112           3 :     std::vector<OGRGeometry *> polygons;
     113           3 :     polygons.push_back(
     114           3 :         readWKT("POLYGON ((10 10, 20 10, 20 20, 20 10, 10 10))"));
     115           3 :     polygons.push_back(readWKT("CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0))"));
     116             : 
     117           3 :     const auto &method = GetParam();
     118           3 :     auto result = organizePolygons(polygons, method);
     119             : 
     120           3 :     ASSERT_NE(result, nullptr);
     121           3 :     ASSERT_EQ(result->getGeometryType(), wkbMultiSurface);
     122             : 
     123             :     std::unique_ptr<OGRGeometry> expected(
     124             :         readWKT("MULTISURFACE ("
     125             :                 "POLYGON ((10 10, 20 10, 20 20, 20 10, 10 10)),"
     126           6 :                 "CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0)))"));
     127             : 
     128           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     129             : }
     130             : 
     131           7 : TEST_P(OrganizePolygonsTest, MixedPolygonPointInput)
     132             : {
     133           3 :     std::vector<OGRGeometry *> polygons;
     134           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))"));
     135           3 :     polygons.push_back(readWKT("POINT (2 2)"));
     136             : 
     137           3 :     std::unique_ptr<OGRGeometry> expected(polygons[0]->clone());
     138             : 
     139           3 :     const auto &method = GetParam();
     140           3 :     auto result = organizePolygons(polygons, method);
     141             : 
     142           3 :     ASSERT_NE(result, nullptr);
     143           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     144             : }
     145             : 
     146           7 : TEST_P(OrganizePolygonsTest, CWPolygonCCWHole)
     147             : {
     148           3 :     std::vector<OGRGeometry *> polygons;
     149           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"));
     150           3 :     polygons.push_back(readWKT("POLYGON ((1 1, 2 1, 2 2, 1 2, 1 1))"));
     151             : 
     152           3 :     const auto &method = GetParam();
     153           3 :     auto result = organizePolygons(polygons, method);
     154             : 
     155           3 :     ASSERT_NE(result, nullptr);
     156             : 
     157           0 :     std::unique_ptr<OGRGeometry> expected;
     158           3 :     if (method == "SKIP")
     159             :     {
     160           1 :         expected.reset(readWKT("MULTIPOLYGON (((0 0, 0 10, 10 10, 10 0, 0 0)), "
     161             :                                "((1 1, 2 1, 2 2, 1 2, 1 1)))"));
     162             :     }
     163             :     else
     164             :     {
     165           2 :         expected.reset(readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (1 1, "
     166             :                                "2 1, 2 2, 1 2, 1 1))"));
     167             :     }
     168             : 
     169           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     170             : }
     171             : 
     172           7 : TEST_P(OrganizePolygonsTest, CWPolygonCCWLakeCWIslandInLake)
     173             : {
     174           3 :     std::vector<OGRGeometry *> polygons;
     175           3 :     polygons.push_back(
     176           3 :         readWKT("POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"));  // CW
     177           3 :     polygons.push_back(
     178           3 :         readWKT("POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))"));  // CCW
     179           3 :     polygons.push_back(
     180           3 :         readWKT("POLYGON ((15 15, 15 16, 16 16, 16 15, 15 15))"));  // CW
     181             : 
     182           3 :     const auto &method = GetParam();
     183           3 :     auto result = organizePolygons(polygons, method);
     184             : 
     185           3 :     ASSERT_NE(result, nullptr);
     186             : 
     187           3 :     if (method != "SKIP")
     188             :     {
     189             :         std::unique_ptr<OGRGeometry> expected(
     190             :             readWKT("MULTIPOLYGON ("
     191             :                     "((0 0, 0 100, 100 100, 100 0, 0 0), (10 10, 20 10, 20 20, "
     192             :                     "10 20, 10 10)),"
     193           4 :                     "((15 15, 15 16, 16 16, 16 15, 15 15)))"));
     194           2 :         ASSERT_TRUE(result->Equals(expected.get()));
     195             :     }
     196             : }
     197             : 
     198           7 : TEST_P(OrganizePolygonsTest, AdjacentCCWPolygons)
     199             : {
     200           3 :     std::vector<OGRGeometry *> polygons;
     201           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"));  // CCW
     202           3 :     polygons.push_back(readWKT("POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))"));  // CCW
     203             : 
     204           3 :     const auto &method = GetParam();
     205           3 :     auto result = organizePolygons(polygons, method);
     206             : 
     207           3 :     ASSERT_NE(result, nullptr);
     208             : 
     209             :     std::unique_ptr<OGRGeometry> expected(
     210             :         readWKT("MULTIPOLYGON("
     211             :                 "((0 0, 1 0, 1 1, 0 1, 0 0)), "
     212           6 :                 "((1 0, 2 0, 2 1, 1 1, 1 0)))"));
     213           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     214             : }
     215             : 
     216           7 : TEST_P(OrganizePolygonsTest, HoleAlongEdge)
     217             : {
     218           3 :     std::vector<OGRGeometry *> polygons;
     219           3 :     polygons.push_back(
     220           3 :         readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"));             // CW
     221           3 :     polygons.push_back(readWKT("POLYGON ((0 2, 1 2, 1 3, 0 3, 0 2))"));  // CCW
     222             : 
     223           3 :     const auto &method = GetParam();
     224           3 :     auto result = organizePolygons(polygons, method);
     225             : 
     226           3 :     ASSERT_NE(result, nullptr);
     227             : 
     228           3 :     if (method != "SKIP")
     229             :     {
     230             :         std::unique_ptr<OGRGeometry> expected(
     231             :             readWKT("POLYGON("
     232             :                     "(0 0, 0 10, 10 10, 10 0, 0 0), "
     233           4 :                     "(0 2, 1 2, 1 3, 0 3, 0 2))"));
     234           2 :         ASSERT_TRUE(result->Equals(expected.get()));
     235             :     }
     236             : }
     237             : 
     238           7 : TEST_P(OrganizePolygonsTest, CrossingCCWPolygons)
     239             : {
     240           3 :     std::vector<OGRGeometry *> polygons;
     241           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"));
     242           3 :     polygons.push_back(readWKT("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"));
     243             : 
     244           3 :     const auto &method = GetParam();
     245           3 :     auto result = organizePolygons(polygons, method);
     246             : 
     247           3 :     ASSERT_NE(result, nullptr);
     248             : 
     249             :     std::unique_ptr<OGRGeometry> expected(
     250             :         readWKT("MULTIPOLYGON("
     251             :                 "((0 0, 10 0, 10 10, 0 10, 0 0)), "
     252           6 :                 "((5 5, 15 5, 15 15, 5 15, 5 5)))"));
     253           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     254             : }

Generated by: LCOV version 1.14