BaseClipper.cpp 48.7 KB
Newer Older
1
2
3
4
5
6
7
//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
8
9
// Copyright 2006-2009 Torsten Rahn <tackat@kde.org>
// Copyright 2007      Inge Wallin  <ingwa@kde.org>
10
11
12
13
14
15
16
// Copyright 2016      David Kolozsvari <freedawson@gmail.com>
//

#include "BaseClipper.h"

#include "MarbleMath.h"

17
#include <QPolygonF>
18
#include <QDebug>
19
20
#include <QSharedPointer>

21
namespace Marble {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
22

23
24
class LinkedPoint {
public:
Dennis Nienhüser's avatar
Dennis Nienhüser committed
25
    explicit LinkedPoint(const QPointF& point, bool isEntering=false, bool isLeaving=false) : m_point(point),
26
27
28
29
30
        m_isEntering(isEntering), m_isLeaving(isLeaving),
        m_nextBasePolygonPoint(nullptr), m_nextClipPolygonPoint(nullptr),
        m_processed(false)
    {}

Dennis Nienhüser's avatar
Dennis Nienhüser committed
31
32
33
34
35
36
    void clear()
    {
        m_nextBasePolygonPoint.clear();
        m_nextClipPolygonPoint.clear();
    }

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    inline bool isEntering() const
    {
        return m_isEntering;
    }

    inline bool isLeaving() const
    {
        return m_isLeaving;
    }

    inline bool isProcessed() const
    {
        return m_processed;
    }

    inline const QPointF& point() const
    {
        return m_point;
    }

    inline const QSharedPointer<LinkedPoint>& nextClipPolygonPoint() const
    {
        return m_nextClipPolygonPoint;
    }

    inline const QSharedPointer<LinkedPoint>& nextBasePolygonPoint() const
    {
        return m_nextBasePolygonPoint;
    }

    inline void setNextClipPolygonPoint(const QSharedPointer<LinkedPoint>& nextPoint)
    {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
69
        m_nextClipPolygonPoint = nextPoint;
70
71
72
73
    }

    inline void setNextBasePolygonPoint(const QSharedPointer<LinkedPoint>& nextPoint)
    {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
74
        m_nextBasePolygonPoint = nextPoint;
75
76
77
78
    }

    inline void setProcessed(bool processed)
    {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
79
        m_processed = processed;
80
81
82
83
84
85
86
87
88
89
90
91
92
    }

private:

    QPointF m_point;
    bool m_isEntering;
    bool m_isLeaving;

    QSharedPointer<LinkedPoint> m_nextBasePolygonPoint;
    QSharedPointer<LinkedPoint> m_nextClipPolygonPoint;

