File indexing completed on 2025-01-05 03:59:15

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2009 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 //
0006 
0007 #include "ClipPainter.h"
0008 
0009 #include <cmath>
0010 
0011 #include "digikam_debug.h"
0012 
0013 namespace Marble
0014 {
0015 
0016 class ClipPainterPrivate
0017 {
0018  public:
0019     explicit ClipPainterPrivate( ClipPainter * parent );
0020 
0021     ClipPainter * q;
0022 
0023     // true if clipping is on.
0024     bool    m_doClip;
0025 
0026     // The limits
0027     qreal  m_left;
0028     qreal  m_right;
0029     qreal  m_top;
0030     qreal  m_bottom;
0031 
0032     // Used in the paint process of vectors..
0033     int     m_currentSector;
0034     int     m_previousSector;
0035 
0036     //  int m_debugNodeCount;
0037 
0038     QPointF    m_currentPoint;
0039     QPointF    m_previousPoint;
0040 
0041     inline int sector( const QPointF & point ) const;
0042 
0043     inline QPointF clipTop( qreal m, const QPointF & point ) const;
0044     inline QPointF clipLeft( qreal m, const QPointF & point ) const;
0045     inline QPointF clipBottom( qreal m, const QPointF & point ) const;
0046     inline QPointF clipRight( qreal m, const QPointF & point ) const;
0047 
0048     inline void initClipRect();
0049 
0050     inline void clipPolyObject ( const QPolygonF & sourcePolygon,
0051                                  QVector<QPolygonF> & clippedPolyObjects,
0052                                  bool isClosed );
0053 
0054     inline void clipMultiple( QPolygonF & clippedPolyObject,
0055                               QVector<QPolygonF> & clippedPolyObjects,
0056                               bool isClosed );
0057     inline void clipOnce( QPolygonF & clippedPolyObject,
0058                               QVector<QPolygonF> & clippedPolyObjects,
0059                               bool isClosed );
0060     inline void clipOnceCorner( QPolygonF & clippedPolyObject,
0061                                 QVector<QPolygonF> & clippedPolyObjects,
0062                                 const QPointF& corner,
0063                                 const QPointF& point,
0064                                 bool isClosed ) const;
0065     inline void clipOnceEdge(   QPolygonF & clippedPolyObject,
0066                                 QVector<QPolygonF> & clippedPolyObjects,
0067                                 const QPointF& point,
0068                                 bool isClosed ) const;
0069 
0070 
0071     void labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
0072                                 LabelPositionFlags labelPositionFlags) const;
0073 
0074     bool pointAllowsLabel(const QPointF &point) const;
0075     QPointF interpolateLabelPoint(const QPointF &previousPoint,
0076                                   const QPointF &currentPoint,
0077                                   LabelPositionFlags labelPositionFlags) const;
0078 
0079     static inline qreal _m( const QPointF & start, const QPointF & end );
0080 
0081     void debugDrawNodes( const QPolygonF & );
0082 
0083     qreal m_labelAreaMargin;
0084 
0085     int m_debugPenBatchColor;
0086     int m_debugBrushBatchColor;
0087     int m_debugPolygonsLevel;
0088     bool m_debugBatchRender;
0089 };
0090 
0091 }
0092 
0093 using namespace Marble;
0094 
0095 ClipPainter::ClipPainter(QPaintDevice * pd, bool clip)
0096     : QPainter( pd ), d( new ClipPainterPrivate( this ) )
0097 {
0098     d->initClipRect();
0099 
0100     // m_debugNodeCount = 0;
0101     d->m_doClip = clip;
0102 }
0103 
0104 
0105 ClipPainter::ClipPainter()
0106     : d( new ClipPainterPrivate( this ) )
0107 {
0108 }
0109 
0110 
0111 ClipPainter::~ClipPainter()
0112 {
0113     delete d;
0114 }
0115 
0116 
0117 void ClipPainter::setScreenClip(bool enable)
0118 {
0119     d->m_doClip = enable;
0120 }
0121 
0122 
0123 bool ClipPainter::hasScreenClip() const
0124 {
0125     return d->m_doClip;
0126 }
0127 
0128 
0129 void ClipPainter::drawPolygon ( const QPolygonF & polygon,
0130                                 Qt::FillRule fillRule )
0131 {
0132     if ( d->m_doClip ) {
0133         d->initClipRect();
0134         QVector<QPolygonF> clippedPolyObjects;
0135 
0136         d->clipPolyObject( polygon, clippedPolyObjects, true );
0137 
0138         for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
0139             if ( clippedPolyObject.size() > 2 ) {
0140                 // qCDebug(DIGIKAM_MARBLE_LOG) << "Size: " << clippedPolyObject.size();
0141                 if (d->m_debugPolygonsLevel) {
0142                     QBrush brush = QPainter::brush();
0143                     QBrush originalBrush = brush;
0144                     QColor color = brush.color();
0145                     color.setAlpha(color.alpha()*0.75);
0146                     brush.setColor(color);
0147                     QPainter::setBrush(brush);
0148 
0149                     QPainter::drawPolygon ( clippedPolyObject, fillRule );
0150 
0151                     QPainter::setBrush(originalBrush);
0152 
0153                     d->debugDrawNodes( clippedPolyObject );
0154                 }
0155                 else {
0156                     QPainter::drawPolygon ( clippedPolyObject, fillRule );
0157                 }
0158             }
0159         }
0160     }
0161     else {
0162         if (d->m_debugPolygonsLevel) {
0163             QBrush brush = QPainter::brush();
0164             QBrush originalBrush = brush;
0165             QColor color = brush.color();
0166             color.setAlpha(color.alpha()*0.75);
0167             brush.setColor(color);
0168             QPainter::setBrush(brush);
0169 
0170             QPainter::drawPolygon ( polygon, fillRule );
0171 
0172             QPainter::setBrush(originalBrush);
0173 
0174             d->debugDrawNodes( polygon );
0175         }
0176         else {
0177             QPainter::drawPolygon ( polygon, fillRule );
0178         }
0179     }
0180 }
0181 
0182 void ClipPainter::drawPolyline( const QPolygonF & polygon )
0183 {
0184     if ( d->m_doClip ) {
0185         d->initClipRect();
0186         QVector<QPolygonF> clippedPolyObjects;
0187 
0188         d->clipPolyObject( polygon, clippedPolyObjects, false );
0189 
0190         for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
0191             if ( clippedPolyObject.size() > 1 ) {
0192                 if (d->m_debugPolygonsLevel) {
0193                     QPen pen = QPainter::pen();
0194                     QPen originalPen = pen;
0195                     QColor color = pen.color();
0196                     color.setAlpha(color.alpha()*0.75);
0197                     pen.setColor(color);
0198                     QPainter::setPen(pen);
0199 
0200                     QPainter::drawPolyline ( clippedPolyObject );
0201 
0202                     QPainter::setPen(originalPen);
0203 
0204                     d->debugDrawNodes( clippedPolyObject );
0205                 }
0206                 else {
0207                     QPainter::drawPolyline ( clippedPolyObject );
0208                 }
0209             }
0210         }
0211     }
0212     else {
0213         if (d->m_debugPolygonsLevel) {
0214             QPen pen = QPainter::pen();
0215             QPen originalPen = pen;
0216             QColor color = pen.color();
0217             color.setAlpha(color.alpha()*0.75);
0218             pen.setColor(color);
0219             QPainter::setPen(pen);
0220 
0221             QPainter::drawPolyline ( polygon );
0222 
0223             QPainter::setPen(originalPen);
0224 
0225             d->debugDrawNodes( polygon );
0226         }
0227         else {
0228             QPainter::drawPolyline ( polygon );
0229         }
0230     }
0231 }
0232 
0233 void ClipPainter::drawPolyline(const QPolygonF & polygon, QVector<QPointF>& labelNodes,
0234                                LabelPositionFlags positionFlags)
0235 {
0236     if ( d->m_doClip ) {
0237         d->initClipRect();
0238         QVector<QPolygonF> clippedPolyObjects;
0239 
0240         d->clipPolyObject( polygon, clippedPolyObjects, false );
0241 
0242         for( const QPolygonF & clippedPolyObject: clippedPolyObjects ) {
0243             if (d->m_debugPolygonsLevel) {
0244                 QPen pen = QPainter::pen();
0245                 QPen originalPen = pen;
0246                 QColor color = pen.color();
0247                 color.setAlpha(color.alpha()*0.75);
0248                 pen.setColor(color);
0249                 QPainter::setPen(pen);
0250 
0251                 QPainter::drawPolyline ( clippedPolyObject );
0252 
0253                 QPainter::setPen(originalPen);
0254 
0255                 d->debugDrawNodes( clippedPolyObject );
0256             }
0257             else {
0258                 QPainter::drawPolyline ( clippedPolyObject );
0259             }
0260         }
0261     }
0262     else {
0263         if (d->m_debugPolygonsLevel) {
0264             QPen pen = QPainter::pen();
0265             QPen originalPen = pen;
0266             QColor color = pen.color();
0267             color.setAlpha(color.alpha()*0.75);
0268             pen.setColor(color);
0269             QPainter::setPen(pen);
0270 
0271             QPainter::drawPolyline ( polygon );
0272 
0273             QPainter::setPen(originalPen);
0274 
0275             d->debugDrawNodes( polygon );
0276         }
0277         else {
0278             QPainter::drawPolyline ( polygon );
0279         }
0280 
0281         d->labelPosition( polygon, labelNodes, positionFlags );
0282     }
0283 }
0284 
0285 void ClipPainter::labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
0286                                        LabelPositionFlags labelPositionFlags) const
0287 {
0288     d->labelPosition(polygon, labelNodes, labelPositionFlags);
0289 }
0290 
0291 void ClipPainter::setPen(const QColor &color) {
0292     if (d->m_debugBatchRender) {
0293         qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO;
0294     }
0295     setPen(QPen(color));
0296 }
0297 
0298 void ClipPainter::setPen(Qt::PenStyle style) {
0299     if (d->m_debugBatchRender) {
0300         qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO;
0301     }
0302     setPen(QPen(style));
0303 }
0304 
0305 void ClipPainter::setPen(const QPen & pen) {
0306     if (d->m_debugBatchRender) {
0307         qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO;
0308         if (pen != QPainter::pen()) {
0309             qCDebug(DIGIKAM_MARBLE_LOG) << "--" << pen.color()  << QPainter::pen().color() ;
0310             QPen newPen = pen;
0311             newPen.setColor((Qt::GlobalColor)(d->m_debugPenBatchColor+4));
0312             QPainter::setPen(newPen);
0313             d->m_debugPenBatchColor++;
0314             d->m_debugPenBatchColor %= 14;
0315         }
0316         else {
0317             qCDebug(DIGIKAM_MARBLE_LOG) << "++";
0318             QPainter::setPen(pen);
0319         }
0320     }
0321     else {
0322         QPainter::setPen(pen);
0323     }
0324 }
0325 
0326 void ClipPainter::setBrush(const QBrush & brush) {
0327     if (d->m_debugBatchRender) {
0328         qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO;
0329         if (brush != QPainter::brush()) {
0330             qCDebug(DIGIKAM_MARBLE_LOG) << "--" << brush.color()  << QPainter::brush().color() ;
0331             QBrush batchColor(QColor((Qt::GlobalColor)(d->m_debugBrushBatchColor)));
0332             QPainter::setBrush(batchColor);
0333             d->m_debugBrushBatchColor++;
0334             d->m_debugBrushBatchColor %= 20;
0335         }
0336         else {
0337             qCDebug(DIGIKAM_MARBLE_LOG) << "++";
0338             QPainter::setBrush(brush);
0339         }
0340     }
0341     else {
0342         QPainter::setBrush(brush);
0343     }
0344 }
0345 
0346 void ClipPainterPrivate::labelPosition(const QPolygonF &polygon, QVector<QPointF> &labelNodes,
0347                                        LabelPositionFlags labelPositionFlags) const
0348 {
0349     if ( labelPositionFlags.testFlag( LineCenter ) ) {
0350         // The Label at the center of the polyline:
0351         if ( polygon.size() > 0 ) {
0352             const int labelPosition = polygon.size() / 2; // implied: 0 <= labelPosition < polygon.size()
0353             labelNodes << polygon.at( labelPosition );
0354         }
0355     }
0356 
0357     if ( polygon.size() > 0 && labelPositionFlags.testFlag( LineStart ) ) {
0358         if ( pointAllowsLabel( polygon.first() ) ) {
0359             labelNodes << polygon.first();
0360         }
0361 
0362         // The Label at the start of the polyline:
0363         for ( int it = 1; it < polygon.size(); ++it ) {
0364             const bool currentAllowsLabel = pointAllowsLabel(polygon.at(it));
0365 
0366             if ( currentAllowsLabel ) {
0367                 // As polygon.size() > 0 it's ensured that it-1 exists.
0368                 QPointF node = interpolateLabelPoint( polygon.at( it -1 ), polygon.at( it ),
0369                                                     labelPositionFlags );
0370                 if ( node != QPointF( -1.0, -1.0 ) ) {
0371                     labelNodes << node;
0372                 }
0373                 break;
0374             }
0375         }
0376     }
0377 
0378     if ( polygon.size() > 1 && labelPositionFlags.testFlag( LineEnd ) ) {
0379         if ( pointAllowsLabel( polygon.at( polygon.size() - 1 ) ) ) {
0380             labelNodes << polygon.at( polygon.size() - 1 );
0381         }
0382 
0383         // The Label at the end of the polyline:
0384         for ( int it = polygon.size() - 2; it > 0; --it ) {
0385             const bool currentAllowsLabel = pointAllowsLabel(polygon.at(it));
0386 
0387             if ( currentAllowsLabel ) {
0388                 QPointF node = interpolateLabelPoint( polygon.at( it + 1 ), polygon.at( it ),
0389                                                     labelPositionFlags );
0390                 if ( node != QPointF( -1.0, -1.0 ) ) {
0391                     labelNodes << node;
0392                 }
0393                 break;
0394             }
0395         }
0396     }
0397 }
0398 
0399 bool ClipPainterPrivate::pointAllowsLabel(const QPointF &point) const
0400 {
0401     return point.x() > m_labelAreaMargin && point.x() < q->viewport().width() - m_labelAreaMargin
0402          && point.y() > m_labelAreaMargin && point.y() < q->viewport().height() - m_labelAreaMargin;
0403 }
0404 
0405 QPointF ClipPainterPrivate::interpolateLabelPoint(const QPointF &previousPoint,
0406                                                   const QPointF &currentPoint,
0407                                                   LabelPositionFlags labelPositionFlags) const
0408 {
0409     qreal m = _m( previousPoint, currentPoint );
0410     if ( previousPoint.x() <= m_labelAreaMargin ) {
0411         if ( labelPositionFlags.testFlag( IgnoreXMargin ) ) {
0412             return QPointF( -1.0, -1.0 );
0413         }
0414         return QPointF( m_labelAreaMargin,
0415                         previousPoint.y() + ( m_labelAreaMargin - previousPoint.x() ) * m );
0416     }
0417     else if ( previousPoint.x() >= q->viewport().width() - m_labelAreaMargin  ) {
0418         if ( labelPositionFlags.testFlag( IgnoreXMargin ) ) {
0419             return QPointF( -1.0, -1.0 );
0420         }
0421         return QPointF( q->viewport().width() - m_labelAreaMargin,
0422                         previousPoint.y() -
0423                         ( previousPoint.x() - q->viewport().width() + m_labelAreaMargin ) * m );
0424     }
0425 
0426     if ( previousPoint.y() <= m_labelAreaMargin ) {
0427         if ( labelPositionFlags.testFlag( IgnoreYMargin ) ) {
0428             return QPointF( -1.0, -1.0 );
0429         }
0430         return QPointF( previousPoint.x() + ( m_labelAreaMargin - previousPoint.y() ) / m,
0431                         m_labelAreaMargin );
0432     }
0433     else if ( previousPoint.y() >= q->viewport().height() - m_labelAreaMargin  ) {
0434         if ( labelPositionFlags.testFlag( IgnoreYMargin ) ) {
0435             return QPointF( -1.0, -1.0 );
0436         }
0437         return QPointF(   previousPoint.x() -
0438                         ( previousPoint.y() - q->viewport().height() + m_labelAreaMargin ) / m,
0439                           q->viewport().height() - m_labelAreaMargin );
0440     }
0441 
0442 //    qCDebug(DIGIKAM_MARBLE_LOG) << Q_FUNC_INFO << "Previous and current node position are allowed!";
0443 
0444     return QPointF( -1.0, -1.0 );
0445 }
0446 
0447 ClipPainterPrivate::ClipPainterPrivate( ClipPainter * parent )
0448     : m_doClip( true ),
0449       m_left(0.0),
0450       m_right(0.0),
0451       m_top(0.0),
0452       m_bottom(0.0),
0453       m_currentSector(4),
0454       m_previousSector(4),
0455       m_currentPoint(QPointF()),
0456       m_previousPoint(QPointF()),
0457       m_labelAreaMargin(10.0),
0458       m_debugPenBatchColor(0),
0459       m_debugBrushBatchColor(0),
0460       m_debugPolygonsLevel(0),
0461       m_debugBatchRender(false)
0462 {
0463     q = parent;
0464 }
0465 
0466 void ClipPainterPrivate::initClipRect ()
0467 {
0468     qreal penHalfWidth = q->pen().widthF() / 2.0 + 1.0;
0469 
0470     m_left   = -penHalfWidth;
0471     m_right  = (qreal)(q->device()->width()) + penHalfWidth;
0472     m_top    = -penHalfWidth;
0473     m_bottom = (qreal)(q->device()->height()) + penHalfWidth;
0474 }
0475 
0476 qreal ClipPainterPrivate::_m( const QPointF & start, const QPointF & end )
0477 {
0478     qreal  divisor = end.x() - start.x();
0479     if ( std::fabs( divisor ) < 0.000001 ) {
0480         // this is in screencoordinates so the difference
0481         // between 0, 0.000001 and -0.000001 isn't visible at all
0482         divisor = 0.000001;
0483     }
0484 
0485     return ( end.y() - start.y() )
0486          / divisor;
0487 }
0488 
0489 
0490 QPointF ClipPainterPrivate::clipTop( qreal m, const QPointF & point ) const
0491 {
0492     return QPointF( ( m_top - point.y() ) / m + point.x(), m_top );
0493 }
0494 
0495 QPointF ClipPainterPrivate::clipLeft( qreal m, const QPointF & point ) const
0496 {
0497     return QPointF( m_left, ( m_left - point.x() ) * m + point.y() );
0498 }
0499 
0500 QPointF ClipPainterPrivate::clipBottom( qreal m, const QPointF & point ) const
0501 {
0502     return QPointF( ( m_bottom - point.y() ) / m + point.x(), m_bottom );
0503 }
0504 
0505 QPointF ClipPainterPrivate::clipRight( qreal m, const QPointF & point ) const
0506 {
0507     return QPointF( m_right, ( m_right - point.x() ) * m + point.y() );
0508 }
0509 
0510 int ClipPainterPrivate::sector( const QPointF & point ) const
0511 {
0512     // If we think of the image borders as (infinitely long) parallel
0513     // lines then the plane is divided into 9 sectors.  Each of these
0514     // sections is identified by a unique keynumber (currentSector):
0515     //
0516     //  0 | 1 | 2
0517     //  --+---+--
0518     //  3 | 4 | 5 <- sector number "4" represents the onscreen sector / viewport
0519     //  --+---+--
0520     //  6 | 7 | 8
0521     //
0522 
0523     // Figure out the section of the current point.
0524     int xSector = 1;
0525     if ( point.x() < m_left )
0526         xSector = 0;
0527     else if ( point.x() > m_right )
0528         xSector = 2;
0529 
0530     int ySector = 3;
0531     if ( point.y() < m_top )
0532         ySector = 0;
0533     else if ( point.y() > m_bottom )
0534         ySector = 6;
0535 
0536     // By adding xSector and ySector we get a
0537     // sector number of the values shown in the ASCII-art graph above.
0538     return ySector + xSector;
0539 
0540 }
0541 
0542 void ClipPainterPrivate::clipPolyObject ( const QPolygonF & polygon,
0543                                           QVector<QPolygonF> & clippedPolyObjects,
0544                                           bool isClosed )
0545 {
0546     //  qCDebug(DIGIKAM_MARBLE_LOG) << "ClipPainter enabled." ;
0547 
0548     // Only create a new polyObject as soon as we know for sure that
0549     // the current point is on the screen.
0550     QPolygonF clippedPolyObject = QPolygonF();
0551 
0552     const QVector<QPointF>::const_iterator  itStartPoint = polygon.constBegin();
0553     const QVector<QPointF>::const_iterator  itEndPoint   = polygon.constEnd();
0554     QVector<QPointF>::const_iterator        itPoint      = itStartPoint;
0555 
0556     // We use a while loop to be able to cover linestrings as well as linear rings:
0557     // Linear rings require to tessellate the path from the last node to the first node
0558     // which isn't really convenient to achieve with a for loop ...
0559 
0560     bool processingLastNode = false;
0561 
0562     while ( itPoint != itEndPoint ) {
0563         m_currentPoint = (*itPoint);
0564         // qCDebug(DIGIKAM_MARBLE_LOG) << "m_currentPoint.x()" << m_currentPoint.x() << "m_currentPOint.y()" << m_currentPoint.y();
0565 
0566         // Figure out the sector of the current point.
0567         m_currentSector = sector( m_currentPoint );
0568 
0569         // Initialize the variables related to the previous point.
0570         if ( itPoint == itStartPoint && processingLastNode == false ) {
0571             if ( isClosed ) {
0572                 m_previousPoint = polygon.last();
0573 
0574                 // Figure out the sector of the previous point.
0575                 m_previousSector = sector( m_previousPoint );
0576             }
0577             else {
0578                 m_previousSector = m_currentSector;
0579             }
0580         }
0581 
0582         // If the current point reaches a new sector, take care of clipping.
0583         if ( m_currentSector != m_previousSector ) {
0584             if ( m_currentSector == 4 || m_previousSector == 4 ) {
0585                 // In this case the current or the previous point is visible on the
0586                 // screen but not both. Hence we only need to clip once and require
0587                 // only one interpolation for both cases.
0588 
0589                 clipOnce( clippedPolyObject, clippedPolyObjects, isClosed );
0590             }
0591             else {
0592                 // This case mostly deals with lines that reach from one
0593                 // sector that is located off screen to another one that
0594                 // is located off screen. In this situation the line
0595                 // can get clipped once, twice, or not at all.
0596                 clipMultiple( clippedPolyObject, clippedPolyObjects, isClosed );
0597             }
0598 
0599             m_previousSector = m_currentSector;
0600         }
0601 
0602         // If the current point is onscreen, just add it to our final polygon.
0603         if ( m_currentSector == 4 ) {
0604 
0605             clippedPolyObject << m_currentPoint;
0606 #ifdef MARBLE_DEBUG
0607             ++(m_debugNodeCount);
0608 #endif
0609         }
0610 
0611         m_previousPoint = m_currentPoint;
0612 
0613         // Now let's handle the case where we have a (closed) polygon and where the
0614         // last point of the polyline is outside the viewport and the start point
0615         // is inside the viewport. This needs special treatment
0616         if ( processingLastNode ) {
0617             break;
0618         }
0619         ++itPoint;
0620 
0621         if ( itPoint == itEndPoint  && isClosed ) {
0622             itPoint = itStartPoint;
0623             processingLastNode = true;
0624         }
0625     }
0626 
0627     // Only add the pointer if there's node data available.
0628     if ( !clippedPolyObject.isEmpty() ) {
0629         clippedPolyObjects << clippedPolyObject;
0630     }
0631 }
0632 
0633 
0634 void ClipPainterPrivate::clipMultiple( QPolygonF & clippedPolyObject,
0635                                        QVector<QPolygonF> & clippedPolyObjects,
0636                                        bool isClosed )
0637 {
0638     Q_UNUSED( clippedPolyObjects )
0639     Q_UNUSED( isClosed )
0640 
0641     // Take care of adding nodes in the image corners if the iterator
0642     // traverses off screen sections.
0643 
0644     qreal  m = _m( m_previousPoint, m_currentPoint );
0645 
0646     switch ( m_currentSector ) {
0647     case 0:
0648         if ( m_previousSector == 5 ) {
0649             QPointF pointRight = clipRight( m, m_previousPoint );
0650             QPointF pointTop = clipTop( m, m_currentPoint );
0651             QPointF pointLeft = clipLeft( m, m_currentPoint );
0652 
0653             if ( pointRight.y() > m_top ) {
0654                 clippedPolyObject << pointRight;
0655             } else {
0656                 clippedPolyObject << QPointF( m_right, m_top );
0657             }
0658             if ( pointTop.x() >= m_left && pointTop.x() < m_right )
0659                 clippedPolyObject << pointTop;
0660             if ( pointLeft.y() > m_top )
0661                 clippedPolyObject << pointLeft;
0662         }
0663         else if ( m_previousSector == 7 ) {
0664             QPointF pointBottom = clipBottom( m, m_previousPoint );
0665             QPointF pointTop = clipTop( m, m_currentPoint );
0666             QPointF pointLeft = clipLeft( m, m_currentPoint );
0667 
0668             if ( pointBottom.x() > m_left ) {
0669                 clippedPolyObject << pointBottom;
0670             } else {
0671                 clippedPolyObject << QPointF( m_left, m_bottom );
0672             }
0673             if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom )
0674                 clippedPolyObject << pointLeft;
0675             if ( pointTop.x() > m_left )
0676                 clippedPolyObject << pointTop;
0677         }
0678         else if ( m_previousSector == 8 ) {
0679             QPointF pointBottom = clipBottom( m, m_previousPoint );
0680             QPointF pointRight = clipRight( m, m_previousPoint );
0681             QPointF pointTop = clipTop( m, m_currentPoint );
0682             QPointF pointLeft = clipLeft( m, m_currentPoint );
0683 
0684             if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
0685                 clippedPolyObject << pointBottom;
0686             if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
0687                 clippedPolyObject << pointRight;
0688             if ( pointTop.x() > m_left && pointTop.x() < m_right )
0689                 clippedPolyObject << pointTop;
0690             if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
0691                 clippedPolyObject << pointLeft;
0692 
0693             if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom )
0694                 clippedPolyObject << QPointF( m_left, m_bottom );
0695             if ( pointTop.x() >= m_right && pointRight.y() <= m_top )
0696                 clippedPolyObject << QPointF( m_right, m_top );
0697         }
0698 
0699         clippedPolyObject << QPointF( m_left, m_top );
0700         break;
0701 
0702     case 1:
0703         if ( m_previousSector == 3 ) {
0704             QPointF pointLeft = clipLeft( m, m_previousPoint );
0705             QPointF pointTop = clipTop( m, m_currentPoint );
0706 
0707             if ( pointLeft.y() > m_top ) {
0708                 clippedPolyObject << pointLeft;
0709             } else {
0710                 clippedPolyObject << QPointF( m_left, m_top );
0711             }
0712             if ( pointTop.x() > m_left )
0713                 clippedPolyObject << pointTop;
0714         }
0715         else if ( m_previousSector == 5 ) {
0716             QPointF pointRight = clipRight( m, m_previousPoint );
0717             QPointF pointTop = clipTop( m, m_currentPoint );
0718 
0719             if ( pointRight.y() > m_top ) {
0720                 clippedPolyObject << pointRight;
0721             } else {
0722                 clippedPolyObject << QPointF( m_right, m_top );
0723             }
0724             if ( pointTop.x() < m_right )
0725                 clippedPolyObject << pointTop;
0726         }
0727         else if ( m_previousSector == 6 ) {
0728             QPointF pointBottom = clipBottom( m, m_previousPoint );
0729             QPointF pointLeft = clipLeft( m, m_previousPoint );
0730             QPointF pointTop = clipTop( m, m_currentPoint );
0731 
0732             if ( pointBottom.x() > m_left )
0733                 clippedPolyObject << pointBottom;
0734             if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom )
0735                 clippedPolyObject << pointLeft;
0736             if ( pointTop.x() > m_left ) {
0737                 clippedPolyObject << pointTop;
0738             } else {
0739                 clippedPolyObject << QPointF( m_left, m_top );
0740             }
0741         }
0742         else if ( m_previousSector == 7 ) {
0743             clippedPolyObject << clipBottom( m, m_previousPoint );
0744             clippedPolyObject << clipTop( m, m_currentPoint );
0745         }
0746         else if ( m_previousSector == 8 ) {
0747             QPointF pointBottom = clipBottom( m, m_previousPoint );
0748             QPointF pointRight = clipRight( m, m_previousPoint );
0749             QPointF pointTop = clipTop( m, m_currentPoint );
0750 
0751             if ( pointBottom.x() < m_right )
0752                 clippedPolyObject << pointBottom;
0753             if ( pointRight.y() > m_top && pointRight.y() <= m_bottom )
0754                 clippedPolyObject << pointRight;
0755             if ( pointTop.x() < m_right ) {
0756                 clippedPolyObject << pointTop;
0757             } else {
0758                 clippedPolyObject << QPointF( m_right, m_top );
0759             }
0760         }
0761         break;
0762 
0763     case 2:
0764         if ( m_previousSector == 3 ) {
0765             QPointF pointLeft = clipLeft( m, m_previousPoint );
0766             QPointF pointTop = clipTop( m, m_currentPoint );
0767             QPointF pointRight = clipRight( m, m_currentPoint );
0768 
0769             if ( pointLeft.y() > m_top ) {
0770                 clippedPolyObject << pointLeft;
0771             } else {
0772                 clippedPolyObject << QPointF( m_left, m_top );
0773             }
0774             if ( pointTop.x() > m_left && pointTop.x() <= m_right )
0775                 clippedPolyObject << pointTop;
0776             if ( pointRight.y() > m_top )
0777                 clippedPolyObject << pointRight;
0778         }
0779         else if ( m_previousSector == 7 ) {
0780             QPointF pointBottom = clipBottom( m, m_previousPoint );
0781             QPointF pointTop = clipTop( m, m_currentPoint );
0782             QPointF pointRight = clipRight( m, m_currentPoint );
0783 
0784             if ( pointBottom.x() < m_right ) {
0785                 clippedPolyObject << pointBottom;
0786             } else {
0787                 clippedPolyObject << QPointF( m_right, m_bottom );
0788             }
0789             if ( pointRight.y() >= m_top && pointRight.y() < m_bottom )
0790                 clippedPolyObject << pointRight;
0791             if ( pointTop.x() < m_right )
0792                 clippedPolyObject << pointTop;
0793         }
0794         else if ( m_previousSector == 6 ) {
0795             QPointF pointBottom = clipBottom( m, m_previousPoint );
0796             QPointF pointLeft = clipLeft( m, m_currentPoint );
0797             QPointF pointTop = clipTop( m, m_currentPoint );
0798             QPointF pointRight = clipRight( m, m_previousPoint );
0799 
0800             if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
0801                 clippedPolyObject << pointBottom;
0802             if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
0803                 clippedPolyObject << pointLeft;
0804             if ( pointTop.x() > m_left && pointTop.x() < m_right )
0805                 clippedPolyObject << pointTop;
0806             if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
0807                 clippedPolyObject << pointRight;
0808 
0809             if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom )
0810                 clippedPolyObject << QPointF( m_right, m_bottom );
0811             if ( pointTop.x() <= m_left && pointLeft.y() <= m_top )
0812                 clippedPolyObject << QPointF( m_left, m_top );
0813         }
0814 
0815         clippedPolyObject << QPointF( m_right, m_top );
0816         break;
0817 
0818     case 3:
0819         if ( m_previousSector == 7 ) {
0820             QPointF pointBottom = clipBottom( m, m_previousPoint );
0821             QPointF pointLeft = clipLeft( m, m_currentPoint );
0822 
0823             if ( pointBottom.x() > m_left )
0824                 clippedPolyObject << pointBottom;
0825             if ( pointLeft.y() < m_bottom ) {
0826                 clippedPolyObject << pointLeft;
0827             } else {
0828                 clippedPolyObject << QPointF( m_left, m_bottom );
0829             }
0830         }
0831         else if ( m_previousSector == 1 ) {
0832             QPointF pointTop = clipTop( m, m_previousPoint );
0833             QPointF pointLeft = clipLeft( m, m_currentPoint );
0834 
0835             if ( pointTop.x() > m_left )
0836                 clippedPolyObject << pointTop;
0837             if ( pointLeft.y() > m_top ) {
0838                 clippedPolyObject << pointLeft;
0839             } else {
0840                 clippedPolyObject << QPointF( m_left, m_top );
0841             }
0842         }
0843         else if ( m_previousSector == 8 ) {
0844             QPointF pointRight = clipRight( m, m_previousPoint );
0845             QPointF pointBottom = clipBottom( m, m_previousPoint );
0846             QPointF pointLeft = clipLeft( m, m_currentPoint );
0847 
0848             if ( pointRight.y() < m_bottom )
0849                 clippedPolyObject << pointRight;
0850             if ( pointBottom.x() > m_left && pointBottom.x() <= m_right )
0851                 clippedPolyObject << pointBottom;
0852             if ( pointLeft.y() < m_bottom ) {
0853                 clippedPolyObject << pointLeft;
0854             } else {
0855                 clippedPolyObject << QPointF( m_left, m_bottom );
0856             }
0857         }
0858         else if ( m_previousSector == 5 ) {
0859             clippedPolyObject << clipRight( m, m_previousPoint );
0860             clippedPolyObject << clipLeft( m, m_currentPoint );
0861         }
0862         else if ( m_previousSector == 2 ) {
0863             QPointF pointRight = clipRight( m, m_previousPoint );
0864             QPointF pointTop = clipTop( m, m_previousPoint );
0865             QPointF pointLeft = clipLeft( m, m_currentPoint );
0866 
0867             if ( pointRight.y() > m_top )
0868                 clippedPolyObject << pointRight;
0869             if ( pointTop.x() > m_left && pointTop.x() <= m_right )
0870                 clippedPolyObject << pointTop;
0871             if ( pointLeft.y() > m_top ) {
0872                 clippedPolyObject << pointLeft;
0873             } else {
0874                 clippedPolyObject << QPointF( m_left, m_top );
0875             }
0876         }
0877         break;
0878 
0879     case 5:
0880         if ( m_previousSector == 7 ) {
0881             QPointF pointBottom = clipBottom( m, m_previousPoint );
0882             QPointF pointRight = clipRight( m, m_currentPoint );
0883 
0884             if ( pointBottom.x() < m_right )
0885                 clippedPolyObject << pointBottom;
0886             if ( pointRight.y() < m_bottom ) {
0887                 clippedPolyObject << pointRight;
0888             } else {
0889                 clippedPolyObject << QPointF( m_right, m_bottom );
0890             }
0891         }
0892         else if ( m_previousSector == 1 ) {
0893             QPointF pointTop = clipTop( m, m_previousPoint );
0894             QPointF pointRight = clipRight( m, m_currentPoint );
0895 
0896             if ( pointTop.x() < m_right )
0897                 clippedPolyObject << pointTop;
0898             if ( pointRight.y() > m_top ) {
0899                 clippedPolyObject << pointRight;
0900             } else {
0901                 clippedPolyObject << QPointF( m_right, m_top );
0902             }
0903         }
0904         else if ( m_previousSector == 6 ) {
0905             QPointF pointLeft = clipLeft( m, m_previousPoint );
0906             QPointF pointBottom = clipBottom( m, m_previousPoint );
0907             QPointF pointRight = clipRight( m, m_currentPoint );
0908 
0909             if ( pointLeft.y() < m_bottom )
0910                 clippedPolyObject << pointLeft;
0911             if ( pointBottom.x() >= m_left && pointBottom.x() < m_right )
0912                 clippedPolyObject << pointBottom;
0913             if ( pointRight.y() < m_bottom ) {
0914                 clippedPolyObject << pointRight;
0915             } else {
0916                 clippedPolyObject << QPointF( m_right, m_bottom );
0917             }
0918         }
0919         else if ( m_previousSector == 3 ) {
0920             clippedPolyObject << clipLeft( m, m_previousPoint );
0921             clippedPolyObject << clipRight( m, m_currentPoint );
0922         }
0923         else if ( m_previousSector == 0 ) {
0924             QPointF pointLeft = clipLeft( m, m_previousPoint );
0925             QPointF pointTop = clipTop( m, m_previousPoint );
0926             QPointF pointRight = clipRight( m, m_currentPoint );
0927 
0928             if ( pointLeft.y() > m_top )
0929                 clippedPolyObject << pointLeft;
0930             if ( pointTop.x() >= m_left && pointTop.x() < m_right )
0931                 clippedPolyObject << pointTop;
0932             if ( pointRight.y() > m_top ) {
0933                 clippedPolyObject << pointRight;
0934             } else {
0935                 clippedPolyObject << QPointF( m_right, m_top );
0936             }
0937         }
0938         break;
0939 
0940     case 6:
0941         if ( m_previousSector == 5 ) {
0942             QPointF pointRight = clipRight( m, m_previousPoint );
0943             QPointF pointBottom = clipBottom( m, m_currentPoint );
0944             QPointF pointLeft = clipLeft( m, m_currentPoint );
0945 
0946             if ( pointRight.y() < m_bottom ) {
0947                 clippedPolyObject << pointRight;
0948             } else {
0949                 clippedPolyObject << QPointF( m_right, m_bottom );
0950             }
0951             if ( pointBottom.x() >= m_left && pointBottom.x() < m_right )
0952                 clippedPolyObject << pointBottom;
0953             if ( pointLeft.y() < m_bottom )
0954                 clippedPolyObject << pointLeft;
0955         }
0956         else if ( m_previousSector == 1 ) {
0957             QPointF pointTop = clipTop( m, m_previousPoint );
0958             QPointF pointLeft = clipLeft( m, m_currentPoint );
0959             QPointF pointBottom = clipBottom( m, m_currentPoint );
0960 
0961             if ( pointTop.x() > m_left ) {
0962                 clippedPolyObject << pointTop;
0963             } else {
0964                 clippedPolyObject << QPointF( m_left, m_top );
0965             }
0966             if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom )
0967                 clippedPolyObject << pointLeft;
0968             if ( pointBottom.x() > m_left )
0969                 clippedPolyObject << pointBottom;
0970         }
0971         else if ( m_previousSector == 2 ) {
0972             QPointF pointTop = clipTop( m, m_currentPoint );
0973             QPointF pointRight = clipRight( m, m_previousPoint );
0974             QPointF pointBottom = clipBottom( m, m_previousPoint );
0975             QPointF pointLeft = clipLeft( m, m_currentPoint );
0976 
0977             if ( pointTop.x() > m_left && pointTop.x() < m_right )
0978                 clippedPolyObject << pointTop;
0979             if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
0980                 clippedPolyObject << pointRight;
0981             if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
0982                 clippedPolyObject << pointBottom;
0983             if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
0984                 clippedPolyObject << pointLeft;
0985 
0986             if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom )
0987                 clippedPolyObject << QPointF( m_right, m_bottom );
0988             if ( pointTop.x() <= m_left && pointLeft.y() <= m_top )
0989                 clippedPolyObject << QPointF( m_left, m_top );
0990         }
0991 
0992         clippedPolyObject << QPointF( m_left, m_bottom );
0993         break;
0994 
0995     case 7:
0996         if ( m_previousSector == 3 ) {
0997             QPointF pointLeft = clipLeft( m, m_previousPoint );
0998             QPointF pointBottom = clipBottom( m, m_currentPoint );
0999 
1000             if ( pointLeft.y() < m_bottom ) {
1001                 clippedPolyObject << pointLeft;
1002             } else {
1003                 clippedPolyObject << QPointF( m_left, m_bottom );
1004             }
1005             if ( pointBottom.x() > m_left )
1006                 clippedPolyObject << pointBottom;
1007         }
1008         else if ( m_previousSector == 5 ) {
1009             QPointF pointRight = clipRight( m, m_previousPoint );
1010             QPointF pointBottom = clipBottom( m, m_currentPoint );
1011 
1012             if ( pointRight.y() < m_bottom ) {
1013                 clippedPolyObject << pointRight;
1014             } else {
1015                 clippedPolyObject << QPointF( m_right, m_bottom );
1016             }
1017             if ( pointBottom.x() < m_right )
1018                 clippedPolyObject << pointBottom;
1019         }
1020         else if ( m_previousSector == 0 ) {
1021             QPointF pointTop = clipTop( m, m_previousPoint );
1022             QPointF pointLeft = clipLeft( m, m_previousPoint );
1023             QPointF pointBottom = clipBottom( m, m_currentPoint );
1024 
1025             if ( pointTop.x() > m_left )
1026                 clippedPolyObject << pointTop;
1027             if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom )
1028                 clippedPolyObject << pointLeft;
1029             if ( pointBottom.x() > m_left ) {
1030                 clippedPolyObject << pointBottom;
1031             } else {
1032                 clippedPolyObject << QPointF( m_left, m_bottom );
1033             }
1034         }
1035         else if ( m_previousSector == 1 ) {
1036             clippedPolyObject << clipTop( m, m_previousPoint );
1037             clippedPolyObject << clipBottom( m, m_currentPoint );
1038         }
1039         else if ( m_previousSector == 2 ) {
1040             QPointF pointTop = clipTop( m, m_previousPoint );
1041             QPointF pointRight = clipRight( m, m_previousPoint );
1042             QPointF pointBottom = clipBottom( m, m_currentPoint );
1043 
1044             if ( pointTop.x() < m_right )
1045                 clippedPolyObject << pointTop;
1046             if ( pointRight.y() >= m_top && pointRight.y() < m_bottom )
1047                 clippedPolyObject << pointRight;
1048             if ( pointBottom.x() < m_right ) {
1049                 clippedPolyObject << pointBottom;
1050             } else {
1051                 clippedPolyObject << QPointF( m_right, m_bottom );
1052             }
1053         }
1054         break;
1055 
1056     case 8:
1057         if ( m_previousSector == 3 ) {
1058             QPointF pointLeft = clipLeft( m, m_previousPoint );
1059             QPointF pointBottom = clipBottom( m, m_currentPoint );
1060             QPointF pointRight = clipRight( m, m_currentPoint );
1061 
1062             if ( pointLeft.y() < m_bottom ) {
1063                 clippedPolyObject << pointLeft;
1064             } else {
1065                 clippedPolyObject << QPointF( m_left, m_bottom );
1066             }
1067             if ( pointBottom.x() > m_left && pointBottom.x() <= m_right )
1068                 clippedPolyObject << pointBottom;
1069             if ( pointRight.y() < m_bottom )
1070                 clippedPolyObject << pointRight;
1071         }
1072         else if ( m_previousSector == 1 ) {
1073             QPointF pointTop = clipTop( m, m_previousPoint );
1074             QPointF pointRight = clipRight( m, m_currentPoint );
1075             QPointF pointBottom = clipBottom( m, m_currentPoint );
1076 
1077             if ( pointTop.x() < m_right ) {
1078                 clippedPolyObject << pointTop;
1079             } else {
1080                 clippedPolyObject << QPointF( m_right, m_top );
1081             }
1082             if ( pointRight.y() > m_top && pointRight.y() <= m_bottom )
1083                 clippedPolyObject << pointRight;
1084             if ( pointBottom.x() < m_right )
1085                 clippedPolyObject << pointBottom;
1086         }
1087         else if ( m_previousSector == 0 ) {
1088             QPointF pointTop = clipTop( m, m_currentPoint );
1089             QPointF pointLeft = clipLeft( m, m_currentPoint );
1090             QPointF pointBottom = clipBottom( m, m_previousPoint );
1091             QPointF pointRight = clipRight( m, m_previousPoint );
1092 
1093             if ( pointTop.x() > m_left && pointTop.x() < m_right )
1094                 clippedPolyObject << pointTop;
1095             if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom )
1096                 clippedPolyObject << pointLeft;
1097             if ( pointBottom.x() > m_left && pointBottom.x() < m_right )
1098                 clippedPolyObject << pointBottom;
1099             if ( pointRight.y() > m_top && pointRight.y() < m_bottom )
1100                 clippedPolyObject << pointRight;
1101 
1102             if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom )
1103                 clippedPolyObject << QPointF( m_left, m_bottom );
1104             if ( pointTop.x() >= m_right && pointRight.y() <= m_top )
1105                 clippedPolyObject << QPointF( m_right, m_top );
1106         }
1107 
1108         clippedPolyObject << QPointF( m_right, m_bottom );
1109         break;
1110 
1111     default:
1112         break;
1113     }
1114 }
1115 
1116 void ClipPainterPrivate::clipOnceCorner( QPolygonF & clippedPolyObject,
1117                                          QVector<QPolygonF> & clippedPolyObjects,
1118                                          const QPointF& corner,
1119                                          const QPointF& point,
1120                                          bool isClosed ) const
1121 {
1122     Q_UNUSED( clippedPolyObjects )
1123     Q_UNUSED( isClosed )
1124 
1125     if ( m_currentSector == 4) {
1126         // Appearing
1127         clippedPolyObject << corner;
1128         clippedPolyObject << point;
1129     } else {
1130         // Disappearing
1131         clippedPolyObject << point;
1132         clippedPolyObject << corner;
1133     }
1134 }
1135 
1136 void ClipPainterPrivate::clipOnceEdge( QPolygonF & clippedPolyObject,
1137                                        QVector<QPolygonF> & clippedPolyObjects,
1138                                        const QPointF& point,
1139                                        bool isClosed ) const
1140 {
1141     if ( m_currentSector == 4) {
1142         // Appearing
1143         if ( !isClosed ) {
1144             clippedPolyObject = QPolygonF();
1145         }
1146         clippedPolyObject << point;
1147     }
1148     else {
1149         // Disappearing
1150         clippedPolyObject << point;
1151         if ( !isClosed ) {
1152             clippedPolyObjects << clippedPolyObject;
1153         }
1154     }
1155 }
1156 
1157 void ClipPainterPrivate::clipOnce( QPolygonF & clippedPolyObject,
1158                                    QVector<QPolygonF> & clippedPolyObjects,
1159                                    bool isClosed )
1160 {
1161     //  Interpolate border points (linear interpolation)
1162     QPointF point;
1163 
1164     // Calculating the slope.
1165     qreal m = _m( m_previousPoint, m_currentPoint );
1166 
1167     // Calculate in which sector the end of the line is located that is off screen
1168     int offscreenpos = ( m_currentSector == 4 ) ? m_previousSector : m_currentSector;
1169 
1170     // "Rise over run" for all possible situations .
1171     switch ( offscreenpos ) {
1172     case 0: // topleft
1173         point = clipTop( m, m_previousPoint );
1174         if ( point.x() < m_left ) {
1175             point = clipLeft( m, point );
1176         }
1177         clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_top ), point, isClosed );
1178         break;
1179     case 1: // top
1180         point = clipTop( m, m_previousPoint );
1181         clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1182         break;
1183     case 2: // topright
1184         point = clipTop( m, m_previousPoint );
1185         if ( point.x() > m_right ) {
1186             point = clipRight( m, point );
1187         }
1188         clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_top ), point, isClosed );
1189         break;
1190     case 3: // left
1191         point = clipLeft( m, m_previousPoint );
1192         clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1193         break;
1194     case 5: // right
1195         point = clipRight( m, m_previousPoint );
1196         clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1197         break;
1198     case 6: // bottomleft
1199         point = clipBottom( m, m_previousPoint );
1200         if ( point.x() < m_left ) {
1201             point = clipLeft( m, point );
1202         }
1203         clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_left, m_bottom ), point, isClosed );
1204         break;
1205     case 7: // bottom
1206         point = clipBottom( m, m_previousPoint );
1207         clipOnceEdge( clippedPolyObject, clippedPolyObjects, point, isClosed );
1208         break;
1209     case 8: // bottomright
1210         point = clipBottom( m, m_previousPoint );
1211         if ( point.x() > m_right ) {
1212             point = clipRight( m, point );
1213         }
1214         clipOnceCorner( clippedPolyObject, clippedPolyObjects, QPointF( m_right, m_bottom ), point, isClosed );
1215         break;
1216     default:
1217         break;
1218     }
1219 
1220 }
1221 
1222 void ClipPainter::setDebugPolygonsLevel( int level ) {
1223     d->m_debugPolygonsLevel = level;
1224 }
1225 
1226 void ClipPainter::setDebugBatchRender( bool enabled ) {
1227     d->m_debugBatchRender = enabled;
1228 }
1229 
1230 
1231 void ClipPainterPrivate::debugDrawNodes( const QPolygonF & polygon )
1232 {
1233 
1234     q->save();
1235     q->setRenderHint( QPainter::Antialiasing, false );
1236 
1237     q->setPen( Qt::red );
1238     q->setBrush(QBrush("#40FF0000"));
1239 
1240     const QVector<QPointF>::const_iterator  itStartPoint = polygon.constBegin();
1241     const QVector<QPointF>::const_iterator  itEndPoint   = polygon.constEnd();
1242     QVector<QPointF>::const_iterator        itPoint      = itStartPoint;
1243 
1244     int i = 0;
1245 
1246     for (; itPoint != itEndPoint; ++itPoint ) {
1247 
1248         ++i;
1249 
1250         if ( itPoint == itStartPoint || itPoint == itStartPoint + 1 || itPoint == itStartPoint + 2 ) {
1251             q->setPen( Qt::darkGreen );
1252             q->setBrush(QBrush("#4000FF00"));
1253             if ( itPoint == itStartPoint ) {
1254                 q->drawRect( itPoint->x() - 6.0, itPoint->y() - 6.0 , 12.0, 12.0 );
1255             }
1256             else if ( itPoint == itStartPoint + 1 ) {
1257                 q->drawRect( itPoint->x() - 4.0, itPoint->y() - 4.0 , 8.0, 8.0 );
1258             }
1259             else {
1260                 q->drawRect( itPoint->x() - 2.0, itPoint->y() - 2.0 , 4.0, 4.0 );
1261             }
1262             q->setPen( Qt::red );
1263             q->setBrush(QBrush("#40FF0000"));
1264         }
1265         else if ( itPoint == itEndPoint - 1 || itPoint == itEndPoint - 2 || itPoint == itEndPoint - 3 ) {
1266             q->setPen( Qt::blue );
1267             q->setBrush(QBrush("#400000FF"));
1268             if ( itPoint == itEndPoint - 3 ) {
1269                 q->drawRect( itPoint->x() - 6.0, itPoint->y() - 6.0 , 12.0, 12.0 );
1270             }
1271             else if ( itPoint == itEndPoint - 2 ) {
1272                 q->drawRect( itPoint->x() - 4.0, itPoint->y() - 4.0 , 8.0, 8.0 );
1273             }
1274             else {
1275                 q->drawRect( itPoint->x() - 2.0, itPoint->y() - 2.0 , 4.0, 4.0 );
1276             }
1277             q->setPen( Qt::red );
1278             q->setBrush(QBrush("#400000FF"));
1279         }
1280         else {
1281             q->drawRect( itPoint->x() - 4, itPoint->y() - 4 , 8.0, 8.0 );
1282         }
1283         if (m_debugPolygonsLevel == 2) {
1284             q->setFont(QFont(QStringLiteral("Sans Serif"), 7));
1285             q->setPen("black");
1286             q->setBrush(Qt::transparent);
1287             q->drawText(itPoint->x() + 6.0, itPoint->y() + (15 - (i * 5) % 30) , QString::number(i));
1288         }
1289     }
1290     q->restore();
1291 }