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
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 Jul 26 2024 11:57:57 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.