Coverage Report

Created: 2026-02-14 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/operation/overlayng/OverlayLabeller.h
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2020 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
#pragma once
16
17
#include <geos/export.h>
18
#include <geos/geom/Location.h>
19
#include <geos/operation/overlayng/OverlayGraph.h>
20
21
#include <vector>
22
#include <deque>
23
24
// Forward declarations
25
namespace geos {
26
namespace geom {
27
class Coordinate;
28
}
29
namespace operation {
30
namespace overlayng {
31
class OverlayLabel;
32
class OverlayGraph;
33
class OverlayEdge;
34
class InputGeometry;
35
}
36
}
37
}
38
39
namespace geos {      // geos.
40
namespace operation { // geos.operation
41
namespace overlayng { // geos.operation.overlayng
42
43
44
class GEOS_DLL OverlayLabeller {
45
46
private:
47
48
    // Members
49
    OverlayGraph* graph;
50
    InputGeometry* inputGeometry;
51
    std::vector<OverlayEdge*>& edges;
52
53
    /**
54
    * Finds a boundary edge for this geom, if one exists.
55
    */
56
    static OverlayEdge* findPropagationStartEdge(OverlayEdge* nodeEdge, uint8_t geomIndex);
57
58
    /**
59
    * At this point collapsed edges with unknown location
60
    * must be disconnected from the boundary edges of the parent
61
    * (because otherwise the location would have
62
    * been propagated from them).
63
    * This can occur with a collapsed hole or shell.
64
    * The edges can be labeled based on their parent ring role (shell or hole).
65
    * (This cannot be done earlier, because the location
66
    * based on the boundary edges must take precedence.
67
    * There are situations where a collapsed edge has a location
68
    * which is different to its ring role -
69
    * e.g. a narrow gore in a polygon, which is in
70
    * the interior of the reduced polygon, but whose
71
    * ring role would imply the location EXTERIOR.)
72
    *
73
    * Note that collapsed edges can NOT have location determined via a PIP location check,
74
    * because that is done against the unreduced input geometry,
75
    * which may give an invalid result due to topology collapse.
76
    *
77
    * The labeling is propagated to other connected linear edges,
78
    * since there may be NOT_PART edges which are connected,
79
    * and they can be labeled in the same way.
80
    * (These would get labeled anyway during subsequent disconnected labeling pass,
81
    * but may be more efficient and accurate to do it here.)
82
    */
83
    void labelCollapsedEdges();
84
    static void labelCollapsedEdge(OverlayEdge* edge, uint8_t geomIndex);
85
86
    /**
87
    * There can be edges which have unknown location
88
    * but are connected to a Line edge with known location.
89
    * In this case line location is propagated to the connected edges.
90
    */
91
    void labelConnectedLinearEdges();
92
    void propagateLinearLocations(uint8_t geomIndex);
93
    static void propagateLinearLocationAtNode(OverlayEdge* eNode, uint8_t geomIndex, bool isInputLine, std::deque<OverlayEdge*>& edgeStack);
94
95
    /**
96
    * Finds all OverlayEdges which are linear
97
    * (i.e. line or collapsed) and have a known location
98
    * for the given input geometry.
99
    */
100
    static std::vector<OverlayEdge*> findLinearEdgesWithLocation(const std::vector<OverlayEdge *> &edges, uint8_t geomIndex);
101
102
    /**
103
    * At this point there may still be edges which have unknown location
104
    * relative to an input geometry.
105
    * This must be because they are NOT_PART edges for that geometry,
106
    * and are disconnected from any edges of that geometry.
107
    * An example of this is rings of one geometry wholly contained
108
    * in another geometry.
109
    * The location must be fully determined to compute a
110
    * correct result for all overlay operations.
111
    *
112
    * If the input geometry is an Area the edge location can
113
    * be determined via a PIP test.
114
    * If the input is not an Area the location is EXTERIOR.
115
    */
116
    void labelDisconnectedEdges();
117
118
    /**
119
    * Determines the location of an edge relative to a target input geometry.
120
    * The edge has no location information
121
    * because it is disconnected from other
122
    * edges that would provide that information.
123
    * The location is determined by checking
124
    * if the edge lies inside the target geometry area (if any).
125
    */
126
    void labelDisconnectedEdge(OverlayEdge* edge, uint8_t geomIndex);
127
128
    /**
129
    * Determines the {@link Location} for an edge within an Area geometry
130
    * via point-in-polygon location.
131
    *
132
    * NOTE this is only safe to use for disconnected edges,
133
    * since the test is carried out against the original input geometry,
134
    * and precision reduction may cause incorrect results for edges
135
    * which are close enough to a boundary to become connected.
136
    */
137
    geom::Location locateEdge(uint8_t geomIndex, OverlayEdge* edge);
138
139
    /**
140
    * Determines the {@link Location} for an edge within an Area geometry
141
    * via point-in-polygon location,
142
    * by checking that both endpoints are interior to the target geometry.
143
    * Checking both endpoints ensures correct results in the presence of topology collapse.
144
    * <p>
145
    * NOTE this is only safe to use for disconnected edges,
146
    * since the test is carried out against the original input geometry,
147
    * and precision reduction may cause incorrect results for edges
148
    * which are close enough to a boundary to become connected.
149
    */
150
    geom::Location locateEdgeBothEnds(uint8_t geomIndex, OverlayEdge* edge);
151
152
    /**
153
    * Labels edges around nodes based on the arrangement
154
    * of incident area boundary edges.
155
    * Also propagates the labelling to connected linear edges.
156
    */
157
    void labelAreaNodeEdges(std::vector<OverlayEdge*>& nodes);
158
159
160
161
public:
162
163
    OverlayLabeller(OverlayGraph* p_graph, InputGeometry* p_inputGeometry)
164
307k
        : graph(p_graph)
165
307k
        , inputGeometry(p_inputGeometry)
166
307k
        , edges(p_graph->getEdges())
167
307k
    {}
168
169
    /**
170
    * Computes the topological labelling for the edges in the graph->
171
    */
172
    void computeLabelling();
173
174
    /**
175
    * Scans around a node CCW, propagating the side labels
176
    * for a given area geometry to all edges (and their sym)
177
    * with unknown locations for that geometry.
178
    */
179
    void propagateAreaLocations(OverlayEdge* nodeEdge, uint8_t geomIndex);
180
181
    void markResultAreaEdges(int overlayOpCode);
182
183
    /**
184
    * Marks an edge which forms part of the boundary of the result area.
185
    * This is determined by the overlay operation being executed,
186
    * and the location of the edge.
187
    * The relevant location is either the right side of a boundary edge,
188
    * or the line location of a non-boundary edge.
189
    */
190
    static void markInResultArea(OverlayEdge* e, int overlayOpCode);
191
192
    /**
193
    * Unmarks result area edges where the sym edge
194
    * is also marked as in the result.
195
    * This has the effect of merging edge-adjacent result areas,
196
    * as required by polygon validity rules.
197
    */
198
    void unmarkDuplicateEdgesFromResultArea();
199
200
201
};
202
203
204
} // namespace geos.operation.overlayng
205
} // namespace geos.operation
206
} // namespace geos
207