Marble

GeoPolyline.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2019 Torsten Rahn <[email protected]>
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 
20 using Marble::EARTH_RADIUS;
21 using Marble::DEG2RAD;
22 
23 namespace 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);
259  lineNode->setFlag(QSGNode::OwnsGeometry);
260  lineNode->setMaterial(material);
261  lineNode->setFlag(QSGNode::OwnsMaterial);
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 setDrawingMode(unsigned int mode)
QRectF boundingRect() const const
qreal x() const const
qreal y() const const
void appendChildNode(QSGNode *node)
void setGeometry(QSGGeometry *geometry)
const QSGGeometry::AttributeSet & defaultAttributes_Point2D()
const T & at(int i) const const
Binds a QML item to a specific geodetic location in screen coordinates.
void reserve(int size)
void setMaterial(QSGMaterial *material)
void setColor(const QColor &color)
qreal width() const const
void update(Part *part, const QByteArray &data, qint64 dataSize)
int size() const const
void allocate(int vertexCount, int indexCount)
QVector2D normalized() const const
QSGGeometry::Point2D * vertexDataAsPoint2D()
QFuture< void > map(Sequence &sequence, MapFunctor function)
qreal height() const const
void setFlag(QSGNode::Flag f, bool enabled)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:26 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.