Coverage Report

Created: 2025-11-16 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/coverage/CoverageEdge.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
 * Copyright (c) 2022 Martin Davis.
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
#include <geos/coverage/CoverageEdge.h>
17
18
#include <geos/geom/Coordinate.h>
19
#include <geos/geom/GeometryFactory.h>
20
#include <geos/geom/LinearRing.h>
21
#include <geos/geom/LineSegment.h>
22
#include <geos/util/IllegalStateException.h>
23
24
25
using geos::geom::Coordinate;
26
using geos::geom::GeometryFactory;
27
using geos::geom::LinearRing;
28
using geos::geom::LineSegment;
29
using geos::geom::MultiLineString;
30
using geos::geom::LineString;
31
using geos::geom::CoordinateSequence;
32
33
34
namespace geos {     // geos
35
namespace coverage { // geos.coverage
36
37
/* public static */
38
std::unique_ptr<CoverageEdge>
39
CoverageEdge::createEdge(const CoordinateSequence& ring)
40
0
{
41
0
    auto pts = extractEdgePoints(ring, 0, ring.getSize() - 1);
42
0
    return detail::make_unique<CoverageEdge>(std::move(pts), true);
43
0
}
44
45
/* public static */
46
std::unique_ptr<CoverageEdge>
47
CoverageEdge::createEdge(const CoordinateSequence& ring,
48
    std::size_t start, std::size_t end)
49
0
{
50
0
    auto pts = extractEdgePoints(ring, start, end);
51
0
    return detail::make_unique<CoverageEdge>(std::move(pts), false);
52
0
}
53
54
/* public static */
55
std::unique_ptr<MultiLineString>
56
CoverageEdge::createLines(
57
    const std::vector<CoverageEdge*>& edges,
58
    const GeometryFactory* geomFactory)
59
0
{
60
0
    std::vector<std::unique_ptr<LineString>> lines;
61
0
    for (const CoverageEdge* edge : edges) {
62
0
        auto cs = edge->getCoordinates()->clone();
63
0
        auto ls = geomFactory->createLineString(std::move(cs));
64
0
        lines.push_back(std::move(ls));
65
0
    }
66
0
    return geomFactory->createMultiLineString(std::move(lines));
67
0
}
68
69
/* public */
70
std::unique_ptr<LineString>
71
CoverageEdge::toLineString(const GeometryFactory* geomFactory)
72
0
{
73
0
    const CoordinateSequence* cs = getCoordinates();
74
0
    return geomFactory->createLineString(cs->clone());
75
0
}
76
77
/* private static */
78
std::unique_ptr<CoordinateSequence>
79
CoverageEdge::extractEdgePoints(const CoordinateSequence& ring,
80
    std::size_t start, std::size_t end)
81
0
{
82
0
    auto pts = detail::make_unique<CoordinateSequence>();
83
0
    std::size_t size = start < end
84
0
                  ? end - start + 1
85
0
                  : ring.getSize() - start + end;
86
0
    std::size_t iring = start;
87
0
    for (std::size_t i = 0; i < size; i++) {
88
0
        pts->add(ring.getAt(iring));
89
0
        iring += 1;
90
0
        if (iring >= ring.getSize())
91
0
            iring = 1;
92
0
    }
93
0
    return pts;
94
0
}
95
96
97
/* public static */
98
LineSegment
99
CoverageEdge::key(const CoordinateSequence& ring)
100
0
{
101
    // find lowest vertex index
102
0
    std::size_t indexLow = 0;
103
0
    for (std::size_t i = 1; i < ring.size() - 1; i++) {
104
0
        if (ring.getAt(indexLow).compareTo(ring.getAt(i)) < 0)
105
0
            indexLow = i;
106
0
    }
107
0
    const Coordinate& key0 = ring.getAt(indexLow);
108
    // find distinct adjacent vertices
109
0
    const Coordinate& adj0 = findDistinctPoint(ring, indexLow, true, key0);
110
0
    const Coordinate& adj1 = findDistinctPoint(ring, indexLow, false, key0);
111
0
    const Coordinate& key1 = adj0.compareTo(adj1) < 0 ? adj0 : adj1;
112
0
    return LineSegment(key0, key1);
113
0
}
114
115
116
/* public static */
117
LineSegment
118
CoverageEdge::key(const CoordinateSequence& ring,
119
    std::size_t start, std::size_t end)
120
0
{
121
    //-- endpoints are distinct in a line edge
122
0
    const Coordinate& end0 = ring.getAt(start);
123
0
    const Coordinate& end1 = ring.getAt(end);
124
0
    bool isForward = 0 > end0.compareTo(end1);
125
0
    const Coordinate* key0;
126
0
    const Coordinate* key1;
127
0
    if (isForward) {
128
0
        key0 = &end0;
129
0
        key1 = &findDistinctPoint(ring, start, true, *key0);
130
0
    }
131
0
    else {
132
0
        key0 = &end1;
133
0
        key1 = &findDistinctPoint(ring, end, false, *key0);
134
0
    }
135
0
    return LineSegment(*key0, *key1);
136
0
}
137
138
/* private static */
139
const Coordinate&
140
CoverageEdge::findDistinctPoint(
141
    const CoordinateSequence& pts,
142
    std::size_t index,
143
    bool isForward,
144
    const Coordinate& pt)
145
0
{
146
0
    std::size_t i = index;
147
0
    std::size_t endIndex = pts.size()-1;
148
0
    do {
149
0
        if (! pts.getAt(i).equals2D(pt)) {
150
0
            return pts.getAt(i);
151
0
        }
152
        // increment index with wrapping
153
0
        if (isForward) {
154
0
            i = (i == endIndex) ? 0 : (i+1);
155
0
        }
156
0
        else {
157
0
            i = (i == 0) ? endIndex : (i-1);
158
0
        }
159
160
0
    } while (i != index);
161
0
    throw util::IllegalStateException("Edge does not contain distinct points");
162
0
}
163
164
165
166
// /* public */
167
// std::string toString()
168
// {
169
//     return WKTWriter::toLineString(pts);
170
// }
171
172
173
174
} // namespace geos.coverage
175
} // namespace geos