Marble

ClipPainter.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5//
6
7
8#include "ClipPainter.h"
9
10#include <cmath>
11
12#include "MarbleDebug.h"
13
14
15namespace Marble
16{
17
18class ClipPainterPrivate
19{
20 public:
21 explicit ClipPainterPrivate( ClipPainter * parent );
22
23 ClipPainter * q;
24
25 // true if clipping is on.
26 bool m_doClip;
27
28 // The limits
29 qreal m_left;
30 qreal m_right;
31 qreal m_top;
32 qreal m_bottom;
33
34 // Used in the paint process of vectors..
35 int m_currentSector;
36 int m_previousSector;
37
38 // int m_debugNodeCount;
39
40 QPointF m_currentPoint;
41 QPointF m_previousPoint;
42
43 inline int sector( const QPointF & point ) const;
44
45 inline QPointF clipTop( qreal m, const QPointF & point ) const;
46 inline QPointF clipLeft( qreal m, const QPointF & point ) const;
47 inline QPointF clipBottom( qreal m, const QPointF & point ) const;
48 inline QPointF clipRight( qreal m, const QPointF & point ) const;
49
50 inline void initClipRect();
51
52 inline void clipPolyObject ( const QPolygonF & sourcePolygon,
53 QVector<QPolygonF> & clippedPolyObjects,
54 bool isClosed );
55
56 inline void clipMultiple( QPolygonF & clippedPolyObject,
57 QVector<QPolygonF> & clippedPolyObjects,
58 bool isClosed );
59 inline void clipOnce( QPolygonF & clippedPolyObject,
60 QVector<QPolygonF> & clippedPolyObjects,
61 bool isClosed );
62 inline void clipOnceCorner( QPolygonF & clippedPolyObject,
63 QVector<QPolygonF> & clippedPolyObjects,
64 const QPointF& corner,
65 const QPointF& point,
66 bool isClosed ) const;
67 inline void clipOnceEdge( QPolygonF & clippedPolyObject,
68 QVector<QPolygonF> & clippedPolyObjects,
69 const QPointF& point,
70 bool isClosed ) const;
71
72
73 void labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
74 LabelPositionFlags labelPositionFlags) const;
75
76 bool pointAllowsLabel(const QPointF &point) const;
77 QPointF interpolateLabelPoint(const QPointF &previousPoint,
78 const QPointF &currentPoint,
79 LabelPositionFlags labelPositionFlags) const;
80
81 static inline qreal _m( const QPointF & start, const QPointF & end );
82
83 void debugDrawNodes( const QPolygonF & );
84
85 qreal m_labelAreaMargin;
86
87 int m_debugPenBatchColor;
88 int m_debugBrushBatchColor;
89 int m_debugPolygonsLevel;
90 bool m_debugBatchRender;
91};
92
93}
94
95using namespace Marble;
96
97// #define MARBLE_DEBUG
98
99ClipPainter::ClipPainter(QPaintDevice * pd, bool clip)
100 : QPainter( pd ), d( new ClipPainterPrivate( this ) )
101{
102 d->initClipRect();
103
104 // m_debugNodeCount = 0;
105 d->m_doClip = clip;
106}
107
108
109ClipPainter::ClipPainter()
110 : d( new ClipPainterPrivate( this ) )
111{
112}
113
114
115ClipPainter::~ClipPainter()
116{
117 delete d;
118}
119
120
121void ClipPainter::setScreenClip(bool enable)
122{
123 d->m_doClip = enable;
124}
125
126
127bool ClipPainter::hasScreenClip() const
128{
129 return d->m_doClip;
130}
131
132
133void ClipPainter::drawPolygon ( const QPolygonF & polygon,
134 Qt::FillRule fillRule )
135{
136 if ( d->m_doClip ) {
137 d->initClipRect();
138 QVector<QPolygonF> clippedPolyObjects;
139
140 d->clipPolyObject( polygon, clippedPolyObjects, true );
141
142 for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
143 if ( clippedPolyObject.size() > 2 ) {
144 // mDebug() << "Size: " << clippedPolyObject.size();
145 if (d->m_debugPolygonsLevel) {
147 QBrush originalBrush = brush;
148 QColor color = brush.color();
149 color.setAlpha(color.alpha()*0.75);
150 brush.setColor(color);
152
153 QPainter::drawPolygon ( clippedPolyObject, fillRule );
154
155 QPainter::setBrush(originalBrush);
156
157 d->debugDrawNodes( clippedPolyObject );
158 }
159 else {
160 QPainter::drawPolygon ( clippedPolyObject, fillRule );
161 }
162 }
163 }
164 }
165 else {
166 if (d->m_debugPolygonsLevel) {
168 QBrush originalBrush = brush;
169 QColor color = brush.color();
170 color.setAlpha(color.alpha()*0.75);
171 brush.setColor(color);
173
174 QPainter::drawPolygon ( polygon, fillRule );
175
176 QPainter::setBrush(originalBrush);
177
178 d->debugDrawNodes( polygon );
179 }
180 else {
181 QPainter::drawPolygon ( polygon, fillRule );
182 }
183 }
184}
185
186void ClipPainter::drawPolyline( const QPolygonF & polygon )
187{
188 if ( d->m_doClip ) {
189 d->initClipRect();
190 QVector<QPolygonF> clippedPolyObjects;
191
192 d->clipPolyObject( polygon, clippedPolyObjects, false );
193
194 for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
195 if ( clippedPolyObject.size() > 1 ) {
196 if (d->m_debugPolygonsLevel) {
198 QPen originalPen = pen;
199 QColor color = pen.color();
200 color.setAlpha(color.alpha()*0.75);
201 pen.setColor(color);
203
204 QPainter::drawPolyline ( clippedPolyObject );
205
206 QPainter::setPen(originalPen);
207
208 d->debugDrawNodes( clippedPolyObject );
209 }
210 else {
211 QPainter::drawPolyline ( clippedPolyObject );
212 }
213 }
214 }
215 }
216 else {
217 if (d->m_debugPolygonsLevel) {
219 QPen originalPen = pen;
220 QColor color = pen.color();
221 color.setAlpha(color.alpha()*0.75);
222 pen.setColor(color);
224
225 QPainter::drawPolyline ( polygon );
226
227 QPainter::setPen(originalPen);
228
229 d->debugDrawNodes( polygon );
230 }
231 else {
232 QPainter::drawPolyline ( polygon );
233 }
234 }
235}
236
237void ClipPainter::drawPolyline(const QPolygonF & polygon, QVector<QPointF>& labelNodes,
238 LabelPositionFlags positionFlags)
239{
240 if ( d->m_doClip ) {
241 d->initClipRect();
242 QVector<QPolygonF> clippedPolyObjects;
243
244 d->clipPolyObject( polygon, clippedPolyObjects, false );
245
246 for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
247 if (d->m_debugPolygonsLevel) {
249 QPen originalPen = pen;
250 QColor color = pen.color();
251 color.setAlpha(color.alpha()*0.75);
252 pen.setColor(color);
254
255 QPainter::drawPolyline ( clippedPolyObject );
256
257 QPainter::setPen(originalPen);
258
259 d->debugDrawNodes( clippedPolyObject );
260 }
261 else {
262 QPainter::drawPolyline ( clippedPolyObject );
263 }
264 }
265 }
266 else {
267 if (d->m_debugPolygonsLevel) {
269 QPen originalPen = pen;
270 QColor color = pen.color();
271 color.setAlpha(color.alpha()*0.75);
272 pen.setColor(color);
274
275 QPainter::drawPolyline ( polygon );
276
277 QPainter::setPen(originalPen);
278
279 d->debugDrawNodes( polygon );
280 }
281 else {
282 QPainter::drawPolyline ( polygon );
283 }
284
285 d->labelPosition( polygon, labelNodes, positionFlags );
286 }
287}
288
289void ClipPainter::labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
290 LabelPositionFlags labelPositionFlags) const
291{
292 d->labelPosition(polygon, labelNodes, labelPositionFlags);
293}
294
295void ClipPainter::setPen(const QColor &color) {
296 if (d->m_debugBatchRender) {
297 qDebug();
298 }
299 setPen(QPen(color));
300}
301
302void ClipPainter::setPen(Qt::PenStyle style) {
303 if (d->m_debugBatchRender) {
304 qDebug();
305 }
306 setPen(QPen(style));
307}
308
309void ClipPainter::setPen(const QPen & pen) {
310 if (d->m_debugBatchRender) {
311 qDebug();
312 if (pen != QPainter::pen()) {
313 qDebug() << "--" << pen.color() << QPainter::pen().color() ;
314 QPen newPen = pen;
315 newPen.setColor((Qt::GlobalColor)(d->m_debugPenBatchColor+4));
316 QPainter::setPen(newPen);
317 d->m_debugPenBatchColor++;
318 d->m_debugPenBatchColor %= 14;
319 }
320 else {
321 qDebug() << "++";
323 }
324 }
325 else {
327 }
328}
329
330void ClipPainter::setBrush(const QBrush & brush) {
331 if (d->m_debugBatchRender) {
332 qDebug();
333 if (brush != QPainter::brush()) {
334 qDebug() << "--" << brush.color() << QPainter::brush().color() ;
335 QBrush batchColor(QColor((Qt::GlobalColor)(d->m_debugBrushBatchColor)));
336 QPainter::setBrush(batchColor);
337 d->m_debugBrushBatchColor++;
338 d->m_debugBrushBatchColor %= 20;
339 }
340 else {
341 qDebug() << "++";
343 }
344 }
345 else {
347 }
348}
349
350void ClipPainterPrivate::labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
351 LabelPositionFlags labelPositionFlags) const
352{
353 if ( labelPositionFlags.testFlag( LineCenter ) ) {
354 // The Label at the center of the polyline:
355 if ( polygon.size() > 0 ) {
356 const int labelPosition = polygon.size() / 2; // implied: 0 <= labelPosition < polygon.size()
357 labelNodes << polygon.at( labelPosition );
358 }
359 }
360
361 if ( polygon.size() > 0 && labelPositionFlags.testFlag( LineStart ) ) {
362 if ( pointAllowsLabel( polygon.first() ) ) {
363 labelNodes << polygon.first();
364 }
365
366 // The Label at the start of the polyline:
367 for ( int it = 1; it < polygon.size(); ++it ) {
368 const bool currentAllowsLabel = pointAllowsLabel(polygon.at(it));
369
370 if ( currentAllowsLabel ) {
371 // As polygon.size() > 0 it's ensured that it-1 exists.
372 QPointF node = interpolateLabelPoint( polygon.at( it -1 ), polygon.at( it ),
373 labelPositionFlags );
374 if ( node != QPointF( -1.0, -1.0 ) ) {
375 labelNodes << node;
376 }
377 break;
378 }
379 }
380 }
381
382 if ( polygon.size() > 1 && labelPositionFlags.testFlag( LineEnd ) ) {
383 if ( pointAllowsLabel( polygon.at( polygon.size() - 1 ) ) ) {
384 labelNodes << polygon.at( polygon.size() - 1 );
385 }
386
387 // The Label at the end of the polyline:
388 for ( int it = polygon.size() - 2; it > 0; --it ) {
389 const bool currentAllowsLabel = pointAllowsLabel(polygon.at(it));
390
391 if ( currentAllowsLabel ) {
392 QPointF node = interpolateLabelPoint( polygon.at( it + 1 ), polygon.at( it ),
393 labelPositionFlags );
394 if ( node != QPointF( -1.0, -1.0 ) ) {
395 labelNodes << node;
396 }
397 break;
398 }
399 }
400 }
401}
402
403bool ClipPainterPrivate::pointAllowsLabel(const QPointF &point) const
404{
405 return point.x() > m_labelAreaMargin && point.x() < q->viewport().width() - m_labelAreaMargin
406 && point.y() > m_labelAreaMargin && point.y() < q->viewport().height() - m_labelAreaMargin;
407}
408
409QPointF ClipPainterPrivate::interpolateLabelPoint(const QPointF &previousPoint,
410 const QPointF &currentPoint,
411 LabelPositionFlags labelPositionFlags) const
412{
413 qreal m = _m( previousPoint, currentPoint );
414 if ( previousPoint.x() <= m_labelAreaMargin ) {
415 if ( labelPositionFlags.testFlag( IgnoreXMargin ) ) {
416 return QPointF( -1.0, -1.0 );
417 }
418 return QPointF( m_labelAreaMargin,
419 previousPoint.y() + ( m_labelAreaMargin - previousPoint.x() ) * m );
420 }
421 else if ( previousPoint.x() >= q->viewport().width() - m_labelAreaMargin ) {
422 if ( labelPositionFlags.testFlag( IgnoreXMargin ) ) {
423 return QPointF( -1.0, -1.0 );
424 }
425 return QPointF( q->viewport().width() - m_labelAreaMargin,
426 previousPoint.y() -
427 ( previousPoint.x() - q->viewport().width() + m_labelAreaMargin ) * m );
428 }
429
430 if ( previousPoint.y() <= m_labelAreaMargin ) {
431 if ( labelPositionFlags.testFlag( IgnoreYMargin ) ) {
432 return QPointF( -1.0, -1.0 );
433 }
434 return QPointF( previousPoint.x() + ( m_labelAreaMargin - previousPoint.y() ) / m,
435 m_labelAreaMargin );
436 }
437 else if ( previousPoint.y() >= q->viewport().height() - m_labelAreaMargin ) {
438 if ( labelPositionFlags.testFlag( IgnoreYMargin ) ) {
439 return QPointF( -1.0, -1.0 );
440 }
441 return QPointF( previousPoint.x() -
442 ( previousPoint.y() - q->viewport().height() + m_labelAreaMargin ) / m,
443 q->viewport().height() - m_labelAreaMargin );
444 }
445
446// mDebug() << "Previous and current node position are allowed!";
447
448 return QPointF( -1.0, -1.0 );
449}
450
451ClipPainterPrivate::ClipPainterPrivate( ClipPainter * parent )
452 : m_doClip( true ),
453 m_left(0.0),
454 m_right(0.0),
455 m_top(0.0),
456 m_bottom(0.0),
457 m_currentSector(4),
458 m_previousSector(4),
459 m_currentPoint(QPointF()),
460 m_previousPoint(QPointF()),
461 m_labelAreaMargin(10.0),
462 m_debugPenBatchColor(0),
463 m_debugBrushBatchColor(0),
464 m_debugPolygonsLevel(0),
465 m_debugBatchRender(false)
466{
467 q = parent;
468}
469
470void ClipPainterPrivate::initClipRect ()
471{
472 qreal penHalfWidth = q->pen().widthF() / 2.0 + 1.0;
473
474 m_left = -penHalfWidth;
475 m_right = (qreal)(q->device()->width()) + penHalfWidth;
476 m_top = -penHalfWidth;
477 m_bottom = (qreal)(q->device()->height()) + penHalfWidth;
478}
479
480qreal ClipPainterPrivate::_m( const QPointF & start, const QPointF & end )
481{
482 qreal divisor = end.x() - start.x();
483 if ( std::fabs( divisor ) < 0.000001 ) {
484 // this is in screencoordinates so the difference
485 // between 0, 0.000001 and -0.000001 isn't visible at all
486 divisor = 0.000001;
487 }
488
489 return ( end.y() - start.y() )
490 / divisor;
491}
492
493
494QPointF ClipPainterPrivate::clipTop( qreal m, const QPointF & point ) const
495{
496 return QPointF( ( m_top - point.y() ) / m + point.x(), m_top );
497}
498
499QPointF ClipPainterPrivate::clipLeft( qreal m, const QPointF & point ) const
500{
501 return QPointF( m_left, ( m_left - point.x() ) * m + point.y() );
502}
503
504QPointF ClipPainterPrivate::clipBottom( qreal m, const QPointF & point ) const
505{
506 return QPointF( ( m_bottom - point.y() ) / m + point.x(), m_bottom );
507}
508
509QPointF ClipPainterPrivate::clipRight( qreal m, const QPointF & point ) const
510{
511 return QPointF( m_right, ( m_right - point.x() ) * m + point.y() );
512}
513
514int ClipPainterPrivate::sector( const QPointF & point ) const
515{
516 // If we think of the image borders as (infinitely long) parallel
517 // lines then the plane is divided into 9 sectors. Each of these
518 // sections is identified by a unique keynumber (currentSector):
519 //
520 // 0 | 1 | 2
521 // --+---+--
522 // 3 | 4 | 5 <- sector number "4" represents the onscreen sector / viewport
523 // --+---+--
524 // 6 | 7 | 8
525 //
526
527 // Figure out the section of the current point.
528 int xSector = 1;
529 if ( point.x() < m_left )
530 xSector = 0;
531 else if ( point.x() > m_right )
532 xSector = 2;
533
534 int ySector = 3;
535 if ( point.y() < m_top )
536 ySector = 0;
537 else if ( point.y() > m_bottom )
538 ySector = 6;
539
540 // By adding xSector and ySector we get a
541 // sector number of the values shown in the ASCII-art graph above.
542 return ySector + xSector;
543
544}
545
546void ClipPainterPrivate::clipPolyObject ( const QPolygonF & polygon,
547 QVector<QPolygonF> & clippedPolyObjects,
548 bool isClosed )
549{
550 // mDebug() << "ClipPainter enabled." ;
551
552 // Only create a new polyObject as soon as we know for sure that
553 // the current point is on the screen.
554 QPolygonF clippedPolyObject = QPolygonF();
555
556 const QVector<QPointF>::const_iterator itStartPoint = polygon.constBegin();
557 const QVector<QPointF>::const_iterator itEndPoint = polygon.constEnd();
558 QVector<QPointF>::const_iterator itPoint = itStartPoint;
559
560 // We use a while loop to be able to cover linestrings as well as linear rings:
561 // Linear rings require to tessellate the path from the last node to the first node
562 // which isn't really convenient to achieve with a for loop ...
563
564 bool processingLastNode = false;
565
566 while ( itPoint != itEndPoint ) {
567 m_currentPoint = (*itPoint);
568 // mDebug() << "m_currentPoint.x()" << m_currentPoint.x() << "m_currentPOint.y()" << m_currentPoint.y();
569
570 // Figure out the sector of the current point.
571 m_currentSector = sector( m_currentPoint );
572
573 // Initialize the variables related to the previous point.
574 if ( itPoint == itStartPoint && processingLastNode == false ) {
575 if ( isClosed ) {
576 m_previousPoint = polygon.last();
577
578 // Figure out the sector of the previous point.
579 m_previousSector = sector( m_previousPoint );
580 }
581 else {
582 m_previousSector = m_currentSector;
583 }
584 }
585
586 // If the current point reaches a new sector, take care of clipping.
587 if ( m_currentSector != m_previousSector ) {
588 if ( m_currentSector == 4 || m_previousSector == 4 ) {
589 // In this case the current or the previous point is visible on the
590 // screen but not both. Hence we only need to clip once and require
591 // only one interpolation for both cases.
592
593 clipOnce( clippedPolyObject, clippedPolyObjects, isClosed );
594 }
595 else {
596 // This case mostly deals with lines that reach from one
597 // sector that is located off screen to another one that
598 // is located off screen. In this situation the line
599 // can get clipped once, twice, or not at all.
600 clipMultiple( clippedPolyObject, clippedPolyObjects, isClosed );
601 }
602
603 m_previousSector = m_currentSector;
604 }
605
606 // If the current point is onscreen, just add it to our final polygon.
607 if ( m_currentSector == 4 ) {
608
609 clippedPolyObject << m_currentPoint;
610#ifdef MARBLE_DEBUG
611 ++(m_debugNodeCount);
612#endif
613 }
614
615 m_previousPoint = m_currentPoint;
616
617 // Now let's handle the case where we have a (closed) polygon and where the
618 // last point of the polyline is outside the viewport and the start point
619 // is inside the viewport. This needs special treatment
620 if ( processingLastNode ) {
621 break;
622 }
623 ++itPoint;
624
625 if ( itPoint == itEndPoint && isClosed ) {
626 itPoint = itStartPoint;
627 processingLastNode = true;
628 }
629 }
630
631 // Only add the pointer if there's node data available.
632 if ( !clippedPolyObject.isEmpty() ) {
633 clippedPolyObjects << clippedPolyObject;
634 }
635}
636
637
638void ClipPainterPrivate::clipMultiple( QPolygonF & clippedPolyObject,
639 QVector<QPolygonF> & clippedPolyObjects,
640 bool isClosed )
641{
642 Q_UNUSED( clippedPolyObjects )
643 Q_UNUSED( isClosed )
644
645 // Take care of adding nodes in the image corners if the iterator
646 // traverses off screen sections.
647
648 qreal m = _m( m_previousPoint, m_currentPoint );
649
650 switch ( m_currentSector ) {
651 case 0:
652 if ( m_previousSector == 5 ) {
653 QPointF pointRight = clipRight( m, m_previousPoint );
654 QPointF pointTop = clipTop( m, m_currentPoint );
655 QPointF pointLeft = clipLeft( m, m_currentPoint );
656
657 if ( pointRight.y() > m_top ) {
658 clippedPolyObject << pointRight;
659 } else {
660 clippedPolyObject << QPointF( m_right, m_top );
661 }
662 if ( pointTop.x() >= m_left && pointTop.x() < m_right )
663 clippedPolyObject << pointTop;
664 if ( pointLeft.y() > m_top )
665 clippedPolyObject << pointLeft;
666 }
667 else if ( m_previousSector == 7 ) {
668 QPointF pointBottom = clipBottom( m, m_previousPoint );
669 QPointF pointTop = clipTop( m, m_currentPoint );
670 QPointF pointLeft = clipLeft( m, m_currentPoint );
671
672 if ( pointBottom.x() > m_left ) {
673 clippedPolyObject << pointBottom;
674 } else {
675 clippedPolyObject << QPointF( m_left, m_bottom );
676 }
677 if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom )
678 clippedPolyObject << pointLeft;
679 if ( pointTop.x() > m_left )
680 clippedPolyObject << pointTop;
681 }
682 else if ( m_previousSector == 8 ) {
683 QPointF pointBottom = clipBottom( m, m_previousPoint );
684 QPointF pointRight = clipRight( m, m_previousPoint );
685 QPointF pointTop = clipTop( m, m_currentPoint );
686 QPointF pointLeft = clipLeft( m, m_currentPoint );
687
688 if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
689 clippedPolyObject << pointBottom;
690 if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
691 clippedPolyObject << pointRight;
692 if ( pointTop.x() > m_left && pointTop.x() < m_right )
693 clippedPolyObject << pointTop;
694 if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
695 clippedPolyObject << pointLeft;
696
697 if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom )
698 clippedPolyObject << QPointF( m_left, m_bottom );
699 if ( pointTop.x() >= m_right && pointRight.y() <= m_top )
700 clippedPolyObject << QPointF( m_right, m_top );
701 }
702
703 clippedPolyObject << QPointF( m_left, m_top );
704 break;
705
706 case 1:
707 if ( m_previousSector == 3 ) {
708 QPointF pointLeft = clipLeft( m, m_previousPoint );
709 QPointF pointTop = clipTop( m, m_currentPoint );
710
711 if ( pointLeft.y() > m_top ) {
712 clippedPolyObject << pointLeft;
713 } else {
714 clippedPolyObject << QPointF( m_left, m_top );
715 }
716 if ( pointTop.x() > m_left )
717 clippedPolyObject << pointTop;
718 }
719 else if ( m_previousSector == 5 ) {
720 QPointF pointRight = clipRight( m, m_previousPoint );
721 QPointF pointTop = clipTop( m, m_currentPoint );
722
723 if ( pointRight.y() > m_top ) {
724 clippedPolyObject << pointRight;
725 } else {
726 clippedPolyObject << QPointF( m_right, m_top );
727 }
728 if ( pointTop.x() < m_right )
729 clippedPolyObject << pointTop;
730 }
731 else if ( m_previousSector == 6 ) {
732 QPointF pointBottom = clipBottom( m, m_previousPoint );
733 QPointF pointLeft = clipLeft( m, m_previousPoint );
734 QPointF pointTop = clipTop( m, m_currentPoint );
735
736 if ( pointBottom.x() > m_left )
737 clippedPolyObject << pointBottom;
738 if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom )
739 clippedPolyObject << pointLeft;
740 if ( pointTop.x() > m_left ) {
741 clippedPolyObject << pointTop;
742 } else {
743 clippedPolyObject << QPointF( m_left, m_top );
744 }
745 }
746 else if ( m_previousSector == 7 ) {
747 clippedPolyObject << clipBottom( m, m_previousPoint );
748 clippedPolyObject << clipTop( m, m_currentPoint );
749 }
750 else if ( m_previousSector == 8 ) {
751 QPointF pointBottom = clipBottom( m, m_previousPoint );
752 QPointF pointRight = clipRight( m, m_previousPoint );
753 QPointF pointTop = clipTop( m, m_currentPoint );
754
755 if ( pointBottom.x() < m_right )
756 clippedPolyObject << pointBottom;
757 if ( pointRight.y() > m_top && pointRight.y() <= m_bottom )
758 clippedPolyObject << pointRight;
759 if ( pointTop.x() < m_right ) {
760 clippedPolyObject << pointTop;
761 } else {
762 clippedPolyObject << QPointF( m_right, m_top );
763 }
764 }
765 break;
766
767 case 2:
768 if ( m_previousSector == 3 ) {
769 QPointF pointLeft = clipLeft( m, m_previousPoint );
770 QPointF pointTop = clipTop( m, m_currentPoint );
771 QPointF pointRight = clipRight( m, m_currentPoint );
772
773 if ( pointLeft.y() > m_top ) {
774 clippedPolyObject << pointLeft;
775 } else {
776 clippedPolyObject << QPointF( m_left, m_top );
777 }
778 if ( pointTop.x() > m_left && pointTop.x() <= m_right )
779 clippedPolyObject << pointTop;
780 if ( pointRight.y() > m_top )
781 clippedPolyObject << pointRight;
782 }
783 else if ( m_previousSector == 7 ) {
784 QPointF pointBottom = clipBottom( m, m_previousPoint );
785 QPointF pointTop = clipTop( m, m_currentPoint );
786 QPointF pointRight = clipRight( m, m_currentPoint );
787
788 if ( pointBottom.x() < m_right ) {
789 clippedPolyObject << pointBottom;
790 } else {
791 clippedPolyObject << QPointF( m_right, m_bottom );
792 }
793 if ( pointRight.y() >= m_top && pointRight.y() < m_bottom )
794 clippedPolyObject << pointRight;
795 if ( pointTop.x() < m_right )
796 clippedPolyObject << pointTop;
797 }
798 else if ( m_previousSector == 6 ) {
799 QPointF pointBottom = clipBottom( m, m_previousPoint );
800 QPointF pointLeft = clipLeft( m, m_currentPoint );
801 QPointF pointTop = clipTop( m, m_currentPoint );
802 QPointF pointRight = clipRight( m, m_previousPoint );
803
804 if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
805 clippedPolyObject << pointBottom;
806 if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
807 clippedPolyObject << pointLeft;
808 if ( pointTop.x() > m_left && pointTop.x() < m_right )
809 clippedPolyObject << pointTop;
810 if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
811 clippedPolyObject << pointRight;
812
813 if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom )
814 clippedPolyObject << QPointF( m_right, m_bottom );
815 if ( pointTop.x() <= m_left && pointLeft.y() <= m_top )
816 clippedPolyObject << QPointF( m_left, m_top );
817 }
818
819 clippedPolyObject << QPointF( m_right, m_top );
820 break;
821
822 case 3:
823 if ( m_previousSector == 7 ) {
824 QPointF pointBottom = clipBottom( m, m_previousPoint );
825 QPointF pointLeft = clipLeft( m, m_currentPoint );
826
827 if ( pointBottom.x() > m_left )
828 clippedPolyObject << pointBottom;
829 if ( pointLeft.y() < m_bottom ) {
830 clippedPolyObject << pointLeft;
831 } else {
832 clippedPolyObject << QPointF( m_left, m_bottom );
833 }
834 }
835 else if ( m_previousSector == 1 ) {
836 QPointF pointTop = clipTop( m, m_previousPoint );
837 QPointF pointLeft = clipLeft( m, m_currentPoint );
838
839 if ( pointTop.x() > m_left )
840 clippedPolyObject << pointTop;
841 if ( pointLeft.y() > m_top ) {
842 clippedPolyObject << pointLeft;
843 } else {
844 clippedPolyObject << QPointF( m_left, m_top );
845 }
846 }
847 else if ( m_previousSector == 8 ) {
848 QPointF pointRight = clipRight( m, m_previousPoint );
849 QPointF pointBottom = clipBottom( m, m_previousPoint );
850 QPointF pointLeft = clipLeft( m, m_currentPoint );
851
852 if ( pointRight.y() < m_bottom )
853 clippedPolyObject << pointRight;
854 if ( pointBottom.x() > m_left && pointBottom.x() <= m_right )
855 clippedPolyObject << pointBottom;
856 if ( pointLeft.y() < m_bottom ) {
857 clippedPolyObject << pointLeft;
858 } else {
859 clippedPolyObject << QPointF( m_left, m_bottom );
860 }
861 }
862 else if ( m_previousSector == 5 ) {
863 clippedPolyObject << clipRight( m, m_previousPoint );
864 clippedPolyObject << clipLeft( m, m_currentPoint );
865 }
866 else if ( m_previousSector == 2 ) {
867 QPointF pointRight = clipRight( m, m_previousPoint );
868 QPointF pointTop = clipTop( m, m_previousPoint );
869 QPointF pointLeft = clipLeft( m, m_currentPoint );
870
871 if ( pointRight.y() > m_top )
872 clippedPolyObject << pointRight;
873 if ( pointTop.x() > m_left && pointTop.x() <= m_right )
874 clippedPolyObject << pointTop;
875 if ( pointLeft.y() > m_top ) {
876 clippedPolyObject << pointLeft;
877 } else {
878 clippedPolyObject << QPointF( m_left, m_top );
879 }
880 }
881 break;
882
883 case 5:
884 if ( m_previousSector == 7 ) {
885 QPointF pointBottom = clipBottom( m, m_previousPoint );
886 QPointF pointRight = clipRight( m, m_currentPoint );
887
888 if ( pointBottom.x() < m_right )
889 clippedPolyObject << pointBottom;
890 if ( pointRight.y() < m_bottom ) {
891 clippedPolyObject << pointRight;
892 } else {
893 clippedPolyObject << QPointF( m_right, m_bottom );
894 }
895 }
896 else if ( m_previousSector == 1 ) {
897 QPointF pointTop = clipTop( m, m_previousPoint );
898 QPointF pointRight = clipRight( m, m_currentPoint );
899
900 if ( pointTop.x() < m_right )
901 clippedPolyObject << pointTop;
902 if ( pointRight.y() > m_top ) {
903 clippedPolyObject << pointRight;
904 } else {
905 clippedPolyObject << QPointF( m_right, m_top );
906 }
907 }
908 else if ( m_previousSector == 6 ) {
909 QPointF pointLeft = clipLeft( m, m_previousPoint );
910 QPointF pointBottom = clipBottom( m, m_previousPoint );
911 QPointF pointRight = clipRight( m, m_currentPoint );
912
913 if ( pointLeft.y() < m_bottom )
914 clippedPolyObject << pointLeft;
915 if ( pointBottom.x() >= m_left && pointBottom.x() < m_right )
916 clippedPolyObject << pointBottom;
917 if ( pointRight.y() < m_bottom ) {
918 clippedPolyObject << pointRight;
919 } else {
920 clippedPolyObject << QPointF( m_right, m_bottom );
921 }
922 }
923 else if ( m_previousSector == 3 ) {
924 clippedPolyObject << clipLeft( m, m_previousPoint );
925 clippedPolyObject << clipRight( m, m_currentPoint );
926 }
927 else if ( m_previousSector == 0 ) {
928 QPointF pointLeft = clipLeft( m, m_previousPoint );
929 QPointF pointTop = clipTop( m, m_previousPoint );
930 QPointF pointRight = clipRight( m, m_currentPoint );
931
932 if ( pointLeft.y() > m_top )
933 clippedPolyObject << pointLeft;
934 if ( pointTop.x() >= m_left && pointTop.x() < m_right )
935 clippedPolyObject << pointTop;
936 if ( pointRight.y() > m_top ) {
937 clippedPolyObject << pointRight;
938 } else {
939 clippedPolyObject << QPointF( m_right, m_top );
940 }
941 }
942 break;
943
944 case 6:
945 if ( m_previousSector == 5 ) {
946 QPointF pointRight = clipRight( m, m_previousPoint );
947 QPointF pointBottom = clipBottom( m, m_currentPoint );
948 QPointF pointLeft = clipLeft( m, m_currentPoint );
949
950 if ( pointRight.y() < m_bottom ) {
951 clippedPolyObject << pointRight;
952 } else {
953 clippedPolyObject << QPointF( m_right, m_bottom );
954 }
955 if ( pointBottom.x() >= m_left && pointBottom.x() < m_right )
956 clippedPolyObject << pointBottom;
957 if ( pointLeft.y() < m_bottom )
958 clippedPolyObject << pointLeft;
959 }
960 else if ( m_previousSector == 1 ) {
961 QPointF pointTop = clipTop( m, m_previousPoint );
962 QPointF pointLeft = clipLeft( m, m_currentPoint );
963 QPointF pointBottom = clipBottom( m, m_currentPoint );
964
965 if ( pointTop.x() > m_left ) {
966 clippedPolyObject << pointTop;
967 } else {
968 clippedPolyObject << QPointF( m_left, m_top );
969 }
970 if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom )
971 clippedPolyObject << pointLeft;
972 if ( pointBottom.x() > m_left )
973 clippedPolyObject << pointBottom;
974 }
975 else if ( m_previousSector == 2 ) {
976 QPointF pointTop = clipTop( m, m_currentPoint );
977 QPointF pointRight = clipRight( m, m_previousPoint );
978 QPointF pointBottom = clipBottom( m, m_previousPoint );
979 QPointF pointLeft = clipLeft( m, m_currentPoint );
980
981 if ( pointTop.x() > m_left && pointTop.x() < m_right )
982 clippedPolyObject << pointTop;
983 if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
984 clippedPolyObject << pointRight;
985 if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
986 clippedPolyObject << pointBottom;
987 if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
988 clippedPolyObject << pointLeft;
989
990 if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom )
991 clippedPolyObject << QPointF( m_right, m_bottom );
992 if ( pointTop.x() <= m_left && pointLeft.y() <= m_top )
993 clippedPolyObject << QPointF( m_left, m_top );
994 }
995
996 clippedPolyObject << QPointF( m_left, m_bottom );
997 break;
998
999 case 7:
1000 if ( m_previousSector == 3 ) {
1001 QPointF pointLeft = clipLeft( m, m_previousPoint );
1002 QPointF pointBottom = clipBottom( m, m_currentPoint );
1003
1004 if ( pointLeft.y() < m_bottom ) {
1005 clippedPolyObject << pointLeft;
1006 } else {
1007 clippedPolyObject << QPointF( m_left, m_bottom );
1008 }
1009 if ( pointBottom.x() > m_left )
1010 clippedPolyObject << pointBottom;
1011 }
1012 else if ( m_previousSector == 5 ) {
1013 QPointF pointRight = clipRight( m, m_previousPoint );
1014 QPointF pointBottom = clipBottom( m, m_currentPoint );
1015
1016 if ( pointRight.y() < m_bottom ) {
1017 clippedPolyObject << pointRight;
1018 } else {
1019 clippedPolyObject << QPointF( m_right, m_bottom );
1020 }
1021 if ( pointBottom.x() < m_right )
1022 clippedPolyObject << pointBottom;
1023 }
1024 else if ( m_previousSector == 0 ) {
1025 QPointF pointTop = clipTop( m, m_previousPoint );
1026 QPointF pointLeft = clipLeft( m, m_previousPoint );
1027 QPointF pointBottom = clipBottom( m, m_currentPoint );
1028
1029 if ( pointTop.x() > m_left )
1030 clippedPolyObject << pointTop;
1031 if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom )
1032 clippedPolyObject << pointLeft;
1033 if ( pointBottom.x() > m_left ) {
1034 clippedPolyObject << pointBottom;
1035 } else {
1036 clippedPolyObject << QPointF( m_left, m_bottom );
1037 }
1038 }
1039 else if ( m_previousSector == 1 ) {
1040 clippedPolyObject << clipTop( m, m_previousPoint );
1041 clippedPolyObject << clipBottom( m, m_currentPoint );
1042 }
1043 else if ( m_previousSector == 2 ) {
1044 QPointF pointTop = clipTop( m, m_previousPoint );
1045 QPointF pointRight = clipRight( m, m_previousPoint );
1046 QPointF pointBottom = clipBottom( m, m_currentPoint );
1047
1048 if ( pointTop.x() < m_right )
1049 clippedPolyObject << pointTop;
1050 if ( pointRight.y() >= m_top && pointRight.y() < m_bottom )
1051 clippedPolyObject << pointRight;
1052 if ( pointBottom.x() < m_right ) {
1053 clippedPolyObject << pointBottom;
1054 } else {
1055 clippedPolyObject << QPointF( m_right, m_bottom );
1056 }
1057 }
1058 break;
1059
1060 case 8:
1061 if ( m_previousSector == 3 ) {
1062 QPointF pointLeft = clipLeft( m, m_previousPoint );
1063 QPointF pointBottom = clipBottom( m, m_currentPoint );
1064 QPointF pointRight = clipRight( m, m_currentPoint );
1065
1066 if ( pointLeft.y() < m_bottom ) {
1067 clippedPolyObject << pointLeft;
1068 } else {
1069 clippedPolyObject << QPointF( m_left, m_bottom );
1070 }
1071 if ( pointBottom.x() > m_left && pointBottom.x() <= m_right )
1072 clippedPolyObject << pointBottom;
1073 if ( pointRight.y() < m_bottom )
1074 clippedPolyObject << pointRight;
1075 }
1076 else if ( m_previousSector == 1 ) {
1077 QPointF pointTop = clipTop( m, m_previousPoint );
1078 QPointF pointRight = clipRight( m, m_currentPoint );
1079 QPointF pointBottom = clipBottom( m, m_currentPoint );
1080
1081 if ( pointTop.x() < m_right ) {
1082 clippedPolyObject << pointTop;
1083 } else {
1084 clippedPolyObject << QPointF( m_right, m_top );
1085 }
1086 if ( pointRight.y() > m_top && pointRight.y() <= m_bottom )
1087 clippedPolyObject << pointRight;
1088 if ( pointBottom.x() < m_right )
1089 clippedPolyObject << pointBottom;
1090 }
1091 else if ( m_previousSector == 0 ) {
1092 QPointF pointTop = clipTop( m, m_currentPoint );
1093 QPointF pointLeft = clipLeft( m, m_currentPoint );
1094 QPointF pointBottom = clipBottom( m, m_previousPoint );
1095 QPointF pointRight = clipRight( m, m_previousPoint );
1096
1097 if ( pointTop.x() > m_left && pointTop.x() < m_right )
1098 clippedPolyObject << pointTop;
1099 if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
1100 clippedPolyObject << pointLeft;
1101 if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
1102 clippedPolyObject << pointBottom;
1103 if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
1104 clippedPolyObject << pointRight;
1105
1106 if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom )
1107 clippedPolyObject << QPointF( m_left, m_bottom );
1108 if ( pointTop.x() >= m_right && pointRight.y() <= m_top )
1109 clippedPolyObject << QPointF( m_right, m_top );
1110 }
1111
1112 clippedPolyObject << QPointF( m_right, m_bottom );
1113 break;
1114
1115 default:
1116 break;
1117 }
1118}
1119
1120void ClipPainterPrivate::clipOnceCorner( QPolygonF & clippedPolyObject,
1121 QVector<QPolygonF> & clippedPolyObjects,
1122 const QPointF& corner,
1123 const QPointF& point,
1124 bool isClosed ) const
1125{
1126 Q_UNUSED( clippedPolyObjects )
1127 Q_UNUSED( isClosed )
1128
1129 if ( m_currentSector == 4) {
1130 // Appearing
1131 clippedPolyObject << corner;
1132 clippedPolyObject << point;
1133 } else {
1134 // Disappearing
1135 clippedPolyObject << point;
1136 clippedPolyObject << corner;
1137 }
1138}
1139
1140void ClipPainterPrivate::clipOnceEdge( QPolygonF & clippedPolyObject,
1141 QVector<QPolygonF> & clippedPolyObjects,
1142 const QPointF& point,
1143 bool isClosed ) const
1144{
1145 if ( m_currentSector == 4) {
1146 // Appearing
1147 if ( !isClosed ) {
1148 clippedPolyObject = QPolygonF();
1149 }
1150 clippedPolyObject << point;
1151 }
1152 else {
1153 // Disappearing
1154 clippedPolyObject << point;
1155 if ( !isClosed ) {
1156 clippedPolyObjects << clippedPolyObject;
1157 }
1158 }
1159}
1160
1161void ClipPainterPrivate::clipOnce( QPolygonF & clippedPolyObject,
1162 QVector<QPolygonF> & clippedPolyObjects,
1163 bool isClosed )
1164{
1165 // Interpolate border points (linear interpolation)
1166 QPointF point;
1167
1168 // Calculating the slope.
1169 qreal m = _m( m_previousPoint, m_currentPoint );
1170
1171 // Calculate in which sector the end of the line is located that is off screen
1172 int offscreenpos = ( m_currentSector == 4 ) ? m_previousSector : m_currentSector;
1173
1174 // "Rise over run" for all possible situations .
1175 switch ( offscreenpos ) {
1176 case 0: // topleft
1177 point = clipTop( m, m_previousPoint );
1178 if ( point.x() < m_left ) {
1179 point = clipLeft( m, point );
1180 }
1181 clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_top ), point, isClosed );
1182 break;
1183 case 1: // top
1184 point = clipTop( m, m_previousPoint );
1185 clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1186 break;
1187 case 2: // topright
1188 point = clipTop( m, m_previousPoint );
1189 if ( point.x() > m_right ) {
1190 point = clipRight( m, point );
1191 }
1192 clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_top ), point, isClosed );
1193 break;
1194 case 3: // left
1195 point = clipLeft( m, m_previousPoint );
1196 clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1197 break;
1198 case 5: // right
1199 point = clipRight( m, m_previousPoint );
1200 clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1201 break;
1202 case 6: // bottomleft
1203 point = clipBottom( m, m_previousPoint );
1204 if ( point.x() < m_left ) {
1205 point = clipLeft( m, point );
1206 }
1207 clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_bottom ), point, isClosed );
1208 break;
1209 case 7: // bottom
1210 point = clipBottom( m, m_previousPoint );
1211 clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1212 break;
1213 case 8: // bottomright
1214 point = clipBottom( m, m_previousPoint );
1215 if ( point.x() > m_right ) {
1216 point = clipRight( m, point );
1217 }
1218 clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_bottom ), point, isClosed );
1219 break;
1220 default:
1221 break;
1222 }
1223
1224}
1225
1226void ClipPainter::setDebugPolygonsLevel( int level ) {
1227 d->m_debugPolygonsLevel = level;
1228}
1229
1230void ClipPainter::setDebugBatchRender( bool enabled ) {
1231 d->m_debugBatchRender = enabled;
1232}
1233
1234
1235void ClipPainterPrivate::debugDrawNodes( const QPolygonF & polygon )
1236{
1237
1238 q->save();
1240
1241 q->setPen( Qt::red );
1242 q->setBrush(QBrush("#40FF0000"));
1243
1244 const QVector<QPointF>::const_iterator itStartPoint = polygon.constBegin();
1245 const QVector<QPointF>::const_iterator itEndPoint = polygon.constEnd();
1246 QVector<QPointF>::const_iterator itPoint = itStartPoint;
1247
1248 int i = 0;
1249
1250 for (; itPoint != itEndPoint; ++itPoint ) {
1251
1252 ++i;
1253
1254 if ( itPoint == itStartPoint || itPoint == itStartPoint + 1 || itPoint == itStartPoint + 2 ) {
1255 q->setPen( Qt::darkGreen );
1256 q->setBrush(QBrush("#4000FF00"));
1257 if ( itPoint == itStartPoint ) {
1258 q->drawRect( itPoint->x() - 6.0, itPoint->y() - 6.0 , 12.0, 12.0 );
1259 }
1260 else if ( itPoint == itStartPoint + 1 ) {
1261 q->drawRect( itPoint->x() - 4.0, itPoint->y() - 4.0 , 8.0, 8.0 );
1262 }
1263 else {
1264 q->drawRect( itPoint->x() - 2.0, itPoint->y() - 2.0 , 4.0, 4.0 );
1265 }
1266 q->setPen( Qt::red );
1267 q->setBrush(QBrush("#40FF0000"));
1268 }
1269 else if ( itPoint == itEndPoint - 1 || itPoint == itEndPoint - 2 || itPoint == itEndPoint - 3 ) {
1270 q->setPen( Qt::blue );
1271 q->setBrush(QBrush("#400000FF"));
1272 if ( itPoint == itEndPoint - 3 ) {
1273 q->drawRect( itPoint->x() - 6.0, itPoint->y() - 6.0 , 12.0, 12.0 );
1274 }
1275 else if ( itPoint == itEndPoint - 2 ) {
1276 q->drawRect( itPoint->x() - 4.0, itPoint->y() - 4.0 , 8.0, 8.0 );
1277 }
1278 else {
1279 q->drawRect( itPoint->x() - 2.0, itPoint->y() - 2.0 , 4.0, 4.0 );
1280 }
1281 q->setPen( Qt::red );
1282 q->setBrush(QBrush("#400000FF"));
1283 }
1284 else {
1285 q->drawRect( itPoint->x() - 4, itPoint->y() - 4 , 8.0, 8.0 );
1286 }
1287 if (m_debugPolygonsLevel == 2) {
1288 q->setFont(QFont(QStringLiteral("Sans Serif"), 7));
1289 q->setPen("black");
1290 q->setBrush(Qt::transparent);
1291 q->drawText(itPoint->x() + 6.0, itPoint->y() + (15 - (i * 5) % 30) , QString::number(i));
1292 }
1293 }
1294 q->restore();
1295}
Q_SCRIPTABLE Q_NOREPLY void start()
QStringView level(QStringView ifopt)
const QList< QKeySequence > & end()
Binds a QML item to a specific geodetic location in screen coordinates.
const QColor & color() const const
void setColor(Qt::GlobalColor color)
int alpha() const const
void setAlpha(int alpha)
bool testFlag(Enum flag) const const
const_reference at(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
T & first()
bool isEmpty() const const
T & last()
qsizetype size() const const
int height() const const
int width() const const
const QBrush & brush() const const
QPaintDevice * device() const const
void drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
void drawPolyline(const QPoint *points, int pointCount)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
const QPen & pen() const const
void restore()
void save()
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
QRect viewport() const const
QColor color() const const
void setColor(const QColor &color)
qreal widthF() const const
qreal x() const const
qreal y() const const
int height() const const
int width() const const
QString number(double n, char format, int precision)
FillRule
GlobalColor
PenStyle
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.