Coverage Report

Created: 2026-04-01 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/coverage/CleanCoverage.h
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (c) 2025 Martin Davis
7
 * Copyright (C) 2025 Paul Ramsey <pramsey@cleverelephant.ca>
8
 *
9
 * This is free software; you can redistribute and/or modify it under
10
 * the terms of the GNU Lesser General Public Licence as published
11
 * by the Free Software Foundation.
12
 * See the COPYING file for more information.
13
 *
14
 **********************************************************************/
15
16
#pragma once
17
18
#include <geos/geom/Envelope.h>
19
#include <geos/constants.h>
20
#include <geos/index/quadtree/Quadtree.h>
21
22
#include <vector>
23
#include <memory>
24
25
// Forward declarations
26
namespace geos {
27
namespace geom {
28
    class Geometry;
29
    class GeometryFactory;
30
    class LineString;
31
    class LinearRing;
32
    class Polygon;
33
}
34
namespace operation {
35
namespace relateng {
36
    class RelateNG;
37
}
38
}
39
namespace index {
40
namespace quadtree {
41
}
42
}
43
}
44
45
46
namespace geos {     // geos.
47
namespace coverage { // geos.coverage
48
49
class CleanCoverage {
50
51
    using Envelope = geos::geom::Envelope;
52
    using Geometry = geos::geom::Geometry;
53
    using GeometryFactory = geos::geom::GeometryFactory;
54
    using LineString = geos::geom::LineString;
55
    using LinearRing = geos::geom::LinearRing;
56
    using Polygon = geos::geom::Polygon;
57
    using RelateNG = geos::operation::relateng::RelateNG;
58
    using Quadtree = geos::index::quadtree::Quadtree;
59
60
61
public:
62
63
    // Classes
64
65
    class CleanArea {
66
67
    private:
68
69
        // Members
70
        std::vector<const Polygon*> polys;
71
        Envelope env;
72
73
    public:
74
75
        // Methods
76
        void add(const Polygon* poly);
77
        const Envelope* getEnvelope();
78
        double getBorderLength(const Polygon* adjPoly);
79
        double getArea();
80
        bool isAdjacent(RelateNG& rel);
81
        std::unique_ptr<Geometry> getUnion();
82
83
    }; // CleanArea
84
85
86
    class MergeStrategy {
87
88
    public:
89
90
0
        virtual ~MergeStrategy() = default;
91
92
        virtual std::size_t getTarget() const = 0;
93
94
        virtual void checkMergeTarget(
95
            std::size_t areaIndex,
96
            CleanArea* cleanArea,
97
            const Polygon* poly) = 0;
98
99
    }; // MergeStrategy
100
101
102
    class BorderMergeStrategy : public MergeStrategy {
103
104
    private:
105
106
        std::size_t m_targetIndex = INDEX_UNKNOWN;
107
        double m_targetBorderLen;
108
109
    public:
110
111
0
        BorderMergeStrategy() {};
112
113
0
        std::size_t getTarget()  const override {
114
0
            return m_targetIndex;
115
0
        };
116
117
0
        void checkMergeTarget(std::size_t areaIndex, CleanArea* area, const Polygon* poly) override {
118
0
            double borderLen = area == nullptr ? 0.0 : area->getBorderLength(poly);
119
0
            if (m_targetIndex == INDEX_UNKNOWN || borderLen > m_targetBorderLen) {
120
0
                m_targetIndex = areaIndex;
121
0
                m_targetBorderLen = borderLen;
122
0
            }
123
0
        };
124
125
    }; // BorderStrategy
126
127
128
    class AreaMergeStrategy : public MergeStrategy {
129
130
    private:
131
132
        std::size_t m_targetIndex = INDEX_UNKNOWN;
133
        double m_targetArea;
134
        bool m_isMax;
135
136
    public:
137
138
0
        AreaMergeStrategy(bool isMax) : m_isMax(isMax) {};
139
140
0
        std::size_t getTarget() const override {
141
0
            return m_targetIndex;
142
0
        }
143
144
0
        void checkMergeTarget(std::size_t areaIndex, CleanArea* area, const Polygon* poly) override {
145
0
            (void)poly;
146
0
            double areaVal = area == nullptr ? 0.0 : area->getArea();
147
0
            bool isBetter = m_isMax
148
0
                ? areaVal > m_targetArea
149
0
                : areaVal < m_targetArea;
150
0
            if (m_targetIndex == INDEX_UNKNOWN || isBetter) {
151
0
                m_targetIndex = areaIndex;
152
0
                m_targetArea = areaVal;
153
0
            }
154
0
        }
155
156
    }; // AreaMergeStrategy
157
158
159
    class IndexMergeStrategy : public MergeStrategy {
160
161
    private:
162
163
        std::size_t m_targetIndex = INDEX_UNKNOWN;
164
        bool m_isMax;
165
166
    public:
167
168
0
        IndexMergeStrategy(bool isMax) : m_isMax(isMax) {};
169
170
0
        std::size_t getTarget()  const override {
171
0
            return m_targetIndex;
172
0
        }
173
174
0
        void checkMergeTarget(std::size_t areaIndex, CleanArea* area, const Polygon* poly) override {
175
0
            (void)area;
176
0
            (void)poly;
177
0
            bool isBetter = m_isMax
178
0
                ? areaIndex > m_targetIndex
179
0
                : areaIndex < m_targetIndex;
180
0
            if (isBetter) {
181
0
                m_targetIndex = areaIndex;
182
0
            }
183
0
        }
184
    }; // MergeStrategy
185
186
187
private:
188
189
    // Members
190
191
    /**
192
     * The areas in the clean coverage.
193
     * Entries may be null, if no resultant corresponded to the input area.
194
     */
195
    std::vector<std::unique_ptr<CleanArea>> cov;
196
    //-- used for finding areas to merge gaps
197
    std::unique_ptr<Quadtree> covIndex = nullptr;
198
199
    void mergeGap(const Polygon* gap);
200
201
    CleanArea* findMaxBorderLength(const Polygon* poly, std::vector<CleanArea*>& areas);
202
203
    std::vector<CleanArea*> findAdjacentAreas(const Geometry* poly);
204
205
    void createIndex();
206
207
208
public:
209
210
    // Methods
211
212
    CleanCoverage(std::size_t size);
213
214
    void add(std::size_t i, const Polygon* poly);
215
216
    void mergeOverlap(const Polygon* overlap,
217
        MergeStrategy& mergeStrategy,
218
        std::vector<std::size_t>& parentIndexes);
219
220
    static std::size_t findMergeTarget(const Polygon* poly,
221
        MergeStrategy& strategy,
222
        std::vector<std::size_t>& parentIndexes,
223
        std::vector<std::unique_ptr<CleanArea>>& cov);
224
225
    void mergeGaps(std::vector<const Polygon*>& gaps);
226
227
    std::vector<std::unique_ptr<Geometry>> toCoverage(const GeometryFactory* geomFactory);
228
229
    /**
230
     * Disable copy construction and assignment. Apparently needed to make this
231
     * class compile under MSVC. (See https://stackoverflow.com/q/29565299)
232
     */
233
    CleanCoverage(const CleanCoverage&) = delete;
234
    CleanCoverage& operator=(const CleanCoverage&) = delete;
235
236
237
};
238
239
} // namespace geos.coverage
240
} // namespace geos
241
242
243
244
245