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