Branch data Line data Source code
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 : : /**
36 : : * \ingroup core
37 : : * \brief A class to trim lines and polygons to within a rectangular region.
38 : : *
39 : : * The functions in this class are likely to be called from within a
40 : : * render loop and hence need to as CPU efficient as possible.
41 : : * The main purpose of the functions in this class are to trim lines
42 : : * and polygons to lie within a rectangular region. This is necessary
43 : : * for drawing items to an X11 display which have a limit on the
44 : : * magnitude of the screen coordinates (+/- 32768, i.e. 16 bit integer).
45 : : */
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 : :
67 : : //! Maximum X-coordinate of the rectangular box used for clipping.
68 : : static const double MAX_X;
69 : : //! Minimum X-coordinate of the rectangular box used for clipping.
70 : : static const double MIN_X;
71 : : //! Maximum Y-coordinate of the rectangular box used for clipping.
72 : : static const double MAX_Y;
73 : : //! Minimum Y-coordinate of the rectangular box used for clipping.
74 : : static const double MIN_Y;
75 : :
76 : :
77 : : //! A handy way to refer to the four boundaries
78 : : enum Boundary
79 : : {
80 : : XMax,
81 : : XMin,
82 : : YMax,
83 : : YMin
84 : : };
85 : :
86 : : SIP_IF_FEATURE( !ARM ) // Not available on ARM sip bindings because of qreal issues
87 : :
88 : : /**
89 : : * Trims the given feature to a rectangular box. Returns the trimmed
90 : : * feature in x and y. The shapeOpen parameter determines whether
91 : : * the function treats the points as a closed shape (polygon), or as
92 : : * an open shape (linestring).
93 : : *
94 : : * \note not available in Python bindings on android
95 : : */
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 : :
104 : : /**
105 : : * Takes a linestring and clips it to clipExtent
106 : : * \param curve the linestring
107 : : * \param clipExtent clipping bounds
108 : : * \returns clipped line coordinates
109 : : */
110 : : static QPolygonF clippedLine( const QgsCurve &curve, const QgsRectangle &clipExtent );
111 : :
112 : : /**
113 : : * Takes a \a curve and clips it to clipExtent.
114 : : *
115 : : * \since QGIS 3.16
116 : : */
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 : :
153 : : /**
154 : : * Connects two lines split by the clip (by inserting points on the clip border)
155 : : * \param x0 x-coordinate of the first line end
156 : : * \param y0 y-coordinate of the first line end
157 : : * \param x1 x-coordinate of the second line start
158 : : * \param y1 y-coordinate of the second line start
159 : : * \param clipRect clip rectangle
160 : : * \param pts: in/out array of clipped points
161 : : */
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 : 0 : inline void QgsClipper::trimPolygon( QPolygonF &pts, const QgsRectangle &clipRect )
211 : : {
212 : 0 : QPolygonF tmpPts;
213 : 0 : tmpPts.reserve( pts.size() );
214 : :
215 : 0 : trimPolygonToBoundary( pts, tmpPts, clipRect, XMax, clipRect.xMaximum() );
216 : 0 : pts.resize( 0 );
217 : 0 : trimPolygonToBoundary( tmpPts, pts, clipRect, YMax, clipRect.yMaximum() );
218 : 0 : tmpPts.resize( 0 );
219 : 0 : trimPolygonToBoundary( pts, tmpPts, clipRect, XMin, clipRect.xMinimum() );
220 : 0 : pts.resize( 0 );
221 : 0 : trimPolygonToBoundary( tmpPts, pts, clipRect, YMin, clipRect.yMinimum() );
222 : 0 : }
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 : : 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 : : 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 : 0 : inline void QgsClipper::trimPolygonToBoundary( const QPolygonF &inPts, QPolygonF &outPts, const QgsRectangle &rect, Boundary b, double boundaryValue )
296 : : {
297 : 0 : int i1 = inPts.size() - 1; // start with last point
298 : :
299 : : // and compare to the first point initially.
300 : 0 : for ( int i2 = 0; i2 < inPts.size() ; ++i2 )
301 : : {
302 : : // look at each edge of the polygon in turn
303 : 0 : if ( inside( inPts[i2], b, boundaryValue ) ) // end point of edge is inside boundary
304 : : {
305 : 0 : if ( inside( inPts[i1], b, boundaryValue ) )
306 : : {
307 : 0 : outPts.append( inPts[i2] );
308 : 0 : }
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 : 0 : outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) );
314 : 0 : outPts.append( inPts[i2] );
315 : : }
316 : 0 : }
317 : : else // end point of edge is outside boundary
318 : : {
319 : : // start point is in boundary, so need to trim back
320 : 0 : if ( inside( inPts[i1], b, boundaryValue ) )
321 : : {
322 : 0 : outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) );
323 : 0 : }
324 : : }
325 : 0 : i1 = i2;
326 : 0 : }
327 : 0 : }
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 : 0 : inline bool QgsClipper::inside( QPointF pt, Boundary b, double val )
357 : : {
358 : 0 : switch ( b )
359 : : {
360 : : case XMax: // x < MAX_X is inside
361 : 0 : return ( pt.x() < val );
362 : : case XMin: // x > MIN_X is inside
363 : 0 : return ( pt.x() > val );
364 : : case YMax: // y < MAX_Y is inside
365 : 0 : return ( pt.y() < val );
366 : : case YMin: // y > MIN_Y is inside
367 : 0 : return ( pt.y() > val );
368 : : }
369 : 0 : return false;
370 : 0 : }
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 : : 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 : 0 : 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 : 0 : double r_n = SMALL_NUM, r_d = SMALL_NUM;
434 : 0 : const double x1 = pt1.x(), x2 = pt2.x();
435 : 0 : const double y1 = pt1.y(), y2 = pt2.y();
436 : :
437 : 0 : switch ( b )
438 : : {
439 : : case XMax: // x = MAX_X boundary
440 : 0 : r_n = -( x1 - rect.xMaximum() ) * ( rect.yMaximum() - rect.yMinimum() );
441 : 0 : r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() );
442 : 0 : break;
443 : : case XMin: // x = MIN_X boundary
444 : 0 : r_n = -( x1 - rect.xMinimum() ) * ( rect.yMaximum() - rect.yMinimum() );
445 : 0 : r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() );
446 : 0 : break;
447 : : case YMax: // y = MAX_Y boundary
448 : 0 : r_n = ( y1 - rect.yMaximum() ) * ( rect.xMaximum() - rect.xMinimum() );
449 : 0 : r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() );
450 : 0 : break;
451 : : case YMin: // y = MIN_Y boundary
452 : 0 : r_n = ( y1 - rect.yMinimum() ) * ( rect.xMaximum() - rect.xMinimum() );
453 : 0 : r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() );
454 : 0 : break;
455 : : }
456 : :
457 : 0 : double r = 0;
458 : 0 : if ( !qgsDoubleNear( r_d, 0.0 ) )
459 : : {
460 : 0 : r = r_n / r_d;
461 : 0 : }
462 : 0 : return QPointF( x1 + r * ( x2 - x1 ), y1 + r * ( y2 - y1 ) );
463 : : }
464 : :
465 : 0 : inline void QgsClipper::clipStartTop( double &x0, double &y0, double x1, double y1, double yMax )
466 : : {
467 : 0 : x0 += ( x1 - x0 ) * ( yMax - y0 ) / ( y1 - y0 );
468 : 0 : y0 = yMax;
469 : 0 : }
470 : :
471 : 0 : inline void QgsClipper::clipStartBottom( double &x0, double &y0, double x1, double y1, double yMin )
472 : : {
473 : 0 : x0 += ( x1 - x0 ) * ( yMin - y0 ) / ( y1 - y0 );
474 : 0 : y0 = yMin;
475 : 0 : }
476 : :
477 : 0 : inline void QgsClipper::clipStartRight( double &x0, double &y0, double x1, double y1, double xMax )
478 : : {
479 : 0 : y0 += ( y1 - y0 ) * ( xMax - x0 ) / ( x1 - x0 );
480 : 0 : x0 = xMax;
481 : 0 : }
482 : :
483 : 0 : inline void QgsClipper::clipStartLeft( double &x0, double &y0, double &x1, double &y1, double xMin )
484 : : {
485 : 0 : y0 += ( y1 - y0 ) * ( xMin - x0 ) / ( x1 - x0 );
486 : 0 : x0 = xMin;
487 : 0 : }
488 : :
489 : 0 : inline void QgsClipper::clipEndTop( double x0, double y0, double &x1, double &y1, double yMax )
490 : : {
491 : 0 : x1 += ( x1 - x0 ) * ( yMax - y1 ) / ( y1 - y0 );
492 : 0 : y1 = yMax;
493 : 0 : }
494 : :
495 : 0 : inline void QgsClipper::clipEndBottom( double x0, double y0, double &x1, double &y1, double yMin )
496 : : {
497 : 0 : x1 += ( x1 - x0 ) * ( yMin - y1 ) / ( y1 - y0 );
498 : 0 : y1 = yMin;
499 : 0 : }
500 : :
501 : 0 : inline void QgsClipper::clipEndRight( double x0, double y0, double &x1, double &y1, double xMax )
502 : : {
503 : 0 : y1 += ( y1 - y0 ) * ( xMax - x1 ) / ( x1 - x0 );
504 : 0 : x1 = xMax;
505 : 0 : }
506 : :
507 : 0 : inline void QgsClipper::clipEndLeft( double x0, double y0, double &x1, double &y1, double xMin )
508 : : {
509 : 0 : y1 += ( y1 - y0 ) * ( xMin - x1 ) / ( x1 - x0 );
510 : 0 : x1 = xMin;
511 : 0 : }
512 : :
513 : : //'Fast clipping' algorithm (Sobkow et al. 1987, Computers & Graphics Vol.11, 4, p.459-467)
514 : 0 : inline bool QgsClipper::clipLineSegment( double xLeft, double xRight, double yBottom, double yTop, double &x0, double &y0, double &x1, double &y1 )
515 : : {
516 : 0 : int lineCode = 0;
517 : :
518 : 0 : if ( y1 < yBottom )
519 : 0 : lineCode |= 4;
520 : 0 : else if ( y1 > yTop )
521 : 0 : lineCode |= 8;
522 : :
523 : 0 : if ( x1 > xRight )
524 : 0 : lineCode |= 2;
525 : 0 : else if ( x1 < xLeft )
526 : 0 : lineCode |= 1;
527 : :
528 : 0 : if ( y0 < yBottom )
529 : 0 : lineCode |= 64;
530 : 0 : else if ( y0 > yTop )
531 : 0 : lineCode |= 128;
532 : :
533 : 0 : if ( x0 > xRight )
534 : 0 : lineCode |= 32;
535 : 0 : else if ( x0 < xLeft )
536 : 0 : lineCode |= 16;
537 : :
538 : 0 : switch ( lineCode )
539 : : {
540 : : case 0: //completely inside
541 : 0 : return true;
542 : :
543 : : case 1:
544 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
545 : 0 : return true;
546 : :
547 : : case 2:
548 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
549 : 0 : return true;
550 : :
551 : : case 4:
552 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
553 : 0 : return true;
554 : :
555 : : case 5:
556 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
557 : 0 : if ( y1 < yBottom )
558 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
559 : 0 : return true;
560 : :
561 : : case 6:
562 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
563 : 0 : if ( y1 < yBottom )
564 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
565 : 0 : return true;
566 : :
567 : : case 8:
568 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
569 : 0 : return true;
570 : :
571 : : case 9:
572 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
573 : 0 : if ( y1 > yTop )
574 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
575 : 0 : return true;
576 : :
577 : : case 10:
578 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
579 : 0 : if ( y1 > yTop )
580 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
581 : 0 : return true;
582 : :
583 : : case 16:
584 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
585 : 0 : return true;
586 : :
587 : : case 18:
588 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
589 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
590 : 0 : return true;
591 : :
592 : : case 20:
593 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
594 : 0 : if ( y0 < yBottom )
595 : 0 : return false;
596 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
597 : 0 : return true;
598 : :
599 : : case 22:
600 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
601 : 0 : if ( y0 < yBottom )
602 : 0 : return false;
603 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
604 : 0 : if ( x1 > xRight )
605 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
606 : 0 : return true;
607 : :
608 : : case 24:
609 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
610 : 0 : if ( y0 > yTop )
611 : 0 : return false;
612 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
613 : 0 : return true;
614 : :
615 : : case 26:
616 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
617 : 0 : if ( y0 > yTop )
618 : 0 : return false;
619 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
620 : 0 : if ( x1 > xRight )
621 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
622 : 0 : return true;
623 : :
624 : : case 32:
625 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
626 : 0 : return true;
627 : :
628 : : case 33:
629 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
630 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
631 : 0 : return true;
632 : :
633 : : case 36:
634 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
635 : 0 : if ( y0 < yBottom )
636 : 0 : return false;
637 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
638 : 0 : return true;
639 : :
640 : : case 37:
641 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
642 : 0 : if ( y0 < yBottom )
643 : 0 : return false;
644 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
645 : 0 : if ( x1 < xLeft )
646 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
647 : 0 : return true;
648 : :
649 : : case 40:
650 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
651 : 0 : if ( y0 > yTop )
652 : 0 : return false;
653 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
654 : 0 : return true;
655 : :
656 : : case 41:
657 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
658 : 0 : if ( y0 > yTop )
659 : 0 : return false;
660 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
661 : 0 : if ( x1 < xLeft )
662 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
663 : 0 : return true;
664 : :
665 : : case 64:
666 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
667 : 0 : return true;
668 : :
669 : : case 65:
670 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
671 : 0 : if ( x0 < xLeft )
672 : 0 : return false;
673 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
674 : 0 : if ( y1 < yBottom )
675 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
676 : 0 : return true;
677 : :
678 : : case 66:
679 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
680 : 0 : if ( x0 > xRight )
681 : 0 : return false;
682 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
683 : 0 : return true;
684 : :
685 : : case 72:
686 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
687 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
688 : 0 : return true;
689 : :
690 : : case 73:
691 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
692 : 0 : if ( x0 < xLeft )
693 : 0 : return false;
694 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
695 : 0 : if ( y1 > yTop )
696 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
697 : 0 : return true;
698 : :
699 : : case 74:
700 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
701 : 0 : if ( x0 > xRight )
702 : 0 : return false;
703 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
704 : 0 : if ( y1 > yTop )
705 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
706 : 0 : return true;
707 : :
708 : : case 80:
709 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
710 : 0 : if ( y0 < yBottom )
711 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
712 : 0 : return true;
713 : :
714 : : case 82:
715 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
716 : 0 : if ( y1 < yBottom )
717 : 0 : return false;
718 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
719 : 0 : if ( x0 < xLeft )
720 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
721 : 0 : return true;
722 : :
723 : : case 88:
724 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
725 : 0 : if ( x1 < xLeft )
726 : 0 : return false;
727 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
728 : 0 : if ( x0 < xLeft )
729 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
730 : 0 : return true;
731 : :
732 : : case 90:
733 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
734 : 0 : if ( y0 > yTop )
735 : 0 : return false;
736 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
737 : 0 : if ( y1 < yBottom )
738 : 0 : return false;
739 : 0 : if ( y0 < yBottom )
740 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
741 : 0 : if ( y1 > yTop )
742 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
743 : 0 : return true;
744 : :
745 : : case 96:
746 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
747 : 0 : if ( y0 < yBottom )
748 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
749 : 0 : return true;
750 : :
751 : : case 97:
752 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
753 : 0 : if ( y1 < yBottom )
754 : 0 : return false;
755 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
756 : 0 : if ( x0 > xRight )
757 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
758 : 0 : return true;
759 : :
760 : : case 104:
761 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
762 : 0 : if ( x1 > xRight )
763 : 0 : return false;
764 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
765 : 0 : if ( y0 < yBottom )
766 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
767 : 0 : return true;
768 : :
769 : : case 105:
770 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
771 : 0 : if ( y1 < yBottom )
772 : 0 : return false;
773 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
774 : 0 : if ( y0 > yTop )
775 : 0 : return false;
776 : 0 : if ( y1 > yTop )
777 : 0 : clipEndTop( x0, y0, x1, y1, yTop );
778 : 0 : if ( y0 < yBottom )
779 : 0 : clipStartBottom( x0, y0, x1, y1, yBottom );
780 : 0 : return true;
781 : :
782 : : case 128:
783 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
784 : 0 : return true;
785 : :
786 : : case 129:
787 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
788 : 0 : if ( x0 < xLeft )
789 : 0 : return false;
790 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
791 : 0 : return true;
792 : :
793 : : case 130:
794 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
795 : 0 : if ( x0 > xRight )
796 : 0 : return false;
797 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
798 : 0 : return true;
799 : :
800 : : case 132:
801 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
802 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
803 : 0 : return true;
804 : :
805 : : case 133:
806 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
807 : 0 : if ( x0 < xLeft )
808 : 0 : return false;
809 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
810 : 0 : if ( y1 < yBottom )
811 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
812 : 0 : return true;
813 : :
814 : : case 134:
815 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
816 : 0 : if ( x0 > xRight )
817 : 0 : return false;
818 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
819 : 0 : if ( y1 < yBottom )
820 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
821 : 0 : return true;
822 : :
823 : : case 144:
824 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
825 : 0 : if ( y0 > yTop )
826 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
827 : 0 : return true;
828 : :
829 : : case 146:
830 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
831 : 0 : if ( y1 > yTop )
832 : 0 : return false;
833 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
834 : 0 : if ( x0 < xLeft )
835 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
836 : 0 : return true;
837 : :
838 : : case 148:
839 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
840 : 0 : if ( x1 < xLeft )
841 : 0 : return false;
842 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
843 : 0 : if ( y0 > yTop )
844 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
845 : 0 : return true;
846 : :
847 : : case 150:
848 : 0 : clipStartLeft( x0, y0, x1, y1, xLeft );
849 : 0 : if ( y0 < yBottom )
850 : 0 : return false;
851 : 0 : clipEndRight( x0, y0, x1, y1, xRight );
852 : 0 : if ( y1 > yTop )
853 : 0 : return false;
854 : 0 : if ( y0 > yTop )
855 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
856 : 0 : if ( y1 < yBottom )
857 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
858 : 0 : return true;
859 : :
860 : : case 160:
861 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
862 : 0 : if ( y0 > yTop )
863 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
864 : 0 : return true;
865 : :
866 : : case 161:
867 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
868 : 0 : if ( y1 > yTop )
869 : 0 : return false;
870 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
871 : 0 : if ( x0 > xRight )
872 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
873 : 0 : return true;
874 : :
875 : : case 164:
876 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
877 : 0 : if ( x1 > xRight )
878 : 0 : return false;
879 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
880 : 0 : if ( y0 > yTop )
881 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
882 : 0 : return true;
883 : :
884 : : case 165:
885 : 0 : clipEndLeft( x0, y0, x1, y1, xLeft );
886 : 0 : if ( y1 > yTop )
887 : 0 : return false;
888 : 0 : clipStartRight( x0, y0, x1, y1, xRight );
889 : 0 : if ( y0 < yBottom )
890 : 0 : return false;
891 : 0 : if ( y1 < yBottom )
892 : 0 : clipEndBottom( x0, y0, x1, y1, yBottom );
893 : 0 : if ( y0 > yTop )
894 : 0 : clipStartTop( x0, y0, x1, y1, yTop );
895 : 0 : return true;
896 : : }
897 : :
898 : 0 : return false;
899 : :
900 : 0 : }
901 : : #endif // SIP_RUN
902 : :
903 : :
904 : : #endif
|