1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qmappolygonobjectqsg_p_p.h"
38 #include <QtQuick/qsgnode.h>
39 #include <QtQuick/qsgsimplerectnode.h>
40 #include <QtPositioning/private/qgeopolygon_p.h>
41 
42 QT_BEGIN_NAMESPACE
43 
QMapPolygonObjectPrivateQSG(QGeoMapObject * q)44 QMapPolygonObjectPrivateQSG::QMapPolygonObjectPrivateQSG(QGeoMapObject *q)
45     : QMapPolygonObjectPrivateDefault(q)
46 {
47 
48 }
49 
QMapPolygonObjectPrivateQSG(const QMapPolygonObjectPrivate & other)50 QMapPolygonObjectPrivateQSG::QMapPolygonObjectPrivateQSG(const QMapPolygonObjectPrivate &other)
51     : QMapPolygonObjectPrivateDefault(other)
52 {
53     // Data already cloned by the *Default copy constructor, but necessary
54     // update operations triggered only by setters overrides
55     markSourceDirty();
56     updateGeometry();
57     if (m_map)
58         emit m_map->sgNodeChanged();
59 }
60 
~QMapPolygonObjectPrivateQSG()61 QMapPolygonObjectPrivateQSG::~QMapPolygonObjectPrivateQSG()
62 {
63     if (m_map)
64         m_map->removeMapObject(q);
65 }
66 
setPath(const QList<QGeoCoordinate> & p)67 void QMapPolygonObjectPrivateQSG::setPath(const QList<QGeoCoordinate> &p)
68 {
69     if (p == path())
70         return;
71     QMapPolygonObjectPrivateDefault::setPath(p);
72     markSourceDirty();
73     updateGeometry();
74 
75     if (m_map)
76         emit m_map->sgNodeChanged();
77     emit static_cast<QMapPolygonObject *>(q)->pathChanged();
78 }
79 
setFillColor(const QColor & color)80 void QMapPolygonObjectPrivateQSG::setFillColor(const QColor &color)
81 {
82     QMapPolygonObjectPrivateDefault::setFillColor(color);
83 
84     if (m_map)
85         emit m_map->sgNodeChanged();
86 }
87 
setBorderColor(const QColor & color)88 void QMapPolygonObjectPrivateQSG::setBorderColor(const QColor &color)
89 {
90     QMapPolygonObjectPrivateDefault::setBorderColor(color);
91 
92     if (m_map)
93         emit m_map->sgNodeChanged();
94 }
95 
setBorderWidth(qreal width)96 void QMapPolygonObjectPrivateQSG::setBorderWidth(qreal width)
97 {
98     QMapPolygonObjectPrivateDefault::setBorderWidth(width);
99 
100     if (m_map)
101         emit m_map->sgNodeChanged();
102 }
103 
clone()104 QGeoMapObjectPrivate *QMapPolygonObjectPrivateQSG::clone()
105 {
106     return new QMapPolygonObjectPrivateQSG(static_cast<QMapPolygonObjectPrivate &>(*this));
107 }
108 
setGeoShape(const QGeoShape & shape)109 void QMapPolygonObjectPrivateQSG::setGeoShape(const QGeoShape &shape)
110 {
111     if (shape == m_path)
112         return;
113 
114     m_path = QGeoPathEager(shape);
115     markSourceDirty();
116     updateGeometry();
117     if (m_map)
118         emit m_map->sgNodeChanged();
119     emit static_cast<QMapPolygonObject *>(q)->pathChanged();
120 }
121 
122 // This is called both when data changes and when viewport changes.
123 // so handle both cases (sourceDirty, !sourceDirty)
updateGeometry()124 void QMapPolygonObjectPrivateQSG::updateGeometry()
125 {
126     if (!m_map || m_map->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
127         return;
128 
129     if (m_path.path().length() == 0) { // Possibly cleared
130         m_geometry.clear();
131         m_borderGeometry.clear();
132         return;
133     }
134     const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_map->geoProjection());
135     if (m_geometry.isSourceDirty() || m_borderGeometry.isSourceDirty()) {
136         // This works a bit differently than MapPolygon:
137         // the "screen bounds" aren't needed, so update only sources,
138         // regardless of the color, as color changes won't trigger polish(),
139         // and remember to flag m_dataChanged, that is in principle the same as
140         // sourceDirty_, but in practice is cleared in two different codepaths.
141         // sourceDirty_ is cleared in any case, dataChanged only if the primitive
142         // is effectively visible (e.g., not transparent or border not null)
143         m_geometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
144         m_borderGeometry.setPreserveGeometry(true, m_path.boundingGeoRectangle().topLeft());
145         m_geometry.m_dataChanged = m_borderGeometry.m_dataChanged = true;
146         m_geometry.updateSourcePoints(*m_map, m_path);
147         m_borderGeometry.updateSourcePoints(*m_map, m_path);
148         m_leftBoundMercator = p.geoToMapProjection(m_geometry.origin());
149     }
150     m_geometry.markScreenDirty();       // ToDo: this needs refactor. It's useless, remove screenDirty_ altogether.
151     m_borderGeometry.markScreenDirty();
152     m_borderGeometry.m_wrapOffset = m_geometry.m_wrapOffset = p.projectionWrapFactor(m_leftBoundMercator) + 1;
153 }
154 
updateMapObjectNode(QSGNode * oldNode,VisibleNode ** visibleNode,QSGNode * root,QQuickWindow *)155 QSGNode *QMapPolygonObjectPrivateQSG::updateMapObjectNode(QSGNode *oldNode,
156                                                           VisibleNode **visibleNode,
157                                                           QSGNode *root,
158                                                           QQuickWindow * /*window*/)
159 {
160     if (!m_rootNode || !oldNode) {
161         m_rootNode = new QDeclarativePolygonMapItemPrivateOpenGL::RootNode();
162         m_node = new MapPolygonNodeGL();
163         m_rootNode->appendChildNode(m_node);
164         m_polylinenode = new MapPolylineNodeOpenGLExtruded();
165         m_rootNode->appendChildNode(m_polylinenode);
166         m_rootNode->markDirty(QSGNode::DirtyNodeAdded);
167         *visibleNode = static_cast<VisibleNode *>(m_rootNode);
168         if (oldNode)
169             delete oldNode;
170     } else {
171         m_rootNode = static_cast<QDeclarativePolygonMapItemPrivateOpenGL::RootNode *>(oldNode);
172     }
173 
174     const QMatrix4x4 &combinedMatrix = m_map->geoProjection().qsgTransform();
175     const QDoubleVector3D &cameraCenter = m_map->geoProjection().centerMercator();
176 
177     if (m_borderGeometry.isScreenDirty()) {
178         /* Do the border update first */
179         m_polylinenode->update(borderColor(),
180                                float(borderWidth()),
181                                &m_borderGeometry,
182                                combinedMatrix,
183                                cameraCenter,
184                                Qt::SquareCap,
185                                true);
186         m_borderGeometry.setPreserveGeometry(false);
187         m_borderGeometry.markClean();
188     }
189     if (m_geometry.isScreenDirty()) {
190         m_node->update(fillColor(),
191                      &m_geometry,
192                      combinedMatrix,
193                      cameraCenter);
194         m_geometry.setPreserveGeometry(false);
195         m_geometry.markClean();
196     }
197 
198     if (!m_polylinenode->isSubtreeBlocked() || !m_node->isSubtreeBlocked()) {
199         m_rootNode->setSubtreeBlocked(false);
200         root->appendChildNode(m_rootNode);
201         return m_rootNode;
202     } else {
203         m_rootNode->setSubtreeBlocked(true);
204         // If the object is currently invisible, but not gone,
205         // it is reasonable to assume it will become visible again.
206         // However, better not to retain unused data.
207         delete m_rootNode;
208         m_rootNode = nullptr;
209         m_node = nullptr;
210         m_polylinenode = nullptr;
211         *visibleNode = nullptr;
212         return nullptr;
213     }
214 }
215 
markSourceDirty()216 void QMapPolygonObjectPrivateQSG::markSourceDirty()
217 {
218     m_geometry.markSourceDirty();
219     m_borderGeometry.markSourceDirty();
220 }
221 
222 QT_END_NAMESPACE
223