Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file Boundary.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // A class that stores the 2D geometrical boundary
21 : /****************************************************************************/
22 : #include <config.h>
23 : #include <utility>
24 :
25 : #include <utils/common/StdDefs.h>
26 : #include "GeomHelper.h"
27 : #include "Boundary.h"
28 : #include "PositionVector.h"
29 : #include "Position.h"
30 :
31 :
32 : // ===========================================================================
33 : // method definitions
34 : // ===========================================================================
35 4517622 : Boundary::Boundary()
36 4517622 : : myXmin(10000000000.0), myXmax(-10000000000.0),
37 4517622 : myYmin(10000000000.0), myYmax(-10000000000.0),
38 4517622 : myZmin(10000000000.0), myZmax(-10000000000.0),
39 4517622 : myWasInitialised(false) {}
40 :
41 :
42 116279 : Boundary::Boundary(double x1, double y1, double x2, double y2)
43 116279 : : myXmin(10000000000.0), myXmax(-10000000000.0),
44 116279 : myYmin(10000000000.0), myYmax(-10000000000.0),
45 116279 : myZmin(10000000000.0), myZmax(-10000000000.0),
46 116279 : myWasInitialised(false) {
47 116279 : add(x1, y1);
48 116279 : add(x2, y2);
49 116279 : }
50 :
51 :
52 0 : Boundary::Boundary(double x1, double y1, double z1, double x2, double y2, double z2)
53 0 : : myXmin(10000000000.0), myXmax(-10000000000.0),
54 0 : myYmin(10000000000.0), myYmax(-10000000000.0),
55 0 : myZmin(10000000000.0), myZmax(-10000000000.0),
56 0 : myWasInitialised(false) {
57 0 : add(x1, y1, z1);
58 0 : add(x2, y2, z2);
59 0 : }
60 :
61 :
62 : void
63 2155 : Boundary::reset() {
64 2155 : myXmin = 10000000000.0;
65 2155 : myXmax = -10000000000.0;
66 2155 : myYmin = 10000000000.0;
67 2155 : myYmax = -10000000000.0;
68 2155 : myZmin = 10000000000.0;
69 2155 : myZmax = -10000000000.0;
70 2155 : myWasInitialised = false;
71 2155 : }
72 :
73 :
74 : void
75 12827426 : Boundary::add(double x, double y, double z) {
76 12827426 : if (!myWasInitialised) {
77 3940796 : myYmin = y;
78 3940796 : myYmax = y;
79 3940796 : myXmin = x;
80 3940796 : myXmax = x;
81 3940796 : myZmin = z;
82 3940796 : myZmax = z;
83 : } else {
84 8886630 : myXmin = myXmin < x ? myXmin : x;
85 8886630 : myXmax = myXmax > x ? myXmax : x;
86 8886630 : myYmin = myYmin < y ? myYmin : y;
87 8886630 : myYmax = myYmax > y ? myYmax : y;
88 8886630 : myZmin = myZmin < z ? myZmin : z;
89 8904911 : myZmax = myZmax > z ? myZmax : z;
90 : }
91 12827426 : myWasInitialised = true;
92 12827426 : }
93 :
94 :
95 : void
96 10762021 : Boundary::add(const Position& p) {
97 10762021 : add(p.x(), p.y(), p.z());
98 10762021 : }
99 :
100 :
101 : void
102 914978 : Boundary::add(const Boundary& p) {
103 914978 : add(p.xmin(), p.ymin(), p.zmin());
104 914978 : add(p.xmax(), p.ymax(), p.zmax());
105 914978 : }
106 :
107 :
108 : Position
109 360407 : Boundary::getCenter() const {
110 360407 : return Position((myXmin + myXmax) / (double) 2.0, (myYmin + myYmax) / (double) 2.0, (myZmin + myZmax) / (double) 2.0);
111 : }
112 :
113 :
114 : double
115 3258752 : Boundary::xmin() const {
116 3258752 : return myXmin;
117 : }
118 :
119 :
120 : double
121 2609564 : Boundary::xmax() const {
122 2609564 : return myXmax;
123 : }
124 :
125 :
126 : double
127 3438992 : Boundary::ymin() const {
128 3438992 : return myYmin;
129 : }
130 :
131 :
132 : double
133 2791198 : Boundary::ymax() const {
134 2791198 : return myYmax;
135 : }
136 :
137 :
138 : double
139 914990 : Boundary::zmin() const {
140 914990 : return myZmin;
141 : }
142 :
143 :
144 : double
145 914990 : Boundary::zmax() const {
146 914990 : return myZmax;
147 : }
148 :
149 :
150 : double
151 12991061 : Boundary::getWidth() const {
152 12991061 : return myXmax - myXmin;
153 : }
154 :
155 :
156 : double
157 9337766 : Boundary::getHeight() const {
158 9337766 : return myYmax - myYmin;
159 : }
160 :
161 :
162 : double
163 1812 : Boundary::getZRange() const {
164 1812 : return myZmax - myZmin;
165 : }
166 :
167 :
168 : bool
169 791856 : Boundary::around(const Position& p, double offset) const {
170 : return
171 401186 : ((p.x() <= myXmax + offset) && (p.x() >= myXmin - offset)) &&
172 802777 : ((p.y() <= myYmax + offset) && (p.y() >= myYmin - offset)) &&
173 2422 : ((p.z() <= myZmax + offset) && (p.z() >= myZmin - offset));
174 : }
175 :
176 :
177 : bool
178 1532 : Boundary::around2D(const Position& p, double offset) const {
179 : return
180 1532 : ((p.x() <= myXmax + offset) && (p.x() >= myXmin - offset)) &&
181 1077 : ((p.y() <= myYmax + offset) && (p.y() >= myYmin - offset));
182 : }
183 :
184 :
185 : bool
186 0 : Boundary::around2D(const double x, const double y) const {
187 : return
188 0 : ((x <= myXmax) && (x >= myXmin)) &&
189 0 : ((y <= myYmax) && (y >= myYmin));
190 : }
191 :
192 :
193 : bool
194 100824 : Boundary::overlapsWith(const AbstractPoly& p, double offset) const {
195 : if (
196 : // check whether one of my points lies within the given poly
197 199533 : partialWithin(p, offset) ||
198 : // check whether the polygon lies within me
199 98709 : p.partialWithin(*this, offset)) {
200 2228 : return true;
201 : }
202 : // check whether the bounderies cross
203 : return
204 98596 : p.crosses(Position(myXmax + offset, myYmax + offset), Position(myXmin - offset, myYmax + offset))
205 98596 : ||
206 98596 : p.crosses(Position(myXmin - offset, myYmax + offset), Position(myXmin - offset, myYmin - offset))
207 98595 : ||
208 98595 : p.crosses(Position(myXmin - offset, myYmin - offset), Position(myXmax + offset, myYmin - offset))
209 197191 : ||
210 197191 : p.crosses(Position(myXmax + offset, myYmin - offset), Position(myXmax + offset, myYmax + offset));
211 : }
212 :
213 :
214 : bool
215 393202 : Boundary::crosses(const Position& p1, const Position& p2) const {
216 393202 : const PositionVector line(p1, p2);
217 : return
218 393202 : line.intersects(Position(myXmax, myYmax), Position(myXmin, myYmax))
219 393200 : ||
220 393200 : line.intersects(Position(myXmin, myYmax), Position(myXmin, myYmin))
221 393199 : ||
222 393199 : line.intersects(Position(myXmin, myYmin), Position(myXmax, myYmin))
223 786400 : ||
224 786400 : line.intersects(Position(myXmax, myYmin), Position(myXmax, myYmax));
225 393202 : }
226 :
227 :
228 : bool
229 0 : Boundary::contains2D(const Boundary& b) const {
230 0 : if ((myXmin <= b.xmin()) && (myYmin <= b.ymin()) &&
231 0 : (myXmax >= b.xmax()) && (myYmax >= b.ymax())) {
232 : return true;
233 : } else {
234 0 : return false;
235 : }
236 : }
237 :
238 :
239 : bool
240 0 : Boundary::overlaps2D(const Boundary& b) const {
241 0 : if (around2D(b.myXmin, b.myYmin)) {
242 : return true;
243 0 : } else if (around2D(b.myXmin, b.myYmax)) {
244 : return true;
245 0 : } else if (around2D(b.myXmax, b.myYmin)) {
246 : return true;
247 0 : } else if (around2D(b.myXmax, b.myYmax)) {
248 : return true;
249 : } else {
250 : return false;
251 : }
252 : }
253 :
254 :
255 : bool
256 715 : Boundary::isInitialised() const {
257 715 : return myWasInitialised;
258 : }
259 :
260 :
261 : double
262 6669 : Boundary::distanceTo2D(const Position& p) const {
263 6669 : const double leftDist = myXmin - p.x();
264 6669 : const double rightDist = p.x() - myXmax;
265 6669 : const double bottomDist = myYmin - p.y();
266 6669 : const double topDist = p.y() - myYmax;
267 6669 : if (leftDist > 0.) {
268 4802 : if (bottomDist > 0.) {
269 3499 : return sqrt(leftDist * leftDist + bottomDist * bottomDist);
270 : }
271 1303 : if (topDist > 0.) {
272 503 : return sqrt(leftDist * leftDist + topDist * topDist);
273 : }
274 : return leftDist;
275 : }
276 1867 : if (rightDist > 0.) {
277 267 : if (bottomDist > 0.) {
278 187 : return sqrt(rightDist * rightDist + bottomDist * bottomDist);
279 : }
280 80 : if (topDist > 0.) {
281 26 : return sqrt(rightDist * rightDist + topDist * topDist);
282 : }
283 : return rightDist;
284 : }
285 1600 : if (bottomDist > 0) {
286 : return bottomDist;
287 : }
288 885 : if (topDist > 0) {
289 47 : return topDist;
290 : }
291 : return 0.;
292 : }
293 :
294 :
295 : double
296 31376 : Boundary::distanceTo2D(const Boundary& b) const {
297 31376 : const double leftDist = myXmin - b.myXmax;
298 31376 : const double rightDist = b.myXmin - myXmax;
299 31376 : const double bottomDist = myYmin - b.myYmax;
300 31376 : const double topDist = b.myYmin - myYmax;
301 31376 : if (leftDist > 0.) {
302 1327 : if (bottomDist > 0.) {
303 212 : return sqrt(leftDist * leftDist + bottomDist * bottomDist);
304 : }
305 1115 : if (topDist > 0.) {
306 451 : return sqrt(leftDist * leftDist + topDist * topDist);
307 : }
308 : return leftDist;
309 : }
310 30049 : if (rightDist > 0.) {
311 13521 : if (bottomDist > 0.) {
312 264 : return sqrt(rightDist * rightDist + bottomDist * bottomDist);
313 : }
314 13257 : if (topDist > 0.) {
315 7871 : return sqrt(rightDist * rightDist + topDist * topDist);
316 : }
317 : return rightDist;
318 : }
319 16528 : if (bottomDist > 0) {
320 : return bottomDist;
321 : }
322 15329 : if (topDist > 0) {
323 3531 : return topDist;
324 : }
325 : return 0.;
326 : }
327 :
328 :
329 : bool
330 199239 : Boundary::partialWithin(const AbstractPoly& poly, double offset) const {
331 : return
332 396858 : poly.around(Position(myXmax, myYmax), offset) ||
333 394941 : poly.around(Position(myXmin, myYmax), offset) ||
334 593666 : poly.around(Position(myXmax, myYmin), offset) ||
335 197105 : poly.around(Position(myXmin, myYmin), offset);
336 : }
337 :
338 :
339 : Boundary&
340 1118344 : Boundary::grow(double by) {
341 :
342 1118344 : myXmax += by;
343 1118344 : myYmax += by;
344 1118344 : myXmin -= by;
345 1118344 : myYmin -= by;
346 1118344 : return *this;
347 : }
348 :
349 :
350 : Boundary&
351 0 : Boundary::scale(double by) {
352 0 : growWidth(by * (myXmax - myXmin));
353 0 : growHeight(by * (myYmax - myYmin));
354 0 : return *this;
355 : }
356 :
357 :
358 : void
359 2238349 : Boundary::growWidth(double by) {
360 2238349 : myXmin -= by;
361 2238349 : myXmax += by;
362 2238349 : }
363 :
364 :
365 : void
366 1383911 : Boundary::growHeight(double by) {
367 1383911 : myYmin -= by;
368 1383911 : myYmax += by;
369 1383911 : }
370 :
371 : void
372 24 : Boundary::flipY() {
373 24 : myYmin *= -1.0;
374 24 : myYmax *= -1.0;
375 : double tmp = myYmin;
376 24 : myYmin = myYmax;
377 24 : myYmax = tmp;
378 24 : }
379 :
380 :
381 :
382 : std::ostream&
383 7496 : operator<<(std::ostream& os, const Boundary& b) {
384 29984 : os << b.myXmin << "," << b.myYmin << "," << b.myXmax << "," << b.myYmax;
385 7496 : return os;
386 : }
387 :
388 :
389 : bool
390 370 : Boundary::operator==(const Boundary& b) const {
391 : return (
392 370 : myXmin == b.myXmin &&
393 0 : myXmax == b.myXmax &&
394 0 : myYmin == b.myYmin &&
395 0 : myYmax == b.myYmax &&
396 0 : myZmin == b.myZmin &&
397 370 : myZmax == b.myZmax &&
398 0 : myWasInitialised == b.myWasInitialised);
399 : }
400 :
401 :
402 : bool
403 0 : Boundary::operator!=(const Boundary& b) const {
404 0 : return !(*this == b);
405 : }
406 :
407 :
408 : void
409 436 : Boundary::set(double xmin, double ymin, double xmax, double ymax) {
410 : /*
411 : Takes care of the following extraneous cases w.r.t the input parameters:
412 : - xmin > xmax
413 : - ymin > ymax
414 : */
415 :
416 436 : myXmin = MIN2(xmin, xmax);
417 436 : myYmin = MIN2(ymin, ymax);
418 436 : myXmax = MAX2(xmin, xmax);
419 436 : myYmax = MAX2(ymin, ymax);
420 436 : }
421 :
422 :
423 : void
424 2 : Boundary::setOffsets(double xmin, double ymin, double xmax, double ymax) {
425 2 : myXmin = xmin;
426 2 : myYmin = ymin;
427 2 : myXmax = xmax;
428 2 : myYmax = ymax;
429 2 : }
430 :
431 :
432 : void
433 1435 : Boundary::moveby(double x, double y, double z) {
434 1435 : myXmin += x;
435 1435 : myYmin += y;
436 1435 : myZmin += z;
437 1435 : myXmax += x;
438 1435 : myYmax += y;
439 1435 : myZmax += z;
440 1435 : }
441 :
442 :
443 : PositionVector
444 2290 : Boundary::getShape(const bool closeShape) const {
445 2290 : PositionVector shape;
446 2290 : shape.push_back(Position(myXmin, myYmin));
447 2290 : shape.push_back(Position(myXmin, myYmax));
448 2290 : shape.push_back(Position(myXmax, myYmax));
449 2290 : shape.push_back(Position(myXmax, myYmin));
450 2290 : if (closeShape) {
451 2290 : shape.push_back(Position(myXmin, myYmin));
452 : }
453 2290 : return shape;
454 0 : }
455 :
456 : /****************************************************************************/
|