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