Marble

AbstractGeoPolygonGraphicsItem.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2011 Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
4//
5
6#include "AbstractGeoPolygonGraphicsItem.h"
7
8#include "GeoDataLinearRing.h"
9#include "GeoDataPolygon.h"
10#include "GeoDataBuilding.h"
11#include "GeoPainter.h"
12#include "GeoDataLatLonAltBox.h"
13#include "GeoDataStyle.h"
14#include "GeoDataIconStyle.h"
15#include "GeoDataLineStyle.h"
16#include "GeoDataPlacemark.h"
17#include "GeoDataPolyStyle.h"
18#include "OsmPlacemarkData.h"
19#include "MarbleDebug.h"
20#include "ViewportParams.h"
21
22#include <QtMath>
23#include <QImageReader>
24#include <QPixmapCache>
25
26namespace Marble
27{
28
29const void *AbstractGeoPolygonGraphicsItem::s_previousStyle = nullptr;
30
31AbstractGeoPolygonGraphicsItem::AbstractGeoPolygonGraphicsItem(const GeoDataPlacemark *placemark, const GeoDataPolygon *polygon) :
32 GeoGraphicsItem(placemark),
33 m_polygon(polygon),
34 m_ring(nullptr),
35 m_building(nullptr)
36{
37}
38
39AbstractGeoPolygonGraphicsItem::AbstractGeoPolygonGraphicsItem(const GeoDataPlacemark *placemark, const GeoDataLinearRing *ring) :
40 GeoGraphicsItem(placemark),
41 m_polygon(nullptr),
42 m_ring(ring),
43 m_building(nullptr)
44{
45}
46
47AbstractGeoPolygonGraphicsItem::AbstractGeoPolygonGraphicsItem(const GeoDataPlacemark *placemark, const GeoDataBuilding *building) :
48 GeoGraphicsItem(placemark),
49 m_polygon(nullptr),
50 m_ring(nullptr),
51 m_building(building)
52{
53}
54
55AbstractGeoPolygonGraphicsItem::~AbstractGeoPolygonGraphicsItem()
56{
57}
58
59const GeoDataLatLonAltBox& AbstractGeoPolygonGraphicsItem::latLonAltBox() const
60{
61 if(m_polygon) {
62 return m_polygon->latLonAltBox();
63 } else if (m_ring) {
64 return m_ring->latLonAltBox();
65 }
66
67 return m_building->latLonAltBox();
68}
69
70void AbstractGeoPolygonGraphicsItem::paint( GeoPainter* painter, const ViewportParams* viewport, const QString &layer, int tileZoomLevel)
71{
72 Q_UNUSED(layer);
73 Q_UNUSED(tileZoomLevel);
74
75 bool isValid = true;
76 if (s_previousStyle != style().data()) {
77 isValid = configurePainter(painter, *viewport);
78 }
79 s_previousStyle = style().data();
80
81 if (!isValid) return;
82
83 if ( m_polygon ) {
84 bool innerResolved = false;
85
86 for(auto const & ring : m_polygon->innerBoundaries()) {
87 if (viewport->resolves(ring.latLonAltBox(), 4)) {
88 innerResolved = true;
89 break;
90 }
91 }
92
93 if (innerResolved) {
94 painter->drawPolygon(*m_polygon);
95 }
96 else {
97 painter->drawPolygon(m_polygon->outerBoundary());
98 }
99 } else if ( m_ring ) {
100 painter->drawPolygon( *m_ring );
101 }
102}
103
104bool AbstractGeoPolygonGraphicsItem::contains(const QPoint &screenPosition, const ViewportParams *viewport) const
105{
106 auto const visualCategory = static_cast<const GeoDataPlacemark*>(feature())->visualCategory();
107 if (visualCategory == GeoDataPlacemark::Landmass ||
108 visualCategory == GeoDataPlacemark::UrbanArea ||
109 (visualCategory >= GeoDataPlacemark::LanduseAllotments && visualCategory <= GeoDataPlacemark::LanduseVineyard)) {
110 return false;
111 }
112
113 double lon, lat;
114 viewport->geoCoordinates(screenPosition.x(), screenPosition.y(), lon, lat, GeoDataCoordinates::Radian);
115 auto const coordinates = GeoDataCoordinates(lon, lat);
116 if (m_polygon) {
117 return m_polygon->contains(coordinates);
118 } else if (m_ring) {
119 return m_ring->contains(coordinates);
120 }
121 return false;
122}
123
124bool AbstractGeoPolygonGraphicsItem::configurePainter(GeoPainter *painter, const ViewportParams &viewport) const
125{
126 QPen currentPen = painter->pen();
127 GeoDataStyle::ConstPtr style = this->style();
128 if (!style) {
129 painter->setPen( QPen() ); // "style-less" polygons: a 1px black solid line
130 }
131 else {
132 const GeoDataPolyStyle& polyStyle = style->polyStyle();
133
134 if (polyStyle.outline()) {
135 const GeoDataLineStyle& lineStyle = style->lineStyle();
136
137 // To save performance we avoid making changes to the painter's pen.
138 // So we first take a copy of the actual painter pen, make changes to it
139 // and only if the resulting pen is different from the actual pen
140 // we replace the painter's pen with our new pen.
141
142 // We want to avoid the mandatory detach in QPen::setColor(),
143 // so we carefully check whether applying the setter is needed
144 currentPen.setColor(lineStyle.paintedColor());
145 currentPen.setWidthF(lineStyle.width());
146 currentPen.setCapStyle(lineStyle.capStyle());
147 currentPen.setStyle(lineStyle.penStyle());
148
149 if (painter->pen().color() != currentPen.color()) {
150 painter->setPen(currentPen);
151 }
152 }
153 else {
154 // polygons without outline: Qt::NoPen (not drawn)
155 if (currentPen.style() != Qt::NoPen) {
156 painter->setPen(Qt::NoPen);
157 }
158 }
159
160 if (!polyStyle.fill()) {
161 painter->setBrush(Qt::transparent);
162 }
163 else {
164 const QColor paintedColor = polyStyle.paintedColor();
165 if (painter->brush().color() != paintedColor ||
166 painter->brush().style() != polyStyle.brushStyle()) {
167 if (!polyStyle.texturePath().isEmpty() || !polyStyle.textureImage().isNull()) {
168 GeoDataCoordinates coords = latLonAltBox().center();
169 qreal x, y;
170 viewport.screenCoordinates(coords, x, y);
171 QBrush brush(texture(polyStyle.texturePath(), paintedColor));
172 painter->setBrush(brush);
173 painter->setBrushOrigin(QPoint(x,y));
174 }
175 else {
176 painter->setBrush(QBrush(paintedColor, polyStyle.brushStyle()));
177 }
178 }
179 }
180 }
181
182 return true;
183}
184
185int AbstractGeoPolygonGraphicsItem::extractElevation(const GeoDataPlacemark &placemark)
186{
187 int elevation = 0;
188
189 const OsmPlacemarkData &osmData = placemark.osmData();
190
191 const auto tagIter = osmData.findTag(QStringLiteral("ele"));
192 if (tagIter != osmData.tagsEnd()) {
193 elevation = tagIter.value().toInt();
194 }
195
196 return elevation;
197}
198
199QPixmap AbstractGeoPolygonGraphicsItem::texture(const QString &texturePath, const QColor &color) const
200{
201 QString const key = QString::number(color.rgba()) + '/' + texturePath;
202 QPixmap texture;
203 if (!QPixmapCache::find(key, &texture)) {
204 QImageReader imageReader(style()->polyStyle().resolvePath(texturePath));
205 texture = QPixmap::fromImageReader(&imageReader);
206
207 if (texture.hasAlphaChannel()) {
208 QPixmap pixmap (texture.size());
209 pixmap.fill(color);
210 QPainter imagePainter(&pixmap);
211 imagePainter.drawPixmap(0, 0, texture);
212 imagePainter.end();
213 texture = pixmap;
214 }
215 QPixmapCache::insert(key, texture);
216 }
217 return texture;
218}
219
220void AbstractGeoPolygonGraphicsItem::setLinearRing(GeoDataLinearRing *ring)
221{
222 Q_ASSERT(m_building);
223 Q_ASSERT(!m_polygon);
224 m_ring = ring;
225}
226
227void AbstractGeoPolygonGraphicsItem::setPolygon(GeoDataPolygon *polygon)
228{
229 Q_ASSERT(m_building);
230 Q_ASSERT(!m_ring);
231 m_polygon = polygon;
232}
233
234}
This file contains the headers for ViewportParams.
bool isValid(QStringView ifopt)
Binds a QML item to a specific geodetic location in screen coordinates.
QRgb rgba() const const
QColor color() const const
void setCapStyle(Qt::PenCapStyle style)
void setColor(const QColor &color)
void setStyle(Qt::PenStyle style)
void setWidthF(qreal width)
Qt::PenStyle style() const const
QPixmap fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags)
bool hasAlphaChannel() const const
QSize size() const const
bool find(const Key &key, QPixmap *pixmap)
Key insert(const QPixmap &pixmap)
int x() const const
int y() const const
QString number(double n, char format, int precision)
transparent
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.