1/****************************************************************************
2**
3** Copyright (C) 2015 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 "qdeclarativerectanglemapitem_p.h"
38#include "qdeclarativerectanglemapitem_p_p.h"
39#include "qdeclarativepolygonmapitem_p.h"
40#include "qlocationutils_p.h"
41#include <QPainterPath>
42#include <qnumeric.h>
43#include <QRectF>
44#include <QPointF>
45#include <QtPositioning/private/qwebmercator_p.h>
46#include <QtLocation/private/qgeomap_p.h>
47#include <QtPositioning/private/qdoublevector2d_p.h>
48#include <QtCore/QScopedValueRollback>
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \qmltype MapRectangle
54 \instantiates QDeclarativeRectangleMapItem
55 \inqmlmodule QtLocation
56 \ingroup qml-QtLocation5-maps
57 \since QtLocation 5.5
58
59 \brief The MapRectangle type displays a rectangle on a Map.
60
61 The MapRectangle type displays a rectangle on a Map. Rectangles are a
62 special case of Polygon with exactly 4 vertices and 4 "straight" edges. In
63 this case, "straight" means that the top-left point has the same latitude
64 as the top-right point (the top edge), and the bottom-left point has the
65 same latitude as the bottom-right point (the bottom edge). Similarly, the
66 points on the left side have the same longitude, and the points on the
67 right side have the same longitude.
68
69 To specify the rectangle, it requires a \l topLeft and \l bottomRight point,
70 both given by a \l {coordinate}.
71
72 By default, the rectangle is displayed with transparent fill and a 1-pixel
73 thick black border. This can be changed using the \l color, \l border.color
74 and \l border.width properties.
75
76 \note Similar to the \l MapPolygon type, MapRectangles are geographic
77 items, thus dragging a MapRectangle causes its vertices to be recalculated
78 in the geographic coordinate space. Apparent stretching of the item
79 occurs when dragged to the a different latitude, however, its edges
80 remain straight.
81
82 \section2 Performance
83
84 MapRectangles have a rendering cost identical to a MapPolygon with 4
85 vertices.
86
87 Like the other map objects, MapRectangle is normally drawn without a smooth
88 appearance. Setting the \l opacity property will force the object to be
89 blended, which decreases performance considerably depending on the hardware
90 in use.
91
92 \section2 Example Usage
93
94 The following snippet shows a map containing a MapRectangle, spanning
95 from (-27, 153) to (-28, 153.5), near Brisbane, Australia. The rectangle
96 is filled in green, with a 2 pixel black border.
97
98 \code
99 Map {
100 MapRectangle {
101 color: 'green'
102 border.width: 2
103 topLeft {
104 latitude: -27
105 longitude: 153
106 }
107 bottomRight {
108 latitude: -28
109 longitude: 153.5
110 }
111 }
112 }
113 \endcode
114
115 \image api-maprectangle.png
116*/
117
118/*!
119 \qmlproperty bool QtLocation::MapRectangle::autoFadeIn
120
121 This property holds whether the item automatically fades in when zooming into the map
122 starting from very low zoom levels. By default this is \c true.
123 Setting this property to \c false causes the map item to always have the opacity specified
124 with the \l QtQuick::Item::opacity property, which is 1.0 by default.
125
126 \since 5.14
127*/
128
129struct RectangleBackendSelector
130{
131 RectangleBackendSelector()
132 {
133 backend = (qgetenv(varName: "QTLOCATION_OPENGL_ITEMS").toInt()) ? QDeclarativeRectangleMapItem::OpenGL : QDeclarativeRectangleMapItem::Software;
134 }
135 QDeclarativeRectangleMapItem::Backend backend = QDeclarativeRectangleMapItem::Software;
136};
137
138Q_GLOBAL_STATIC(RectangleBackendSelector, mapRectangleBackendSelector)
139
140QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
141: QDeclarativeGeoMapItemBase(parent), m_border(this), m_color(Qt::transparent), m_dirtyMaterial(true),
142 m_updatingGeometry(false)
143 , m_d(new QDeclarativeRectangleMapItemPrivateCPU(*this))
144{
145 // ToDo: handle envvar, and switch implementation.
146 m_itemType = QGeoMap::MapRectangle;
147 setFlag(flag: ItemHasContents, enabled: true);
148 QObject::connect(sender: &m_border, SIGNAL(colorChanged(QColor)),
149 receiver: this, SLOT(onLinePropertiesChanged()));
150 QObject::connect(sender: &m_border, SIGNAL(widthChanged(qreal)),
151 receiver: this, SLOT(onLinePropertiesChanged()));
152 setBackend(mapRectangleBackendSelector->backend);
153}
154
155QDeclarativeRectangleMapItem::~QDeclarativeRectangleMapItem()
156{
157}
158
159/*!
160 \qmlproperty MapRectangle.Backend QtLocation::MapRectangle::backend
161
162 This property holds which backend is in use to render the map item.
163 Valid values are \b MapRectangle.Software and \b{MapRectangle.OpenGL}.
164 The default value is \b{MapRectangle.Software}.
165
166 \note \b{The release of this API with Qt 5.15 is a Technology Preview}.
167 Ideally, as the OpenGL backends for map items mature, there will be
168 no more need to also offer the legacy software-projection backend.
169 So this property will likely disappear at some later point.
170 To select OpenGL-accelerated item backends without using this property,
171 it is also possible to set the environment variable \b QTLOCATION_OPENGL_ITEMS
172 to \b{1}.
173 Also note that all current OpenGL backends won't work as expected when enabling
174 layers on the individual item, or when running on OpenGL core profiles greater than 2.x.
175
176 \since 5.15
177*/
178QDeclarativeRectangleMapItem::Backend QDeclarativeRectangleMapItem::backend() const
179{
180 return m_backend;
181}
182
183void QDeclarativeRectangleMapItem::setBackend(QDeclarativeRectangleMapItem::Backend b)
184{
185 if (b == m_backend)
186 return;
187 m_backend = b;
188 QScopedPointer<QDeclarativeRectangleMapItemPrivate> d(
189 (m_backend == Software) ? static_cast<QDeclarativeRectangleMapItemPrivate *>(
190 new QDeclarativeRectangleMapItemPrivateCPU(*this))
191#if QT_CONFIG(opengl)
192 : static_cast<QDeclarativeRectangleMapItemPrivate *>(
193 new QDeclarativeRectangleMapItemPrivateOpenGL(*this)));
194#else
195 : nullptr);
196 qFatal("Requested non software rendering backend, but source code is compiled wihtout opengl "
197 "support");
198#endif
199
200 m_d.swap(other&: d);
201 m_d->onGeoGeometryChanged();
202 emit backendChanged();
203}
204
205/*!
206 \internal
207*/
208void QDeclarativeRectangleMapItem::setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map)
209{
210 QDeclarativeGeoMapItemBase::setMap(quickMap,map);
211 if (!map)
212 return;
213 m_d->onMapSet();
214}
215
216/*!
217 \qmlpropertygroup Location::MapRectangle::border
218 \qmlproperty int MapRectangle::border.width
219 \qmlproperty color MapRectangle::border.color
220
221 This property is part of the border property group. The border property group
222 holds the width and color used to draw the border of the rectangle.
223 The width is in pixels and is independent of the zoom level of the map.
224
225 The default values correspond to a black border with a width of 1 pixel.
226 For no line, use a width of 0 or a transparent color.
227*/
228QDeclarativeMapLineProperties *QDeclarativeRectangleMapItem::border()
229{
230 return &m_border;
231}
232
233/*!
234 \qmlproperty coordinate MapRectangle::topLeft
235
236 This property holds the top-left coordinate of the MapRectangle which
237 can be used to retrieve its longitude, latitude and altitude.
238*/
239void QDeclarativeRectangleMapItem::setTopLeft(const QGeoCoordinate &topLeft)
240{
241 if (m_rectangle.topLeft() == topLeft)
242 return;
243
244 m_rectangle.setTopLeft(topLeft);
245 m_d->onGeoGeometryChanged();
246 emit topLeftChanged(topLeft);
247}
248
249QGeoCoordinate QDeclarativeRectangleMapItem::topLeft()
250{
251 return m_rectangle.topLeft();
252}
253
254/*!
255 \internal
256*/
257void QDeclarativeRectangleMapItem::markSourceDirtyAndUpdate()
258{
259 m_d->markSourceDirtyAndUpdate();
260}
261
262void QDeclarativeRectangleMapItem::onLinePropertiesChanged()
263{
264 m_d->onLinePropertiesChanged();
265}
266
267/*!
268 \qmlproperty coordinate MapRectangle::bottomRight
269
270 This property holds the bottom-right coordinate of the MapRectangle which
271 can be used to retrieve its longitude, latitude and altitude.
272*/
273void QDeclarativeRectangleMapItem::setBottomRight(const QGeoCoordinate &bottomRight)
274{
275 if (m_rectangle.bottomRight() == bottomRight)
276 return;
277
278 m_rectangle.setBottomRight(bottomRight);
279 m_d->onGeoGeometryChanged();
280 emit bottomRightChanged(bottomRight);
281}
282
283QGeoCoordinate QDeclarativeRectangleMapItem::bottomRight()
284{
285 return m_rectangle.bottomRight();
286}
287
288/*!
289 \qmlproperty color MapRectangle::color
290
291 This property holds the fill color of the rectangle. For no fill, use
292 a transparent color.
293*/
294QColor QDeclarativeRectangleMapItem::color() const
295{
296 return m_color;
297}
298
299void QDeclarativeRectangleMapItem::setColor(const QColor &color)
300{
301 if (m_color == color)
302 return;
303 m_color = color;
304 m_dirtyMaterial = true;
305 polishAndUpdate();
306 emit colorChanged(color: m_color);
307}
308
309/*!
310 \qmlproperty real MapRectangle::opacity
311
312 This property holds the opacity of the item. Opacity is specified as a
313 number between 0 (fully transparent) and 1 (fully opaque). The default is 1.
314
315 An item with 0 opacity will still receive mouse events. To stop mouse events, set the
316 visible property of the item to false.
317*/
318
319/*!
320 \internal
321*/
322QSGNode *QDeclarativeRectangleMapItem::updateMapItemPaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
323{
324 return m_d->updateMapItemPaintNode(oldNode, data);
325}
326
327/*!
328 \internal
329*/
330void QDeclarativeRectangleMapItem::updatePolish()
331{
332 if (!map() || map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
333 return;
334 m_d->updatePolish();
335}
336
337/*!
338 \internal
339*/
340void QDeclarativeRectangleMapItem::afterViewportChanged(const QGeoMapViewportChangeEvent &event)
341{
342 if (event.mapSize.width() <= 0 || event.mapSize.height() <= 0)
343 return;
344 m_d->afterViewportChanged();
345}
346
347/*!
348 \internal
349*/
350bool QDeclarativeRectangleMapItem::contains(const QPointF &point) const
351{
352 return m_d->contains(point);
353}
354
355const QGeoShape &QDeclarativeRectangleMapItem::geoShape() const
356{
357 return m_rectangle;
358}
359
360void QDeclarativeRectangleMapItem::setGeoShape(const QGeoShape &shape)
361{
362 if (shape == m_rectangle)
363 return;
364
365 const QGeoRectangle rectangle = m_rectangle.boundingGeoRectangle();
366 const bool tlHasChanged = rectangle.topLeft() != m_rectangle.topLeft();
367 const bool brHasChanged = rectangle.bottomRight() != m_rectangle.bottomRight();
368 m_rectangle = rectangle;
369
370 m_d->onGeoGeometryChanged();
371 if (tlHasChanged)
372 emit topLeftChanged(topLeft: m_rectangle.topLeft());
373 if (brHasChanged)
374 emit bottomRightChanged(bottomRight: m_rectangle.bottomRight());
375}
376
377/*!
378 \internal
379*/
380void QDeclarativeRectangleMapItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
381{
382 if (!map() || !m_rectangle.isValid() || m_updatingGeometry || newGeometry.topLeft() == oldGeometry.topLeft()) {
383 QDeclarativeGeoMapItemBase::geometryChanged(newGeometry, oldGeometry);
384 return;
385 }
386 // TODO: change the algorithm to preserve the distances and size
387 QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(newGeometry.center()), clipToViewport: false);
388 QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(pos: QDoubleVector2D(oldGeometry.center()), clipToViewport: false);
389 if (!newCenter.isValid() || !oldCenter.isValid())
390 return;
391 double offsetLongi = newCenter.longitude() - oldCenter.longitude();
392 double offsetLati = newCenter.latitude() - oldCenter.latitude();
393 if (offsetLati == 0.0 && offsetLongi == 0.0)
394 return;
395
396 m_rectangle.translate(degreesLatitude: offsetLati, degreesLongitude: offsetLongi);
397 m_d->onItemGeometryChanged();
398 emit topLeftChanged(topLeft: m_rectangle.topLeft());
399 emit bottomRightChanged(bottomRight: m_rectangle.bottomRight());
400
401 // Not calling QDeclarativeGeoMapItemBase::geometryChanged() as it will be called from a nested
402 // call to this function.
403}
404
405QDeclarativeRectangleMapItemPrivate::~QDeclarativeRectangleMapItemPrivate() {}
406
407QDeclarativeRectangleMapItemPrivateCPU::~QDeclarativeRectangleMapItemPrivateCPU() {}
408
409#if QT_CONFIG(opengl)
410QDeclarativeRectangleMapItemPrivateOpenGL::~QDeclarativeRectangleMapItemPrivateOpenGL() {}
411#endif
412
413QT_END_NAMESPACE
414

source code of qtlocation/src/location/declarativemaps/qdeclarativerectanglemapitem.cpp