Marble

GeoPolyline.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2019 Torsten Rahn <rahn@kde.org>
4//
5
6#include "MarbleQuickItem.h"
7#include "GeoPolyline.h"
8#include "Coordinate.h"
9
10#include <QSGGeometryNode>
11#include <QSGFlatColorMaterial>
12#include <QSGSimpleTextureNode>
13#include <QSGTexture>
14#include <QPolygonF>
15#include <QtMath>
16
17#include "MarbleGlobal.h"
18
20using Marble::EARTH_RADIUS;
21using Marble::DEG2RAD;
22
23namespace Marble
24{
25 GeoPolyline::GeoPolyline(QQuickItem *parent ) :
26 QQuickItem( parent ),
27 m_map(nullptr),
28 m_observable(false),
29 m_lineColor(Qt::black),
30 m_lineWidth(1),
31 m_tessellate(true),
32 m_clipScreenCoordinates(true)
33 {
34 setFlag(ItemHasContents, true);
35 }
36
37 MarbleQuickItem * GeoPolyline::map() const
38 {
39 return m_map;
40 }
41
42 void GeoPolyline::setMap(MarbleQuickItem *map)
43 {
44 if (m_map == map)
45 return;
46
47 m_map = map;
48
49 connect(m_map, &MarbleQuickItem::visibleLatLonAltBoxChanged, this, &GeoPolyline::updateScreenPositions);
50 emit mapChanged(m_map);
51 }
52
53 void GeoPolyline::updateScreenPositions() {
54 GeoDataLineString lineString(m_lineString);
55
56 if (m_map) {
57 QPolygonF displayPolygon;
58 displayPolygon << QPointF(-10,-10) << QPointF(m_map->mapWidth() + 10, -10)
59 << QPointF(m_map->mapWidth() + 10, m_map->mapHeight() + 10) << QPointF(-10, m_map->mapHeight() + 10);
60 m_screenPolygons.clear();
61 QVector<QPolygonF*> fullScreenPolygons;
62 bool success = m_map->screenCoordinatesFromGeoDataLineString(lineString, fullScreenPolygons);
63 if (m_clipScreenCoordinates) {
64 for (auto reducedPolygon : qAsConst(fullScreenPolygons)) {
65 m_screenPolygons << reducedPolygon->intersected(displayPolygon);
66 }
67 }
68 else {
69 for (auto eachPolygon : qAsConst(fullScreenPolygons)) {
70 m_screenPolygons << *eachPolygon;
71 }
72 }
73
74 qDeleteAll(fullScreenPolygons);
75
76 QVariantList previousScreenCoordinates;
77 previousScreenCoordinates = m_screenCoordinates;
78 m_screenCoordinates.clear();
79 if (success) {
80 int i = 0;
81 for (auto screenPolygon : qAsConst(m_screenPolygons)) {
82 QVariantList polyline;
83 for (auto node : screenPolygon) {
84 QVariantMap vmap;
85 vmap["x"] = node.x();
86 vmap["y"] = node.y();
87 polyline.append(vmap);
88 }
89 m_screenCoordinates.insert(i, polyline);
90 ++i;
91 }
92 }
93
94 QRectF polygonBoundingRect;
95 if (m_screenPolygons.length() == 1) {
96 polygonBoundingRect = m_screenPolygons[0].boundingRect();
97 }
98 else {
99 QPolygonF polygons;
100 for (auto polygon : qAsConst(m_screenPolygons)) {
101 polygons << polygon;
102 }
103 polygonBoundingRect = polygons.boundingRect();
104 }
105 setX(polygonBoundingRect.x());
106 setY(polygonBoundingRect.y());
107 setWidth(polygonBoundingRect.width());
108 setHeight(polygonBoundingRect.height());
109
110 if (m_screenCoordinates != previousScreenCoordinates) {
111 emit screenCoordinatesChanged();
112 }
113 emit readonlyXChanged();
114 emit readonlyYChanged();
115 emit readonlyWidthChanged();
116 emit readonlyHeightChanged();
117 update();
118 }
119 }
120
121 bool GeoPolyline::observable() const
122 {
123 return m_observable;
124 }
125
126 QVariantList GeoPolyline::geoCoordinates() const
127 {
128 return m_geoCoordinates;
129 }
130
131 void GeoPolyline::setGeoCoordinates(const QVariantList & coordinates)
132 {
133 m_lineString.clear();
134 m_lineString.setTessellate(m_tessellate);
135 for(auto & item : coordinates) {
136 QVariantMap map = item.toMap();
137 m_lineString << GeoDataCoordinates(
138 map["lon"].toReal(),
139 map["lat"].toReal(),
140 map["alt"].toReal(),
141 GeoDataCoordinates::Degree
142 );
143 }
144
145 m_geoCoordinates = coordinates;
146 emit geoCoordinatesChanged();
147 updateScreenPositions();
148 }
149
150 QVariantList GeoPolyline::screenCoordinates() const
151 {
152 return m_screenCoordinates;
153 }
154
155 QColor GeoPolyline::lineColor() const
156 {
157 return m_lineColor;
158 }
159
160 qreal GeoPolyline::lineWidth() const
161 {
162 return m_lineWidth;
163 }
164
165 void GeoPolyline::setLineColor(const QColor& lineColor)
166 {
167 if (m_lineColor == lineColor)
168 return;
169
170 m_lineColor = lineColor;
171 emit lineColorChanged(m_lineColor);
172 }
173
174 void GeoPolyline::setLineWidth(const qreal lineWidth)
175 {
176 if (m_lineWidth == lineWidth)
177 return;
178
179 m_lineWidth = lineWidth;
180 emit lineWidthChanged(m_lineWidth);
181 }
182
183 bool GeoPolyline::tessellate() const
184 {
185 return m_tessellate;
186 }
187
188 bool GeoPolyline::clipScreenCoordinates() const
189 {
190 return m_clipScreenCoordinates;
191 }
192
193 void GeoPolyline::setTessellate(bool tessellate)
194 {
195 if (m_tessellate == tessellate)
196 return;
197
198 m_tessellate = tessellate;
199 emit tessellateChanged(m_tessellate);
200 }
201
202 void GeoPolyline::setClipScreenCoordinates(bool clipped)
203 {
204 if (m_clipScreenCoordinates == clipped)
205 return;
206
207 m_clipScreenCoordinates = clipped;
208 emit clipScreenCoordinatesChanged(m_clipScreenCoordinates);
209 }
210
211 qreal GeoPolyline::readonlyX() const
212 {
213 return x();
214 }
215
216 qreal GeoPolyline::readonlyY() const
217 {
218 return y();
219 }
220
221 qreal GeoPolyline::readonlyWidth() const
222 {
223 return width();
224 }
225
226 qreal GeoPolyline::readonlyHeight() const
227 {
228 return height();
229 }
230
231 QSGNode *GeoPolyline::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
232 {
233 qreal const halfWidth = m_lineWidth;
234
235 delete oldNode;
236 oldNode = new QSGNode;
237
238 if (m_screenPolygons.isEmpty()) return oldNode;
239
240 for(int i = 0; i < m_screenPolygons.length(); ++i) {
241 QPolygonF polygon = m_screenPolygons[i];
242 QVector<QVector2D> normals;
243 int segmentCount = polygon.size() - 1;
244 normals.reserve(segmentCount);
245 for(int i = 0; i < segmentCount; ++i) {
246 normals << QVector2D(polygon.at(i+1) - polygon.at(i)).normalized();
247 }
248 QSGGeometryNode* lineNode = new QSGGeometryNode;
249
250 QSGGeometry * lineNodeGeo = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), segmentCount*2);
251 lineNodeGeo->setDrawingMode(0x0005);
252 lineNodeGeo->allocate((segmentCount + 1)*2);
253
254
256 material->setColor(m_lineColor);
257
258 lineNode->setGeometry(lineNodeGeo);
260 lineNode->setMaterial(material);
262
263 auto points = lineNodeGeo->vertexDataAsPoint2D();
264 int k = -1;
265 for(int i = 0; i < segmentCount + 1; ++i) {
266 auto const & a = mapFromItem(m_map, polygon.at(i));
267 auto const & n = normals[qMin(i, segmentCount - 1)].toPointF();
268 points[++k].set(a.x() - halfWidth * n.y(), a.y() + halfWidth * n.x());
269 points[++k].set(a.x() + halfWidth * n.y(), a.y() - halfWidth * n.x());
270 }
271 oldNode->appendChildNode(lineNode);
272 }
273
274 return oldNode;
275 }
276}
277
278#include "moc_GeoPolyline.cpp"
A 3d point representation.
void update(Part *part, const QByteArray &data, qint64 dataSize)
Binds a QML item to a specific geodetic location in screen coordinates.
const_reference at(qsizetype i) const const
void reserve(qsizetype size)
qsizetype size() const const
T qobject_cast(QObject *object)
QRectF boundingRect() const const
qreal height() const const
qreal width() const const
qreal x() const const
qreal y() const const
void setGeometry(QSGGeometry *geometry)
void setColor(const QColor &color)
void allocate(int vertexCount, int indexCount)
const AttributeSet & defaultAttributes_Point2D()
void setDrawingMode(unsigned int mode)
Point2D * vertexDataAsPoint2D()
void setMaterial(QSGMaterial *material)
void appendChildNode(QSGNode *node)
void setFlag(Flag f, bool enabled)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVector2D normalized() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:49:04 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.