summaryrefslogtreecommitdiff
path: root/src/location/maps/qgeoprojection.cpp
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2017-07-07 15:31:00 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2017-07-17 12:40:42 +0000
commit2ab93acd9751b3ffe2c36a4a0e37dc792686a08f (patch)
tree59070747c2225f76754cf292e15ed29b30141d85 /src/location/maps/qgeoprojection.cpp
parentb02916a5568d57eda767ca930dcdb366179250bc (diff)
downloadqtlocation-2ab93acd9751b3ffe2c36a4a0e37dc792686a08f.tar.gz
Fix dragging items out of map bounds
In 5.9.0 map items are clipped against the visible region. This implies that their geometry is also clipped against the visible region. This is problematic in ::geometryChanged, since the old geometry is always clipped in this way. This patch clips items against a "projectable" region instead, that is the part of the map that is in front of the camera. Since this can produce very large vertices, mapbox earcut 3rd party library is pulled in, to replace qTriangulate that only supports coordinates up to 1<<21. Task-number: QTBUG-61727 Change-Id: I7449e755a4848a2b2107c5de4e27821e3e887bfb Reviewed-by: Paolo Angelelli <paolo.angelelli@qt.io>
Diffstat (limited to 'src/location/maps/qgeoprojection.cpp')
-rw-r--r--src/location/maps/qgeoprojection.cpp57
1 files changed, 52 insertions, 5 deletions
diff --git a/src/location/maps/qgeoprojection.cpp b/src/location/maps/qgeoprojection.cpp
index 07747a31..609fb934 100644
--- a/src/location/maps/qgeoprojection.cpp
+++ b/src/location/maps/qgeoprojection.cpp
@@ -317,6 +317,13 @@ QList<QDoubleVector2D> QGeoProjectionWebMercator::visibleRegion() const
return m_visibleRegion;
}
+QList<QDoubleVector2D> QGeoProjectionWebMercator::projectableRegion() const
+{
+ if (m_visibleRegionDirty)
+ const_cast<QGeoProjectionWebMercator *>(this)->updateVisibleRegion();
+ return m_projectableRegion;
+}
+
QDoubleVector2D QGeoProjectionWebMercator::viewportToWrappedMapProjection(const QDoubleVector2D &itemPosition) const
{
double s;
@@ -350,6 +357,8 @@ void QGeoProjectionWebMercator::setupCamera()
int intZoomLevel = static_cast<int>(std::floor(m_cameraData.zoomLevel()));
m_sideLength = (1 << intZoomLevel) * defaultTileSize;
m_center = m_centerMercator * m_sideLength;
+ //aperture(90 / 2) = 1
+ m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
double f = m_viewportHeight;
double z = std::pow(2.0, m_cameraData.zoomLevel() - intZoomLevel) * defaultTileSize;
@@ -358,15 +367,13 @@ void QGeoProjectionWebMercator::setupCamera()
double z_mercator = std::pow(2.0, m_cameraData.zoomLevel()) * defaultTileSize;
double altitude_mercator = f / (2.0 * z_mercator);
- //aperture(90 / 2) = 1
- m_aperture = tan(QLocationUtils::radians(m_cameraData.fieldOfView()) * 0.5);
// calculate eye
m_eye = m_center;
m_eye.setZ(altitude * defaultTileSize / m_aperture);
// And in mercator space
m_eyeMercator = m_centerMercator;
- m_eyeMercator.setZ(altitude_mercator);
+ m_eyeMercator.setZ(altitude_mercator / m_aperture);
m_view = m_eye - m_center;
QDoubleVector3D side = QDoubleVector3D::normal(m_view, QDoubleVector3D(0.0, 1.0, 0.0));
@@ -402,7 +409,7 @@ void QGeoProjectionWebMercator::setupCamera()
m_eyeMercator = mTiltMercator * m_viewMercator + m_centerMercator;
}
- m_view = m_eye - m_center;
+ m_view = m_eye - m_center; // ToDo: this should be inverted (center - eye), and the rest should follow
m_viewNormalized = m_view.normalized();
m_up = QDoubleVector3D::normal(m_view, m_side);
@@ -455,7 +462,7 @@ void QGeoProjectionWebMercator::setupCamera()
m_transformation.scale(m_sideLength, m_sideLength, 1.0);
m_centerNearPlane = m_eye + m_viewNormalized;
- m_centerNearPlaneMercator = m_eyeMercator + m_viewNormalized * m_nearPlaneMercator;
+ m_centerNearPlaneMercator = m_eyeMercator - m_viewNormalized * m_nearPlaneMercator;
// The method does not support tilting angles >= 90.0 or < 0.
@@ -505,6 +512,46 @@ void QGeoProjectionWebMercator::updateVisibleRegion()
m_visibleRegion.clear();
if (res.size())
m_visibleRegion = QClipperUtils::pathToQList(res[0]); // Intersection between two convex quadrilaterals should always be a single polygon
+
+ m_projectableRegion.clear();
+ if (m_cameraData.tilt() == 0) {
+ m_projectableRegion = mapRect;
+ } else {
+ QGeoProjectionWebMercator::Plane nearPlane(m_centerNearPlaneMercator, m_viewNormalized);
+ Line2D nearPlaneXYIntersection = nearPlane.planeXYIntersection();
+ double squareHalfSide = qMax(5.0, nearPlaneXYIntersection.m_point.length());
+ QDoubleVector2D viewDirectionProjected = -m_viewNormalized.toVector2D().normalized();
+
+
+ QDoubleVector2D tl = nearPlaneXYIntersection.m_point
+ - squareHalfSide * nearPlaneXYIntersection.m_direction
+ + 2 * squareHalfSide * viewDirectionProjected;
+ QDoubleVector2D tr = nearPlaneXYIntersection.m_point
+ + squareHalfSide * nearPlaneXYIntersection.m_direction
+ + 2 * squareHalfSide * viewDirectionProjected;
+ QDoubleVector2D bl = nearPlaneXYIntersection.m_point
+ - squareHalfSide * nearPlaneXYIntersection.m_direction;
+ QDoubleVector2D br = nearPlaneXYIntersection.m_point
+ + squareHalfSide * nearPlaneXYIntersection.m_direction;
+
+ QList<QDoubleVector2D> projectableRect;
+ projectableRect.push_back(bl);
+ projectableRect.push_back(br);
+ projectableRect.push_back(tr);
+ projectableRect.push_back(tl);
+
+
+ c2t::clip2tri clipperProjectable;
+ clipperProjectable.clearClipper();
+ clipperProjectable.addSubjectPath(QClipperUtils::qListToPath(mapRect), true);
+ clipperProjectable.addClipPolygon(QClipperUtils::qListToPath(projectableRect));
+
+ Paths resProjectable = clipperProjectable.execute(c2t::clip2tri::Intersection);
+ if (resProjectable.size())
+ m_projectableRegion = QClipperUtils::pathToQList(resProjectable[0]); // Intersection between two convex quadrilaterals should always be a single polygon
+ else
+ m_projectableRegion = viewportRect;
+ }
}
/*