diff options
Diffstat (limited to 'src/location/quickmapitems/qdeclarativepolygonmapitem.cpp')
-rw-r--r-- | src/location/quickmapitems/qdeclarativepolygonmapitem.cpp | 391 |
1 files changed, 1 insertions, 390 deletions
diff --git a/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp b/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp index 3ef35bb5..eb99a264 100644 --- a/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp +++ b/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp @@ -39,20 +39,14 @@ #include "qdeclarativegeomapitemutils_p.h" #include "qdeclarativepolygonmapitem_p.h" -#include "qdeclarativepolylinemapitem_p_p.h" #include "qdeclarativepolygonmapitem_p_p.h" -#include "qdeclarativerectanglemapitem_p_p.h" -#include "error_messages_p.h" +#include "rhi/qdeclarativepolygonmapitem_rhi_p.h" #include "locationvaluetypehelper_p.h" #include <QtCore/QScopedValueRollback> #include <qnumeric.h> -#include <QPainter> #include <QPainterPath> -#include <QtQml/QQmlInfo> -#include <QtQuick/qsgnode.h> -#include <QtQuick/private/qsgmaterialshader_p.h> #include <QtLocation/private/qgeomap_p.h> #include <QtPositioning/private/qlocationutils_p.h> #include <QtPositioning/private/qdoublevector2d_p.h> @@ -428,267 +422,6 @@ bool QDeclarativePolygonMapItemPrivateCPU::contains(const QPointF &point) const return (m_geometry.contains(point) || m_borderGeometry.contains(point)); } - -QGeoMapPolygonGeometryOpenGL::QGeoMapPolygonGeometryOpenGL() -{ -} - -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QList<QDoubleVector2D> &path) -{ - QList<QGeoCoordinate> geopath; - for (const auto &c: path) - geopath.append(QWebMercator::mercatorToCoord(c)); - updateSourcePoints(map, geopath); -} - -// wrapPath always preserves the geometry -// This one handles holes -static void wrapPath(const QGeoPolygon &poly - ,const QGeoCoordinate &geoLeftBound - ,const QGeoProjectionWebMercator &p - ,QList<QList<QDoubleVector2D> > &wrappedPaths - ,QDoubleVector2D *leftBoundWrapped = nullptr) -{ - QList<QList<QDoubleVector2D> > paths; - for (qsizetype i = 0; i < 1 + poly.holesCount(); ++i) { - QList<QDoubleVector2D> path; - if (!i) { - for (const QGeoCoordinate &c : poly.perimeter()) - path << p.geoToMapProjection(c); - } else { - for (const QGeoCoordinate &c : poly.holePath(i-1)) - path << p.geoToMapProjection(c); - } - paths.append(path); - } - - const QDoubleVector2D leftBound = p.geoToMapProjection(geoLeftBound); - wrappedPaths.clear(); - - QList<QDoubleVector2D> wrappedPath; - // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - for (const auto &path : paths) { - wrappedPath.clear(); - for (QDoubleVector2D coord : path) { - // We can get NaN if the map isn't set up correctly, or the projection - // is faulty -- probably best thing to do is abort - if (!qIsFinite(coord.x()) || !qIsFinite(coord.y())) { - wrappedPaths.clear(); - return; - } - - const bool isPointLessThanUnwrapBelowX = (coord.x() < leftBound.x()); - // unwrap x to preserve geometry if moved to border of map - if (isPointLessThanUnwrapBelowX) - coord.setX(coord.x() + 1.0); - wrappedPath.append(coord); - } - wrappedPaths.append(wrappedPath); - } - - if (leftBoundWrapped) - *leftBoundWrapped = leftBound; -} - -static void cutPathEars(const QList<QList<QDoubleVector2D>> &wrappedPaths, - QList<QDeclarativeGeoMapItemUtils::vec2> &screenVertices, - QList<quint32> &screenIndices) -{ - using Coord = double; - using N = uint32_t; - using Point = std::array<Coord, 2>; - screenVertices.clear(); - screenIndices.clear(); - - std::vector<std::vector<Point>> polygon; - std::vector<Point> poly; - - for (const QList<QDoubleVector2D> &wrappedPath: wrappedPaths) { - poly.clear(); - for (const QDoubleVector2D &v: wrappedPath) { - screenVertices << v; - Point pt = {{ v.x(), v.y() }}; - poly.push_back( pt ); - } - polygon.push_back(poly); - } - - std::vector<N> indices = qt_mapbox::earcut<N>(polygon); - - for (const auto &i: indices) - screenIndices << quint32(i); -} - -static void cutPathEars(const QList<QDoubleVector2D> &wrappedPath, - QList<QDeclarativeGeoMapItemUtils::vec2> &screenVertices, - QList<quint32> &screenIndices) -{ - using Coord = double; - using N = uint32_t; - using Point = std::array<Coord, 2>; - screenVertices.clear(); - screenIndices.clear(); - - std::vector<std::vector<Point>> polygon; - std::vector<Point> poly; - - for (const QDoubleVector2D &v: wrappedPath) { - screenVertices << v; - Point pt = {{ v.x(), v.y() }}; - poly.push_back( pt ); - } - polygon.push_back(poly); - - std::vector<N> indices = qt_mapbox::earcut<N>(polygon); - - for (const auto &i: indices) - screenIndices << quint32(i); -} - -/*! - \internal -*/ -// This one does only a perimeter -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, - const QList<QGeoCoordinate> &perimeter) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - srcOrigin_ = geoLeftBound_; - - QDoubleVector2D leftBoundWrapped; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - QList<QDoubleVector2D> wrappedPath; - QDeclarativeGeoMapItemUtils::wrapPath(perimeter, geoLeftBound_, p, - wrappedPath, &leftBoundWrapped); - - // 1.1) do the same for the bbox - QList<QDoubleVector2D> wrappedBbox, wrappedBboxPlus1, wrappedBboxMinus1; - QGeoPolygon bbox(QGeoPath(perimeter).boundingGeoRectangle()); - QDeclarativeGeoMapItemUtils::wrapPath(bbox.perimeter(), bbox.boundingGeoRectangle().topLeft(), p, - wrappedBbox, wrappedBboxMinus1, wrappedBboxPlus1, &m_bboxLeftBoundWrapped); - - // 2) Store the triangulated polygon, and the wrapped bbox paths. - // the triangulations can be used as they are, as they "bypass" the QtQuick display chain - // the bbox wraps have to be however clipped, and then projected, in order to figure out the geometry. - // Note that this might still cause the geometryChange method to fail under some extreme conditions. - cutPathEars(wrappedPath, m_screenVertices, m_screenIndices); - - m_wrappedPolygons.resize(3); - m_wrappedPolygons[0].wrappedBboxes = wrappedBboxMinus1; - m_wrappedPolygons[1].wrappedBboxes = wrappedBbox; - m_wrappedPolygons[2].wrappedBboxes = wrappedBboxPlus1; -} - -// This one handles whole QGeoPolygon w. holes -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoPolygon &poly) -{ - if (!sourceDirty_) - return; - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - - // build the actual path - // The approach is the same as described in QGeoMapPolylineGeometry::updateSourcePoints - srcOrigin_ = geoLeftBound_; - - QDoubleVector2D leftBoundWrapped; - QList<QList<QDoubleVector2D>> wrappedPath; - // 1) pre-compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0 - wrapPath(poly, geoLeftBound_, p, - wrappedPath, &leftBoundWrapped); - - // 1.1) do the same for the bbox - QList<QDoubleVector2D> wrappedBbox, wrappedBboxPlus1, wrappedBboxMinus1; - QGeoPolygon bbox(poly.boundingGeoRectangle()); - QDeclarativeGeoMapItemUtils::wrapPath(bbox.perimeter(), bbox.boundingGeoRectangle().topLeft(), p, - wrappedBbox, wrappedBboxMinus1, wrappedBboxPlus1, &m_bboxLeftBoundWrapped); - - // 2) Store the triangulated polygon, and the wrapped bbox paths. - // the triangulations can be used as they are, as they "bypass" the QtQuick display chain - // the bbox wraps have to be however clipped, and then projected, in order to figure out the geometry. - // Note that this might still cause the geometryChange method to fail under some extreme conditions. - cutPathEars(wrappedPath, m_screenVertices, m_screenIndices); - m_wrappedPolygons.resize(3); - m_wrappedPolygons[0].wrappedBboxes = wrappedBboxMinus1; - m_wrappedPolygons[1].wrappedBboxes = wrappedBbox; - m_wrappedPolygons[2].wrappedBboxes = wrappedBboxPlus1; -} - -void QGeoMapPolygonGeometryOpenGL::updateSourcePoints(const QGeoMap &map, const QGeoRectangle &rect) -{ - if (!sourceDirty_) - return; - const QList<QGeoCoordinate> perimeter = QGeoMapItemGeometry::path(rect); - updateSourcePoints(map, perimeter); -} - -/*! - \internal -*/ -void QGeoMapPolygonGeometryOpenGL::updateScreenPoints(const QGeoMap &map, qreal strokeWidth , const QColor &strokeColor) -{ - if (map.viewportWidth() == 0 || map.viewportHeight() == 0) { - clear(); - return; - } - - // 1) identify which set to use: std, +1 or -1 - const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection()); - const QDoubleVector2D leftBoundMercator = p.geoToMapProjection(srcOrigin_); - m_wrapOffset = p.projectionWrapFactor(leftBoundMercator) + 1; // +1 to get the offset into QLists - - // 1.1) select geometry set - // This could theoretically be skipped for those polygons whose bbox is not even projectable. - // However, such optimization could only be introduced if not calculating bboxes lazily. - // Hence not doing it. - if (sourceDirty_) { - m_dataChanged = true; - } - - if (strokeWidth == 0.0 || strokeColor.alpha() == 0) // or else the geometry of the border is used, so no point in calculating 2 of them - updateQuickGeometry(p, strokeWidth); -} - -void QGeoMapPolygonGeometryOpenGL::updateQuickGeometry(const QGeoProjectionWebMercator &p, qreal /*strokeWidth*/) -{ - // 2) clip bbox - // BBox handling -- this is related to the bounding box geometry - // that has to inevitably follow the old projection codepath - // As it needs to provide projected coordinates for QtQuick interaction. - // This could be futher optimized to be updated in a lazy fashion. - const QList<QDoubleVector2D> &wrappedBbox = m_wrappedPolygons.at(m_wrapOffset).wrappedBboxes; - QList<QList<QDoubleVector2D> > clippedBbox; - QDoubleVector2D bboxLeftBoundWrapped = m_bboxLeftBoundWrapped; - bboxLeftBoundWrapped.setX(bboxLeftBoundWrapped.x() + double(m_wrapOffset - 1)); - QDeclarativeGeoMapItemUtils::clipPolygon(wrappedBbox, p, clippedBbox, &bboxLeftBoundWrapped); - - // 3) project bbox - QPainterPath ppi; - if (!clippedBbox.size() || clippedBbox.first().size() < 3) { - sourceBounds_ = screenBounds_ = QRectF(); - firstPointOffset_ = QPointF(); - screenOutline_ = ppi; - return; - } - - QDeclarativeGeoMapItemUtils::projectBbox(clippedBbox.first(), p, ppi); // Using first because a clipped box should always result in one polygon - const QRectF brect = ppi.boundingRect(); - firstPointOffset_ = QPointF(brect.topLeft()); - screenOutline_ = ppi; - - // 4) Set Screen bbox - screenBounds_ = brect; - sourceBounds_.setX(0); - sourceBounds_.setY(0); - sourceBounds_.setWidth(brect.width()); - sourceBounds_.setHeight(brect.height()); -} - -QDeclarativePolygonMapItemPrivateOpenGL::~QDeclarativePolygonMapItemPrivateOpenGL() {} /* * QDeclarativePolygonMapItem Implementation */ @@ -986,26 +719,6 @@ void QDeclarativePolygonMapItem::geometryChange(const QRectF &newGeometry, const ////////////////////////////////////////////////////////////////////// -QSGMaterialShader *MapPolygonMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const -{ - Q_UNUSED(renderMode); - return new MapPolygonShader(); -} - -int MapPolygonMaterial::compare(const QSGMaterial *other) const -{ - const MapPolygonMaterial &o = *static_cast<const MapPolygonMaterial *>(other); - if (o.m_center == m_center && o.m_geoProjection == m_geoProjection && o.m_wrapOffset == m_wrapOffset) - return QSGFlatColorMaterial::compare(other); - return -1; -} - -QSGMaterialType *MapPolygonMaterial::type() const -{ - static QSGMaterialType type; - return &type; -} - MapPolygonNode::MapPolygonNode() : border_(new MapPolylineNode()), geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) @@ -1056,106 +769,4 @@ void MapPolygonNode::update(const QColor &fillColor, const QColor &borderColor, } } -MapPolygonNodeGL::MapPolygonNodeGL() : - //fill_material_(this), - fill_material_(), - geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) -{ - geometry_.setDrawingMode(QSGGeometry::DrawTriangles); - QSGGeometryNode::setMaterial(&fill_material_); - QSGGeometryNode::setGeometry(&geometry_); -} - -MapPolygonNodeGL::~MapPolygonNodeGL() -{ -} - -/*! - \internal -*/ -void MapPolygonNodeGL::update(const QColor &fillColor, - const QGeoMapPolygonGeometryOpenGL *fillShape, - const QMatrix4x4 &geoProjection, - const QDoubleVector3D ¢er) -{ - if (fillShape->m_screenIndices.size() < 3 || fillColor.alpha() == 0) { - setSubtreeBlocked(true); - return; - } - setSubtreeBlocked(false); - - QSGGeometry *fill = QSGGeometryNode::geometry(); - if (fillShape->m_dataChanged || !fill->vertexCount()) { - fillShape->allocateAndFillPolygon(fill); - markDirty(DirtyGeometry); - fillShape->m_dataChanged = false; - } - - //if (fillColor != fill_material_.color()) // Any point in optimizing this? - { - fill_material_.setColor(fillColor); - fill_material_.setGeoProjection(geoProjection); - fill_material_.setCenter(center); - fill_material_.setWrapOffset(fillShape->m_wrapOffset - 1); - setMaterial(&fill_material_); - markDirty(DirtyMaterial); - } -} - -MapPolygonShader::MapPolygonShader() : QSGMaterialShader(*new QSGMaterialShaderPrivate(this)) -{ - setShaderFileName(VertexStage, QLatin1String(":/location/quickmapitems/shaders/polygon.vert.qsb")); - setShaderFileName(FragmentStage, QLatin1String(":/location/quickmapitems/shaders/polygon.frag.qsb")); -} - -bool MapPolygonShader::updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - MapPolygonMaterial *oldMaterial = static_cast<MapPolygonMaterial *>(oldEffect); - MapPolygonMaterial *newMaterial = static_cast<MapPolygonMaterial *>(newEffect); - - const QColor &c = newMaterial->color(); - const QMatrix4x4 &geoProjection = newMaterial->geoProjection(); - const QDoubleVector3D ¢er = newMaterial->center(); - - // It is safer to use vec4 instead on vec3, as described in: - // https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout - QVector4D vecCenter, vecCenter_lowpart; - for (int i = 0; i < 3; i++) - QLocationUtils::split_double(center.get(i), &vecCenter[i], &vecCenter_lowpart[i]); - vecCenter[3] = 0; - vecCenter_lowpart[3] = 0; - - int offset = 0; - char *buf_p = state.uniformData()->data(); - - if (state.isMatrixDirty()) { - const QMatrix4x4 m = state.projectionMatrix(); - memcpy(buf_p + offset, m.constData(), 4*4*4); - } - offset += 4*4*4; - - memcpy(buf_p + offset, geoProjection.constData(), 4*4*4); offset+=4*4*4; - - memcpy(buf_p + offset, &vecCenter, 4*4); offset += 4*4; - - memcpy(buf_p + offset, &vecCenter_lowpart, 4*4); offset+=4*4; - - const float wrapOffset = newMaterial->wrapOffset(); - memcpy(buf_p + offset, &wrapOffset, 4); offset+=4; - - offset += 4+4+4; // Padding - - if (oldMaterial == nullptr || c != oldMaterial->color() || state.isOpacityDirty()) { - float opacity = state.opacity() * c.alphaF(); - QVector4D v(c.redF() * opacity, - c.greenF() * opacity, - c.blueF() * opacity, - opacity); - memcpy(buf_p + offset, &v, 4*4); - } - offset+=4*4; - - return true; -} QT_END_NAMESPACE |