8#include <QtGui/QMatrix4x4>
9#include <QtPositioning/QGeoPolygon>
10#include <QtPositioning/QGeoRectangle>
12#include <QtPositioning/private/qwebmercator_p.h>
13#include <QtPositioning/private/qlocationutils_p.h>
14#include <QtPositioning/private/qclipperutils_p.h>
19 static const double defaultTileSize = 256.0;
20 static const QDoubleVector3D xyNormal(0.0, 0.0, 1.0);
21 static const QGeoProjectionWebMercator::Plane xyPlane(QDoubleVector3D(0,0,0), QDoubleVector3D(0,0,1));
22 static const QList<QDoubleVector2D> mercatorGeometry = {
23 QDoubleVector2D(-1.0,0.0),
24 QDoubleVector2D( 2.0,0.0),
25 QDoubleVector2D( 2.0,1.0),
26 QDoubleVector2D(-1.0,1.0) };
31 return QMatrix4x4(m(0,0), m(0,1), m(0,2), m(0,3),
32 m(1,0), m(1,1), m(1,2), m(1,3),
33 m(2,0), m(2,1), m(2,2), m(2,3),
34 m(3,0), m(3,1), m(3,2), m(3,3));
39 QRectF va = visibleArea;
41 va = QRectF(0, 0, screenSize.width(), screenSize.height());
43 QRectF screen = QRectF(QPointF(0,0),screenSize);
44 QPointF vaCenter = va.center();
46 QPointF screenCenter = screen.center();
47 QPointF diff = screenCenter - vaCenter;
54 QPointF diff = centerOffset(screenSize, visibleArea);
55 qreal xdiffpct = diff.x() / qMax<
double>(screenSize.width() - 1, 1);
56 qreal ydiffpct = diff.y() / qMax<
double>(screenSize.height() - 1, 1);
58 return QPointF(-xdiffpct, -ydiffpct);
63QGeoProjection::QGeoProjection()
68QGeoProjection::~QGeoProjection()
73QGeoCoordinate QGeoProjection::anchorCoordinateToPoint(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint)
const
76 Q_UNUSED(anchorPoint);
77 return QGeoCoordinate();
80QGeoShape QGeoProjection::visibleRegion()
const
85bool QGeoProjection::setBearing(qreal bearing,
const QGeoCoordinate &coordinate)
92void QGeoProjection::setItemToWindowTransform(
const QTransform &itemToWindowTransform)
94 if (m_itemToWindowTransform == itemToWindowTransform)
96 m_qsgTransformDirty =
true;
97 m_itemToWindowTransform = itemToWindowTransform;
100QTransform QGeoProjection::itemToWindowTransform()
const
102 return m_itemToWindowTransform;
107
108
110QGeoCoordinate QGeoProjectionWebMercator::anchorCoordinateToPoint(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint)
const
113 QDoubleVector2D centerProj = geoToWrappedMapProjection(cameraData().center());
114 QDoubleVector2D coordProj = geoToWrappedMapProjection(coordinate);
116 QDoubleVector2D anchorProj = itemPositionToWrappedMapProjection(QDoubleVector2D(anchorPoint));
118 return wrappedMapProjectionToGeo(centerProj + coordProj - anchorProj);
121bool QGeoProjectionWebMercator::setBearing(qreal bearing,
const QGeoCoordinate &coordinate)
123 const QDoubleVector2D coordWrapped = geoToWrappedMapProjection(coordinate);
124 if (!isProjectable(coordWrapped))
126 const QPointF rotationPoint = wrappedMapProjectionToItemPosition(coordWrapped).toPointF();
128 QGeoCameraData camera = cameraData();
130 camera.setBearing(bearing);
131 setCameraData(camera);
132 camera = cameraData();
135 const QGeoCoordinate center = anchorCoordinateToPoint(coordinate, rotationPoint);
136 camera.setCenter(center);
137 setCameraData(camera);
141QGeoProjectionWebMercator::QGeoProjectionWebMercator()
145 m_cameraCenterXMercator(0),
146 m_cameraCenterYMercator(0),
149 m_1_viewportWidth(0),
150 m_1_viewportHeight(0),
151 m_sideLengthPixels(256),
157 m_minimumUnprojectableY(0.0),
158 m_verticalEstateToSkip(0.0),
159 m_visibleRegionDirty(
false)
163QGeoProjectionWebMercator::~QGeoProjectionWebMercator()
170double QGeoProjectionWebMercator::minimumZoom()
const
172 return m_minimumZoom;
175QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation()
const
177 return toMatrix4x4(m_transformation);
180QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation_centered()
const
182 return toMatrix4x4(m_transformation0);
185const QMatrix4x4 &QGeoProjectionWebMercator::qsgTransform()
const
187 if (m_qsgTransformDirty) {
188 m_qsgTransformDirty =
false;
189 m_qsgTransform = QMatrix4x4(m_itemToWindowTransform) * toMatrix4x4(m_transformation0);
192 return m_qsgTransform;
195QDoubleVector3D QGeoProjectionWebMercator::centerMercator()
const
197 return geoToMapProjection(m_cameraData.center()).toVector3D();
206double QGeoProjectionWebMercator::maximumCenterLatitudeAtZoom(
const QGeoCameraData &cameraData)
const
208 double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
211 int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
212 QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
213 double hpct = offsetPct.y() / qMax<
double>(m_viewportHeight - 1, 1);
216 double mercatorTopmost = (clampedWindowHeight * (0.5 - hpct)) / mapEdgeSize ;
217 QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost));
218 return topMost.latitude();
221double QGeoProjectionWebMercator::minimumCenterLatitudeAtZoom(
const QGeoCameraData &cameraData)
const
223 double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
226 int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
227 QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
228 double hpct = offsetPct.y() / qMax<
double>(m_viewportHeight - 1, 1);
231 double mercatorTopmost = (clampedWindowHeight * (0.5 + hpct)) / mapEdgeSize ;
232 QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost));
233 return -topMost.latitude();
236void QGeoProjectionWebMercator::setVisibleArea(
const QRectF &visibleArea)
238 m_visibleArea = visibleArea;
242double QGeoProjectionWebMercator::mapWidth()
const
244 return m_mapEdgeSize;
247double QGeoProjectionWebMercator::mapHeight()
const
249 return m_mapEdgeSize;
252void QGeoProjectionWebMercator::setViewportSize(
const QSize &size)
254 if (
int(m_viewportWidth) == size.width() &&
int(m_viewportHeight) == size.height())
257 m_viewportWidth = size.width();
258 m_viewportHeight = size.height();
259 m_1_viewportWidth = 1.0 / m_viewportWidth;
260 m_1_viewportHeight = 1.0 / m_viewportHeight;
261 m_minimumZoom = std::log(qMax(m_viewportWidth, m_viewportHeight) / defaultTileSize) / std::log(2.0);
265void QGeoProjectionWebMercator::setCameraData(
const QGeoCameraData &cameraData,
bool force)
267 if (m_cameraData == cameraData && !force)
270 m_cameraData = cameraData;
271 m_mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
275QDoubleVector2D QGeoProjectionWebMercator::geoToMapProjection(
const QGeoCoordinate &coordinate)
const
277 return QWebMercator::coordToMercator(coordinate);
280QGeoCoordinate QGeoProjectionWebMercator::mapProjectionToGeo(
const QDoubleVector2D &projection)
const
282 return QWebMercator::mercatorToCoord(projection);
285int QGeoProjectionWebMercator::projectionWrapFactor(
const QDoubleVector2D &projection)
const
287 const double &x = projection.x();
288 if (m_cameraCenterXMercator < 0.5) {
289 if (x - m_cameraCenterXMercator > 0.5 )
291 }
else if (m_cameraCenterXMercator > 0.5) {
292 if (x - m_cameraCenterXMercator < -0.5 )
299QDoubleVector2D QGeoProjectionWebMercator::wrapMapProjection(
const QDoubleVector2D &projection)
const
301 return QDoubleVector2D(projection.x() +
double(projectionWrapFactor(projection)), projection.y());
304QDoubleVector2D QGeoProjectionWebMercator::unwrapMapProjection(
const QDoubleVector2D &wrappedProjection)
const
306 double x = wrappedProjection.x();
308 return QDoubleVector2D(x - 1.0, wrappedProjection.y());
310 return QDoubleVector2D(x + 1.0, wrappedProjection.y());
311 return wrappedProjection;
314QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(
const QDoubleVector2D &wrappedProjection)
const
316 return (m_transformation * wrappedProjection).toVector2D();
319QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(
const QDoubleVector2D &itemPosition)
const
321 const QPointF centerOff = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
322 QDoubleVector2D pos = itemPosition + QDoubleVector2D(centerOff);
323 pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
325 pos -= QDoubleVector2D(1.0,1.0);
328 QDoubleVector2D res = viewportToWrappedMapProjection(pos, s);
334 pos.setY(m_minimumUnprojectableY);
335 pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
337 pos -= QDoubleVector2D(1.0,1.0);
338 res = viewportToWrappedMapProjection(pos, s);
345QGeoCoordinate QGeoProjectionWebMercator::itemPositionToCoordinate(
const QDoubleVector2D &pos,
bool clipToViewport)
const
347 if (qIsNaN(pos.x()) || qIsNaN(pos.y()))
348 return QGeoCoordinate();
350 if (clipToViewport) {
351 int w = m_viewportWidth;
352 int h = m_viewportHeight;
354 if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
355 return QGeoCoordinate();
358 QDoubleVector2D wrappedMapProjection = itemPositionToWrappedMapProjection(pos);
360 if (!isProjectable(wrappedMapProjection))
361 return QGeoCoordinate();
362 return mapProjectionToGeo(unwrapMapProjection(wrappedMapProjection));
365QDoubleVector2D QGeoProjectionWebMercator::coordinateToItemPosition(
const QGeoCoordinate &coordinate,
bool clipToViewport)
const
367 if (!coordinate.isValid())
368 return QDoubleVector2D(qQNaN(), qQNaN());
370 QDoubleVector2D wrappedProjection = wrapMapProjection(geoToMapProjection(coordinate));
371 if (!isProjectable(wrappedProjection))
372 return QDoubleVector2D(qQNaN(), qQNaN());
374 QDoubleVector2D pos = wrappedMapProjectionToItemPosition(wrappedProjection);
376 if (clipToViewport) {
377 int w = m_viewportWidth;
378 int h = m_viewportHeight;
381 if ((x < -0.5) || (x > w + 0.5) || (y < -0.5) || (y > h + 0.5) || qIsNaN(x) || qIsNaN(y))
382 return QDoubleVector2D(qQNaN(), qQNaN());
387QDoubleVector2D QGeoProjectionWebMercator::geoToWrappedMapProjection(
const QGeoCoordinate &coordinate)
const
389 return wrapMapProjection(geoToMapProjection(coordinate));
392QGeoCoordinate QGeoProjectionWebMercator::wrappedMapProjectionToGeo(
const QDoubleVector2D &wrappedProjection)
const
394 return mapProjectionToGeo(unwrapMapProjection(wrappedProjection));
397QMatrix4x4 QGeoProjectionWebMercator::quickItemTransformation(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint, qreal zoomLevel)
const
399 const QDoubleVector2D coordWrapped = geoToWrappedMapProjection(coordinate);
400 double scale = std::pow(0.5, zoomLevel - m_cameraData.zoomLevel());
401 const QDoubleVector2D anchorScaled = QDoubleVector2D(anchorPoint.x(), anchorPoint.y()) * scale;
402 const QDoubleVector2D anchorMercator = anchorScaled / mapWidth();
404 const QDoubleVector2D coordAnchored = coordWrapped - anchorMercator;
405 const QDoubleVector2D coordAnchoredScaled = coordAnchored * m_sideLengthPixels;
406 QDoubleMatrix4x4 matTranslateScale;
407 matTranslateScale.translate(coordAnchoredScaled.x(), coordAnchoredScaled.y(), 0.0);
409 scale = std::pow(0.5, (zoomLevel - std::floor(zoomLevel)) +
410 (std::floor(zoomLevel) - std::floor(m_cameraData.zoomLevel())));
411 matTranslateScale.scale(scale);
414
415
416
417
418
419
420
421
422
424 return toMatrix4x4(m_quickItemTransformation * matTranslateScale);
427bool QGeoProjectionWebMercator::isProjectable(
const QDoubleVector2D &wrappedProjection)
const
429 if (m_cameraData.tilt() == 0.0)
432 QDoubleVector3D pos = wrappedProjection * m_sideLengthPixels;
434 QDoubleVector3D p = m_centerNearPlane - pos;
435 double dot = QDoubleVector3D::dotProduct(p , m_viewNormalized);
442QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleGeometry()
const
444 if (m_visibleRegionDirty)
445 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
446 return m_visibleRegion;
449QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleGeometryExpanded()
const
451 if (m_visibleRegionDirty)
452 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
453 return m_visibleRegionExpanded;
456QList<QDoubleVector2D> QGeoProjectionWebMercator::projectableGeometry()
const
458 if (m_visibleRegionDirty)
459 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
460 return m_projectableRegion;
463QGeoShape QGeoProjectionWebMercator::visibleRegion()
const
465 const QList<QDoubleVector2D> &visibleRegion = visibleGeometry();
467 for (qsizetype i = 0; i < visibleRegion.size(); ++i) {
468 const QDoubleVector2D &c = visibleRegion.at(i);
470 if (i && qAbs(visibleRegion.at(i - 1).x() - c.x()) >= 0.5) {
471 QDoubleVector2D extraPoint = (visibleRegion.at(i - 1) + c) * 0.5;
472 poly.addCoordinate(wrappedMapProjectionToGeo(extraPoint));
474 poly.addCoordinate(wrappedMapProjectionToGeo(c));
476 if (visibleRegion.size() >= 2 && qAbs(visibleRegion.last().x() - visibleRegion.first().x()) >= 0.5) {
477 QDoubleVector2D extraPoint = (visibleRegion.last() + visibleRegion.first()) * 0.5;
478 poly.addCoordinate(wrappedMapProjectionToGeo(extraPoint));
484QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(
const QDoubleVector2D &itemPosition)
const
487 return viewportToWrappedMapProjection(itemPosition, s);
491
492
493QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(
const QDoubleVector2D &itemPosition,
double &s)
const
495 QDoubleVector2D pos = itemPosition;
496 pos *= QDoubleVector2D(m_halfWidth, m_halfHeight);
499 QDoubleVector3D p = m_centerNearPlane;
501 p += m_side * pos.x();
504 QDoubleVector3D ray = m_eye - p;
507 return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLengthPixels).toVector2D();
511
512
513QPair<QGeoCoordinate, qreal> QGeoProjectionWebMercator::fitViewportToGeoRectangle(
const QGeoRectangle &rectangle,
514 const QMargins &m)
const
516 QPair<QGeoCoordinate, qreal> res;
517 res.second = qQNaN();
518 if (m_viewportWidth <= m.left() + m.right() || m_viewportHeight <= m.top() + m.bottom())
521 QDoubleVector2D topLeftPoint = geoToMapProjection(rectangle.topLeft());
522 QDoubleVector2D bottomRightPoint = geoToMapProjection(rectangle.bottomRight());
523 if (bottomRightPoint.x() < topLeftPoint.x())
524 bottomRightPoint.setX(bottomRightPoint.x() + 1.0);
527 QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
528 center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
529 res.first = mapProjectionToGeo(center);
532 double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * mapWidth();
533 double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * mapHeight();
535 if (bboxHeight == 0.0 && bboxWidth == 0.0)
538 double zoomRatio = qMax(bboxWidth / (m_viewportWidth - m.left() - m.right()),
539 bboxHeight / (m_viewportHeight - m.top() - m.bottom()));
540 zoomRatio = std::log(zoomRatio) / std::log(2.0);
541 res.second = m_cameraData.zoomLevel() - zoomRatio;
546QGeoProjection::ProjectionGroup QGeoProjectionWebMercator::projectionGroup()
const
548 return QGeoProjection::ProjectionCylindrical;
551QGeoProjection::Datum QGeoProjectionWebMercator::datum()
const
553 return QGeoProjection::DatumWGS84;
556QGeoProjection::ProjectionType QGeoProjectionWebMercator::projectionType()
const
558 return QGeoProjection::ProjectionWebMercator;
561void QGeoProjectionWebMercator::setupCamera()
563 m_qsgTransformDirty =
true;
564 m_centerMercator = geoToMapProjection(m_cameraData.center());
565 m_cameraCenterXMercator = m_centerMercator.x();
566 m_cameraCenterYMercator = m_centerMercator.y();
568 int intZoomLevel =
static_cast<
int>(std::floor(m_cameraData.zoomLevel()));
569 m_sideLengthPixels = (1 << intZoomLevel) * defaultTileSize;
570 m_center = m_centerMercator * m_sideLengthPixels;
572 m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
574 double f = m_viewportHeight;
575 double z = std::pow(2.0, m_cameraData.zoomLevel() - intZoomLevel) * defaultTileSize;
576 double altitude = f / (2.0 * z);
578 double z_mercator = std::pow(2.0, m_cameraData.zoomLevel()) * defaultTileSize;
579 double altitude_mercator = f / (2.0 * z_mercator);
583 m_eye.setZ(altitude * defaultTileSize / m_aperture);
586 m_eyeMercator = m_centerMercator;
587 m_eyeMercator.setZ(altitude_mercator / m_aperture);
588 m_eyeMercator0 = QDoubleVector3D(0,0,0);
589 m_eyeMercator0.setZ(altitude_mercator / m_aperture);
590 QDoubleVector3D eye0(0,0,0);
591 eye0.setZ(altitude * defaultTileSize / m_aperture);
593 m_view = m_eye - m_center;
594 QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0));
595 m_up = QDoubleVector3D::normal(side, m_view);
598 m_viewMercator = m_eyeMercator - m_centerMercator;
599 QDoubleVector3D sideMercator = QDoubleVector3D::normal(m_viewMercator, QDoubleVector3D(0.0, 1.0, 0.0));
600 m_upMercator = QDoubleVector3D::normal(sideMercator, m_viewMercator);
602 if (m_cameraData.bearing() > 0.0) {
603 QDoubleMatrix4x4 mBearing;
604 mBearing.rotate(m_cameraData.bearing(), m_view);
605 m_up = mBearing * m_up;
608 QDoubleMatrix4x4 mBearingMercator;
609 mBearingMercator.rotate(m_cameraData.bearing(), m_viewMercator);
610 m_upMercator = mBearingMercator * m_upMercator;
613 m_side = QDoubleVector3D::normal(m_up, m_view);
614 m_sideMercator = QDoubleVector3D::normal(m_upMercator, m_viewMercator);
616 if (m_cameraData.tilt() > 0.0) {
617 QDoubleMatrix4x4 mTilt;
618 mTilt.rotate(-m_cameraData.tilt(), m_side);
619 m_eye = mTilt * m_view + m_center;
620 eye0 = mTilt * m_view;
623 QDoubleMatrix4x4 mTiltMercator;
624 mTiltMercator.rotate(-m_cameraData.tilt(), m_sideMercator);
625 m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator;
626 m_eyeMercator0 = mTiltMercator * m_viewMercator;
629 m_view = m_eye - m_center;
630 m_viewNormalized = m_view.normalized();
631 m_up = QDoubleVector3D::normal(m_view, m_side);
643 m_farPlane = (altitude + 2097152.0) * defaultTileSize;
645 m_viewMercator = m_eyeMercator - m_centerMercator;
646 m_upMercator = QDoubleVector3D::normal(m_viewMercator, m_sideMercator);
647 m_nearPlaneMercator = 0.000002;
650 double aspectRatio = 1.0 * m_viewportWidth / m_viewportHeight;
652 m_halfWidth = m_aperture * aspectRatio;
653 m_halfHeight = m_aperture;
655 double verticalHalfFOV = QLocationUtils::degrees(atan(m_aperture));
657 m_cameraMatrix.setToIdentity();
658 m_cameraMatrix.lookAt(m_eye, m_center, m_up);
659 m_cameraMatrix0.setToIdentity();
660 m_cameraMatrix0.lookAt(eye0, QDoubleVector3D(0,0,0), m_up);
662 QDoubleMatrix4x4 projectionMatrix;
663 projectionMatrix.frustum(-m_halfWidth, m_halfWidth, -m_halfHeight, m_halfHeight, m_nearPlane, m_farPlane);
666
667
668
669
670
671
672
673
675 QPointF offsetPct = marginsOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
676 QDoubleMatrix4x4 matScreenTransformation;
677 matScreenTransformation.scale(0.5 * m_viewportWidth, 0.5 * m_viewportHeight, 1.0);
678 matScreenTransformation(0,3) = (0.5 + offsetPct.x()) * m_viewportWidth;
679 matScreenTransformation(1,3) = (0.5 + offsetPct.y()) * m_viewportHeight;
681 m_transformation = matScreenTransformation * projectionMatrix * m_cameraMatrix;
682 m_quickItemTransformation = m_transformation;
683 m_transformation.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
685 m_transformation0 = matScreenTransformation * projectionMatrix * m_cameraMatrix0;
686 m_transformation0.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
688 m_centerNearPlane = m_eye - m_viewNormalized;
689 m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator;
695 const double upperBoundEpsilon = 1.0 / std::pow(10, 1.0 + m_cameraData.zoomLevel() / 5.0);
696 const double elevationUpperBound = 90.0 - upperBoundEpsilon;
697 const double maxRayElevation = qMin(elevationUpperBound - m_cameraData.tilt(), verticalHalfFOV);
698 double maxHalfAperture = 0;
699 m_verticalEstateToSkip = 0;
700 if (maxRayElevation < verticalHalfFOV) {
701 maxHalfAperture = tan(QLocationUtils::radians(maxRayElevation));
702 m_verticalEstateToSkip = 1.0 - maxHalfAperture / m_aperture;
705 m_minimumUnprojectableY = m_verticalEstateToSkip * 0.5 * m_viewportHeight;
706 m_visibleRegionDirty =
true;
709void QGeoProjectionWebMercator::updateVisibleRegion()
711 m_visibleRegionDirty =
false;
713 double viewportHalfWidth = (!m_visibleArea.isEmpty()) ? m_visibleArea.width() / m_viewportWidth : 1.0;
714 double viewportHalfHeight = (!m_visibleArea.isEmpty()) ? m_visibleArea.height() / m_viewportHeight : 1.0;
716 double top = qMax<
double>(-viewportHalfHeight, -1 + m_verticalEstateToSkip);
717 double bottom = viewportHalfHeight;
718 double left = -viewportHalfWidth;
719 double right = viewportHalfWidth;
721 QDoubleVector2D tl = viewportToWrappedMapProjection(QDoubleVector2D(left, top ));
722 QDoubleVector2D tr = viewportToWrappedMapProjection(QDoubleVector2D(right, top ));
723 QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(left, bottom ));
724 QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D(right, bottom ));
727 double mapLeftLongitude = QLocationUtils::mapLeftLongitude(m_cameraData.center().longitude());
728 double mapRightLongitude = QLocationUtils::mapRightLongitude(m_cameraData.center().longitude());
729 double leftX = geoToWrappedMapProjection(QGeoCoordinate(0, mapLeftLongitude)).x();
730 double rightX = geoToWrappedMapProjection(QGeoCoordinate(0, mapRightLongitude)).x();
732 QList<QDoubleVector2D> mapRect;
733 mapRect.push_back(QDoubleVector2D(leftX, 1.0));
734 mapRect.push_back(QDoubleVector2D(rightX, 1.0));
735 mapRect.push_back(QDoubleVector2D(rightX, 0.0));
736 mapRect.push_back(QDoubleVector2D(leftX, 0.0));
738 QList<QDoubleVector2D> viewportRect;
739 viewportRect.push_back(bl);
740 viewportRect.push_back(br);
741 viewportRect.push_back(tr);
742 viewportRect.push_back(tl);
744 QClipperUtils clipper;
745 clipper.clearClipper();
746 clipper.addSubjectPath(mapRect,
true);
747 clipper.addClipPolygon(viewportRect);
749 const auto res = clipper.execute(QClipperUtils::Intersection);
750 m_visibleRegion.clear();
752 m_visibleRegion = res[0];
754 m_projectableRegion.clear();
757 mapRect.push_back(QDoubleVector2D(-1.0, 1.0));
758 mapRect.push_back(QDoubleVector2D( 2.0, 1.0));
759 mapRect.push_back(QDoubleVector2D( 2.0, 0.0));
760 mapRect.push_back(QDoubleVector2D(-1.0, 0.0));
761 if (m_cameraData.tilt() == 0) {
762 m_projectableRegion = mapRect;
764 QGeoProjectionWebMercator::Plane nearPlane(m_centerNearPlaneMercator, m_viewNormalized);
765 Line2D nearPlaneXYIntersection = nearPlane.planeXYIntersection();
766 double squareHalfSide = qMax(5.0, nearPlaneXYIntersection.m_point.length());
767 QDoubleVector2D viewDirectionProjected = -m_viewNormalized.toVector2D().normalized();
770 QDoubleVector2D tl = nearPlaneXYIntersection.m_point
771 - squareHalfSide * nearPlaneXYIntersection.m_direction
772 + 2 * squareHalfSide * viewDirectionProjected;
773 QDoubleVector2D tr = nearPlaneXYIntersection.m_point
774 + squareHalfSide * nearPlaneXYIntersection.m_direction
775 + 2 * squareHalfSide * viewDirectionProjected;
776 QDoubleVector2D bl = nearPlaneXYIntersection.m_point
777 - squareHalfSide * nearPlaneXYIntersection.m_direction;
778 QDoubleVector2D br = nearPlaneXYIntersection.m_point
779 + squareHalfSide * nearPlaneXYIntersection.m_direction;
781 QList<QDoubleVector2D> projectableRect;
782 projectableRect.push_back(bl);
783 projectableRect.push_back(br);
784 projectableRect.push_back(tr);
785 projectableRect.push_back(tl);
788 QClipperUtils clipperProjectable;
789 clipperProjectable.clearClipper();
790 clipperProjectable.addSubjectPath(mapRect,
true);
791 clipperProjectable.addClipPolygon(projectableRect);
793 const auto resProjectable = clipperProjectable.execute(QClipperUtils::Intersection);
794 if (resProjectable.size())
795 m_projectableRegion = resProjectable[0];
797 m_projectableRegion = viewportRect;
801 QDoubleVector2D centroid;
802 for (
const QDoubleVector2D &v: std::as_const(m_visibleRegion))
804 centroid /= m_visibleRegion.size();
806 m_visibleRegionExpanded.clear();
807 for (
const QDoubleVector2D &v: std::as_const(m_visibleRegion)) {
808 const QDoubleVector2D vc = v - centroid;
809 m_visibleRegionExpanded.push_back(centroid + vc * 1.2);
814QGeoCameraData QGeoProjectionWebMercator::cameraData()
const
820
821
822
823
825QGeoProjectionWebMercator::Line2D::Line2D()
830QGeoProjectionWebMercator::Line2D::Line2D(
const QDoubleVector2D &linePoint,
const QDoubleVector2D &lineDirection)
831 : m_point(linePoint), m_direction(lineDirection.normalized())
836bool QGeoProjectionWebMercator::Line2D::isValid()
const
838 return (m_direction.length() > 0.5);
842
843
844
845
847QGeoProjectionWebMercator::Plane::Plane()
852QGeoProjectionWebMercator::Plane::Plane(
const QDoubleVector3D &planePoint,
const QDoubleVector3D &planeNormal)
853 : m_point(planePoint), m_normal(planeNormal.normalized()) { }
855QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(
const QDoubleVector3D &linePoint,
const QDoubleVector3D &lineDirection)
const
858 return lineIntersection(linePoint, lineDirection, s);
861QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(
const QDoubleVector3D &linePoint,
const QDoubleVector3D &lineDirection,
double &s)
const
863 QDoubleVector3D w = linePoint - m_point;
865 s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection);
866 return linePoint + lineDirection * s;
869QGeoProjectionWebMercator::Line2D QGeoProjectionWebMercator::Plane::planeXYIntersection()
const
872 QDoubleVector3D lineDirection = QDoubleVector3D::crossProduct(m_normal, xyNormal);
873 lineDirection.setZ(0.0);
874 lineDirection.normalize();
878 QDoubleVector3D directionToXY = QDoubleVector3D::crossProduct(m_normal, lineDirection);
879 QDoubleVector3D p = xyPlane.lineIntersection(m_point, directionToXY);
880 return Line2D(p.toVector2D(), lineDirection.toVector2D());
883bool QGeoProjectionWebMercator::Plane::isValid()
const
885 return (m_normal.length() > 0.5);
static QPointF centerOffset(const QSizeF &screenSize, const QRectF &visibleArea)
static QPointF marginsOffset(const QSizeF &screenSize, const QRectF &visibleArea)
static QMatrix4x4 toMatrix4x4(const QDoubleMatrix4x4 &m)