Coverage Report

Created: 2026-09-01 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/coverage/CoverageRing.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2022 Paul Ramsey <pramsey@cleverelephant.ca>
7
 *
8
 * This is free software; you can redistribute and/or modify it under
9
 * the terms of the GNU Lesser General Public Licence as published
10
 * by the Free Software Foundation.
11
 * See the COPYING file for more information.
12
 *
13
 **********************************************************************/
14
15
#include <geos/coverage/CoverageRing.h>
16
17
#include <geos/algorithm/Orientation.h>
18
#include <geos/geom/Coordinate.h>
19
#include <geos/geom/CoordinateSequence.h>
20
#include <geos/geom/Geometry.h>
21
#include <geos/geom/GeometryFactory.h>
22
#include <geos/geom/LineString.h>
23
#include <geos/geom/LinearRing.h>
24
#include <geos/geom/Polygon.h>
25
#include <geos/geom/util/PolygonExtracter.h>
26
#include <geos/util/IllegalStateException.h>
27
28
using geos::geom::Coordinate;
29
using geos::geom::CoordinateSequence;
30
using geos::geom::Geometry;
31
using geos::geom::GeometryFactory;
32
using geos::geom::LineString;
33
using geos::geom::LinearRing;
34
using geos::geom::Polygon;
35
36
37
namespace geos {     // geos
38
namespace coverage { // geos.coverage
39
40
41
/* public static */
42
bool
43
CoverageRing::isKnown(std::vector<CoverageRing*>& rings)
44
0
{
45
0
    for (auto* ring : rings) {
46
0
        if (! ring->isKnown())
47
0
            return false;
48
0
    }
49
0
    return true;
50
0
}
51
52
53
/* public */
54
CoverageRing::CoverageRing(const std::shared_ptr<const CoordinateSequence>& inPts, bool interiorOnRight)
55
0
    : noding::BasicSegmentString(inPts, nullptr)
56
0
    , m_isInteriorOnRight(interiorOnRight)
57
0
{
58
0
    m_isInvalid.resize(size() - 1, false);
59
0
    m_isMatched.resize(size() - 1, false);
60
0
}
61
62
63
/* public */
64
CoverageRing::CoverageRing(const LinearRing* ring, bool isShell)
65
0
    : CoverageRing(
66
0
        ring->getSharedCoordinates(),
67
0
        algorithm::Orientation::isCCW(ring->getCoordinatesRO()) != isShell)
68
0
{}
69
70
/* public */ 
71
geom::Envelope CoverageRing::getEnvelope(std::size_t start, std::size_t end) 
72
0
{
73
0
    geom::Envelope env;
74
0
    for (std::size_t i = start; i < end; i++) {
75
0
        env.expandToInclude(getCoordinate(i));
76
0
    }
77
0
    return env;
78
0
}
79
80
81
/* public */
82
bool
83
CoverageRing::isInteriorOnRight() const
84
0
{
85
0
    return m_isInteriorOnRight;
86
0
}
87
88
89
/* public */
90
void
91
CoverageRing::markInvalid(std::size_t index)
92
0
{
93
0
    m_isInvalid[index] = true;
94
0
}
95
96
97
/* public */
98
void
99
CoverageRing::markMatched(std::size_t index)
100
0
{
101
0
    m_isMatched[index] = true;
102
0
}
103
104
105
/* public */
106
bool
107
CoverageRing::isKnown() const
108
0
{
109
0
    for (size_t i = 0; i < m_isMatched.size(); i++ ) {
110
0
        if (!(m_isMatched[i] && m_isInvalid[i]))
111
0
            return false;
112
0
    }
113
0
    return true;
114
0
}
115
116
/* public */
117
bool
118
CoverageRing::isInvalid(std::size_t i) const
119
0
{
120
0
    return m_isInvalid[i];
121
0
}
122
123
/* public */
124
bool
125
CoverageRing::isInvalid() const
126
0
{
127
0
    for (bool b: m_isInvalid) {
128
0
        if (!b)
129
0
            return false;
130
0
    }
131
0
    return true;
132
0
}
133
134
135
/* public */
136
bool
137
CoverageRing::hasInvalid() const
138
0
{
139
0
    for (bool b: m_isInvalid) {
140
0
        if (b)
141
0
            return true;
142
0
    }
143
0
    return false;
144
0
}
145
146
147
/* public */
148
bool
149
CoverageRing::isKnown(std::size_t i) const
150
0
{
151
0
    return m_isMatched[i] || m_isInvalid[i];
152
0
}
153
154
155
/* public */
156
const Coordinate&
157
CoverageRing::findVertexPrev(std::size_t index, const Coordinate& pt) const
158
0
{
159
0
    std::size_t iPrev = index;
160
0
    const Coordinate* cPrev = &getCoordinate(iPrev);
161
0
    while (pt.equals2D(*cPrev)) {
162
0
        iPrev = prev(iPrev);
163
0
        cPrev = &getCoordinate(iPrev);
164
0
    }
165
0
    return *cPrev;
166
0
}
167
168
169
/* public */
170
const Coordinate&
171
CoverageRing::findVertexNext(std::size_t index, const Coordinate& pt) const
172
0
{
173
    //-- safe, since index is always the start of a segment
174
0
    std::size_t iNext = index + 1;
175
0
    const Coordinate* cNext = &getCoordinate(iNext);
176
0
    while (pt.equals2D(*cNext)) {
177
0
        iNext = next(iNext);
178
0
        cNext = &getCoordinate(iNext);
179
0
    }
180
0
    return *cNext;
181
0
}
182
183
184
/* public */
185
std::size_t
186
CoverageRing::prev(std::size_t index) const
187
0
{
188
0
    if (index == 0)
189
0
        return size() - 2;
190
0
    return index - 1;
191
0
}
192
193
194
/* public */
195
std::size_t
196
CoverageRing::next(std::size_t index) const
197
0
{
198
0
    if (index < size() - 2)
199
0
        return index + 1;
200
0
    return 0;
201
0
}
202
203
204
/* public */
205
void
206
CoverageRing::createInvalidLines(
207
    const GeometryFactory* geomFactory,
208
    std::vector<std::unique_ptr<LineString>>& lines)
209
0
{
210
    //-- empty case
211
0
    if (! hasInvalid()) {
212
0
        return;
213
0
    }
214
    //-- entire ring case
215
0
    if (isInvalid()) {
216
0
        std::unique_ptr<LineString> line = createLine(0, size() - 1, geomFactory);
217
0
        lines.push_back(std::move(line));
218
0
        return;
219
0
    }
220
221
    //-- find first end after index 0, to allow wrap-around
222
0
    std::size_t startIndex = findInvalidStart(0);
223
0
    std::size_t firstEndIndex = findInvalidEnd(startIndex);
224
0
    std::size_t endIndex = firstEndIndex;
225
0
    while (true) {
226
0
        startIndex = findInvalidStart(endIndex);
227
0
        endIndex = findInvalidEnd(startIndex);
228
0
        std::unique_ptr<LineString> line = createLine(startIndex, endIndex, geomFactory);
229
0
        lines.push_back(std::move(line));
230
0
        if (endIndex == firstEndIndex)
231
0
            break;
232
0
    }
233
0
}
234
235
236
/* private */
237
std::size_t
238
CoverageRing::findInvalidStart(std::size_t index)
239
0
{
240
0
    while (! isInvalid(index)) {
241
0
        index = nextMarkIndex(index);
242
0
    }
243
0
    return index;
244
0
}
245
246
247
/* private */
248
std::size_t
249
CoverageRing::findInvalidEnd(std::size_t index)
250
0
{
251
0
    index = nextMarkIndex(index);
252
0
    while (isInvalid(index)) {
253
0
        index = nextMarkIndex(index);
254
0
    }
255
0
    return index;
256
0
}
257
258
259
/* private */
260
std::size_t
261
CoverageRing::nextMarkIndex(std::size_t index)
262
0
{
263
0
    if (index >= m_isInvalid.size() - 1) {
264
0
        return 0;
265
0
    }
266
0
    return index + 1;
267
0
}
268
269
270
/* private */
271
std::unique_ptr<LineString>
272
CoverageRing::createLine(
273
    std::size_t startIndex,
274
    std::size_t endIndex,
275
    const GeometryFactory* geomFactory)
276
0
{
277
0
    std::unique_ptr<CoordinateSequence> linePts = endIndex < startIndex
278
0
        ? extractSectionWrap(startIndex, endIndex)
279
0
        : extractSection(startIndex, endIndex);
280
0
    return geomFactory->createLineString(std::move(linePts));
281
0
}
282
283
284
/* private */
285
std::unique_ptr<CoordinateSequence>
286
CoverageRing::extractSection(std::size_t startIndex, std::size_t endIndex)
287
0
{
288
    // std::size_t sz = endIndex - startIndex + 1;
289
0
    std::unique_ptr<CoordinateSequence> linePts(new CoordinateSequence());
290
0
    for (std::size_t i = startIndex; i <= endIndex; i++) {
291
0
        linePts->add(getCoordinate(i));
292
0
    }
293
294
0
    return linePts;
295
0
}
296
297
298
/* private */
299
std::unique_ptr<CoordinateSequence>
300
CoverageRing::extractSectionWrap(std::size_t startIndex, std::size_t endIndex)
301
0
{
302
0
    std::size_t sz = endIndex + (size() - startIndex);
303
0
    std::unique_ptr<CoordinateSequence> linePts(new CoordinateSequence);
304
0
    std::size_t index = startIndex;
305
0
    for (std::size_t i = 0; i < sz; i++) {
306
0
        linePts->add(getCoordinate(index));
307
0
        index = nextMarkIndex(index);
308
0
    }
309
310
0
    return linePts;
311
0
}
312
313
314
} // namespace geos.coverage
315
} // namespace geos
316
317