Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgsrendererv2.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines