Quantum GIS API Documentation
1.7.4
|
00001 00002 #include "qgsrendererv2.h" 00003 #include "qgssymbolv2.h" 00004 #include "qgssymbollayerv2utils.h" 00005 00006 #include "qgssinglesymbolrendererv2.h" // for default renderer 00007 00008 #include "qgsrendererv2registry.h" 00009 00010 #include "qgsrendercontext.h" 00011 #include "qgsclipper.h" 00012 #include "qgsgeometry.h" 00013 #include "qgsfeature.h" 00014 #include "qgslogger.h" 00015 #include "qgsvectorlayer.h" 00016 00017 #include <QDomElement> 00018 #include <QDomDocument> 00019 #include <QPolygonF> 00020 00021 00022 00023 unsigned char* QgsFeatureRendererV2::_getPoint( QPointF& pt, QgsRenderContext& context, unsigned char* wkb ) 00024 { 00025 wkb++; // jump over endian info 00026 unsigned int wkbType = *(( int* ) wkb ); 00027 wkb += sizeof( unsigned int ); 00028 00029 double x = *(( double * ) wkb ); wkb += sizeof( double ); 00030 double y = *(( double * ) wkb ); wkb += sizeof( double ); 00031 00032 if ( wkbType == QGis::WKBPolygon25D ) 00033 wkb += sizeof( double ); 00034 00035 if ( context.coordinateTransform() ) 00036 { 00037 double z = 0; // dummy variable for coordiante transform 00038 context.coordinateTransform()->transformInPlace( x, y, z ); 00039 } 00040 00041 context.mapToPixel().transformInPlace( x, y ); 00042 00043 pt = QPointF( x, y ); 00044 return wkb; 00045 } 00046 00047 unsigned char* QgsFeatureRendererV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, unsigned char* wkb ) 00048 { 00049 wkb++; // jump over endian info 00050 unsigned int wkbType = *(( int* ) wkb ); 00051 wkb += sizeof( unsigned int ); 00052 unsigned int nPoints = *(( int* ) wkb ); 00053 wkb += sizeof( unsigned int ); 00054 00055 bool hasZValue = ( wkbType == QGis::WKBLineString25D ); 00056 double x, y, z; 00057 00058 const QgsCoordinateTransform* ct = context.coordinateTransform(); 00059 const QgsMapToPixel& mtp = context.mapToPixel(); 00060 00061 //apply clipping for large lines to achieve a better rendering performance 00062 if ( nPoints > 100 ) 00063 { 00064 const QgsRectangle& e = context.extent(); 00065 double cw = e.width() / 10; double ch = e.height() / 10; 00066 QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch ); 00067 wkb = QgsClipper::clippedLineWKB( wkb - ( 2 * sizeof( unsigned int ) + 1 ), clipRect, pts ); 00068 } 00069 else 00070 { 00071 pts.resize( nPoints ); 00072 00073 for ( unsigned int i = 0; i < nPoints; ++i ) 00074 { 00075 x = *(( double * ) wkb ); 00076 wkb += sizeof( double ); 00077 y = *(( double * ) wkb ); 00078 wkb += sizeof( double ); 00079 00080 if ( hasZValue ) // ignore Z value 00081 wkb += sizeof( double ); 00082 00083 pts[i] = QPointF( x, y ); 00084 } 00085 } 00086 00087 //transform the QPolygonF to screen coordinates 00088 for ( int i = 0; i < pts.size(); ++i ) 00089 { 00090 if ( ct ) 00091 { 00092 z = 0; 00093 ct->transformInPlace( pts[i].rx(), pts[i].ry(), z ); 00094 } 00095 mtp.transformInPlace( pts[i].rx(), pts[i].ry() ); 00096 } 00097 00098 00099 return wkb; 00100 } 00101 00102 unsigned char* QgsFeatureRendererV2::_getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, unsigned char* wkb ) 00103 { 00104 wkb++; // jump over endian info 00105 unsigned int wkbType = *(( int* ) wkb ); 00106 wkb += sizeof( unsigned int ); // jump over wkb type 00107 unsigned int numRings = *(( int* ) wkb ); 00108 wkb += sizeof( unsigned int ); 00109 00110 if ( numRings == 0 ) // sanity check for zero rings in polygon 00111 return wkb; 00112 00113 bool hasZValue = ( wkbType == QGis::WKBPolygon25D ); 00114 double x, y; 00115 holes.clear(); 00116 00117 const QgsCoordinateTransform* ct = context.coordinateTransform(); 00118 const QgsMapToPixel& mtp = context.mapToPixel(); 00119 double z = 0; // dummy variable for coordiante transform 00120 00121 const QgsRectangle& e = context.extent(); 00122 double cw = e.width() / 10; double ch = e.height() / 10; 00123 QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch ); 00124 00125 for ( unsigned int idx = 0; idx < numRings; idx++ ) 00126 { 00127 unsigned int nPoints = *(( int* )wkb ); 00128 wkb += sizeof( unsigned int ); 00129 00130 QPolygonF poly( nPoints ); 00131 00132 // Extract the points from the WKB and store in a pair of vectors. 00133 for ( unsigned int jdx = 0; jdx < nPoints; jdx++ ) 00134 { 00135 x = *(( double * ) wkb ); wkb += sizeof( double ); 00136 y = *(( double * ) wkb ); wkb += sizeof( double ); 00137 00138 poly[jdx] = QPointF( x, y ); 00139 00140 if ( hasZValue ) 00141 wkb += sizeof( double ); 00142 } 00143 00144 if ( nPoints < 1 ) 00145 continue; 00146 00147 //clip close to view extent 00148 QgsClipper::trimPolygon( poly, clipRect ); 00149 00150 //transform the QPolygonF to screen coordinates 00151 for ( int i = 0; i < poly.size(); ++i ) 00152 { 00153 if ( ct ) 00154 { 00155 z = 0; 00156 ct->transformInPlace( poly[i].rx(), poly[i].ry(), z ); 00157 } 00158 mtp.transformInPlace( poly[i].rx(), poly[i].ry() ); 00159 } 00160 00161 if ( idx == 0 ) 00162 pts = poly; 00163 else 00164 holes.append( poly ); 00165 } 00166 00167 return wkb; 00168 } 00169 00170 00171 QgsFeatureRendererV2::QgsFeatureRendererV2( QString type ) 00172 : mType( type ), mUsingSymbolLevels( false ), 00173 mCurrentVertexMarkerType( QgsVectorLayer::Cross ), 00174 mCurrentVertexMarkerSize( 3 ) 00175 { 00176 } 00177 00178 QgsFeatureRendererV2* QgsFeatureRendererV2::defaultRenderer( QGis::GeometryType geomType ) 00179 { 00180 return new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geomType ) ); 00181 } 00182 00183 00184 void QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) 00185 { 00186 QgsSymbolV2* symbol = symbolForFeature( feature ); 00187 if ( symbol == NULL ) 00188 return; 00189 00190 QgsSymbolV2::SymbolType symbolType = symbol->type(); 00191 00192 QgsGeometry* geom = feature.geometry(); 00193 switch ( geom->wkbType() ) 00194 { 00195 case QGis::WKBPoint: 00196 case QGis::WKBPoint25D: 00197 { 00198 if ( symbolType != QgsSymbolV2::Marker ) 00199 { 00200 QgsDebugMsg( "point can be drawn only with marker symbol!" ); 00201 break; 00202 } 00203 QPointF pt; 00204 _getPoint( pt, context, geom->asWkb() ); 00205 (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, context, layer, selected ); 00206 00207 //if ( drawVertexMarker ) 00208 // renderVertexMarker( pt, context ); 00209 } 00210 break; 00211 00212 case QGis::WKBLineString: 00213 case QGis::WKBLineString25D: 00214 { 00215 if ( symbolType != QgsSymbolV2::Line ) 00216 { 00217 QgsDebugMsg( "linestring can be drawn only with line symbol!" ); 00218 break; 00219 } 00220 QPolygonF pts; 00221 _getLineString( pts, context, geom->asWkb() ); 00222 (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, context, layer, selected ); 00223 00224 if ( drawVertexMarker ) 00225 renderVertexMarkerPolyline( pts, context ); 00226 } 00227 break; 00228 00229 case QGis::WKBPolygon: 00230 case QGis::WKBPolygon25D: 00231 { 00232 if ( symbolType != QgsSymbolV2::Fill ) 00233 { 00234 QgsDebugMsg( "polygon can be drawn only with fill symbol!" ); 00235 break; 00236 } 00237 QPolygonF pts; 00238 QList<QPolygonF> holes; 00239 _getPolygon( pts, holes, context, geom->asWkb() ); 00240 (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), context, layer, selected ); 00241 00242 if ( drawVertexMarker ) 00243 renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context ); 00244 } 00245 break; 00246 00247 case QGis::WKBMultiPoint: 00248 case QGis::WKBMultiPoint25D: 00249 { 00250 if ( symbolType != QgsSymbolV2::Marker ) 00251 { 00252 QgsDebugMsg( "multi-point can be drawn only with marker symbol!" ); 00253 break; 00254 } 00255 00256 unsigned char* wkb = geom->asWkb(); 00257 unsigned int num = *(( int* )( wkb + 5 ) ); 00258 unsigned char* ptr = wkb + 9; 00259 QPointF pt; 00260 00261 for ( unsigned int i = 0; i < num; ++i ) 00262 { 00263 ptr = _getPoint( pt, context, ptr ); 00264 (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, context, layer, selected ); 00265 00266 //if ( drawVertexMarker ) 00267 // renderVertexMarker( pt, context ); 00268 } 00269 } 00270 break; 00271 00272 case QGis::WKBMultiLineString: 00273 case QGis::WKBMultiLineString25D: 00274 { 00275 if ( symbolType != QgsSymbolV2::Line ) 00276 { 00277 QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" ); 00278 break; 00279 } 00280 00281 unsigned char* wkb = geom->asWkb(); 00282 unsigned int num = *(( int* )( wkb + 5 ) ); 00283 unsigned char* ptr = wkb + 9; 00284 QPolygonF pts; 00285 00286 for ( unsigned int i = 0; i < num; ++i ) 00287 { 00288 ptr = _getLineString( pts, context, ptr ); 00289 (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, context, layer, selected ); 00290 00291 if ( drawVertexMarker ) 00292 renderVertexMarkerPolyline( pts, context ); 00293 } 00294 } 00295 break; 00296 00297 case QGis::WKBMultiPolygon: 00298 case QGis::WKBMultiPolygon25D: 00299 { 00300 if ( symbolType != QgsSymbolV2::Fill ) 00301 { 00302 QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" ); 00303 break; 00304 } 00305 00306 unsigned char* wkb = geom->asWkb(); 00307 unsigned int num = *(( int* )( wkb + 5 ) ); 00308 unsigned char* ptr = wkb + 9; 00309 QPolygonF pts; 00310 QList<QPolygonF> holes; 00311 00312 for ( unsigned int i = 0; i < num; ++i ) 00313 { 00314 ptr = _getPolygon( pts, holes, context, ptr ); 00315 (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), context, layer, selected ); 00316 00317 if ( drawVertexMarker ) 00318 renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context ); 00319 } 00320 } 00321 break; 00322 00323 default: 00324 QgsDebugMsg( "unsupported wkb type for rendering" ); 00325 } 00326 } 00327 00328 QString QgsFeatureRendererV2::dump() 00329 { 00330 return "UNKNOWN RENDERER\n"; 00331 } 00332 00333 00334 QgsFeatureRendererV2* QgsFeatureRendererV2::load( QDomElement& element ) 00335 { 00336 // <renderer-v2 type=""> ... </renderer-v2> 00337 00338 if ( element.isNull() ) 00339 return NULL; 00340 00341 // load renderer 00342 QString rendererType = element.attribute( "type" ); 00343 00344 QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererType ); 00345 if ( m == NULL ) 00346 return NULL; 00347 00348 QgsFeatureRendererV2* r = m->createRenderer( element ); 00349 if ( r ) 00350 { 00351 r->setUsingSymbolLevels( element.attribute( "symbollevels", "0" ).toInt() ); 00352 r->setUsingFirstRule( element.attribute( "firstrule", "0" ).toInt() ); 00353 } 00354 return r; 00355 } 00356 00357 QDomElement QgsFeatureRendererV2::save( QDomDocument& doc ) 00358 { 00359 // create empty renderer element 00360 return doc.createElement( RENDERER_TAG_NAME ); 00361 } 00362 00363 QgsLegendSymbologyList QgsFeatureRendererV2::legendSymbologyItems( QSize iconSize ) 00364 { 00365 // empty list by default 00366 return QgsLegendSymbologyList(); 00367 } 00368 00369 QgsLegendSymbolList QgsFeatureRendererV2::legendSymbolItems() 00370 { 00371 return QgsLegendSymbolList(); 00372 } 00373 00374 void QgsFeatureRendererV2::setVertexMarkerAppearance( int type, int size ) 00375 { 00376 mCurrentVertexMarkerType = type; 00377 mCurrentVertexMarkerSize = size; 00378 } 00379 00380 void QgsFeatureRendererV2::renderVertexMarker( QPointF& pt, QgsRenderContext& context ) 00381 { 00382 QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), 00383 ( QgsVectorLayer::VertexMarkerType ) mCurrentVertexMarkerType, 00384 mCurrentVertexMarkerSize ); 00385 } 00386 00387 void QgsFeatureRendererV2::renderVertexMarkerPolyline( QPolygonF& pts, QgsRenderContext& context ) 00388 { 00389 foreach( QPointF pt, pts ) 00390 renderVertexMarker( pt, context ); 00391 } 00392 00393 void QgsFeatureRendererV2::renderVertexMarkerPolygon( QPolygonF& pts, QList<QPolygonF>* rings, QgsRenderContext& context ) 00394 { 00395 foreach( QPointF pt, pts ) 00396 renderVertexMarker( pt, context ); 00397 00398 if ( rings ) 00399 { 00400 foreach( QPolygonF ring, *rings ) 00401 { 00402 foreach( QPointF pt, ring ) 00403 renderVertexMarker( pt, context ); 00404 } 00405 } 00406 }