QGIS API Documentation  3.17.0-Master (3b262f2a79)
qgsclipper.h
Go to the documentation of this file.
1 /***************************************************************************
2  qgsclipper.h - a class that clips line
3  segments and polygons
4  -------------------
5  begin : March 2004
6  copyright : (C) 2005 by Gavin Macaulay
7  email :
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #ifndef QGSCLIPPER_H
20 #define QGSCLIPPER_H
21 
22 #include "qgis_core.h"
23 #include "qgis_sip.h"
24 #include "qgspointxy.h"
25 #include "qgsrectangle.h"
26 
27 #include <QVector>
28 #include <QPolygonF>
29 
30 class QgsCurve;
31 
32 SIP_FEATURE( ARM ) // Some parts are not available in sip bindings on ARM because of qreal double vs. float issues
33 
34 
35 
45 class CORE_EXPORT QgsClipper
46 {
47  public:
48 
49  // These are the limits for X11 screen coordinates. The actual
50  // values are +/-32767, but we allow a little bit of space for
51  // rounding errors.
52 
53  // You may wonder why the clipping is done to these coordinates
54  // rather than the boundaries of the qgis canvas. Reasons include:
55  // - making the boundaries static const allows the compiler to
56  // optimise the code that uses these values more than if they changed
57  // for every call to the trim code.
58  // - clipping takes quite a bit of CPU effort, and the less that this is
59  // done the better. More stuff would have to be clipped if the
60  // boundaries were the qgis canvas (but this may be offset by
61  // having less to draw).
62  //
63  // The limit is set to 30,000 instead of 32768 because that things
64  // still go wrong.
65 
67  static const double MAX_X;
69  static const double MIN_X;
71  static const double MAX_Y;
73  static const double MIN_Y;
74 
75 
77  enum Boundary
78  {
82  YMin
83  };
84 
85  SIP_IF_FEATURE( !ARM ) // Not available on ARM sip bindings because of qreal issues
86 
87 
95  static void trimFeature( QVector<double> &x,
96  QVector<double> &y,
97  bool shapeOpen );
98 
99  SIP_END
100 
101  static void trimPolygon( QPolygonF &pts, const QgsRectangle &clipRect );
102 
109  static QPolygonF clippedLine( const QgsCurve &curve, const QgsRectangle &clipExtent );
110 
116  static QPolygonF clippedLine( const QPolygonF &curve, const QgsRectangle &clipExtent );
117 
118  private:
119 
120  // Used when testing for equivalence to 0.0
121  static const double SMALL_NUM;
122 
123  // Trims the given feature to the given boundary. Returns the
124  // trimmed feature in the outX and outY vectors.
125  static inline void trimFeatureToBoundary( const QVector<double> &inX,
126  const QVector<double> &inY,
127  QVector<double> &outX,
128  QVector<double> &outY,
129  Boundary b,
130  bool shapeOpen );
131 
132  static inline void trimPolygonToBoundary( const QPolygonF &inPts, QPolygonF &outPts, const QgsRectangle &rect, Boundary b, double boundaryValue );
133 
134  // Determines if a point is inside or outside the given boundary
135  static inline bool inside( double x, double y, Boundary b );
136 
137  static inline bool inside( QPointF pt, Boundary b, double val );
138 
139  // Calculates the intersection point between a line defined by a
140  // (x1, y1), and (x2, y2) and the given boundary
141  static inline QgsPointXY intersect( double x1, double y1,
142  double x2, double y2,
143  Boundary b );
144 
145  static inline QPointF intersectRect( QPointF pt1,
146  QPointF pt2,
147  Boundary b, const QgsRectangle &rect );
148 
149  //Implementation of 'Fast clipping' algorithm (Sobkow et al. 1987, Computers & Graphics Vol.11, 4, p.459-467)
150  static bool clipLineSegment( double xLeft, double xRight, double yBottom, double yTop, double &x0, double &y0, double &x1, double &y1 );
151 
161  static void connectSeparatedLines( double x0, double y0, double x1, double y1,
162  const QgsRectangle &clipRect, QPolygonF &pts );
163 
164  //low level clip methods for fast clip algorithm
165  static void clipStartTop( double &x0, double &y0, double x1, double y1, double yMax );
166  static void clipStartBottom( double &x0, double &y0, double x1, double y1, double yMin );
167  static void clipStartRight( double &x0, double &y0, double x1, double y1, double xMax );
168  static void clipStartLeft( double &x0, double &y0, double &x1, double &y1, double xMin );
169  static void clipEndTop( double x0, double y0, double &x1, double &y1, double yMax );
170  static void clipEndBottom( double x0, double y0, double &x1, double &y1, double yMin );
171  static void clipEndRight( double x0, double y0, double &x1, double &y1, double xMax );
172  static void clipEndLeft( double x0, double y0, double &x1, double &y1, double xMin );
173 };
174 
175 #ifndef SIP_RUN
176 // The inline functions
177 
178 // Trim the feature using Sutherland and Hodgman's
179 // polygon-clipping algorithm. See J. D. Foley, A. van Dam,
180 // S. K. Feiner, and J. F. Hughes, Computer Graphics, Principles and
181 // Practice. Addison-Wesley Systems Programming Series,
182 // Addison-Wesley, 2nd ed., 1991.
183 
184 // I understand that this is not the most efficient algorithm, but is
185 // one (the only?) that is guaranteed to always give the correct
186 // result.
187 
188 inline void QgsClipper::trimFeature( QVector<double> &x,
189  QVector<double> &y,
190  bool shapeOpen )
191 {
192  QVector<double> tmpX;
193  QVector<double> tmpY;
194  trimFeatureToBoundary( x, y, tmpX, tmpY, XMax, shapeOpen );
195 
196  x.clear();
197  y.clear();
198  trimFeatureToBoundary( tmpX, tmpY, x, y, YMax, shapeOpen );
199 
200  tmpX.clear();
201  tmpY.clear();
202  trimFeatureToBoundary( x, y, tmpX, tmpY, XMin, shapeOpen );
203 
204  x.clear();
205  y.clear();
206  trimFeatureToBoundary( tmpX, tmpY, x, y, YMin, shapeOpen );
207 }
208 
209 inline void QgsClipper::trimPolygon( QPolygonF &pts, const QgsRectangle &clipRect )
210 {
211  QPolygonF tmpPts;
212  tmpPts.reserve( pts.size() );
213 
214  trimPolygonToBoundary( pts, tmpPts, clipRect, XMax, clipRect.xMaximum() );
215  pts.resize( 0 );
216  trimPolygonToBoundary( tmpPts, pts, clipRect, YMax, clipRect.yMaximum() );
217  tmpPts.resize( 0 );
218  trimPolygonToBoundary( pts, tmpPts, clipRect, XMin, clipRect.xMinimum() );
219  pts.resize( 0 );
220  trimPolygonToBoundary( tmpPts, pts, clipRect, YMin, clipRect.yMinimum() );
221 }
222 
223 // An auxiliary function that is part of the polygon trimming
224 // code. Will trim the given polygon to the given boundary and return
225 // the trimmed polygon in the out pointer. Uses Sutherland and
226 // Hodgman's polygon-clipping algorithm.
227 
228 inline void QgsClipper::trimFeatureToBoundary(
229  const QVector<double> &inX,
230  const QVector<double> &inY,
231  QVector<double> &outX,
232  QVector<double> &outY,
233  Boundary b, bool shapeOpen )
234 {
235  // The shapeOpen parameter selects whether this function treats the
236  // shape as open or closed. False is appropriate for polygons and
237  // true for polylines.
238 
239  int i1 = inX.size() - 1; // start with last point
240 
241  // and compare to the first point initially.
242  for ( int i2 = 0; i2 < inX.size() ; ++i2 )
243  {
244  // look at each edge of the polygon in turn
245 
246  //ignore segments with nan or inf coordinates
247  if ( std::isnan( inX[i2] ) || std::isnan( inY[i2] ) || std::isinf( inX[i2] ) || std::isinf( inY[i2] )
248  || std::isnan( inX[i1] ) || std::isnan( inY[i1] ) || std::isinf( inX[i1] ) || std::isinf( inY[i1] ) )
249  {
250  i1 = i2;
251  continue;
252  }
253 
254 
255  if ( inside( inX[i2], inY[i2], b ) ) // end point of edge is inside boundary
256  {
257  if ( inside( inX[i1], inY[i1], b ) )
258  {
259  outX.push_back( inX[i2] );
260  outY.push_back( inY[i2] );
261  }
262  else
263  {
264  // edge crosses into the boundary, so trim back to the boundary, and
265  // store both ends of the new edge
266  if ( !( i2 == 0 && shapeOpen ) )
267  {
268  QgsPointXY p = intersect( inX[i1], inY[i1], inX[i2], inY[i2], b );
269  outX.push_back( p.x() );
270  outY.push_back( p.y() );
271  }
272 
273  outX.push_back( inX[i2] );
274  outY.push_back( inY[i2] );
275  }
276  }
277  else // end point of edge is outside boundary
278  {
279  // start point is in boundary, so need to trim back
280  if ( inside( inX[i1], inY[i1], b ) )
281  {
282  if ( !( i2 == 0 && shapeOpen ) )
283  {
284  QgsPointXY p = intersect( inX[i1], inY[i1], inX[i2], inY[i2], b );
285  outX.push_back( p.x() );
286  outY.push_back( p.y() );
287  }
288  }
289  }
290  i1 = i2;
291  }
292 }
293 
294 inline void QgsClipper::trimPolygonToBoundary( const QPolygonF &inPts, QPolygonF &outPts, const QgsRectangle &rect, Boundary b, double boundaryValue )
295 {
296  int i1 = inPts.size() - 1; // start with last point
297 
298  // and compare to the first point initially.
299  for ( int i2 = 0; i2 < inPts.size() ; ++i2 )
300  {
301  // look at each edge of the polygon in turn
302  if ( inside( inPts[i2], b, boundaryValue ) ) // end point of edge is inside boundary
303  {
304  if ( inside( inPts[i1], b, boundaryValue ) )
305  {
306  outPts.append( inPts[i2] );
307  }
308  else
309  {
310  // edge crosses into the boundary, so trim back to the boundary, and
311  // store both ends of the new edge
312  outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) );
313  outPts.append( inPts[i2] );
314  }
315  }
316  else // end point of edge is outside boundary
317  {
318  // start point is in boundary, so need to trim back
319  if ( inside( inPts[i1], b, boundaryValue ) )
320  {
321  outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) );
322  }
323  }
324  i1 = i2;
325  }
326 }
327 
328 // An auxiliary function to trimPolygonToBoundarY() that returns
329 // whether a point is inside or outside the given boundary.
330 
331 inline bool QgsClipper::inside( const double x, const double y, Boundary b )
332 {
333  switch ( b )
334  {
335  case XMax: // x < MAX_X is inside
336  if ( x < MAX_X )
337  return true;
338  break;
339  case XMin: // x > MIN_X is inside
340  if ( x > MIN_X )
341  return true;
342  break;
343  case YMax: // y < MAX_Y is inside
344  if ( y < MAX_Y )
345  return true;
346  break;
347  case YMin: // y > MIN_Y is inside
348  if ( y > MIN_Y )
349  return true;
350  break;
351  }
352  return false;
353 }
354 
355 inline bool QgsClipper::inside( QPointF pt, Boundary b, double val )
356 {
357  switch ( b )
358  {
359  case XMax: // x < MAX_X is inside
360  return ( pt.x() < val );
361  case XMin: // x > MIN_X is inside
362  return ( pt.x() > val );
363  case YMax: // y < MAX_Y is inside
364  return ( pt.y() < val );
365  case YMin: // y > MIN_Y is inside
366  return ( pt.y() > val );
367  }
368  return false;
369 }
370 
371 
372 // An auxiliary function to trimPolygonToBoundarY() that calculates and
373 // returns the intersection of the line defined by the given points
374 // and the given boundary.
375 
376 inline QgsPointXY QgsClipper::intersect( const double x1, const double y1,
377  const double x2, const double y2,
378  Boundary b )
379 {
380  // This function assumes that the two given points (x1, y1), and
381  // (x2, y2) cross the given boundary. Making this assumption allows
382  // some optimisations.
383 
384  double r_n = SMALL_NUM, r_d = SMALL_NUM;
385 
386  switch ( b )
387  {
388  case XMax: // x = MAX_X boundary
389  r_n = -( x1 - MAX_X ) * ( MAX_Y - MIN_Y );
390  r_d = ( x2 - x1 ) * ( MAX_Y - MIN_Y );
391  break;
392  case XMin: // x = MIN_X boundary
393  r_n = -( x1 - MIN_X ) * ( MAX_Y - MIN_Y );
394  r_d = ( x2 - x1 ) * ( MAX_Y - MIN_Y );
395  break;
396  case YMax: // y = MAX_Y boundary
397  r_n = ( y1 - MAX_Y ) * ( MAX_X - MIN_X );
398  r_d = -( y2 - y1 ) * ( MAX_X - MIN_X );
399  break;
400  case YMin: // y = MIN_Y boundary
401  r_n = ( y1 - MIN_Y ) * ( MAX_X - MIN_X );
402  r_d = -( y2 - y1 ) * ( MAX_X - MIN_X );
403  break;
404  }
405 
406  QgsPointXY p;
407 
408  if ( std::fabs( r_d ) > SMALL_NUM && std::fabs( r_n ) > SMALL_NUM )
409  {
410  // they cross
411  double r = r_n / r_d;
412  p.set( x1 + r * ( x2 - x1 ), y1 + r * ( y2 - y1 ) );
413  }
414  else
415  {
416  // Should never get here, but if we do for some reason, cause a
417  // clunk because something else is wrong if we do.
418  Q_ASSERT( std::fabs( r_d ) > SMALL_NUM && std::fabs( r_n ) > SMALL_NUM );
419  }
420 
421  return p;
422 }
423 
424 inline QPointF QgsClipper::intersectRect( QPointF pt1,
425  QPointF pt2,
426  Boundary b, const QgsRectangle &rect )
427 {
428  // This function assumes that the two given points (x1, y1), and
429  // (x2, y2) cross the given boundary. Making this assumption allows
430  // some optimisations.
431 
432  double r_n = SMALL_NUM, r_d = SMALL_NUM;
433  const double x1 = pt1.x(), x2 = pt2.x();
434  const double y1 = pt1.y(), y2 = pt2.y();
435 
436  switch ( b )
437  {
438  case XMax: // x = MAX_X boundary
439  r_n = -( x1 - rect.xMaximum() ) * ( rect.yMaximum() - rect.yMinimum() );
440  r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() );
441  break;
442  case XMin: // x = MIN_X boundary
443  r_n = -( x1 - rect.xMinimum() ) * ( rect.yMaximum() - rect.yMinimum() );
444  r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() );
445  break;
446  case YMax: // y = MAX_Y boundary
447  r_n = ( y1 - rect.yMaximum() ) * ( rect.xMaximum() - rect.xMinimum() );
448  r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() );
449  break;
450  case YMin: // y = MIN_Y boundary
451  r_n = ( y1 - rect.yMinimum() ) * ( rect.xMaximum() - rect.xMinimum() );
452  r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() );
453  break;
454  }
455 
456  double r = 0;
457  if ( !qgsDoubleNear( r_d, 0.0 ) )
458  {
459  r = r_n / r_d;
460  }
461  return QPointF( x1 + r * ( x2 - x1 ), y1 + r * ( y2 - y1 ) );
462 }
463 
464 inline void QgsClipper::clipStartTop( double &x0, double &y0, double x1, double y1, double yMax )
465 {
466  x0 += ( x1 - x0 ) * ( yMax - y0 ) / ( y1 - y0 );
467  y0 = yMax;
468 }
469 
470 inline void QgsClipper::clipStartBottom( double &x0, double &y0, double x1, double y1, double yMin )
471 {
472  x0 += ( x1 - x0 ) * ( yMin - y0 ) / ( y1 - y0 );
473  y0 = yMin;
474 }
475 
476 inline void QgsClipper::clipStartRight( double &x0, double &y0, double x1, double y1, double xMax )
477 {
478  y0 += ( y1 - y0 ) * ( xMax - x0 ) / ( x1 - x0 );
479  x0 = xMax;
480 }
481 
482 inline void QgsClipper::clipStartLeft( double &x0, double &y0, double &x1, double &y1, double xMin )
483 {
484  y0 += ( y1 - y0 ) * ( xMin - x0 ) / ( x1 - x0 );
485  x0 = xMin;
486 }
487 
488 inline void QgsClipper::clipEndTop( double x0, double y0, double &x1, double &y1, double yMax )
489 {
490  x1 += ( x1 - x0 ) * ( yMax - y1 ) / ( y1 - y0 );
491  y1 = yMax;
492 }
493 
494 inline void QgsClipper::clipEndBottom( double x0, double y0, double &x1, double &y1, double yMin )
495 {
496  x1 += ( x1 - x0 ) * ( yMin - y1 ) / ( y1 - y0 );
497  y1 = yMin;
498 }
499 
500 inline void QgsClipper::clipEndRight( double x0, double y0, double &x1, double &y1, double xMax )
501 {
502  y1 += ( y1 - y0 ) * ( xMax - x1 ) / ( x1 - x0 );
503  x1 = xMax;
504 }
505 
506 inline void QgsClipper::clipEndLeft( double x0, double y0, double &x1, double &y1, double xMin )
507 {
508  y1 += ( y1 - y0 ) * ( xMin - x1 ) / ( x1 - x0 );
509  x1 = xMin;
510 }
511 
512 //'Fast clipping' algorithm (Sobkow et al. 1987, Computers & Graphics Vol.11, 4, p.459-467)
513 inline bool QgsClipper::clipLineSegment( double xLeft, double xRight, double yBottom, double yTop, double &x0, double &y0, double &x1, double &y1 )
514 {
515  int lineCode = 0;
516 
517  if ( y1 < yBottom )
518  lineCode |= 4;
519  else if ( y1 > yTop )
520  lineCode |= 8;
521 
522  if ( x1 > xRight )
523  lineCode |= 2;
524  else if ( x1 < xLeft )
525  lineCode |= 1;
526 
527  if ( y0 < yBottom )
528  lineCode |= 64;
529  else if ( y0 > yTop )
530  lineCode |= 128;
531 
532  if ( x0 > xRight )
533  lineCode |= 32;
534  else if ( x0 < xLeft )
535  lineCode |= 16;
536 
537  switch ( lineCode )
538  {
539  case 0: //completely inside
540  return true;
541 
542  case 1:
543  clipEndLeft( x0, y0, x1, y1, xLeft );
544  return true;
545 
546  case 2:
547  clipEndRight( x0, y0, x1, y1, xRight );
548  return true;
549 
550  case 4:
551  clipEndBottom( x0, y0, x1, y1, yBottom );
552  return true;
553 
554  case 5:
555  clipEndLeft( x0, y0, x1, y1, xLeft );
556  if ( y1 < yBottom )
557  clipEndBottom( x0, y0, x1, y1, yBottom );
558  return true;
559 
560  case 6:
561  clipEndRight( x0, y0, x1, y1, xRight );
562  if ( y1 < yBottom )
563  clipEndBottom( x0, y0, x1, y1, yBottom );
564  return true;
565 
566  case 8:
567  clipEndTop( x0, y0, x1, y1, yTop );
568  return true;
569 
570  case 9:
571  clipEndLeft( x0, y0, x1, y1, xLeft );
572  if ( y1 > yTop )
573  clipEndTop( x0, y0, x1, y1, yTop );
574  return true;
575 
576  case 10:
577  clipEndRight( x0, y0, x1, y1, xRight );
578  if ( y1 > yTop )
579  clipEndTop( x0, y0, x1, y1, yTop );
580  return true;
581 
582  case 16:
583  clipStartLeft( x0, y0, x1, y1, xLeft );
584  return true;
585 
586  case 18:
587  clipStartLeft( x0, y0, x1, y1, xLeft );
588  clipEndRight( x0, y0, x1, y1, xRight );
589  return true;
590 
591  case 20:
592  clipStartLeft( x0, y0, x1, y1, xLeft );
593  if ( y0 < yBottom )
594  return false;
595  clipEndBottom( x0, y0, x1, y1, yBottom );
596  return true;
597 
598  case 22:
599  clipStartLeft( x0, y0, x1, y1, xLeft );
600  if ( y0 < yBottom )
601  return false;
602  clipEndBottom( x0, y0, x1, y1, yBottom );
603  if ( x1 > xRight )
604  clipEndRight( x0, y0, x1, y1, xRight );
605  return true;
606 
607  case 24:
608  clipStartLeft( x0, y0, x1, y1, xLeft );
609  if ( y0 > yTop )
610  return false;
611  clipEndTop( x0, y0, x1, y1, yTop );
612  return true;
613 
614  case 26:
615  clipStartLeft( x0, y0, x1, y1, xLeft );
616  if ( y0 > yTop )
617  return false;
618  clipEndTop( x0, y0, x1, y1, yTop );
619  if ( x1 > xRight )
620  clipEndRight( x0, y0, x1, y1, xRight );
621  return true;
622 
623  case 32:
624  clipStartRight( x0, y0, x1, y1, xRight );
625  return true;
626 
627  case 33:
628  clipStartRight( x0, y0, x1, y1, xRight );
629  clipEndLeft( x0, y0, x1, y1, xLeft );
630  return true;
631 
632  case 36:
633  clipStartRight( x0, y0, x1, y1, xRight );
634  if ( y0 < yBottom )
635  return false;
636  clipEndBottom( x0, y0, x1, y1, yBottom );
637  return true;
638 
639  case 37:
640  clipStartRight( x0, y0, x1, y1, xRight );
641  if ( y0 < yBottom )
642  return false;
643  clipEndBottom( x0, y0, x1, y1, yBottom );
644  if ( x1 < xLeft )
645  clipEndLeft( x0, y0, x1, y1, xLeft );
646  return true;
647 
648  case 40:
649  clipStartRight( x0, y0, x1, y1, xRight );
650  if ( y0 > yTop )
651  return false;
652  clipEndTop( x0, y0, x1, y1, yTop );
653  return true;
654 
655  case 41:
656  clipStartRight( x0, y0, x1, y1, xRight );
657  if ( y0 > yTop )
658  return false;
659  clipEndTop( x0, y0, x1, y1, yTop );
660  if ( x1 < xLeft )
661  clipEndLeft( x0, y0, x1, y1, xLeft );
662  return true;
663 
664  case 64:
665  clipStartBottom( x0, y0, x1, y1, yBottom );
666  return true;
667 
668  case 65:
669  clipStartBottom( x0, y0, x1, y1, yBottom );
670  if ( x0 < xLeft )
671  return false;
672  clipEndLeft( x0, y0, x1, y1, xLeft );
673  if ( y1 < yBottom )
674  clipEndBottom( x0, y0, x1, y1, yBottom );
675  return true;
676 
677  case 66:
678  clipStartBottom( x0, y0, x1, y1, yBottom );
679  if ( x0 > xRight )
680  return false;
681  clipEndRight( x0, y0, x1, y1, xRight );
682  return true;
683 
684  case 72:
685  clipStartBottom( x0, y0, x1, y1, yBottom );
686  clipEndTop( x0, y0, x1, y1, yTop );
687  return true;
688 
689  case 73:
690  clipStartBottom( x0, y0, x1, y1, yBottom );
691  if ( x0 < xLeft )
692  return false;
693  clipEndLeft( x0, y0, x1, y1, xLeft );
694  if ( y1 > yTop )
695  clipEndTop( x0, y0, x1, y1, yTop );
696  return true;
697 
698  case 74:
699  clipStartBottom( x0, y0, x1, y1, yBottom );
700  if ( x0 > xRight )
701  return false;
702  clipEndRight( x0, y0, x1, y1, xRight );
703  if ( y1 > yTop )
704  clipEndTop( x0, y0, x1, y1, yTop );
705  return true;
706 
707  case 80:
708  clipStartLeft( x0, y0, x1, y1, xLeft );
709  if ( y0 < yBottom )
710  clipStartBottom( x0, y0, x1, y1, yBottom );
711  return true;
712 
713  case 82:
714  clipEndRight( x0, y0, x1, y1, xRight );
715  if ( y1 < yBottom )
716  return false;
717  clipStartBottom( x0, y0, x1, y1, yBottom );
718  if ( x0 < xLeft )
719  clipStartLeft( x0, y0, x1, y1, xLeft );
720  return true;
721 
722  case 88:
723  clipEndTop( x0, y0, x1, y1, yTop );
724  if ( x1 < xLeft )
725  return false;
726  clipStartBottom( x0, y0, x1, y1, yBottom );
727  if ( x0 < xLeft )
728  clipStartLeft( x0, y0, x1, y1, xLeft );
729  return true;
730 
731  case 90:
732  clipStartLeft( x0, y0, x1, y1, xLeft );
733  if ( y0 > yTop )
734  return false;
735  clipEndRight( x0, y0, x1, y1, xRight );
736  if ( y1 < yBottom )
737  return false;
738  if ( y0 < yBottom )
739  clipStartBottom( x0, y0, x1, y1, yBottom );
740  if ( y1 > yTop )
741  clipEndTop( x0, y0, x1, y1, yTop );
742  return true;
743 
744  case 96:
745  clipStartRight( x0, y0, x1, y1, xRight );
746  if ( y0 < yBottom )
747  clipStartBottom( x0, y0, x1, y1, yBottom );
748  return true;
749 
750  case 97:
751  clipEndLeft( x0, y0, x1, y1, xLeft );
752  if ( y1 < yBottom )
753  return false;
754  clipStartBottom( x0, y0, x1, y1, yBottom );
755  if ( x0 > xRight )
756  clipStartRight( x0, y0, x1, y1, xRight );
757  return true;
758 
759  case 104:
760  clipEndTop( x0, y0, x1, y1, yTop );
761  if ( x1 > xRight )
762  return false;
763  clipStartRight( x0, y0, x1, y1, xRight );
764  if ( y0 < yBottom )
765  clipStartBottom( x0, y0, x1, y1, yBottom );
766  return true;
767 
768  case 105:
769  clipEndLeft( x0, y0, x1, y1, xLeft );
770  if ( y1 < yBottom )
771  return false;
772  clipStartRight( x0, y0, x1, y1, xRight );
773  if ( y0 > yTop )
774  return false;
775  if ( y1 > yTop )
776  clipEndTop( x0, y0, x1, y1, yTop );
777  if ( y0 < yBottom )
778  clipStartBottom( x0, y0, x1, y1, yBottom );
779  return true;
780 
781  case 128:
782  clipStartTop( x0, y0, x1, y1, yTop );
783  return true;
784 
785  case 129:
786  clipStartTop( x0, y0, x1, y1, yTop );
787  if ( x0 < xLeft )
788  return false;
789  clipEndLeft( x0, y0, x1, y1, xLeft );
790  return true;
791 
792  case 130:
793  clipStartTop( x0, y0, x1, y1, yTop );
794  if ( x0 > xRight )
795  return false;
796  clipEndRight( x0, y0, x1, y1, xRight );
797  return true;
798 
799  case 132:
800  clipStartTop( x0, y0, x1, y1, yTop );
801  clipEndBottom( x0, y0, x1, y1, yBottom );
802  return true;
803 
804  case 133:
805  clipStartTop( x0, y0, x1, y1, yTop );
806  if ( x0 < xLeft )
807  return false;
808  clipEndLeft( x0, y0, x1, y1, xLeft );
809  if ( y1 < yBottom )
810  clipEndBottom( x0, y0, x1, y1, yBottom );
811  return true;
812 
813  case 134:
814  clipStartTop( x0, y0, x1, y1, yTop );
815  if ( x0 > xRight )
816  return false;
817  clipEndRight( x0, y0, x1, y1, xRight );
818  if ( y1 < yBottom )
819  clipEndBottom( x0, y0, x1, y1, yBottom );
820  return true;
821 
822  case 144:
823  clipStartLeft( x0, y0, x1, y1, xLeft );
824  if ( y0 > yTop )
825  clipStartTop( x0, y0, x1, y1, yTop );
826  return true;
827 
828  case 146:
829  clipEndRight( x0, y0, x1, y1, xRight );
830  if ( y1 > yTop )
831  return false;
832  clipStartTop( x0, y0, x1, y1, yTop );
833  if ( x0 < xLeft )
834  clipStartLeft( x0, y0, x1, y1, xLeft );
835  return true;
836 
837  case 148:
838  clipEndBottom( x0, y0, x1, y1, yBottom );
839  if ( x1 < xLeft )
840  return false;
841  clipStartLeft( x0, y0, x1, y1, xLeft );
842  if ( y0 > yTop )
843  clipStartTop( x0, y0, x1, y1, yTop );
844  return true;
845 
846  case 150:
847  clipStartLeft( x0, y0, x1, y1, xLeft );
848  if ( y0 < yBottom )
849  return false;
850  clipEndRight( x0, y0, x1, y1, xRight );
851  if ( y1 > yTop )
852  return false;
853  if ( y0 > yTop )
854  clipStartTop( x0, y0, x1, y1, yTop );
855  if ( y1 < yBottom )
856  clipEndBottom( x0, y0, x1, y1, yBottom );
857  return true;
858 
859  case 160:
860  clipStartRight( x0, y0, x1, y1, xRight );
861  if ( y0 > yTop )
862  clipStartTop( x0, y0, x1, y1, yTop );
863  return true;
864 
865  case 161:
866  clipEndLeft( x0, y0, x1, y1, xLeft );
867  if ( y1 > yTop )
868  return false;
869  clipStartTop( x0, y0, x1, y1, yTop );
870  if ( x0 > xRight )
871  clipStartRight( x0, y0, x1, y1, xRight );
872  return true;
873 
874  case 164:
875  clipEndBottom( x0, y0, x1, y1, yBottom );
876  if ( x1 > xRight )
877  return false;
878  clipStartRight( x0, y0, x1, y1, xRight );
879  if ( y0 > yTop )
880  clipStartTop( x0, y0, x1, y1, yTop );
881  return true;
882 
883  case 165:
884  clipEndLeft( x0, y0, x1, y1, xLeft );
885  if ( y1 > yTop )
886  return false;
887  clipStartRight( x0, y0, x1, y1, xRight );
888  if ( y0 < yBottom )
889  return false;
890  if ( y1 < yBottom )
891  clipEndBottom( x0, y0, x1, y1, yBottom );
892  if ( y0 > yTop )
893  clipStartTop( x0, y0, x1, y1, yTop );
894  return true;
895  }
896 
897  return false;
898 
899 }
900 #endif // SIP_RUN
901 
902 
903 #endif
static const double MAX_Y
Maximum Y-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:71
A rectangle specified with double values.
Definition: qgsrectangle.h:41
static void trimFeature(QVector< double > &x, QVector< double > &y, bool shapeOpen)
Trims the given feature to a rectangular box.
Definition: qgsclipper.h:188
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
static const double MIN_X
Minimum X-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:69
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
A class to trim lines and polygons to within a rectangular region.
Definition: qgsclipper.h:45
#define SIP_END
Definition: qgis_sip.h:194
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
void set(double x, double y) SIP_HOLDGIL
Sets the x and y value of the point.
Definition: qgspointxy.h:124
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
double x
Definition: qgspointxy.h:47
#define SIP_IF_FEATURE(feature)
Definition: qgis_sip.h:167
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
Boundary
A handy way to refer to the four boundaries.
Definition: qgsclipper.h:77
#define SIP_FEATURE(feature)
Definition: qgis_sip.h:162
static const double MIN_Y
Minimum Y-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:73
static void trimPolygon(QPolygonF &pts, const QgsRectangle &clipRect)
Definition: qgsclipper.h:209
static const double MAX_X
Maximum X-coordinate of the rectangular box used for clipping.
Definition: qgsclipper.h:67