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