|
Quantum GIS API Documentation
master-693a1fe
|
00001 /*************************************************************************** 00002 qgsclipper.h - a class that clips line 00003 segments and polygons 00004 ------------------- 00005 begin : March 2004 00006 copyright : (C) 2005 by Gavin Macaulay 00007 email : 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 #ifndef QGSCLIPPER_H 00020 #define QGSCLIPPER_H 00021 00022 #include "qgis.h" 00023 #include "qgspoint.h" 00024 #include "qgsrectangle.h" 00025 00026 #include <QVector> 00027 #include <QPolygonF> 00028 00039 class CORE_EXPORT QgsClipper 00040 { 00041 public: 00042 00043 // Coordinates of the rectangular box that we trim to. 00044 // 00045 // These are the limits for X11 screen coordinates. The actual 00046 // values are +/-32767, but we allow a little bit of space for 00047 // rounding errors. 00048 00049 // You may wonder why the clipping is done to these coordindates 00050 // rather than the boundaries of the qgis canvas. Reasons include: 00051 // - making the boundaries static const allows the compiler to 00052 // optimise the code that uses these values more than if they changed 00053 // for every call to the trim code. 00054 // - clipping takes quite a bit of CPU effort, and the less that this is 00055 // done the better. More stuff would have to be clipped if the 00056 // boundaries were the qgis canvas (but this may be offset by 00057 // having less to draw). 00058 // 00059 // The limit is set to 30,000 instead of 32768 because that things 00060 // still go wrong. 00061 00062 static const double MAX_X; 00063 static const double MIN_X; 00064 static const double MAX_Y; 00065 static const double MIN_Y; 00066 00067 00068 // A handy way to refer to the four boundaries 00069 enum Boundary {XMax, XMin, YMax, YMin}; 00070 00071 // Trims the given feature to a rectangular box. Returns the trimmed 00072 // feature in x and y. The shapeOpen parameter determines whether 00073 // the function treats the points as a closed shape (polygon), or as 00074 // an open shape (linestring). 00075 static void trimFeature( QVector<double>& x, 00076 QVector<double>& y, 00077 bool shapeOpen ); 00078 00079 static void trimPolygon( QPolygonF& pts, const QgsRectangle& clipRect ); 00080 00085 static unsigned char* clippedLineWKB( unsigned char* wkb, const QgsRectangle& clipExtent, QPolygonF& line ); 00086 00087 private: 00088 00089 // Used when testing for equivalance to 0.0 00090 static const double SMALL_NUM; 00091 00092 // Trims the given feature to the given boundary. Returns the 00093 // trimmed feature in the outX and outY vectors. 00094 static void trimFeatureToBoundary( const QVector<double>& inX, 00095 const QVector<double>& inY, 00096 QVector<double>& outX, 00097 QVector<double>& outY, 00098 Boundary b, 00099 bool shapeOpen ); 00100 00101 static void trimPolygonToBoundary( const QPolygonF& inPts, QPolygonF& outPts, const QgsRectangle& rect, Boundary b, double boundaryValue ); 00102 00103 // Determines if a point is inside or outside the given boundary 00104 static bool inside( const double x, const double y, Boundary b ); 00105 00106 static bool inside( const QPointF& pt, Boundary b, double val ); 00107 00108 // Calculates the intersection point between a line defined by a 00109 // (x1, y1), and (x2, y2) and the given boundary 00110 static QgsPoint intersect( const double x1, const double y1, 00111 const double x2, const double y2, 00112 Boundary b ); 00113 00114 static QPointF intersectRect( const QPointF& pt1, 00115 const QPointF& pt2, 00116 Boundary b, const QgsRectangle& rect ); 00117 00118 //Implementation of 'Fast clipping' algorithm (Sobkow et al. 1987, Computers & Graphics Vol.11, 4, p.459-467) 00119 static bool clipLineSegment( double xLeft, double xRight, double yBottom, double yTop, double& x0, double& y0, double& x1, double& y1 ); 00120 00129 static void connectSeparatedLines( double x0, double y0, double x1, double y1, 00130 const QgsRectangle& clipRect, QPolygonF& pts ); 00131 00132 //low level clip methods for fast clip algorithm 00133 static void clipStartTop( double& x0, double& y0, const double& x1, const double& y1, double yMax ); 00134 static void clipStartBottom( double& x0, double& y0, const double& x1, const double& y1, double yMin ); 00135 static void clipStartRight( double& x0, double& y0, const double& x1, const double& y1, double xMax ); 00136 static void clipStartLeft( double& x0, double& y0, const double& x1, const double& y1, double xMin ); 00137 static void clipEndTop( const double& x0, const double& y0, double& x1, double& y1, double yMax ); 00138 static void clipEndBottom( const double& x0, const double& y0, double& x1, double& y1, double yMin ); 00139 static void clipEndRight( const double& x0, const double& y0, double& x1, double& y1, double xMax ); 00140 static void clipEndLeft( const double& x0, const double& y0, double& x1, double& y1, double xMin ); 00141 }; 00142 00143 // The inline functions 00144 00145 // Trim the feature using Sutherland and Hodgman's 00146 // polygon-clipping algorithm. See J. D. Foley, A. van Dam, 00147 // S. K. Feiner, and J. F. Hughes, Computer Graphics, Principles and 00148 // Practice. Addison-Wesley Systems Programming Series, 00149 // Addison-Wesley, 2nd ed., 1991. 00150 00151 // I understand that this is not the most efficient algorithm, but is 00152 // one (the only?) that is guaranteed to always give the correct 00153 // result. 00154 00155 inline void QgsClipper::trimFeature( QVector<double>& x, 00156 QVector<double>& y, 00157 bool shapeOpen ) 00158 { 00159 QVector<double> tmpX; 00160 QVector<double> tmpY; 00161 trimFeatureToBoundary( x, y, tmpX, tmpY, XMax, shapeOpen ); 00162 00163 x.clear(); 00164 y.clear(); 00165 trimFeatureToBoundary( tmpX, tmpY, x, y, YMax, shapeOpen ); 00166 00167 tmpX.clear(); 00168 tmpY.clear(); 00169 trimFeatureToBoundary( x, y, tmpX, tmpY, XMin, shapeOpen ); 00170 00171 x.clear(); 00172 y.clear(); 00173 trimFeatureToBoundary( tmpX, tmpY, x, y, YMin, shapeOpen ); 00174 } 00175 00176 inline void QgsClipper::trimPolygon( QPolygonF& pts, const QgsRectangle& clipRect ) 00177 { 00178 QPolygonF tmpPts; 00179 tmpPts.reserve( pts.size() ); 00180 00181 trimPolygonToBoundary( pts, tmpPts, clipRect, XMax, clipRect.xMaximum() ); 00182 pts.clear(); 00183 trimPolygonToBoundary( tmpPts, pts, clipRect, YMax, clipRect.yMaximum() ); 00184 tmpPts.clear(); 00185 trimPolygonToBoundary( pts, tmpPts, clipRect, XMin, clipRect.xMinimum() ); 00186 pts.clear(); 00187 trimPolygonToBoundary( tmpPts, pts, clipRect, YMin, clipRect.yMinimum() ); 00188 } 00189 00190 // An auxilary function that is part of the polygon trimming 00191 // code. Will trim the given polygon to the given boundary and return 00192 // the trimmed polygon in the out pointer. Uses Sutherland and 00193 // Hodgman's polygon-clipping algorithm. 00194 00195 inline void QgsClipper::trimFeatureToBoundary( 00196 const QVector<double>& inX, 00197 const QVector<double>& inY, 00198 QVector<double>& outX, 00199 QVector<double>& outY, 00200 Boundary b, bool shapeOpen ) 00201 { 00202 // The shapeOpen parameter selects whether this function treats the 00203 // shape as open or closed. False is appropriate for polygons and 00204 // true for polylines. 00205 00206 int i1 = inX.size() - 1; // start with last point 00207 00208 // and compare to the first point initially. 00209 for ( int i2 = 0; i2 < inX.size() ; ++i2 ) 00210 { 00211 // look at each edge of the polygon in turn 00212 00213 //ignore segments with nan or inf coordinates 00214 if ( qIsNaN( inX[i2] ) || qIsNaN( inY[i2] ) || qIsInf( inX[i2] ) || qIsInf( inY[i2] ) 00215 || qIsNaN( inX[i1] ) || qIsNaN( inY[i1] ) || qIsInf( inX[i1] ) || qIsInf( inY[i1] ) ) 00216 { 00217 i1 = i2; 00218 continue; 00219 } 00220 00221 00222 if ( inside( inX[i2], inY[i2], b ) ) // end point of edge is inside boundary 00223 { 00224 if ( inside( inX[i1], inY[i1], b ) ) 00225 { 00226 outX.push_back( inX[i2] ); 00227 outY.push_back( inY[i2] ); 00228 } 00229 else 00230 { 00231 // edge crosses into the boundary, so trim back to the boundary, and 00232 // store both ends of the new edge 00233 if ( !( i2 == 0 && shapeOpen ) ) 00234 { 00235 QgsPoint p = intersect( inX[i1], inY[i1], inX[i2], inY[i2], b ); 00236 outX.push_back( p.x() ); 00237 outY.push_back( p.y() ); 00238 } 00239 00240 outX.push_back( inX[i2] ); 00241 outY.push_back( inY[i2] ); 00242 } 00243 } 00244 else // end point of edge is outside boundary 00245 { 00246 // start point is in boundary, so need to trim back 00247 if ( inside( inX[i1], inY[i1], b ) ) 00248 { 00249 if ( !( i2 == 0 && shapeOpen ) ) 00250 { 00251 QgsPoint p = intersect( inX[i1], inY[i1], inX[i2], inY[i2], b ); 00252 outX.push_back( p.x() ); 00253 outY.push_back( p.y() ); 00254 } 00255 } 00256 } 00257 i1 = i2; 00258 } 00259 } 00260 00261 inline void QgsClipper::trimPolygonToBoundary( const QPolygonF& inPts, QPolygonF& outPts, const QgsRectangle& rect, Boundary b, double boundaryValue ) 00262 { 00263 int i1 = inPts.size() - 1; // start with last point 00264 00265 // and compare to the first point initially. 00266 for ( int i2 = 0; i2 < inPts.size() ; ++i2 ) 00267 { // look at each edge of the polygon in turn 00268 if ( inside( inPts[i2], b, boundaryValue ) ) // end point of edge is inside boundary 00269 { 00270 if ( inside( inPts[i1], b, boundaryValue ) ) 00271 { 00272 outPts.append( inPts[i2] ); 00273 } 00274 else 00275 { 00276 // edge crosses into the boundary, so trim back to the boundary, and 00277 // store both ends of the new edge 00278 outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) ); 00279 outPts.append( inPts[i2] ); 00280 } 00281 } 00282 else // end point of edge is outside boundary 00283 { 00284 // start point is in boundary, so need to trim back 00285 if ( inside( inPts[i1], b, boundaryValue ) ) 00286 { 00287 outPts.append( intersectRect( inPts[i1], inPts[i2], b, rect ) ); 00288 } 00289 } 00290 i1 = i2; 00291 } 00292 } 00293 00294 // An auxilary function to trimPolygonToBoundarY() that returns 00295 // whether a point is inside or outside the given boundary. 00296 00297 inline bool QgsClipper::inside( const double x, const double y, Boundary b ) 00298 { 00299 switch ( b ) 00300 { 00301 case XMax: // x < MAX_X is inside 00302 if ( x < MAX_X ) 00303 return true; 00304 break; 00305 case XMin: // x > MIN_X is inside 00306 if ( x > MIN_X ) 00307 return true; 00308 break; 00309 case YMax: // y < MAX_Y is inside 00310 if ( y < MAX_Y ) 00311 return true; 00312 break; 00313 case YMin: // y > MIN_Y is inside 00314 if ( y > MIN_Y ) 00315 return true; 00316 break; 00317 } 00318 return false; 00319 } 00320 00321 inline bool QgsClipper::inside( const QPointF& pt, Boundary b, double val ) 00322 { 00323 switch ( b ) 00324 { 00325 case XMax: // x < MAX_X is inside 00326 return ( pt.x() < val ); 00327 case XMin: // x > MIN_X is inside 00328 return ( pt.x() > val ); 00329 case YMax: // y < MAX_Y is inside 00330 return ( pt.y() < val ); 00331 case YMin: // y > MIN_Y is inside 00332 return ( pt.y() > val ); 00333 } 00334 return false; 00335 } 00336 00337 00338 // An auxilary function to trimPolygonToBoundarY() that calculates and 00339 // returns the intersection of the line defined by the given points 00340 // and the given boundary. 00341 00342 inline QgsPoint QgsClipper::intersect( const double x1, const double y1, 00343 const double x2, const double y2, 00344 Boundary b ) 00345 { 00346 // This function assumes that the two given points (x1, y1), and 00347 // (x2, y2) cross the given boundary. Making this assumption allows 00348 // some optimisations. 00349 00350 double r_n = SMALL_NUM, r_d = SMALL_NUM; 00351 00352 switch ( b ) 00353 { 00354 case XMax: // x = MAX_X boundary 00355 r_n = -( x1 - MAX_X ) * ( MAX_Y - MIN_Y ); 00356 r_d = ( x2 - x1 ) * ( MAX_Y - MIN_Y ); 00357 break; 00358 case XMin: // x = MIN_X boundary 00359 r_n = -( x1 - MIN_X ) * ( MAX_Y - MIN_Y ); 00360 r_d = ( x2 - x1 ) * ( MAX_Y - MIN_Y ); 00361 break; 00362 case YMax: // y = MAX_Y boundary 00363 r_n = ( y1 - MAX_Y ) * ( MAX_X - MIN_X ); 00364 r_d = -( y2 - y1 ) * ( MAX_X - MIN_X ); 00365 break; 00366 case YMin: // y = MIN_Y boundary 00367 r_n = ( y1 - MIN_Y ) * ( MAX_X - MIN_X ); 00368 r_d = -( y2 - y1 ) * ( MAX_X - MIN_X ); 00369 break; 00370 } 00371 00372 QgsPoint p; 00373 00374 if ( qAbs( r_d ) > SMALL_NUM && qAbs( r_n ) > SMALL_NUM ) 00375 { // they cross 00376 double r = r_n / r_d; 00377 p.set( x1 + r*( x2 - x1 ), y1 + r*( y2 - y1 ) ); 00378 } 00379 else 00380 { 00381 // Should never get here, but if we do for some reason, cause a 00382 // clunk because something else is wrong if we do. 00383 Q_ASSERT( qAbs( r_d ) > SMALL_NUM && qAbs( r_n ) > SMALL_NUM ); 00384 } 00385 00386 return p; 00387 } 00388 00389 inline QPointF QgsClipper::intersectRect( const QPointF& pt1, 00390 const QPointF& pt2, 00391 Boundary b, const QgsRectangle& rect ) 00392 { 00393 // This function assumes that the two given points (x1, y1), and 00394 // (x2, y2) cross the given boundary. Making this assumption allows 00395 // some optimisations. 00396 00397 double r_n = SMALL_NUM, r_d = SMALL_NUM; 00398 const double x1 = pt1.x(), x2 = pt2.x(); 00399 const double y1 = pt1.y(), y2 = pt2.y(); 00400 00401 switch ( b ) 00402 { 00403 case XMax: // x = MAX_X boundary 00404 r_n = -( x1 - rect.xMaximum() ) * ( rect.yMaximum() - rect.yMinimum() ); 00405 r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() ); 00406 break; 00407 case XMin: // x = MIN_X boundary 00408 r_n = -( x1 - rect.xMinimum() ) * ( rect.yMaximum() - rect.yMinimum() ); 00409 r_d = ( x2 - x1 ) * ( rect.yMaximum() - rect.yMinimum() ); 00410 break; 00411 case YMax: // y = MAX_Y boundary 00412 r_n = ( y1 - rect.yMaximum() ) * ( rect.xMaximum() - rect.xMinimum() ); 00413 r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() ); 00414 break; 00415 case YMin: // y = MIN_Y boundary 00416 r_n = ( y1 - rect.yMinimum() ) * ( rect.xMaximum() - rect.xMinimum() ); 00417 r_d = -( y2 - y1 ) * ( rect.xMaximum() - rect.xMinimum() ); 00418 break; 00419 } 00420 00421 double r = 0; 00422 if ( !qgsDoubleNear( r_d, 0.0 ) ) 00423 { 00424 r = r_n / r_d; 00425 } 00426 return QPointF( x1 + r*( x2 - x1 ), y1 + r*( y2 - y1 ) ); 00427 } 00428 00429 inline void QgsClipper::clipStartTop( double& x0, double& y0, const double& x1, const double& y1, double yMax ) 00430 { 00431 x0 += ( x1 - x0 ) * ( yMax - y0 ) / ( y1 - y0 ); 00432 y0 = yMax; 00433 } 00434 00435 inline void QgsClipper::clipStartBottom( double& x0, double& y0, const double& x1, const double& y1, double yMin ) 00436 { 00437 x0 += ( x1 - x0 ) * ( yMin - y0 ) / ( y1 - y0 ); 00438 y0 = yMin; 00439 } 00440 00441 inline void QgsClipper::clipStartRight( double& x0, double& y0, const double& x1, const double& y1, double xMax ) 00442 { 00443 y0 += ( y1 - y0 ) * ( xMax - x0 ) / ( x1 - x0 ); 00444 x0 = xMax; 00445 } 00446 00447 inline void QgsClipper::clipStartLeft( double& x0, double& y0, const double& x1, const double& y1, double xMin ) 00448 { 00449 y0 += ( y1 - y0 ) * ( xMin - x0 ) / ( x1 - x0 ); 00450 x0 = xMin; 00451 } 00452 00453 inline void QgsClipper::clipEndTop( const double& x0, const double& y0, double& x1, double& y1, double yMax ) 00454 { 00455 x1 += ( x1 - x0 ) * ( yMax - y1 ) / ( y1 - y0 ); 00456 y1 = yMax; 00457 } 00458 00459 inline void QgsClipper::clipEndBottom( const double& x0, const double& y0, double& x1, double& y1, double yMin ) 00460 { 00461 x1 += ( x1 - x0 ) * ( yMin - y1 ) / ( y1 - y0 ); 00462 y1 = yMin; 00463 } 00464 00465 inline void QgsClipper::clipEndRight( const double& x0, const double& y0, double& x1, double& y1, double xMax ) 00466 { 00467 y1 += ( y1 - y0 ) * ( xMax - x1 ) / ( x1 - x0 ); 00468 x1 = xMax; 00469 } 00470 00471 inline void QgsClipper::clipEndLeft( const double& x0, const double& y0, double& x1, double& y1, double xMin ) 00472 { 00473 y1 += ( y1 - y0 ) * ( xMin - x1 ) / ( x1 - x0 ); 00474 x1 = xMin; 00475 } 00476 00477 //'Fast clipping' algorithm (Sobkow et al. 1987, Computers & Graphics Vol.11, 4, p.459-467) 00478 inline bool QgsClipper::clipLineSegment( double xLeft, double xRight, double yBottom, double yTop, double& x0, double& y0, double& x1, double& y1 ) 00479 { 00480 int lineCode = 0; 00481 00482 if ( y1 < yBottom ) 00483 lineCode |= 4; 00484 else if ( y1 > yTop ) 00485 lineCode |= 8; 00486 00487 if ( x1 > xRight ) 00488 lineCode |= 2; 00489 else if ( x1 < xLeft ) 00490 lineCode |= 1; 00491 00492 if ( y0 < yBottom ) 00493 lineCode |= 64; 00494 else if ( y0 > yTop ) 00495 lineCode |= 128; 00496 00497 if ( x0 > xRight ) 00498 lineCode |= 32; 00499 else if ( x0 < xLeft ) 00500 lineCode |= 16; 00501 00502 switch ( lineCode ) 00503 { 00504 case 0: //completely inside 00505 return true; 00506 00507 case 1: 00508 clipEndLeft( x0, y0, x1, y1, xLeft ); 00509 return true; 00510 00511 case 2: 00512 clipEndRight( x0, y0, x1, y1, xRight ); 00513 return true; 00514 00515 case 4: 00516 clipEndBottom( x0, y0, x1, y1, yBottom ); 00517 return true; 00518 00519 case 5: 00520 clipEndLeft( x0, y0, x1, y1, xLeft ); 00521 if ( y1 < yBottom ) 00522 clipEndBottom( x0, y0, x1, y1, yBottom ); 00523 return true; 00524 00525 case 6: 00526 clipEndRight( x0, y0, x1, y1, xRight ); 00527 if ( y1 < yBottom ) 00528 clipEndBottom( x0, y0, x1, y1, yBottom ); 00529 return true; 00530 00531 case 8: 00532 clipEndTop( x0, y0, x1, y1, yTop ); 00533 return true; 00534 00535 case 9: 00536 clipEndLeft( x0, y0, x1, y1, xLeft ); 00537 if ( y1 > yTop ) 00538 clipEndTop( x0, y0, x1, y1, yTop ); 00539 return true; 00540 00541 case 10: 00542 clipEndRight( x0, y0, x1, y1, xRight ); 00543 if ( y1 > yTop ) 00544 clipEndTop( x0, y0, x1, y1, yTop ); 00545 return true; 00546 00547 case 16: 00548 clipStartLeft( x0, y0, x1, y1, xLeft ); 00549 return true; 00550 00551 case 18: 00552 clipStartLeft( x0, y0, x1, y1, xLeft ); 00553 clipEndRight( x0, y0, x1, y1, xRight ); 00554 return true; 00555 00556 case 20: 00557 clipStartLeft( x0, y0, x1, y1, xLeft ); 00558 if ( y0 < yBottom ) 00559 return false; 00560 clipEndBottom( x0, y0, x1, y1, yBottom ); 00561 return true; 00562 00563 case 22: 00564 clipStartLeft( x0, y0, x1, y1, xLeft ); 00565 if ( y0 < yBottom ) 00566 return false; 00567 clipEndBottom( x0, y0, x1, y1, yBottom ); 00568 if ( x1 > xRight ) 00569 clipEndRight( x0, y0, x1, y1, xRight ); 00570 return true; 00571 00572 case 24: 00573 clipStartLeft( x0, y0, x1, y1, xLeft ); 00574 if ( y0 > yTop ) 00575 return false; 00576 clipEndTop( x0, y0, x1, y1, yTop ); 00577 return true; 00578 00579 case 26: 00580 clipStartLeft( x0, y0, x1, y1, xLeft ); 00581 if ( y0 > yTop ) 00582 return false; 00583 clipEndTop( x0, y0, x1, y1, yTop ); 00584 if ( x1 > xRight ) 00585 clipEndRight( x0, y0, x1, y1, xRight ); 00586 return true; 00587 00588 case 32: 00589 clipStartRight( x0, y0, x1, y1, xRight ); 00590 return true; 00591 00592 case 33: 00593 clipStartRight( x0, y0, x1, y1, xRight ); 00594 clipEndLeft( x0, y0, x1, y1, xLeft ); 00595 return true; 00596 00597 case 36: 00598 clipStartRight( x0, y0, x1, y1, xRight ); 00599 if ( y0 < yBottom ) 00600 return false; 00601 clipEndBottom( x0, y0, x1, y1, yBottom ); 00602 return true; 00603 00604 case 37: 00605 clipStartRight( x0, y0, x1, y1, xRight ); 00606 if ( y0 < yBottom ) 00607 return false; 00608 clipEndBottom( x0, y0, x1, y1, yBottom ); 00609 if ( x1 < xLeft ) 00610 clipEndLeft( x0, y0, x1, y1, xLeft ); 00611 return true; 00612 00613 case 40: 00614 clipStartRight( x0, y0, x1, y1, xRight ); 00615 if ( y0 > yTop ) 00616 return false; 00617 clipEndTop( x0, y0, x1, y1, yTop ); 00618 return true; 00619 00620 case 41: 00621 clipStartRight( x0, y0, x1, y1, xRight ); 00622 if ( y0 > yTop ) 00623 return false; 00624 clipEndTop( x0, y0, x1, y1, yTop ); 00625 if ( x1 < xLeft ) 00626 clipEndLeft( x0, y0, x1, y1, xLeft ); 00627 return true; 00628 00629 case 64: 00630 clipStartBottom( x0, y0, x1, y1, yBottom ); 00631 return true; 00632 00633 case 65: 00634 clipStartBottom( x0, y0, x1, y1, yBottom ); 00635 if ( x0 < xLeft ) 00636 return false; 00637 clipEndLeft( x0, y0, x1, y1, xLeft ); 00638 if ( y1 < yBottom ) 00639 clipEndBottom( x0, y0, x1, y1, yBottom ); 00640 return true; 00641 00642 case 66: 00643 clipStartBottom( x0, y0, x1, y1, yBottom ); 00644 if ( x0 > xRight ) 00645 return false; 00646 clipEndRight( x0, y0, x1, y1, xRight ); 00647 return true; 00648 00649 case 72: 00650 clipStartBottom( x0, y0, x1, y1, yBottom ); 00651 clipEndTop( x0, y0, x1, y1, yTop ); 00652 return true; 00653 00654 case 73: 00655 clipStartBottom( x0, y0, x1, y1, yBottom ); 00656 if ( x0 < xLeft ) 00657 return false; 00658 clipEndLeft( x0, y0, x1, y1, xLeft ); 00659 if ( y1 > yTop ) 00660 clipEndTop( x0, y0, x1, y1, yTop ); 00661 return true; 00662 00663 case 74: 00664 clipStartBottom( x0, y0, x1, y1, yBottom ); 00665 if ( x0 > xRight ) 00666 return false; 00667 clipEndRight( x0, y0, x1, y1, xRight ); 00668 if ( y1 > yTop ) 00669 clipEndTop( x0, y0, x1, y1, yTop ); 00670 return true; 00671 00672 case 80: 00673 clipStartLeft( x0, y0, x1, y1, xLeft ); 00674 if ( y0 < yBottom ) 00675 clipStartBottom( x0, y0, x1, y1, yBottom ); 00676 return true; 00677 00678 case 82: 00679 clipEndRight( x0, y0, x1, y1, xRight ); 00680 if ( y1 < yBottom ) 00681 return false; 00682 clipStartBottom( x0, y0, x1, y1, yBottom ); 00683 if ( x0 < xLeft ) 00684 clipStartLeft( x0, y0, x1, y1, xLeft ); 00685 return true; 00686 00687 case 88: 00688 clipEndTop( x0, y0, x1, y1, yTop ); 00689 if ( x1 < xLeft ) 00690 return false; 00691 clipStartBottom( x0, y0, x1, y1, yBottom ); 00692 if ( x0 < xLeft ) 00693 clipStartLeft( x0, y0, x1, y1, xLeft ); 00694 return true; 00695 00696 case 90: 00697 clipStartLeft( x0, y0, x1, y1, xLeft ); 00698 if ( y0 > yTop ) 00699 return false; 00700 clipEndRight( x0, y0, x1, y1, xRight ); 00701 if ( y1 < yBottom ) 00702 return false; 00703 if ( y0 < yBottom ) 00704 clipStartBottom( x0, y0, x1, y1, yBottom ); 00705 if ( y1 > yTop ) 00706 clipEndTop( x0, y0, x1, y1, yTop ); 00707 return true; 00708 00709 case 96: 00710 clipStartRight( x0, y0, x1, y1, xRight ); 00711 if ( y0 < yBottom ) 00712 clipStartBottom( x0, y0, x1, y1, yBottom ); 00713 return true; 00714 00715 case 97: 00716 clipEndLeft( x0, y0, x1, y1, xLeft ); 00717 if ( y1 < yBottom ) 00718 return false; 00719 clipStartBottom( x0, y0, x1, y1, yBottom ); 00720 if ( x0 > xRight ) 00721 clipStartRight( x0, y0, x1, y1, xRight ); 00722 return true; 00723 00724 case 104: 00725 clipEndTop( x0, y0, x1, y1, yTop ); 00726 if ( x1 > xRight ) 00727 return false; 00728 clipStartRight( x0, y0, x1, y1, xRight ); 00729 if ( y0 < yBottom ) 00730 clipStartBottom( x0, y0, x1, y1, yBottom ); 00731 return true; 00732 00733 case 105: 00734 clipEndLeft( x0, y0, x1, y1, xLeft ); 00735 if ( y1 < yBottom ) 00736 return false; 00737 clipStartRight( x0, y0, x1, y1, xRight ); 00738 if ( y0 > yTop ) 00739 return false; 00740 if ( y1 > yTop ) 00741 clipEndTop( x0, y0, x1, y1, yTop ); 00742 if ( y0 < yBottom ) 00743 clipStartBottom( x0, y0, x1, y1, yBottom ); 00744 return true; 00745 00746 case 128: 00747 clipStartTop( x0, y0, x1, y1, yTop ); 00748 return true; 00749 00750 case 129: 00751 clipStartTop( x0, y0, x1, y1, yTop ); 00752 if ( x0 < xLeft ) 00753 return false; 00754 clipEndLeft( x0, y0, x1, y1, xLeft ); 00755 return true; 00756 00757 case 130: 00758 clipStartTop( x0, y0, x1, y1, yTop ); 00759 if ( x0 > xRight ) 00760 return false; 00761 clipEndRight( x0, y0, x1, y1, xRight ); 00762 return true; 00763 00764 case 132: 00765 clipStartTop( x0, y0, x1, y1, yTop ); 00766 clipEndBottom( x0, y0, x1, y1, yBottom ); 00767 return true; 00768 00769 case 133: 00770 clipStartTop( x0, y0, x1, y1, yTop ); 00771 if ( x0 < xLeft ) 00772 return false; 00773 clipEndLeft( x0, y0, x1, y1, xLeft ); 00774 if ( y1 < yBottom ) 00775 clipEndBottom( x0, y0, x1, y1, yBottom ); 00776 return true; 00777 00778 case 134: 00779 clipStartTop( x0, y0, x1, y1, yTop ); 00780 if ( x0 > xRight ) 00781 return false; 00782 clipEndRight( x0, y0, x1, y1, xRight ); 00783 if ( y1 < yBottom ) 00784 clipEndBottom( x0, y0, x1, y1, yBottom ); 00785 return true; 00786 00787 case 144: 00788 clipStartLeft( x0, y0, x1, y1, xLeft ); 00789 if ( y0 > yTop ) 00790 clipStartTop( x0, y0, x1, y1, yTop ); 00791 return true; 00792 00793 case 146: 00794 clipEndRight( x0, y0, x1, y1, xRight ); 00795 if ( y1 > yTop ) 00796 return false; 00797 clipStartTop( x0, y0, x1, y1, yTop ); 00798 if ( x0 < xLeft ) 00799 clipStartLeft( x0, y0, x1, y1, xLeft ); 00800 return true; 00801 00802 case 148: 00803 clipEndBottom( x0, y0, x1, y1, yBottom ); 00804 if ( x1 < xLeft ) 00805 return false; 00806 clipStartLeft( x0, y0, x1, y1, xLeft ); 00807 if ( y0 > yTop ) 00808 clipStartTop( x0, y0, x1, y1, yTop ); 00809 return true; 00810 00811 case 150: 00812 clipStartLeft( x0, y0, x1, y1, xLeft ); 00813 if ( y0 < yBottom ) 00814 return false; 00815 clipEndRight( x0, y0, x1, y1, xRight ); 00816 if ( y1 > yTop ) 00817 return false; 00818 if ( y0 > yTop ) 00819 clipStartTop( x0, y0, x1, y1, yTop ); 00820 if ( y1 < yBottom ) 00821 clipEndBottom( x0, y0, x1, y1, yBottom ); 00822 return true; 00823 00824 case 160: 00825 clipStartRight( x0, y0, x1, y1, xRight ); 00826 if ( y0 > yTop ) 00827 clipStartTop( x0, y0, x1, y1, yTop ); 00828 return true; 00829 00830 case 161: 00831 clipEndLeft( x0, y0, x1, y1, xLeft ); 00832 if ( y1 > yTop ) 00833 return false; 00834 clipStartTop( x0, y0, x1, y1, yTop ); 00835 if ( x0 > xRight ) 00836 clipStartRight( x0, y0, x1, y1, xRight ); 00837 return true; 00838 00839 case 164: 00840 clipEndBottom( x0, y0, x1, y1, yBottom ); 00841 if ( x1 > xRight ) 00842 return false; 00843 clipStartRight( x0, y0, x1, y1, xRight ); 00844 if ( y0 > yTop ) 00845 clipStartTop( x0, y0, x1, y1, yTop ); 00846 return true; 00847 00848 case 165: 00849 clipEndLeft( x0, y0, x1, y1, xLeft ); 00850 if ( y1 > yTop ) 00851 return false; 00852 clipStartRight( x0, y0, x1, y1, xRight ); 00853 if ( y0 < yBottom ) 00854 return false; 00855 if ( y1 < yBottom ) 00856 clipEndBottom( x0, y0, x1, y1, yBottom ); 00857 if ( y0 > yTop ) 00858 clipStartTop( x0, y0, x1, y1, yTop ); 00859 return true; 00860 } 00861 00862 return false; 00863 00864 } 00865 00866 00867 #endif