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