LCOV - code coverage report
Current view: top level - autotest/cpp - test_marching_squares_polygon.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 122 124 98.4 %
Date: 2024-05-13 13:33:37 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  GDAL algorithms
       5             :  * Purpose:  Tests for the marching squares algorithm
       6             :  * Author:   Hugo Mercier, <hugo dot mercier at oslandia dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2018, Hugo Mercier, <hugo dot mercier at oslandia dot com>
      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 "gdal_alg.h"
      33             : 
      34             : #include "marching_squares/level_generator.h"
      35             : #include "marching_squares/polygon_ring_appender.h"
      36             : #include "marching_squares/segment_merger.h"
      37             : #include "marching_squares/contour_generator.h"
      38             : 
      39             : #ifdef DEBUG
      40             : #include <fstream>
      41             : #endif
      42             : 
      43             : #include "gtest_include.h"
      44             : 
      45             : namespace marching_squares
      46             : {
      47             : class TestPolygonWriter
      48             : {
      49             :   public:
      50          11 :     void startPolygon(double level)
      51             :     {
      52          11 :         currentPolygon_ = &polygons_[level];
      53          11 :     }
      54             : 
      55          11 :     void endPolygon()
      56             :     {
      57          11 :     }
      58             : 
      59          15 :     void addPart(const std::list<marching_squares::Point> &ring)
      60             :     {
      61          15 :         PolygonPart part;
      62          15 :         part.push_back(ring);
      63          15 :         currentPolygon_->emplace_back(part);
      64          15 :         currentPart_ = &currentPolygon_->back();
      65          15 :     }
      66             : 
      67           3 :     void addInteriorRing(const std::list<marching_squares::Point> &ring)
      68             :     {
      69           3 :         currentPart_->push_back(ring);
      70           3 :     }
      71             : 
      72          12 :     void out(std::ostream &ostr, double level) const
      73             :     {
      74          12 :         auto pIt = polygons_.find(level);
      75          12 :         if (pIt == polygons_.end())
      76           1 :             return;
      77             : 
      78          26 :         for (const auto &part : pIt->second)
      79             :         {
      80          15 :             ostr << "{ ";
      81          33 :             for (const auto &ring : part)
      82             :             {
      83          18 :                 ostr << "{ ";
      84         236 :                 for (const auto &pt : ring)
      85             :                 {
      86         218 :                     ostr << "(" << pt.x << "," << pt.y << ") ";
      87             :                 }
      88          18 :                 ostr << "} ";
      89             :             }
      90          15 :             ostr << "} ";
      91             :         }
      92             :     }
      93             : 
      94             : #ifdef DEBUG
      95             :     void toSvg(const std::string &filename)
      96             :     {
      97             :         std::ofstream ofs(filename);
      98             :         ofs << "<?xml version=\"1.0\" encoding=\"UTF-8\" "
      99             :                "standalone=\"no\"?><svg xmlns=\"http://www.w3.org/2000/svg\" "
     100             :                "version=\"1.1\">\n";
     101             :         ofs << "<defs><marker id=\"arrow\" refX=\"0\" refY=\"0\" "
     102             :                "orient=\"auto\">\n";
     103             :         ofs << "<path d=\"M 0,0 L-1.5,-1 L-1.5,1 L0,0\" "
     104             :                "style=\"fill:#000000;\" />\n";
     105             :         ofs << "</marker></defs>\n";
     106             : 
     107             :         const std::string colors[] = {"white", "#bbb", "#888",
     108             :                                       "#666",  "#333", "black"};
     109             : 
     110             :         int level = 0;
     111             :         for (auto &p : polygons_)
     112             :         {
     113             :             for (const auto &part : p.second)
     114             :             {
     115             :                 ofs << "<path style=\"fill:" << colors[level] << ";\" d=\"";
     116             :                 for (const auto &ring : part)
     117             :                 {
     118             :                     ofs << "M ";
     119             :                     for (const auto &point : ring)
     120             :                     {
     121             :                         ofs << point.x * 10 << "," << point.y * 10 << " ";
     122             :                     }
     123             :                 }
     124             :                 ofs << "\"/>";
     125             :             }
     126             :             level++;
     127             :         }
     128             :         ofs << "</svg>";
     129             :     }
     130             : #endif
     131             : 
     132             :   private:
     133             :     typedef std::vector<LineString> PolygonPart;
     134             :     typedef std::vector<PolygonPart> Polygon;
     135             :     Polygon *currentPolygon_ = nullptr;
     136             :     PolygonPart *currentPart_ = nullptr;
     137             : 
     138             :   public:
     139             :     std::map<double, Polygon> polygons_;
     140             : };
     141             : 
     142           2 : static bool equal_linestrings(const LineString &ls1, const LineString &ls2)
     143             : {
     144           2 :     if (ls1.size() != ls2.size())
     145           0 :         return false;
     146           2 :     auto it1 = ls1.begin();
     147           2 :     auto it2 = ls2.begin();
     148          20 :     for (; it1 != ls1.end(); it1++, it2++)
     149             :     {
     150          18 :         if (!(*it1 == *it2))
     151           0 :             return false;
     152             :     }
     153           2 :     return true;
     154             : }
     155             : }  // namespace marching_squares
     156             : 
     157             : namespace
     158             : {
     159             : using namespace marching_squares;
     160             : 
     161             : // Common fixture with test data
     162             : struct test_ms_polygon : public ::testing::Test
     163             : {
     164             : };
     165             : 
     166             : // Dummy test
     167           4 : TEST_F(test_ms_polygon, dummy)
     168             : {
     169             :     // one pixel
     170           2 :     std::vector<double> data = {2.0};
     171           2 :     TestPolygonWriter w;
     172             :     {
     173           2 :         PolygonRingAppender<TestPolygonWriter> appender(w);
     174           1 :         IntervalLevelRangeIterator levels(0.0, 10.0);
     175             :         SegmentMerger<PolygonRingAppender<TestPolygonWriter>,
     176             :                       IntervalLevelRangeIterator>
     177           2 :             writer(appender, levels, /* polygonize */ true);
     178             :         ContourGenerator<decltype(writer), IntervalLevelRangeIterator> cg(
     179           2 :             1, 1, false, NaN, writer, levels);
     180           1 :         cg.feedLine(&data[0]);
     181             :     }
     182             : 
     183             :     {
     184           2 :         std::ostringstream ostr;
     185           1 :         w.out(ostr, 10.0);
     186             :         // "Polygon #0",
     187           2 :         EXPECT_EQ(ostr.str(), "{ { (0.5,1) (1,1) (1,0.5) (1,0) (0.5,0) (0,0) "
     188             :                               "(0,0.5) (0,1) (0.5,1) } } ");
     189             :     }
     190           1 : }
     191             : 
     192           4 : TEST_F(test_ms_polygon, four_pixels)
     193             : {
     194             :     // four pixels
     195             :     // two rings
     196             :     // 5  10
     197             :     // 10  5
     198             :     // levels = 0, 10
     199             :     //
     200             :     // legend:
     201             :     //  :   contour
     202             :     //  #   border (level 0)
     203             :     //  =   border (level 10)
     204             :     //
     205             :     //   NaN                NaN                NaN
     206             :     //    +------------------+------------------+------------------+
     207             :     //    |                  |                  |                  |
     208             :     //    |    (0,0)         |      (1,0)       |      (2,0)       |
     209             :     //    |       5         5|      7.5       10|        10        |
     210             :     //    |        +#########+########+########o+========++        |
     211             :     //    |        #         |        |         :        ||        |
     212             :     //    |        #         |        |         :        ||        |
     213             :     //    |        #         |        |         :        ||        |
     214             :     //    +--------+---------+--------+---------o........o+--------+
     215             :     //    |NaN   5 #        5|                10|      10#      NaN|
     216             :     //    |        #         |                  |        #         |
     217             :     //    |        #         |                  |        #         |
     218             :     //    |    7.5++---------+ 7.5           7.5+--------+         |
     219             :     //    |        #         |                  |        #         |
     220             :     //    |        #         |                  |        #         |
     221             :     //    |        #         |       7.5        |        #         |
     222             :     //    +-------++.........o--------+---------+--------+---------+
     223             :     //    |NaN  10||       10:        |        5|      5 #      NaN|
     224             :     //    |       ||         :        |         |        #         |
     225             :     //    |       ||         :        |         |        #         |
     226             :     //    |       ++=========o########+#########+########+         |
     227             :     //    |      10        10|      7.5        5|        5         |
     228             :     //    |     (0,2)        |       (1,2)      |       (2,2)      |
     229             :     //    |                  |                  |                  |
     230             :     //    +------------------+------------------+------------------+
     231             :     //  NaN                 NaN                NaN                NaN
     232             : 
     233           2 :     std::vector<double> data = {5.0, 10.0, 10.0, 5.0};
     234           2 :     TestPolygonWriter w;
     235             :     {
     236           2 :         PolygonRingAppender<TestPolygonWriter> appender(w);
     237           1 :         IntervalLevelRangeIterator levels(0.0, 10.0);
     238             :         SegmentMerger<PolygonRingAppender<TestPolygonWriter>,
     239             :                       IntervalLevelRangeIterator>
     240           2 :             writer(appender, levels, /* polygonize */ true);
     241             :         ContourGenerator<decltype(writer), IntervalLevelRangeIterator> cg(
     242           2 :             2, 2, false, NaN, writer, levels);
     243           1 :         cg.feedLine(&data[0]);
     244           1 :         cg.feedLine(&data[2]);
     245             :     }
     246             : 
     247             :     {
     248           2 :         std::ostringstream ostr;
     249           1 :         w.out(ostr, 10.0);
     250             :         // "Polygon #1"
     251           2 :         EXPECT_EQ(ostr.str(),
     252             :                   "{ { (1.5,2) (2,2) (2,1.5) (2,1) (2,0.5) (1.5,0.5) (1.5,0.5) "
     253             :                   "(1.5,0) (1,0) (0.5,0) (0,0) (0,0.5) (0,1) (0,1.5) (0.5,1.5) "
     254             :                   "(0.5,1.5) (0.5,2) (1,2) (1.5,2) } } ");
     255             :     }
     256             :     {
     257           2 :         std::ostringstream ostr;
     258           1 :         w.out(ostr, 20.0);
     259             :         // "Polygon #2"
     260           2 :         EXPECT_EQ(ostr.str(),
     261             :                   "{ { (2,0.5) (2,0.5) (2,0) (1.5,0) (1.5,0) (1.5,0.5) "
     262             :                   "(1.5,0.5) (2,0.5) } } { { (0.5,1.5) (0.5,1.5) (0,1.5) "
     263             :                   "(0,1.5) (0,2) (0.5,2) (0.5,2) (0.5,1.5) } } ");
     264             :     }
     265           1 : }
     266             : 
     267           4 : TEST_F(test_ms_polygon, four_pixels_2)
     268             : {
     269             :     // four pixels
     270             :     // 155    155.01
     271             :     // 154.99 155
     272             :     // levels = 155
     273             : 
     274             :     //   NaN                NaN                NaN
     275             :     //    +------------------+------------------+------------------+
     276             :     //    |                  |                  |                  |
     277             :     //    |    (0,0)         |      (1,0)       |      (2,0)       |
     278             :     //    |      155         |     155.005      |      155.01      |
     279             :     //    |        +---------+--------+---------+---------+        |
     280             :     //    |        |       155        |      155.01       |        |
     281             :     //    |        |         |        |         |         |        |
     282             :     //    |        |         |     155.005      |         |        |
     283             :     //    +--------+---------+--------+---------+---------+--------+
     284             :     //    |NaN   155       155               155.01    155.01   NaN|
     285             :     //    |        |         |                  |         |        |
     286             :     //    |    154.995       |                  |      155.005     |
     287             :     //    |        +-------154.995           155.005------+        |
     288             :     //    |        |         |                  |         |        |
     289             :     //    |        |         |                  |         |        |
     290             :     //    |        |         |                  |         |        |
     291             :     //    +--------+---------+--------+---------+---------+--------+
     292             :     //    |NaN  154.99    154.99   154.995    155       155     NaN|
     293             :     //    |        |         |        |         |         |        |
     294             :     //    |        |         |        |         |         |        |
     295             :     //    |        +---------+--------+---------+---------+        |
     296             :     //    |     154.99    154.99   154.995    155       155        |
     297             :     //    |     (0,2)        |       (1,2)      |       (2,2)      |
     298             :     //    |                  |                  |                  |
     299             :     //    +------------------+------------------+------------------+
     300             :     //  NaN                 NaN                NaN                NaN
     301             : 
     302           2 :     std::vector<double> data = {155.0, 155.01, 154.99, 155.0};
     303           2 :     TestPolygonWriter w;
     304             :     {
     305           2 :         PolygonRingAppender<TestPolygonWriter> appender(w);
     306           1 :         const double levels[] = {155.0};
     307           1 :         FixedLevelRangeIterator levelGenerator(levels, 1);
     308             :         SegmentMerger<PolygonRingAppender<TestPolygonWriter>,
     309             :                       FixedLevelRangeIterator>
     310           2 :             writer(appender, levelGenerator, /* polygonize */ true);
     311             :         ContourGenerator<decltype(writer), FixedLevelRangeIterator> cg(
     312           2 :             2, 2, false, NaN, writer, levelGenerator);
     313           1 :         cg.feedLine(&data[0]);
     314           1 :         cg.feedLine(&data[2]);
     315             :     }
     316             :     {
     317           2 :         std::ostringstream ostr;
     318           1 :         w.out(ostr, 155.0);
     319             :         // "Polygon #0"
     320           2 :         EXPECT_EQ(ostr.str(),
     321             :                   "{ { (1.4999,2) (1.4999,1.5) (0.5,0.5001) (0,0.5001) (0,1) "
     322             :                   "(0,1.5) (0,2) (0.5,2) (1,2) (1.4999,2) } } ");
     323             :     }
     324             :     {
     325           2 :         std::ostringstream ostr;
     326           1 :         w.out(ostr, Inf);
     327             :         // "Polygon #1"
     328           2 :         EXPECT_EQ(ostr.str(),
     329             :                   "{ { (1.5,2) (2,2) (2,1.5) (2,1) (2,0.5) (2,0) (1.5,0) (1,0) "
     330             :                   "(0.5,0) (0,0) (0,0.5) (0,0.5001) (0.5,0.5001) (1.4999,1.5) "
     331             :                   "(1.4999,2) (1.5,2) } } ");
     332             :     }
     333           1 : }
     334             : 
     335           4 : TEST_F(test_ms_polygon, nine_pixels)
     336             : {
     337             :     // nine pixels
     338             :     // two nested rings
     339             :     // levels = 1, 11, 21
     340             :     // pixels
     341             :     // +-----+-----+-----+-----+-----+
     342             :     // |     |     |     |     |     |
     343             :     // | NaN | NaN | NaN | NaN | NaN |
     344             :     // |     |     |     |     |     |
     345             :     // +-----+-----+-----+-----+-----+
     346             :     // |     |     |     |     |     |
     347             :     // | NaN |  0  |  4  |  0  | NaN |
     348             :     // |     |     |     |     |     |
     349             :     // +-----+-----+-----+-----+-----+
     350             :     // |     |     |     |     |     |
     351             :     // | NaN |  4  |  12 |  4  | NaN |
     352             :     // |     |     |     |     |     |
     353             :     // +-----+-----+-----+-----+-----+
     354             :     // |     |     |     |     |     |
     355             :     // | NaN |  0  |  4  |  0  | NaN |
     356             :     // |     |     |     |     |     |
     357             :     // +-----+-----+-----+-----+-----+
     358             :     // |     |     |     |     |     |
     359             :     // | NaN | NaN | NaN | NaN | NaN |
     360             :     // |     |     |     |     |     |
     361             :     // +-----+-----+-----+-----+-----+
     362             :     //
     363             :     //   NaN                NaN                NaN                NaN NaN
     364             :     //    +------------------+------------------+------------------+------------------+
     365             :     //    |                  |                  |                  | | | (0,0)
     366             :     //    |      (1,0)       |      (2,0)       |                  | |        0
     367             :     //    0|        2        4|         2       0|         0        | |
     368             :     //    +---------+---o----+---------+---------+----o---+---------+        |
     369             :     //    |        |         |   :    |         |         |    :   |         | |
     370             :     //    |        |         |   :    |         |         |    :   |         | |
     371             :     //    |        |         |   :    |         |         |    :   |         | |
     372             :     //    +--------+---------+---o----+---------+---------+----o---+---------+--------+
     373             :     //    NaN |NaN    0|        0| _/     2        4|         2     \_0| |0 | |
     374             :     //    o.........o/                 |                 \o.........o        |
     375             :     //    |        |         |                  |                  |         | |
     376             :     //    |       2+---------+ 2                |                 2+---------+2
     377             :     //    | |        |         |                  |                  |         |
     378             :     //    | |        |         |                 _o_                 |         |
     379             :     //    | |        |         |                / | \                |         |
     380             :     //    |
     381             :     //    +--------+---------+---------------o--+--o---------------+---------+--------+
     382             :     //    NaN |NaN    4|        4|                \12 /               4| |4 | |
     383             :     //    |         |                 -o-                 |         |        |
     384             :     //    |        |         |                  |                  |         | |
     385             :     //    |       2+---------+ 2                |                 2+---------+2
     386             :     //    | |        |         |                  |                  |         |
     387             :     //    | |        o.........o_                 |                 _o.........o
     388             :     //    | |        |         | \_     2         |        2      _/ |         |
     389             :     //    |
     390             :     //    +--------+---------+---o----+---------+--------+----o/---+---------+--------+
     391             :     //    NaN |NaN    0|        0|   :    |        4|        |    :   0| |0 | |
     392             :     //    |         |   :    |         |        |    :    |         |        |
     393             :     //    |        |         |   :    |         |        |    :    |         | |
     394             :     //    |        +---------+---o----+---------+--------+----o----+---------+ |
     395             :     //    |       0         0|        2        4|        2        0|         0 |
     396             :     //    |     (0,3)        |       (1,3)      |       (2,3)      | | | | | | |
     397             :     //    +------------------+------------------+------------------+------------------+
     398             :     //  NaN                 NaN                NaN                NaN NaN
     399           2 :     std::vector<double> data = {0.0, 4.0, 0.0, 4.0, 12.0, 4.0, 0.0, 4.0, 0.0};
     400           2 :     TestPolygonWriter w;
     401             :     {
     402           2 :         PolygonRingAppender<TestPolygonWriter> appender(w);
     403           1 :         IntervalLevelRangeIterator levels(1.0, 10.0);
     404             :         SegmentMerger<PolygonRingAppender<TestPolygonWriter>,
     405             :                       IntervalLevelRangeIterator>
     406           2 :             writer(appender, levels, /* polygonize */ true);
     407             :         ContourGenerator<decltype(writer), IntervalLevelRangeIterator> cg(
     408           2 :             3, 3, false, NaN, writer, levels);
     409           1 :         cg.feedLine(&data[0]);
     410           1 :         cg.feedLine(&data[3]);
     411           1 :         cg.feedLine(&data[6]);
     412             :     }
     413             : 
     414             :     {
     415           2 :         std::ostringstream ostr;
     416           1 :         w.out(ostr, 1.0);
     417             :         // "Polygon #0"
     418           2 :         EXPECT_EQ(ostr.str(),
     419             :                   "{ { (0.5,0.75) (0.75,0.5) (0.75,0) (0.5,0) (0,0) (0,0.5) "
     420             :                   "(0,0.75) (0.5,0.75) } } { { (2.5,0.75) (3,0.75) (3,0.5) "
     421             :                   "(3,0) (2.5,0) (2.25,0) (2.25,0.5) (2.5,0.75) } } { { "
     422             :                   "(0.75,3) (0.75,2.5) (0.5,2.25) (0,2.25) (0,2.5) (0,3) "
     423             :                   "(0.5,3) (0.75,3) } } { { (2.5,3) (3,3) (3,2.5) (3,2.25) "
     424             :                   "(2.5,2.25) (2.25,2.5) (2.25,3) (2.5,3) } } ");
     425             :     }
     426             :     {
     427           2 :         std::ostringstream ostr;
     428           1 :         w.out(ostr, 11.0);
     429             :         // "Polygon #1"
     430           2 :         EXPECT_EQ(ostr.str(),
     431             :                   "{ { (2.25,2.5) (2.5,2.25) (3,2.25) (3,2) (3,1.5) (3,1) "
     432             :                   "(3,0.75) (2.5,0.75) (2.25,0.5) (2.25,0) (2,0) (1.5,0) (1,0) "
     433             :                   "(0.75,0) (0.75,0.5) (0.5,0.75) (0,0.75) (0,1) (0,1.5) (0,2) "
     434             :                   "(0,2.25) (0.5,2.25) (0.75,2.5) (0.75,3) (1,3) (1.5,3) (2,3) "
     435             :                   "(2.25,3) (2.25,2.5) } { (1.625,1.5) (1.5,1.625) (1.375,1.5) "
     436             :                   "(1.5,1.375) (1.625,1.5) } } ");
     437             :     }
     438             :     {
     439           2 :         std::ostringstream ostr;
     440           1 :         w.out(ostr, 21.0);
     441             :         // "Polygon #2"
     442           2 :         EXPECT_EQ(ostr.str(), "{ { (1.625,1.5) (1.5,1.625) (1.375,1.5) "
     443             :                               "(1.5,1.375) (1.625,1.5) } } ");
     444             :     }
     445           1 : }
     446             : 
     447           4 : TEST_F(test_ms_polygon, three_nested_rings)
     448             : {
     449             :     // Three nested rings
     450             :     std::vector<double> data = {2, 2, 2, 2, 2, 2, 4, 4, 4, 2, 2, 4, 6,
     451           2 :                                 4, 2, 2, 4, 4, 4, 2, 2, 2, 2, 2, 2};
     452           2 :     TestPolygonWriter w;
     453             :     {
     454           2 :         PolygonRingAppender<TestPolygonWriter> appender(w);
     455           1 :         IntervalLevelRangeIterator levels(1.0, 2.0);
     456             :         SegmentMerger<PolygonRingAppender<TestPolygonWriter>,
     457             :                       IntervalLevelRangeIterator>
     458           2 :             writer(appender, levels, /* polygonize */ true);
     459             :         ContourGenerator<decltype(writer), IntervalLevelRangeIterator> cg(
     460           2 :             5, 5, false, NaN, writer, levels);
     461           6 :         for (int i = 0; i < 5; i++)
     462             :         {
     463           5 :             cg.feedLine(&data[5 * i]);
     464             :         }
     465             :     }
     466             :     {
     467           2 :         std::ostringstream ostr;
     468           1 :         w.out(ostr, 1.0);
     469             :         // "Polygon #0"
     470           2 :         EXPECT_EQ(ostr.str(), "");
     471             :     }
     472             :     {
     473           2 :         std::ostringstream ostr;
     474           1 :         w.out(ostr, 3.0);
     475             :         // "Polygon #1"
     476           2 :         EXPECT_EQ(
     477             :             ostr.str(),
     478             :             "{ { (4.5,5) (5,5) (5,4.5) (5,4) (5,3.5) (5,3) (5,2.5) (5,2) "
     479             :             "(5,1.5) (5,1) (5,0.5) (5,0) (4.5,0) (4,0) (3.5,0) (3,0) (2.5,0) "
     480             :             "(2,0) (1.5,0) (1,0) (0.5,0) (0,0) (0,0.5) (0,1) (0,1.5) (0,2) "
     481             :             "(0,2.5) (0,3) (0,3.5) (0,4) (0,4.5) (0,5) (0.5,5) (1,5) (1.5,5) "
     482             :             "(2,5) (2.5,5) (3,5) (3.5,5) (4,5) (4.5,5) } { (4,3.5) (3.5,4) "
     483             :             "(2.5,4) (1.5,4) (1,3.5) (1,2.5) (1,1.5) (1.5,1) (2.5,1) (3.5,1) "
     484             :             "(4,1.5) (4,2.5) (4,3.5) } } ");
     485             :     }
     486             :     {
     487           2 :         std::ostringstream ostr;
     488           1 :         w.out(ostr, 5.0);
     489             :         // "Polygon #2"
     490           2 :         EXPECT_EQ(ostr.str(),
     491             :                   "{ { (4,3.5) (3.5,4) (2.5,4) (1.5,4) (1,3.5) (1,2.5) (1,1.5) "
     492             :                   "(1.5,1) (2.5,1) (3.5,1) (4,1.5) (4,2.5) (4,3.5) } { (3,2.5) "
     493             :                   "(2.5,3) (2,2.5) (2.5,2) (3,2.5) } } ");
     494             :     }
     495             :     {
     496           2 :         std::ostringstream ostr;
     497           1 :         w.out(ostr, 7.0);
     498             :         // "Polygon #3"
     499           2 :         EXPECT_EQ(ostr.str(),
     500             :                   "{ { (3,2.5) (2.5,3) (2,2.5) (2.5,2) (3,2.5) } } ");
     501             :     }
     502             : 
     503             :     // "Inner ring of polygon #1 = exterioring ring of polygon #2"
     504           1 :     EXPECT_TRUE(
     505             :         equal_linestrings(w.polygons_[3.0][0][1], w.polygons_[5.0][0][0]));
     506             :     // "Inner ring of polygon #2 = exterioring ring of polygon #3"
     507           1 :     EXPECT_TRUE(
     508             :         equal_linestrings(w.polygons_[5.0][0][1], w.polygons_[7.0][0][0]));
     509           1 : }
     510             : }  // namespace

Generated by: LCOV version 1.14