Coverage Report

Created: 2025-08-25 06:57

/src/geos/src/noding/GeometryNoder.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2012  Sandro Santilli <strk@kbt.io>
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
 * NOTE: this is not in JTS. JTS has a snapround/GeometryNoder though
16
 *
17
 **********************************************************************/
18
19
#include <geos/noding/GeometryNoder.h>
20
#include <geos/noding/SegmentString.h>
21
#include <geos/noding/NodedSegmentString.h>
22
#include <geos/noding/OrientedCoordinateArray.h>
23
#include <geos/noding/Noder.h>
24
#include <geos/geom/Geometry.h>
25
#include <geos/geom/PrecisionModel.h>
26
#include <geos/geom/CoordinateSequence.h>
27
#include <geos/geom/GeometryFactory.h>
28
#include <geos/geom/LineString.h>
29
30
#include <geos/noding/IteratedNoder.h>
31
32
#include <geos/algorithm/LineIntersector.h>
33
#include <geos/noding/IntersectionAdder.h>
34
#include <geos/noding/MCIndexNoder.h>
35
36
#include <geos/noding/snapround/MCIndexSnapRounder.h>
37
38
#include <memory> // for unique_ptr
39
#include <iostream>
40
41
namespace geos {
42
namespace noding { // geos.noding
43
44
namespace {
45
46
/**
47
 * Add every linear element in a geometry into SegmentString vector
48
 */
49
class SegmentStringExtractor: public geom::GeometryComponentFilter {
50
public:
51
    SegmentStringExtractor(SegmentString::NonConstVect& to,
52
                           bool constructZ,
53
                           bool constructM)
54
0
        : _to(to)
55
0
        , _constructZ(constructZ)
56
0
        , _constructM(constructM)
57
0
    {}
58
59
    void
60
    filter_ro(const geom::Geometry* g) override
61
0
    {
62
0
        const geom::LineString* ls = dynamic_cast<const geom::LineString*>(g);
63
0
        if(ls) {
64
0
            auto coord = ls->getCoordinates();
65
            // coord ownership transferred to SegmentString
66
0
            SegmentString* ss = new NodedSegmentString(coord.release(), _constructZ, _constructM, nullptr);
67
0
            _to.push_back(ss);
68
0
        }
69
0
    }
70
private:
71
    SegmentString::NonConstVect& _to;
72
    bool _constructZ;
73
    bool _constructM;
74
75
    SegmentStringExtractor(SegmentStringExtractor const&); /*= delete*/
76
    SegmentStringExtractor& operator=(SegmentStringExtractor const&); /*= delete*/
77
};
78
79
}
80
81
82
/* public static */
83
std::unique_ptr<geom::Geometry>
84
GeometryNoder::node(const geom::Geometry& geom)
85
0
{
86
0
    GeometryNoder noder(geom);
87
0
    return noder.getNoded();
88
0
}
89
90
/* public */
91
GeometryNoder::GeometryNoder(const geom::Geometry& g)
92
    :
93
0
    argGeom(g)
94
0
{
95
0
    util::ensureNoCurvedComponents(argGeom);
96
0
}
97
98
/* private */
99
std::unique_ptr<geom::Geometry>
100
GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges)
101
0
{
102
0
    const geom::GeometryFactory* geomFact = argGeom.getFactory();
103
104
0
    std::set< OrientedCoordinateArray > ocas;
105
106
    // Create a geometry out of the noded substrings.
107
0
    std::vector<std::unique_ptr<geom::Geometry>> lines;
108
0
    lines.reserve(nodedEdges.size());
109
0
    for(auto& ss :  nodedEdges) {
110
0
        const geom::CoordinateSequence* coords = ss->getCoordinates();
111
112
        // Check if an equivalent edge is known
113
0
        OrientedCoordinateArray oca1(*coords);
114
0
        if(ocas.insert(oca1).second) {
115
0
            lines.push_back(geomFact->createLineString(coords->clone()));
116
0
        }
117
0
    }
118
119
0
    return geomFact->createMultiLineString(std::move(lines));
120
0
}
121
122
/* public */
123
std::unique_ptr<geom::Geometry>
124
GeometryNoder::getNoded()
125
0
{
126
0
    SegmentString::NonConstVect p_lineList;
127
0
    if (argGeom.isEmpty())
128
0
        return argGeom.clone();
129
130
0
    extractSegmentStrings(argGeom, p_lineList);
131
132
0
    Noder& p_noder = getNoder();
133
0
    SegmentString::NonConstVect* nodedEdges = nullptr;
134
135
0
    try {
136
0
        p_noder.computeNodes(&p_lineList);
137
0
        nodedEdges = p_noder.getNodedSubstrings();
138
0
    }
139
0
    catch(const std::exception&) {
140
0
        for(std::size_t i = 0, n = p_lineList.size(); i < n; ++i) {
141
0
            delete p_lineList[i];
142
0
        }
143
0
        throw;
144
0
    }
145
146
0
    std::unique_ptr<geom::Geometry> noded = toGeometry(*nodedEdges);
147
148
0
    for(auto* elem : (*nodedEdges)) {
149
0
        delete elem;
150
0
    }
151
0
    delete nodedEdges;
152
153
0
    for(auto* elem : p_lineList) {
154
0
        delete elem;
155
0
    }
156
157
0
    return noded;
158
0
}
159
160
/* private static */
161
void
162
GeometryNoder::extractSegmentStrings(const geom::Geometry& g,
163
                                     SegmentString::NonConstVect& to)
164
0
{
165
0
    SegmentStringExtractor ex(to, g.hasZ(), g.hasM());
166
0
    g.apply_ro(&ex);
167
0
}
168
169
/* private */
170
Noder&
171
GeometryNoder::getNoder()
172
0
{
173
0
    if(! noder.get()) {
174
0
        const geom::PrecisionModel* pm = argGeom.getFactory()->getPrecisionModel();
175
0
        IteratedNoder* in = new IteratedNoder(pm);
176
0
        noder.reset(in);
177
0
    }
178
0
    return *noder;
179
0
}
180
181
182
} // namespace geos.noding
183
} // namespace geos