Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgeorectangle.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
10#include "qnumeric.h"
12#include <QList>
14
15QT_IMPL_METATYPE_EXTERN(QGeoRectangle)
16
17/*!
18 \class QGeoRectangle
19 \inmodule QtPositioning
20 \ingroup QtPositioning-positioning
21 \since 5.2
22
23 \brief The QGeoRectangle class defines a rectangular geographic area.
24
25 The rectangle is defined in terms of a QGeoCoordinate which specifies the
26 top left coordinate of the rectangle and a QGeoCoordinate which specifies
27 the bottom right coordinate of the rectangle.
28
29 A geo rectangle is considered invalid if the top left or bottom right
30 coordinates are invalid or if the top left coordinate is south of the
31 bottom right coordinate.
32
33 Geo rectangles can never cross the poles.
34
35 Several methods behave as though the geo rectangle is defined in terms of a
36 center coordinate, the width of the geo rectangle in degrees and the height
37 of the geo rectangle in degrees.
38
39 If the height or center of a geo rectangle is adjusted such that it would
40 cross one of the poles the height is modified such that the geo rectangle
41 touches but does not cross the pole and that the center coordinate is still
42 in the center of the geo rectangle.
43
44 This class is a \l Q_GADGET since Qt 5.5. It can be
45 \l{Cpp_value_integration_positioning}{directly used from C++ and QML}.
46*/
47
48/*!
49 \property QGeoRectangle::bottomLeft
50 \brief This property holds the bottom left coorindate of this geo rectangle.
51
52 While this property is introduced in Qt 5.5, the related accessor functions
53 exist since the first version of this class.
54
55 \since 5.5
56*/
57
58/*!
59 \property QGeoRectangle::bottomRight
60 \brief This property holds the bottom right coordinate of this geo rectangle.
61
62 While this property is introduced in Qt 5.5, the related accessor functions
63 exist since the first version of this class.
64
65 \since 5.5
66*/
67
68/*!
69 \property QGeoRectangle::topLeft
70 \brief This property holds the top left coordinate of this geo rectangle.
71
72 While this property is introduced in Qt 5.5, the related accessor functions
73 exist since the first version of this class.
74
75 \since 5.5
76*/
77
78/*!
79 \property QGeoRectangle::topRight
80 \brief This property holds the top right coordinate of this geo rectangle.
81
82 While this property is introduced in Qt 5.5, the related accessor functions
83 exist since the first version of this class.
84
85 \since 5.5
86*/
87
88/*!
89 \property QGeoRectangle::center
90 \brief This property holds the center of this geo rectangle.
91
92 While this property is introduced in Qt 5.5, the related accessor functions
93 exist since the first version of this class.
94
95 \sa QGeoShape::center
96
97 \since 5.5
98*/
99
100/*!
101 \property QGeoRectangle::width
102 \brief This property holds the width of this geo rectangle in degrees.
103
104 The property value is undefined if this geo rectangle is invalid.
105
106 If the new width is less than 0.0 or if this geo rectangle is invalid, this
107 function does nothing. To set up the values of an invalid
108 geo rectangle based on the center, width, and height, you should use
109 \l setCenter() first to make the geo rectangle valid.
110
111 360.0 is the width used only if the new width is equal or greater than 360.
112 In such cases the leftmost longitude of the geo rectangle is set to -180.0
113 degrees and the rightmost longitude of the geo rectangle is set to 180.0
114 degrees.
115
116 While this property is introduced in Qt 5.5, the related accessor functions
117 exist since the first version of this class.
118
119 \since 5.5
120*/
121
122/*!
123 \property QGeoRectangle::height
124 \brief This property holds the height of this geo rectangle in degrees.
125
126 The property value is undefined if this geo rectangle is invalid.
127
128 If the new height is less than 0.0 or if this geo rectangle is invalid,
129 the property is not changed. To set up the values of an invalid
130 geo rectangle based on the center, width, and height, you should use
131 \l setCenter() first to make the geo rectangle valid.
132
133 If the change in height would cause the geo rectangle to cross a pole,
134 the height is adjusted such that the geo rectangle only touches the pole.
135
136 This change is done such that the center coordinate is still at the
137 center of the geo rectangle, which may result in a geo rectangle with
138 a smaller height than expected.
139
140 180.0 is the height used only if the new height is greater or equal than 180.
141
142 While this property is introduced in Qt 5.5, the related accessor functions
143 exist since the first version of this class.
144
145 \since 5.5
146*/
147
148inline QGeoRectanglePrivate *QGeoRectangle::d_func()
149{
150 return static_cast<QGeoRectanglePrivate *>(d_ptr.data());
151}
152
153inline const QGeoRectanglePrivate *QGeoRectangle::d_func() const
154{
155 return static_cast<const QGeoRectanglePrivate *>(d_ptr.constData());
156}
157
158/*!
159 Constructs a new, invalid geo rectangle.
160*/
161QGeoRectangle::QGeoRectangle()
162: QGeoShape(new QGeoRectanglePrivate)
163{
164}
165
166/*!
167 Constructs a new geo rectangle centered at \a center with a
168 width in degrees of \a degreesWidth and a height in degrees of \a degreesHeight.
169
170 If \a degreesHeight would take the geo rectangle beyond one of the poles,
171 the height of the geo rectangle will be truncated such that the geo rectangle
172 only extends up to the pole. The center of the geo rectangle will be
173 unchanged, and the height will be adjusted such that the center point is at
174 the center of the truncated geo rectangle.
175*/
176QGeoRectangle::QGeoRectangle(const QGeoCoordinate &center, double degreesWidth, double degreesHeight)
177{
178 d_ptr = new QGeoRectanglePrivate(center, center);
179 setWidth(degreesWidth);
180 setHeight(degreesHeight);
181}
182
183/*!
184 Constructs a new geo rectangle with a top left coordinate \a topLeft and a bottom right
185 coordinate \a bottomRight.
186*/
187QGeoRectangle::QGeoRectangle(const QGeoCoordinate &topLeft, const QGeoCoordinate &bottomRight)
188{
189 d_ptr = new QGeoRectanglePrivate(topLeft, bottomRight);
190}
191
192/*!
193 Constructs a new geo rectangle, of minimum size, containing all of the \a coordinates.
194*/
195QGeoRectangle::QGeoRectangle(const QList<QGeoCoordinate> &coordinates)
196{
197 if (coordinates.isEmpty()) {
198 d_ptr = new QGeoRectanglePrivate;
199 } else {
200 const QGeoCoordinate &startCoordinate = coordinates.first();
201 d_ptr = new QGeoRectanglePrivate(startCoordinate, startCoordinate);
202
203 for (const QGeoCoordinate &coordinate : coordinates)
204 d_func()->extendRectangle(coordinate);
205 }
206}
207
208/*!
209 Constructs a geo rectangle from the contents of \a other.
210*/
211QGeoRectangle::QGeoRectangle(const QGeoRectangle &other)
212: QGeoShape(other)
213{
214}
215
216/*!
217 Constructs a geo rectangle from the contents of \a other.
218*/
219QGeoRectangle::QGeoRectangle(const QGeoShape &other)
220: QGeoShape(other)
221{
222 if (type() != QGeoShape::RectangleType)
223 d_ptr = new QGeoRectanglePrivate;
224}
225
226/*!
227 Destroys this geo rectangle.
228*/
229QGeoRectangle::~QGeoRectangle()
230{
231}
232
233/*!
234 Assigns \a other to this geo rectangle and returns a reference to this geo rectangle.
235*/
236QGeoRectangle &QGeoRectangle::operator=(const QGeoRectangle &other)
237{
238 QGeoShape::operator=(other);
239 return *this;
240}
241
242bool QGeoRectanglePrivate::isValid() const
243{
244 return topLeft.isValid() && bottomRight.isValid() &&
245 topLeft.latitude() >= bottomRight.latitude();
246}
247
248bool QGeoRectanglePrivate::isEmpty() const
249{
250 if (!isValid())
251 return true;
252
253 return topLeft.latitude() == bottomRight.latitude() ||
254 topLeft.longitude() == bottomRight.longitude();
255}
256
257/*!
258 Sets the top left coordinate of this geo rectangle to \a topLeft.
259*/
260void QGeoRectangle::setTopLeft(const QGeoCoordinate &topLeft)
261{
262 Q_D(QGeoRectangle);
263
264 d->topLeft = topLeft;
265}
266
267/*!
268 Returns the top left coordinate of this geo rectangle.
269*/
270QGeoCoordinate QGeoRectangle::topLeft() const
271{
272 Q_D(const QGeoRectangle);
273
274 return d->topLeft;
275}
276
277/*!
278 Sets the top right coordinate of this geo rectangle to \a topRight.
279*/
280void QGeoRectangle::setTopRight(const QGeoCoordinate &topRight)
281{
282 Q_D(QGeoRectangle);
283
284 d->topLeft.setLatitude(topRight.latitude());
285 d->bottomRight.setLongitude(topRight.longitude());
286}
287
288/*!
289 Returns the top right coordinate of this geo rectangle.
290*/
291QGeoCoordinate QGeoRectangle::topRight() const
292{
293 // TODO remove?
294 if (!isValid())
295 return QGeoCoordinate();
296
297 Q_D(const QGeoRectangle);
298
299 return QGeoCoordinate(d->topLeft.latitude(), d->bottomRight.longitude());
300}
301
302/*!
303 Sets the bottom left coordinate of this geo rectangle to \a bottomLeft.
304*/
305void QGeoRectangle::setBottomLeft(const QGeoCoordinate &bottomLeft)
306{
307 Q_D(QGeoRectangle);
308
309 d->bottomRight.setLatitude(bottomLeft.latitude());
310 d->topLeft.setLongitude(bottomLeft.longitude());
311}
312
313/*!
314 Returns the bottom left coordinate of this geo rectangle.
315*/
316QGeoCoordinate QGeoRectangle::bottomLeft() const
317{
318 // TODO remove?
319 if (!isValid())
320 return QGeoCoordinate();
321
322 Q_D(const QGeoRectangle);
323
324 return QGeoCoordinate(d->bottomRight.latitude(), d->topLeft.longitude());
325}
326
327/*!
328 Sets the bottom right coordinate of this geo rectangle to \a bottomRight.
329*/
330void QGeoRectangle::setBottomRight(const QGeoCoordinate &bottomRight)
331{
332 Q_D(QGeoRectangle);
333
334 d->bottomRight = bottomRight;
335}
336
337/*!
338 Returns the bottom right coordinate of this geo rectangle.
339*/
340QGeoCoordinate QGeoRectangle::bottomRight() const
341{
342 Q_D(const QGeoRectangle);
343
344 return d->bottomRight;
345}
346
347/*!
348 Sets the center of this geo rectangle to \a center.
349
350 If this causes the geo rectangle to cross on of the poles the height of the
351 geo rectangle will be truncated such that the geo rectangle only extends up
352 to the pole. The center of the geo rectangle will be unchanged, and the
353 height will be adjusted such that the center point is at the center of the
354 truncated geo rectangle.
355
356*/
357void QGeoRectangle::setCenter(const QGeoCoordinate &center)
358{
359 Q_D(QGeoRectangle);
360
361 if (!isValid()) {
362 d->topLeft = center;
363 d->bottomRight = center;
364 return;
365 }
366 double width = this->width();
367 double height = this->height();
368
369 double tlLat = center.latitude() + height / 2.0;
370 double tlLon = center.longitude() - width / 2.0;
371 double brLat = center.latitude() - height / 2.0;
372 double brLon = center.longitude() + width / 2.0;
373 tlLon = QLocationUtils::wrapLong(tlLon);
374 brLon = QLocationUtils::wrapLong(brLon);
375
376 if (tlLat > 90.0) {
377 brLat = 2 * center.latitude() - 90.0;
378 tlLat = 90.0;
379 }
380
381 if (tlLat < -90.0) {
382 brLat = -90.0;
383 tlLat = -90.0;
384 }
385
386 if (brLat > 90.0) {
387 tlLat = 90.0;
388 brLat = 90.0;
389 }
390
391 if (brLat < -90.0) {
392 tlLat = 2 * center.latitude() + 90.0;
393 brLat = -90.0;
394 }
395
396 if (width == 360.0) {
397 tlLon = -180.0;
398 brLon = 180.0;
399 }
400
401 d->topLeft = QGeoCoordinate(tlLat, tlLon);
402 d->bottomRight = QGeoCoordinate(brLat, brLon);
403}
404
405/*!
406 Returns the center of this geo rectangle. Equivalent to QGeoShape::center().
407*/
408QGeoCoordinate QGeoRectangle::center() const
409{
410 Q_D(const QGeoRectangle);
411
412 return d->center();
413}
414
415/*!
416 Sets the width of this geo rectangle in degrees to \a degreesWidth.
417*/
418void QGeoRectangle::setWidth(double degreesWidth)
419{
420 if (!isValid())
421 return;
422
423 if (degreesWidth < 0.0)
424 return;
425
426 Q_D(QGeoRectangle);
427
428 if (degreesWidth >= 360.0) {
429 d->topLeft.setLongitude(-180.0);
430 d->bottomRight.setLongitude(180.0);
431 return;
432 }
433
434 double tlLat = d->topLeft.latitude();
435 double brLat = d->bottomRight.latitude();
436
437 QGeoCoordinate c = center();
438
439 double tlLon = c.longitude() - degreesWidth / 2.0;
440 tlLon = QLocationUtils::wrapLong(tlLon);
441
442 double brLon = c.longitude() + degreesWidth / 2.0;
443 brLon = QLocationUtils::wrapLong(brLon);
444
445 d->topLeft = QGeoCoordinate(tlLat, tlLon);
446 d->bottomRight = QGeoCoordinate(brLat, brLon);
447}
448
449/*!
450 Returns the width of this geo rectangle in degrees.
451
452 The return value is undefined if this geo rectangle is invalid.
453*/
454double QGeoRectangle::width() const
455{
456 if (!isValid())
457 return qQNaN();
458
459 Q_D(const QGeoRectangle);
460
461 double result = d->bottomRight.longitude() - d->topLeft.longitude();
462 if (result < 0.0)
463 result += 360.0;
464 if (result > 360.0)
465 result -= 360.0;
466
467 return result;
468}
469
470/*!
471 Sets the height of this geo rectangle in degrees to \a degreesHeight.
472*/
473void QGeoRectangle::setHeight(double degreesHeight)
474{
475 if (!isValid())
476 return;
477
478 if (degreesHeight < 0.0)
479 return;
480
481 if (degreesHeight >= 180.0) {
482 degreesHeight = 180.0;
483 }
484
485 Q_D(QGeoRectangle);
486
487 double tlLon = d->topLeft.longitude();
488 double brLon = d->bottomRight.longitude();
489
490 QGeoCoordinate c = center();
491
492 double tlLat = c.latitude() + degreesHeight / 2.0;
493 double brLat = c.latitude() - degreesHeight / 2.0;
494
495 if (tlLat > 90.0) {
496 brLat = 2* c.latitude() - 90.0;
497 tlLat = 90.0;
498 }
499
500 if (tlLat < -90.0) {
501 brLat = -90.0;
502 tlLat = -90.0;
503 }
504
505 if (brLat > 90.0) {
506 tlLat = 90.0;
507 brLat = 90.0;
508 }
509
510 if (brLat < -90.0) {
511 tlLat = 2 * c.latitude() + 90.0;
512 brLat = -90.0;
513 }
514
515 d->topLeft = QGeoCoordinate(tlLat, tlLon);
516 d->bottomRight = QGeoCoordinate(brLat, brLon);
517}
518
519/*!
520 Returns the height of this geo rectangle in degrees.
521
522 The return value is undefined if this geo rectangle is invalid.
523*/
524double QGeoRectangle::height() const
525{
526 if (!isValid())
527 return qQNaN();
528
529 Q_D(const QGeoRectangle);
530
531 return d->topLeft.latitude() - d->bottomRight.latitude();
532}
533
534bool QGeoRectanglePrivate::contains(const QGeoCoordinate &coordinate) const
535{
536 if (!isValid() || !coordinate.isValid())
537 return false;
538
539 double left = topLeft.longitude();
540 double right = bottomRight.longitude();
541 double top = topLeft.latitude();
542 double bottom = bottomRight.latitude();
543
544 double lon = coordinate.longitude();
545 double lat = coordinate.latitude();
546
547 if (lat > top)
548 return false;
549 if (lat < bottom)
550 return false;
551
552 if ((lat == 90.0) && (top == 90.0))
553 return true;
554
555 if ((lat == -90.0) && (bottom == -90.0))
556 return true;
557
558 if (left <= right) {
559 if ((lon < left) || (lon > right))
560 return false;
561 } else {
562 if ((lon < left) && (lon > right))
563 return false;
564 }
565
566 return true;
567}
568
569QGeoCoordinate QGeoRectanglePrivate::center() const
570{
571 if (!isValid())
572 return QGeoCoordinate();
573
574 double cLat = (topLeft.latitude() + bottomRight.latitude()) / 2.0;
575 double cLon = (bottomRight.longitude() + topLeft.longitude()) / 2.0;
576
577 if (topLeft.longitude() > bottomRight.longitude())
578 cLon = cLon - 180.0;
579
580 cLon = QLocationUtils::wrapLong(cLon);
581 return QGeoCoordinate(cLat, cLon);
582}
583
584QGeoRectangle QGeoRectanglePrivate::boundingGeoRectangle() const
585{
586 return QGeoRectangle(topLeft, bottomRight);
587}
588
589/*!
590 Returns whether the geo rectangle \a rectangle is contained within this
591 geo rectangle.
592*/
593bool QGeoRectangle::contains(const QGeoRectangle &rectangle) const
594{
595 Q_D(const QGeoRectangle);
596
597 return (d->contains(rectangle.topLeft())
598 && d->contains(rectangle.topRight())
599 && d->contains(rectangle.bottomLeft())
600 && d->contains(rectangle.bottomRight()));
601}
602
603/*!
604 Returns whether the geo rectangle \a rectangle intersects this geo rectangle.
605
606 If the top or bottom edges of both geo rectangles are at one of the poles
607 the geo rectangles are considered to be intersecting, since the longitude
608 is irrelevant when the edges are at the pole.
609*/
610bool QGeoRectangle::intersects(const QGeoRectangle &rectangle) const
611{
612 Q_D(const QGeoRectangle);
613
614 double left1 = d->topLeft.longitude();
615 double right1 = d->bottomRight.longitude();
616 double top1 = d->topLeft.latitude();
617 double bottom1 = d->bottomRight.latitude();
618
619 double left2 = rectangle.d_func()->topLeft.longitude();
620 double right2 = rectangle.d_func()->bottomRight.longitude();
621 double top2 = rectangle.d_func()->topLeft.latitude();
622 double bottom2 = rectangle.d_func()->bottomRight.latitude();
623
624 if (top1 < bottom2)
625 return false;
626
627 if (bottom1 > top2)
628 return false;
629
630 if ((top1 == 90.0) && (top1 == top2))
631 return true;
632
633 if ((bottom1 == -90.0) && (bottom1 == bottom2))
634 return true;
635
636 if (left1 < right1) {
637 if (left2 < right2) {
638 if ((left1 > right2) || (right1 < left2))
639 return false;
640 } else {
641 if ((left1 > right2) && (right1 < left2))
642 return false;
643 }
644 } else {
645 if (left2 < right2) {
646 if ((left2 > right1) && (right2 < left1))
647 return false;
648 } else {
649 // if both wrap then they have to intersect
650 }
651 }
652
653 return true;
654}
655
656/*!
657 Translates this geo rectangle by \a degreesLatitude northwards and \a
658 degreesLongitude eastwards.
659
660 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
661 southward and westward translation respectively.
662
663 If the translation would have caused the geo rectangle to cross a pole the
664 geo rectangle will be translated until the top or bottom edge of the geo rectangle
665 touches the pole but not further.
666*/
667void QGeoRectangle::translate(double degreesLatitude, double degreesLongitude)
668{
669 // TODO handle dlat, dlon larger than 360 degrees
670
671 Q_D(QGeoRectangle);
672
673 double tlLat = d->topLeft.latitude();
674 double tlLon = d->topLeft.longitude();
675 double brLat = d->bottomRight.latitude();
676 double brLon = d->bottomRight.longitude();
677
678 if (degreesLatitude >= 0.0)
679 degreesLatitude = qMin(degreesLatitude, 90.0 - tlLat);
680 else
681 degreesLatitude = qMax(degreesLatitude, -90.0 - brLat);
682
683 if ( (tlLon != -180.0) || (brLon != 180.0) ) {
684 tlLon = QLocationUtils::wrapLong(tlLon + degreesLongitude);
685 brLon = QLocationUtils::wrapLong(brLon + degreesLongitude);
686 }
687
688 tlLat += degreesLatitude;
689 brLat += degreesLatitude;
690
691 d->topLeft = QGeoCoordinate(tlLat, tlLon);
692 d->bottomRight = QGeoCoordinate(brLat, brLon);
693}
694
695/*!
696 Returns a copy of this geo rectangle translated by \a degreesLatitude northwards and \a
697 degreesLongitude eastwards.
698
699 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
700 southward and westward translation respectively.
701
702 \sa translate()
703*/
704QGeoRectangle QGeoRectangle::translated(double degreesLatitude, double degreesLongitude) const
705{
706 QGeoRectangle result(*this);
707 result.translate(degreesLatitude, degreesLongitude);
708 return result;
709}
710
711/*!
712 Extends the geo rectangle to also cover the coordinate \a coordinate
713
714 \since 5.9
715*/
716void QGeoRectangle::extendRectangle(const QGeoCoordinate &coordinate)
717{
718 Q_D(QGeoRectangle);
719 d->extendRectangle(coordinate);
720}
721
722/*!
723 Returns the smallest geo rectangle which contains both this geo rectangle and \a rectangle.
724
725 If the centers of the two geo rectangles are separated by exactly 180.0 degrees then the
726 width is set to 360.0 degrees with the leftmost longitude set to -180.0 degrees and the
727 rightmost longitude set to 180.0 degrees. This is done to ensure that the result is
728 independent of the order of the operands.
729
730*/
731QGeoRectangle QGeoRectangle::united(const QGeoRectangle &rectangle) const
732{
733 QGeoRectangle result(*this);
734 if (rectangle.isValid())
735 result |= rectangle;
736 return result;
737}
738
739/*!
740 Extends the rectangle in the smallest possible way to include \a coordinate in
741 the shape.
742
743 Both the rectangle and coordinate needs to be valid. If the rectangle already covers
744 the coordinate noting happens.
745
746*/
747void QGeoRectanglePrivate::extendRectangle(const QGeoCoordinate &coordinate)
748{
749 if (!isValid() || !coordinate.isValid() || contains(coordinate))
750 return;
751
752 double left = topLeft.longitude();
753 double right = bottomRight.longitude();
754 double top = topLeft.latitude();
755 double bottom = bottomRight.latitude();
756
757 double inputLat = coordinate.latitude();
758 double inputLon = coordinate.longitude();
759
760 top = qMax(top, inputLat);
761 bottom = qMin(bottom, inputLat);
762
763 bool wrap = left > right;
764
765 if (wrap && inputLon > right && inputLon < left) {
766 if (qAbs(left - inputLon) < qAbs(right - inputLon))
767 left = inputLon;
768 else
769 right = inputLon;
770 } else if (!wrap) {
771 if (inputLon < left) {
772 if (360 - (right - inputLon) < left - inputLon)
773 right = inputLon;
774 else
775 left = inputLon;
776 } else if (inputLon > right) {
777 if (360 - (inputLon - left) < inputLon - right)
778 left = inputLon;
779 else
780 right = inputLon;
781 }
782 }
783 topLeft = QGeoCoordinate(top, left);
784 bottomRight = QGeoCoordinate(bottom, right);
785}
786
787/*!
788 \fn QGeoRectangle QGeoRectangle::operator|(const QGeoRectangle &rectangle) const
789
790 Returns the smallest geo rectangle which contains both this geo rectangle and \a rectangle.
791
792 If the centers of the two geo rectangles are separated by exactly 180.0 degrees then the
793 width is set to 360.0 degrees with the leftmost longitude set to -180.0 degrees and the
794 rightmost longitude set to 180.0 degrees. This is done to ensure that the result is
795 independent of the order of the operands.
796
797*/
798
799/*!
800 Returns the smallest geo rectangle which contains both this geo rectangle and \a rectangle.
801
802 If the centers of the two geo rectangles are separated by exactly 180.0 degrees then the
803 width is set to 360.0 degrees with the leftmost longitude set to -180.0 degrees and the
804 rightmost longitude set to 180.0 degrees. This is done to ensure that the result is
805 independent of the order of the operands.
806
807*/
808QGeoRectangle &QGeoRectangle::operator|=(const QGeoRectangle &rectangle)
809{
810 // If non-intersecting goes for most narrow box
811
812 Q_D(QGeoRectangle);
813
814 double top = qMax(d->topLeft.latitude(), rectangle.d_func()->topLeft.latitude());
815 double bottom = qMin(d->bottomRight.latitude(), rectangle.d_func()->bottomRight.latitude());
816
817 QGeoRectangle candidate(
818 {top, d->topLeft.longitude()},
819 {bottom, rectangle.d_func()->bottomRight.longitude()}
820 );
821 QGeoRectangle otherCandidate(
822 {top, rectangle.d_func()->topLeft.longitude()},
823 {bottom, d->bottomRight.longitude()}
824 );
825 double unwrappedWidth = (candidate.width() < rectangle.width() ? 360 : 0) + candidate.width();
826 double otherUnwrappedWidth = (otherCandidate.width() < width() ? 360 : 0) + otherCandidate.width();
827 if (otherUnwrappedWidth < unwrappedWidth) {
828 candidate = otherCandidate;
829 unwrappedWidth = otherUnwrappedWidth;
830 }
831 if (360 <= unwrappedWidth) {
832 candidate.d_func()->topLeft.setLongitude(-180.0);
833 candidate.d_func()->bottomRight.setLongitude(180.0);
834 }
835
836 candidate = (candidate.width() < width() ? *this : candidate);
837 candidate = (candidate.width() < rectangle.width() ? rectangle : candidate);
838
839 double middle1 = center().longitude();
840 double middle2 = rectangle.center().longitude();
841 if ((middle1 <= middle2 ? 0 : 360) + middle2 - middle1 == 180) {
842 candidate.d_func()->topLeft.setLongitude(-180.0);
843 candidate.d_func()->bottomRight.setLongitude(180.0);
844 }
845
846 *this = candidate;
847 this->d_func()->topLeft.setLatitude(top);
848 this->d_func()->bottomRight.setLatitude(bottom);
849
850 return *this;
851}
852
853/*!
854 Returns the geo rectangle properties as a string.
855
856 \since 5.5
857*/
858QString QGeoRectangle::toString() const
859{
860 if (type() != QGeoShape::RectangleType) {
861 qWarning("Not a rectangle a %d\n", type());
862 return QStringLiteral("QGeoRectangle(not a rectangle)");
863 }
864
865 return QStringLiteral("QGeoRectangle({%1, %2}, {%3, %4})")
866 .arg(topLeft().latitude())
867 .arg(topLeft().longitude())
868 .arg(bottomRight().latitude())
869 .arg(bottomRight().longitude());
870}
871
872/*******************************************************************************
873*******************************************************************************/
874
875QGeoRectanglePrivate::QGeoRectanglePrivate()
876: QGeoShapePrivate(QGeoShape::RectangleType)
877{
878}
879
880QGeoRectanglePrivate::QGeoRectanglePrivate(const QGeoCoordinate &topLeft,
881 const QGeoCoordinate &bottomRight)
882: QGeoShapePrivate(QGeoShape::RectangleType), topLeft(topLeft), bottomRight(bottomRight)
883{
884}
885
886QGeoRectanglePrivate::QGeoRectanglePrivate(const QGeoRectanglePrivate &other)
887: QGeoShapePrivate(QGeoShape::RectangleType), topLeft(other.topLeft),
888 bottomRight(other.bottomRight)
889{
890}
891
892QGeoRectanglePrivate::~QGeoRectanglePrivate() {}
893
894QGeoShapePrivate *QGeoRectanglePrivate::clone() const
895{
896 return new QGeoRectanglePrivate(*this);
897}
898
899bool QGeoRectanglePrivate::operator==(const QGeoShapePrivate &other) const
900{
901 if (!QGeoShapePrivate::operator==(other))
902 return false;
903
904 const QGeoRectanglePrivate &otherBox = static_cast<const QGeoRectanglePrivate &>(other);
905
906 return topLeft == otherBox.topLeft && bottomRight == otherBox.bottomRight;
907}
908
909size_t QGeoRectanglePrivate::hash(size_t seed) const
910{
911 return qHashMulti(seed, topLeft, bottomRight);
912}
913
914QT_END_NAMESPACE
915
916#include "moc_qgeorectangle.cpp"
Combined button and popup list for selecting options.