Qt 6.x
The Qt SDK
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
4#include "qgeorectangle.h"
5#include "qgeorectangle_p.h"
6
7#include "qwebmercator_p.h"
8#include "qdoublevector2d_p.h"
9#include "qgeocoordinate.h"
10#include "qnumeric.h"
11#include "qlocationutils_p.h"
12#include <QList>
14
16
17
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
163{
164}
165
176QGeoRectangle::QGeoRectangle(const QGeoCoordinate &center, double degreesWidth, double degreesHeight)
177{
179 setWidth(degreesWidth);
180 setHeight(degreesHeight);
181}
182
188{
190}
191
196{
197 if (coordinates.isEmpty()) {
199 } else {
200 const QGeoCoordinate &startCoordinate = coordinates.first();
201 d_ptr = new QGeoRectanglePrivate(startCoordinate, startCoordinate);
202
203 foreach (const QGeoCoordinate &coordinate, coordinates) {
204 d_func()->extendRectangle(coordinate);
205 }
206 }
207}
208
214{
215}
216
222{
225}
226
231{
232}
233
238{
240 return *this;
241}
242
244{
245 return topLeft.isValid() && bottomRight.isValid() &&
247}
248
250{
251 if (!isValid())
252 return true;
253
254 return topLeft.latitude() == bottomRight.latitude() ||
256}
257
262{
263 Q_D(QGeoRectangle);
264
265 d->topLeft = topLeft;
266}
267
272{
273 Q_D(const QGeoRectangle);
274
275 return d->topLeft;
276}
277
282{
283 Q_D(QGeoRectangle);
284
285 d->topLeft.setLatitude(topRight.latitude());
286 d->bottomRight.setLongitude(topRight.longitude());
287}
288
293{
294 // TODO remove?
295 if (!isValid())
296 return QGeoCoordinate();
297
298 Q_D(const QGeoRectangle);
299
300 return QGeoCoordinate(d->topLeft.latitude(), d->bottomRight.longitude());
301}
302
307{
308 Q_D(QGeoRectangle);
309
310 d->bottomRight.setLatitude(bottomLeft.latitude());
311 d->topLeft.setLongitude(bottomLeft.longitude());
312}
313
318{
319 // TODO remove?
320 if (!isValid())
321 return QGeoCoordinate();
322
323 Q_D(const QGeoRectangle);
324
325 return QGeoCoordinate(d->bottomRight.latitude(), d->topLeft.longitude());
326}
327
332{
333 Q_D(QGeoRectangle);
334
335 d->bottomRight = bottomRight;
336}
337
342{
343 Q_D(const QGeoRectangle);
344
345 return d->bottomRight;
346}
347
359{
360 Q_D(QGeoRectangle);
361
362 if (!isValid()) {
363 d->topLeft = center;
364 d->bottomRight = center;
365 return;
366 }
367 double width = this->width();
368 double height = this->height();
369
370 double tlLat = center.latitude() + height / 2.0;
371 double tlLon = center.longitude() - width / 2.0;
372 double brLat = center.latitude() - height / 2.0;
373 double brLon = center.longitude() + width / 2.0;
374 tlLon = QLocationUtils::wrapLong(tlLon);
375 brLon = QLocationUtils::wrapLong(brLon);
376
377 if (tlLat > 90.0) {
378 brLat = 2 * center.latitude() - 90.0;
379 tlLat = 90.0;
380 }
381
382 if (tlLat < -90.0) {
383 brLat = -90.0;
384 tlLat = -90.0;
385 }
386
387 if (brLat > 90.0) {
388 tlLat = 90.0;
389 brLat = 90.0;
390 }
391
392 if (brLat < -90.0) {
393 tlLat = 2 * center.latitude() + 90.0;
394 brLat = -90.0;
395 }
396
397 if (width == 360.0) {
398 tlLon = -180.0;
399 brLon = 180.0;
400 }
401
402 d->topLeft = QGeoCoordinate(tlLat, tlLon);
403 d->bottomRight = QGeoCoordinate(brLat, brLon);
404}
405
410{
411 Q_D(const QGeoRectangle);
412
413 return d->center();
414}
415
419void QGeoRectangle::setWidth(double degreesWidth)
420{
421 if (!isValid())
422 return;
423
424 if (degreesWidth < 0.0)
425 return;
426
427 Q_D(QGeoRectangle);
428
429 if (degreesWidth >= 360.0) {
430 d->topLeft.setLongitude(-180.0);
431 d->bottomRight.setLongitude(180.0);
432 return;
433 }
434
435 double tlLat = d->topLeft.latitude();
436 double brLat = d->bottomRight.latitude();
437
439
440 double tlLon = c.longitude() - degreesWidth / 2.0;
441 tlLon = QLocationUtils::wrapLong(tlLon);
442
443 double brLon = c.longitude() + degreesWidth / 2.0;
444 brLon = QLocationUtils::wrapLong(brLon);
445
446 d->topLeft = QGeoCoordinate(tlLat, tlLon);
447 d->bottomRight = QGeoCoordinate(brLat, brLon);
448}
449
456{
457 if (!isValid())
458 return qQNaN();
459
460 Q_D(const QGeoRectangle);
461
462 double result = d->bottomRight.longitude() - d->topLeft.longitude();
463 if (result < 0.0)
464 result += 360.0;
465 if (result > 360.0)
466 result -= 360.0;
467
468 return result;
469}
470
474void QGeoRectangle::setHeight(double degreesHeight)
475{
476 if (!isValid())
477 return;
478
479 if (degreesHeight < 0.0)
480 return;
481
482 if (degreesHeight >= 180.0) {
483 degreesHeight = 180.0;
484 }
485
486 Q_D(QGeoRectangle);
487
488 double tlLon = d->topLeft.longitude();
489 double brLon = d->bottomRight.longitude();
490
492
493 double tlLat = c.latitude() + degreesHeight / 2.0;
494 double brLat = c.latitude() - degreesHeight / 2.0;
495
496 if (tlLat > 90.0) {
497 brLat = 2* c.latitude() - 90.0;
498 tlLat = 90.0;
499 }
500
501 if (tlLat < -90.0) {
502 brLat = -90.0;
503 tlLat = -90.0;
504 }
505
506 if (brLat > 90.0) {
507 tlLat = 90.0;
508 brLat = 90.0;
509 }
510
511 if (brLat < -90.0) {
512 tlLat = 2 * c.latitude() + 90.0;
513 brLat = -90.0;
514 }
515
516 d->topLeft = QGeoCoordinate(tlLat, tlLon);
517 d->bottomRight = QGeoCoordinate(brLat, brLon);
518}
519
526{
527 if (!isValid())
528 return qQNaN();
529
530 Q_D(const QGeoRectangle);
531
532 return d->topLeft.latitude() - d->bottomRight.latitude();
533}
534
536{
537 if (!isValid() || !coordinate.isValid())
538 return false;
539
540 double left = topLeft.longitude();
541 double right = bottomRight.longitude();
542 double top = topLeft.latitude();
543 double bottom = bottomRight.latitude();
544
545 double lon = coordinate.longitude();
546 double lat = coordinate.latitude();
547
548 if (lat > top)
549 return false;
550 if (lat < bottom)
551 return false;
552
553 if ((lat == 90.0) && (top == 90.0))
554 return true;
555
556 if ((lat == -90.0) && (bottom == -90.0))
557 return true;
558
559 if (left <= right) {
560 if ((lon < left) || (lon > right))
561 return false;
562 } else {
563 if ((lon < left) && (lon > right))
564 return false;
565 }
566
567 return true;
568}
569
571{
572 if (!isValid())
573 return QGeoCoordinate();
574
575 double cLat = (topLeft.latitude() + bottomRight.latitude()) / 2.0;
576 double cLon = (bottomRight.longitude() + topLeft.longitude()) / 2.0;
577
579 cLon = cLon - 180.0;
580
581 cLon = QLocationUtils::wrapLong(cLon);
582 return QGeoCoordinate(cLat, cLon);
583}
584
586{
588}
589
594bool QGeoRectangle::contains(const QGeoRectangle &rectangle) const
595{
596 Q_D(const QGeoRectangle);
597
598 return (d->contains(rectangle.topLeft())
599 && d->contains(rectangle.topRight())
600 && d->contains(rectangle.bottomLeft())
601 && d->contains(rectangle.bottomRight()));
602}
603
611bool QGeoRectangle::intersects(const QGeoRectangle &rectangle) const
612{
613 Q_D(const QGeoRectangle);
614
615 double left1 = d->topLeft.longitude();
616 double right1 = d->bottomRight.longitude();
617 double top1 = d->topLeft.latitude();
618 double bottom1 = d->bottomRight.latitude();
619
620 double left2 = rectangle.d_func()->topLeft.longitude();
621 double right2 = rectangle.d_func()->bottomRight.longitude();
622 double top2 = rectangle.d_func()->topLeft.latitude();
623 double bottom2 = rectangle.d_func()->bottomRight.latitude();
624
625 if (top1 < bottom2)
626 return false;
627
628 if (bottom1 > top2)
629 return false;
630
631 if ((top1 == 90.0) && (top1 == top2))
632 return true;
633
634 if ((bottom1 == -90.0) && (bottom1 == bottom2))
635 return true;
636
637 if (left1 < right1) {
638 if (left2 < right2) {
639 if ((left1 > right2) || (right1 < left2))
640 return false;
641 } else {
642 if ((left1 > right2) && (right1 < left2))
643 return false;
644 }
645 } else {
646 if (left2 < right2) {
647 if ((left2 > right1) && (right2 < left1))
648 return false;
649 } else {
650 // if both wrap then they have to intersect
651 }
652 }
653
654 return true;
655}
656
668void QGeoRectangle::translate(double degreesLatitude, double degreesLongitude)
669{
670 // TODO handle dlat, dlon larger than 360 degrees
671
672 Q_D(QGeoRectangle);
673
674 double tlLat = d->topLeft.latitude();
675 double tlLon = d->topLeft.longitude();
676 double brLat = d->bottomRight.latitude();
677 double brLon = d->bottomRight.longitude();
678
679 if (degreesLatitude >= 0.0)
680 degreesLatitude = qMin(degreesLatitude, 90.0 - tlLat);
681 else
682 degreesLatitude = qMax(degreesLatitude, -90.0 - brLat);
683
684 if ( (tlLon != -180.0) || (brLon != 180.0) ) {
685 tlLon = QLocationUtils::wrapLong(tlLon + degreesLongitude);
686 brLon = QLocationUtils::wrapLong(brLon + degreesLongitude);
687 }
688
689 tlLat += degreesLatitude;
690 brLat += degreesLatitude;
691
692 d->topLeft = QGeoCoordinate(tlLat, tlLon);
693 d->bottomRight = QGeoCoordinate(brLat, brLon);
694}
695
705QGeoRectangle QGeoRectangle::translated(double degreesLatitude, double degreesLongitude) const
706{
707 QGeoRectangle result(*this);
708 result.translate(degreesLatitude, degreesLongitude);
709 return result;
710}
711
718{
719 Q_D(QGeoRectangle);
720 d->extendRectangle(coordinate);
721}
722
733{
734 QGeoRectangle result(*this);
735 if (rectangle.isValid())
736 result |= rectangle;
737 return result;
738}
739
749{
750 if (!isValid() || !coordinate.isValid() || contains(coordinate))
751 return;
752
753 double left = topLeft.longitude();
754 double right = bottomRight.longitude();
755 double top = topLeft.latitude();
756 double bottom = bottomRight.latitude();
757
758 double inputLat = coordinate.latitude();
759 double inputLon = coordinate.longitude();
760
761 top = qMax(top, inputLat);
762 bottom = qMin(bottom, inputLat);
763
764 bool wrap = left > right;
765
766 if (wrap && inputLon > right && inputLon < left) {
767 if (qAbs(left - inputLon) < qAbs(right - inputLon))
768 left = inputLon;
769 else
770 right = inputLon;
771 } else if (!wrap) {
772 if (inputLon < left) {
773 if (360 - (right - inputLon) < left - inputLon)
774 right = inputLon;
775 else
776 left = inputLon;
777 } else if (inputLon > right) {
778 if (360 - (inputLon - left) < inputLon - right)
779 left = inputLon;
780 else
781 right = inputLon;
782 }
783 }
786}
787
810{
811 // If non-intersecting goes for most narrow box
812
813 Q_D(QGeoRectangle);
814
815 double top = qMax(d->topLeft.latitude(), rectangle.d_func()->topLeft.latitude());
816 double bottom = qMin(d->bottomRight.latitude(), rectangle.d_func()->bottomRight.latitude());
817
818 QGeoRectangle candidate(
819 {top, d->topLeft.longitude()},
820 {bottom, rectangle.d_func()->bottomRight.longitude()}
821 );
822 QGeoRectangle otherCandidate(
823 {top, rectangle.d_func()->topLeft.longitude()},
824 {bottom, d->bottomRight.longitude()}
825 );
826 double unwrappedWidth = (candidate.width() < rectangle.width() ? 360 : 0) + candidate.width();
827 double otherUnwrappedWidth = (otherCandidate.width() < width() ? 360 : 0) + otherCandidate.width();
828 if (otherUnwrappedWidth < unwrappedWidth) {
829 candidate = otherCandidate;
830 unwrappedWidth = otherUnwrappedWidth;
831 }
832 if (360 <= unwrappedWidth) {
833 candidate.d_func()->topLeft.setLongitude(-180.0);
834 candidate.d_func()->bottomRight.setLongitude(180.0);
835 }
836
837 candidate = (candidate.width() < width() ? *this : candidate);
838 candidate = (candidate.width() < rectangle.width() ? rectangle : candidate);
839
840 double middle1 = center().longitude();
841 double middle2 = rectangle.center().longitude();
842 if ((middle1 <= middle2 ? 0 : 360) + middle2 - middle1 == 180) {
843 candidate.d_func()->topLeft.setLongitude(-180.0);
844 candidate.d_func()->bottomRight.setLongitude(180.0);
845 }
846
847 *this = candidate;
848 this->d_func()->topLeft.setLatitude(top);
849 this->d_func()->bottomRight.setLatitude(bottom);
850
851 return *this;
852}
853
860{
862 qWarning("Not a rectangle a %d\n", type());
863 return QStringLiteral("QGeoRectangle(not a rectangle)");
864 }
865
866 return QStringLiteral("QGeoRectangle({%1, %2}, {%3, %4})")
867 .arg(topLeft().latitude())
868 .arg(topLeft().longitude())
869 .arg(bottomRight().latitude())
870 .arg(bottomRight().longitude());
871}
872
873/*******************************************************************************
874*******************************************************************************/
875
877: QGeoShapePrivate(QGeoShape::RectangleType)
878{
879}
880
882 const QGeoCoordinate &bottomRight)
883: QGeoShapePrivate(QGeoShape::RectangleType), topLeft(topLeft), bottomRight(bottomRight)
884{
885}
886
888: QGeoShapePrivate(QGeoShape::RectangleType), topLeft(other.topLeft),
889 bottomRight(other.bottomRight)
890{
891}
892
894
896{
897 return new QGeoRectanglePrivate(*this);
898}
899
901{
902 if (!QGeoShapePrivate::operator==(other))
903 return false;
904
905 const QGeoRectanglePrivate &otherBox = static_cast<const QGeoRectanglePrivate &>(other);
906
907 return topLeft == otherBox.topLeft && bottomRight == otherBox.bottomRight;
908}
909
911{
913}
914
916
917#include "moc_qgeorectangle.cpp"
\inmodule QtPositioning
double longitude
This property holds the longitude in decimal degrees.
double latitude
This property holds the latitude in decimal degrees.
void setLatitude(double latitude)
Sets the latitude (in decimal degrees) to latitude.
bool isValid
This property holds the validity of this geo coordinate.
QGeoCoordinate bottomRight
QGeoShapePrivate * clone() const override
QGeoCoordinate topLeft
void extendRectangle(const QGeoCoordinate &coordinate)
Extends the rectangle in the smallest possible way to include coordinate in the shape.
bool isEmpty() const override
QGeoRectangle boundingGeoRectangle() const override
bool operator==(const QGeoShapePrivate &other) const override
size_t hash(size_t seed) const override
bool contains(const QGeoCoordinate &coordinate) const override
bool isValid() const override
QGeoCoordinate center() const override
\inmodule QtPositioning
double height
This property holds the height of this geo rectangle in degrees.
Q_INVOKABLE bool intersects(const QGeoRectangle &rectangle) const
Returns whether the geo rectangle rectangle intersects this geo rectangle.
QGeoCoordinate topLeft
This property holds the top left coordinate of this geo rectangle.
QGeoCoordinate bottomRight
This property holds the bottom right coordinate of this geo rectangle.
void setTopLeft(const QGeoCoordinate &topLeft)
Sets the top left coordinate of this geo rectangle to topLeft.
Q_INVOKABLE QGeoRectangle united(const QGeoRectangle &rectangle) const
Returns the smallest geo rectangle which contains both this geo rectangle and rectangle.
void setBottomRight(const QGeoCoordinate &bottomRight)
Sets the bottom right coordinate of this geo rectangle to bottomRight.
bool contains(const QGeoRectangle &rectangle) const
Returns whether the geo rectangle rectangle is contained within this geo rectangle.
QGeoRectangle & operator=(const QGeoRectangle &other)
Assigns other to this geo rectangle and returns a reference to this geo rectangle.
QGeoCoordinate center
This property holds the center of this geo rectangle.
void setTopRight(const QGeoCoordinate &topRight)
Sets the top right coordinate of this geo rectangle to topRight.
QGeoRectangle()
Constructs a new, invalid geo rectangle.
void setCenter(const QGeoCoordinate &center)
Sets the center of this geo rectangle to center.
Q_INVOKABLE QString toString() const
Returns the geo rectangle properties as a string.
void setWidth(double degreesWidth)
Sets the width of this geo rectangle in degrees to degreesWidth.
void setHeight(double degreesHeight)
Sets the height of this geo rectangle in degrees to degreesHeight.
QGeoRectangle & operator|=(const QGeoRectangle &rectangle)
Returns the smallest geo rectangle which contains both this geo rectangle and rectangle.
~QGeoRectangle()
Destroys this geo rectangle.
Q_INVOKABLE QGeoRectangle translated(double degreesLatitude, double degreesLongitude) const
Returns a copy of this geo rectangle translated by degreesLatitude northwards and degreesLongitude ea...
QGeoCoordinate bottomLeft
This property holds the bottom left coorindate of this geo rectangle.
Q_INVOKABLE void extendRectangle(const QGeoCoordinate &coordinate)
Extends the geo rectangle to also cover the coordinate coordinate.
QGeoCoordinate topRight
This property holds the top right coordinate of this geo rectangle.
double width
This property holds the width of this geo rectangle in degrees.
void setBottomLeft(const QGeoCoordinate &bottomLeft)
Sets the bottom left coordinate of this geo rectangle to bottomLeft.
Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude)
Translates this geo rectangle by degreesLatitude northwards and degreesLongitude eastwards.
\inmodule QtPositioning
Definition qgeoshape.h:17
bool isValid
This property holds the validity of the geo shape.
Definition qgeoshape.h:20
QGeoShape & operator=(const QGeoShape &other)
Assigns other to this geo shape and returns a reference to this geo shape.
QSharedDataPointer< QGeoShapePrivate > d_ptr
Definition qgeoshape.h:61
ShapeType type
This property holds the type of this geo shape.
Definition qgeoshape.h:19
@ RectangleType
Definition qgeoshape.h:32
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
T & first()
Definition qlist.h:628
static double wrapLong(double lng)
const T * constData() const noexcept
Returns a const pointer to the shared data object.
Definition qshareddata.h:51
T * data()
Returns a pointer to the shared data object.
Definition qshareddata.h:47
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
#define qWarning
Definition qlogging.h:162
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1369
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION double qQNaN()
GLint GLsizei GLsizei height
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLint GLsizei width
GLint left
GLint GLint bottom
const GLubyte * c
GLuint64EXT * result
[6]
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
#define QStringLiteral(str)
QSharedPointer< T > other(t)
[5]