    bool m_processed;
};
93
94
95
96
97
98

BaseClipper::BaseClipper() :
    m_left(0.0),
    m_right(0.0),
    m_top(0.0),
    m_bottom(0.0),
99
100
101
102
103
    m_topLeft(QPointF()),
    m_topRight(QPointF()),
    m_bottomRight(QPointF()),
    m_bottomLeft(QPointF()),
    m_viewport(QPolygonF()),
104
105
106
    m_currentSector(4),
    m_previousSector(4),
    m_currentPoint(QPointF()),
107
108
    m_previousPoint(QPointF()),
    m_clippedTwice(false)
109
110
111
112
113
114
115
116
117
118
119
{

}

qreal BaseClipper::tileX2lon( unsigned int x, unsigned int maxTileX )
{
    return ( (2*M_PI * x) / maxTileX - M_PI );
}

qreal BaseClipper::tileY2lat( unsigned int y, unsigned int maxTileY )
{
Torsten Rahn's avatar
Torsten Rahn committed
120
    return gd(M_PI * (1.0 - (2.0 * y) / maxTileY));
121
122
123
124
125
}




126
void BaseClipper::initClipRect (const GeoDataLatLonBox &clippingBox, int pointsToAddAtEdges)
127
128
129
130
131
132
133
134
135
136
{
    m_left   = clippingBox.west();
    m_right  = clippingBox.east();

    // Had to flip the 'Y' axis, because the origo of the coordinate system in which the
    // geographics coordinates are is based in the bottom left corner, while the
    // screencoordinatas on which this clipper operated are in an upper left corner based origo.

    m_top    = -clippingBox.north();
    m_bottom = -clippingBox.south();
137
138
139
140
141
142

    m_topLeft = QPointF(m_left, m_top);
    m_topRight = QPointF(m_right, m_top);
    m_bottomRight = QPointF(m_right, m_bottom);
    m_bottomLeft = QPointF(m_left, m_bottom);

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    qreal x, y;
    qreal deltaX = fabs(m_right - m_left) / (pointsToAddAtEdges + 1);
    qreal deltaY = fabs(m_bottom - m_top) / (pointsToAddAtEdges + 1);

    m_topEdge.clear();
    x = m_left;
    for(int i = 0; i < pointsToAddAtEdges; ++i) {
        x += deltaX;
        m_topEdge << QPointF(x, m_top);
    }

    m_rightEdge.clear();
    y = m_top;
    for(int i = 0; i < pointsToAddAtEdges; ++i) {
        y += deltaY;
        m_rightEdge << QPointF(m_right, y);
    }

    m_bottomEdge.clear();
    x = m_right;
    for(int i = 0; i < pointsToAddAtEdges; ++i) {
        x -= deltaX;
        m_bottomEdge << QPointF(x, m_bottom);
    }

    m_leftEdge.clear();
    y = m_bottom;
    for(int i = 0; i < pointsToAddAtEdges; ++i) {
        y -= deltaY;
        m_leftEdge << QPointF(m_left, y);
    }

175
176
177
    m_viewport.clear();
    m_viewport << m_topLeft << m_topRight << m_bottomRight << m_bottomLeft;
    m_viewport.isClosed();
178
179
180
181
182
183
}

qreal BaseClipper::_m( const QPointF & start, const QPointF & end )
{
    qreal  divisor = end.x() - start.x();

184
185
    // Had to add more zeros, because what was acceptable in screen coordinates
    // could become meters or hundreds of meters in geographic coordinates.
186
187
188
189
190
    if ( std::fabs( divisor ) < 0.00000000000000001 ) {
        divisor = 0.00000000000000001 * (divisor < 0 ? -1 : 1);
    }

    return ( end.y() - start.y() )
191
            / divisor;
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
}


QPointF BaseClipper::clipTop( qreal m, const QPointF & point ) const
{
    return QPointF( ( m_top - point.y() ) / m + point.x(), m_top );
}

QPointF BaseClipper::clipLeft( qreal m, const QPointF & point ) const
{
    return QPointF( m_left, ( m_left - point.x() ) * m + point.y() );
}

QPointF BaseClipper::clipBottom( qreal m, const QPointF & point ) const
{
    return QPointF( ( m_bottom - point.y() ) / m + point.x(), m_bottom );
}

QPointF BaseClipper::clipRight( qreal m, const QPointF & point ) const
{
    return QPointF( m_right, ( m_right - point.x() ) * m + point.y() );
}

int BaseClipper::sector( const QPointF & point ) const
{
    // If we think of the image borders as (infinitely long) parallel
    // lines then the plane is divided into 9 sectors.  Each of these
    // sections is identified by a unique keynumber (currentSector):
    //
    //  0 | 1 | 2
    //  --+---+--
    //  3 | 4 | 5 <- sector number "4" represents the onscreen sector / viewport
    //  --+---+--
    //  6 | 7 | 8
    //

    // Figure out the section of the current point.
    int xSector = 1;
    if ( point.x() < m_left )
        xSector = 0;
    else if ( point.x() > m_right )
        xSector = 2;

    int ySector = 3;
    if ( point.y() < m_top )
        ySector = 0;
    else if ( point.y() > m_bottom )
        ySector = 6;

    // By adding xSector and ySector we get a
    // sector number of the values shown in the ASCII-art graph above.
    return ySector + xSector;
}

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// Determines that the point on which border or corner is exactly on, 4 otherwise.
int BaseClipper::borderSector( const QPointF & point ) const
{
    if(point.x() == m_left) {
        return 3;
    } else if (point.x() == m_right) {
        return 5;
    } else if (point.y() == m_top) {
        return 1;
    } else if (point.y() == m_bottom) {
        return 7;
    } else {
        return sector(point);
    }
}

bool BaseClipper::isCornerPoint (const QPointF & point) const {
    return point == m_topLeft || point == m_topRight ||
            point == m_bottomRight || point == m_bottomLeft;
}

267
268
269
270
void BaseClipper::clipPolyObject ( const QPolygonF & polygon,
                                   QVector<QPolygonF> & clippedPolyObjects,
                                   bool isClosed )
{
Dennis Nienhüser's avatar
Dennis Nienhüser committed
271
272
273
274
275
276
277
278
    QVector<QSharedPointer<LinkedPoint>> basePolygon;
    QVector<QSharedPointer<LinkedPoint>> clipPolygon;
    QVector<QSharedPointer<LinkedPoint>> intersections;

    QVector<QSharedPointer<LinkedPoint>> intersectionsTop;
    QVector<QSharedPointer<LinkedPoint>> intersectionsRight;
    QVector<QSharedPointer<LinkedPoint>> intersectionsBottom;
    QVector<QSharedPointer<LinkedPoint>> intersectionsLeft;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

    auto appendToIntersectionKind = [&](QSharedPointer<LinkedPoint>& intersection) {
        switch(borderSector(intersection->point())) {
        case 1:
            intersectionsTop << intersection;
            break;
        case 3:
            intersectionsLeft << intersection;
            break;
        case 5:
            intersectionsRight << intersection;
            break;
        case 7:
            intersectionsBottom << intersection;
            break;
        default: break;
        }
    };

    bool intersectionAdded = false;

300
301
302
303
304
305
306
307
308
309
310
311
312
313
    // Only create a new polyObject as soon as we know for sure that
    // the current point is on the screen.
    QPolygonF clippedPolyObject = QPolygonF();

    const QVector<QPointF>::const_iterator  itStartPoint = polygon.constBegin();
    const QVector<QPointF>::const_iterator  itEndPoint   = polygon.constEnd();
    QVector<QPointF>::const_iterator        itPoint      = itStartPoint;

    // We use a while loop to be able to cover linestrings as well as linear rings:
    // Linear rings require to tessellate the path from the last node to the first node
    // which isn't really convenient to achieve with a for loop ...

    bool processingLastNode = false;

314
    // qDebug() << "\nNew polygon, size:" << polygon.size();
315

316
317
    while ( itPoint != itEndPoint ) {
        m_currentPoint = (*itPoint);
318
        // mDebug() << "m_currentPoint.x()" << m_currentPoint.x() << "m_currentPOint.y()" << m_currentPoint.y();
319
320
321
322
323
324
325
326
327

        // Figure out the sector of the current point.
        m_currentSector = sector( m_currentPoint );

        // Initialize the variables related to the previous point.
        if ( itPoint == itStartPoint && processingLastNode == false ) {
            if ( isClosed ) {
                m_previousPoint = polygon.last();

328
329
330
                QSharedPointer<LinkedPoint> firstPoint = QSharedPointer<LinkedPoint>(new LinkedPoint(m_currentPoint));
                basePolygon << firstPoint;

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
                // Figure out the sector of the previous point.
                m_previousSector = sector( m_previousPoint );
            }
            else {
                m_previousSector = m_currentSector;
            }
        }

        // If the current point reaches a new sector, take care of clipping.
        if ( m_currentSector != m_previousSector ) {
            if ( m_currentSector == 4 || m_previousSector == 4 ) {
                // In this case the current or the previous point is visible on the
                // screen but not both. Hence we only need to clip once and require
                // only one interpolation for both cases.

                clipOnce( clippedPolyObject, clippedPolyObjects, isClosed );
347
348
349
350
351

                if(isClosed) {

                    if(!clippedPolyObject.isEmpty()) {

352
                        if(isCornerPoint(clippedPolyObject.last()) && clippedPolyObject.size() > 1) {
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
                            clippedPolyObject.removeLast();
                        }

                        QSharedPointer<LinkedPoint> intersection =
                                QSharedPointer<LinkedPoint>(new LinkedPoint(clippedPolyObject.last(),
                                                                            m_currentSector == 4,
                                                                            m_previousSector == 4));

                        intersections << intersection;
                        basePolygon.last()->setNextBasePolygonPoint(intersection);

                        QSharedPointer<LinkedPoint> nextPoint = QSharedPointer<LinkedPoint>(new LinkedPoint(m_currentPoint));
                        basePolygon << nextPoint;
                        intersections.last()->setNextBasePolygonPoint(nextPoint);

                        appendToIntersectionKind(intersection);

                        intersectionAdded = true;
                    }
                }
            } else {
374
375
376
377
                // This case mostly deals with lines that reach from one
                // sector that is located off screen to another one that
                // is located off screen. In this situation the line
                // can get clipped once, twice, or not at all.
378
                m_clippedTwice = false;
379
                clipMultiple( clippedPolyObject, clippedPolyObjects, isClosed );
380
381

                if(isClosed && m_clippedTwice) {
382
                    // qDebug() << "Clipped twice";
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
                    QPointF firstAddedPoint = clippedPolyObject.at(clippedPolyObject.size()-2);
                    QPointF secondAddedPoint = clippedPolyObject.last();

                    int firstAddedPointSector = borderSector(firstAddedPoint);
                    int secondAddedPointSector = borderSector(secondAddedPoint);

                    QSharedPointer<LinkedPoint> intersectionFirst = QSharedPointer<LinkedPoint>(new LinkedPoint(firstAddedPoint, firstAddedPointSector == m_previousSector, firstAddedPointSector == m_currentSector));
                    intersections << intersectionFirst;
                    QSharedPointer<LinkedPoint> intersectionSecond = QSharedPointer<LinkedPoint>(new LinkedPoint(secondAddedPoint, secondAddedPointSector == m_previousSector, secondAddedPointSector == m_currentSector));
                    intersections << intersectionSecond;

                    basePolygon.last()->setNextBasePolygonPoint(intersectionFirst);
                    intersectionFirst->setNextBasePolygonPoint(intersectionSecond);
                    QSharedPointer<LinkedPoint> nextPoint = QSharedPointer<LinkedPoint>(new LinkedPoint(m_currentPoint));
                    basePolygon << nextPoint;
                    intersectionSecond->setNextBasePolygonPoint(basePolygon.last());

                    appendToIntersectionKind(intersectionFirst);

                    appendToIntersectionKind(intersectionSecond);

                    intersectionAdded = true;
                }
406
407
408
409
410
            }

            m_previousSector = m_currentSector;
        }

411
412
413
414
415
416
417
418
419
420
        if (isClosed) {
            if(!intersectionAdded) {
                QSharedPointer<LinkedPoint> nextPoint = QSharedPointer<LinkedPoint>(new LinkedPoint(m_currentPoint));
                if(!basePolygon.isEmpty()) {
                    basePolygon.last()->setNextBasePolygonPoint(nextPoint);
                }
                basePolygon << nextPoint;
            } else {
                intersectionAdded = false;
            }
421
422
423
        }

        m_previousPoint = m_currentPoint;
424
425
426
        if(m_currentSector == 4) {
            clippedPolyObject << m_currentPoint;
        }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
        // Now let's handle the case where we have a (closed) polygon and where the
        // last point of the polyline is outside the viewport and the start point
        // is inside the viewport. This needs special treatment
        if ( processingLastNode ) {
            break;
        }
        ++itPoint;

        if ( itPoint == itEndPoint  && isClosed ) {
            itPoint = itStartPoint;
            processingLastNode = true;
        }
    }

441
442
443
444
445
    if(isClosed && !basePolygon.isEmpty()) {
        basePolygon.last()->setNextBasePolygonPoint(basePolygon.first());

        if(!intersections.isEmpty()) {

Dennis Nienhüser's avatar
Dennis Nienhüser committed
446
447
448
449
450
            //            qDebug() << "intersections count:" << intersections.size();
            //            qDebug() << "intersectionsTop count:" << intersectionsTop.size();
            //            qDebug() << "intersectionsRight count:" << intersectionsRight.size();
            //            qDebug() << "intersectionsBottom count:" << intersectionsBottom.size();
            //            qDebug() << "intersectionsLeft count:" << intersectionsLeft.size();
451
452
453
454

            clippedPolyObjects.clear();
            clippedPolyObject = QPolygonF();

455
456
457
            for(const auto& point : m_topEdge) {
                intersectionsTop << QSharedPointer<LinkedPoint>(new LinkedPoint(point));
            }
458
            std::sort(intersectionsTop.begin(), intersectionsTop.end(), [](const QSharedPointer<LinkedPoint>& A, const QSharedPointer<LinkedPoint>& B) {
459
460
461
                return A->point().x() < B->point().x();
            });

462
463
464
            for(const auto& point : m_rightEdge) {
                intersectionsRight << QSharedPointer<LinkedPoint>(new LinkedPoint(point));
            }
465
            std::sort(intersectionsRight.begin(), intersectionsRight.end(), [](const QSharedPointer<LinkedPoint>& A, const QSharedPointer<LinkedPoint>& B) {
466
467
468
                return A->point().y() < B->point().y();
            });

469
470
471
            for(const auto& point : m_bottomEdge) {
                intersectionsBottom << QSharedPointer<LinkedPoint>(new LinkedPoint(point));
            }
472
            std::sort(intersectionsBottom.begin(), intersectionsBottom.end(), [](const QSharedPointer<LinkedPoint>& A, const QSharedPointer<LinkedPoint>& B) {
473
474
475
                return B->point().x() < A->point().x();
            });

476
477
478
            for(const auto& point : m_leftEdge) {
                intersectionsLeft << QSharedPointer<LinkedPoint>(new LinkedPoint(point));
            }
479
            std::sort(intersectionsLeft.begin(), intersectionsLeft.end(), [](const QSharedPointer<LinkedPoint>& A, const QSharedPointer<LinkedPoint>& B) {
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
                return B->point().y() < A->point().y();
            });

            clipPolygon << QSharedPointer<LinkedPoint>(new LinkedPoint(m_topLeft))     << intersectionsTop     <<
                           QSharedPointer<LinkedPoint>(new LinkedPoint(m_topRight))    << intersectionsRight   <<
                           QSharedPointer<LinkedPoint>(new LinkedPoint(m_bottomRight)) << intersectionsBottom  <<
                           QSharedPointer<LinkedPoint>(new LinkedPoint(m_bottomLeft))  << intersectionsLeft;

            for(int i = 0; i < clipPolygon.size() - 1; ++i) {
                clipPolygon[i]->setNextClipPolygonPoint(clipPolygon[i+1]);
            }
            clipPolygon.last()->setNextClipPolygonPoint(clipPolygon.first());

            bool iterateBasePolygon = false;

            for(const auto& intersection : intersections) {
                if(intersection->isEntering() && !intersection->isProcessed()) {
                    iterateBasePolygon = true;

                    QSharedPointer<LinkedPoint> it = intersection;
                    clippedPolyObject << it->point();
                    it->setProcessed(true);

                    do {
                        if(iterateBasePolygon) {
                            it = it->nextBasePolygonPoint();
                            if(it->isLeaving()) {
                                iterateBasePolygon = false;
                                it->setProcessed(true);
                            } else if(it->isEntering()) {
                                it->setProcessed(true);
                            }
                        }  else {
                            it = it->nextClipPolygonPoint();
                            if(it->isEntering()) {
                                iterateBasePolygon = true;
                                it->setProcessed(true);
                            } else if(it->isLeaving()) {
                                it->setProcessed(true);
                            }
                        }
                        clippedPolyObject << it->point();
522
                        Q_ASSERT(clippedPolyObject.size() <= 2 * basePolygon.size());
523

Dennis Nienhüser's avatar
Dennis Nienhüser committed
524
525
526
527
528
529
                        //                        // To avoid crashes because of infinite loop.
                        //                        // Needs to be investigated
                        //                        if(clippedPolyObject.size() > basePolygon.size()) {
                        //                            qDebug() << "Something went wrong, exiting current clipping loop...";
                        //                            break;
                        //                        }
530
531
532
533
534
535
536
537
538
539
540

                    } while(clippedPolyObject.first() != clippedPolyObject.last());

                    clippedPolyObjects << clippedPolyObject;
                    clippedPolyObject = QPolygonF();
                }
            }
        } else {
            clippedPolyObjects.clear();
            clippedPolyObject = polygon.intersected(m_viewport);

541
            if (clippedPolyObject == m_viewport.intersected(m_viewport)) {
542
543
544
545
546
547
                clippedPolyObject = QPolygonF();
                clippedPolyObject << m_topLeft << m_topEdge
                                  << m_topRight << m_rightEdge
                                  << m_bottomRight << m_bottomEdge
                                  << m_bottomLeft << m_leftEdge;
                clippedPolyObjects << clippedPolyObject;
548
549
            } else if(!clippedPolyObject.isEmpty()) {
                clippedPolyObjects << polygon;
550
551
552
            }
        }
    } else if(!clippedPolyObject.isEmpty()) {
553
554
        clippedPolyObjects << clippedPolyObject;
    }
Dennis Nienhüser's avatar
Dennis Nienhüser committed
555
556
557
558
559
560
561
562
563

    // Break shared pointer deadlocks. Needed to free memory, without it no LinkedPoint instance would be deleted
    typedef QVector<QSharedPointer<LinkedPoint>> Container;
    auto containers = QVector<Container*>() << &clipPolygon << &basePolygon << &intersections;
    foreach (auto const & container, containers) {
        foreach (auto const & element, *container) {
            element->clear();
        }
    }
564
565
566
567
568
569
570
571
572
573
574
575
576
}


void BaseClipper::clipMultiple( QPolygonF & clippedPolyObject,
                                QVector<QPolygonF> & clippedPolyObjects,
                                bool isClosed )
{
    Q_UNUSED( clippedPolyObjects )
    Q_UNUSED( isClosed )

    // Take care of adding nodes in the image corners if the iterator
    // traverses off screen sections.

577
578
    int numAddedPoints = 0;

579
580
581
582
583
584
585
586
587
588
589
    qreal  m = _m( m_previousPoint, m_currentPoint );

    switch ( m_currentSector ) {
    case 0:
        if ( m_previousSector == 5 ) {
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

            if ( pointRight.y() > m_top ) {
                clippedPolyObject << pointRight;
590
                numAddedPoints++;
591
592
            } else {
                clippedPolyObject << QPointF( m_right, m_top );
593
                numAddedPoints++;
594
            }
595
            if ( pointTop.x() >= m_left && pointTop.x() < m_right ) {
596
                clippedPolyObject << pointTop;
597
598
599
                numAddedPoints++;
            }
            if ( pointLeft.y() > m_top ) {
600
                clippedPolyObject << pointLeft;
601
602
                numAddedPoints++;
            }
603
604
605
606
607
608
609
610
        }
        else if ( m_previousSector == 7 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

            if ( pointBottom.x() > m_left ) {
                clippedPolyObject << pointBottom;
611
                numAddedPoints++;
612
613
            } else {
                clippedPolyObject << QPointF( m_left, m_bottom );
614
                numAddedPoints++;
615
            }
616
            if ( pointLeft.y() >= m_top && pointLeft.y() < m_bottom ) {
617
                clippedPolyObject << pointLeft;
618
619
620
                numAddedPoints++;
            }
            if ( pointTop.x() > m_left ) {
621
                clippedPolyObject << pointTop;
622
623
                numAddedPoints++;
            }
624
625
626
627
628
629
630
        }
        else if ( m_previousSector == 8 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

631
            if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) {
632
                clippedPolyObject << pointBottom;
633
634
635
                numAddedPoints++;
            }
            if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) {
636
                clippedPolyObject << pointRight;
637
638
639
                numAddedPoints++;
            }
            if ( pointTop.x() > m_left && pointTop.x() < m_right ) {
640
                clippedPolyObject << pointTop;
641
642
643
                numAddedPoints++;
            }
            if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) {
644
                clippedPolyObject << pointLeft;
645
646
                numAddedPoints++;
            }
647

648
            if ( pointBottom.x() <= m_left && pointLeft.y() >= m_bottom ) {
649
                clippedPolyObject << QPointF( m_left, m_bottom );
650
651
652
                numAddedPoints++;
            }
            if ( pointTop.x() >= m_right && pointRight.y() <= m_top ) {
653
                clippedPolyObject << QPointF( m_right, m_top );
654
655
                numAddedPoints++;
            }
656
657
658
        }

        clippedPolyObject << QPointF( m_left, m_top );
