Quantum GIS API Documentation  1.8
src/core/qgsclipper.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines