Marble

GeoPainter.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <[email protected]>
4 
5 
6 #include "GeoPainter.h"
7 #include "GeoPainter_p.h"
8 
9 #include <QList>
10 #include <QPainterPath>
11 #include <QPixmapCache>
12 #include <QRegion>
13 #include <qmath.h>
14 
15 #include "MarbleDebug.h"
16 
17 #include "GeoDataCoordinates.h"
18 #include "GeoDataLatLonAltBox.h"
19 #include "GeoDataLineString.h"
20 #include "GeoDataLinearRing.h"
21 #include "GeoDataPoint.h"
22 #include "GeoDataPolygon.h"
23 
24 #include "ViewportParams.h"
25 #include "AbstractProjection.h"
26 
27 // #define MARBLE_DEBUG
28 
29 using namespace Marble;
30 
31 GeoPainterPrivate::GeoPainterPrivate( GeoPainter* q, const ViewportParams *viewport, MapQuality mapQuality )
32  : m_viewport( viewport ),
33  m_mapQuality( mapQuality ),
34  m_x( new qreal[100] ),
35  m_parent(q)
36 {
37 }
38 
39 GeoPainterPrivate::~GeoPainterPrivate()
40 {
41  delete[] m_x;
42 }
43 
44 void GeoPainterPrivate::createAnnotationLayout ( qreal x, qreal y,
45  const QSizeF& bubbleSize,
46  qreal bubbleOffsetX, qreal bubbleOffsetY,
47  qreal xRnd, qreal yRnd,
48  QPainterPath& path, QRectF& rect )
49 {
50  // TODO: MOVE this into an own Annotation class
51  qreal arrowPosition = 0.3;
52  qreal arrowWidth = 12.0;
53 
54  qreal width = bubbleSize.width();
55  qreal height = bubbleSize.height();
56 
57  qreal dx = ( bubbleOffsetX > 0 ) ? 1.0 : -1.0; // x-Mirror
58  qreal dy = ( bubbleOffsetY < 0 ) ? 1.0 : -1.0; // y-Mirror
59 
60  qreal x0 = ( x + bubbleOffsetX ) - dx * ( 1.0 - arrowPosition ) * ( width - 2.0 * xRnd ) - xRnd *dx;
61  qreal x1 = ( x + bubbleOffsetX ) - dx * ( 1.0 - arrowPosition ) * ( width - 2.0 * xRnd );
62  qreal x2 = ( x + bubbleOffsetX ) - dx * ( 1.0 - arrowPosition ) * ( width - 2.0 * xRnd ) + xRnd * dx;
63  qreal x3 = ( x + bubbleOffsetX ) - dx * arrowWidth / 2.0;
64  qreal x4 = ( x + bubbleOffsetX ) + dx * arrowWidth / 2.0;
65  qreal x5 = ( x + bubbleOffsetX ) + dx * arrowPosition * ( width - 2.0 * xRnd )- xRnd * dx;
66  qreal x6 = ( x + bubbleOffsetX ) + dx * arrowPosition * ( width - 2.0 * xRnd );
67  qreal x7 = ( x + bubbleOffsetX ) + dx * arrowPosition * ( width - 2.0 * xRnd ) + xRnd * dx;
68 
69  qreal y0 = ( y + bubbleOffsetY );
70  qreal y1 = ( y + bubbleOffsetY ) - dy * yRnd;
71  qreal y2 = ( y + bubbleOffsetY ) - dy * 2 * yRnd;
72  qreal y5 = ( y + bubbleOffsetY ) - dy * ( height - 2 * yRnd );
73  qreal y6 = ( y + bubbleOffsetY ) - dy * ( height - yRnd );
74  qreal y7 = ( y + bubbleOffsetY ) - dy * height;
75 
76  QPointF p1 ( x, y ); // pointing point
77  QPointF p2 ( x4, y0 );
78  QPointF p3 ( x6, y0 );
79  QPointF p4 ( x7, y1 );
80  QPointF p5 ( x7, y6 );
81  QPointF p6 ( x6, y7 );
82  QPointF p7 ( x1, y7 );
83  QPointF p8 ( x0, y6 );
84  QPointF p9 ( x0, y1 );
85  QPointF p10( x1, y0 );
86  QPointF p11( x3, y0 );
87 
88  QRectF bubbleBoundingBox( QPointF( x0, y7 ), QPointF( x7, y0 ) );
89 
90  path.moveTo( p1 );
91  path.lineTo( p2 );
92 
93  path.lineTo( p3 );
94  QRectF bottomRight( QPointF( x5, y2 ), QPointF( x7, y0 ) );
95  path.arcTo( bottomRight, 270.0, 90.0 );
96 
97  path.lineTo( p5 );
98  QRectF topRight( QPointF( x5, y7 ), QPointF( x7, y5 ) );
99  path.arcTo( topRight, 0.0, 90.0 );
100 
101  path.lineTo( p7 );
102  QRectF topLeft( QPointF( x0, y7 ), QPointF( x2, y5 ) );
103  path.arcTo( topLeft, 90.0, 90.0 );
104 
105  path.lineTo( p9 );
106  QRectF bottomLeft( QPointF( x0, y2 ), QPointF( x2, y0 ) );
107  path.arcTo( bottomLeft, 180.0, 90.0 );
108 
109  path.lineTo( p10 );
110  path.lineTo( p11 );
111  path.lineTo( p1 );
112 
113  qreal left = ( dx > 0 ) ? x1 : x6;
114  qreal right = ( dx > 0 ) ? x6 : x1;
115  qreal top = ( dy > 0 ) ? y6 : y1;
116  qreal bottom = ( dy > 0 ) ? y1 : y6;
117 
118  rect.setTopLeft( QPointF( left, top ) );
119  rect.setBottomRight( QPointF( right, bottom ) );
120 }
121 
122 GeoDataLinearRing GeoPainterPrivate::createLinearRingFromGeoRect( const GeoDataCoordinates & centerCoordinates,
123  qreal width, qreal height )
124 {
125  qreal lon = 0.0;
126  qreal lat = 0.0;
127  qreal altitude = centerCoordinates.altitude();
128  centerCoordinates.geoCoordinates( lon, lat, GeoDataCoordinates::Degree );
129 
130  lon = GeoDataCoordinates::normalizeLon( lon, GeoDataCoordinates::Degree );
131  lat = GeoDataCoordinates::normalizeLat( lat, GeoDataCoordinates::Degree );
132 
133  qreal west = GeoDataCoordinates::normalizeLon( lon - width * 0.5, GeoDataCoordinates::Degree );
134  qreal east = GeoDataCoordinates::normalizeLon( lon + width * 0.5, GeoDataCoordinates::Degree );
135 
136  qreal north = GeoDataCoordinates::normalizeLat( lat + height * 0.5, GeoDataCoordinates::Degree );
137  qreal south = GeoDataCoordinates::normalizeLat( lat - height * 0.5, GeoDataCoordinates::Degree );
138 
139  GeoDataCoordinates southWest( west, south,
140  altitude, GeoDataCoordinates::Degree );
141  GeoDataCoordinates southEast( east, south,
142  altitude, GeoDataCoordinates::Degree );
143  GeoDataCoordinates northEast( east, north,
144  altitude, GeoDataCoordinates::Degree );
145  GeoDataCoordinates northWest( west, north,
146  altitude, GeoDataCoordinates::Degree );
147 
148  GeoDataLinearRing rectangle( Tessellate | RespectLatitudeCircle );
149 
150  // If the width of the rect is larger as 180 degree, we have to enforce the long way.
151  if ( width >= 180 ) {
152  qreal center = lon;
153  GeoDataCoordinates southCenter( center, south, altitude, GeoDataCoordinates::Degree );
154  GeoDataCoordinates northCenter( center, north, altitude, GeoDataCoordinates::Degree );
155 
156  rectangle << southWest << southCenter << southEast << northEast << northCenter << northWest;
157  }
158  else {
159  rectangle << southWest << southEast << northEast << northWest;
160  }
161 
162  return rectangle;
163 }
164 
165 bool GeoPainterPrivate::doClip( const ViewportParams *viewport )
166 {
167  if ( !viewport->currentProjection()->isClippedToSphere() )
168  return true;
169 
170  const qint64 radius = viewport->radius() * viewport->currentProjection()->clippingRadius();
171 
172  return ( radius > viewport->width() / 2 || radius > viewport->height() / 2 );
173 }
174 
175 qreal GeoPainterPrivate::normalizeAngle(qreal angle)
176 {
177  angle = fmodf(angle, 360);
178  return angle < 0 ? angle + 360 : angle;
179 }
180 
181 void GeoPainterPrivate::drawTextRotated( const QPointF &startPoint, qreal angle, const QString &text )
182 {
183  QRectF textRect(startPoint, m_parent->fontMetrics().size( 0, text));
184  QTransform const oldTransform = m_parent->transform();
185  m_parent->translate(startPoint);
186  m_parent->rotate(angle);
187  m_parent->translate( -startPoint - QPointF(0.0, m_parent->fontMetrics().height()/2.0) );
188 
189  m_parent->drawText( textRect, text);
190  m_parent->setTransform(oldTransform);
191 }
192 
193 // -------------------------------------------------------------------------------------------------
194 
196  : ClipPainter( pd, GeoPainterPrivate::doClip( viewport ) ),
197  d( new GeoPainterPrivate( this, viewport, mapQuality ) )
198 {
199  const bool antialiased = mapQuality == HighQuality || mapQuality == PrintQuality;
200  setRenderHint( QPainter::Antialiasing, antialiased );
201  ClipPainter::setScreenClip(false);
202 }
203 
204 
206 {
207  delete d;
208 }
209 
210 
212 {
213  return d->m_mapQuality;
214 }
215 
216 
218  const QString & text, QSizeF bubbleSize,
219  qreal bubbleOffsetX, qreal bubbleOffsetY,
220  qreal xRnd, qreal yRnd )
221 {
222  int pointRepeatNum;
223  qreal y;
224  bool globeHidesPoint;
225 
226  if ( bubbleSize.height() <= 0 ) {
227  QRectF rect = QRectF( QPointF( 0.0, 0.0 ), bubbleSize - QSizeF( 2 * xRnd, 0.0 ) );
228  qreal idealTextHeight = boundingRect( rect, Qt::TextWordWrap, text ).height();
229  bubbleSize.setHeight( 2 * yRnd + idealTextHeight );
230  }
231 
232  bool visible = d->m_viewport->screenCoordinates( position, d->m_x, y, pointRepeatNum, QSizeF(), globeHidesPoint );
233 
234  if ( visible ) {
235  // Draw all the x-repeat-instances of the point on the screen
236  for( int it = 0; it < pointRepeatNum; ++it ) {
237  QPainterPath path;
238  QRectF rect;
239  d->createAnnotationLayout( d->m_x[it], y, bubbleSize, bubbleOffsetX, bubbleOffsetY, xRnd, yRnd, path, rect );
240  QPainter::drawPath( path );
241  QPainter::drawText( rect, Qt::TextWordWrap, text, &rect );
242  }
243  }
244 }
245 
246 
247 void GeoPainter::drawPoint ( const GeoDataCoordinates & position )
248 {
249  int pointRepeatNum;
250  qreal y;
251  bool globeHidesPoint;
252 
253  bool visible = d->m_viewport->screenCoordinates( position, d->m_x, y, pointRepeatNum, QSizeF(), globeHidesPoint );
254 
255  if ( visible ) {
256  // Draw all the x-repeat-instances of the point on the screen
257  for( int it = 0; it < pointRepeatNum; ++it ) {
258  QPainter::drawPoint(QPointF(d->m_x[it], y));
259  }
260  }
261 }
262 
263 
265  qreal width ) const
266 {
267  return regionFromRect( position, width, width, false, 3 );
268 }
269 
270 
271 void GeoPainter::drawPoint( const GeoDataPoint & point )
272 {
273  drawPoint( point.coordinates() );
274 }
275 
276 
278  qreal width ) const
279 {
280  return regionFromRect( point.coordinates(), width, width, false, 3 );
281 }
282 
283 
284 void GeoPainter::drawText ( const GeoDataCoordinates & position,
285  const QString & text,
286  qreal xOffset, qreal yOffset,
287  qreal width, qreal height,
288  const QTextOption & option )
289 {
290  // Of course in theory we could have the "isGeoProjected" parameter used
291  // for drawText as well. However this would require us to convert all
292  // glyphs to PainterPaths / QPolygons. From QPolygons we could create
293  // GeoDataPolygons which could get painted on screen. Any patches appreciated ;-)
294 
295  int pointRepeatNum;
296  qreal y;
297  bool globeHidesPoint;
298 
299  QSizeF textSize( fontMetrics().width( text ), fontMetrics().height() );
300 
301  bool visible = d->m_viewport->screenCoordinates( position, d->m_x, y, pointRepeatNum, textSize, globeHidesPoint );
302 
303  if ( visible ) {
304  // Draw all the x-repeat-instances of the point on the screen
305  const qreal posY = y - yOffset;
306  for( int it = 0; it < pointRepeatNum; ++it ) {
307  const qreal posX = d->m_x[it] + xOffset;
308  if (width == 0.0 && height == 0.0) {
309  QPainter::drawText(QPointF(posX, posY), text);
310  }
311  else {
312  const QRectF boundingRect(posX, posY, width, height);
313  QPainter::drawText( boundingRect, text, option );
314  }
315  }
316  }
317 }
318 
319 
320 void GeoPainter::drawEllipse ( const GeoDataCoordinates & centerPosition,
321  qreal width, qreal height,
322  bool isGeoProjected )
323 {
324  if ( !isGeoProjected ) {
325  int pointRepeatNum;
326  qreal y;
327  bool globeHidesPoint;
328 
329  bool visible = d->m_viewport->screenCoordinates( centerPosition, d->m_x, y, pointRepeatNum, QSizeF( width, height ), globeHidesPoint );
330 
331  if ( visible ) {
332  // Draw all the x-repeat-instances of the point on the screen
333  const qreal rx = width / 2.0;
334  const qreal ry = height / 2.0;
335  for( int it = 0; it < pointRepeatNum; ++it ) {
336  QPainter::drawEllipse(QPointF(d->m_x[it], y), rx, ry);
337  }
338  }
339  }
340  else {
341  // Initialize variables
342  const qreal centerLon = centerPosition.longitude( GeoDataCoordinates::Degree );
343  const qreal centerLat = centerPosition.latitude( GeoDataCoordinates::Degree );
344  const qreal altitude = centerPosition.altitude();
345 
346  // Ensure a valid latitude range:
347  if ( centerLat + 0.5 * height > 90.0 || centerLat - 0.5 * height < -90.0 ) {
348  return;
349  }
350 
351  // Don't show the ellipse if it's too small:
352  GeoDataLatLonBox ellipseBox( centerLat + 0.5 * height, centerLat - 0.5 * height,
353  centerLon + 0.5 * width, centerLon - 0.5 * width,
354  GeoDataCoordinates::Degree );
355  if ( !d->m_viewport->viewLatLonAltBox().intersects( ellipseBox ) ||
356  !d->m_viewport->resolves( ellipseBox ) ) return;
357 
358  GeoDataLinearRing ellipse;
359 
360  // Optimizing the precision by determining the size which the
361  // ellipse covers on the screen:
362  const qreal degreeResolution = d->m_viewport->angularResolution() * RAD2DEG;
363  // To create a circle shape even for very small precision we require uneven numbers:
364  const int precision = qMin<qreal>( width / degreeResolution / 8 + 1, 81 );
365 
366  // Calculate the shape of the upper half of the ellipse:
367  for ( int i = 0; i <= precision; ++i ) {
368  const qreal t = 1.0 - 2.0 * (qreal)(i) / (qreal)(precision);
369  const qreal lat = centerLat + 0.5 * height * sqrt( 1.0 - t * t );
370  const qreal lon = centerLon + 0.5 * width * t;
371  ellipse << GeoDataCoordinates( lon, lat, altitude, GeoDataCoordinates::Degree );
372  }
373  // Calculate the shape of the lower half of the ellipse:
374  for ( int i = 0; i <= precision; ++i ) {
375  const qreal t = 2.0 * (qreal)(i) / (qreal)(precision) - 1.0;
376  const qreal lat = centerLat - 0.5 * height * sqrt( 1.0 - t * t );
377  const qreal lon = centerLon + 0.5 * width * t;
378  ellipse << GeoDataCoordinates( lon, lat, altitude, GeoDataCoordinates::Degree );
379  }
380 
381  drawPolygon( ellipse );
382 
383  }
384 
385 }
386 
387 
389  qreal width, qreal height,
390  bool isGeoProjected,
391  qreal strokeWidth ) const
392 {
393  if ( !isGeoProjected ) {
394  int pointRepeatNum;
395  qreal y;
396  bool globeHidesPoint;
397 
398  bool visible = d->m_viewport->screenCoordinates( centerPosition, d->m_x, y, pointRepeatNum, QSizeF( width, height ), globeHidesPoint );
399 
400  QRegion regions;
401 
402  if ( visible ) {
403  // only a hint, a backend could still ignore it, but we cannot know more
404  const bool antialiased = testRenderHint(QPainter::Antialiasing);
405 
406  const qreal halfStrokeWidth = strokeWidth/2.0;
407  const int startY = antialiased ? (qFloor(y - halfStrokeWidth)) : (qFloor(y+0.5 - halfStrokeWidth));
408  const int endY = antialiased ? (qCeil(y + height + halfStrokeWidth)) : (qFloor(y+0.5 + height + halfStrokeWidth));
409  // Draw all the x-repeat-instances of the point on the screen
410  for( int it = 0; it < pointRepeatNum; ++it ) {
411  const qreal x = d->m_x[it];
412  const int startX = antialiased ? (qFloor(x - halfStrokeWidth)) : (qFloor(x+0.5 - halfStrokeWidth));
413  const int endX = antialiased ? (qCeil(x + width + halfStrokeWidth)) : (qFloor(x+0.5 + width + halfStrokeWidth));
414 
415  regions += QRegion(startX, startY, endX - startX, endY - startY, QRegion::Ellipse);
416  }
417  }
418  return regions;
419  }
420  else {
421  // Initialize variables
422  const qreal centerLon = centerPosition.longitude( GeoDataCoordinates::Degree );
423  const qreal centerLat = centerPosition.latitude( GeoDataCoordinates::Degree );
424  const qreal altitude = centerPosition.altitude();
425 
426  // Ensure a valid latitude range:
427  if ( centerLat + 0.5 * height > 90.0 || centerLat - 0.5 * height < -90.0 ) {
428  return QRegion();
429  }
430 
431  // Don't show the ellipse if it's too small:
432  GeoDataLatLonBox ellipseBox( centerLat + 0.5 * height, centerLat - 0.5 * height,
433  centerLon + 0.5 * width, centerLon - 0.5 * width,
434  GeoDataCoordinates::Degree );
435  if ( !d->m_viewport->viewLatLonAltBox().intersects( ellipseBox ) ||
436  !d->m_viewport->resolves( ellipseBox ) ) return QRegion();
437 
438  GeoDataLinearRing ellipse;
439 
440  // Optimizing the precision by determining the size which the
441  // ellipse covers on the screen:
442  const qreal degreeResolution = d->m_viewport->angularResolution() * RAD2DEG;
443  // To create a circle shape even for very small precision we require uneven numbers:
444  const int precision = qMin<qreal>( width / degreeResolution / 8 + 1, 81 );
445 
446  // Calculate the shape of the upper half of the ellipse:
447  for ( int i = 0; i <= precision; ++i ) {
448  const qreal t = 1.0 - 2.0 * (qreal)(i) / (qreal)(precision);
449  const qreal lat = centerLat + 0.5 * height * sqrt( 1.0 - t * t );
450  const qreal lon = centerLon + 0.5 * width * t;
451  ellipse << GeoDataCoordinates( lon, lat, altitude, GeoDataCoordinates::Degree );
452  }
453  // Calculate the shape of the lower half of the ellipse:
454  for ( int i = 0; i <= precision; ++i ) {
455  const qreal t = 2.0 * (qreal)(i) / (qreal)(precision) - 1.0;
456  const qreal lat = centerLat - 0.5 * height * sqrt( 1.0 - t * t );
457  const qreal lon = centerLon + 0.5 * width * t;
458  ellipse << GeoDataCoordinates( lon, lat, altitude, GeoDataCoordinates::Degree );
459  }
460 
461  return regionFromPolygon( ellipse, Qt::OddEvenFill, strokeWidth );
462  }
463 }
464 
465 
466 void GeoPainter::drawImage ( const GeoDataCoordinates & centerPosition,
467  const QImage & image /*, bool isGeoProjected */ )
468 {
469  // isGeoProjected = true would project the image/pixmap onto the globe. This
470  // requires to deal with the TextureMapping classes -> should get
471  // implemented later on
472 
473  int pointRepeatNum;
474  qreal y;
475  bool globeHidesPoint;
476 
477 // if ( !isGeoProjected ) {
478  bool visible = d->m_viewport->screenCoordinates( centerPosition, d->m_x, y, pointRepeatNum, image.size(), globeHidesPoint );
479 
480  if ( visible ) {
481  // Draw all the x-repeat-instances of the point on the screen
482  const qreal posY = y - (image.height() / 2.0);
483  for( int it = 0; it < pointRepeatNum; ++it ) {
484  const qreal posX = d->m_x[it] - (image.width() / 2.0);
485  QPainter::drawImage(QPointF(posX, posY), image);
486  }
487  }
488 // }
489 }
490 
491 
492 void GeoPainter::drawPixmap ( const GeoDataCoordinates & centerPosition,
493  const QPixmap & pixmap /* , bool isGeoProjected */ )
494 {
495  int pointRepeatNum;
496  qreal y;
497  bool globeHidesPoint;
498 
499 // if ( !isGeoProjected ) {
500  // FIXME: Better visibility detection that takes the circle geometry into account
501  bool visible = d->m_viewport->screenCoordinates( centerPosition, d->m_x, y, pointRepeatNum, pixmap.size(), globeHidesPoint );
502 
503  if ( visible ) {
504  // Draw all the x-repeat-instances of the point on the screen
505  const qreal posY = y - (pixmap.height() / 2.0);
506  for( int it = 0; it < pointRepeatNum; ++it ) {
507  const qreal posX = d->m_x[it] - (pixmap.width() / 2.0);
508  QPainter::drawPixmap(QPointF(posX, posY), pixmap);
509  }
510  }
511 // }
512 }
513 
514 
516  int width, int height,
517  int margin) const
518 {
519  const int fullWidth = width + 2 * margin;
520  const int fullHeight = height + 2 * margin;
521  int pointRepeatNum;
522  qreal y;
523  bool globeHidesPoint;
524 
525  const bool visible = d->m_viewport->screenCoordinates(centerCoordinates,
526  d->m_x, y, pointRepeatNum,
527  QSizeF(fullWidth, fullHeight), globeHidesPoint);
528 
529  QRegion regions;
530 
531  if (visible) {
532  // cmp. GeoPainter::drawPixmap() position calculation
533  // QPainter::drawPixmap seems to qRound the passed position
534  const int posY = qRound(y - (height / 2.0)) - margin;
535  for (int it = 0; it < pointRepeatNum; ++it) {
536  const int posX = qRound(d->m_x[it] - (width / 2.0)) - margin;
537  regions += QRegion(posX, posY, width, height);
538  }
539  }
540 
541  return regions;
542 }
543 
545  QVector<QPolygonF*> &polygons ) const
546 {
547  // Immediately leave this method now if:
548  // - the object is not visible in the viewport or if
549  // - the size of the object is below the resolution of the viewport
550  if ( ! d->m_viewport->viewLatLonAltBox().intersects( lineString.latLonAltBox() ) ||
551  ! d->m_viewport->resolves( lineString.latLonAltBox() )
552  )
553  {
554  // mDebug() << "LineString doesn't get displayed on the viewport";
555  return;
556  }
557 
558  d->m_viewport->screenCoordinates( lineString, polygons );
559 }
560 
561 
562 void GeoPainter::drawPolyline ( const GeoDataLineString & lineString,
563  const QString& labelText,
564  LabelPositionFlags labelPositionFlags,
565  const QColor& labelColor)
566 {
567  // no labels to draw?
568  // TODO: !labelColor.isValid() || labelColor.alpha() == 0 does not work,
569  // something injects invalid labelColor for city streets
570  if (labelText.isEmpty() || labelPositionFlags.testFlag(NoLabel) ||
571  labelColor == Qt::transparent) {
572  drawPolyline(lineString);
573  return;
574  }
575 
576  QVector<QPolygonF*> polygons;
577  polygonsFromLineString(lineString, polygons);
578  if (polygons.empty()) return;
579 
580  for(const QPolygonF* itPolygon: polygons) {
581  ClipPainter::drawPolyline(*itPolygon);
582  }
583 
584  drawLabelsForPolygons(polygons,
585  labelText,
586  labelPositionFlags,
587  labelColor);
588 
589  qDeleteAll( polygons );
590 }
591 
593  const QString& labelText,
594  LabelPositionFlags labelPositionFlags,
595  const QColor& labelColor )
596 {
597  if (labelText.isEmpty()) {
598  return;
599  }
600  QPen const oldPen = pen();
601 
602  if (labelPositionFlags.testFlag(FollowLine)) {
603  const qreal maximumLabelFontSize = 20;
604  qreal fontSize = pen().widthF() * 0.45;
605  fontSize = qMin( fontSize, maximumLabelFontSize );
606 
607  if (fontSize < 6.0 || labelColor == "transparent") {
608  return;
609  }
610  QFont font = this->font();
611  font.setPointSizeF(fontSize);
612  setFont(font);
613  int labelWidth = fontMetrics().width( labelText );
614  if (labelText.size() < 20) {
615  labelWidth *= (20.0 / labelText.size());
616  }
617  setPen(labelColor);
618 
619  QVector<QPointF> labelNodes;
620  QRectF viewportRect = QRectF(QPointF(0, 0), d->m_viewport->size());
621  for( QPolygonF* itPolygon: polygons ) {
622  if (!itPolygon->boundingRect().intersects(viewportRect)) {
623  continue;
624  }
625 
626  labelNodes.clear();
627 
628  QPainterPath path;
629  path.addPolygon(*itPolygon);
630  qreal pathLength = path.length();
631  if (pathLength == 0) continue;
632 
633  int maxNumLabels = static_cast<int>(pathLength / labelWidth);
634 
635  if (maxNumLabels > 0) {
636  qreal textRelativeLength = labelWidth / pathLength;
637  int numLabels = 1;
638  if (maxNumLabels > 1) {
639  numLabels = maxNumLabels/2;
640  }
641  qreal offset = (1.0 - numLabels*textRelativeLength)/numLabels;
642  qreal startPercent = offset/2.0;
643 
644  for (int k = 0; k < numLabels; ++k, startPercent += textRelativeLength + offset) {
645  QPointF point = path.pointAtPercent(startPercent);
646  QPointF endPoint = path.pointAtPercent(startPercent + textRelativeLength);
647 
648  if ( viewport().contains(point.toPoint()) || viewport().contains(endPoint.toPoint()) ) {
649  qreal angle = -path.angleAtPercent(startPercent);
650  qreal angle2 = -path.angleAtPercent(startPercent + textRelativeLength);
651  angle = GeoPainterPrivate::normalizeAngle(angle);
652  angle2 = GeoPainterPrivate::normalizeAngle(angle2);
653  bool upsideDown = angle > 90.0 && angle < 270.0;
654 
655  if ( qAbs(angle - angle2) < 3.0 ) {
656  if ( upsideDown ) {
657  angle += 180.0;
658  point = path.pointAtPercent(startPercent + textRelativeLength);
659  }
660 
661  d->drawTextRotated(point, angle, labelText);
662  } else {
663  for (int i = 0; i < labelText.length(); ++i) {
664  qreal currentGlyphTextLength = fontMetrics().width(labelText.left(i)) / pathLength;
665 
666  if ( !upsideDown ) {
667  angle = -path.angleAtPercent(startPercent + currentGlyphTextLength);
668  point = path.pointAtPercent(startPercent + currentGlyphTextLength);
669  }
670  else {
671  angle = -path.angleAtPercent(startPercent + textRelativeLength - currentGlyphTextLength) + 180;
672  point = path.pointAtPercent(startPercent + textRelativeLength - currentGlyphTextLength);
673  }
674 
675  d->drawTextRotated(point, angle, labelText.at(i));
676  }
677  }
678  }
679  }
680  }
681  }
682  } else {
683  setPen(labelColor);
684 
685  int labelWidth = fontMetrics().width( labelText );
686  int labelAscent = fontMetrics().ascent();
687 
688  QVector<QPointF> labelNodes;
689  for( QPolygonF* itPolygon: polygons ) {
690  labelNodes.clear();
691  ClipPainter::labelPosition( *itPolygon, labelNodes, labelPositionFlags );
692  if (!labelNodes.isEmpty()) {
693  for ( const QPointF& labelNode: labelNodes ) {
694  QPointF labelPosition = labelNode + QPointF( 3.0, -2.0 );
695 
696  // FIXME: This is a Q&D fix.
697  qreal xmax = viewport().width() - 10.0 - labelWidth;
698  if ( labelPosition.x() > xmax ) labelPosition.setX( xmax );
699  qreal ymin = 10.0 + labelAscent;
700  if ( labelPosition.y() < ymin ) labelPosition.setY( ymin );
701  qreal ymax = viewport().height() - 10.0 - labelAscent;
702  if ( labelPosition.y() > ymax ) labelPosition.setY( ymax );
703 
704  drawText( QRectF( labelPosition, fontMetrics().size( 0, labelText) ), labelText );
705  }
706  }
707  }
708  }
709  setPen(oldPen);
710 }
711 
713 {
714  QVector<QPolygonF*> polygons;
715  polygonsFromLineString(lineString, polygons);
716  if (polygons.empty()) return;
717 
718  for(const QPolygonF* itPolygon: polygons) {
719  ClipPainter::drawPolyline(*itPolygon);
720  }
721 
722  qDeleteAll(polygons);
723 }
724 
725 
727  qreal strokeWidth ) const
728 {
729  // Immediately leave this method now if:
730  // - the object is not visible in the viewport or if
731  // - the size of the object is below the resolution of the viewport
732  if ( ! d->m_viewport->viewLatLonAltBox().intersects( lineString.latLonAltBox() ) ||
733  ! d->m_viewport->resolves( lineString.latLonAltBox() )
734  )
735  {
736  // mDebug() << "LineString doesn't get displayed on the viewport";
737  return QRegion();
738  }
739 
740  QPainterPath painterPath;
741 
742  QVector<QPolygonF*> polygons;
743  d->m_viewport->screenCoordinates( lineString, polygons );
744 
745  for( QPolygonF* itPolygon: polygons ) {
746  painterPath.addPolygon( *itPolygon );
747  }
748 
749  qDeleteAll( polygons );
750 
751  QPainterPathStroker stroker;
752  stroker.setWidth( strokeWidth );
753  QPainterPath strokePath = stroker.createStroke( painterPath );
754 
755  return QRegion( strokePath.toFillPolygon().toPolygon(), Qt::WindingFill );
756 }
757 
758 
759 void GeoPainter::drawPolygon ( const GeoDataLinearRing & linearRing,
760  Qt::FillRule fillRule )
761 {
762  // Immediately leave this method now if:
763  // - the object is not visible in the viewport or if
764  // - the size of the object is below the resolution of the viewport
765  if ( ! d->m_viewport->viewLatLonAltBox().intersects( linearRing.latLonAltBox() ) ||
766  ! d->m_viewport->resolves( linearRing.latLonAltBox() )
767  )
768  {
769  // mDebug() << "Polygon doesn't get displayed on the viewport";
770  return;
771  }
772 
773  QVector<QPolygonF*> polygons;
774  d->m_viewport->screenCoordinates( linearRing, polygons );
775 
776  for( QPolygonF* itPolygon: polygons ) {
777  ClipPainter::drawPolygon( *itPolygon, fillRule );
778  }
779 
780  qDeleteAll( polygons );
781 }
782 
783 
785  Qt::FillRule fillRule, qreal strokeWidth ) const
786 {
787  // Immediately leave this method now if:
788  // - the object is not visible in the viewport or if
789  // - the size of the object is below the resolution of the viewport
790  if ( ! d->m_viewport->viewLatLonAltBox().intersects( linearRing.latLonAltBox() ) ||
791  ! d->m_viewport->resolves( linearRing.latLonAltBox() )
792  )
793  {
794  return QRegion();
795  }
796 
797  QRegion regions;
798 
799  QVector<QPolygonF*> polygons;
800  d->m_viewport->screenCoordinates( linearRing, polygons );
801 
802  if ( strokeWidth == 0 ) {
803  // This is the faster way
804  for( QPolygonF* itPolygon: polygons ) {
805  regions += QRegion ( (*itPolygon).toPolygon(), fillRule );
806  }
807  }
808  else {
809  QPainterPath painterPath;
810  for( QPolygonF* itPolygon: polygons ) {
811  painterPath.addPolygon( *itPolygon );
812  }
813 
814  QPainterPathStroker stroker;
815  stroker.setWidth( strokeWidth );
816  QPainterPath strokePath = stroker.createStroke( painterPath );
817  painterPath = painterPath.united( strokePath );
818  regions = QRegion( painterPath.toFillPolygon().toPolygon() );
819  }
820 
821  qDeleteAll( polygons );
822 
823  return regions;
824 }
825 
826 
828  Qt::FillRule fillRule )
829 {
830  // If the object is not visible in the viewport return
831  if ( ! d->m_viewport->viewLatLonAltBox().intersects( polygon.outerBoundary().latLonAltBox() ) ||
832  // If the size of the object is below the resolution of the viewport then return
833  ! d->m_viewport->resolves( polygon.outerBoundary().latLonAltBox() )
834  )
835  {
836  // mDebug() << "Polygon doesn't get displayed on the viewport";
837  return;
838  }
839  // mDebug() << "Drawing Polygon";
840 
841  QVector<QPolygonF*> outerPolygons;
842  QVector<QPolygonF*> innerPolygons;
843  d->m_viewport->screenCoordinates( polygon.outerBoundary(), outerPolygons );
844 
845  QPen const currentPen = pen();
846 
847  bool const hasInnerBoundaries = !polygon.innerBoundaries().isEmpty();
848  bool innerBoundariesOnScreen = false;
849 
850  if ( hasInnerBoundaries ) {
851  QVector<GeoDataLinearRing> const & innerBoundaries = polygon.innerBoundaries();
852 
853  const GeoDataLatLonAltBox & viewLatLonAltBox = d->m_viewport->viewLatLonAltBox();
854  for( const GeoDataLinearRing& itInnerBoundary: innerBoundaries ) {
855  if ( viewLatLonAltBox.intersects(itInnerBoundary.latLonAltBox())
856  && d->m_viewport->resolves(itInnerBoundary.latLonAltBox()), 4 ) {
857  innerBoundariesOnScreen = true;
858  break;
859  }
860  }
861 
862  if (innerBoundariesOnScreen) {
863  // Create the inner screen polygons
864  for( const GeoDataLinearRing& itInnerBoundary: innerBoundaries ) {
865  QVector<QPolygonF*> innerPolygonsPerBoundary;
866 
867  d->m_viewport->screenCoordinates( itInnerBoundary, innerPolygonsPerBoundary );
868 
869  for( QPolygonF* innerPolygonPerBoundary: innerPolygonsPerBoundary ) {
870  innerPolygons << innerPolygonPerBoundary;
871  }
872  }
873 
874  setPen(Qt::NoPen);
875  QVector<QPolygonF*> fillPolygons = createFillPolygons( outerPolygons,
876  innerPolygons );
877 
878  for( const QPolygonF* fillPolygon: fillPolygons ) {
879  ClipPainter::drawPolygon(*fillPolygon, fillRule);
880  }
881 
882  setPen(currentPen);
883 
884  for( const QPolygonF* outerPolygon: outerPolygons ) {
885  ClipPainter::drawPolyline( *outerPolygon );
886  }
887  for( const QPolygonF* innerPolygon: innerPolygons ) {
888  ClipPainter::drawPolyline( *innerPolygon );
889  }
890 
891  qDeleteAll(fillPolygons);
892  }
893  }
894 
895  if ( !hasInnerBoundaries || !innerBoundariesOnScreen ) {
896  drawPolygon( polygon.outerBoundary(), fillRule );
897  }
898 
899  qDeleteAll(outerPolygons);
900  qDeleteAll(innerPolygons);
901 }
902 
903 QVector<QPolygonF*> GeoPainter::createFillPolygons( const QVector<QPolygonF*> & outerPolygons,
904  const QVector<QPolygonF*> & innerPolygons ) const
905 {
906  QVector<QPolygonF*> fillPolygons;
907  fillPolygons.reserve(outerPolygons.size());
908 
909  for( const QPolygonF* outerPolygon: outerPolygons ) {
910  QPolygonF* fillPolygon = new QPolygonF;
911  *fillPolygon << *outerPolygon;
912  *fillPolygon << outerPolygon->first();
913 
914  for( const QPolygonF* innerPolygon: innerPolygons ) {
915  *fillPolygon << *innerPolygon;
916  *fillPolygon << innerPolygon->first();
917  *fillPolygon << outerPolygon->first();
918  }
919 
920  fillPolygons << fillPolygon;
921  }
922 
923  return fillPolygons;
924 }
925 
926 
927 void GeoPainter::drawRect ( const GeoDataCoordinates & centerCoordinates,
928  qreal width, qreal height,
929  bool isGeoProjected )
930 {
931  if ( !isGeoProjected ) {
932  int pointRepeatNum;
933  qreal y;
934  bool globeHidesPoint;
935 
936  bool visible = d->m_viewport->screenCoordinates( centerCoordinates,
937  d->m_x, y, pointRepeatNum, QSizeF( width, height ), globeHidesPoint );
938 
939  if ( visible ) {
940  // Draw all the x-repeat-instances of the point on the screen
941  const qreal posY = y - height / 2.0;
942  for( int it = 0; it < pointRepeatNum; ++it ) {
943  const qreal posX = d->m_x[it] - width / 2.0;
944  QPainter::drawRect(QRectF(posX, posY, width, height));
945  }
946  }
947  }
948  else {
949  drawPolygon( d->createLinearRingFromGeoRect( centerCoordinates, width, height ),
950  Qt::OddEvenFill );
951  }
952 }
953 
954 
956  qreal width, qreal height,
957  bool isGeoProjected,
958  qreal strokeWidth ) const
959 {
960  if ( !isGeoProjected ) {
961  int pointRepeatNum;
962  qreal centerY;
963  bool globeHidesPoint;
964 
965  bool visible = d->m_viewport->screenCoordinates( centerCoordinates,
966  d->m_x, centerY, pointRepeatNum, QSizeF( width, height ), globeHidesPoint );
967 
968  QRegion regions;
969 
970  if ( visible ) {
971  // only a hint, a backend could still ignore it, but we cannot know more
972  const bool antialiased = testRenderHint(QPainter::Antialiasing);
973 
974  const qreal halfStrokeWidth = strokeWidth/2.0;
975  const int topY = centerY - height/2.0;
976  const int startY = antialiased ? (qFloor(topY - halfStrokeWidth)) : (qFloor(topY+0.5 - halfStrokeWidth));
977  const int endY = antialiased ? (qCeil(topY + height + halfStrokeWidth)) : (qFloor(centerY+0.5 + height + halfStrokeWidth));
978  // Draw all the x-repeat-instances of the point on the screen
979  for( int it = 0; it < pointRepeatNum; ++it ) {
980  const qreal leftX = d->m_x[it] - width/2.0;
981  const int startX = antialiased ? (qFloor(leftX - halfStrokeWidth)) : (qFloor(leftX+0.5 - halfStrokeWidth));
982  const int endX = antialiased ? (qCeil(leftX + width + halfStrokeWidth)) : (qFloor(leftX+0.5 + width + halfStrokeWidth));
983  regions += QRegion(startX, startY, endX - startX, endY - startY);
984  }
985  }
986  return regions;
987  }
988  else {
989  return regionFromPolygon( d->createLinearRingFromGeoRect( centerCoordinates, width, height ),
990  Qt::OddEvenFill, strokeWidth );
991  }
992 }
993 
994 
996  qreal width, qreal height,
997  qreal xRnd, qreal yRnd)
998 {
999  int pointRepeatNum;
1000  qreal y;
1001  bool globeHidesPoint;
1002 
1003  // FIXME: Better visibility detection that takes the circle geometry into account
1004  bool visible = d->m_viewport->screenCoordinates( centerPosition, d->m_x, y, pointRepeatNum, QSizeF( width, height ), globeHidesPoint );
1005 
1006  if ( visible ) {
1007  // Draw all the x-repeat-instances of the point on the screen
1008  const qreal posY = y - height / 2.0;
1009  for( int it = 0; it < pointRepeatNum; ++it ) {
1010  const qreal posX = d->m_x[it] - width / 2.0;
1011  QPainter::drawRoundedRect(QRectF(posX, posY, width, height), xRnd, yRnd);
1012  }
1013  }
1014 }
1015 
1016 
1017 void GeoPainter::drawTextFragment(const QPoint &position, const QString &text,
1018  const qreal fontSize, const QColor &color,
1019  const Frames &flags)
1020 {
1021  const QString key = text + ":" + QString::number(static_cast<int>(flags));
1022 
1023  QPixmap pixmap;
1024 
1025  if (!QPixmapCache::find(key, &pixmap)) {
1026  const bool hasRoundFrame = flags.testFlag(RoundFrame);
1027 
1028  QPixmap pixmap(10,10);
1029  QPainter textPainter;
1030 
1031  textPainter.begin(&pixmap);
1032  const QFontMetrics metrics = textPainter.fontMetrics();
1033  textPainter.end();
1034 
1035  const int width = metrics.width(text);
1036  const int height = metrics.height();
1037  const QSize size = hasRoundFrame
1038  ? QSize(qMax(1.2*width, 1.1*height), 1.2*height)
1039  : QSize(width, height);
1040  pixmap = QPixmap(size);
1041  pixmap.fill(Qt::transparent);
1042  const QRect labelRect(QPoint(), size);
1043  textPainter.begin(&pixmap);
1044  QFont textFont = textPainter.font();
1045  textFont.setPointSize(fontSize);
1046  textPainter.setFont(textFont);
1047  textPainter.setRenderHint(QPainter::Antialiasing, true);
1048 
1049  const QColor brushColor = color;
1050  if (hasRoundFrame) {
1051  QColor lighterColor = brushColor.lighter(110);
1052  lighterColor.setAlphaF(0.9);
1053  textPainter.setBrush(lighterColor);
1054  textPainter.drawRoundedRect(labelRect, 3, 3);
1055  }
1056 
1057  textPainter.setBrush(brushColor);
1058  textPainter.drawText(labelRect, Qt::AlignHCenter , text);
1059 
1060  if (hasRoundFrame) {
1061  textPainter.setBrush(brushColor);
1062  }
1063 
1064  textPainter.end();
1065  QPixmapCache::insert(key, pixmap);
1066  }
1067 
1068  QPainter::drawPixmap(position.x() - pixmap.width()/2,
1069  position.y() - pixmap.height()/2,
1070  pixmap);
1071 }
A Geometry object representing a 3d point.
Definition: GeoDataPoint.h:42
void setWidth(qreal width)
QRegion regionFromRect(const GeoDataCoordinates &centerPosition, qreal width, qreal height, bool isGeoProjected=false, qreal strokeWidth=3) const
Creates a region for a rectangle at a given position.
Definition: GeoPainter.cpp:955
QSize size() const const
A 3d point representation.
void setPointSize(int pointSize)
QPolygon toPolygon() const const
virtual bool intersects(const GeoDataLatLonAltBox &) const
Check if this GeoDataLatLonAltBox intersects with the given one.
int ascent() const const
void drawPolygon(const GeoDataLinearRing &linearRing, Qt::FillRule fillRule=Qt::OddEvenFill)
Draws a given linear ring (a "polygon without holes").
Definition: GeoPainter.cpp:759
int width() const const
bool end()
A LinearRing that allows to store a closed, contiguous set of line segments.
void setRenderHint(QPainter::RenderHint hint, bool on)
void strokePath(const QPainterPath &path, const QPen &pen)
void fill(const QColor &color)
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:88
static qreal normalizeLon(qreal lon, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize the longitude to always be -M_PI <= lon <= +M_PI (Radian).
qreal length() const const
Binds a QML item to a specific geodetic location in screen coordinates.
const QFont & font() const const
OddEvenFill
int size() const const
QTextStream & right(QTextStream &stream)
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
void moveTo(const QPointF &point)
int height() const const
Print quality.
Definition: MarbleGlobal.h:79
MapQuality
This enum is used to choose the map quality shown in the view.
Definition: MarbleGlobal.h:74
T & first()
~GeoPainter()
Destroys the geo painter.
Definition: GeoPainter.cpp:205
QRegion regionFromPixmapRect(const GeoDataCoordinates &centerCoordinates, int width, int height, int margin=0) const
Creates a region for a rectangle for a pixmap at a given position.
Definition: GeoPainter.cpp:515
QRegion regionFromPolyline(const GeoDataLineString &lineString, qreal strokeWidth=3) const
Creates a region for a given line string (a "polyline").
Definition: GeoPainter.cpp:726
void drawEllipse(const GeoDataCoordinates &centerPosition, qreal width, qreal height, bool isGeoProjected=false)
Draws an ellipse at the given position. The ellipse is placed with its center located at the given ce...
Definition: GeoPainter.cpp:320
QRegion regionFromEllipse(const GeoDataCoordinates &centerPosition, qreal width, qreal height, bool isGeoProjected=false, qreal strokeWidth=3) const
Creates a region for an ellipse at a given position.
Definition: GeoPainter.cpp:388
This file contains the headers for AbstractProjection.
AlignHCenter
int x() const const
int y() const const
void drawRoundedRect(const GeoDataCoordinates &centerPosition, qreal width, qreal height, qreal xRnd=25.0, qreal yRnd=25.0)
Draws a rectangle with rounded corners at the given position. The rectangle is placed with its center...
Definition: GeoPainter.cpp:995
QTextStream & left(QTextStream &stream)
qreal altitude() const
return the altitude of the Point in meters
void drawLabelsForPolygons(const QVector< QPolygonF * > &polygons, const QString &labelText, LabelPositionFlags labelPositionFlags, const QColor &labelColor)
Draws Labels for a given set of screen polygons.
Definition: GeoPainter.cpp:592
void drawRect(const QRectF &rectangle)
void clear()
void setFont(const QFont &font)
QTransform & translate(qreal dx, qreal dy)
QString number(int n, int base)
qreal x() const const
qreal y() const const
void addPolygon(const QPolygonF &polygon)
void drawPoint(const QPointF &position)
QPainterPath united(const QPainterPath &p) const const
void drawRect(const GeoDataCoordinates &centerPosition, qreal width, qreal height, bool isGeoProjected=false)
Draws a rectangle at the given position. The rectangle is placed with its center located at the given...
Definition: GeoPainter.cpp:927
QRectF boundingRect(const QRectF &rectangle, int flags, const QString &text)
int width() const const
void drawEllipse(const QRectF &rectangle)
void lineTo(const QPointF &endPoint)
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
A polygon that can have "holes".
bool isEmpty() const const
GeoPainter(QPaintDevice *paintDevice, const ViewportParams *viewportParams, MapQuality mapQuality=NormalQuality)
Creates a new geo painter.
Definition: GeoPainter.cpp:195
QRegion regionFromPoint(const GeoDataCoordinates &position, qreal strokeWidth=3) const
Creates a region for a given geographic position.
Definition: GeoPainter.cpp:264
QTextStream & center(QTextStream &stream)
virtual bool isClippedToSphere() const
Defines whether a projection is supposed to be clipped to a certain radius.
void setBrush(const QBrush &brush)
void drawAnnotation(const GeoDataCoordinates &position, const QString &text, QSizeF bubbleSize=QSizeF(130, 100), qreal bubbleOffsetX=-10, qreal bubbleOffsetY=-30, qreal xRnd=5, qreal yRnd=5)
Draws a text annotation that points to a geodesic position.
Definition: GeoPainter.cpp:217
void drawText(const QPointF &position, const QString &text)
QPainterPath createStroke(const QPainterPath &path) const const
static qreal normalizeLat(qreal lat, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize latitude to always be in -M_PI / 2.
QPointF pointAtPercent(qreal t) const const
A LineString that allows to store a contiguous set of line segments.
GeoDataLinearRing & outerBoundary()
Returns the outer boundary that is represented as a LinearRing.
A public class that controls what is visible in the viewport of a Marble map.
void reserve(int size)
void drawImage(const GeoDataCoordinates &centerPosition, const QImage &image)
Draws an image at the given position. The image is placed with its center located at the given center...
Definition: GeoPainter.cpp:466
int height() const const
QColor lighter(int factor) const const
This file contains the headers for ViewportParams.
void setTopLeft(const QPointF &position)
void setPointSizeF(qreal pointSize)
QRect viewport() const const
QTransform & rotate(qreal angle, Qt::Axis axis)
qreal angleAtPercent(qreal t) const const
bool contains(const QRect &rectangle, bool proper) const const
QRegion regionFromPolygon(const GeoDataLinearRing &linearRing, Qt::FillRule fillRule, qreal strokeWidth=3) const
Creates a region for a given linear ring (a "polygon without holes").
Definition: GeoPainter.cpp:784
QVector< GeoDataLinearRing > & innerBoundaries()
Returns a set of inner boundaries which are represented as LinearRings.
int width() const const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags)
void drawPath(const QPainterPath &path)
QPoint toPoint() const const
void geoCoordinates(qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit) const
use this function to get the longitude and latitude with one call - use the unit parameter to switch ...
High quality (e.g. antialiasing for lines)
Definition: MarbleGlobal.h:78
void polygonsFromLineString(const GeoDataLineString &lineString, QVector< QPolygonF * > &polygons) const
Helper method for safe and quick linestring conversion.
Definition: GeoPainter.cpp:544
bool isEmpty() const const
void drawText(const GeoDataCoordinates &position, const QString &text, qreal xOffset=0.0, qreal yOffset=0.0, qreal width=0.0, qreal height=0.0, const QTextOption &option=QTextOption())
Draws the given text at a given geographic position. The text is drawn starting at the given position...
Definition: GeoPainter.cpp:284
QFontMetrics fontMetrics() const const
void setX(qreal x)
void setY(qreal y)
const QChar at(int position) const const
int height() const const
QPixmap * find(const QString &key)
TextWordWrap
qreal widthF() const const
int length() const const
QSize size() const const
QString left(int n) const const
bool testRenderHint(QPainter::RenderHint hint) const const
void setAlphaF(qreal alpha)
qreal height() const const
int height() const const
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
MapQuality mapQuality() const
Returns the map quality.
Definition: GeoPainter.cpp:211
void drawPoint(const GeoDataCoordinates &position)
Draws a single point at a given geographic position. The point is drawn using the painter&#39;s pen color...
Definition: GeoPainter.cpp:247
int width(const QString &text, int len) const const
QPolygonF toFillPolygon(const QMatrix &matrix) const const
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
qreal height() const const
transparent
bool insert(const QString &key, const QPixmap &pixmap)
int size() const const
bool begin(QPaintDevice *device)
void setHeight(qreal height)
void setBottomRight(const QPointF &position)
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
bool empty() const const
const QPen & pen() const const
bool testFlag(Enum flag) const const
void drawPolyline(const GeoDataLineString &lineString, const QString &labelText, LabelPositionFlags labelPositionFlags=LineCenter, const QColor &labelcolor=Qt::black)
Draws a given line string (a "polyline") with a label.
Definition: GeoPainter.cpp:562
void drawPixmap(const GeoDataCoordinates &centerPosition, const QPixmap &pixmap)
Draws a pixmap at the given position. The pixmap is placed with its center located at the given cente...
Definition: GeoPainter.cpp:492
A class that defines a 3D bounding box for geographic data.
qreal width() const const
A class that defines a 2D bounding box for geographic data.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Dec 7 2021 23:10:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.