659
        numAddedPoints++;
660
661
662
663
664
665
666
667
668
        break;

    case 1:
        if ( m_previousSector == 3 ) {
            QPointF pointLeft = clipLeft( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );

            if ( pointLeft.y() > m_top ) {
                clippedPolyObject << pointLeft;
669
                numAddedPoints++;
670
671
            } else {
                clippedPolyObject << QPointF( m_left, m_top );
672
                numAddedPoints++;
673
            }
674
            if ( pointTop.x() > m_left ) {
675
                clippedPolyObject << pointTop;
676
677
                numAddedPoints++;
            }
678
679
680
681
682
683
684
        }
        else if ( m_previousSector == 5 ) {
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );

            if ( pointRight.y() > m_top ) {
                clippedPolyObject << pointRight;
685
                numAddedPoints++;
686
687
            } else {
                clippedPolyObject << QPointF( m_right, m_top );
688
                numAddedPoints++;
689
            }
690
            if ( pointTop.x() < m_right ) {
691
                clippedPolyObject << pointTop;
692
693
                numAddedPoints++;
            }
694
695
696
697
698
699
        }
        else if ( m_previousSector == 6 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );

700
            if ( pointBottom.x() > m_left ) {
701
                clippedPolyObject << pointBottom;
702
703
704
                numAddedPoints++;
            }
            if ( pointLeft.y() > m_top && pointLeft.y() <= m_bottom ) {
705
                clippedPolyObject << pointLeft;
706
707
                numAddedPoints++;
            }
