/src/geos/src/geom/Envelope.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2005-2006 Refractions Research Inc. |
7 | | * Copyright (C) 2001-2002 Vivid Solutions Inc. |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Public Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | ********************************************************************** |
15 | | * |
16 | | * Last port: geom/Envelope.java rev 1.46 (JTS-1.10) |
17 | | * |
18 | | **********************************************************************/ |
19 | | |
20 | | #include <geos/geom/Envelope.h> |
21 | | #include <geos/geom/Coordinate.h> |
22 | | |
23 | | #include <algorithm> |
24 | | #include <sstream> |
25 | | #include <cmath> |
26 | | |
27 | | |
28 | | #ifndef GEOS_DEBUG |
29 | | #define GEOS_DEBUG 0 |
30 | | #endif |
31 | | |
32 | | #if GEOS_DEBUG |
33 | | #include <iostream> |
34 | | #endif |
35 | | |
36 | | namespace geos { |
37 | | namespace geom { // geos::geom |
38 | | |
39 | | /*public*/ |
40 | | bool |
41 | | Envelope::intersects(const CoordinateXY& p1, const CoordinateXY& p2, |
42 | | const CoordinateXY& q) |
43 | 220M | { |
44 | | //OptimizeIt shows that Math#min and Math#max here are a bottleneck. |
45 | | //Replace with direct comparisons. [Jon Aquino] |
46 | 220M | if(((q.x >= (p1.x < p2.x ? p1.x : p2.x)) && (q.x <= (p1.x > p2.x ? p1.x : p2.x))) && |
47 | 188M | ((q.y >= (p1.y < p2.y ? p1.y : p2.y)) && (q.y <= (p1.y > p2.y ? p1.y : p2.y)))) { |
48 | 153M | return true; |
49 | 153M | } |
50 | 66.5M | return false; |
51 | 220M | } |
52 | | |
53 | | /*public*/ |
54 | | bool |
55 | | Envelope::intersects(const CoordinateXY& a, const CoordinateXY& b) const |
56 | 4.33M | { |
57 | | // These comparisons look redundant, but an alternative using |
58 | | // std::minmax performs no better and compiles down to more |
59 | | // instructions. |
60 | 4.33M | double envminx = (a.x < b.x) ? a.x : b.x; |
61 | 4.33M | if(!std::isgreaterequal(maxx, envminx)) { // awkward comparison catches cases where this->isNull() |
62 | 1.98M | return false; |
63 | 1.98M | } |
64 | | |
65 | 2.34M | double envmaxx = (a.x > b.x) ? a.x : b.x; |
66 | 2.34M | if(std::isless(envmaxx, minx)) { |
67 | 27.8k | return false; |
68 | 27.8k | } |
69 | | |
70 | 2.31M | double envminy = (a.y < b.y) ? a.y : b.y; |
71 | 2.31M | if(std::isgreater(envminy, maxy)) { |
72 | 72.4k | return false; |
73 | 72.4k | } |
74 | | |
75 | 2.24M | double envmaxy = (a.y > b.y) ? a.y : b.y; |
76 | 2.24M | if(std::isless(envmaxy, miny)) { |
77 | 21.0k | return false; |
78 | 21.0k | } |
79 | | |
80 | 2.22M | return true; |
81 | 2.24M | } |
82 | | |
83 | | /*public*/ |
84 | | Envelope::Envelope(const std::string& str) |
85 | 0 | { |
86 | | // The string should be in the format: |
87 | | // Env[7.2:2.3,7.1:8.2] |
88 | | |
89 | | // extract out the values between the [ and ] characters |
90 | 0 | std::string::size_type index = str.find('['); |
91 | 0 | std::string coordString = str.substr(index + 1, str.size() - 1 - 1); |
92 | | |
93 | | // now split apart the string on : and , characters |
94 | 0 | std::vector<std::string> values = split(coordString, ":,"); |
95 | | |
96 | | // create a new envelope |
97 | 0 | init(strtod(values[0].c_str(), nullptr), |
98 | 0 | strtod(values[1].c_str(), nullptr), |
99 | 0 | strtod(values[2].c_str(), nullptr), |
100 | 0 | strtod(values[3].c_str(), nullptr)); |
101 | 0 | } |
102 | | |
103 | | /*public*/ |
104 | | bool |
105 | | Envelope::covers(const Envelope& other) const |
106 | 49.3k | { |
107 | 49.3k | return |
108 | 49.3k | std::isgreaterequal(other.minx, minx) && |
109 | 45.3k | std::islessequal(other.maxx, maxx) && |
110 | 40.4k | std::isgreaterequal(other.miny, miny) && |
111 | 38.4k | std::islessequal(other.maxy, maxy); |
112 | 49.3k | } |
113 | | |
114 | | /*public*/ |
115 | | bool |
116 | | Envelope::equals(const Envelope* other) const |
117 | 8.14k | { |
118 | 8.14k | if(isNull()) { |
119 | 0 | return other->isNull(); |
120 | 0 | } |
121 | 8.14k | return other->minx == minx && |
122 | 2.47k | other->maxx == maxx && |
123 | 532 | other->miny == miny && |
124 | 214 | other->maxy == maxy; |
125 | 8.14k | } |
126 | | |
127 | | bool |
128 | | Envelope::isfinite() const |
129 | 0 | { |
130 | 0 | return std::isfinite(minx) && std::isfinite(maxx) && |
131 | 0 | std::isfinite(miny) && std::isfinite(maxy); |
132 | 0 | } |
133 | | |
134 | | /* public */ |
135 | | std::ostream& |
136 | | operator<< (std::ostream& os, const Envelope& o) |
137 | 0 | { |
138 | 0 | os << "Env[" << o.minx << ":" << o.maxx << "," |
139 | 0 | << o.miny << ":" << o.maxy << "]"; |
140 | 0 | return os; |
141 | 0 | } |
142 | | |
143 | | |
144 | | /*public*/ |
145 | | std::string |
146 | | Envelope::toString() const |
147 | 0 | { |
148 | 0 | std::ostringstream s; |
149 | 0 | s << *this; |
150 | 0 | return s.str(); |
151 | 0 | } |
152 | | |
153 | | /*public static*/ |
154 | | std::vector<std::string> |
155 | | Envelope::split(const std::string& str, const std::string& delimiters) |
156 | 0 | { |
157 | 0 | std::vector<std::string> tokens; |
158 | | |
159 | | // Find first "non-delimiter". |
160 | 0 | std::string::size_type lastPos = 0; |
161 | 0 | std::string::size_type pos = str.find_first_of(delimiters, lastPos); |
162 | |
|
163 | 0 | while(std::string::npos != pos || std::string::npos != lastPos) { |
164 | | // Found a token, add it to the vector. |
165 | 0 | tokens.push_back(str.substr(lastPos, pos - lastPos)); |
166 | | |
167 | | // Skip delimiters. Note the "not_of" |
168 | 0 | lastPos = str.find_first_not_of(delimiters, pos); |
169 | | |
170 | | // Find next "non-delimiter" |
171 | 0 | pos = str.find_first_of(delimiters, lastPos); |
172 | 0 | } |
173 | |
|
174 | 0 | return tokens; |
175 | 0 | } |
176 | | |
177 | | /*public*/ |
178 | | bool |
179 | | Envelope::centre(CoordinateXY& p_centre) const |
180 | 0 | { |
181 | 0 | if(isNull()) { |
182 | 0 | return false; |
183 | 0 | } |
184 | 0 | p_centre.x = (getMinX() + getMaxX()) / 2.0; |
185 | 0 | p_centre.y = (getMinY() + getMaxY()) / 2.0; |
186 | 0 | return true; |
187 | 0 | } |
188 | | |
189 | | /*public*/ |
190 | | bool |
191 | | Envelope::intersection(const Envelope& env, Envelope& result) const |
192 | 11.4k | { |
193 | 11.4k | if(isNull() || env.isNull() || ! intersects(env)) { |
194 | 1 | return false; |
195 | 1 | } |
196 | | |
197 | 11.4k | double intMinX = minx > env.minx ? minx : env.minx; |
198 | 11.4k | double intMinY = miny > env.miny ? miny : env.miny; |
199 | 11.4k | double intMaxX = maxx < env.maxx ? maxx : env.maxx; |
200 | 11.4k | double intMaxY = maxy < env.maxy ? maxy : env.maxy; |
201 | 11.4k | result.init(intMinX, intMaxX, intMinY, intMaxY); |
202 | 11.4k | return true; |
203 | 11.4k | } |
204 | | |
205 | | /*public*/ |
206 | | Envelope |
207 | | Envelope::intersection(const Envelope& env) const |
208 | 0 | { |
209 | 0 | Envelope ret; |
210 | |
|
211 | 0 | if(isNull() || env.isNull() || ! intersects(env)) { |
212 | 0 | return ret; |
213 | 0 | } |
214 | | |
215 | 0 | double intMinX = minx > env.minx ? minx : env.minx; |
216 | 0 | double intMinY = miny > env.miny ? miny : env.miny; |
217 | 0 | double intMaxX = maxx < env.maxx ? maxx : env.maxx; |
218 | 0 | double intMaxY = maxy < env.maxy ? maxy : env.maxy; |
219 | 0 | ret.init(intMinX, intMaxX, intMinY, intMaxY); |
220 | 0 | return ret; |
221 | 0 | } |
222 | | |
223 | | /*public*/ |
224 | | void |
225 | | Envelope::translate(double transX, double transY) |
226 | 0 | { |
227 | 0 | if(isNull()) { |
228 | 0 | return; |
229 | 0 | } |
230 | 0 | init(getMinX() + transX, getMaxX() + transX, |
231 | 0 | getMinY() + transY, getMaxY() + transY); |
232 | 0 | } |
233 | | |
234 | | |
235 | | /*public*/ |
236 | | void |
237 | | Envelope::expandBy(double deltaX, double deltaY) |
238 | 52.0M | { |
239 | 52.0M | minx -= deltaX; |
240 | 52.0M | maxx += deltaX; |
241 | 52.0M | miny -= deltaY; |
242 | 52.0M | maxy += deltaY; |
243 | | |
244 | | // check for envelope disappearing |
245 | 52.0M | if(std::isgreater(minx, maxx) || std::isgreater(miny, maxy)) { |
246 | 0 | setToNull(); |
247 | 0 | } |
248 | 52.0M | } |
249 | | |
250 | | |
251 | | bool |
252 | | operator< (const Envelope& a, const Envelope& b) |
253 | 0 | { |
254 | | /* |
255 | | * Compares two envelopes using lexicographic ordering. |
256 | | * The ordering comparison is based on the usual numerical |
257 | | * comparison between the sequence of ordinates. |
258 | | * Null envelopes are less than all non-null envelopes. |
259 | | */ |
260 | 0 | if (a.isNull()) { |
261 | | // null == null |
262 | 0 | if (b.isNull()) |
263 | 0 | return false; |
264 | | // null < notnull |
265 | 0 | else |
266 | 0 | return true; |
267 | 0 | } |
268 | | // notnull > null |
269 | 0 | if (b.isNull()) |
270 | 0 | return false; |
271 | | |
272 | | // compare based on numerical ordering of ordinates |
273 | 0 | if (a.getMinX() < b.getMinX()) return true; |
274 | 0 | if (a.getMinX() > b.getMinX()) return false; |
275 | 0 | if (a.getMinY() < b.getMinY()) return true; |
276 | 0 | if (a.getMinY() > b.getMinY()) return false; |
277 | 0 | if (a.getMaxX() < b.getMaxX()) return true; |
278 | 0 | if (a.getMaxX() > b.getMaxX()) return false; |
279 | 0 | if (a.getMaxY() < b.getMaxY()) return true; |
280 | 0 | if (a.getMaxY() > b.getMaxY()) return false; |
281 | 0 | return false; // == is not strictly < |
282 | 0 | } |
283 | | |
284 | | |
285 | | |
286 | | } // namespace geos::geom |
287 | | } // namespace geos |