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