Marble

ClipPainter.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <[email protected]>
5 //
6 
7 
8 #include "ClipPainter.h"
9 
10 #include <cmath>
11 
12 #include "MarbleDebug.h"
13 
14 
15 namespace Marble
16 {
17 
18 class 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 
95 using namespace Marble;
96 
97 // #define MARBLE_DEBUG
98 
99 ClipPainter::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 
109 ClipPainter::ClipPainter()
110  : d( new ClipPainterPrivate( this ) )
111 {
112 }
113 
114 
115 ClipPainter::~ClipPainter()
116 {
117  delete d;
118 }
119 
120 
121 void ClipPainter::setScreenClip(bool enable)
122 {
123  d->m_doClip = enable;
124 }
125 
126 
127 bool ClipPainter::hasScreenClip() const
128 {
129  return d->m_doClip;
130 }
131 
132 
133 void 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) {
146  QBrush brush = QPainter::brush();
147  QBrush originalBrush = brush;
148  QColor color = brush.color();
149  color.setAlpha(color.alpha()*0.75);
150  brush.setColor(color);
151  QPainter::setBrush(brush);
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) {
167  QBrush brush = QPainter::brush();
168  QBrush originalBrush = brush;
169  QColor color = brush.color();
170  color.setAlpha(color.alpha()*0.75);
171  brush.setColor(color);
172  QPainter::setBrush(brush);
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 
186 void 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) {
197  QPen pen = QPainter::pen();
198  QPen originalPen = pen;
199  QColor color = pen.color();
200  color.setAlpha(color.alpha()*0.75);
201  pen.setColor(color);
202  QPainter::setPen(pen);
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) {
218  QPen pen = QPainter::pen();
219  QPen originalPen = pen;
220  QColor color = pen.color();
221  color.setAlpha(color.alpha()*0.75);
222  pen.setColor(color);
223  QPainter::setPen(pen);
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 
237 void 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) {
248  QPen pen = QPainter::pen();
249  QPen originalPen = pen;
250  QColor color = pen.color();
251  color.setAlpha(color.alpha()*0.75);
252  pen.setColor(color);
253  QPainter::setPen(pen);
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) {
268  QPen pen = QPainter::pen();
269  QPen originalPen = pen;
270  QColor color = pen.color();
271  color.setAlpha(color.alpha()*0.75);
272  pen.setColor(color);
273  QPainter::setPen(pen);
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 
289 void ClipPainter::labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
290  LabelPositionFlags labelPositionFlags) const
291 {
292  d->labelPosition(polygon, labelNodes, labelPositionFlags);
293 }
294 
295 void ClipPainter::setPen(const QColor &color) {
296  if (d->m_debugBatchRender) {
297  qDebug() << Q_FUNC_INFO;
298  }
299  setPen(QPen(color));
300 }
301 
302 void ClipPainter::setPen(Qt::PenStyle style) {
303  if (d->m_debugBatchRender) {
304  qDebug() << Q_FUNC_INFO;
305  }
306  setPen(QPen(style));
307 }
308 
309 void ClipPainter::setPen(const QPen & pen) {
310  if (d->m_debugBatchRender) {
311  qDebug() << Q_FUNC_INFO;
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() << "++";
322  QPainter::setPen(pen);
323  }
324  }
325  else {
326  QPainter::setPen(pen);
327  }
328 }
329 
330 void ClipPainter::setBrush(const QBrush & brush) {
331  if (d->m_debugBatchRender) {
332  qDebug() << Q_FUNC_INFO;
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() << "++";
342  QPainter::setBrush(brush);
343  }
344  }
345  else {
346  QPainter::setBrush(brush);
347  }
348 }
349 
350 void 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 
403 bool 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 
409 QPointF 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() << Q_FUNC_INFO << "Previous and current node position are allowed!";
447 
448  return QPointF( -1.0, -1.0 );
449 }
450 
451 ClipPainterPrivate::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 
470 void 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 
480 qreal 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 
494 QPointF ClipPainterPrivate::clipTop( qreal m, const QPointF & point ) const
495 {
496  return QPointF( ( m_top - point.y() ) / m + point.x(), m_top );
497 }
498 
499 QPointF ClipPainterPrivate::clipLeft( qreal m, const QPointF & point ) const
500 {
501  return QPointF( m_left, ( m_left - point.x() ) * m + point.y() );
502 }
503 
504 QPointF ClipPainterPrivate::clipBottom( qreal m, const QPointF & point ) const
505 {
506  return QPointF( ( m_bottom - point.y() ) / m + point.x(), m_bottom );
507 }
508 
509 QPointF ClipPainterPrivate::clipRight( qreal m, const QPointF & point ) const
510 {
511  return QPointF( m_right, ( m_right - point.x() ) * m + point.y() );
512 }
513 
514 int 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 
546 void 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 
638 void 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 
1120 void 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 
1140 void 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 
1161 void 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 
1226 void ClipPainter::setDebugPolygonsLevel( int level ) {
1227  d->m_debugPolygonsLevel = level;
1228 }
1229 
1230 void ClipPainter::setDebugBatchRender( bool enabled ) {
1231  d->m_debugBatchRender = enabled;
1232 }
1233 
1234 
1235 void ClipPainterPrivate::debugDrawNodes( const QPolygonF & polygon )
1236 {
1237 
1238  q->save();
1239  q->setRenderHint( QPainter::Antialiasing, false );
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 }
const QColor & color() const const
bool isEmpty() const const
void setPen(const QColor &color)
QString number(int n, int base)
T & last()
bool testFlag(Enum flag) const const
QStringView level(QStringView ifopt)
QVector::const_iterator constEnd() const const
const QPen & pen() const const
T & first()
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void setColor(const QColor &color)
Q_SCRIPTABLE Q_NOREPLY void start()
FillRule
const T & at(int i) const const
void setAlpha(int alpha)
int alpha() const const
Binds a QML item to a specific geodetic location in screen coordinates.
void drawPolyline(const QPointF *points, int pointCount)
const QBrush & brush() const const
void setBrush(const QBrush &brush)
qreal x() const const
qreal y() const const
void setColor(const QColor &color)
QColor color() const const
int size() const const
QVector::const_iterator constBegin() const const
PenStyle
QObject * parent() const const
const QList< QKeySequence > & end()
GlobalColor
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Oct 3 2023 04:09:47 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.