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