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