/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 |