Quantum GIS API Documentation
1.8
|
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 }