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-05-13 13:33:37 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "gdal_unit_test.h"
      30             : #include "cpl_string.h"
      31             : #include "ogr_geometry.h"
      32             : #include "gtest_include.h"
      33             : 
      34             : #include <vector>
      35             : 
      36             : static std::unique_ptr<OGRGeometry>
      37          33 : organizePolygons(std::vector<OGRGeometry *> &polygons,
      38             :                  const std::string &method)
      39             : {
      40          66 :     CPLStringList options;
      41          33 :     options.AddNameValue("METHOD", method.c_str());
      42             : 
      43             :     return std::unique_ptr<OGRGeometry>(OGRGeometryFactory::organizePolygons(
      44          33 :         polygons.data(), static_cast<int>(polygons.size()), nullptr,
      45          99 :         (const char **)options.List()));
      46             : }
      47             : 
      48          70 : static OGRGeometry *readWKT(const std::string &wkt)
      49             : {
      50             :     OGRGeometry *g;
      51          70 :     auto err = OGRGeometryFactory::createFromWkt(wkt.c_str(), nullptr, &g);
      52             : 
      53          70 :     if (err != OGRERR_NONE)
      54             :     {
      55           0 :         throw std::runtime_error("Failed to parse WKT");
      56             :     }
      57             : 
      58          70 :     return g;
      59             : }
      60             : 
      61             : class OrganizePolygonsTest : public testing::TestWithParam<std::string>
      62             : {
      63             : };
      64             : 
      65          88 : INSTANTIATE_TEST_SUITE_P(
      66             :     test_gdal, OrganizePolygonsTest,
      67             :     ::testing::Values("DEFAULT", "ONLY_CCW", "SKIP"),
      68             :     [](const ::testing::TestParamInfo<std::string> &param_info) -> std::string
      69             :     { return param_info.param; });
      70             : 
      71           7 : TEST_P(OrganizePolygonsTest, EmptyInputVector)
      72             : {
      73           3 :     std::vector<OGRGeometry *> polygons;
      74             : 
      75           3 :     const auto &method = GetParam();
      76           3 :     auto result = organizePolygons(polygons, method);
      77             : 
      78           3 :     ASSERT_NE(result, nullptr);
      79           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
      80           3 :     ASSERT_TRUE(result->IsEmpty());
      81             : }
      82             : 
      83           7 : TEST_P(OrganizePolygonsTest, SinglePolygonInput)
      84             : {
      85           3 :     std::vector<OGRGeometry *> polygons;
      86           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))"));
      87             : 
      88           3 :     std::unique_ptr<OGRGeometry> expected(polygons.front()->clone());
      89             : 
      90           3 :     const auto &method = GetParam();
      91           3 :     auto result = organizePolygons(polygons, method);
      92             : 
      93           3 :     ASSERT_NE(result, nullptr);
      94           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
      95           3 :     ASSERT_TRUE(result->Equals(expected.get()));
      96             : }
      97             : 
      98           7 : TEST_P(OrganizePolygonsTest, SingleCurvePolygonInput)
      99             : {
     100           3 :     std::vector<OGRGeometry *> polygons;
     101           3 :     polygons.push_back(readWKT("CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0))"));
     102             : 
     103           3 :     std::unique_ptr<OGRGeometry> expected(polygons.front()->clone());
     104             : 
     105           3 :     const auto &method = GetParam();
     106           3 :     auto result = organizePolygons(polygons, method);
     107             : 
     108           3 :     ASSERT_NE(result, nullptr);
     109           3 :     ASSERT_EQ(result->getGeometryType(), wkbCurvePolygon);
     110           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     111             : }
     112             : 
     113           7 : TEST_P(OrganizePolygonsTest, SinglePointInput)
     114             : {
     115           3 :     std::vector<OGRGeometry *> polygons;
     116           3 :     polygons.push_back(readWKT("POINT (0 0)"));
     117             : 
     118           3 :     const auto &method = GetParam();
     119           3 :     auto result = organizePolygons(polygons, method);
     120             : 
     121           3 :     ASSERT_NE(result, nullptr);
     122           3 :     ASSERT_EQ(result->getGeometryType(), wkbPolygon);
     123           3 :     ASSERT_TRUE(result->IsEmpty());
     124             : }
     125             : 
     126           7 : TEST_P(OrganizePolygonsTest, MixedPolygonCurvePolygonInput)
     127             : {
     128           3 :     std::vector<OGRGeometry *> polygons;
     129           3 :     polygons.push_back(
     130           3 :         readWKT("POLYGON ((10 10, 20 10, 20 20, 20 10, 10 10))"));
     131           3 :     polygons.push_back(readWKT("CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0))"));
     132             : 
     133           3 :     const auto &method = GetParam();
     134           3 :     auto result = organizePolygons(polygons, method);
     135             : 
     136           3 :     ASSERT_NE(result, nullptr);
     137           3 :     ASSERT_EQ(result->getGeometryType(), wkbMultiSurface);
     138             : 
     139             :     std::unique_ptr<OGRGeometry> expected(
     140             :         readWKT("MULTISURFACE ("
     141             :                 "POLYGON ((10 10, 20 10, 20 20, 20 10, 10 10)),"
     142           6 :                 "CURVEPOLYGON ((0 0, 1 0, 1 1, 0 0)))"));
     143             : 
     144           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     145             : }
     146             : 
     147           7 : TEST_P(OrganizePolygonsTest, MixedPolygonPointInput)
     148             : {
     149           3 :     std::vector<OGRGeometry *> polygons;
     150           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))"));
     151           3 :     polygons.push_back(readWKT("POINT (2 2)"));
     152             : 
     153           3 :     std::unique_ptr<OGRGeometry> expected(polygons[0]->clone());
     154             : 
     155           3 :     const auto &method = GetParam();
     156           3 :     auto result = organizePolygons(polygons, method);
     157             : 
     158           3 :     ASSERT_NE(result, nullptr);
     159           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     160             : }
     161             : 
     162           7 : TEST_P(OrganizePolygonsTest, CWPolygonCCWHole)
     163             : {
     164           3 :     std::vector<OGRGeometry *> polygons;
     165           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"));
     166           3 :     polygons.push_back(readWKT("POLYGON ((1 1, 2 1, 2 2, 1 2, 1 1))"));
     167             : 
     168           3 :     const auto &method = GetParam();
     169           3 :     auto result = organizePolygons(polygons, method);
     170             : 
     171           3 :     ASSERT_NE(result, nullptr);
     172             : 
     173           0 :     std::unique_ptr<OGRGeometry> expected;
     174           3 :     if (method == "SKIP")
     175             :     {
     176           1 :         expected.reset(readWKT("MULTIPOLYGON (((0 0, 0 10, 10 10, 10 0, 0 0)), "
     177             :                                "((1 1, 2 1, 2 2, 1 2, 1 1)))"));
     178             :     }
     179             :     else
     180             :     {
     181           2 :         expected.reset(readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (1 1, "
     182             :                                "2 1, 2 2, 1 2, 1 1))"));
     183             :     }
     184             : 
     185           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     186             : }
     187             : 
     188           7 : TEST_P(OrganizePolygonsTest, CWPolygonCCWLakeCWIslandInLake)
     189             : {
     190           3 :     std::vector<OGRGeometry *> polygons;
     191           3 :     polygons.push_back(
     192           3 :         readWKT("POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"));  // CW
     193           3 :     polygons.push_back(
     194           3 :         readWKT("POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))"));  // CCW
     195           3 :     polygons.push_back(
     196           3 :         readWKT("POLYGON ((15 15, 15 16, 16 16, 16 15, 15 15))"));  // CW
     197             : 
     198           3 :     const auto &method = GetParam();
     199           3 :     auto result = organizePolygons(polygons, method);
     200             : 
     201           3 :     ASSERT_NE(result, nullptr);
     202             : 
     203           3 :     if (method != "SKIP")
     204             :     {
     205             :         std::unique_ptr<OGRGeometry> expected(
     206             :             readWKT("MULTIPOLYGON ("
     207             :                     "((0 0, 0 100, 100 100, 100 0, 0 0), (10 10, 20 10, 20 20, "
     208             :                     "10 20, 10 10)),"
     209           4 :                     "((15 15, 15 16, 16 16, 16 15, 15 15)))"));
     210           2 :         ASSERT_TRUE(result->Equals(expected.get()));
     211             :     }
     212             : }
     213             : 
     214           7 : TEST_P(OrganizePolygonsTest, AdjacentCCWPolygons)
     215             : {
     216           3 :     std::vector<OGRGeometry *> polygons;
     217           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"));  // CCW
     218           3 :     polygons.push_back(readWKT("POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))"));  // CCW
     219             : 
     220           3 :     const auto &method = GetParam();
     221           3 :     auto result = organizePolygons(polygons, method);
     222             : 
     223           3 :     ASSERT_NE(result, nullptr);
     224             : 
     225             :     std::unique_ptr<OGRGeometry> expected(
     226             :         readWKT("MULTIPOLYGON("
     227             :                 "((0 0, 1 0, 1 1, 0 1, 0 0)), "
     228           6 :                 "((1 0, 2 0, 2 1, 1 1, 1 0)))"));
     229           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     230             : }
     231             : 
     232           7 : TEST_P(OrganizePolygonsTest, HoleAlongEdge)
     233             : {
     234           3 :     std::vector<OGRGeometry *> polygons;
     235           3 :     polygons.push_back(
     236           3 :         readWKT("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"));             // CW
     237           3 :     polygons.push_back(readWKT("POLYGON ((0 2, 1 2, 1 3, 0 3, 0 2))"));  // CCW
     238             : 
     239           3 :     const auto &method = GetParam();
     240           3 :     auto result = organizePolygons(polygons, method);
     241             : 
     242           3 :     ASSERT_NE(result, nullptr);
     243             : 
     244           3 :     if (method != "SKIP")
     245             :     {
     246             :         std::unique_ptr<OGRGeometry> expected(
     247             :             readWKT("POLYGON("
     248             :                     "(0 0, 0 10, 10 10, 10 0, 0 0), "
     249           4 :                     "(0 2, 1 2, 1 3, 0 3, 0 2))"));
     250           2 :         ASSERT_TRUE(result->Equals(expected.get()));
     251             :     }
     252             : }
     253             : 
     254           7 : TEST_P(OrganizePolygonsTest, CrossingCCWPolygons)
     255             : {
     256           3 :     std::vector<OGRGeometry *> polygons;
     257           3 :     polygons.push_back(readWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"));
     258           3 :     polygons.push_back(readWKT("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"));
     259             : 
     260           3 :     const auto &method = GetParam();
     261           3 :     auto result = organizePolygons(polygons, method);
     262             : 
     263           3 :     ASSERT_NE(result, nullptr);
     264             : 
     265             :     std::unique_ptr<OGRGeometry> expected(
     266             :         readWKT("MULTIPOLYGON("
     267             :                 "((0 0, 10 0, 10 10, 0 10, 0 0)), "
     268           6 :                 "((5 5, 15 5, 15 15, 5 15, 5 5)))"));
     269           3 :     ASSERT_TRUE(result->Equals(expected.get()));
     270             : }

Generated by: LCOV version 1.14