Coverage Report

Created: 2026-09-01 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/geomgraph/Node.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
7
 * Copyright (C) 2005-2006 Refractions Research Inc.
8
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
9
 *
10
 * This is free software; you can redistribute and/or modify it under
11
 * the terms of the GNU Lesser General Public Licence as published
12
 * by the Free Software Foundation.
13
 * See the COPYING file for more information.
14
 *
15
 **********************************************************************
16
 *
17
 * Last port: geomgraph/Node.java r411 (JTS-1.12+)
18
 *
19
 **********************************************************************/
20
21
#include <geos/geom/Coordinate.h>
22
#include <geos/geomgraph/Node.h>
23
#include <geos/geomgraph/Edge.h>
24
#include <geos/geomgraph/EdgeEndStar.h>
25
#include <geos/geomgraph/Label.h>
26
#include <geos/geomgraph/DirectedEdge.h>
27
#include <geos/geom/Location.h>
28
#include <geos/util/IllegalArgumentException.h>
29
#include <geos/util.h>
30
31
#include <cmath>
32
#include <memory>
33
#include <string>
34
#include <sstream>
35
#include <vector>
36
#include <algorithm>
37
38
#ifndef GEOS_DEBUG
39
#define GEOS_DEBUG 0
40
#endif
41
#ifndef COMPUTE_Z
42
#define COMPUTE_Z 1
43
#endif
44
45
using namespace geos::geom;
46
47
namespace geos {
48
namespace geomgraph { // geos.geomgraph
49
50
/*public*/
51
Node::Node(const Coordinate& newCoord, EdgeEndStar* newEdges)
52
    :
53
0
    GraphComponent(Label(0, Location::NONE)),
54
0
    coord(newCoord),
55
0
    edges(newEdges)
56
57
0
{
58
#if GEOS_DEBUG
59
    std::cerr << "[" << this << "] Node::Node(" << newCoord.toString() << ")" << std::endl;
60
#endif
61
62
0
#if COMPUTE_Z
63
0
    ztot = 0;
64
0
    addZ(newCoord.z);
65
0
    if(edges) {
66
0
        EdgeEndStar::iterator endIt = edges->end();
67
0
        for(EdgeEndStar::iterator it = edges->begin(); it != endIt; ++it) {
68
0
            EdgeEnd* ee = *it;
69
0
            addZ(ee->getCoordinate().z);
70
0
        }
71
0
    }
72
0
#endif // COMPUTE_Z
73
74
0
    testInvariant();
75
0
}
76
77
/*public*/
78
Node::~Node()
79
0
{
80
0
    testInvariant();
81
#if GEOS_DEBUG
82
    std::cerr << "[" << this << "] Node::~Node()" << std::endl;
83
#endif
84
0
    delete edges;
85
0
}
86
87
/*public*/
88
const Coordinate&
89
Node::getCoordinate() const
90
0
{
91
0
    testInvariant();
92
0
    return coord;
93
0
}
94
95
/*public*/
96
EdgeEndStar*
97
Node::getEdges()
98
0
{
99
0
    testInvariant();
100
101
0
    return edges;
102
0
}
103
104
/*public*/
105
bool
106
Node::isIsolated() const
107
0
{
108
0
    testInvariant();
109
110
0
    return (label.getGeometryCount() == 1);
111
0
}
112
113
/*public*/
114
bool
115
Node::isIncidentEdgeInResult() const
116
0
{
117
0
    testInvariant();
118
119
0
    if(!edges) {
120
0
        return false;
121
0
    }
122
123
0
    EdgeEndStar::iterator it = edges->begin();
124
0
    EdgeEndStar::iterator endIt = edges->end();
125
0
    for(; it != endIt; ++it) {
126
0
        assert(*it);
127
0
        DirectedEdge* de = detail::down_cast<DirectedEdge*>(*it);
128
0
        if(de->getEdge()->isInResult()) {
129
0
            return true;
130
0
        }
131
0
    }
132
0
    return false;
133
0
}
134
135
void
136
Node::add(EdgeEnd* e)
137
0
{
138
0
    assert(e);
139
#if GEOS_DEBUG
140
    std::cerr << "[" << this << "] Node::add(" << e->print() << ")" << std::endl;
141
#endif
142
    // Assert: start pt of e is equal to node point
143
0
    if(! e->getCoordinate().equals2D(coord)) {
144
0
        std::stringstream ss;
145
0
        ss << "EdgeEnd with coordinate " << e->getCoordinate()
146
0
           << " invalid for node " << coord;
147
0
        throw util::IllegalArgumentException(ss.str());
148
0
    }
149
150
    // It seems it's legal for edges to be NULL
151
    // we'd not be honouring the promise of adding
152
    // an EdgeEnd in this case, though ...
153
0
    assert(edges);
154
    //if (edges==NULL) return;
155
156
0
    edges->insert(e);
157
0
    e->setNode(this);
158
0
#if COMPUTE_Z
159
0
    addZ(e->getCoordinate().z);
160
0
#endif
161
0
    testInvariant();
162
0
}
163
164
/*public*/
165
void
166
Node::mergeLabel(const Node& n)
167
0
{
168
0
    assert(!n.label.isNull());
169
0
    mergeLabel(n.label);
170
0
    testInvariant();
171
0
}
172
173
/*public*/
174
void
175
Node::mergeLabel(const Label& label2)
176
0
{
177
0
    for(uint8_t i = 0; i < 2; i++) {
178
0
        Location loc = computeMergedLocation(label2, i);
179
0
        Location thisLoc = label.getLocation(i);
180
0
        if(thisLoc == Location::NONE) {
181
0
            label.setLocation(i, loc);
182
0
        }
183
0
    }
184
0
    testInvariant();
185
0
}
186
187
/*public*/
188
void
189
Node::setLabel(uint8_t argIndex, Location onLocation)
190
0
{
191
0
    if(label.isNull()) {
192
0
        label = Label(argIndex, onLocation);
193
0
    }
194
0
    else {
195
0
        label.setLocation(argIndex, onLocation);
196
0
    }
197
198
0
    testInvariant();
199
0
}
200
201
/*public*/
202
void
203
Node::setLabelBoundary(uint8_t argIndex)
204
0
{
205
0
    Location loc = label.getLocation(argIndex);
206
    // flip the loc
207
0
    Location newLoc;
208
0
    switch(loc) {
209
0
    case Location::BOUNDARY:
210
0
        newLoc = Location::INTERIOR;
211
0
        break;
212
0
    case Location::INTERIOR:
213
0
        newLoc = Location::BOUNDARY;
214
0
        break;
215
0
    default:
216
0
        newLoc = Location::BOUNDARY;
217
0
        break;
218
0
    }
219
0
    label.setLocation(argIndex, newLoc);
220
221
0
    testInvariant();
222
0
}
223
224
/*public*/
225
Location
226
Node::computeMergedLocation(const Label& label2, uint8_t eltIndex)
227
0
{
228
0
    Location loc = label.getLocation(eltIndex);
229
0
    if(!label2.isNull(eltIndex)) {
230
0
        Location nLoc = label2.getLocation(eltIndex);
231
0
        if(loc != Location::BOUNDARY) {
232
0
            loc = nLoc;
233
0
        }
234
0
    }
235
236
0
    testInvariant();
237
238
0
    return loc;
239
0
}
240
241
/*public*/
242
std::string
243
Node::print() const
244
0
{
245
0
    testInvariant();
246
247
0
    std::ostringstream ss;
248
0
    ss << *this;
249
0
    return ss.str();
250
0
}
251
252
/*public*/
253
void
254
Node::addZ(double z)
255
0
{
256
#if GEOS_DEBUG
257
    std::cerr << "[" << this << "] Node::addZ(" << z << ")";
258
#endif
259
0
    if(std::isnan(z)) {
260
#if GEOS_DEBUG
261
        std::cerr << " skipped" << std::endl;
262
#endif
263
0
        return;
264
0
    }
265
0
    if(find(zvals.begin(), zvals.end(), z) != zvals.end()) {
266
#if GEOS_DEBUG
267
        std::cerr << " already stored" << std::endl;
268
#endif
269
0
        return;
270
0
    }
271
0
    zvals.push_back(z);
272
0
    ztot += z;
273
0
    coord.z = ztot / static_cast<double>(zvals.size());
274
#if GEOS_DEBUG
275
    std::cerr << " added " << z << ": [" << ztot << "/" << zvals.size() << "=" << coord.z << "]" << std::endl;
276
#endif
277
0
}
278
279
/*public*/
280
const std::vector<double>&
281
Node::getZ() const
282
0
{
283
0
    return zvals;
284
0
}
285
286
std::ostream&
287
operator<< (std::ostream& os, const Node& node)
288
0
{
289
0
    os << "Node[" << &node << "]" << std::endl
290
0
       << "  POINT(" << node.coord << ")" << std::endl
291
0
       << "  lbl: " << node.label;
292
0
    return os;
293
0
}
294
295
} // namespace geos.geomgraph
296
} // namespace geos
297