6 #include "GeoLineStringGraphicsItem.h"
8 #include "GeoDataLineStyle.h"
9 #include "GeoDataLabelStyle.h"
10 #include "GeoDataPlacemark.h"
11 #include "GeoDataPolyStyle.h"
12 #include "GeoPainter.h"
13 #include "StyleBuilder.h"
15 #include "GeoDataStyle.h"
16 #include "GeoDataColorStyle.h"
17 #include "MarbleDebug.h"
18 #include "OsmPlacemarkData.h"
21 #include <QPainterPathStroker>
26 const GeoDataStyle *GeoLineStringGraphicsItem::s_previousStyle =
nullptr;
27 bool GeoLineStringGraphicsItem::s_paintInline =
true;
28 bool GeoLineStringGraphicsItem::s_paintOutline =
true;
30 GeoLineStringGraphicsItem::GeoLineStringGraphicsItem(
const GeoDataPlacemark *placemark,
31 const GeoDataLineString *lineString) :
32 GeoGraphicsItem(placemark),
33 m_lineString(lineString),
34 m_renderLineString(lineString),
37 m_name(placemark->
name())
39 QString const category = StyleBuilder::visualCategoryName(placemark->visualCategory());
43 if (!m_name.isEmpty()) {
46 setPaintLayers(paintLayers);
49 GeoLineStringGraphicsItem::~GeoLineStringGraphicsItem()
51 qDeleteAll(m_cachedPolygons);
55 void GeoLineStringGraphicsItem::setLineString(
const GeoDataLineString* lineString )
57 m_lineString = lineString;
58 m_renderLineString = lineString;
61 const GeoDataLineString *GeoLineStringGraphicsItem::lineString()
const
69 return GeoDataLineString();
72 Q_ASSERT(!lineStrings_.
isEmpty());
73 auto lineStrings = lineStrings_;
74 GeoDataLineString result = *lineStrings.
first();
75 lineStrings.pop_front();
76 for (
bool matched =
true; matched && !lineStrings.isEmpty();) {
78 for (
auto lineString: lineStrings) {
79 if (canMerge(result.first(), lineString->first())) {
82 result << *lineString;
83 lineStrings.removeOne(lineString);
86 }
else if (canMerge(result.last(), lineString->first())) {
87 result.remove(result.size()-1);
88 result << *lineString;
89 lineStrings.removeOne(lineString);
92 }
else if (canMerge(result.first(), lineString->last())) {
93 GeoDataLineString behind = result;
97 lineStrings.removeOne(lineString);
100 }
else if (canMerge(result.last(), lineString->last())) {
101 GeoDataLineString behind = *lineString;
105 lineStrings.removeOne(lineString);
112 return GeoDataLineString();
115 return lineStrings.isEmpty() ? result : GeoDataLineString();
118 void GeoLineStringGraphicsItem::setMergedLineString(
const GeoDataLineString &mergedLineString)
120 m_mergedLineString = mergedLineString;
121 m_renderLineString = mergedLineString.isEmpty() ? m_lineString : &m_mergedLineString;
124 const GeoDataLatLonAltBox& GeoLineStringGraphicsItem::latLonAltBox()
const
126 return m_renderLineString->latLonAltBox();
129 void GeoLineStringGraphicsItem::paint(GeoPainter* painter,
const ViewportParams* viewport ,
const QString &layer,
int tileLevel)
131 setRenderContext(RenderContext(tileLevel));
134 qDeleteAll(m_cachedPolygons);
135 m_cachedPolygons.clear();
137 painter->polygonsFromLineString(*m_renderLineString, m_cachedPolygons);
138 if (m_cachedPolygons.empty()) {
142 paintOutline(painter, viewport);
145 if (m_cachedPolygons.empty()) {
148 paintInline(painter, viewport);
150 if (!m_cachedPolygons.empty()) {
152 paintLabel(painter, viewport);
156 qDeleteAll(m_cachedPolygons);
157 m_cachedPolygons.clear();
159 painter->polygonsFromLineString(*m_renderLineString, m_cachedPolygons);
160 if (m_cachedPolygons.empty()) {
163 if (s_previousStyle != style().data()) {
164 configurePainterForLine(painter, viewport,
false);
166 s_previousStyle = style().data();
167 for(
const QPolygonF* itPolygon: m_cachedPolygons) {
168 painter->drawPolyline(*itPolygon);
173 bool GeoLineStringGraphicsItem::contains(
const QPoint &screenPosition,
const ViewportParams *)
const
175 if (m_penWidth <= 0.0) {
179 if (m_cachedRegion.isNull()) {
181 for (
auto polygon: m_cachedPolygons) {
185 qreal
const margin = 6.0;
186 stroker.
setWidth(m_penWidth + margin);
190 return m_cachedRegion.contains(screenPosition);
196 for (
auto relation: relations) {
197 auto const ref = relation->osmData().tagValue(QStringLiteral(
"ref"));
198 if (relation->isVisible() && !
ref.isEmpty()) {
199 names[relation->relationType()] <<
ref;
203 m_name = feature()->name();
206 for (
auto iter = names.
begin(); iter != names.
end(); ++iter) {
208 switch (iter.key()) {
209 case GeoDataRelation::UnknownType:
210 case GeoDataRelation::RouteRoad:
break;
211 case GeoDataRelation::RouteDetour: value = tr(
"Detour");
break;
212 case GeoDataRelation::RouteFerry: value = tr(
"Ferry Route");
break;
213 case GeoDataRelation::RouteTrain: value = tr(
"Train");
break;
214 case GeoDataRelation::RouteSubway: value = tr(
"Subway");
break;
215 case GeoDataRelation::RouteTram: value = tr(
"Tram");
break;
216 case GeoDataRelation::RouteBus: value = tr(
"Bus");
break;
217 case GeoDataRelation::RouteTrolleyBus: value = tr(
"Trolley Bus");
break;
218 case GeoDataRelation::RouteBicycle: value = tr(
"Bicycle Route");
break;
219 case GeoDataRelation::RouteMountainbike: value = tr(
"Mountainbike Route");
break;
220 case GeoDataRelation::RouteFoot: value = tr(
"Walking Route");
break;
221 case GeoDataRelation::RouteHiking: value = tr(
"Hiking Route");
break;
222 case GeoDataRelation::RouteHorse: value = tr(
"Bridleway");
break;
223 case GeoDataRelation::RouteInlineSkates: value = tr(
"Inline Skates Route");
break;
224 case GeoDataRelation::RouteSkiDownhill: value = tr(
"Downhill Piste");
break;
225 case GeoDataRelation::RouteSkiNordic: value = tr(
"Nordic Ski Trail");
break;
226 case GeoDataRelation::RouteSkitour: value = tr(
"Skitour");
break;
227 case GeoDataRelation::RouteSled: value = tr(
"Sled Trail");
break;
231 std::sort(references.
begin(), references.
end());
232 auto const last = std::unique(references.
begin(), references.
end());
233 references.
erase(last, references.
end());
234 auto const routes = references.
join(
", ");
235 namesList << (value.
isEmpty() ? routes : QStringLiteral(
"%1 %2").arg(value, routes));
237 auto const allRoutes = namesList.
join(QStringLiteral(
"; "));
238 if (feature()->name().isEmpty()) {
241 m_name = QStringLiteral(
"%1 (%2)").
arg(feature()->
name(), allRoutes);
246 void GeoLineStringGraphicsItem::paintInline(GeoPainter* painter,
const ViewportParams* viewport)
248 if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
252 if (s_previousStyle != style().data()) {
253 s_paintInline = configurePainterForLine(painter, viewport,
false);
255 s_previousStyle = style().data();
258 m_renderLabel = painter->pen().widthF() >= 6.0f;
259 m_penWidth = painter->pen().widthF();
260 for(
const QPolygonF* itPolygon: m_cachedPolygons) {
261 painter->drawPolyline(*itPolygon);
266 void GeoLineStringGraphicsItem::paintOutline(GeoPainter *painter,
const ViewportParams *viewport)
const
268 if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
272 if (s_previousStyle != style().data()) {
273 s_paintOutline = configurePainterForLine(painter, viewport,
true);
275 s_previousStyle = style().data();
277 if (s_paintOutline) {
278 for(
const QPolygonF* itPolygon: m_cachedPolygons) {
279 painter->drawPolyline(*itPolygon);
285 void GeoLineStringGraphicsItem::paintLabel(GeoPainter *painter,
const ViewportParams *viewport)
const
287 if ( ( !viewport->resolves( m_renderLineString->latLonAltBox(), 2) ) ) {
291 LabelPositionFlags labelPositionFlags = NoLabel;
292 bool isValid = configurePainterForLabel(painter, viewport, labelPositionFlags);
295 GeoDataStyle::ConstPtr style = this->style();
304 const GeoDataLabelStyle& labelStyle = style->labelStyle();
305 painter->drawLabelsForPolygons(m_cachedPolygons, m_name, FollowLine,
306 labelStyle.paintedColor());
311 bool GeoLineStringGraphicsItem::configurePainterForLine(GeoPainter *painter,
const ViewportParams *viewport,
const bool isOutline)
const
313 QPen currentPen = painter->pen();
314 GeoDataStyle::ConstPtr style = this->style();
316 painter->setPen(
QPen() );
321 if (isOutline && !style->polyStyle().outline()) {
325 const GeoDataLineStyle& lineStyle = style->lineStyle();
334 const QColor linePaintedColor = (!isOutline && (lineStyle.cosmeticOutline() && lineStyle.penStyle() ==
Qt::SolidLine))
335 ? style->polyStyle().paintedColor()
336 : lineStyle.paintedColor();
337 if (currentPen.
color() != linePaintedColor) {
338 if (linePaintedColor.
alpha() == 255) {
339 currentPen.
setColor(linePaintedColor);
344 QColor penColor = linePaintedColor;
345 if (penColor.
alpha() != 0) {
348 if (currentPen.
color() != penColor) {
353 currentPen.
setColor(linePaintedColor);
358 const float lineWidth = lineStyle.width();
359 const float linePhysicalWidth = lineStyle.physicalWidth();
360 float newLineWidth = lineWidth;
361 if (linePhysicalWidth != 0.0) {
362 const float scaledLinePhysicalWidth = float(viewport->radius()) / EARTH_RADIUS * linePhysicalWidth;
363 newLineWidth = scaledLinePhysicalWidth > lineWidth
364 ? scaledLinePhysicalWidth
368 if (!isOutline && lineStyle.cosmeticOutline() && lineStyle.penStyle() ==
Qt::SolidLine) {
369 if (newLineWidth > 2.5) {
374 const qreal lineDrawThreshold = isOutline ? 2.5 : 0.5;
378 if (currentPen.
widthF() != newLineWidth && newLineWidth != 0.0) {
379 if (newLineWidth < lineDrawThreshold) {
380 if (painter->pen().style() !=
Qt::NoPen) {
400 if (currentPen.
dashPattern() != lineStyle.dashPattern()) {
408 if ( painter->pen() != currentPen ) {
409 painter->setPen( currentPen );
415 if (lineStyle.background()) {
416 QBrush brush = painter->background();
417 brush.
setColor(style->polyStyle().paintedColor());
418 painter->setBackground( brush );
436 bool GeoLineStringGraphicsItem::configurePainterForLabel(GeoPainter *painter,
const ViewportParams *viewport, LabelPositionFlags &labelPositionFlags)
const
438 QPen currentPen = painter->pen();
439 GeoDataStyle::ConstPtr style = this->style();
441 painter->setPen(
QPen() );
444 const GeoDataLineStyle& lineStyle = style->lineStyle();
454 const float lineWidth = lineStyle.width();
455 const float linePhysicalWidth = lineStyle.physicalWidth();
456 float newLineWidth = lineWidth;
457 if (linePhysicalWidth != 0.0) {
458 const float scaledLinePhysicalWidth = float(viewport->radius()) / EARTH_RADIUS * linePhysicalWidth;
459 newLineWidth = scaledLinePhysicalWidth > lineWidth
460 ? scaledLinePhysicalWidth
466 if (currentPen.
widthF() != newLineWidth && newLineWidth != 0.0) {
467 if (newLineWidth < 6.0) {
474 if ( painter->pen() != currentPen ) {
475 painter->setPen( currentPen );
488 const GeoDataLabelStyle& labelStyle = style->labelStyle();
489 painter->setFont(labelStyle.font() );
490 switch (labelStyle.alignment()) {
491 case GeoDataLabelStyle::Corner:
492 case GeoDataLabelStyle::Right:
493 labelPositionFlags |= LineStart;
495 case GeoDataLabelStyle::Center:
496 labelPositionFlags |= LineCenter;
504 bool GeoLineStringGraphicsItem::canMerge(
const GeoDataCoordinates &a,
const GeoDataCoordinates &b)
506 return a.sphericalDistanceTo(b) * EARTH_RADIUS < 0.1;