Changeset View
Changeset View
Standalone View
Standalone View
src/lib/marble/geodata/graphicsitem/BuildingGraphicsItem.cpp
- This file was moved from src/lib/marble/geodata/graphicsitem/BuildingGeoPolygonGraphicsItem.cpp.
1 | // | 1 | // | ||
---|---|---|---|---|---|
2 | // This file is part of the Marble Virtual Globe. | 2 | // This file is part of the Marble Virtual Globe. | ||
3 | // | 3 | // | ||
4 | // This program is free software licensed under the GNU LGPL. You can | 4 | // This program is free software licensed under the GNU LGPL. You can | ||
5 | // find a copy of this license in LICENSE.txt in the top directory of | 5 | // find a copy of this license in LICENSE.txt in the top directory of | ||
6 | // the source code. | 6 | // the source code. | ||
7 | // | 7 | // | ||
8 | // Copyright 2011 Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com> | 8 | // Copyright 2011 Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com> | ||
9 | // | 9 | // | ||
10 | 10 | | |||
11 | #include "BuildingGeoPolygonGraphicsItem.h" | 11 | #include "BuildingGraphicsItem.h" | ||
12 | 12 | | |||
13 | #include "MarbleDebug.h" | 13 | #include "MarbleDebug.h" | ||
14 | #include "ViewportParams.h" | 14 | #include "ViewportParams.h" | ||
15 | #include "GeoDataTypes.h" | 15 | #include "GeoDataTypes.h" | ||
16 | #include "GeoDataPlacemark.h" | 16 | #include "GeoDataPlacemark.h" | ||
17 | #include "GeoDataLinearRing.h" | 17 | #include "GeoDataLinearRing.h" | ||
18 | #include "GeoDataPolygon.h" | 18 | #include "GeoDataPolygon.h" | ||
19 | #include "GeoDataBuilding.h" | ||||
20 | #include "GeoDataMultiGeometry.h" | ||||
19 | #include "GeoDataPolyStyle.h" | 21 | #include "GeoDataPolyStyle.h" | ||
20 | #include "OsmPlacemarkData.h" | 22 | #include "OsmPlacemarkData.h" | ||
21 | #include "GeoPainter.h" | 23 | #include "GeoPainter.h" | ||
22 | 24 | | |||
23 | #include <QScreen> | 25 | #include <QScreen> | ||
24 | #include <QApplication> | 26 | #include <QApplication> | ||
25 | 27 | | |||
26 | namespace Marble | 28 | namespace Marble | ||
27 | { | 29 | { | ||
28 | 30 | | |||
29 | BuildingGeoPolygonGraphicsItem::BuildingGeoPolygonGraphicsItem(const GeoDataPlacemark *placemark, | 31 | BuildingGraphicsItem::BuildingGraphicsItem(const GeoDataPlacemark *placemark, const GeoDataBuilding *building) | ||
30 | const GeoDataPolygon *polygon) | 32 | : AbstractGeoPolygonGraphicsItem(placemark, building) | ||
31 | : AbstractGeoPolygonGraphicsItem(placemark, polygon) | | |||
32 | , m_buildingHeight(extractBuildingHeight(*placemark)) | | |||
33 | , m_buildingText(extractBuildingLabel(*placemark)) | | |||
34 | , m_entries(extractNamedEntries(*placemark)) | | |||
35 | , m_hasInnerBoundaries(false) | | |||
36 | { | 33 | { | ||
37 | setZValue(m_buildingHeight); | 34 | if (const auto ring = geodata_cast<GeoDataLinearRing>(&building->multiGeometry()->at(0))) { | ||
38 | Q_ASSERT(m_buildingHeight > 0.0); | 35 | setLinearRing(ring); | ||
39 | 36 | } else if (const auto poly = geodata_cast<GeoDataPolygon>(&building->multiGeometry()->at(0))) { | |||
40 | QStringList paintLayers; | 37 | setPolygon(poly); | ||
41 | paintLayers << QStringLiteral("Polygon/Building/frame") | | |||
42 | << QStringLiteral("Polygon/Building/roof"); | | |||
43 | setPaintLayers(paintLayers); | | |||
44 | } | 38 | } | ||
45 | 39 | | |||
46 | BuildingGeoPolygonGraphicsItem::BuildingGeoPolygonGraphicsItem(const GeoDataPlacemark *placemark, | 40 | setZValue(building->height()); | ||
47 | const GeoDataLinearRing* ring) | 41 | Q_ASSERT(building->height() > 0.0); | ||
48 | : AbstractGeoPolygonGraphicsItem(placemark, ring) | | |||
49 | , m_buildingHeight(extractBuildingHeight(*placemark)) | | |||
50 | , m_buildingText(extractBuildingLabel(*placemark)) | | |||
51 | , m_entries(extractNamedEntries(*placemark)) | | |||
52 | { | | |||
53 | setZValue(m_buildingHeight); | | |||
54 | Q_ASSERT(m_buildingHeight > 0.0); | | |||
55 | 42 | | |||
56 | QStringList paintLayers; | 43 | QStringList paintLayers; | ||
57 | paintLayers << QStringLiteral("Polygon/Building/frame") | 44 | paintLayers << QStringLiteral("Polygon/Building/frame") | ||
58 | << QStringLiteral("Polygon/Building/roof"); | 45 | << QStringLiteral("Polygon/Building/roof"); | ||
59 | setPaintLayers(paintLayers); | 46 | setPaintLayers(paintLayers); | ||
60 | } | 47 | } | ||
61 | 48 | | |||
62 | BuildingGeoPolygonGraphicsItem::~BuildingGeoPolygonGraphicsItem() | 49 | BuildingGraphicsItem::~BuildingGraphicsItem() | ||
63 | { | 50 | { | ||
64 | qDeleteAll(m_cachedOuterPolygons); | 51 | qDeleteAll(m_cachedOuterPolygons); | ||
65 | qDeleteAll(m_cachedInnerPolygons); | 52 | qDeleteAll(m_cachedInnerPolygons); | ||
66 | qDeleteAll(m_cachedOuterRoofPolygons); | 53 | qDeleteAll(m_cachedOuterRoofPolygons); | ||
67 | qDeleteAll(m_cachedInnerRoofPolygons); | 54 | qDeleteAll(m_cachedInnerRoofPolygons); | ||
68 | } | 55 | } | ||
69 | 56 | | |||
70 | void BuildingGeoPolygonGraphicsItem::initializeBuildingPainting(const GeoPainter* painter, const ViewportParams *viewport, | 57 | void BuildingGraphicsItem::initializeBuildingPainting(const GeoPainter* painter, const ViewportParams *viewport, | ||
71 | bool &drawAccurate3D, bool &isCameraAboveBuilding ) const | 58 | bool &drawAccurate3D, bool &isCameraAboveBuilding ) const | ||
72 | { | 59 | { | ||
73 | drawAccurate3D = false; | 60 | drawAccurate3D = false; | ||
74 | isCameraAboveBuilding = false; | 61 | isCameraAboveBuilding = false; | ||
75 | 62 | | |||
76 | auto const screen = QApplication::screens().first(); | 63 | auto const screen = QApplication::screens().first(); | ||
77 | double const physicalSize = 1.0; // mm | 64 | double const physicalSize = 1.0; // mm | ||
78 | int const pixelSize = qRound(physicalSize * screen->physicalDotsPerInch() / (IN2M * M2MM)); | 65 | int const pixelSize = qRound(physicalSize * screen->physicalDotsPerInch() / (IN2M * M2MM)); | ||
79 | 66 | | |||
80 | QPointF offsetAtCorner = buildingOffset(QPointF(0, 0), viewport, &isCameraAboveBuilding); | 67 | QPointF offsetAtCorner = buildingOffset(QPointF(0, 0), viewport, &isCameraAboveBuilding); | ||
81 | qreal maxOffset = qMax( qAbs( offsetAtCorner.x() ), qAbs( offsetAtCorner.y() ) ); | 68 | qreal maxOffset = qMax( qAbs( offsetAtCorner.x() ), qAbs( offsetAtCorner.y() ) ); | ||
82 | drawAccurate3D = painter->mapQuality() == HighQuality ? maxOffset > pixelSize : maxOffset > 1.5 * pixelSize; | 69 | drawAccurate3D = painter->mapQuality() == HighQuality ? maxOffset > pixelSize : maxOffset > 1.5 * pixelSize; | ||
83 | } | 70 | } | ||
84 | 71 | | |||
85 | void BuildingGeoPolygonGraphicsItem::updatePolygons( const ViewportParams *viewport, | 72 | void BuildingGraphicsItem::updatePolygons(const ViewportParams *viewport, | ||
86 | QVector<QPolygonF*>& outerPolygons, | 73 | QVector<QPolygonF*>& outerPolygons, | ||
87 | QVector<QPolygonF*>& innerPolygons, | 74 | QVector<QPolygonF*>& innerPolygons, | ||
88 | bool &hasInnerBoundaries ) | 75 | bool &hasInnerBoundaries ) | ||
89 | { | 76 | { | ||
90 | // Since subtracting one fully contained polygon from another results in a single | 77 | // Since subtracting one fully contained polygon from another results in a single | ||
91 | // polygon with a "connecting line" between the inner and outer part we need | 78 | // polygon with a "connecting line" between the inner and outer part we need | ||
92 | // to first paint the inner area with no pen and then the outlines with the correct pen. | 79 | // to first paint the inner area with no pen and then the outlines with the correct pen. | ||
93 | hasInnerBoundaries = polygon() ? !polygon()->innerBoundaries().isEmpty() : false; | 80 | hasInnerBoundaries = polygon() ? !polygon()->innerBoundaries().isEmpty() : false; | ||
94 | if (polygon()) { | 81 | if (polygon()) { | ||
95 | if (hasInnerBoundaries) { | 82 | if (hasInnerBoundaries) { | ||
96 | screenPolygons(viewport, polygon(), innerPolygons, outerPolygons); | 83 | screenPolygons(viewport, polygon(), innerPolygons, outerPolygons); | ||
97 | } | 84 | } | ||
98 | else { | 85 | else { | ||
99 | viewport->screenCoordinates(polygon()->outerBoundary(), outerPolygons); | 86 | viewport->screenCoordinates(polygon()->outerBoundary(), outerPolygons); | ||
100 | } | 87 | } | ||
101 | } else if (ring()) { | 88 | } else if (ring()) { | ||
102 | viewport->screenCoordinates(*ring(), outerPolygons); | 89 | viewport->screenCoordinates(*ring(), outerPolygons); | ||
103 | } | 90 | } | ||
104 | } | 91 | } | ||
105 | 92 | | |||
106 | QPointF BuildingGeoPolygonGraphicsItem::centroid(const QPolygonF &polygon, double &area) | 93 | QPointF BuildingGraphicsItem::centroid(const QPolygonF &polygon, double &area) | ||
107 | { | 94 | { | ||
108 | auto centroid = QPointF(0.0, 0.0); | 95 | auto centroid = QPointF(0.0, 0.0); | ||
109 | area = 0.0; | 96 | area = 0.0; | ||
110 | for (auto i=0, n=polygon.size(); i<n; ++i) { | 97 | for (auto i=0, n=polygon.size(); i<n; ++i) { | ||
111 | auto const x0 = polygon[i].x(); | 98 | auto const x0 = polygon[i].x(); | ||
112 | auto const y0 = polygon[i].y(); | 99 | auto const y0 = polygon[i].y(); | ||
113 | auto const j = i == n-1 ? 0 : i+1; | 100 | auto const j = i == n-1 ? 0 : i+1; | ||
114 | auto const x1 = polygon[j].x(); | 101 | auto const x1 = polygon[j].x(); | ||
115 | auto const y1 = polygon[j].y(); | 102 | auto const y1 = polygon[j].y(); | ||
116 | auto const a = x0*y1 - x1*y0; | 103 | auto const a = x0*y1 - x1*y0; | ||
117 | area += a; | 104 | area += a; | ||
118 | centroid.rx() += (x0 + x1)*a; | 105 | centroid.rx() += (x0 + x1)*a; | ||
119 | centroid.ry() += (y0 + y1)*a; | 106 | centroid.ry() += (y0 + y1)*a; | ||
120 | } | 107 | } | ||
121 | 108 | | |||
122 | area *= 0.5; | 109 | area *= 0.5; | ||
123 | return area != 0 ? centroid / (6.0*area) : polygon.boundingRect().center(); | 110 | return area != 0 ? centroid / (6.0*area) : polygon.boundingRect().center(); | ||
124 | } | 111 | } | ||
125 | 112 | | |||
126 | QPointF BuildingGeoPolygonGraphicsItem::buildingOffset(const QPointF &point, const ViewportParams *viewport, bool* isCameraAboveBuilding) const | 113 | QPointF BuildingGraphicsItem::buildingOffset(const QPointF &point, const ViewportParams *viewport, bool* isCameraAboveBuilding) const | ||
127 | { | 114 | { | ||
128 | qreal const cameraFactor = 0.5 * tan(0.5 * 110 * DEG2RAD); | 115 | qreal const cameraFactor = 0.5 * tan(0.5 * 110 * DEG2RAD); | ||
129 | Q_ASSERT(m_buildingHeight > 0.0); | 116 | Q_ASSERT(building()->height() > 0.0); | ||
130 | qreal const buildingFactor = m_buildingHeight / EARTH_RADIUS; | 117 | qreal const buildingFactor = building()->height() / EARTH_RADIUS; | ||
131 | 118 | | |||
132 | qreal const cameraHeightPixel = viewport->width() * cameraFactor; | 119 | qreal const cameraHeightPixel = viewport->width() * cameraFactor; | ||
133 | qreal buildingHeightPixel = viewport->radius() * buildingFactor; | 120 | qreal buildingHeightPixel = viewport->radius() * buildingFactor; | ||
134 | qreal const cameraDistance = cameraHeightPixel-buildingHeightPixel; | 121 | qreal const cameraDistance = cameraHeightPixel-buildingHeightPixel; | ||
135 | 122 | | |||
136 | if (isCameraAboveBuilding) { | 123 | if (isCameraAboveBuilding) { | ||
137 | *isCameraAboveBuilding = cameraDistance > 0; | 124 | *isCameraAboveBuilding = cameraDistance > 0; | ||
138 | } | 125 | } | ||
Show All 11 Lines | |||||
150 | qreal const offsetY = point.y() - viewport->height() / 2.0; | 137 | qreal const offsetY = point.y() - viewport->height() / 2.0; | ||
151 | 138 | | |||
152 | qreal const shiftX = offsetX * cb / (cc + offsetX); | 139 | qreal const shiftX = offsetX * cb / (cc + offsetX); | ||
153 | qreal const shiftY = offsetY * cb / (cc + offsetY); | 140 | qreal const shiftY = offsetY * cb / (cc + offsetY); | ||
154 | 141 | | |||
155 | return QPointF(shiftX, shiftY); | 142 | return QPointF(shiftX, shiftY); | ||
156 | } | 143 | } | ||
157 | 144 | | |||
158 | double BuildingGeoPolygonGraphicsItem::extractBuildingHeight(const GeoDataPlacemark &placemark) | 145 | void BuildingGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport, const QString &layer, int tileZoomLevel) | ||
159 | { | | |||
160 | double height = 8.0; | | |||
161 | | ||||
162 | const OsmPlacemarkData &osmData = placemark.osmData(); | | |||
163 | | ||||
164 | QHash<QString, QString>::const_iterator tagIter; | | |||
165 | if ((tagIter = osmData.findTag(QStringLiteral("height"))) != osmData.tagsEnd()) { | | |||
166 | /** @todo Also parse non-SI units, see https://wiki.openstreetmap.org/wiki/Key:height#Height_of_buildings */ | | |||
167 | QString const heightValue = QString(tagIter.value()).remove(QStringLiteral(" meters")).remove(QStringLiteral(" m")); | | |||
168 | bool extracted = false; | | |||
169 | double extractedHeight = heightValue.toDouble(&extracted); | | |||
170 | if (extracted) { | | |||
171 | height = extractedHeight; | | |||
172 | } | | |||
173 | } else if ((tagIter = osmData.findTag(QStringLiteral("building:levels"))) != osmData.tagsEnd()) { | | |||
174 | int const levels = tagIter.value().toInt(); | | |||
175 | int const skipLevels = osmData.tagValue(QStringLiteral("building:min_level")).toInt(); | | |||
176 | /** @todo Is 35 as an upper bound for the number of levels sane? */ | | |||
177 | height = 3.0 * qBound(1, 1+levels-skipLevels, 35); | | |||
178 | } | | |||
179 | | ||||
180 | return qBound(1.0, height, 1000.0); | | |||
181 | } | | |||
182 | | ||||
183 | QString BuildingGeoPolygonGraphicsItem::extractBuildingLabel(const GeoDataPlacemark &placemark) | | |||
184 | { | | |||
185 | const OsmPlacemarkData &osmData = placemark.osmData(); | | |||
186 | | ||||
187 | auto tagIter = osmData.findTag(QStringLiteral("addr:housename")); | | |||
188 | if (tagIter != osmData.tagsEnd()) { | | |||
189 | return tagIter.value(); | | |||
190 | } | | |||
191 | | ||||
192 | tagIter = osmData.findTag(QStringLiteral("addr:housenumber")); | | |||
193 | if (tagIter != osmData.tagsEnd()) { | | |||
194 | return tagIter.value(); | | |||
195 | } | | |||
196 | | ||||
197 | return QString(); | | |||
198 | } | | |||
199 | | ||||
200 | QVector<BuildingGeoPolygonGraphicsItem::NamedEntry> BuildingGeoPolygonGraphicsItem::extractNamedEntries(const GeoDataPlacemark &placemark) | | |||
201 | { | | |||
202 | QVector<NamedEntry> entries; | | |||
203 | | ||||
204 | const auto end = placemark.osmData().nodeReferencesEnd(); | | |||
205 | for (auto iter = placemark.osmData().nodeReferencesBegin(); iter != end; ++iter) { | | |||
206 | const auto tagIter = iter.value().findTag(QStringLiteral("addr:housenumber")); | | |||
207 | if (tagIter != iter.value().tagsEnd()) { | | |||
208 | NamedEntry entry; | | |||
209 | entry.point = iter.key(); | | |||
210 | entry.label = tagIter.value(); | | |||
211 | entries.push_back(entry); | | |||
212 | } | | |||
213 | } | | |||
214 | | ||||
215 | return entries; | | |||
216 | } | | |||
217 | | ||||
218 | void BuildingGeoPolygonGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport, const QString &layer, int tileZoomLevel) | | |||
219 | { | 146 | { | ||
220 | // Just display flat buildings for tile level 17 | 147 | // Just display flat buildings for tile level 17 | ||
221 | if (tileZoomLevel == 17) { | 148 | if (tileZoomLevel == 17) { | ||
222 | setZValue(0.0); | 149 | setZValue(0.0); | ||
223 | if (layer.endsWith(QLatin1String("/roof"))) { | 150 | if (layer.endsWith(QLatin1String("/roof"))) { | ||
224 | AbstractGeoPolygonGraphicsItem::paint(painter, viewport, layer, tileZoomLevel ); | 151 | AbstractGeoPolygonGraphicsItem::paint(painter, viewport, layer, tileZoomLevel ); | ||
225 | } | 152 | } | ||
226 | return; | 153 | return; | ||
227 | } | 154 | } | ||
228 | setZValue(m_buildingHeight); | 155 | setZValue(building()->height()); | ||
229 | 156 | | |||
230 | // For level 18, 19 .. render 3D buildings in perspective | 157 | // For level 18, 19 .. render 3D buildings in perspective | ||
231 | if (layer.endsWith(QLatin1String("/frame"))) { | 158 | if (layer.endsWith(QLatin1String("/frame"))) { | ||
232 | qDeleteAll(m_cachedOuterPolygons); | 159 | qDeleteAll(m_cachedOuterPolygons); | ||
233 | qDeleteAll(m_cachedInnerPolygons); | 160 | qDeleteAll(m_cachedInnerPolygons); | ||
234 | qDeleteAll(m_cachedOuterRoofPolygons); | 161 | qDeleteAll(m_cachedOuterRoofPolygons); | ||
235 | qDeleteAll(m_cachedInnerRoofPolygons); | 162 | qDeleteAll(m_cachedInnerRoofPolygons); | ||
236 | m_cachedOuterPolygons.clear(); | 163 | m_cachedOuterPolygons.clear(); | ||
Show All 12 Lines | 175 | if (m_cachedOuterPolygons.isEmpty()) { | |||
249 | return; | 176 | return; | ||
250 | } | 177 | } | ||
251 | paintRoof(painter, viewport); | 178 | paintRoof(painter, viewport); | ||
252 | } else { | 179 | } else { | ||
253 | mDebug() << "Didn't expect to have to paint layer " << layer << ", ignoring it."; | 180 | mDebug() << "Didn't expect to have to paint layer " << layer << ", ignoring it."; | ||
254 | } | 181 | } | ||
255 | } | 182 | } | ||
256 | 183 | | |||
257 | void BuildingGeoPolygonGraphicsItem::paintRoof(GeoPainter* painter, const ViewportParams* viewport) | 184 | void BuildingGraphicsItem::paintRoof(GeoPainter* painter, const ViewportParams* viewport) | ||
258 | { | 185 | { | ||
259 | bool drawAccurate3D; | 186 | bool drawAccurate3D; | ||
260 | bool isCameraAboveBuilding; | 187 | bool isCameraAboveBuilding; | ||
261 | initializeBuildingPainting(painter, viewport, drawAccurate3D, isCameraAboveBuilding); | 188 | initializeBuildingPainting(painter, viewport, drawAccurate3D, isCameraAboveBuilding); | ||
262 | if (!isCameraAboveBuilding) { | 189 | if (!isCameraAboveBuilding) { | ||
263 | return; // do not render roof if we look inside the building | 190 | return; // do not render roof if we look inside the building | ||
264 | } | 191 | } | ||
265 | 192 | | |||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Line(s) | |||||
349 | double maxArea = 0.0; | 276 | double maxArea = 0.0; | ||
350 | 277 | | |||
351 | for (int i = 0; i < m_cachedOuterRoofPolygons.size(); ++i) { | 278 | for (int i = 0; i < m_cachedOuterRoofPolygons.size(); ++i) { | ||
352 | const QPolygonF *outerRoof = m_cachedOuterRoofPolygons[i]; | 279 | const QPolygonF *outerRoof = m_cachedOuterRoofPolygons[i]; | ||
353 | 280 | | |||
354 | QPointF roofCenter; | 281 | QPointF roofCenter; | ||
355 | 282 | | |||
356 | // Label position calculation | 283 | // Label position calculation | ||
357 | if (!m_buildingText.isEmpty() || !m_entries.isEmpty()) { | 284 | if (!building()->name().isEmpty() || !building()->entries().isEmpty()) { | ||
358 | QSizeF const polygonSize = outerRoof->boundingRect().size(); | 285 | QSizeF const polygonSize = outerRoof->boundingRect().size(); | ||
359 | qreal size = polygonSize.width() * polygonSize.height(); | 286 | qreal size = polygonSize.width() * polygonSize.height(); | ||
360 | if (size > maxSize) { | 287 | if (size > maxSize) { | ||
361 | maxSize = size; | 288 | maxSize = size; | ||
362 | double area; | 289 | double area; | ||
363 | roofCenter = centroid(*outerRoof, area); | 290 | roofCenter = centroid(*outerRoof, area); | ||
364 | maxArea = qMax(area, maxArea); | 291 | maxArea = qMax(area, maxArea); | ||
365 | } | 292 | } | ||
366 | } | 293 | } | ||
367 | 294 | | |||
368 | // Draw the housenumber labels | 295 | // Draw the housenumber labels | ||
369 | if (drawAccurate3D && !m_buildingText.isEmpty() && !roofCenter.isNull()) { | 296 | if (drawAccurate3D && !building()->name().isEmpty() && !roofCenter.isNull()) { | ||
370 | double const w2 = 0.5 * painter->fontMetrics().width(m_buildingText); | 297 | double const w2 = 0.5 * painter->fontMetrics().width(building()->name()); | ||
371 | double const ascent = painter->fontMetrics().ascent(); | 298 | double const ascent = painter->fontMetrics().ascent(); | ||
372 | double const descent = painter->fontMetrics().descent(); | 299 | double const descent = painter->fontMetrics().descent(); | ||
373 | double const a2 = 0.5 * painter->fontMetrics().ascent(); | 300 | double const a2 = 0.5 * painter->fontMetrics().ascent(); | ||
374 | QPointF const textPosition = roofCenter - QPointF(w2, -a2); | 301 | QPointF const textPosition = roofCenter - QPointF(w2, -a2); | ||
375 | if (outerRoof->containsPoint(textPosition + QPointF(-2, -ascent), Qt::OddEvenFill) | 302 | if (outerRoof->containsPoint(textPosition + QPointF(-2, -ascent), Qt::OddEvenFill) | ||
376 | && outerRoof->containsPoint(textPosition + QPointF(-2, descent), Qt::OddEvenFill) | 303 | && outerRoof->containsPoint(textPosition + QPointF(-2, descent), Qt::OddEvenFill) | ||
377 | && outerRoof->containsPoint(textPosition + QPointF(2+2*w2, descent), Qt::OddEvenFill) | 304 | && outerRoof->containsPoint(textPosition + QPointF(2+2*w2, descent), Qt::OddEvenFill) | ||
378 | && outerRoof->containsPoint(textPosition + QPointF(2+2*w2, -ascent), Qt::OddEvenFill) | 305 | && outerRoof->containsPoint(textPosition + QPointF(2+2*w2, -ascent), Qt::OddEvenFill) | ||
379 | ) { | 306 | ) { | ||
380 | painter->drawTextFragment(roofCenter.toPoint(), m_buildingText, | 307 | painter->drawTextFragment(roofCenter.toPoint(), building()->name(), | ||
381 | painter->font().pointSize(), painter->brush().color()); | 308 | painter->font().pointSize(), painter->brush().color()); | ||
382 | } | 309 | } | ||
383 | } | 310 | } | ||
384 | } | 311 | } | ||
385 | 312 | | |||
386 | // Render additional housenumbers at building entries | 313 | // Render additional housenumbers at building entries | ||
387 | if (!m_entries.isEmpty() && maxArea > 1600 * m_entries.size()) { | 314 | if (!building()->entries().isEmpty() && maxArea > 1600 * building()->entries().size()) { | ||
388 | for(const auto &entry: m_entries) { | 315 | for(const auto &entry: building()->entries()) { | ||
389 | qreal x, y; | 316 | qreal x, y; | ||
390 | viewport->screenCoordinates(entry.point, x, y); | 317 | viewport->screenCoordinates(entry.point, x, y); | ||
391 | QPointF point(x, y); | 318 | QPointF point(x, y); | ||
392 | point += buildingOffset(point, viewport); | 319 | point += buildingOffset(point, viewport); | ||
393 | painter->drawTextFragment(point.toPoint(), | 320 | painter->drawTextFragment(point.toPoint(), | ||
394 | m_buildingText, painter->font().pointSize(), painter->brush().color(), | 321 | building()->name(), painter->font().pointSize(), painter->brush().color(), | ||
395 | GeoPainter::RoundFrame); | 322 | GeoPainter::RoundFrame); | ||
396 | } | 323 | } | ||
397 | } | 324 | } | ||
398 | } | 325 | } | ||
399 | 326 | | |||
400 | void BuildingGeoPolygonGraphicsItem::paintFrame(GeoPainter *painter, const ViewportParams *viewport) | 327 | void BuildingGraphicsItem::paintFrame(GeoPainter *painter, const ViewportParams *viewport) | ||
401 | { | 328 | { | ||
402 | // TODO: how does this match the Q_ASSERT in the constructor? | 329 | // TODO: how does this match the Q_ASSERT in the constructor? | ||
403 | if (m_buildingHeight == 0.0) { | 330 | if (building()->height() == 0.0) { | ||
404 | return; | 331 | return; | ||
405 | } | 332 | } | ||
406 | 333 | | |||
407 | if ((polygon() && !viewport->resolves(polygon()->outerBoundary().latLonAltBox(), 4)) | 334 | if ((polygon() && !viewport->resolves(polygon()->outerBoundary().latLonAltBox(), 4)) | ||
408 | || (ring() && !viewport->resolves(ring()->latLonAltBox(), 4))) { | 335 | || (ring() && !viewport->resolves(ring()->latLonAltBox(), 4))) { | ||
409 | return; | 336 | return; | ||
410 | } | 337 | } | ||
411 | 338 | | |||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Line(s) | 410 | } else { | |||
487 | 414 | | |||
488 | for( QPolygonF* fillPolygon: fillPolygons ) { | 415 | for( QPolygonF* fillPolygon: fillPolygons ) { | ||
489 | painter->drawPolygon(*fillPolygon); | 416 | painter->drawPolygon(*fillPolygon); | ||
490 | } | 417 | } | ||
491 | qDeleteAll(fillPolygons); | 418 | qDeleteAll(fillPolygons); | ||
492 | } | 419 | } | ||
493 | } | 420 | } | ||
494 | 421 | | |||
495 | void BuildingGeoPolygonGraphicsItem::screenPolygons(const ViewportParams *viewport, const GeoDataPolygon *polygon, | 422 | void BuildingGraphicsItem::screenPolygons(const ViewportParams *viewport, const GeoDataPolygon *polygon, | ||
496 | QVector<QPolygonF *> &innerPolygons, | 423 | QVector<QPolygonF *> &innerPolygons, | ||
497 | QVector<QPolygonF *> &outerPolygons | 424 | QVector<QPolygonF *> &outerPolygons | ||
498 | ) | 425 | ) | ||
499 | { | 426 | { | ||
500 | Q_ASSERT(polygon); | 427 | Q_ASSERT(polygon); | ||
501 | 428 | | |||
502 | viewport->screenCoordinates( polygon->outerBoundary(), outerPolygons ); | 429 | viewport->screenCoordinates( polygon->outerBoundary(), outerPolygons ); | ||
503 | 430 | | |||
504 | QVector<GeoDataLinearRing> const & innerBoundaries = polygon->innerBoundaries(); | 431 | QVector<GeoDataLinearRing> const & innerBoundaries = polygon->innerBoundaries(); | ||
505 | for (const GeoDataLinearRing &innerBoundary: innerBoundaries) { | 432 | for (const GeoDataLinearRing &innerBoundary: innerBoundaries) { | ||
506 | QVector<QPolygonF*> innerPolygonsPerBoundary; | 433 | QVector<QPolygonF*> innerPolygonsPerBoundary; | ||
507 | viewport->screenCoordinates(innerBoundary, innerPolygonsPerBoundary); | 434 | viewport->screenCoordinates(innerBoundary, innerPolygonsPerBoundary); | ||
508 | 435 | | |||
509 | innerPolygons.reserve(innerPolygons.size() + innerPolygonsPerBoundary.size()); | 436 | innerPolygons.reserve(innerPolygons.size() + innerPolygonsPerBoundary.size()); | ||
510 | for( QPolygonF* innerPolygonPerBoundary: innerPolygonsPerBoundary ) { | 437 | for( QPolygonF* innerPolygonPerBoundary: innerPolygonsPerBoundary ) { | ||
511 | innerPolygons << innerPolygonPerBoundary; | 438 | innerPolygons << innerPolygonPerBoundary; | ||
512 | } | 439 | } | ||
513 | } | 440 | } | ||
514 | } | 441 | } | ||
515 | 442 | | |||
516 | bool BuildingGeoPolygonGraphicsItem::contains(const QPoint &screenPosition, const ViewportParams *viewport) const | 443 | bool BuildingGraphicsItem::contains(const QPoint &screenPosition, const ViewportParams *viewport) const | ||
517 | { | 444 | { | ||
518 | if (m_cachedOuterPolygons.isEmpty()) { | 445 | if (m_cachedOuterPolygons.isEmpty()) { | ||
519 | // Level 17 | 446 | // Level 17 | ||
520 | return AbstractGeoPolygonGraphicsItem::contains(screenPosition, viewport); | 447 | return AbstractGeoPolygonGraphicsItem::contains(screenPosition, viewport); | ||
521 | } | 448 | } | ||
522 | 449 | | |||
523 | QPointF const point = screenPosition; | 450 | QPointF const point = screenPosition; | ||
524 | for (auto polygon: m_cachedOuterRoofPolygons) { | 451 | for (auto polygon: m_cachedOuterRoofPolygons) { | ||
Show All 14 Lines | 463 | for (auto polygon: m_cachedInnerPolygons) { | |||
539 | } | 466 | } | ||
540 | } | 467 | } | ||
541 | return true; | 468 | return true; | ||
542 | } | 469 | } | ||
543 | } | 470 | } | ||
544 | return false; | 471 | return false; | ||
545 | } | 472 | } | ||
546 | 473 | | |||
547 | bool BuildingGeoPolygonGraphicsItem::configurePainterForFrame(GeoPainter *painter) const | 474 | bool BuildingGraphicsItem::configurePainterForFrame(GeoPainter *painter) const | ||
548 | { | 475 | { | ||
549 | QPen currentPen = painter->pen(); | 476 | QPen currentPen = painter->pen(); | ||
550 | 477 | | |||
551 | GeoDataStyle::ConstPtr style = this->style(); | 478 | GeoDataStyle::ConstPtr style = this->style(); | ||
552 | if (!style) { | 479 | if (!style) { | ||
553 | painter->setPen( QPen() ); | 480 | painter->setPen( QPen() ); | ||
554 | } | 481 | } | ||
555 | else { | 482 | else { | ||
Show All 21 Lines |