7#include <QtGui/QMatrix4x4>
8#include <QtPositioning/QGeoPolygon>
9#include <QtPositioning/QGeoRectangle>
11#include <QtPositioning/private/qwebmercator_p.h>
12#include <QtPositioning/private/qlocationutils_p.h>
13#include <QtPositioning/private/qclipperutils_p.h>
18 static const double defaultTileSize = 256.0;
19 static const QDoubleVector3D xyNormal(0.0, 0.0, 1.0);
20 static const QGeoProjectionWebMercator::Plane xyPlane(QDoubleVector3D(0,0,0), QDoubleVector3D(0,0,1));
21 static const QList<QDoubleVector2D> mercatorGeometry = {
22 QDoubleVector2D(-1.0,0.0),
23 QDoubleVector2D( 2.0,0.0),
24 QDoubleVector2D( 2.0,1.0),
25 QDoubleVector2D(-1.0,1.0) };
30 return QMatrix4x4(m(0,0), m(0,1), m(0,2), m(0,3),
31 m(1,0), m(1,1), m(1,2), m(1,3),
32 m(2,0), m(2,1), m(2,2), m(2,3),
33 m(3,0), m(3,1), m(3,2), m(3,3));
38 QRectF va = visibleArea;
40 va = QRectF(0, 0, screenSize.width(), screenSize.height());
42 QRectF screen = QRectF(QPointF(0,0),screenSize);
43 QPointF vaCenter = va.center();
45 QPointF screenCenter = screen.center();
46 QPointF diff = screenCenter - vaCenter;
53 QPointF diff = centerOffset(screenSize, visibleArea);
54 qreal xdiffpct = diff.x() / qMax<
double>(screenSize.width() - 1, 1);
55 qreal ydiffpct = diff.y() / qMax<
double>(screenSize.height() - 1, 1);
57 return QPointF(-xdiffpct, -ydiffpct);
62QGeoProjection::QGeoProjection()
67QGeoProjection::~QGeoProjection()
72QGeoCoordinate QGeoProjection::anchorCoordinateToPoint(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint)
const
75 Q_UNUSED(anchorPoint);
76 return QGeoCoordinate();
79QGeoShape QGeoProjection::visibleRegion()
const
84bool QGeoProjection::setBearing(qreal bearing,
const QGeoCoordinate &coordinate)
91void QGeoProjection::setItemToWindowTransform(
const QTransform &itemToWindowTransform)
93 if (m_itemToWindowTransform == itemToWindowTransform)
95 m_qsgTransformDirty =
true;
96 m_itemToWindowTransform = itemToWindowTransform;
99QTransform QGeoProjection::itemToWindowTransform()
const
101 return m_itemToWindowTransform;
106
107
109QGeoCoordinate QGeoProjectionWebMercator::anchorCoordinateToPoint(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint)
const
112 QDoubleVector2D centerProj = geoToWrappedMapProjection(cameraData().center());
113 QDoubleVector2D coordProj = geoToWrappedMapProjection(coordinate);
115 QDoubleVector2D anchorProj = itemPositionToWrappedMapProjection(QDoubleVector2D(anchorPoint));
117 return wrappedMapProjectionToGeo(centerProj + coordProj - anchorProj);
120bool QGeoProjectionWebMercator::setBearing(qreal bearing,
const QGeoCoordinate &coordinate)
122 const QDoubleVector2D coordWrapped = geoToWrappedMapProjection(coordinate);
123 if (!isProjectable(coordWrapped))
125 const QPointF rotationPoint = wrappedMapProjectionToItemPosition(coordWrapped).toPointF();
127 QGeoCameraData camera = cameraData();
129 camera.setBearing(bearing);
130 setCameraData(camera);
131 camera = cameraData();
134 const QGeoCoordinate center = anchorCoordinateToPoint(coordinate, rotationPoint);
135 camera.setCenter(center);
136 setCameraData(camera);
140QGeoProjectionWebMercator::QGeoProjectionWebMercator()
144 m_cameraCenterXMercator(0),
145 m_cameraCenterYMercator(0),
148 m_1_viewportWidth(0),
149 m_1_viewportHeight(0),
150 m_sideLengthPixels(256),
156 m_minimumUnprojectableY(0.0),
157 m_verticalEstateToSkip(0.0),
158 m_visibleRegionDirty(
false)
162QGeoProjectionWebMercator::~QGeoProjectionWebMercator()
169double QGeoProjectionWebMercator::minimumZoom()
const
171 return m_minimumZoom;
174QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation()
const
176 return toMatrix4x4(m_transformation);
179QMatrix4x4 QGeoProjectionWebMercator::projectionTransformation_centered()
const
181 return toMatrix4x4(m_transformation0);
184const QMatrix4x4 &QGeoProjectionWebMercator::qsgTransform()
const
186 if (m_qsgTransformDirty) {
187 m_qsgTransformDirty =
false;
188 m_qsgTransform = QMatrix4x4(m_itemToWindowTransform) * toMatrix4x4(m_transformation0);
191 return m_qsgTransform;
194QDoubleVector3D QGeoProjectionWebMercator::centerMercator()
const
196 return geoToMapProjection(m_cameraData.center()).toVector3D();
205double QGeoProjectionWebMercator::maximumCenterLatitudeAtZoom(
const QGeoCameraData &cameraData)
const
207 double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
210 int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
211 QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
212 double hpct = offsetPct.y() / qMax<
double>(m_viewportHeight - 1, 1);
215 double mercatorTopmost = (clampedWindowHeight * (0.5 - hpct)) / mapEdgeSize ;
216 QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost));
217 return topMost.latitude();
220double QGeoProjectionWebMercator::minimumCenterLatitudeAtZoom(
const QGeoCameraData &cameraData)
const
222 double mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
225 int clampedWindowHeight = (m_viewportHeight > mapEdgeSize) ? mapEdgeSize : m_viewportHeight;
226 QPointF offsetPct = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
227 double hpct = offsetPct.y() / qMax<
double>(m_viewportHeight - 1, 1);
230 double mercatorTopmost = (clampedWindowHeight * (0.5 + hpct)) / mapEdgeSize ;
231 QGeoCoordinate topMost = QWebMercator::mercatorToCoord(QDoubleVector2D(0.0, mercatorTopmost));
232 return -topMost.latitude();
235void QGeoProjectionWebMercator::setVisibleArea(
const QRectF &visibleArea)
237 m_visibleArea = visibleArea;
241double QGeoProjectionWebMercator::mapWidth()
const
243 return m_mapEdgeSize;
246double QGeoProjectionWebMercator::mapHeight()
const
248 return m_mapEdgeSize;
251void QGeoProjectionWebMercator::setViewportSize(
const QSize &size)
253 if (
int(m_viewportWidth) == size.width() &&
int(m_viewportHeight) == size.height())
256 m_viewportWidth = size.width();
257 m_viewportHeight = size.height();
258 m_1_viewportWidth = 1.0 / m_viewportWidth;
259 m_1_viewportHeight = 1.0 / m_viewportHeight;
260 m_minimumZoom = std::log(qMax(m_viewportWidth, m_viewportHeight) / defaultTileSize) / std::log(2.0);
264void QGeoProjectionWebMercator::setCameraData(
const QGeoCameraData &cameraData,
bool force)
266 if (m_cameraData == cameraData && !force)
269 m_cameraData = cameraData;
270 m_mapEdgeSize = std::pow(2.0, cameraData.zoomLevel()) * defaultTileSize;
274QDoubleVector2D QGeoProjectionWebMercator::geoToMapProjection(
const QGeoCoordinate &coordinate)
const
276 return QWebMercator::coordToMercator(coordinate);
279QGeoCoordinate QGeoProjectionWebMercator::mapProjectionToGeo(
const QDoubleVector2D &projection)
const
281 return QWebMercator::mercatorToCoord(projection);
284int QGeoProjectionWebMercator::projectionWrapFactor(
const QDoubleVector2D &projection)
const
286 const double &x = projection.x();
287 if (m_cameraCenterXMercator < 0.5) {
288 if (x - m_cameraCenterXMercator > 0.5 )
290 }
else if (m_cameraCenterXMercator > 0.5) {
291 if (x - m_cameraCenterXMercator < -0.5 )
298QDoubleVector2D QGeoProjectionWebMercator::wrapMapProjection(
const QDoubleVector2D &projection)
const
300 return QDoubleVector2D(projection.x() +
double(projectionWrapFactor(projection)), projection.y());
303QDoubleVector2D QGeoProjectionWebMercator::unwrapMapProjection(
const QDoubleVector2D &wrappedProjection)
const
305 double x = wrappedProjection.x();
307 return QDoubleVector2D(x - 1.0, wrappedProjection.y());
309 return QDoubleVector2D(x + 1.0, wrappedProjection.y());
310 return wrappedProjection;
313QDoubleVector2D QGeoProjectionWebMercator::wrappedMapProjectionToItemPosition(
const QDoubleVector2D &wrappedProjection)
const
315 return (m_transformation * wrappedProjection).toVector2D();
318QDoubleVector2D QGeoProjectionWebMercator::itemPositionToWrappedMapProjection(
const QDoubleVector2D &itemPosition)
const
320 const QPointF centerOff = centerOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
321 QDoubleVector2D pos = itemPosition + QDoubleVector2D(centerOff);
322 pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
324 pos -= QDoubleVector2D(1.0,1.0);
327 QDoubleVector2D res = viewportToWrappedMapProjection(pos, s);
333 pos.setY(m_minimumUnprojectableY);
334 pos *= QDoubleVector2D(m_1_viewportWidth, m_1_viewportHeight);
336 pos -= QDoubleVector2D(1.0,1.0);
337 res = viewportToWrappedMapProjection(pos, s);
344QGeoCoordinate QGeoProjectionWebMercator::itemPositionToCoordinate(
const QDoubleVector2D &pos,
bool clipToViewport)
const
346 if (qIsNaN(pos.x()) || qIsNaN(pos.y()))
347 return QGeoCoordinate();
349 if (clipToViewport) {
350 int w = m_viewportWidth;
351 int h = m_viewportHeight;
353 if ((pos.x() < 0) || (w < pos.x()) || (pos.y() < 0) || (h < pos.y()))
354 return QGeoCoordinate();
357 QDoubleVector2D wrappedMapProjection = itemPositionToWrappedMapProjection(pos);
359 if (!isProjectable(wrappedMapProjection))
360 return QGeoCoordinate();
361 return mapProjectionToGeo(unwrapMapProjection(wrappedMapProjection));
364QDoubleVector2D QGeoProjectionWebMercator::coordinateToItemPosition(
const QGeoCoordinate &coordinate,
bool clipToViewport)
const
366 if (!coordinate.isValid())
367 return QDoubleVector2D(qQNaN(), qQNaN());
369 QDoubleVector2D wrappedProjection = wrapMapProjection(geoToMapProjection(coordinate));
370 if (!isProjectable(wrappedProjection))
371 return QDoubleVector2D(qQNaN(), qQNaN());
373 QDoubleVector2D pos = wrappedMapProjectionToItemPosition(wrappedProjection);
375 if (clipToViewport) {
376 int w = m_viewportWidth;
377 int h = m_viewportHeight;
380 if ((x < -0.5) || (x > w + 0.5) || (y < -0.5) || (y > h + 0.5) || qIsNaN(x) || qIsNaN(y))
381 return QDoubleVector2D(qQNaN(), qQNaN());
386QDoubleVector2D QGeoProjectionWebMercator::geoToWrappedMapProjection(
const QGeoCoordinate &coordinate)
const
388 return wrapMapProjection(geoToMapProjection(coordinate));
391QGeoCoordinate QGeoProjectionWebMercator::wrappedMapProjectionToGeo(
const QDoubleVector2D &wrappedProjection)
const
393 return mapProjectionToGeo(unwrapMapProjection(wrappedProjection));
396QMatrix4x4 QGeoProjectionWebMercator::quickItemTransformation(
const QGeoCoordinate &coordinate,
const QPointF &anchorPoint, qreal zoomLevel)
const
398 const QDoubleVector2D coordWrapped = geoToWrappedMapProjection(coordinate);
399 double scale = std::pow(0.5, zoomLevel - m_cameraData.zoomLevel());
400 const QDoubleVector2D anchorScaled = QDoubleVector2D(anchorPoint.x(), anchorPoint.y()) * scale;
401 const QDoubleVector2D anchorMercator = anchorScaled / mapWidth();
403 const QDoubleVector2D coordAnchored = coordWrapped - anchorMercator;
404 const QDoubleVector2D coordAnchoredScaled = coordAnchored * m_sideLengthPixels;
405 QDoubleMatrix4x4 matTranslateScale;
406 matTranslateScale.translate(coordAnchoredScaled.x(), coordAnchoredScaled.y(), 0.0);
408 scale = std::pow(0.5, (zoomLevel - std::floor(zoomLevel)) +
409 (std::floor(zoomLevel) - std::floor(m_cameraData.zoomLevel())));
410 matTranslateScale.scale(scale);
413
414
415
416
417
418
419
420
421
423 return toMatrix4x4(m_quickItemTransformation * matTranslateScale);
426bool QGeoProjectionWebMercator::isProjectable(
const QDoubleVector2D &wrappedProjection)
const
428 if (m_cameraData.tilt() == 0.0)
431 QDoubleVector3D pos = wrappedProjection * m_sideLengthPixels;
433 QDoubleVector3D p = m_centerNearPlane - pos;
434 double dot = QDoubleVector3D::dotProduct(p , m_viewNormalized);
441QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleGeometry()
const
443 if (m_visibleRegionDirty)
444 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
445 return m_visibleRegion;
448QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleGeometryExpanded()
const
450 if (m_visibleRegionDirty)
451 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
452 return m_visibleRegionExpanded;
455QList<QDoubleVector2D> QGeoProjectionWebMercator::projectableGeometry()
const
457 if (m_visibleRegionDirty)
458 const_cast<QGeoProjectionWebMercator *>(
this)->updateVisibleRegion();
459 return m_projectableRegion;
462QGeoShape QGeoProjectionWebMercator::visibleRegion()
const
464 const QList<QDoubleVector2D> &visibleRegion = visibleGeometry();
466 for (qsizetype i = 0; i < visibleRegion.size(); ++i) {
467 const QDoubleVector2D &c = visibleRegion.at(i);
469 if (i && qAbs(visibleRegion.at(i - 1).x() - c.x()) >= 0.5) {
470 QDoubleVector2D extraPoint = (visibleRegion.at(i - 1) + c) * 0.5;
471 poly.addCoordinate(wrappedMapProjectionToGeo(extraPoint));
473 poly.addCoordinate(wrappedMapProjectionToGeo(c));
475 if (visibleRegion.size() >= 2 && qAbs(visibleRegion.last().x() - visibleRegion.first().x()) >= 0.5) {
476 QDoubleVector2D extraPoint = (visibleRegion.last() + visibleRegion.first()) * 0.5;
477 poly.addCoordinate(wrappedMapProjectionToGeo(extraPoint));
483QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(
const QDoubleVector2D &itemPosition)
const
486 return viewportToWrappedMapProjection(itemPosition, s);
490
491
492QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(
const QDoubleVector2D &itemPosition,
double &s)
const
494 QDoubleVector2D pos = itemPosition;
495 pos *= QDoubleVector2D(m_halfWidth, m_halfHeight);
498 QDoubleVector3D p = m_centerNearPlane;
500 p += m_side * pos.x();
503 QDoubleVector3D ray = m_eye - p;
506 return (xyPlane.lineIntersection(m_eye, ray, s) / m_sideLengthPixels).toVector2D();
510
511
512QPair<QGeoCoordinate, qreal> QGeoProjectionWebMercator::fitViewportToGeoRectangle(
const QGeoRectangle &rectangle,
513 const QMargins &m)
const
515 QPair<QGeoCoordinate, qreal> res;
516 res.second = qQNaN();
517 if (m_viewportWidth <= m.left() + m.right() || m_viewportHeight <= m.top() + m.bottom())
520 QDoubleVector2D topLeftPoint = geoToMapProjection(rectangle.topLeft());
521 QDoubleVector2D bottomRightPoint = geoToMapProjection(rectangle.bottomRight());
522 if (bottomRightPoint.x() < topLeftPoint.x())
523 bottomRightPoint.setX(bottomRightPoint.x() + 1.0);
526 QDoubleVector2D center = (topLeftPoint + bottomRightPoint) * 0.5;
527 center.setX(center.x() > 1.0 ? center.x() - 1.0 : center.x());
528 res.first = mapProjectionToGeo(center);
531 double bboxWidth = (bottomRightPoint.x() - topLeftPoint.x()) * mapWidth();
532 double bboxHeight = (bottomRightPoint.y() - topLeftPoint.y()) * mapHeight();
534 if (bboxHeight == 0.0 && bboxWidth == 0.0)
537 double zoomRatio = qMax(bboxWidth / (m_viewportWidth - m.left() - m.right()),
538 bboxHeight / (m_viewportHeight - m.top() - m.bottom()));
539 zoomRatio = std::log(zoomRatio) / std::log(2.0);
540 res.second = m_cameraData.zoomLevel() - zoomRatio;
545QGeoProjection::ProjectionGroup QGeoProjectionWebMercator::projectionGroup()
const
547 return QGeoProjection::ProjectionCylindrical;
550QGeoProjection::Datum QGeoProjectionWebMercator::datum()
const
552 return QGeoProjection::DatumWGS84;
555QGeoProjection::ProjectionType QGeoProjectionWebMercator::projectionType()
const
557 return QGeoProjection::ProjectionWebMercator;
560void QGeoProjectionWebMercator::setupCamera()
562 m_qsgTransformDirty =
true;
563 m_centerMercator = geoToMapProjection(m_cameraData.center());
564 m_cameraCenterXMercator = m_centerMercator.x();
565 m_cameraCenterYMercator = m_centerMercator.y();
567 int intZoomLevel =
static_cast<
int>(std::floor(m_cameraData.zoomLevel()));
568 m_sideLengthPixels = (1 << intZoomLevel) * defaultTileSize;
569 m_center = m_centerMercator * m_sideLengthPixels;
571 m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
573 double f = m_viewportHeight;
574 double z = std::pow(2.0, m_cameraData.zoomLevel() - intZoomLevel) * defaultTileSize;
575 double altitude = f / (2.0 * z);
577 double z_mercator = std::pow(2.0, m_cameraData.zoomLevel()) * defaultTileSize;
578 double altitude_mercator = f / (2.0 * z_mercator);
582 m_eye.setZ(altitude * defaultTileSize / m_aperture);
585 m_eyeMercator = m_centerMercator;
586 m_eyeMercator.setZ(altitude_mercator / m_aperture);
587 m_eyeMercator0 = QDoubleVector3D(0,0,0);
588 m_eyeMercator0.setZ(altitude_mercator / m_aperture);
589 QDoubleVector3D eye0(0,0,0);
590 eye0.setZ(altitude * defaultTileSize / m_aperture);
592 m_view = m_eye - m_center;
593 QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0));
594 m_up = QDoubleVector3D::normal(side, m_view);
597 m_viewMercator = m_eyeMercator - m_centerMercator;
598 QDoubleVector3D sideMercator = QDoubleVector3D::normal(m_viewMercator, QDoubleVector3D(0.0, 1.0, 0.0));
599 m_upMercator = QDoubleVector3D::normal(sideMercator, m_viewMercator);
601 if (m_cameraData.bearing() > 0.0) {
602 QDoubleMatrix4x4 mBearing;
603 mBearing.rotate(m_cameraData.bearing(), m_view);
604 m_up = mBearing * m_up;
607 QDoubleMatrix4x4 mBearingMercator;
608 mBearingMercator.rotate(m_cameraData.bearing(), m_viewMercator);
609 m_upMercator = mBearingMercator * m_upMercator;
612 m_side = QDoubleVector3D::normal(m_up, m_view);
613 m_sideMercator = QDoubleVector3D::normal(m_upMercator, m_viewMercator);
615 if (m_cameraData.tilt() > 0.0) {
616 QDoubleMatrix4x4 mTilt;
617 mTilt.rotate(-m_cameraData.tilt(), m_side);
618 m_eye = mTilt * m_view + m_center;
619 eye0 = mTilt * m_view;
622 QDoubleMatrix4x4 mTiltMercator;
623 mTiltMercator.rotate(-m_cameraData.tilt(), m_sideMercator);
624 m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator;
625 m_eyeMercator0 = mTiltMercator * m_viewMercator;
628 m_view = m_eye - m_center;
629 m_viewNormalized = m_view.normalized();
630 m_up = QDoubleVector3D::normal(m_view, m_side);
642 m_farPlane = (altitude + 2097152.0) * defaultTileSize;
644 m_viewMercator = m_eyeMercator - m_centerMercator;
645 m_upMercator = QDoubleVector3D::normal(m_viewMercator, m_sideMercator);
646 m_nearPlaneMercator = 0.000002;
649 double aspectRatio = 1.0 * m_viewportWidth / m_viewportHeight;
651 m_halfWidth = m_aperture * aspectRatio;
652 m_halfHeight = m_aperture;
654 double verticalHalfFOV = QLocationUtils::degrees(atan(m_aperture));
656 m_cameraMatrix.setToIdentity();
657 m_cameraMatrix.lookAt(m_eye, m_center, m_up);
658 m_cameraMatrix0.setToIdentity();
659 m_cameraMatrix0.lookAt(eye0, QDoubleVector3D(0,0,0), m_up);
661 QDoubleMatrix4x4 projectionMatrix;
662 projectionMatrix.frustum(-m_halfWidth, m_halfWidth, -m_halfHeight, m_halfHeight, m_nearPlane, m_farPlane);
665
666
667
668
669
670
671
672
674 QPointF offsetPct = marginsOffset(QSizeF(m_viewportWidth, m_viewportHeight), m_visibleArea);
675 QDoubleMatrix4x4 matScreenTransformation;
676 matScreenTransformation.scale(0.5 * m_viewportWidth, 0.5 * m_viewportHeight, 1.0);
677 matScreenTransformation(0,3) = (0.5 + offsetPct.x()) * m_viewportWidth;
678 matScreenTransformation(1,3) = (0.5 + offsetPct.y()) * m_viewportHeight;
680 m_transformation = matScreenTransformation * projectionMatrix * m_cameraMatrix;
681 m_quickItemTransformation = m_transformation;
682 m_transformation.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
684 m_transformation0 = matScreenTransformation * projectionMatrix * m_cameraMatrix0;
685 m_transformation0.scale(m_sideLengthPixels, m_sideLengthPixels, 1.0);
687 m_centerNearPlane = m_eye - m_viewNormalized;
688 m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator;
694 const double upperBoundEpsilon = 1.0 / std::pow(10, 1.0 + m_cameraData.zoomLevel() / 5.0);
695 const double elevationUpperBound = 90.0 - upperBoundEpsilon;
696 const double maxRayElevation = qMin(elevationUpperBound - m_cameraData.tilt(), verticalHalfFOV);
697 double maxHalfAperture = 0;
698 m_verticalEstateToSkip = 0;
699 if (maxRayElevation < verticalHalfFOV) {
700 maxHalfAperture = tan(QLocationUtils::radians(maxRayElevation));
701 m_verticalEstateToSkip = 1.0 - maxHalfAperture / m_aperture;
704 m_minimumUnprojectableY = m_verticalEstateToSkip * 0.5 * m_viewportHeight;
705 m_visibleRegionDirty =
true;
708void QGeoProjectionWebMercator::updateVisibleRegion()
710 m_visibleRegionDirty =
false;
712 double viewportHalfWidth = (!m_visibleArea.isEmpty()) ? m_visibleArea.width() / m_viewportWidth : 1.0;
713 double viewportHalfHeight = (!m_visibleArea.isEmpty()) ? m_visibleArea.height() / m_viewportHeight : 1.0;
715 double top = qMax<
double>(-viewportHalfHeight, -1 + m_verticalEstateToSkip);
716 double bottom = viewportHalfHeight;
717 double left = -viewportHalfWidth;
718 double right = viewportHalfWidth;
720 QDoubleVector2D tl = viewportToWrappedMapProjection(QDoubleVector2D(left, top ));
721 QDoubleVector2D tr = viewportToWrappedMapProjection(QDoubleVector2D(right, top ));
722 QDoubleVector2D bl = viewportToWrappedMapProjection(QDoubleVector2D(left, bottom ));
723 QDoubleVector2D br = viewportToWrappedMapProjection(QDoubleVector2D(right, bottom ));
726 double mapLeftLongitude = QLocationUtils::mapLeftLongitude(m_cameraData.center().longitude());
727 double mapRightLongitude = QLocationUtils::mapRightLongitude(m_cameraData.center().longitude());
728 double leftX = geoToWrappedMapProjection(QGeoCoordinate(0, mapLeftLongitude)).x();
729 double rightX = geoToWrappedMapProjection(QGeoCoordinate(0, mapRightLongitude)).x();
731 QList<QDoubleVector2D> mapRect;
732 mapRect.push_back(QDoubleVector2D(leftX, 1.0));
733 mapRect.push_back(QDoubleVector2D(rightX, 1.0));
734 mapRect.push_back(QDoubleVector2D(rightX, 0.0));
735 mapRect.push_back(QDoubleVector2D(leftX, 0.0));
737 QList<QDoubleVector2D> viewportRect;
738 viewportRect.push_back(bl);
739 viewportRect.push_back(br);
740 viewportRect.push_back(tr);
741 viewportRect.push_back(tl);
743 QClipperUtils clipper;
744 clipper.clearClipper();
745 clipper.addSubjectPath(mapRect,
true);
746 clipper.addClipPolygon(viewportRect);
748 const auto res = clipper.execute(QClipperUtils::Intersection);
749 m_visibleRegion.clear();
751 m_visibleRegion = res[0];
753 m_projectableRegion.clear();
756 mapRect.push_back(QDoubleVector2D(-1.0, 1.0));
757 mapRect.push_back(QDoubleVector2D( 2.0, 1.0));
758 mapRect.push_back(QDoubleVector2D( 2.0, 0.0));
759 mapRect.push_back(QDoubleVector2D(-1.0, 0.0));
760 if (m_cameraData.tilt() == 0) {
761 m_projectableRegion = mapRect;
763 QGeoProjectionWebMercator::Plane nearPlane(m_centerNearPlaneMercator, m_viewNormalized);
764 Line2D nearPlaneXYIntersection = nearPlane.planeXYIntersection();
765 double squareHalfSide = qMax(5.0, nearPlaneXYIntersection.m_point.length());
766 QDoubleVector2D viewDirectionProjected = -m_viewNormalized.toVector2D().normalized();
769 QDoubleVector2D tl = nearPlaneXYIntersection.m_point
770 - squareHalfSide * nearPlaneXYIntersection.m_direction
771 + 2 * squareHalfSide * viewDirectionProjected;
772 QDoubleVector2D tr = nearPlaneXYIntersection.m_point
773 + squareHalfSide * nearPlaneXYIntersection.m_direction
774 + 2 * squareHalfSide * viewDirectionProjected;
775 QDoubleVector2D bl = nearPlaneXYIntersection.m_point
776 - squareHalfSide * nearPlaneXYIntersection.m_direction;
777 QDoubleVector2D br = nearPlaneXYIntersection.m_point
778 + squareHalfSide * nearPlaneXYIntersection.m_direction;
780 QList<QDoubleVector2D> projectableRect;
781 projectableRect.push_back(bl);
782 projectableRect.push_back(br);
783 projectableRect.push_back(tr);
784 projectableRect.push_back(tl);
787 QClipperUtils clipperProjectable;
788 clipperProjectable.clearClipper();
789 clipperProjectable.addSubjectPath(mapRect,
true);
790 clipperProjectable.addClipPolygon(projectableRect);
792 const auto resProjectable = clipperProjectable.execute(QClipperUtils::Intersection);
793 if (resProjectable.size())
794 m_projectableRegion = resProjectable[0];
796 m_projectableRegion = viewportRect;
800 QDoubleVector2D centroid;
801 for (
const QDoubleVector2D &v: std::as_const(m_visibleRegion))
803 centroid /= m_visibleRegion.size();
805 m_visibleRegionExpanded.clear();
806 for (
const QDoubleVector2D &v: std::as_const(m_visibleRegion)) {
807 const QDoubleVector2D vc = v - centroid;
808 m_visibleRegionExpanded.push_back(centroid + vc * 1.2);
813QGeoCameraData QGeoProjectionWebMercator::cameraData()
const
819
820
821
822
824QGeoProjectionWebMercator::Line2D::Line2D()
829QGeoProjectionWebMercator::Line2D::Line2D(
const QDoubleVector2D &linePoint,
const QDoubleVector2D &lineDirection)
830 : m_point(linePoint), m_direction(lineDirection.normalized())
835bool QGeoProjectionWebMercator::Line2D::isValid()
const
837 return (m_direction.length() > 0.5);
841
842
843
844
846QGeoProjectionWebMercator::Plane::Plane()
851QGeoProjectionWebMercator::Plane::Plane(
const QDoubleVector3D &planePoint,
const QDoubleVector3D &planeNormal)
852 : m_point(planePoint), m_normal(planeNormal.normalized()) { }
854QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(
const QDoubleVector3D &linePoint,
const QDoubleVector3D &lineDirection)
const
857 return lineIntersection(linePoint, lineDirection, s);
860QDoubleVector3D QGeoProjectionWebMercator::Plane::lineIntersection(
const QDoubleVector3D &linePoint,
const QDoubleVector3D &lineDirection,
double &s)
const
862 QDoubleVector3D w = linePoint - m_point;
864 s = QDoubleVector3D::dotProduct(-m_normal, w) / QDoubleVector3D::dotProduct(m_normal, lineDirection);
865 return linePoint + lineDirection * s;
868QGeoProjectionWebMercator::Line2D QGeoProjectionWebMercator::Plane::planeXYIntersection()
const
871 QDoubleVector3D lineDirection = QDoubleVector3D::crossProduct(m_normal, xyNormal);
872 lineDirection.setZ(0.0);
873 lineDirection.normalize();
877 QDoubleVector3D directionToXY = QDoubleVector3D::crossProduct(m_normal, lineDirection);
878 QDoubleVector3D p = xyPlane.lineIntersection(m_point, directionToXY);
879 return Line2D(p.toVector2D(), lineDirection.toVector2D());
882bool QGeoProjectionWebMercator::Plane::isValid()
const
884 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)