8#include "GeoDataLatLonBox.h"
10#include "MarbleDebug.h"
11#include "GeoDataLineString.h"
13#include "GeoDataTypes.h"
20const GeoDataLatLonBox GeoDataLatLonBox::empty = GeoDataLatLonBox();
22class GeoDataLatLonBoxPrivate
25 GeoDataLatLonBoxPrivate()
41bool operator==( GeoDataLatLonBox
const& lhs, GeoDataLatLonBox
const& rhs )
43 return lhs.d->m_west == rhs.d->m_west &&
44 lhs.d->m_east == rhs.d->m_east &&
45 lhs.d->m_north == rhs.d->m_north &&
46 lhs.d->m_south == rhs.d->m_south &&
47 lhs.d->m_rotation == rhs.d->m_rotation;
50bool operator!=( GeoDataLatLonBox
const& lhs, GeoDataLatLonBox
const& rhs )
52 return !( lhs == rhs );
55GeoDataLatLonBox::GeoDataLatLonBox()
57 d( new GeoDataLatLonBoxPrivate )
61GeoDataLatLonBox::GeoDataLatLonBox( qreal north, qreal south, qreal east, qreal west, GeoDataCoordinates::Unit unit )
63 d( new GeoDataLatLonBoxPrivate )
65 setBoundaries( north, south, east, west, unit );
68GeoDataLatLonBox::GeoDataLatLonBox(
const GeoDataLatLonBox & other )
69 : GeoDataObject( other ),
70 d( new GeoDataLatLonBoxPrivate( *other.d ) )
74GeoDataLatLonBox::~GeoDataLatLonBox()
79const char* GeoDataLatLonBox::nodeType()
const
81 return GeoDataTypes::GeoDataLatLonBoxType;
86 if ( unit == GeoDataCoordinates::Degree ) {
87 return d->m_north * RAD2DEG;
96 case GeoDataCoordinates::Radian:
97 d->m_north = GeoDataCoordinates::normalizeLat( north );
99 case GeoDataCoordinates::Degree:
100 d->m_north = GeoDataCoordinates::normalizeLat( north * DEG2RAD );
107 if ( unit == GeoDataCoordinates::Degree ) {
108 return d->m_south * RAD2DEG;
117 case GeoDataCoordinates::Radian:
118 d->m_south = GeoDataCoordinates::normalizeLat( south );
120 case GeoDataCoordinates::Degree:
121 d->m_south = GeoDataCoordinates::normalizeLat( south * DEG2RAD );
128 if ( unit == GeoDataCoordinates::Degree ) {
129 return d->m_east * RAD2DEG;
138 case GeoDataCoordinates::Radian:
139 d->m_east = GeoDataCoordinates::normalizeLon( east );
141 case GeoDataCoordinates::Degree:
142 d->m_east = GeoDataCoordinates::normalizeLon( east * DEG2RAD );
149 if ( unit == GeoDataCoordinates::Degree ) {
150 return d->m_west * RAD2DEG;
159 case GeoDataCoordinates::Radian:
160 d->m_west = GeoDataCoordinates::normalizeLon( west );
162 case GeoDataCoordinates::Degree:
163 d->m_west = GeoDataCoordinates::normalizeLon( west * DEG2RAD );
168void GeoDataLatLonBox::setRotation(
const qreal rotation, GeoDataCoordinates::Unit unit )
172 case GeoDataCoordinates::Radian:
173 d->m_rotation = rotation;
175 case GeoDataCoordinates::Degree:
176 d->m_rotation = rotation * DEG2RAD;
183 if ( unit == GeoDataCoordinates::Degree ) {
184 return d->m_rotation * RAD2DEG;
186 return d->m_rotation;
189void GeoDataLatLonBox::boundaries( qreal &north, qreal &south, qreal &east, qreal &west,
GeoDataCoordinates::Unit unit )
const
193 case GeoDataCoordinates::Radian:
199 case GeoDataCoordinates::Degree:
200 north = d->m_north * RAD2DEG;
201 south = d->m_south * RAD2DEG;
202 east = d->m_east * RAD2DEG;
203 west = d->m_west * RAD2DEG;
208void GeoDataLatLonBox::setBoundaries( qreal north, qreal south, qreal east, qreal west, GeoDataCoordinates::Unit unit )
212 case GeoDataCoordinates::Radian:
213 d->m_north = GeoDataCoordinates::normalizeLat( north );
214 d->m_south = GeoDataCoordinates::normalizeLat( south );
215 d->m_east = GeoDataCoordinates::normalizeLon( east );
216 d->m_west = GeoDataCoordinates::normalizeLon( west );
218 case GeoDataCoordinates::Degree:
219 d->m_north = GeoDataCoordinates::normalizeLat( north * DEG2RAD );
220 d->m_south = GeoDataCoordinates::normalizeLat( south * DEG2RAD );
221 d->m_east = GeoDataCoordinates::normalizeLon( east * DEG2RAD );
222 d->m_west = GeoDataCoordinates::normalizeLon( west * DEG2RAD );
227void GeoDataLatLonBox::scale(qreal verticalFactor, qreal horizontalFactor)
const
230 qreal
const deltaY = 0.5 * height() * verticalFactor;
231 qreal
const deltaX = 0.5 * width() * horizontalFactor;
232 d->m_north = qMin((middle.
latitude() + deltaY),
static_cast<qreal
>(M_PI/2));
233 d->m_south = qMax((middle.
latitude() - deltaY),
static_cast<qreal
>(-M_PI/2));
234 if (deltaX > 180 * DEG2RAD) {
239 d->m_east = GeoDataCoordinates::normalizeLon(middle.
longitude() + deltaX);
240 d->m_west = GeoDataCoordinates::normalizeLon(middle.
longitude() - deltaX);
244GeoDataLatLonBox GeoDataLatLonBox::scaled(qreal verticalFactor, qreal horizontalFactor)
const
247 result.
scale(verticalFactor, horizontalFactor);
253 return GeoDataLatLonBox::width( d->m_east, d->m_west, unit );
258 qreal width = fabs( (qreal)( GeoDataLatLonBox::crossesDateLine(east, west)
259 ? 2 * M_PI - west + east
264 if ( width > 2 * M_PI ) {
268 if ( unit == GeoDataCoordinates::Degree ) {
269 return width * RAD2DEG;
277 return GeoDataLatLonBox::height(d->m_north, d->m_south, unit);
282 qreal height = fabs( (qreal)( south - north ) );
284 if ( unit == GeoDataCoordinates::Degree ) {
285 return height * RAD2DEG;
291bool GeoDataLatLonBox::crossesDateLine()
const
293 return GeoDataLatLonBox::crossesDateLine(d->m_east, d->m_west);
296bool GeoDataLatLonBox::crossesDateLine(qreal east, qreal west)
298 return east < west || ( east == M_PI && west == -M_PI );
306 if( crossesDateLine() )
307 return GeoDataCoordinates( GeoDataCoordinates::normalizeLon( east() + 2 * M_PI - ( east() + 2 * M_PI - west() ) / 2 ) ,
308 north() - ( north() - south() ) / 2 );
311 north() - ( north() - south() ) / 2 );
314bool GeoDataLatLonBox::containsPole(
Pole pole )
const
318 return ( 2 * north() == +M_PI );
320 return ( 2 * south() == -M_PI );
323 return ( 2 * north() == +M_PI
324 || 2 * south() == -M_PI );
327 mDebug() <<
"Invalid pole";
331bool GeoDataLatLonBox::contains(qreal lon, qreal lat)
const
333 if ( lat < d->m_south || lat > d->m_north ) {
338 if ( ( ( lon < d->m_west || lon > d->m_east ) && ( d->m_west < d->m_east ) ) ||
340 ( ( lon < d->m_west && lon > d->m_east ) && ( d->m_west > d->m_east ) ) )
352 return contains(lon, lat);
355bool GeoDataLatLonBox::contains(
const GeoDataLatLonBox &other )
const
359 if ( d->m_north >= other.north() && d->m_south <= other.south() ) {
361 if ( !crossesDateLine() ) {
362 if ( !other.crossesDateLine() ) {
364 if ( d->m_west <= other.west() && d->m_east >= other.east() ) {
375 if ( ( other.west() <= d->m_west && d->m_east <= +M_PI )
376 || ( other.east() >= d->m_east && d->m_west >= -M_PI ) ) {
382 if ( other.crossesDateLine() ) {
384 if ( d->m_west <= other.west() && d->m_east >= other.east() ) {
395 if ( ( d->m_west <= other.west() && other.east() <= +M_PI )
396 || ( d->m_east >= other.east() && other.west() >= -M_PI ) ) {
402 if ( d->m_west == -M_PI && d->m_east == +M_PI ) {
413bool GeoDataLatLonBox::intersects(
const GeoDataLatLonBox &other )
const
415 if ( isEmpty() || other.isEmpty() ) {
422 if ( (d->m_north >= other.d->m_north && d->m_south <= other.d->m_north)
424 || (other.d->m_north >= d->m_north && other.d->m_south <= d->m_north)
426 || (d->m_north >= other.d->m_south && d->m_south <= other.d->m_south)
428 || (other.d->m_north >= d->m_south && other.d->m_south <= d->m_south)) {
430 if ( !crossesDateLine() ) {
431 if ( !other.crossesDateLine() ) {
434 if ( (d->m_east >= other.d->m_east && d->m_west <= other.d->m_east)
436 || (other.d->m_east >= d->m_east && other.d->m_west <= d->m_east)
438 || (d->m_east >= other.d->m_west && d->m_west <= other.d->m_west)
440 || (other.d->m_east >= d->m_west && other.d->m_west <= d->m_west)) {
448 if ( d->m_west <= other.d->m_east || d->m_east >= other.d->m_west) {
454 if ( other.crossesDateLine() ) {
464 if ( other.d->m_west <= d->m_east || other.d->m_east >= d->m_west ) {
493 result.setNorth(qMax( d->m_north, other.
north() ) );
494 result.setSouth( qMin( d->m_south, other.
south() ) );
496 qreal w1 = d->m_west;
497 qreal w2 = other.
west();
498 qreal e1 = d->m_east;
499 qreal e2 = other.
east();
501 bool const idl1 = d->m_east < d->m_west;
502 bool const idl2 = other.d->m_east < other.d->m_west;
520 || ( idl1 ^ idl2 ) ) {
523 result.setEast( qMin( e1, e2 ) );
524 result.setWest( qMax( w1, w2 ) );
528 result.setEast( qMax( e1, e2 ) );
529 result.setWest( qMin( w1, w2 ) );
544 const qreal cosRotation = cos( rotation() );
545 const qreal sinRotation = sin( rotation() );
547 qreal centerLat = center().latitude();
548 qreal centerLon = center().longitude();
549 if (
GeoDataLatLonBox( 0, 0, center().longitude(), west() ).crossesDateLine() ) {
550 if ( !centerLon ) centerLon += M_PI;
551 else centerLon += 2 * M_PI;
556 bool northSet =
false;
557 bool southSet =
false;
558 bool eastSet =
false;
559 bool westSet =
false;
563 const qreal lon = coord.longitude();
564 const qreal lat = coord.latitude();
566 const qreal rotatedLon = ( lon - centerLon ) * cosRotation - ( lat - centerLat ) * sinRotation + centerLon;
567 const qreal rotatedLat = ( lon - centerLon ) * sinRotation + ( lat - centerLat ) * cosRotation + centerLat;
569 if ( !northSet || rotatedLat > box.
north() ) {
571 box.setNorth( rotatedLat );
574 if ( !southSet || rotatedLat < box.
south() ) {
576 box.setSouth( rotatedLat );
579 if ( !westSet || rotatedLon < box.
west() ) {
581 box.setWest( rotatedLon );
584 if ( !eastSet || rotatedLon > box.
east() ) {
586 box.setEast( rotatedLon );
597 GeoDataObject::operator=( other );
603GeoDataLatLonBox GeoDataLatLonBox::operator|(
const GeoDataLatLonBox& other )
const
605 return united( other );
610 *
this = united( other );
617 GeoDataObject::pack( stream );
619 stream << d->m_north << d->m_south << d->m_east << d->m_west << d->m_rotation;
624 GeoDataObject::unpack( stream );
626 stream >> d->m_north >> d->m_south >> d->m_east >> d->m_west >> d->m_rotation;
638 GeoDataCoordinates::normalizeLonLat( lon, lat );
646 if ( lineString.
size() == 1 )
650 bool idlCrossed =
false;
659 int idlCrossState = 0;
660 int idlMaxCrossState = 0;
661 int idlMinCrossState = 0;
664 qreal otherWest = lon;
665 qreal otherEast = lon;
667 qreal previousLon = lon;
669 int currentSign = ( lon < 0 ) ? -1 : +1;
670 int previousSign = currentSign;
675 bool processingLastNode =
false;
677 while( it != itEnd ) {
679 (it)->geoCoordinates( lon, lat );
680 GeoDataCoordinates::normalizeLonLat( lon, lat );
685 }
else if ( lat < south ) {
689 currentSign = ( lon < 0 ) ? -1 : +1;
700 if ( previousSign != currentSign
701 && fabs( previousLon ) + fabs( lon ) > M_PI ) {
704 if ( idlCrossed ==
false ) {
711 if ( previousLon < 0 ) {
713 if ( idlCrossState > idlMaxCrossState ) {
714 idlMaxCrossState = idlCrossState;
719 if ( idlCrossState < idlMinCrossState ) {
720 idlMinCrossState = idlCrossState;
725 if ( idlCrossState == 0 ) {
726 if ( lon > east ) east = lon;
727 if ( lon < west ) west = lon;
730 if ( lon > otherEast ) otherEast = lon;
731 if ( lon < otherWest ) otherWest = lon;
735 previousSign = currentSign;
737 if ( processingLastNode ) {
742 if( lineString.
isClosed() && it == itEnd ) {
744 processingLastNode =
true;
749 if ( idlMinCrossState < 0 ) {
752 if ( idlMaxCrossState > 0 ) {
755 if ( ( idlMinCrossState < 0 && idlMaxCrossState > 0 )
756 || idlMinCrossState < -1 || idlMaxCrossState > 1
772bool GeoDataLatLonBox::isNull()
const
774 return d->m_north == d->m_south && d->m_east == d->m_west;
777bool GeoDataLatLonBox::isEmpty()
const
779 return *
this == empty;
790 double latDelta = lhs.
height() * factor;
792 if (fabs(lhs.
north() - rhs.
north()) > latDelta) equal =
false;
793 if (fabs(lhs.
south() - rhs.
south()) > latDelta) equal =
false;
798 double lonDelta = lhs.
width() * factor;
800 double lhsEast = lhs.
east();
801 double rhsEast = rhs.
east();
803 if (!GeoDataLatLonBox::crossesDateLine(lhsEast, rhsEast)) {
804 if (fabs(lhsEast - rhsEast) > lonDelta) equal =
false;
807 if (lhsEast < 0 && rhsEast > 0) {
809 if (fabs(lhsEast - rhsEast) > lonDelta) equal =
false;
811 if (lhsEast > 0 && rhsEast < 0) {
813 if (fabs(lhsEast - rhsEast) > lonDelta) equal =
false;
817 double lhsWest = lhs.
west();
818 double rhsWest = rhs.
west();
820 if (!GeoDataLatLonBox::crossesDateLine(lhsWest, rhsWest)) {
821 if (fabs(lhsWest - rhsWest) > lonDelta) equal =
false;
824 if (lhsWest < 0 && rhsWest > 0) {
826 if (fabs(lhsWest - rhsWest) > lonDelta) equal =
false;
828 if (lhsWest > 0 && rhsWest < 0) {
830 if (fabs(lhsWest - rhsWest) > lonDelta) equal =
false;
838void GeoDataLatLonBox::clear()
A 3d point representation.
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
Unit
enum used constructor to specify the units used
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
void geoCoordinates(qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit) const
use this function to get the longitude and latitude with one call - use the unit parameter to switch ...
A class that defines a 2D bounding box for geographic data.
void scale(qreal verticalFactor, qreal horizontalFactor) const
Changes the differences between the boundaries and the center by the given factor,...
qreal north(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the northern boundary of the bounding box.
qreal east(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the eastern boundary of the bounding box.
qreal height(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the height of the latitude interval.
virtual bool isEmpty() const
Indicates whether the bounding box is not initialised (and contains nothing).
qreal width(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the width of the longitude interval.
qreal west(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the western boundary of the bounding box.
qreal south(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
Get the southern boundary of the bounding box.
virtual GeoDataCoordinates center() const
returns the center of this box
A LineString that allows to store a contiguous set of line segments.
virtual bool isClosed() const
Returns whether a LineString is a closed polygon.
bool isEmpty() const
Returns whether the LineString has no nodes at all.
QVector< GeoDataCoordinates >::ConstIterator constEnd() const
Returns a const iterator that points to the end of the LineString.
GeoDataCoordinates & first()
Returns a reference to the first node in the LineString. This method detaches the returned coordinate...
int size() const
Returns the number of nodes in a LineString.
QVector< GeoDataCoordinates >::ConstIterator constBegin() const
Returns a const iterator that points to the begin of the LineString.
Binds a QML item to a specific geodetic location in screen coordinates.
@ SouthPole
Only South Pole.
@ NorthPole
Only North Pole.
void append(QList< T > &&value)
void reserve(qsizetype size)
bool operator==(const QGraphicsApiFilter &reference, const QGraphicsApiFilter &sample)
bool operator!=(const QGraphicsApiFilter &reference, const QGraphicsApiFilter &sample)