708
709
            if ( pointTop.x() > m_left ) {
                clippedPolyObject << pointTop;
710
                numAddedPoints++;
711
712
            } else {
                clippedPolyObject << QPointF( m_left, m_top );
713
                numAddedPoints++;
714
715
716
717
            }
        }
        else if ( m_previousSector == 7 ) {
            clippedPolyObject << clipBottom( m, m_previousPoint );
718
            numAddedPoints++;
719
            clippedPolyObject << clipTop( m, m_currentPoint );
720
            numAddedPoints++;
721
722
723
724
725
726
        }
        else if ( m_previousSector == 8 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );

727
            if ( pointBottom.x() < m_right ) {
728
                clippedPolyObject << pointBottom;
729
730
731
                numAddedPoints++;
            }
            if ( pointRight.y() > m_top && pointRight.y() <= m_bottom ) {
732
                clippedPolyObject << pointRight;
733
734
                numAddedPoints++;
            }
735
736
            if ( pointTop.x() < m_right ) {
                clippedPolyObject << pointTop;
737
                numAddedPoints++;
738
739
            } else {
                clippedPolyObject << QPointF( m_right, m_top );
740
                numAddedPoints++;
741
742
743
744
745
746
747
748
749
750
751
752
            }
        }
        break;

    case 2:
        if ( m_previousSector == 3 ) {
            QPointF pointLeft = clipLeft( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

            if ( pointLeft.y() > m_top ) {
                clippedPolyObject << pointLeft;
753
                numAddedPoints++;
754
755
            } else {
                clippedPolyObject << QPointF( m_left, m_top );
756
                numAddedPoints++;
757
            }
758
            if ( pointTop.x() > m_left && pointTop.x() <= m_right ) {
759
                clippedPolyObject << pointTop;
760
761
762
                numAddedPoints++;
            }
            if ( pointRight.y() > m_top ) {
763
                clippedPolyObject << pointRight;
764
765
                numAddedPoints++;
            }
766
767
768
769
770
771
772
773
        }
        else if ( m_previousSector == 7 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

            if ( pointBottom.x() < m_right ) {
                clippedPolyObject << pointBottom;
774
                numAddedPoints++;
775
776
            } else {
                clippedPolyObject << QPointF( m_right, m_bottom );
777
                numAddedPoints++;
778
            }
779
            if ( pointRight.y() >= m_top && pointRight.y() < m_bottom ) {
780
                clippedPolyObject << pointRight;
781
782
783
                numAddedPoints++;
            }
            if ( pointTop.x() < m_right ) {
784
                clippedPolyObject << pointTop;
785
786
                numAddedPoints++;
            }
787
788
789
790
791
792
793
        }
        else if ( m_previousSector == 6 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );
            QPointF pointTop = clipTop( m, m_currentPoint );
            QPointF pointRight = clipRight( m, m_previousPoint );

794
            if ( pointBottom.x() > m_left && pointBottom.x() < m_right ) {
795
                clippedPolyObject << pointBottom;
796
797
798
                numAddedPoints++;
            }
            if ( pointLeft.y() > m_top && pointLeft.y() < m_bottom ) {
799
                clippedPolyObject << pointLeft;
800
801
802
                numAddedPoints++;
            }
            if ( pointTop.x() > m_left && pointTop.x() < m_right ) {
803
                clippedPolyObject << pointTop;
804
805
806
                numAddedPoints++;
            }
            if ( pointRight.y() > m_top && pointRight.y() < m_bottom ) {
807
                clippedPolyObject << pointRight;
808
809
                numAddedPoints++;
            }
810

811
            if ( pointBottom.x() >= m_right && pointRight.y() >= m_bottom ) {
812
                clippedPolyObject << QPointF( m_right, m_bottom );
813
814
815
                numAddedPoints++;
            }
            if ( pointTop.x() <= m_left && pointLeft.y() <= m_top ) {
816
                clippedPolyObject << QPointF( m_left, m_top );
817
818
                numAddedPoints++;
            }
819
820
821
        }

        clippedPolyObject << QPointF( m_right, m_top );
822
        numAddedPoints++;
823
824
825
826
827
828
829
        break;

    case 3:
        if ( m_previousSector == 7 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

830
            if ( pointBottom.x() > m_left ) {
831
                clippedPolyObject << pointBottom;
832
833
                numAddedPoints++;
            }
834
835
            if ( pointLeft.y() < m_bottom ) {
                clippedPolyObject << pointLeft;
836
                numAddedPoints++;
837
838
            } else {
                clippedPolyObject << QPointF( m_left, m_bottom );
839
                numAddedPoints++;
840
841
842
843
844
845
            }
        }
        else if ( m_previousSector == 1 ) {
            QPointF pointTop = clipTop( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

846
            if ( pointTop.x() > m_left ) {
847
                clippedPolyObject << pointTop;
848
849
                numAddedPoints++;
            }
850
851
            if ( pointLeft.y() > m_top ) {
                clippedPolyObject << pointLeft;
852
                numAddedPoints++;
853
854
            } else {
                clippedPolyObject << QPointF( m_left, m_top );
855
                numAddedPoints++;
856
857
858
859
860
861
862
            }
        }
        else if ( m_previousSector == 8 ) {
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

863
            if ( pointRight.y() < m_bottom ) {
864
                clippedPolyObject << pointRight;
865
866
867
                numAddedPoints++;
            }
            if ( pointBottom.x() > m_left && pointBottom.x() <= m_right ) {
868
                clippedPolyObject << pointBottom;
869
870
                numAddedPoints++;
            }
871
872
            if ( pointLeft.y() < m_bottom ) {
                clippedPolyObject << pointLeft;
873
                numAddedPoints++;
874
875
            } else {
                clippedPolyObject << QPointF( m_left, m_bottom );
876
                numAddedPoints++;
877
878
879
880
            }
        }
        else if ( m_previousSector == 5 ) {
            clippedPolyObject << clipRight( m, m_previousPoint );
881
            numAddedPoints++;
882
            clippedPolyObject << clipLeft( m, m_currentPoint );
883
            numAddedPoints++;
884
885
886
887
888
889
        }
        else if ( m_previousSector == 2 ) {
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_previousPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

890
            if ( pointRight.y() > m_top ) {
891
                clippedPolyObject << pointRight;
892
893
894
                numAddedPoints++;
            }
            if ( pointTop.x() > m_left && pointTop.x() <= m_right ) {
895
                clippedPolyObject << pointTop;
896
897
                numAddedPoints++;
            }
898
899
            if ( pointLeft.y() > m_top ) {
                clippedPolyObject << pointLeft;
900
                numAddedPoints++;
901
902
            } else {
                clippedPolyObject << QPointF( m_left, m_top );
903
                numAddedPoints++;
904
905
906
907
908
909
910
911
912
            }
        }
        break;

    case 5:
        if ( m_previousSector == 7 ) {
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

913
            if ( pointBottom.x() < m_right ) {
914
                clippedPolyObject << pointBottom;
915
916
                numAddedPoints++;
            }
917
918
            if ( pointRight.y() < m_bottom ) {
                clippedPolyObject << pointRight;
919
                numAddedPoints++;
920
921
            } else {
                clippedPolyObject << QPointF( m_right, m_bottom );
922
                numAddedPoints++;
923
924
925
926
927
928
            }
        }
        else if ( m_previousSector == 1 ) {
            QPointF pointTop = clipTop( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

929
            if ( pointTop.x() < m_right ) {
930
                clippedPolyObject << pointTop;
931
932
                numAddedPoints++;
            }
933
934
            if ( pointRight.y() > m_top ) {
                clippedPolyObject << pointRight;
935
                numAddedPoints++;
936
937
            } else {
                clippedPolyObject << QPointF( m_right, m_top );
938
                numAddedPoints++;
939
940
941
942
943
944
945
            }
        }
        else if ( m_previousSector == 6 ) {
            QPointF pointLeft = clipLeft( m, m_previousPoint );
            QPointF pointBottom = clipBottom( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

946
            if ( pointLeft.y() < m_bottom ) {
947
                clippedPolyObject << pointLeft;
948
949
950
                numAddedPoints++;
            }
            if ( pointBottom.x() >= m_left && pointBottom.x() < m_right ) {
951
                clippedPolyObject << pointBottom;
952
953
                numAddedPoints++;
            }
954
955
            if ( pointRight.y() < m_bottom ) {
                clippedPolyObject << pointRight;
956
                numAddedPoints++;
957
958
            } else {
                clippedPolyObject << QPointF( m_right, m_bottom );
959
                numAddedPoints++;
960
961
962
963
            }
        }
        else if ( m_previousSector == 3 ) {
            clippedPolyObject << clipLeft( m, m_previousPoint );
964
            numAddedPoints++;
965
            clippedPolyObject << clipRight( m, m_currentPoint );
966
            numAddedPoints++;
967
968
969
970
971
972
        }
        else if ( m_previousSector == 0 ) {
            QPointF pointLeft = clipLeft( m, m_previousPoint );
            QPointF pointTop = clipTop( m, m_previousPoint );
            QPointF pointRight = clipRight( m, m_currentPoint );

973
            if ( pointLeft.y() > m_top ) {
974
                clippedPolyObject << pointLeft;
975
976
977
                numAddedPoints++;
            }
            if ( pointTop.x() >= m_left && pointTop.x() < m_right ) {
978
                clippedPolyObject << pointTop;
979
980
                numAddedPoints++;
            }
981
982
            if ( pointRight.y() > m_top ) {
                clippedPolyObject << pointRight;
983
                numAddedPoints++;
984
985
            } else {
                clippedPolyObject << QPointF( m_right, m_top );
986
                numAddedPoints++;
987
988
989
990
991
992
993
994
995
996
997
998
            }
        }
        break;

    case 6:
        if ( m_previousSector == 5 ) {
            QPointF pointRight = clipRight( m, m_previousPoint );
            QPointF pointBottom = clipBottom( m, m_currentPoint );
            QPointF pointLeft = clipLeft( m, m_currentPoint );

            if ( pointRight.y() < m_bottom ) {
                clippedPolyObject << pointRight;
999
                numAddedPoints++;
1000
            } else {
For faster browsing, not all history is shown. View entire blame