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