• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

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

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal