Quantum GIS API Documentation  1.7.4
src/core/qgsclipper.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsclipper.cpp  -  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 /* $Id$ */
00019 
00020 #include "qgsclipper.h"
00021 
00022 // Where has all the code gone?
00023 
00024 // It's been inlined, so its in the qgsclipper.h file.
00025 
00026 // But the static members must be initialised outside the class! (or GCC 4 dies)
00027 
00028 // Qt also does clipping when the coordinates go over +/- 32767
00029 // moreover from Qt 4.6, Qt clips also when the width/height of a painter path
00030 // is more than 32767. Since we want to avoid clipping by Qt (because it is slow)
00031 // we set coordinate limit to less than 32767 / 2
00032 const double QgsClipper::MAX_X =  16000;
00033 const double QgsClipper::MIN_X = -16000;
00034 const double QgsClipper::MAX_Y =  16000;
00035 const double QgsClipper::MIN_Y = -16000;
00036 
00037 const double QgsClipper::SMALL_NUM = 1e-12;
00038 
00039 unsigned char* QgsClipper::clippedLineWKB( unsigned char* wkb, const QgsRectangle& clipExtent, QPolygonF& line )
00040 {
00041   wkb++; // jump over endian info
00042   unsigned int wkbType = *(( int* ) wkb );
00043   wkb += sizeof( unsigned int );
00044   unsigned int nPoints = *(( int* ) wkb );
00045   wkb += sizeof( unsigned int );
00046 
00047   bool hasZValue = ( wkbType == QGis::WKBLineString25D );
00048 
00049   double p0x, p0y, p1x, p1y; //original coordinates
00050   double p1x_c, p1y_c; //clipped end coordinates
00051   double lastClipX, lastClipY; //last successfully clipped coords
00052 
00053   line.reserve( nPoints + 1 );
00054   line.clear();
00055 
00056   for ( unsigned int i = 0; i < nPoints; ++i )
00057   {
00058     if ( i == 0 )
00059     {
00060       memcpy( &p1x, wkb, sizeof( double ) );
00061       wkb += sizeof( double );
00062       memcpy( &p1y, wkb, sizeof( double ) );
00063       wkb += sizeof( double );
00064       if ( hasZValue ) // ignore Z value
00065       {
00066         wkb += sizeof( double );
00067       }
00068       continue;
00069     }
00070     else
00071     {
00072       p0x = p1x;
00073       p0y = p1y;
00074 
00075       memcpy( &p1x, wkb, sizeof( double ) );
00076       wkb += sizeof( double );
00077       memcpy( &p1y, wkb, sizeof( double ) );
00078       wkb += sizeof( double );
00079       if ( hasZValue ) // ignore Z value
00080       {
00081         wkb += sizeof( double );
00082       }
00083 
00084       p1x_c = p1x; p1y_c = p1y;
00085       if ( clipLineSegment( clipExtent.xMinimum(), clipExtent.xMaximum(), clipExtent.yMinimum(), clipExtent.yMaximum(),
00086                             p0x, p0y, p1x_c,  p1y_c ) )
00087       {
00088         bool newLine = line.size() > 0 && ( p0x != lastClipX || p0y != lastClipY );
00089         if ( newLine )
00090         {
00091           //add edge points to connect old and new line
00092           connectSeparatedLines( lastClipX, lastClipY, p0x, p0y, clipExtent, line );
00093         }
00094         if ( line.size() < 1 || newLine )
00095         {
00096           //add first point
00097           line << QPointF( p0x, p0y );
00098         }
00099 
00100         //add second point
00101         lastClipX = p1x_c; lastClipY = p1y_c;
00102         line << QPointF( p1x_c,  p1y_c );
00103       }
00104     }
00105   }
00106   return wkb;
00107 }
00108 
00109 void QgsClipper::connectSeparatedLines( double x0, double y0, double x1, double y1,
00110                                         const QgsRectangle& clipRect, QPolygonF& pts )
00111 {
00112   //test the different edge combinations...
00113   if ( doubleNear( x0, clipRect.xMinimum() ) )
00114   {
00115     if ( doubleNear( x1, clipRect.xMinimum() ) )
00116     {
00117       return;
00118     }
00119     else if ( doubleNear( y1, clipRect.yMaximum() ) )
00120     {
00121       pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
00122       return;
00123     }
00124     else if ( doubleNear( x1, clipRect.xMaximum() ) )
00125     {
00126       pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
00127       pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
00128       return;
00129     }
00130     else if ( doubleNear( y1, clipRect.yMinimum() ) )
00131     {
00132       pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
00133       return;
00134     }
00135   }
00136   else if ( doubleNear( y0, clipRect.yMaximum() ) )
00137   {
00138     if ( doubleNear( y1, clipRect.yMaximum() ) )
00139     {
00140       return;
00141     }
00142     else if ( doubleNear( x1, clipRect.xMaximum() ) )
00143     {
00144       pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
00145       return;
00146     }
00147     else if ( doubleNear( y1, clipRect.yMinimum() ) )
00148     {
00149       pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
00150       pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
00151       return;
00152     }
00153     else if ( doubleNear( x1, clipRect.xMinimum() ) )
00154     {
00155       pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
00156       return;
00157     }
00158   }
00159   else if ( doubleNear( x0, clipRect.xMaximum() ) )
00160   {
00161     if ( doubleNear( x1, clipRect.xMaximum() ) )
00162     {
00163       return;
00164     }
00165     else if ( doubleNear( y1, clipRect.yMinimum() ) )
00166     {
00167       pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
00168       return;
00169     }
00170     else if ( doubleNear( x1, clipRect.xMinimum() ) )
00171     {
00172       pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
00173       pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
00174       return;
00175     }
00176     else if ( doubleNear( y1, clipRect.yMaximum() ) )
00177     {
00178       pts << QPointF( clipRect.xMaximum(), clipRect.yMaximum() );
00179       return;
00180     }
00181   }
00182   else if ( doubleNear( y0, clipRect.yMinimum() ) )
00183   {
00184     if ( doubleNear( y1, clipRect.yMinimum() ) )
00185     {
00186       return;
00187     }
00188     else if ( doubleNear( x1, clipRect.xMinimum() ) )
00189     {
00190       pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
00191       return;
00192     }
00193     else if ( doubleNear( y1, clipRect.yMaximum() ) )
00194     {
00195       pts << QPointF( clipRect.xMinimum(), clipRect.yMinimum() );
00196       pts << QPointF( clipRect.xMinimum(), clipRect.yMaximum() );
00197       return;
00198     }
00199     else if ( doubleNear( x1, clipRect.xMaximum() ) )
00200     {
00201       pts << QPointF( clipRect.xMaximum(), clipRect.yMinimum() );
00202       return;
00203     }
00204   }
00205 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines