Coverage Report

Created: 2026-10-28 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/noding/snapround/HotPixel.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2006 Refractions Research Inc.
7
 *
8
 * This is free software; you can redistribute and/or modify it under
9
 * the terms of the GNU Lesser General Licence as published
10
 * by the Free Software Foundation.
11
 * See the COPYING file for more information.
12
 *
13
 **********************************************************************
14
 *
15
 * Last port: noding/snapround/HotPixel.java r320 (JTS-1.12)
16
 *
17
 **********************************************************************/
18
19
#include <geos/algorithm/CGAlgorithmsDD.h>
20
#include <geos/algorithm/LineIntersector.h>
21
#include <geos/noding/NodedSegmentString.h>
22
#include <geos/geom/Coordinate.h>
23
#include <geos/noding/snapround/HotPixel.h>
24
#include <geos/io/WKTWriter.h>
25
26
#include <algorithm> // for std::min and std::max
27
#include <cassert>
28
#include <memory>
29
30
using namespace geos::algorithm;
31
using namespace geos::geom;
32
33
namespace geos {
34
namespace noding { // geos.noding
35
namespace snapround { // geos.noding.snapround
36
37
/*public*/
38
const geom::CoordinateXYZM&
39
HotPixel::getCoordinate() const
40
28.2M
{
41
28.2M
    return originalPt;
42
28.2M
}
43
44
/* public */
45
bool
46
HotPixel::intersects(const CoordinateXY& p) const
47
3.51M
{
48
3.51M
    double x = scale(p.x);
49
3.51M
    double y = scale(p.y);
50
3.51M
    if (x >= hpx + TOLERANCE) return false;
51
    // check Left side
52
2.05M
    if (x < hpx - TOLERANCE) return false;
53
    // check Top side
54
564k
    if (y >= hpy + TOLERANCE) return false;
55
    // check Bottom side
56
501k
    if (y < hpy - TOLERANCE) return false;
57
    // finally
58
462k
    return true;
59
501k
}
60
61
/*public*/
62
bool
63
HotPixel::intersects(const CoordinateXY& p0,
64
                     const CoordinateXY& p1) const
65
39.4M
{
66
39.4M
    if(scaleFactor == 1.0) {
67
31.0M
        return intersectsScaled(p0.x, p0.y, p1.x, p1.y);
68
31.0M
    }
69
70
8.36M
    double sp0x = scale(p0.x);
71
8.36M
    double sp0y = scale(p0.y);
72
8.36M
    double sp1x = scale(p1.x);
73
8.36M
    double sp1y = scale(p1.y);
74
8.36M
    return intersectsScaled(sp0x, sp0y, sp1x, sp1y);
75
39.4M
}
76
77
/*private*/
78
bool
79
HotPixel::intersectsScaled(double p0x, double p0y, double p1x, double p1y) const
80
39.4M
{
81
    // determine oriented segment pointing in positive X direction
82
39.4M
    double px = p0x;
83
39.4M
    double py = p0y;
84
39.4M
    double qx = p1x;
85
39.4M
    double qy = p1y;
86
39.4M
    if (px > qx) {
87
18.6M
        px = p1x;
88
18.6M
        py = p1y;
89
18.6M
        qx = p0x;
90
18.6M
        qy = p0y;
91
18.6M
    }
92
93
    /**
94
    * Report false if segment env does not intersect pixel env.
95
    * This check reflects the fact that the pixel Top and Right sides
96
    * are open (not part of the pixel).
97
    */
98
    // check Right side
99
39.4M
    double maxx = hpx + TOLERANCE;
100
39.4M
    double segMinx = std::min(px, qx);
101
39.4M
    if (segMinx >= maxx) return false;
102
    // check Left side
103
39.2M
    double minx = hpx - TOLERANCE;
104
39.2M
    double segMaxx = std::max(px, qx);
105
39.2M
    if (segMaxx < minx) return false;
106
    // check Top side
107
39.1M
    double maxy = hpy + TOLERANCE;
108
39.1M
    double segMiny = std::min(py, qy);
109
39.1M
    if (segMiny >= maxy) return false;
110
    // check Bottom side
111
39.0M
    double miny = hpy - TOLERANCE;
112
39.0M
    double segMaxy = std::max(py, qy);
113
39.0M
    if (segMaxy < miny) return false;
114
115
    /**
116
    * Vertical or horizontal segments must now intersect
117
    * the segment interior or Left or Bottom sides.
118
    */
119
    // check vertical segment
120
38.9M
    if (px == qx) {
121
1.08M
        return true;
122
1.08M
    }
123
    // check horizontal segment
124
37.8M
    if (py == qy) {
125
889k
        return true;
126
889k
    }
127
128
    /**
129
    * Now know segment is not horizontal or vertical.
130
    *
131
    * Compute orientation WRT each pixel corner.
132
    * If corner orientation == 0,
133
    * segment intersects the corner.
134
    * From the corner and whether segment is heading up or down,
135
    * can determine intersection or not.
136
    *
137
    * Otherwise, check whether segment crosses interior of pixel side
138
    * This is the case if the orientations for each corner of the side are different.
139
    */
140
36.9M
    int orientUL = CGAlgorithmsDD::orientationIndex(px, py, qx, qy, minx, maxy);
141
36.9M
    if (orientUL == 0) {
142
        // upward segment does not intersect pixel interior
143
130k
        if (py < qy) return false;
144
        // downward segment must intersect pixel interior
145
125k
        return true;
146
130k
    }
147
148
36.7M
    int orientUR = CGAlgorithmsDD::orientationIndex(px, py, qx, qy, maxx, maxy);
149
36.7M
    if (orientUR == 0) {
150
        // downward segment does not intersect pixel interior
151
133k
        if (py > qy) return false;
152
        // upward segment must intersect pixel interior
153
133k
        return true;
154
133k
    }
155
    // check crossing Top side
156
36.6M
    if (orientUL != orientUR) {
157
7.53M
        return true;
158
7.53M
    }
159
160
29.1M
    int orientLL = CGAlgorithmsDD::orientationIndex(px, py, qx, qy, minx, miny);
161
29.1M
    if (orientLL == 0) {
162
        // LL corner is the only one in pixel interior
163
2.86k
        return true;
164
2.86k
    }
165
    // check crossing Left side
166
29.1M
    if (orientLL != orientUL) {
167
6.14M
        return true;
168
6.14M
    }
169
170
22.9M
    int orientLR = CGAlgorithmsDD::orientationIndex(px, py, qx, qy, maxx, miny);
171
22.9M
    if (orientLR == 0) {
172
        // upward segment does not intersect pixel interior
173
1.99k
        if (py < qy) return false;
174
        // downward segment must intersect pixel interior
175
0
        return true;
176
1.99k
    }
177
178
    // check crossing Bottom side
179
22.9M
    if (orientLL != orientLR) {
180
1.47M
        return true;
181
1.47M
    }
182
    // check crossing Right side
183
21.5M
    if (orientLR != orientUR) {
184
0
        return true;
185
0
    }
186
187
    // segment does not intersect pixel
188
21.5M
    return false;
189
21.5M
}
190
191
/*private*/
192
bool
193
HotPixel::intersectsPixelClosure(const Coordinate& p0, const Coordinate& p1) const
194
0
{
195
0
    LineIntersector li;
196
0
    std::array<Coordinate, 4> corner;
197
198
0
    double minx = hpx - TOLERANCE;
199
0
    double maxx = hpx + TOLERANCE;
200
0
    double miny = hpy - TOLERANCE;
201
0
    double maxy = hpy + TOLERANCE;
202
203
0
    corner[UPPER_RIGHT] = Coordinate(maxx, maxy);
204
0
    corner[UPPER_LEFT]  = Coordinate(minx, maxy);
205
0
    corner[LOWER_LEFT]  = Coordinate(minx, miny);
206
0
    corner[LOWER_RIGHT] = Coordinate(maxx, miny);
207
208
0
    li.computeIntersection(p0, p1, corner[UPPER_RIGHT], corner[UPPER_LEFT]);
209
0
    if (li.hasIntersection()) {
210
0
        return true;
211
0
    }
212
0
    li.computeIntersection(p0, p1, corner[UPPER_LEFT], corner[LOWER_LEFT]);
213
0
    if (li.hasIntersection()) {
214
0
        return true;
215
0
    }
216
0
    li.computeIntersection(p0, p1, corner[LOWER_LEFT], corner[LOWER_RIGHT]);
217
0
    if (li.hasIntersection()) {
218
0
        return true;
219
0
    }
220
0
    li.computeIntersection(p0, p1, corner[LOWER_RIGHT], corner[UPPER_RIGHT]);
221
0
    if (li.hasIntersection()) {
222
0
        return true;
223
0
    }
224
225
0
    return false;
226
0
}
227
228
229
std::ostream&
230
HotPixel::operator<< (std::ostream& os)
231
0
{
232
0
    os << "HP(" << io::WKTWriter::toPoint(originalPt) << ")";
233
0
    return os;
234
0
}
235
236
237
} // namespace geos.noding.snapround
238
} // namespace geos.noding
239
} // namespace geos