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