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