diff options
author | Michal Klocek <michal.klocek@digia.com> | 2011-12-13 10:30:10 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-12-13 12:58:25 +0100 |
commit | 68e2fc8934756e299b04642682d1d8203e971399 (patch) | |
tree | e602d68bf4ddd87421e450be73bc8429108faeb2 | |
parent | fc576c395676bb766e4a14f8fb38df7e7498ccbf (diff) | |
download | qtlocation-68e2fc8934756e299b04642682d1d8203e971399.tar.gz |
Reimplement mapitems
* fixes performance issue on high zoomLevels
* fixes "pop" effect when zooming
* fixes flickering when zooming circle
* remove qquickpainteditem
* adds map mapitem graphical representation as geometry node
* add basic vertex drawing support
* removes updateContent, mapChanged, contentLeftPoint
Change-Id: Ic76b24c7e47f83c2a45a680607c46595e5a9a790
Reviewed-by: Michal Klocek <michal.klocek@digia.com>
Reviewed-by: Juha Vuolle <juha.vuolle@nokia.com>
-rw-r--r-- | src/imports/location/qdeclarativecirclemapitem.cpp | 380 | ||||
-rw-r--r-- | src/imports/location/qdeclarativecirclemapitem_p.h | 81 | ||||
-rw-r--r-- | src/imports/location/qdeclarativegeomapitembase.cpp | 30 | ||||
-rw-r--r-- | src/imports/location/qdeclarativegeomapitembase_p.h | 17 | ||||
-rw-r--r-- | src/imports/location/qdeclarativegeomapquickitem.cpp | 108 | ||||
-rw-r--r-- | src/imports/location/qdeclarativegeomapquickitem_p.h | 12 | ||||
-rw-r--r-- | src/imports/location/qdeclarativepolygonmapitem.cpp | 294 | ||||
-rw-r--r-- | src/imports/location/qdeclarativepolygonmapitem_p.h | 76 | ||||
-rw-r--r-- | src/imports/location/qdeclarativepolylinemapitem.cpp | 304 | ||||
-rw-r--r-- | src/imports/location/qdeclarativepolylinemapitem_p.h | 77 | ||||
-rw-r--r-- | src/imports/location/qdeclarativerectanglemapitem.cpp | 308 | ||||
-rw-r--r-- | src/imports/location/qdeclarativerectanglemapitem_p.h | 75 | ||||
-rw-r--r-- | src/imports/location/qdeclarativeroutemapitem.cpp | 88 | ||||
-rw-r--r-- | src/imports/location/qdeclarativeroutemapitem_p.h | 16 |
14 files changed, 820 insertions, 1046 deletions
diff --git a/src/imports/location/qdeclarativecirclemapitem.cpp b/src/imports/location/qdeclarativecirclemapitem.cpp index b6fdeada..a2e2a026 100644 --- a/src/imports/location/qdeclarativecirclemapitem.cpp +++ b/src/imports/location/qdeclarativecirclemapitem.cpp @@ -54,6 +54,11 @@ QT_BEGIN_NAMESPACE #define M_PI 3.14159265358979323846 #endif +struct Vertex +{ + QVector2D position; +}; + static const qreal qgeocoordinate_EARTH_MEAN_RADIUS = 6371.0072; inline static qreal qgeocoordinate_degToRad(qreal deg) @@ -65,9 +70,8 @@ inline static qreal qgeocoordinate_radToDeg(qreal rad) return rad * 180 / M_PI; } -static QPolygonF createPolygon(const Map& map, const QList<QGeoCoordinate> &path, qreal& w, qreal& h) +static void updatePolygon(QPolygonF& points,const Map& map, const QList<QGeoCoordinate> &path, qreal& w, qreal& h) { - QPolygonF points; qreal minX, maxX, minY, maxY; //TODO: dateline handling @@ -99,23 +103,82 @@ static QPolygonF createPolygon(const Map& map, const QList<QGeoCoordinate> &path w = maxX - minX; h = maxY - minY; +} + +static void calcualtePeripheralPoints(QList<QGeoCoordinate>& path, const QGeoCoordinate& center, qreal distance, int steps) +{ + // get angular distance in radians + distance = distance / (qgeocoordinate_EARTH_MEAN_RADIUS * 1000); - return points; + // We are using horizontal system, we have radius (distance) + // projected onto Celestial sphere. + // This way we know the altitude in horizontal system => h = 90 - r; + // We can now "spin" around with azimuth as a step to get all the points from + // peripheral of the given circle. + // To get geographical position we need to change from horizontal system + // to equatorial system. + + // get location + qreal lat = qgeocoordinate_degToRad(center.latitude()); + qreal lon = qgeocoordinate_degToRad(center.longitude()); + + // precalculate + qreal cos_h = sin(distance); + qreal sin_h = cos(distance); + qreal cos_phi = cos(lat), sin_phi = sin(lat); + qreal sin_phi_x_sin_h = sin_phi * sin_h; + qreal cos_phi_x_cos_h = cos_phi * cos_h; + qreal sin_phi_x_cos_h = sin_phi * cos_h; + qreal cos_phi_x_sin_h = cos_phi * sin_h; + + for (int i = 0; i < steps; ++i) { + + qreal a = 2 * M_PI * i / steps; + qreal sin_delta = sin_phi_x_sin_h - cos_phi_x_cos_h * cos(a); + qreal cos_delta_x_cos_tau = cos_phi_x_sin_h + sin_phi_x_cos_h * cos(a); + qreal cos_delta_x_sin_tau = -sin(a) * cos_h; + // get the hour angle (use Cartesian to polar conversion) + qreal tau = atan2(cos_delta_x_sin_tau, cos_delta_x_cos_tau); + qreal cos_delta = sqrt(cos_delta_x_sin_tau + * cos_delta_x_sin_tau + cos_delta_x_cos_tau + * cos_delta_x_cos_tau); + // get declination ( use Cartesian to polar conversion ) + qreal delta = atan2(sin_delta, cos_delta); + // get right ascension from tau , use a greenwich star time of 0 + qreal alpha = lon - tau; + qreal lat2 = qgeocoordinate_radToDeg(delta); + qreal lon2 = qgeocoordinate_radToDeg(alpha); + if (lon2 < -180.0) { + lon2 += 360.0; + } else if (lon2 > 180.0) { + lon2 -= 360.0; + } + path << QGeoCoordinate(lat2, lon2, 0.0f); + } } QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent): - QDeclarativeGeoMapItemBase(parent), + QDeclarativeGeoMapItemBase(parent), center_(0), - circleItem_(new CircleMapPaintedItem(this)), + mapCircleNode_(0), + radius_(0), + zoomLevel_(0.0), dragActive_(false) + { - circleItem_->setParentItem(this); + setFlag(ItemHasContents, true); } QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem() { } +void QDeclarativeCircleMapItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) +{ + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map) QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); +} + void QDeclarativeCircleMapItem::setCenter(QDeclarativeCoordinate *center) { if (center_ == center) @@ -123,10 +186,8 @@ void QDeclarativeCircleMapItem::setCenter(QDeclarativeCoordinate *center) if (center_) center_->disconnect(this); center_ = center; - if (!center_) { - circleItem_->setCenter(QGeoCoordinate()); - } else { - circleItem_->setCenter(center_->coordinate()); + + if (center_) { connect(center_, SIGNAL(latitudeChanged(double)), this, SLOT(updateMapItem())); connect(center_, SIGNAL(longitudeChanged(double)), this, @@ -134,8 +195,9 @@ void QDeclarativeCircleMapItem::setCenter(QDeclarativeCoordinate *center) connect(center_, SIGNAL(altitudeChanged(double)), this, SLOT(updateMapItem())); } + + updateMapItem(true); emit centerChanged(center_); - updateMapItem(); } QDeclarativeCoordinate* QDeclarativeCircleMapItem::center() @@ -143,66 +205,80 @@ QDeclarativeCoordinate* QDeclarativeCircleMapItem::center() return center_; } -void QDeclarativeCircleMapItem::updateContent() +void QDeclarativeCircleMapItem::setColor(const QColor &color) { - circleItem_->updateGeometry(); - setWidth(circleItem_->width()); - setHeight(circleItem_->height()); + if (color_ == color) + return; + color_ = color; + updateMapItem(false); + emit colorChanged(color_); } -QPointF QDeclarativeCircleMapItem::contentTopLeftPoint() +QColor QDeclarativeCircleMapItem::color() const { - return map_->coordinateToScreenPosition(center()->coordinate(), false) - QPointF(width(),height()) / 2; + return color_; } -void QDeclarativeCircleMapItem::mapChanged() +void QDeclarativeCircleMapItem::setRadius(qreal radius) { - circleItem_->setMap(map_); - if (map_) { - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); - // initial update - handleCameraDataChanged(map_->cameraData()); - } -} -void QDeclarativeCircleMapItem::handleCenterCoordinateChanged() -{ - circleItem_->setCenter(center_->coordinate()); -} + if (radius_ == radius) + return; -void QDeclarativeCircleMapItem::handleCameraDataChanged(const CameraData& cameraData) -{ - circleItem_->setZoomLevel(cameraData.zoomFactor()); - updateMapItem(); + radius_ = radius; + updateMapItem(true); + emit radiusChanged(radius); } -void QDeclarativeCircleMapItem::setColor(const QColor &color) +qreal QDeclarativeCircleMapItem::radius() const { - if (color_ == color) - return; - color_ = color; - QBrush m_brush(color); - circleItem_->setBrush(m_brush); - emit colorChanged(color_); + return radius_; } -QColor QDeclarativeCircleMapItem::color() const + +QSGNode* QDeclarativeCircleMapItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) { - return color_; + Q_UNUSED(data); + + MapCircleNode *node = static_cast<MapCircleNode*>(oldNode); + + if (!node) { + mapCircleNode_ = new MapCircleNode(); + updateMapItem(true); + } + + mapCircleNode_->update(); + return mapCircleNode_; } -void QDeclarativeCircleMapItem::setRadius(qreal radius) +void QDeclarativeCircleMapItem::updateMapItem(bool dirtyGeometry) { - if (circleItem_->radius() == radius) + if (!map() || !center() || !center()->coordinate().isValid() || !mapCircleNode_) return; - circleItem_->setRadius(radius); - updateMapItem(); - emit radiusChanged(radius); + + mapCircleNode_->setBrushColor(color_); + + if (dirtyGeometry) mapCircleNode_->setGeometry(*map(), radius(),center()->coordinate()); + + const QSizeF& size = mapCircleNode_->size(); + + setWidth(size.width()); + setHeight(size.height()); + + setPositionOnMap(center()->coordinate(), QPointF(size.width(),size.height()) / 2); + update(); + } -qreal QDeclarativeCircleMapItem::radius() const +void QDeclarativeCircleMapItem::handleCameraDataChanged(const CameraData& cameraData) { - return circleItem_->radius(); + if (cameraData.zoomFactor() != zoomLevel_) { + zoomLevel_ = cameraData.zoomFactor(); + updateMapItem(true); + } + else { + updateMapItem(false); + } } void QDeclarativeCircleMapItem::dragEnded() @@ -211,7 +287,7 @@ void QDeclarativeCircleMapItem::dragEnded() return; dragActive_ = false; QPointF newPoint = QPointF(x(),y()) + QPointF(width(), height()) / 2; - QGeoCoordinate newCoordinate = map_->screenPositionToCoordinate(newPoint, false); + QGeoCoordinate newCoordinate = map()->screenPositionToCoordinate(newPoint, false); if (newCoordinate.isValid()) { internalCoordinate_.setCoordinate(newCoordinate); setCenter(&internalCoordinate_); @@ -225,204 +301,98 @@ void QDeclarativeCircleMapItem::dragStarted() bool QDeclarativeCircleMapItem::contains(QPointF point) { - return circleItem_->contains(point); + return mapCircleNode_->contains(point); } -void QDeclarativeCircleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - // TODO - if X and Y of the wrapper item are changed, currently - // the item moves, but returns to old position when map camera changes - QQuickItem::geometryChanged(newGeometry, oldGeometry); -} ////////////////////////////////////////////////////////////////////// -CircleMapPaintedItem::CircleMapPaintedItem(QQuickItem *parent): - QQuickPaintedItem(parent), - map_(0), - zoomLevel_(-1), - initialized_(false), - dirtyGeometry_(false) +MapCircleNode::MapCircleNode(): + fillColor_(Qt::black), + borderColor_(Qt::black), + geometry_(QSGGeometry::defaultAttributes_Point2D(),0) { - setAntialiasing(true); - connect(this, SIGNAL(xChanged()), this, SLOT(update())); - connect(this, SIGNAL(yChanged()), this, SLOT(update())); + geometry_.setDrawingMode(GL_TRIANGLE_FAN); + QSGGeometryNode::setMaterial(&fill_material_); + QSGGeometryNode::setGeometry(&geometry_); } -CircleMapPaintedItem::~CircleMapPaintedItem() {} +MapCircleNode::~MapCircleNode() {} -void CircleMapPaintedItem::setMap(Map* map) +void MapCircleNode::update() { - if (map_ == map) + //TODO: optimize , perform calculation only if polygon has changed + if (polygon_.size()==0) return; - map_ = map; -} -Map* CircleMapPaintedItem::map() -{ - return map_; -} + QSGGeometry *fill = QSGGeometryNode::geometry(); -void CircleMapPaintedItem::setZoomLevel(qreal zoomLevel) -{ - if (zoomLevel_ == zoomLevel) - return; - zoomLevel_ = zoomLevel; - dirtyGeometry_ = true; -} + Q_ASSERT(fill->sizeOfVertex() == sizeof(Vertex)); -qreal CircleMapPaintedItem::zoomLevel() const -{ - return zoomLevel_; -} - -void CircleMapPaintedItem::paint(QPainter *painter) -{ - if (!initialized_) - return; - - painter->setPen(pen_); - painter->setBrush(brush_); - painter->drawConvexPolygon(polygon_); -} + int fillVertexCount = 0; + //note this will not allocate new buffer if the size has not changed + fill->allocate(polygon_.size() + 1 + 1); //one for center + one to close the circle -void CircleMapPaintedItem::updateGeometry() -{ - if (!dirtyGeometry_) - return; - - initialized_ = false; - if (!map_) - return; + Vertex *vertices = (Vertex *)fill->vertexData(); - if (!centerCoord_.isValid() || radius_ <= 0) - return; + //set center + vertices[fillVertexCount++].position = QVector2D(size_.width()/2,size_.height()/2); - if (zoomLevel_ == -1) - return; - - QPointF center = map_->coordinateToScreenPosition(centerCoord_, false); - - qreal w = 0; - qreal h = 0; - //TODO: execute only for radius or center changes - path_.clear(); - calcualtePeripheralPoints(path_, centerCoord_, radius_, 125); - //TODO: optimize essential part - polygon_ = createPolygon(*map_, path_, w, h); - - setWidth(w); - setHeight(h); - setContentsSize(QSize(w, h)); - - initialized_ = true; - dirtyGeometry_ = false; - update(); // qquickpainteditem -} - -void CircleMapPaintedItem::calcualtePeripheralPoints(QList<QGeoCoordinate>& path, const QGeoCoordinate& center, qreal distance, int steps) const -{ - // get angular distance in radians - distance = distance / (qgeocoordinate_EARTH_MEAN_RADIUS * 1000); - - // We are using horizontal system, we have radius (distance) - // projected onto Celestial sphere. - // This way we know the altitude in horizontal system => h = 90 - r; - // We can now "spin" around with azimuth as a step to get all the points from - // peripheral of the given circle. - // To get geographical position we need to change from horizontal system - // to equatorial system. - - // get location - qreal lat = qgeocoordinate_degToRad(center.latitude()); - qreal lon = qgeocoordinate_degToRad(center.longitude()); + for (int i = 0; i < polygon_.size(); ++i) { + vertices[fillVertexCount++].position = QVector2D(polygon_.at(i)); + } + //close circle + vertices[fillVertexCount++].position = QVector2D(polygon_.at(0)); - // precalculate - qreal cos_h = sin(distance); - qreal sin_h = cos(distance); - qreal cos_phi = cos(lat), sin_phi = sin(lat); - qreal sin_phi_x_sin_h = sin_phi * sin_h; - qreal cos_phi_x_cos_h = cos_phi * cos_h; - qreal sin_phi_x_cos_h = sin_phi * cos_h; - qreal cos_phi_x_sin_h = cos_phi * sin_h; + Q_ASSERT(fillVertexCount == fill->vertexCount()); - for (int i = 0; i < steps; ++i) { + markDirty(DirtyGeometry); - qreal a = 2 * M_PI * i / steps; - qreal sin_delta = sin_phi_x_sin_h - cos_phi_x_cos_h * cos(a); - qreal cos_delta_x_cos_tau = cos_phi_x_sin_h + sin_phi_x_cos_h * cos(a); - qreal cos_delta_x_sin_tau = -sin(a) * cos_h; - // get the hour angle (use Cartesian to polar conversion) - qreal tau = atan2(cos_delta_x_sin_tau, cos_delta_x_cos_tau); - qreal cos_delta = sqrt(cos_delta_x_sin_tau - * cos_delta_x_sin_tau + cos_delta_x_cos_tau - * cos_delta_x_cos_tau); - // get declination ( use Cartesian to polar conversion ) - qreal delta = atan2(sin_delta, cos_delta); - // get right ascension from tau , use a greenwich star time of 0 - qreal alpha = lon - tau; - qreal lat2 = qgeocoordinate_radToDeg(delta); - qreal lon2 = qgeocoordinate_radToDeg(alpha); - if (lon2 < -180.0) { - lon2 += 360.0; - } else if (lon2 > 180.0) { - lon2 -= 360.0; - } - path << QGeoCoordinate(lat2, lon2, 0.0f); + if (fillColor_ != fill_material_.color()) { + fill_material_.setColor(fillColor_); + setMaterial(&fill_material_); } -} - - -void CircleMapPaintedItem::setBrush(const QBrush &brush) -{ - brush_ = brush; -} -QBrush CircleMapPaintedItem::brush() const -{ - return brush_; + //TODO: implement me : borders , gradient } -void CircleMapPaintedItem::setPen(const QPen &pen) +void MapCircleNode::setBrushColor(const QColor &color) { - pen_ = pen; + fillColor_= color; } -QPen CircleMapPaintedItem::pen() const +QColor MapCircleNode::brushColor() const { - return pen_; + return fillColor_; } -void CircleMapPaintedItem::setCenter(const QGeoCoordinate ¢er) +void MapCircleNode::setPenColor(const QColor &color) { - if (centerCoord_ == center) - return; - centerCoord_ = center; - dirtyGeometry_ = true; + borderColor_ = color; } -const QGeoCoordinate& CircleMapPaintedItem::center() const +QColor MapCircleNode::penColor() const { - return centerCoord_; + return borderColor_; } -bool CircleMapPaintedItem::contains(QPointF point) +bool MapCircleNode::contains(QPointF point) { return polygon_.containsPoint(point, Qt::OddEvenFill); } -void CircleMapPaintedItem::setRadius(qreal radius) + +void MapCircleNode::setGeometry(const Map& map, qreal radius,const QGeoCoordinate ¢er) { - if (radius_ == radius) - return; + path_.clear(); + calcualtePeripheralPoints(path_, center, radius, 125); - radius_ = radius; - dirtyGeometry_ = true; -} + qreal w = 0; + qreal h = 0; -qreal CircleMapPaintedItem::radius() const -{ - return radius_; + polygon_.clear(); + updatePolygon(polygon_, map, path_, w, h); + size_ = QSizeF(w, h); } QT_END_NAMESPACE diff --git a/src/imports/location/qdeclarativecirclemapitem_p.h b/src/imports/location/qdeclarativecirclemapitem_p.h index 012274d9..886c9fa0 100644 --- a/src/imports/location/qdeclarativecirclemapitem_p.h +++ b/src/imports/location/qdeclarativecirclemapitem_p.h @@ -43,12 +43,13 @@ #define QDECLARATIVECIRCLEMAPITEM_H #include "qdeclarativegeomapitembase_p.h" -#include <QPen> -#include <QBrush> +#include <QSGGeometryNode> +#include <QSGFlatColorMaterial> QT_BEGIN_NAMESPACE -class CircleMapPaintedItem; +class QDeclarativeGeoMapQuickItem; +class MapCircleNode; class QDeclarativeCircleMapItem : public QDeclarativeGeoMapItemBase { @@ -61,6 +62,10 @@ public: QDeclarativeCircleMapItem(QQuickItem *parent = 0); ~QDeclarativeCircleMapItem(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + //from QuickItem + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QDeclarativeCoordinate* center(); void setCenter(QDeclarativeCoordinate* center); @@ -70,6 +75,7 @@ public: QColor color() const; void setColor(const QColor &color); + void dragStarted(); void dragEnded(); bool contains(QPointF point); @@ -79,71 +85,62 @@ Q_SIGNALS: void radiusChanged(qreal radius); void colorChanged(const QColor &color); -protected: - void updateContent(); - QPointF contentTopLeftPoint(); - void mapChanged(); - // from qquickitem - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); +protected Q_SLOTS: + virtual void updateMapItem(bool dirtyGeomoetry=true); private Q_SLOTS: void handleCameraDataChanged(const CameraData& cameraData); - void handleCenterCoordinateChanged(); private: + //TODO: pimpl QDeclarativeCoordinate internalCoordinate_; QDeclarativeCoordinate *center_; - CircleMapPaintedItem *circleItem_; + MapCircleNode *mapCircleNode_; QColor color_; + qreal radius_; + qreal zoomLevel_; bool dragActive_; }; ////////////////////////////////////////////////////////////////////// -class CircleMapPaintedItem: public QQuickPaintedItem +class MapCircleNode: public QSGGeometryNode { public: - CircleMapPaintedItem(QQuickItem *parent = 0); - ~CircleMapPaintedItem(); + MapCircleNode(); + ~MapCircleNode(); - void setMap(Map* map); - Map* map(); - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; - - void setCenter(const QGeoCoordinate ¢er); - const QGeoCoordinate& center() const; - - void setRadius(qreal radius); - qreal radius() const; + void setSize(const QSize &size); + QSizeF size() const { + return size_; + } - void paint(QPainter *painter); + QColor penColor() const; + void setPenColor(const QColor &pen); - QPen pen() const; - void setPen(const QPen &pen); - - QBrush brush() const; - void setBrush(const QBrush &brush); + QColor brushColor() const; + void setBrushColor(const QColor &color); + void update(); bool contains(QPointF point); - void updateGeometry(); + void setGeometry(const Map &map, qreal radius,const QGeoCoordinate ¢er); private: - void calcualtePeripheralPoints(QList<QGeoCoordinate>& path, const QGeoCoordinate& center, qreal distance, int steps) const; - - Map *map_; - qreal zoomLevel_; - QGeoCoordinate centerCoord_; - qreal radius_; - QPen pen_; - QBrush brush_; - QPolygonF polygon_; + QSGFlatColorMaterial fill_material_; + //QSGFlatColorMaterial border_material_; + QColor fillColor_; + QColor borderColor_; + //keeps pixel geometry + QSGGeometry geometry_; + //keeps geographic geometry QList<QGeoCoordinate> path_; - bool initialized_; - bool dirtyGeometry_; + QPolygonF polygon_; + QSizeF size_; }; QT_END_NAMESPACE +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativeCircleMapItem)); + #endif /* QDECLARATIVECIRCLEMAPITEM_H */ diff --git a/src/imports/location/qdeclarativegeomapitembase.cpp b/src/imports/location/qdeclarativegeomapitembase.cpp index 572b8258..4d48e37c 100644 --- a/src/imports/location/qdeclarativegeomapitembase.cpp +++ b/src/imports/location/qdeclarativegeomapitembase.cpp @@ -46,12 +46,8 @@ QT_BEGIN_NAMESPACE QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent) : QQuickItem(parent), map_(0), - quickMap_(0), - inUpdate_(false) + quickMap_(0) { - setParentItem(parent); - setFlag(ItemHasContents, true); - setAcceptHoverEvents(false); } QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase() @@ -61,9 +57,6 @@ QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase() quickMap_->removeMapItem(this); } -void QDeclarativeGeoMapItemBase::mapChanged() -{ -} bool QDeclarativeGeoMapItemBase::contains(QPointF point) { @@ -79,10 +72,6 @@ void QDeclarativeGeoMapItemBase::dragEnded() { } -void QDeclarativeGeoMapItemBase::updateContent() -{ -} - void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, Map *map) { if (quickMap == quickMap_) return; @@ -94,18 +83,15 @@ void QDeclarativeGeoMapItemBase::setMap(QDeclarativeGeoMap *quickMap, Map *map) map_->disconnect(this); quickMap_ = quickMap; map_ = map; - mapChanged(); - updateMapItem(); } -void QDeclarativeGeoMapItemBase::updateMapItem() +void QDeclarativeGeoMapItemBase::setPositionOnMap(const QGeoCoordinate& coordinate, const QPointF& offset) { - if (inUpdate_ || !map_ || !quickMap_) + if (!map_ || !quickMap_) return; - inUpdate_ = true; - updateContent(); - QPointF topLeft = contentTopLeftPoint(); + QPointF topLeft = map_->coordinateToScreenPosition(coordinate, false) - offset; + if ((topLeft.x() > quickMap()->width()) || (topLeft.x() + width() < 0) || (topLeft.y() + height() < 0) @@ -115,12 +101,6 @@ void QDeclarativeGeoMapItemBase::updateMapItem() setVisible(true); setPos(topLeft); } - inUpdate_ = false; -} - -QDeclarativeGeoMap* QDeclarativeGeoMapItemBase::quickMap() -{ - return quickMap_; } #include "moc_qdeclarativegeomapitembase_p.cpp" diff --git a/src/imports/location/qdeclarativegeomapitembase_p.h b/src/imports/location/qdeclarativegeomapitembase_p.h index 3c303493..03adff7b 100644 --- a/src/imports/location/qdeclarativegeomapitembase_p.h +++ b/src/imports/location/qdeclarativegeomapitembase_p.h @@ -56,23 +56,22 @@ public: QDeclarativeGeoMapItemBase(QQuickItem *parent = 0); virtual ~QDeclarativeGeoMapItemBase(); - void setMap(QDeclarativeGeoMap* quickMap, Map *map); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + virtual void setPositionOnMap(const QGeoCoordinate& coordinate, const QPointF& offset); virtual bool contains(QPointF point); virtual void dragStarted(); virtual void dragEnded(); - QDeclarativeGeoMap* quickMap(); - protected Q_SLOTS: - virtual void updateMapItem(); + QDeclarativeGeoMap* quickMap() {return quickMap_;} + Map* map() {return map_;} -protected: - virtual void mapChanged(); - virtual void updateContent(); - virtual QPointF contentTopLeftPoint() = 0; +protected Q_SLOT: + virtual void updateMapItem(bool dirtyGeometry = true) = 0; + +private: Map* map_; QDeclarativeGeoMap* quickMap_; - bool inUpdate_; }; QT_END_NAMESPACE diff --git a/src/imports/location/qdeclarativegeomapquickitem.cpp b/src/imports/location/qdeclarativegeomapquickitem.cpp index 0f0f070f..1de6597c 100644 --- a/src/imports/location/qdeclarativegeomapquickitem.cpp +++ b/src/imports/location/qdeclarativegeomapquickitem.cpp @@ -61,7 +61,10 @@ QDeclarativeGeoMapQuickItem::QDeclarativeGeoMapQuickItem(QQuickItem *parent) zoomLevel_(0.0), inUpdate_(false), mapAndSourceItemSet_(false), - dragActive_(true) {} + dragActive_(true) +{ + setFlag(ItemHasContents, true); +} QDeclarativeGeoMapQuickItem::~QDeclarativeGeoMapQuickItem() {} @@ -72,31 +75,46 @@ void QDeclarativeGeoMapQuickItem::setCoordinate(QDeclarativeCoordinate *coordina if (coordinate_) coordinate_->disconnect(this); coordinate_ = coordinate; - update(); + if (coordinate_) { connect(coordinate_, SIGNAL(latitudeChanged(double)), this, - SLOT(coordinateCoordinateChanged(double))); + SLOT(updateMapItem())); connect(coordinate_, SIGNAL(longitudeChanged(double)), this, - SLOT(coordinateCoordinateChanged(double))); + SLOT(updateMapItem())); connect(coordinate_, SIGNAL(altitudeChanged(double)), this, - SLOT(coordinateCoordinateChanged(double))); + SLOT(updateMapItem())); } + + updateMapItem(); + emit coordinateChanged(); } +void QDeclarativeGeoMapQuickItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) +{ + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map && quickMap) { + QObject::connect(quickMap, SIGNAL(heightChanged()), this, SLOT(updateMapItem())); + QObject::connect(quickMap, SIGNAL(widthChanged()), this, SLOT(updateMapItem())); + QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(updateMapItem())); + updateMapItem(); + } +} + + void QDeclarativeGeoMapQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (!dragActive_ && quickMap() && sourceItem() && newGeometry.isValid() && newGeometry != oldGeometry) { QPointF point(newGeometry.x(), newGeometry.y()); // screenPositionToCoordinate seems to return nan values when // it goes beyond viewport, hence sanity check (fixme todo): - QGeoCoordinate newCoordinate = map_->screenPositionToCoordinate(point, false); + QGeoCoordinate newCoordinate = map()->screenPositionToCoordinate(point, false); if (newCoordinate.isValid()) { internalCoordinate_.setCoordinate(newCoordinate); setCoordinate(&internalCoordinate_); @@ -119,7 +137,7 @@ void QDeclarativeGeoMapQuickItem::dragEnded() QPointF point(x(), y()); // screenPositionToCoordinate seems to return nan values when // it goes beyond viewport, hence sanity check (fixme todo): - QGeoCoordinate newCoordinate = map_->screenPositionToCoordinate(point, false); + QGeoCoordinate newCoordinate = map()->screenPositionToCoordinate(point, false); if (newCoordinate.isValid()) { internalCoordinate_.setCoordinate(newCoordinate); setCoordinate(&internalCoordinate_); @@ -127,11 +145,6 @@ void QDeclarativeGeoMapQuickItem::dragEnded() } } -void QDeclarativeGeoMapQuickItem::coordinateCoordinateChanged(double) -{ - updateMapItem(); - emit coordinateChanged(); -} QDeclarativeCoordinate* QDeclarativeGeoMapQuickItem::coordinate() { @@ -143,42 +156,10 @@ void QDeclarativeGeoMapQuickItem::setSourceItem(QQuickItem* sourceItem) if (sourceItem == sourceItem_) return; sourceItem_ = sourceItem; - mapChanged(); - emit sourceItemChanged(); -} - -void QDeclarativeGeoMapQuickItem::updateMapItem() -{ - if (!mapAndSourceItemSet_) - return; - QDeclarativeGeoMapItemBase::updateMapItem(); -} -void QDeclarativeGeoMapQuickItem::mapChanged() -{ - // currently this function checks for source item changes too - if (!quickMap() && sourceItem_) { - mapAndSourceItemSet_ = false; - sourceItem_->setParentItem(0); - return; - } - if (!quickMap() || !map_ || !sourceItem_) { - mapAndSourceItemSet_ = false; - return; - } - if (!mapAndSourceItemSet_ && quickMap() && map_ && sourceItem_) { - mapAndSourceItemSet_ = true; - sourceItem_->setParentItem(this); - sourceItem_->setTransformOrigin(QQuickItem::TopLeft); - connect(quickMap(), SIGNAL(heightChanged()), this, SLOT(updateMapItem())); - connect(quickMap(), SIGNAL(widthChanged()), this, SLOT(updateMapItem())); - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(updateMapItem())); - connect(sourceItem_, SIGNAL(xChanged()), this, SLOT(updateMapItem())); - connect(sourceItem_, SIGNAL(yChanged()), this, SLOT(updateMapItem())); - connect(sourceItem_, SIGNAL(widthChanged()), this, SLOT(updateMapItem())); - connect(sourceItem_, SIGNAL(heightChanged()), this, SLOT(updateMapItem())); - } updateMapItem(); + + emit sourceItemChanged(); } QQuickItem* QDeclarativeGeoMapQuickItem::sourceItem() @@ -214,26 +195,43 @@ qreal QDeclarativeGeoMapQuickItem::zoomLevel() const return zoomLevel_; } -void QDeclarativeGeoMapQuickItem::updateContent() +void QDeclarativeGeoMapQuickItem::updateMapItem(bool dirtyGeometry) { + Q_UNUSED(dirtyGeometry); + if (!quickMap() && sourceItem_) { + mapAndSourceItemSet_ = false; + sourceItem_->setParentItem(0); + return; + } + + if (!quickMap() || !map() || !sourceItem_) { + mapAndSourceItemSet_ = false; + return; + } + + if (!mapAndSourceItemSet_ && quickMap() && map() && sourceItem_) { + mapAndSourceItemSet_ = true; + sourceItem_->setParentItem(this); + sourceItem_->setTransformOrigin(QQuickItem::TopLeft); + connect(sourceItem_, SIGNAL(xChanged()), this, SLOT(updateMapItem())); + connect(sourceItem_, SIGNAL(yChanged()), this, SLOT(updateMapItem())); + connect(sourceItem_, SIGNAL(widthChanged()), this, SLOT(updateMapItem())); + connect(sourceItem_, SIGNAL(heightChanged()), this, SLOT(updateMapItem())); + } + sourceItem_->setScale(scaleFactor()); sourceItem_->setPos(QPointF(0,0)); setWidth(sourceItem_->width()); setHeight(sourceItem_->height()); -} - -QPointF QDeclarativeGeoMapQuickItem::contentTopLeftPoint() -{ - if (!map_) - return QPointF(0,0); - return map_->coordinateToScreenPosition(coordinate()->coordinate(), false) - scaleFactor() * anchorPoint_; + setPositionOnMap(coordinate()->coordinate() , scaleFactor() * anchorPoint_); + update(); } qreal QDeclarativeGeoMapQuickItem::scaleFactor() { qreal scale = 1.0; if (zoomLevel_ != 0.0) - scale = pow(0.5, zoomLevel_ - map_->cameraData().zoomFactor()); + scale = pow(0.5, zoomLevel_ - map()->cameraData().zoomFactor()); return scale; } diff --git a/src/imports/location/qdeclarativegeomapquickitem_p.h b/src/imports/location/qdeclarativegeomapquickitem_p.h index b54d87f3..e359cecf 100644 --- a/src/imports/location/qdeclarativegeomapquickitem_p.h +++ b/src/imports/location/qdeclarativegeomapquickitem_p.h @@ -62,6 +62,8 @@ public: QDeclarativeGeoMapQuickItem(QQuickItem *parent = 0); ~QDeclarativeGeoMapQuickItem(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + void setCoordinate(QDeclarativeCoordinate *coordinate); QDeclarativeCoordinate* coordinate(); @@ -83,19 +85,11 @@ Q_SIGNALS: void anchorPointChanged(); void zoomLevelChanged(); -protected: - void updateContent(); - void mapChanged(); - QPointF contentTopLeftPoint(); - protected Q_SLOTS: - void updateMapItem(); + virtual void updateMapItem(bool dirtyGeometry = true); // from qquickitem void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); -private Q_SLOTS: - void coordinateCoordinateChanged(double); - private: qreal scaleFactor(); QDeclarativeCoordinate* coordinate_; diff --git a/src/imports/location/qdeclarativepolygonmapitem.cpp b/src/imports/location/qdeclarativepolygonmapitem.cpp index 94ada8d4..2591eb22 100644 --- a/src/imports/location/qdeclarativepolygonmapitem.cpp +++ b/src/imports/location/qdeclarativepolygonmapitem.cpp @@ -43,10 +43,13 @@ #include <QDeclarativeInfo> #include <QPainter> -static QPolygonF createPolygon(const Map& map, const QList<QGeoCoordinate> &path, qreal& w, - qreal& h) +struct Vertex +{ + QVector2D position; +}; + +static void updatePolygon(QPolygonF& points,const Map& map, const QList<QGeoCoordinate> &path, qreal& w, qreal& h) { - QPolygonF polygon; qreal minX, maxX, minY, maxY; //TODO: dateline handling @@ -65,297 +68,252 @@ static QPolygonF createPolygon(const Map& map, const QList<QGeoCoordinate> &path maxX = point.x(); minY = point.y(); maxY = point.y(); - polygon.append(point); } else { minX = qMin(point.x(), minX); maxX = qMax(point.x(), maxX); minY = qMin(point.y(), minY); maxY = qMax(point.y(), maxY); } - - polygon.append(point); + points.append(point); } - polygon.translate(-minX, -minY); + points.translate(-minX, -minY); w = maxX - minX; h = maxY - minY; - - return polygon; } QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), - polygonItem_(new PolygonMapPaintedItem(this)), - initialized_(false) + mapPolygonNode_(0), + zoomLevel_(0.0) { - polygonItem_->setParentItem(this); + setFlag(ItemHasContents, true); } QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem() { } -void QDeclarativePolygonMapItem::componentComplete() +void QDeclarativePolygonMapItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) { - initialized_ = true; + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map) QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); } QDeclarativeListProperty<QDeclarativeCoordinate> QDeclarativePolygonMapItem::declarativePath() { return QDeclarativeListProperty<QDeclarativeCoordinate>(this, 0, path_append, path_count, - path_at, path_clear); + path_at, path_clear); } void QDeclarativePolygonMapItem::path_append( - QDeclarativeListProperty<QDeclarativeCoordinate> *property, QDeclarativeCoordinate *coordinate) + QDeclarativeListProperty<QDeclarativeCoordinate> *property, QDeclarativeCoordinate *coordinate) { - QDeclarativePolygonMapItem* item = qobject_cast<QDeclarativePolygonMapItem*>( - property->object); - item->path_.append(coordinate); - QList<QGeoCoordinate> p = item->polygonItem_->path(); - p.append(coordinate->coordinate()); - item->polygonItem_->setPath(p); - if (item->initialized_) - emit item->pathChanged(); - item->updateMapItem(); + QDeclarativePolygonMapItem* item = qobject_cast<QDeclarativePolygonMapItem*>(property->object); + item->coordPath_.append(coordinate); + item->path_.append(coordinate->coordinate()); + item->updateMapItem(true); + emit item->pathChanged(); } int QDeclarativePolygonMapItem::path_count( - QDeclarativeListProperty<QDeclarativeCoordinate> *property) + QDeclarativeListProperty<QDeclarativeCoordinate> *property) { - return qobject_cast<QDeclarativePolygonMapItem*>(property->object)->path_.count(); + return qobject_cast<QDeclarativePolygonMapItem*>(property->object)->coordPath_.count(); } QDeclarativeCoordinate* QDeclarativePolygonMapItem::path_at( - QDeclarativeListProperty<QDeclarativeCoordinate> *property, int index) + QDeclarativeListProperty<QDeclarativeCoordinate> *property, int index) { - return qobject_cast<QDeclarativePolygonMapItem*>(property->object)->path_.at(index); + return qobject_cast<QDeclarativePolygonMapItem*>(property->object)->coordPath_.at(index); } void QDeclarativePolygonMapItem::path_clear( - QDeclarativeListProperty<QDeclarativeCoordinate> *property) + QDeclarativeListProperty<QDeclarativeCoordinate> *property) { QDeclarativePolygonMapItem* item = qobject_cast<QDeclarativePolygonMapItem*>( - property->object); - qDeleteAll(item->path_); + property->object); + qDeleteAll(item->coordPath_); + item->coordPath_.clear(); item->path_.clear(); - item->polygonItem_->setPath(QList<QGeoCoordinate>()); - if (item->initialized_) - emit item->pathChanged(); - item->updateMapItem(); + item->updateMapItem(true); + emit item->pathChanged(); } void QDeclarativePolygonMapItem::addCoordinate(QDeclarativeCoordinate* coordinate) { - path_.append(coordinate); - QList<QGeoCoordinate> path = polygonItem_->path(); - path.append(coordinate->coordinate()); - polygonItem_->setPath(path); - updateMapItem(); + coordPath_.append(coordinate); + path_.append(coordinate->coordinate()); + updateMapItem(true); emit pathChanged(); } void QDeclarativePolygonMapItem::removeCoordinate(QDeclarativeCoordinate* coordinate) { - int index = path_.lastIndexOf(coordinate); + int index = coordPath_.lastIndexOf(coordinate); if (index == -1) { qmlInfo(this) << tr("Coordinate does not belong to PolygonMapItem."); return; } - QList<QGeoCoordinate> path = polygonItem_->path(); - - if (path.count() < index + 1) { + if (path_.count() < index + 1) { qmlInfo(this) << tr("Coordinate does not belong to PolygonMapItem."); return; } - path.removeAt(index); - polygonItem_->setPath(path); + coordPath_.removeAt(index); path_.removeAt(index); - updateMapItem(); + updateMapItem(true); emit pathChanged(); } -void QDeclarativePolygonMapItem::updateContent() +QColor QDeclarativePolygonMapItem::color() const { - polygonItem_->updateGeometry(); - setWidth(polygonItem_->width()); - setHeight(polygonItem_->height()); + return color_; } -QPointF QDeclarativePolygonMapItem::contentTopLeftPoint() +void QDeclarativePolygonMapItem::setColor(const QColor &color) { - return map_->coordinateToScreenPosition( - polygonItem_->quickItemCoordinate(), false) - polygonItem_->quickItemAnchorPoint(); -} + if (color_ == color) + return; -void QDeclarativePolygonMapItem::mapChanged() + color_ = color; + updateMapItem(false); + emit colorChanged(color_); +} +QSGNode* QDeclarativePolygonMapItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) { - polygonItem_->setMap(map_); - if (map_) { - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); - // initial update - handleCameraDataChanged(map_->cameraData()); + Q_UNUSED(data); + + MapPolygonNode *node = static_cast<MapPolygonNode*>(oldNode); + + if (!node) { + mapPolygonNode_ = new MapPolygonNode(); + updateMapItem(true); } -} -void QDeclarativePolygonMapItem::dragStarted() -{ - qmlInfo(this) << "warning: mouse dragging is not currently supported with polygon."; + mapPolygonNode_->update(); + return mapPolygonNode_; } -bool QDeclarativePolygonMapItem::contains(QPointF point) +void +QDeclarativePolygonMapItem::updateMapItem(bool dirtyGeometry) { - return polygonItem_->contains(point); + if (!map() || path_.count() == 0 || !mapPolygonNode_) + return; + + mapPolygonNode_->setBrushColor(color_); + + if (dirtyGeometry) + mapPolygonNode_->setGeometry(*map(), path_); + + const QSizeF& size = mapPolygonNode_->size(); + + setWidth(size.width()); + setHeight(size.height()); + + setPositionOnMap(path_.at(0), mapPolygonNode_->geometry().at(0)); + update(); } void QDeclarativePolygonMapItem::handleCameraDataChanged(const CameraData& cameraData) { - polygonItem_->setZoomLevel(cameraData.zoomFactor()); - updateMapItem(); + if (cameraData.zoomFactor() != zoomLevel_) { + zoomLevel_ = cameraData.zoomFactor(); + updateMapItem(true); + } else { + updateMapItem(false); + } } -QColor QDeclarativePolygonMapItem::color() const +void QDeclarativePolygonMapItem::dragStarted() { - return color_; + qmlInfo(this) << "warning: mouse dragging is not currently supported with polygon."; } -void QDeclarativePolygonMapItem::setColor(const QColor &color) +bool QDeclarativePolygonMapItem::contains(QPointF point) { - if (color_ == color) - return; - - color_ = color; - polygonItem_->setBrush(color); - emit colorChanged(color_); + return mapPolygonNode_->contains(point); } ////////////////////////////////////////////////////////////////////// -PolygonMapPaintedItem::PolygonMapPaintedItem(QQuickItem *parent) : - QQuickPaintedItem(parent), map_(0), zoomLevel_(-1), initialized_(false) +MapPolygonNode::MapPolygonNode() : + fillColor_(Qt::black), + borderColor_(Qt::black), + geometry_(QSGGeometry::defaultAttributes_Point2D(), 0) { - setAntialiasing(true); - connect(this, SIGNAL(xChanged()), this, SLOT(update())); - connect(this, SIGNAL(yChanged()), this, SLOT(update())); + geometry_.setDrawingMode(GL_POLYGON); + QSGGeometryNode::setMaterial(&fill_material_); + QSGGeometryNode::setGeometry(&geometry_); } -PolygonMapPaintedItem::~PolygonMapPaintedItem() +MapPolygonNode::~MapPolygonNode() { } -void PolygonMapPaintedItem::setMap(Map* map) +void MapPolygonNode::update() { - map_ = map; -} + //TODO: optimize , perform calculation only if polygon has changed + if (polygon_.size()==0) return; -Map* PolygonMapPaintedItem::map() -{ - return map_; -} + QSGGeometry *fill = QSGGeometryNode::geometry(); -void PolygonMapPaintedItem::setZoomLevel(qreal zoomLevel) -{ - if (zoomLevel_ == zoomLevel) - return; + Q_ASSERT(fill->sizeOfVertex() == sizeof(Vertex)); - zoomLevel_ = zoomLevel; - dirtyGeometry_ = true; -} + int fillVertexCount = 0; + //note this will not allocate new buffer if the size has not changed + fill->allocate(polygon_.size()); -qreal PolygonMapPaintedItem::zoomLevel() const -{ - return zoomLevel_; -} + Vertex *vertices = (Vertex *)fill->vertexData(); -bool PolygonMapPaintedItem::contains(QPointF point) -{ - return polygon_.containsPoint(point, Qt::OddEvenFill); -} + for (int i = 0; i < polygon_.size(); ++i) { + vertices[fillVertexCount++].position = QVector2D(polygon_.at(i)); + } -void PolygonMapPaintedItem::setPath(const QList<QGeoCoordinate>& path) -{ - coordPath_ = path; - dirtyGeometry_ = true; -} + Q_ASSERT(fillVertexCount == fill->vertexCount()); -QList<QGeoCoordinate> PolygonMapPaintedItem::path() const -{ - return coordPath_; -} + markDirty(DirtyGeometry); -QGeoCoordinate PolygonMapPaintedItem::quickItemCoordinate() const -{ - return quickItemCoordinate_; -} + if (fillColor_ != fill_material_.color()) { + fill_material_.setColor(fillColor_); + setMaterial(&fill_material_); + } -QPointF PolygonMapPaintedItem::quickItemAnchorPoint() const -{ - return quickItemAnchorPoint_; + //TODO: implement me : borders , gradient } -void PolygonMapPaintedItem::setBrush(const QBrush &brush) +void MapPolygonNode::setBrushColor(const QColor &color) { - brush_ = brush; + fillColor_= color; } -QBrush PolygonMapPaintedItem::brush() const +QColor MapPolygonNode::brushColor() const { - return brush_; + return fillColor_; } -void PolygonMapPaintedItem::setPen(const QPen &pen) +void MapPolygonNode::setPenColor(const QColor &color) { - pen_ = pen; + borderColor_ = color; } -QPen PolygonMapPaintedItem::pen() const +QColor MapPolygonNode::penColor() const { - return pen_; + return borderColor_; } -void PolygonMapPaintedItem::paint(QPainter *painter) +bool MapPolygonNode::contains(QPointF point) { - if (!initialized_) - return; - painter->setPen(pen_); - painter->setBrush(brush_); - painter->drawConvexPolygon(polygon_); + return polygon_.containsPoint(point, Qt::OddEvenFill); } -void PolygonMapPaintedItem::updateGeometry() +void MapPolygonNode::setGeometry(const Map& map, const QList<QGeoCoordinate> &path) { - if (!dirtyGeometry_) - return; - initialized_ = false; - - if (!map_) - return; - - if (coordPath_.size() == 0) - return; - - if (zoomLevel_ == -1) - return; - - QPointF point = map_->coordinateToScreenPosition(coordPath_.at(0), false); - - qreal w = 0; qreal h = 0; - - //TODO: optimize essential part - polygon_ = createPolygon(*map_, coordPath_, w, h); - - setWidth(w); - setHeight(h); - setContentsSize(QSize(w, h)); - - quickItemCoordinate_ = coordPath_.at(0); - quickItemAnchorPoint_ = polygon_.first(); - initialized_ = true; - - dirtyGeometry_ = false; - update(); // qquickpainteditem + qreal w = 0; + polygon_.clear(); + updatePolygon(polygon_, map, path, w, h); + size_ = QSizeF(w, h); } diff --git a/src/imports/location/qdeclarativepolygonmapitem_p.h b/src/imports/location/qdeclarativepolygonmapitem_p.h index 8cd3342a..060ca0f7 100644 --- a/src/imports/location/qdeclarativepolygonmapitem_p.h +++ b/src/imports/location/qdeclarativepolygonmapitem_p.h @@ -43,14 +43,12 @@ #define QDECLARATIVEPOLYGONMAPITEM #include "qdeclarativegeomapitembase_p.h" -#include "qdeclarativecoordinate_p.h" -#include "qdeclarativegeomap_p.h" -#include <QPen> -#include <QBrush> +#include <QSGGeometryNode> +#include <QSGFlatColorMaterial> QT_BEGIN_NAMESPACE -class PolygonMapPaintedItem; +class MapPolygonNode; class QDeclarativePolygonMapItem : public QDeclarativeGeoMapItemBase { @@ -63,7 +61,9 @@ public: QDeclarativePolygonMapItem(QQuickItem *parent = 0); ~QDeclarativePolygonMapItem(); - virtual void componentComplete(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + //from QuickItem + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); Q_INVOKABLE void addCoordinate(QDeclarativeCoordinate* coordinate); Q_INVOKABLE void removeCoordinate(QDeclarativeCoordinate* coordinate); @@ -80,10 +80,8 @@ Q_SIGNALS: void pathChanged(); void colorChanged(const QColor &color); -protected: - void updateContent(); - QPointF contentTopLeftPoint(); - void mapChanged(); +protected Q_SLOTS: + virtual void updateMapItem(bool dirtyGeomoetry = true); private Q_SLOTS: // map size changed @@ -97,57 +95,45 @@ private: void pathPropertyChanged(); private: - PolygonMapPaintedItem *polygonItem_; - QList<QDeclarativeCoordinate*> path_; + MapPolygonNode *mapPolygonNode_; + QList<QDeclarativeCoordinate*> coordPath_; + QList<QGeoCoordinate> path_; QColor color_; - bool initialized_; + qreal zoomLevel_; }; ////////////////////////////////////////////////////////////////////// -class PolygonMapPaintedItem : public QQuickPaintedItem +class MapPolygonNode : public QSGGeometryNode { - Q_OBJECT public: - PolygonMapPaintedItem(QQuickItem *parent = 0); - ~PolygonMapPaintedItem(); - - void setMap(Map* map); - Map* map(); - - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; + MapPolygonNode(); + ~MapPolygonNode(); - QList<QGeoCoordinate> path() const; - void setPath(const QList<QGeoCoordinate>& path); + void setSize(const QSize &size); + QSizeF size() const { + return size_; + } - void paint(QPainter *painter); + QColor penColor() const; + void setPenColor(const QColor &pen); - QPen pen() const; - void setPen(const QPen &pen); - - QBrush brush() const; - void setBrush(const QBrush &brush); - - QGeoCoordinate quickItemCoordinate() const; - QPointF quickItemAnchorPoint() const; + QColor brushColor() const; + void setBrushColor(const QColor &color); + void update(); bool contains(QPointF point); - void updateGeometry(); + void setGeometry(const Map &map, const QList<QGeoCoordinate> &path); + const QPolygonF& geometry() { return polygon_; } private: - - Map *map_; - qreal zoomLevel_; - QGeoCoordinate quickItemCoordinate_; - QPointF quickItemAnchorPoint_; - QPen pen_; - QBrush brush_; - QList<QGeoCoordinate> coordPath_; + QSGFlatColorMaterial fill_material_; + QColor fillColor_; + QColor borderColor_; + QSGGeometry geometry_; QPolygonF polygon_; - bool initialized_; - bool dirtyGeometry_; + QSizeF size_; }; diff --git a/src/imports/location/qdeclarativepolylinemapitem.cpp b/src/imports/location/qdeclarativepolylinemapitem.cpp index fcbbd52e..bb84256f 100644 --- a/src/imports/location/qdeclarativepolylinemapitem.cpp +++ b/src/imports/location/qdeclarativepolylinemapitem.cpp @@ -45,322 +45,272 @@ QT_BEGIN_NAMESPACE -static QPainterPath createPath(const Map& map, const QList<QGeoCoordinate> &path, qreal& w, - qreal& h) +struct Vertex +{ + QVector2D position; +}; + +static void updatePolyline(QPolygonF& points,const Map& map, const QList<QGeoCoordinate> &path, qreal& w, qreal& h) { - QPainterPath painter; qreal minX, maxX, minY, maxY; //TODO: dateline handling for (int i = 0; i < path.size(); ++i) { + const QGeoCoordinate &coord = path.at(i); if (!coord.isValid()) continue; QPointF point = map.coordinateToScreenPosition(coord, false); + if (i == 0) { minX = point.x(); maxX = point.x(); minY = point.y(); maxY = point.y(); - painter.moveTo(point); } else { minX = qMin(point.x(), minX); maxX = qMax(point.x(), maxX); minY = qMin(point.y(), minY); maxY = qMax(point.y(), maxY); - painter.lineTo(point); } - + points.append(point); } - painter.translate(-minX, -minY); + points.translate(-minX, -minY); w = maxX - minX; h = maxY - minY; - - return painter; } QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent) : QDeclarativeGeoMapItemBase(parent), - polylineItem_(new PolylineMapPaintedItem(this)), - initialized_(false) + mapPolylineNode_(0), + zoomLevel_(0.0) { - polylineItem_->setParentItem(this); + setFlag(ItemHasContents, true); } QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem() { } +void QDeclarativePolylineMapItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) +{ + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map) QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); +} + QDeclarativeListProperty<QDeclarativeCoordinate> QDeclarativePolylineMapItem::declarativePath() { return QDeclarativeListProperty<QDeclarativeCoordinate>(this, 0, path_append, path_count, - path_at, path_clear); + path_at, path_clear); } -void QDeclarativePolylineMapItem::path_append( - QDeclarativeListProperty<QDeclarativeCoordinate> *property, QDeclarativeCoordinate *coordinate) +void QDeclarativePolylineMapItem::path_append(QDeclarativeListProperty<QDeclarativeCoordinate> *property, QDeclarativeCoordinate *coordinate) { QDeclarativePolylineMapItem* item = qobject_cast<QDeclarativePolylineMapItem*>( - property->object); - item->path_.append(coordinate); - QList<QGeoCoordinate> p = item->polylineItem_->path(); - p.append(coordinate->coordinate()); - item->polylineItem_->setPath(p); - if (item->initialized_) - emit item->pathChanged(); - item->updateMapItem(); + property->object); + item->coordPath_.append(coordinate); + item->path_.append(coordinate->coordinate()); + item->updateMapItem(true); + emit item->pathChanged(); } int QDeclarativePolylineMapItem::path_count( - QDeclarativeListProperty<QDeclarativeCoordinate> *property) + QDeclarativeListProperty<QDeclarativeCoordinate> *property) { - return qobject_cast<QDeclarativePolylineMapItem*>(property->object)->path_.count(); + return qobject_cast<QDeclarativePolylineMapItem*>(property->object)->coordPath_.count(); } QDeclarativeCoordinate* QDeclarativePolylineMapItem::path_at( - QDeclarativeListProperty<QDeclarativeCoordinate> *property, int index) + QDeclarativeListProperty<QDeclarativeCoordinate> *property, int index) { - return qobject_cast<QDeclarativePolylineMapItem*>(property->object)->path_.at(index); + return qobject_cast<QDeclarativePolylineMapItem*>(property->object)->coordPath_.at(index); } void QDeclarativePolylineMapItem::path_clear( - QDeclarativeListProperty<QDeclarativeCoordinate> *property) + QDeclarativeListProperty<QDeclarativeCoordinate> *property) { QDeclarativePolylineMapItem* item = qobject_cast<QDeclarativePolylineMapItem*>( - property->object); - qDeleteAll(item->path_); + property->object); + qDeleteAll(item->coordPath_); + item->coordPath_.clear(); item->path_.clear(); - item->polylineItem_->setPath(QList<QGeoCoordinate>()); - if (item->initialized_) - emit item->pathChanged(); - item->updateMapItem(); + item->updateMapItem(true); + emit item->pathChanged(); } void QDeclarativePolylineMapItem::addCoordinate(QDeclarativeCoordinate* coordinate) { - path_.append(coordinate); - QList<QGeoCoordinate> path = polylineItem_->path(); - path.append(coordinate->coordinate()); - polylineItem_->setPath(path); - updateMapItem(); + coordPath_.append(coordinate); + path_.append(coordinate->coordinate()); + updateMapItem(true); emit pathChanged(); } void QDeclarativePolylineMapItem::removeCoordinate(QDeclarativeCoordinate* coordinate) { - int index = path_.lastIndexOf(coordinate); + int index = coordPath_.lastIndexOf(coordinate); if (index == -1) { qmlInfo(this) << tr("Coordinate does not belong to PolylineMapItem."); return; } - QList<QGeoCoordinate> path = polylineItem_->path(); - - if (path.count() < index + 1) { + if (path_.count() < index + 1) { qmlInfo(this) << tr("Coordinate does not belong to PolylineMapItem."); return; } - path.removeAt(index); - polylineItem_->setPath(path); + coordPath_.removeAt(index); path_.removeAt(index); - updateMapItem(); + updateMapItem(true); emit pathChanged(); } -void QDeclarativePolylineMapItem::updateContent() +QColor QDeclarativePolylineMapItem::color() const { - polylineItem_->updateGeometry(); - setWidth(polylineItem_->width()); - setHeight(polylineItem_->height()); + return color_; } -QPointF QDeclarativePolylineMapItem::contentTopLeftPoint() +void QDeclarativePolylineMapItem::setColor(const QColor &color) { - return map_->coordinateToScreenPosition( - polylineItem_->quickItemCoordinate(), false) - polylineItem_->quickItemAnchorPoint(); + if (color_ == color) + return; + + color_ = color; + updateMapItem(false); + emit colorChanged(color_); } -void QDeclarativePolylineMapItem::mapChanged() +QSGNode* QDeclarativePolylineMapItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) { - polylineItem_->setMap(map_); - if (map_) { - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); - // initial update - handleCameraDataChanged(map_->cameraData()); + Q_UNUSED(data); + + MapPolylineNode *node = static_cast<MapPolylineNode*>(oldNode); + + if (!node) { + mapPolylineNode_ = new MapPolylineNode(); + updateMapItem(true); } -} -void QDeclarativePolylineMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - // TODO - if X and Y of the wrapper item are changed, currently - // the item moves, but returns to old position when map camera changes - QQuickItem::geometryChanged(newGeometry, oldGeometry); + mapPolylineNode_->update(); + return mapPolylineNode_; } -void QDeclarativePolylineMapItem::dragStarted() -{ - qmlInfo(this) << "warning: mouse dragging is not currently supported with polylines/routes."; -} +void QDeclarativePolylineMapItem::updateMapItem(bool dirtyGeometry) { -bool QDeclarativePolylineMapItem::contains(QPointF point) -{ - // todo this currently returns all points _inside_ of the implicitly closed - // painterpath whereas we are only interested in the outlines of it - return polylineItem_->contains(point); + if (!map() || path_.count()==0 || !mapPolylineNode_) + return; + + mapPolylineNode_->setPenColor(color_); + + if (dirtyGeometry) mapPolylineNode_->setGeometry(*map(), path_); + + const QSizeF& size = mapPolylineNode_->size(); + + setWidth(size.width()); + setHeight(size.height()); + + setPositionOnMap(path_.at(0),mapPolylineNode_->geometry().at(0)); + update(); } void QDeclarativePolylineMapItem::handleCameraDataChanged(const CameraData& cameraData) { - polylineItem_->setZoomLevel(cameraData.zoomFactor()); - updateMapItem(); + if (cameraData.zoomFactor() != zoomLevel_) { + zoomLevel_ = cameraData.zoomFactor(); + updateMapItem(true); + } else { + updateMapItem(false); + } } -QColor QDeclarativePolylineMapItem::color() const +bool QDeclarativePolylineMapItem::contains(QPointF point) { - return color_; + // TODO: this currently returns all points _inside_ of the implicitly closed + // painterpath whereas we are only interested in the outlines of it + return mapPolylineNode_->contains(point); } -void QDeclarativePolylineMapItem::setColor(const QColor &color) +void QDeclarativePolylineMapItem::dragStarted() { - if (color_ == color) - return; - - color_ = color; - polylineItem_->setPen(color); - emit colorChanged(color_); + qmlInfo(this) << "warning: mouse dragging is not currently supported with polylines/routes."; } ////////////////////////////////////////////////////////////////////// -PolylineMapPaintedItem::PolylineMapPaintedItem(QQuickItem *parent) : - QQuickPaintedItem(parent), map_(0), zoomLevel_(-1), initialized_(false), - dirtyGeometry_(false) +MapPolylineNode::MapPolylineNode() : + fillColor_(Qt::black), + geometry_(QSGGeometry::defaultAttributes_Point2D(),0) { - setAntialiasing(true); - connect(this, SIGNAL(xChanged()), this, SLOT(update())); - connect(this, SIGNAL(yChanged()), this, SLOT(update())); + geometry_.setDrawingMode(GL_LINE_STRIP); + QSGGeometryNode::setMaterial(&fill_material_); + QSGGeometryNode::setGeometry(&geometry_); } -PolylineMapPaintedItem::~PolylineMapPaintedItem() -{ -} -void PolylineMapPaintedItem::setMap(Map* map) +MapPolylineNode::~MapPolylineNode() { - map_ = map; } -Map* PolylineMapPaintedItem::map() +void MapPolylineNode::update() { - return map_; -} - -void PolylineMapPaintedItem::setZoomLevel(qreal zoomLevel) -{ - if (zoomLevel_ == zoomLevel) + //TODO: optimize , perform calculation only if polygon has changed + if (polyline_.size() == 0) return; - zoomLevel_ = zoomLevel; - dirtyGeometry_ = true; -} + QSGGeometry *fill = QSGGeometryNode::geometry(); -qreal PolylineMapPaintedItem::zoomLevel() const -{ - return zoomLevel_; -} + Q_ASSERT(fill->sizeOfVertex() == sizeof(Vertex)); -bool PolylineMapPaintedItem::contains(QPointF point) -{ - return path_.contains(point); -} + int fillVertexCount = 0; + //note this will not allocate new buffer if the size has not changed + fill->allocate(polyline_.size()); -void PolylineMapPaintedItem::setPath(const QList<QGeoCoordinate>& path) -{ - coordPath_ = path; - dirtyGeometry_ = true; -} + Vertex *vertices = (Vertex *)fill->vertexData(); -QList<QGeoCoordinate> PolylineMapPaintedItem::path() const -{ - return coordPath_; -} + for (int i = 0; i < polyline_.size(); ++i) { + vertices[fillVertexCount++].position = QVector2D(polyline_.at(i)); + } -QGeoCoordinate PolylineMapPaintedItem::quickItemCoordinate() const -{ - return quickItemCoordinate_; -} + Q_ASSERT(fillVertexCount == fill->vertexCount()); -QPointF PolylineMapPaintedItem::quickItemAnchorPoint() const -{ - return quickItemAnchorPoint_; -} + markDirty(DirtyGeometry); -void PolylineMapPaintedItem::setBrush(const QBrush &brush) -{ - brush_ = brush; -} + if (fillColor_ != fill_material_.color()) { + fill_material_.setColor(fillColor_); + setMaterial(&fill_material_); + } -QBrush PolylineMapPaintedItem::brush() const -{ - return brush_; + //TODO: implement me : borders , gradient } -void PolylineMapPaintedItem::setPen(const QPen &pen) +bool MapPolylineNode::contains(QPointF point) { - pen_ = pen; + //TODO: implement me + return polyline_.contains(point); } -QPen PolylineMapPaintedItem::pen() const +void MapPolylineNode::setPenColor(const QColor &color) { - return pen_; + fillColor_ = color; } -void PolylineMapPaintedItem::paint(QPainter *painter) +QColor MapPolylineNode::penColor() const { - if (!initialized_) - return; - painter->setPen(pen_); - painter->setBrush(brush_); - painter->drawPath(path_); + return fillColor_; } -void PolylineMapPaintedItem::updateGeometry() +void MapPolylineNode::setGeometry(const Map& map, const QList<QGeoCoordinate> &path) { - if (!dirtyGeometry_) - return; - initialized_ = false; - - if (!map()) - return; - - if (coordPath_.size() == 0) - return; - - if (zoomLevel_ == -1) - return; - - qreal w = 0; qreal h = 0; - - //TODO: optimize essential part - path_ = createPath(*map_, coordPath_, w, h); - - setWidth(w); - setHeight(h); - setContentsSize(QSize(w, h)); - - quickItemCoordinate_ = coordPath_.at(0); - quickItemAnchorPoint_ = path_.pointAtPercent(0); - initialized_ = true; - - dirtyGeometry_ = false; - update(); + qreal w = 0; + polyline_.clear(); + updatePolyline(polyline_, map, path, w, h); + size_ = QSizeF(w, h); } QT_END_NAMESPACE diff --git a/src/imports/location/qdeclarativepolylinemapitem_p.h b/src/imports/location/qdeclarativepolylinemapitem_p.h index 60853a31..bcc5799d 100644 --- a/src/imports/location/qdeclarativepolylinemapitem_p.h +++ b/src/imports/location/qdeclarativepolylinemapitem_p.h @@ -43,14 +43,12 @@ #define QDECLARATIVEPOLYLINEMAPITEM #include "qdeclarativegeomapitembase_p.h" -#include "qdeclarativecoordinate_p.h" -#include "qdeclarativegeomap_p.h" -#include <QPen> -#include <QBrush> +#include <QSGGeometryNode> +#include <QSGFlatColorMaterial> QT_BEGIN_NAMESPACE -class PolylineMapPaintedItem; +class MapPolylineNode; class QDeclarativePolylineMapItem : public QDeclarativeGeoMapItemBase { @@ -63,6 +61,10 @@ public: QDeclarativePolylineMapItem(QQuickItem *parent = 0); ~QDeclarativePolylineMapItem(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + //from QuickItem + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + Q_INVOKABLE void addCoordinate(QDeclarativeCoordinate* coordinate); Q_INVOKABLE void removeCoordinate(QDeclarativeCoordinate* coordinate); @@ -79,13 +81,7 @@ Q_SIGNALS: void colorChanged(const QColor &color); protected Q_SLOTS: - // from qquickitem - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - -protected: - void updateContent(); - QPointF contentTopLeftPoint(); - void mapChanged(); + virtual void updateMapItem(bool dirtyGeomoetry = true); private Q_SLOTS: // map size changed @@ -99,57 +95,42 @@ private: void pathPropertyChanged(); private: - PolylineMapPaintedItem *polylineItem_; - QList<QDeclarativeCoordinate*> path_; + MapPolylineNode *mapPolylineNode_; + QList<QDeclarativeCoordinate*> coordPath_; + QList<QGeoCoordinate> path_; QColor color_; - bool initialized_; + qreal zoomLevel_; }; ////////////////////////////////////////////////////////////////////// -class PolylineMapPaintedItem : public QQuickPaintedItem +class MapPolylineNode : public QSGGeometryNode { - Q_OBJECT public: - PolylineMapPaintedItem(QQuickItem *parent = 0); - ~PolylineMapPaintedItem(); - - void setMap(Map* map); - Map* map(); + MapPolylineNode(); + ~MapPolylineNode(); - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; + void setSize(const QSize &size); + QSizeF size() const { + return size_; + } - QList<QGeoCoordinate> path() const; - void setPath(const QList<QGeoCoordinate>& path); - - void paint(QPainter *painter); - - QPen pen() const; - void setPen(const QPen &pen); - - QBrush brush() const; - void setBrush(const QBrush &brush); + QColor penColor() const; + void setPenColor(const QColor &pen); + void update(); bool contains(QPointF point); - QGeoCoordinate quickItemCoordinate() const; - QPointF quickItemAnchorPoint() const; - - void updateGeometry(); + void setGeometry(const Map &map, const QList<QGeoCoordinate> &path); + const QPolygonF& geometry() { return polyline_; } private: - Map *map_; - qreal zoomLevel_; - QPen pen_; - QBrush brush_; - QGeoCoordinate quickItemCoordinate_; - QPointF quickItemAnchorPoint_; - QList<QGeoCoordinate> coordPath_; - QPainterPath path_; - bool initialized_; - bool dirtyGeometry_; + QSGFlatColorMaterial fill_material_; + QColor fillColor_; + QSGGeometry geometry_; + QPolygonF polyline_; + QSizeF size_; }; diff --git a/src/imports/location/qdeclarativerectanglemapitem.cpp b/src/imports/location/qdeclarativerectanglemapitem.cpp index 9c31b662..24398983 100644 --- a/src/imports/location/qdeclarativerectanglemapitem.cpp +++ b/src/imports/location/qdeclarativerectanglemapitem.cpp @@ -44,20 +44,32 @@ QT_BEGIN_NAMESPACE -QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent) -: QDeclarativeGeoMapItemBase(parent), - rectangleItem_(new RectangleMapPaintedItem(this)), - topLeft_(0), - bottomRight_(0), - dragActive_(false) +struct Vertex { - rectangleItem_->setParentItem(this); + QVector2D position; +}; + +QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent): + QDeclarativeGeoMapItemBase(parent), + mapRectangleNode_(0), + topLeft_(0), + bottomRight_(0), + zoomLevel_(0.0), + dragActive_(false) +{ + setFlag(ItemHasContents, true); } QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem() { } +void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) +{ + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map) QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); +} + void QDeclarativeRectangleMapItem::setTopLeft(QDeclarativeCoordinate *topLeft) { if (topLeft_ == topLeft) @@ -65,19 +77,18 @@ void QDeclarativeRectangleMapItem::setTopLeft(QDeclarativeCoordinate *topLeft) if (topLeft_) topLeft_->disconnect(this); topLeft_ = topLeft; - if (!topLeft_) { - rectangleItem_->setTopLeft(QGeoCoordinate()); - } else { - rectangleItem_->setTopLeft(topLeft_->coordinate()); + + if (topLeft_) { connect(topLeft_, SIGNAL(latitudeChanged(double)), this, - SLOT(handleTopLeftCoordinateChanged())); + SLOT(updateMapItem())); connect(topLeft_, SIGNAL(longitudeChanged(double)), this, - SLOT(handleTopLeftCoordinateChanged())); + SLOT(updateMapItem())); connect(topLeft_, SIGNAL(altitudeChanged(double)), this, - SLOT(handleTopLeftCoordinateChanged())); + SLOT(updateMapItem())); } + + updateMapItem(true); emit topLeftChanged(topLeft_); - updateMapItem(); } QDeclarativeCoordinate* QDeclarativeRectangleMapItem::topLeft() @@ -92,19 +103,16 @@ void QDeclarativeRectangleMapItem::setBottomRight(QDeclarativeCoordinate *bottom if (bottomRight_) bottomRight_->disconnect(this); bottomRight_ = bottomRight; - if (!bottomRight_) { - rectangleItem_->setBottomRight(QGeoCoordinate()); - } else { - rectangleItem_->setBottomRight(bottomRight_->coordinate()); + if (bottomRight_) { connect(bottomRight_, SIGNAL(latitudeChanged(double)), this, - SLOT(handleBottomRightCoordinateChanged())); + SLOT(updateMapItem())); connect(bottomRight_, SIGNAL(longitudeChanged(double)), this, - SLOT(handleBottomRightCoordinateChanged())); + SLOT(updateMapItem())); connect(bottomRight_, SIGNAL(altitudeChanged(double)), this, - SLOT(handleBottomRightCoordinateChanged())); + SLOT(updateMapItem())); } - emit bottomRightChanged(bottomRight); - updateMapItem(); + updateMapItem(true); + emit bottomRightChanged(bottomRight_); } QDeclarativeCoordinate* QDeclarativeRectangleMapItem::bottomRight() @@ -112,25 +120,68 @@ QDeclarativeCoordinate* QDeclarativeRectangleMapItem::bottomRight() return bottomRight_; } -void QDeclarativeRectangleMapItem::updateContent() +QColor QDeclarativeRectangleMapItem::color() const { - rectangleItem_->updateGeometry(); - setWidth(rectangleItem_->width()); - setHeight(rectangleItem_->height()); + return color_; } -QPointF QDeclarativeRectangleMapItem::contentTopLeftPoint() +void QDeclarativeRectangleMapItem::setColor(const QColor &color) { - return map_->coordinateToScreenPosition(rectangleItem_->topLeft(), false); + if (color_ == color) + return; + color_ = color; + updateMapItem(false); + emit colorChanged(color_); } -void QDeclarativeRectangleMapItem::mapChanged() +QSGNode* QDeclarativeRectangleMapItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) { - rectangleItem_->setMap(map_); - if (map_) { - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); - handleCameraDataChanged(map_->cameraData()); + Q_UNUSED(data); + + MapRectangleNode *node = static_cast<MapRectangleNode*>(oldNode); + + if (!node) { + mapRectangleNode_ = new MapRectangleNode(); + updateMapItem(true); } + + mapRectangleNode_->update(); + return mapRectangleNode_; +} + +void QDeclarativeRectangleMapItem::updateMapItem(bool dirtyGeometry) +{ + if (!map() || !topLeft() || !topLeft()->coordinate().isValid() + || !bottomRight() || !bottomRight()->coordinate().isValid() + || !mapRectangleNode_) + return; + + mapRectangleNode_->setBrushColor(color_); + + if (dirtyGeometry) mapRectangleNode_->setGeometry(*map(), topLeft()->coordinate(), bottomRight()->coordinate()); + + const QSizeF& size = mapRectangleNode_->size(); + + setWidth(size.width()); + setHeight(size.height()); + + setPositionOnMap(topLeft()->coordinate(), QPointF(0, 0)); + update(); +} + +void QDeclarativeRectangleMapItem::handleCameraDataChanged(const CameraData& cameraData) +{ + if (cameraData.zoomFactor() != zoomLevel_) { + zoomLevel_ = cameraData.zoomFactor(); + updateMapItem(true); + } else { + updateMapItem(false); + } +} + +bool QDeclarativeRectangleMapItem::contains(QPointF point) +{ + return mapRectangleNode_->contains(point); } void QDeclarativeRectangleMapItem::dragEnded() @@ -140,9 +191,9 @@ void QDeclarativeRectangleMapItem::dragEnded() dragActive_ = false; QPointF newTopLeftPoint = QPointF(x(),y()); // does not preserve exact projection geometry but that should be acceptable - QGeoCoordinate newTopLeft = map_->screenPositionToCoordinate(newTopLeftPoint, false); + QGeoCoordinate newTopLeft = map()->screenPositionToCoordinate(newTopLeftPoint, false); QPointF newBottomRightPoint = QPointF(x() + width(), y() + height()); - QGeoCoordinate newBottomRight = map_->screenPositionToCoordinate(newBottomRightPoint, false); + QGeoCoordinate newBottomRight = map()->screenPositionToCoordinate(newBottomRightPoint, false); if (newTopLeft.isValid() && newBottomRight.isValid()) { internalTopLeft_.setCoordinate(newTopLeft); internalBottomRight_.setCoordinate(newBottomRight); @@ -155,146 +206,80 @@ void QDeclarativeRectangleMapItem::dragStarted() { dragActive_ = true; } +////////////////////////////////////////////////////////////////////// -void QDeclarativeRectangleMapItem::handleCameraDataChanged(const CameraData& cameraData) +MapRectangleNode::MapRectangleNode(): + fillColor_(Qt::black), + borderColor_(Qt::black), + geometry_(QSGGeometry::defaultAttributes_Point2D(),0) { - rectangleItem_->setZoomLevel(cameraData.zoomFactor()); - updateMapItem(); + geometry_.setDrawingMode(GL_QUADS); + QSGGeometryNode::setMaterial(&fill_material_); + QSGGeometryNode::setGeometry(&geometry_); } -bool QDeclarativeRectangleMapItem::contains(QPointF point) +MapRectangleNode::~MapRectangleNode() { - return rectangleItem_->contains(point); } -void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +void MapRectangleNode::update() { - // TODO - if X and Y of the wrapper item are changed, currently - // the item moves, but returns to old position when map camera changes - QQuickItem::geometryChanged(newGeometry, oldGeometry); -} + QSGGeometry *fill = QSGGeometryNode::geometry(); -void QDeclarativeRectangleMapItem::handleTopLeftCoordinateChanged() -{ - rectangleItem_->setTopLeft(topLeft_->coordinate()); - emit topLeftChanged(topLeft_); -} + Q_ASSERT(fill->sizeOfVertex() == sizeof(Vertex)); -void QDeclarativeRectangleMapItem::handleBottomRightCoordinateChanged() -{ - rectangleItem_->setBottomRight(bottomRight_->coordinate()); - emit bottomRightChanged(bottomRight_); -} + int fillVertexCount = 0; + //note this will not allocate new buffer if the size has not changed + fill->allocate(4); -QColor QDeclarativeRectangleMapItem::color() const -{ - return color_; -} + Vertex *vertices = (Vertex *)fill->vertexData(); -void QDeclarativeRectangleMapItem::setColor(const QColor &color) -{ - if (color_ == color) - return; + //set corners + vertices[fillVertexCount++].position = QVector2D(rect_.left(),rect_.top()); + vertices[fillVertexCount++].position = QVector2D(rect_.right(),rect_.top()); + vertices[fillVertexCount++].position = QVector2D(rect_.right(),rect_.bottom()); + vertices[fillVertexCount++].position = QVector2D(rect_.left(),rect_.bottom()); - color_ = color; - QBrush m_brush(color); - rectangleItem_->setBrush(m_brush); - emit colorChanged(color_); -} - -////////////////////////////////////////////////////////////////////// - -RectangleMapPaintedItem::RectangleMapPaintedItem(QQuickItem *parent) : - QQuickPaintedItem(parent), map_(0), zoomLevel_(-1), initialized_(false), - dirtyGeometry_(false) -{ - setAntialiasing(true); - connect(this, SIGNAL(xChanged()), this, SLOT(update())); - connect(this, SIGNAL(yChanged()), this, SLOT(update())); -} - -RectangleMapPaintedItem::~RectangleMapPaintedItem() -{ -} - -void RectangleMapPaintedItem::setMap(Map* map) -{ - map_ = map; -} + Q_ASSERT(fillVertexCount == fill->vertexCount()); -Map* RectangleMapPaintedItem::map() -{ - return map_; -} - -void RectangleMapPaintedItem::setZoomLevel(qreal zoomLevel) -{ - if (zoomLevel_ == zoomLevel) - return; - - zoomLevel_ = zoomLevel; - dirtyGeometry_ = true; -} + markDirty(DirtyGeometry); -qreal RectangleMapPaintedItem::zoomLevel() const -{ - return zoomLevel_; + if (fillColor_ != fill_material_.color()) { + fill_material_.setColor(fillColor_); + setMaterial(&fill_material_); + } + //TODO: implement me : borders , gradient } -void RectangleMapPaintedItem::setTopLeft(const QGeoCoordinate &topLeftCoord) +void MapRectangleNode::setBrushColor(const QColor &color) { - if (topLeftCoord_ == topLeftCoord) - return; - - topLeftCoord_ = topLeftCoord; - dirtyGeometry_ = true; + fillColor_= color; } -QGeoCoordinate RectangleMapPaintedItem::topLeft() const +QColor MapRectangleNode::brushColor() const { - return topLeftCoord_; + return fillColor_; } -void RectangleMapPaintedItem::setBottomRight(const QGeoCoordinate &bottomRightCoord) +void MapRectangleNode::setPenColor(const QColor &color) { - if (bottomRightCoord_ == bottomRightCoord) - return; - - bottomRightCoord_ = bottomRightCoord; - dirtyGeometry_ = true; + borderColor_ = color; } -QGeoCoordinate RectangleMapPaintedItem::bottomRight() const +QColor MapRectangleNode::penColor() const { - return bottomRightCoord_; + return borderColor_; } -void RectangleMapPaintedItem::paint(QPainter *painter) +bool MapRectangleNode::contains(QPointF point) { - if (!initialized_) - return; - painter->setPen(pen_); - painter->setBrush(brush_); - painter->drawRect(rect_); + return rect_.contains(point); } -void RectangleMapPaintedItem::updateGeometry() +void MapRectangleNode::setGeometry(const Map& map, const QGeoCoordinate &topLeft, const QGeoCoordinate &bottomRight) { - if (!dirtyGeometry_) - return; - initialized_ = false; - - if (!map_) - return; - - if (!topLeftCoord_.isValid() || !bottomRightCoord_.isValid()) - return; - - if (zoomLevel_ == -1) - return; - - QPointF p1 = map_->coordinateToScreenPosition(topLeftCoord_, false); - QPointF p2 = map_->coordinateToScreenPosition(bottomRightCoord_, false); + QPointF p1 = map.coordinateToScreenPosition(topLeft, false); + QPointF p2 = map.coordinateToScreenPosition(bottomRight, false); qreal minX = qMin(p1.x(), p2.x()); qreal maxX = qMax(p1.x(), p2.x()); @@ -304,42 +289,9 @@ void RectangleMapPaintedItem::updateGeometry() qreal w = maxX - minX; qreal h = maxY - minY; - setWidth(w); - setHeight(h); - setContentsSize(QSize(w, h)); - + size_ = QSizeF(w, h); rect_.setTopLeft(QPointF(0, 0)); rect_.setBottomRight(QPointF(w, h)); - - initialized_ = true; - dirtyGeometry_ = false; - update(); // qquickpainteditem -} - - -bool RectangleMapPaintedItem::contains(QPointF point) -{ - return rect_.contains(point); -} - -void RectangleMapPaintedItem::setBrush(const QBrush &brush) -{ - brush_ = brush; -} - -QBrush RectangleMapPaintedItem::brush() const -{ - return brush_; -} - -void RectangleMapPaintedItem::setPen(const QPen &pen) -{ - pen_ = pen; -} - -QPen RectangleMapPaintedItem::pen() const -{ - return pen_; } QT_END_NAMESPACE diff --git a/src/imports/location/qdeclarativerectanglemapitem_p.h b/src/imports/location/qdeclarativerectanglemapitem_p.h index 7e3653c0..bea588de 100644 --- a/src/imports/location/qdeclarativerectanglemapitem_p.h +++ b/src/imports/location/qdeclarativerectanglemapitem_p.h @@ -43,14 +43,12 @@ #define QDECLARATIVERECTANGLEMAPITEM_H_ #include "qdeclarativegeomapitembase_p.h" -#include "qdeclarativecoordinate_p.h" -#include "qdeclarativegeomap_p.h" -#include <QPen> -#include <QBrush> +#include <QSGGeometryNode> +#include <QSGFlatColorMaterial> QT_BEGIN_NAMESPACE -class RectangleMapPaintedItem; +class MapRectangleNode; class QDeclarativeRectangleMapItem: public QDeclarativeGeoMapItemBase { @@ -64,6 +62,10 @@ public: QDeclarativeRectangleMapItem(QQuickItem *parent = 0); ~QDeclarativeRectangleMapItem(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + //from QuickItem + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QDeclarativeCoordinate* topLeft(); void setTopLeft(QDeclarativeCoordinate *center); @@ -83,73 +85,56 @@ Q_SIGNALS: void colorChanged(const QColor &color); protected Q_SLOTS: - void updateContent(); - QPointF contentTopLeftPoint(); - void mapChanged(); - // from qquickitem - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + virtual void updateMapItem(bool dirtyGeometry = true); + private Q_SLOTS: // map size changed void handleCameraDataChanged(const CameraData& cameraData); - void handleTopLeftCoordinateChanged(); - void handleBottomRightCoordinateChanged(); private: - RectangleMapPaintedItem *rectangleItem_; + MapRectangleNode *mapRectangleNode_; QDeclarativeCoordinate* topLeft_; QDeclarativeCoordinate* bottomRight_; QDeclarativeCoordinate internalTopLeft_; QDeclarativeCoordinate internalBottomRight_; QColor color_; + qreal zoomLevel_; bool dragActive_; }; ////////////////////////////////////////////////////////////////////// -class RectangleMapPaintedItem: public QQuickPaintedItem +class MapRectangleNode: public QSGGeometryNode { - Q_OBJECT public: - RectangleMapPaintedItem(QQuickItem *parent = 0); - ~RectangleMapPaintedItem(); - - void setMap(Map* map); - Map* map(); + MapRectangleNode(); + ~MapRectangleNode(); - void setZoomLevel(qreal zoomLevel); - qreal zoomLevel() const; + void setSize(const QSize &size); + QSizeF size() const { + return size_; + } - QGeoCoordinate topLeft() const; - void setTopLeft(const QGeoCoordinate &topLeft); + QColor penColor() const; + void setPenColor(const QColor &pen); - QGeoCoordinate bottomRight() const; - void setBottomRight(const QGeoCoordinate &bottomRight); - - void paint(QPainter *painter); - - QPen pen() const; - void setPen(const QPen &pen); - - QBrush brush() const; - void setBrush(const QBrush &brush); + QColor brushColor() const; + void setBrushColor(const QColor &color); + void update(); bool contains(QPointF point); - void updateGeometry(); + void setGeometry(const Map& map, const QGeoCoordinate &topLeft, const QGeoCoordinate &bottomRight); private: - Map *map_; - qreal zoomLevel_; - QGeoCoordinate topLeftCoord_; - QGeoCoordinate bottomRightCoord_; - QGeoCoordinate quickItemCoordinate_; - QPointF quickItemAnchorPoint_; - QPen pen_; - QBrush brush_; + QSGFlatColorMaterial fill_material_; + QColor fillColor_; + QColor borderColor_; + QSGGeometry geometry_; QRectF rect_; - bool initialized_; - bool dirtyGeometry_; + QSizeF size_; + }; QT_END_NAMESPACE diff --git a/src/imports/location/qdeclarativeroutemapitem.cpp b/src/imports/location/qdeclarativeroutemapitem.cpp index 7a904b87..c708473b 100644 --- a/src/imports/location/qdeclarativeroutemapitem.cpp +++ b/src/imports/location/qdeclarativeroutemapitem.cpp @@ -46,18 +46,25 @@ #include <QtDeclarative/QDeclarativeInfo> #include <QtGui/QPainter> -QDeclarativeRouteMapItem::QDeclarativeRouteMapItem(QQuickItem *parent) - : QDeclarativeGeoMapItemBase(parent), - polylineItem_(new PolylineMapPaintedItem(this)), - route_(0) +QDeclarativeRouteMapItem::QDeclarativeRouteMapItem(QQuickItem *parent): + QDeclarativeGeoMapItemBase(parent), + mapPolylineNode_(0), + route_(0), + zoomLevel_(0.0) { - polylineItem_->setParentItem(this); + setFlag(ItemHasContents, true); } QDeclarativeRouteMapItem::~QDeclarativeRouteMapItem() { } +void QDeclarativeRouteMapItem::setMap(QDeclarativeGeoMap* quickMap, Map *map) +{ + QDeclarativeGeoMapItemBase::setMap(quickMap,map); + if (map) QObject::connect(map, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); +} + QColor QDeclarativeRouteMapItem::color() const { return color_; @@ -69,9 +76,7 @@ void QDeclarativeRouteMapItem::setColor(const QColor &color) return; color_ = color; - //QBrush m_brush(color); - //polylineItem_->setBrush(m_brush); - polylineItem_->setPen(color); + updateMapItem(false); emit colorChanged(color_); } @@ -88,51 +93,66 @@ void QDeclarativeRouteMapItem::setRoute(QDeclarativeGeoRoute *route) route_ = route; if (route_) { - polylineItem_->setPath(route_->routePath()); + path_ = route_->routePath(); } else { - polylineItem_->setPath(QList<QGeoCoordinate>()); + path_ = QList<QGeoCoordinate>(); } - updateMapItem(); + updateMapItem(true); emit routeChanged(route_); } -void QDeclarativeRouteMapItem::updateContent() +QSGNode* QDeclarativeRouteMapItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) { - polylineItem_->updateGeometry(); - setWidth(polylineItem_->width()); - setHeight(polylineItem_->height()); -} + Q_UNUSED(data); -QPointF QDeclarativeRouteMapItem::contentTopLeftPoint() -{ - return map_->coordinateToScreenPosition( - polylineItem_->quickItemCoordinate(), false) - polylineItem_->quickItemAnchorPoint(); -} + MapPolylineNode *node = static_cast<MapPolylineNode*>(oldNode); -void QDeclarativeRouteMapItem::mapChanged() -{ - polylineItem_->setMap(map_); - if (map_) { - connect(map_, SIGNAL(cameraDataChanged(CameraData)), this, SLOT(handleCameraDataChanged(CameraData))); - // initial update - handleCameraDataChanged(map_->cameraData()); + if (!node) { + mapPolylineNode_ = new MapPolylineNode(); + updateMapItem(true); } + + mapPolylineNode_->update(); + return mapPolylineNode_; } -void QDeclarativeRouteMapItem::dragStarted() + +void QDeclarativeRouteMapItem::updateMapItem(bool dirtyGeometry) { + + if (!map() || path_.count() == 0 || !mapPolylineNode_) + return; + + mapPolylineNode_->setPenColor(color_); + + if (dirtyGeometry) mapPolylineNode_->setGeometry(*map(), path_); + + const QSizeF& size = mapPolylineNode_->size(); + + setWidth(size.width()); + setHeight(size.height()); + + setPositionOnMap(path_.at(0), mapPolylineNode_->geometry().at(0)); + update(); +} + +void QDeclarativeRouteMapItem::handleCameraDataChanged(const CameraData& cameraData) { - qmlInfo(this) << "warning: mouse dragging is not currently supported with polylines/routes."; + if (cameraData.zoomFactor() != zoomLevel_) { + zoomLevel_ = cameraData.zoomFactor(); + updateMapItem(true); + } else { + updateMapItem(false); + } } bool QDeclarativeRouteMapItem::contains(QPointF point) { - return polylineItem_->contains(point); + return mapPolylineNode_->contains(point); } -void QDeclarativeRouteMapItem::handleCameraDataChanged(const CameraData& cameraData) +void QDeclarativeRouteMapItem::dragStarted() { - polylineItem_->setZoomLevel(cameraData.zoomFactor()); - updateMapItem(); + qmlInfo(this) << "warning: mouse dragging is not currently supported with polylines/routes."; } diff --git a/src/imports/location/qdeclarativeroutemapitem_p.h b/src/imports/location/qdeclarativeroutemapitem_p.h index b46795a6..157acc41 100644 --- a/src/imports/location/qdeclarativeroutemapitem_p.h +++ b/src/imports/location/qdeclarativeroutemapitem_p.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QDeclarativeGeoRoute; -class PolylineMapPaintedItem; +class MapPolylineNode; class QDeclarativeRouteMapItem : public QDeclarativeGeoMapItemBase { @@ -64,6 +64,10 @@ public: QDeclarativeRouteMapItem(QQuickItem *parent = 0); ~QDeclarativeRouteMapItem(); + virtual void setMap(QDeclarativeGeoMap* quickMap, Map *map); + //from QuickItem + virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QDeclarativeGeoRoute* route() const; void setRoute(QDeclarativeGeoRoute *route); @@ -77,19 +81,19 @@ Q_SIGNALS: void routeChanged(const QDeclarativeGeoRoute *route); void colorChanged(const QColor &color); -protected: - void updateContent(); - QPointF contentTopLeftPoint(); - void mapChanged(); +protected Q_SLOTS: + virtual void updateMapItem(bool dirtyGeomoetry = true); private Q_SLOTS: // map size changed void handleCameraDataChanged(const CameraData& cameraData); private: - PolylineMapPaintedItem *polylineItem_; + MapPolylineNode *mapPolylineNode_; QDeclarativeGeoRoute* route_; QColor color_; + qreal zoomLevel_; + QList<QGeoCoordinate> path_; bool dragActive_; }; |