Marble

GeoPainter.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <tackat@kde.org>
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
29using namespace Marble;
30
31GeoPainterPrivate::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
39GeoPainterPrivate::~GeoPainterPrivate()
40{
41 delete[] m_x;
42}
43
44void 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
122GeoDataLinearRing 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
165bool 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
175qreal GeoPainterPrivate::normalizeAngle(qreal angle)
176{
177 angle = fmodf(angle, 360);
178 return angle < 0 ? angle + 360 : angle;
179}
180
181void 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;
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
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
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
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().horizontalAdvance( 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
320void 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
466void 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
492void 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
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().horizontalAdvance( 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().horizontalAdvance(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().horizontalAdvance( 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
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
903QVector<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
927void 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 ),
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
1017void 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.horizontalAdvance(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}
This file contains the headers for AbstractProjection.
This file contains the headers for ViewportParams.
virtual bool isClippedToSphere() const
Defines whether a projection is supposed to be clipped to a certain radius.
A 3d point representation.
static qreal normalizeLon(qreal lon, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize the longitude to always be -M_PI <= lon <= +M_PI (Radian).
qreal altitude() const
return the altitude of the Point in meters
qreal longitude(GeoDataCoordinates::Unit unit) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
qreal latitude(GeoDataCoordinates::Unit unit) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
static qreal normalizeLat(qreal lat, GeoDataCoordinates::Unit=GeoDataCoordinates::Radian)
normalize latitude to always be in -M_PI / 2.
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 ...
A class that defines a 3D bounding box for geographic data.
virtual bool intersects(const GeoDataLatLonAltBox &) const
Check if this GeoDataLatLonAltBox intersects with the given one.
A class that defines a 2D bounding box for geographic data.
A LineString that allows to store a contiguous set of line segments.
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
A LinearRing that allows to store a closed, contiguous set of line segments.
A Geometry object representing a 3d point.
A polygon that can have "holes".
QVector< GeoDataLinearRing > & innerBoundaries()
Returns a set of inner boundaries which are represented as LinearRings.
GeoDataLinearRing & outerBoundary()
Returns the outer boundary that is represented as a LinearRing.
A painter that allows to draw geometric primitives on the map.
Definition GeoPainter.h:89
GeoPainter(QPaintDevice *paintDevice, const ViewportParams *viewportParams, MapQuality mapQuality=NormalQuality)
Creates a new geo painter.
MapQuality mapQuality() const
Returns the map quality.
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...
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...
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...
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.
void drawPolygon(const GeoDataLinearRing &linearRing, Qt::FillRule fillRule=Qt::OddEvenFill)
Draws a given linear ring (a "polygon without holes").
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.
QRegion regionFromPoint(const GeoDataCoordinates &position, qreal strokeWidth=3) const
Creates a region for a given geographic position.
~GeoPainter()
Destroys the geo painter.
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...
void drawPoint(const GeoDataCoordinates &position)
Draws a single point at a given geographic position. The point is drawn using the painter's pen color...
QRegion regionFromPolygon(const GeoDataLinearRing &linearRing, Qt::FillRule fillRule, qreal strokeWidth=3) const
Creates a region for a given linear ring (a "polygon without holes").
void drawLabelsForPolygons(const QVector< QPolygonF * > &polygons, const QString &labelText, LabelPositionFlags labelPositionFlags, const QColor &labelColor)
Draws Labels for a given set of screen polygons.
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.
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...
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...
void polygonsFromLineString(const GeoDataLineString &lineString, QVector< QPolygonF * > &polygons) const
Helper method for safe and quick linestring conversion.
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.
QRegion regionFromPolyline(const GeoDataLineString &lineString, qreal strokeWidth=3) const
Creates a region for a given line string (a "polyline").
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.
A public class that controls what is visible in the viewport of a Marble map.
QString path(const QString &relativePath)
Binds a QML item to a specific geodetic location in screen coordinates.
MapQuality
This enum is used to choose the map quality shown in the view.
@ HighQuality
High quality (e.g. antialiasing for lines)
@ PrintQuality
Print quality.
QColor lighter(int factor) const const
void setAlphaF(float alpha)
bool testFlag(Enum flag) const const
void setPointSize(int pointSize)
void setPointSizeF(qreal pointSize)
int ascent() const const
int height() const const
int horizontalAdvance(QChar ch) const const
int height() const const
QSize size() const const
int width() const const
void clear()
bool empty() const const
T & first()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
bool begin(QPaintDevice *device)
QRect boundingRect(const QRect &rectangle, int flags, const QString &text)
void drawEllipse(const QPoint &center, int rx, int ry)
void drawImage(const QPoint &point, const QImage &image)
void drawPath(const QPainterPath &path)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawPoint(const QPoint &position)
void drawRect(const QRect &rectangle)
void drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawText(const QPoint &position, const QString &text)
bool end()
const QFont & font() const const
QFontMetrics fontMetrics() const const
const QPen & pen() const const
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setRenderHint(RenderHint hint, bool on)
void strokePath(const QPainterPath &path, const QPen &pen)
bool testRenderHint(RenderHint hint) const const
QRect viewport() const const
void addPolygon(const QPolygonF &polygon)
QPolygonF toFillPolygon(const QTransform &matrix) const const
QPainterPath united(const QPainterPath &p) const const
QPainterPath createStroke(const QPainterPath &path) const const
void setWidth(qreal width)
qreal widthF() const const
void fill(const QColor &color)
int height() const const
QSize size() const const
int width() const const
bool find(const Key &key, QPixmap *pixmap)
Key insert(const QPixmap &pixmap)
int x() const const
int y() const const
void setX(qreal x)
void setY(qreal y)
QPoint toPoint() const const
qreal x() const const
qreal y() const const
QPolygon toPolygon() const const
bool contains(const QPoint &point, bool proper) const const
int height() const const
int width() const const
void setBottomRight(const QPointF &position)
void setTopLeft(const QPointF &position)
qreal height() const const
void setHeight(qreal height)
qreal width() const const
const QChar at(qsizetype position) const const
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString number(double n, char format, int precision)
qsizetype size() const const
AlignHCenter
OddEvenFill
transparent
TextWordWrap
QTextStream & center(QTextStream &stream)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
QTransform & rotate(qreal a, Qt::Axis axis)
QTransform & translate(qreal dx, qreal dy)
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.