00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "qgsrendererv2.h"
00017 #include "qgssymbolv2.h"
00018 #include "qgssymbollayerv2utils.h"
00019
00020 #include "qgssinglesymbolrendererv2.h"
00021
00022 #include "qgsrendererv2registry.h"
00023
00024 #include "qgsrendercontext.h"
00025 #include "qgsclipper.h"
00026 #include "qgsgeometry.h"
00027 #include "qgsfeature.h"
00028 #include "qgslogger.h"
00029 #include "qgsvectorlayer.h"
00030
00031 #include <QDomElement>
00032 #include <QDomDocument>
00033 #include <QPolygonF>
00034
00035
00036
00037 unsigned char* QgsFeatureRendererV2::_getPoint( QPointF& pt, QgsRenderContext& context, unsigned char* wkb )
00038 {
00039 wkb++;
00040 unsigned int wkbType = *(( int* ) wkb );
00041 wkb += sizeof( unsigned int );
00042
00043 double x = *(( double * ) wkb ); wkb += sizeof( double );
00044 double y = *(( double * ) wkb ); wkb += sizeof( double );
00045
00046 if ( wkbType == QGis::WKBPolygon25D )
00047 wkb += sizeof( double );
00048
00049 if ( context.coordinateTransform() )
00050 {
00051 double z = 0;
00052 context.coordinateTransform()->transformInPlace( x, y, z );
00053 }
00054
00055 context.mapToPixel().transformInPlace( x, y );
00056
00057 pt = QPointF( x, y );
00058 return wkb;
00059 }
00060
00061 unsigned char* QgsFeatureRendererV2::_getLineString( QPolygonF& pts, QgsRenderContext& context, unsigned char* wkb )
00062 {
00063 wkb++;
00064 unsigned int wkbType = *(( int* ) wkb );
00065 wkb += sizeof( unsigned int );
00066 unsigned int nPoints = *(( int* ) wkb );
00067 wkb += sizeof( unsigned int );
00068
00069 bool hasZValue = ( wkbType == QGis::WKBLineString25D );
00070 double x, y;
00071 #ifdef ANDROID
00072 qreal z;
00073 #else
00074 double z;
00075 #endif //ANDROID
00076 const QgsCoordinateTransform* ct = context.coordinateTransform();
00077 const QgsMapToPixel& mtp = context.mapToPixel();
00078
00079
00080 if ( nPoints > 100 )
00081 {
00082 const QgsRectangle& e = context.extent();
00083 double cw = e.width() / 10; double ch = e.height() / 10;
00084 QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
00085 wkb = QgsClipper::clippedLineWKB( wkb - ( 2 * sizeof( unsigned int ) + 1 ), clipRect, pts );
00086 }
00087 else
00088 {
00089 pts.resize( nPoints );
00090
00091 for ( unsigned int i = 0; i < nPoints; ++i )
00092 {
00093 x = *(( double * ) wkb );
00094 wkb += sizeof( double );
00095 y = *(( double * ) wkb );
00096 wkb += sizeof( double );
00097
00098 if ( hasZValue )
00099 wkb += sizeof( double );
00100
00101 pts[i] = QPointF( x, y );
00102 }
00103 }
00104
00105
00106 for ( int i = 0; i < pts.size(); ++i )
00107 {
00108 if ( ct )
00109 {
00110 z = 0;
00111 ct->transformInPlace( pts[i].rx(), pts[i].ry(), z );
00112 }
00113 mtp.transformInPlace( pts[i].rx(), pts[i].ry() );
00114 }
00115
00116
00117 return wkb;
00118 }
00119
00120 unsigned char* QgsFeatureRendererV2::_getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, unsigned char* wkb )
00121 {
00122 wkb++;
00123 unsigned int wkbType = *(( int* ) wkb );
00124 wkb += sizeof( unsigned int );
00125 unsigned int numRings = *(( int* ) wkb );
00126 wkb += sizeof( unsigned int );
00127
00128 if ( numRings == 0 )
00129 return wkb;
00130
00131 bool hasZValue = ( wkbType == QGis::WKBPolygon25D );
00132 double x, y;
00133 holes.clear();
00134
00135 const QgsCoordinateTransform* ct = context.coordinateTransform();
00136 const QgsMapToPixel& mtp = context.mapToPixel();
00137 #ifdef ANDROID
00138 qreal z = 0;
00139 #else
00140 double z = 0;
00141 #endif
00142 const QgsRectangle& e = context.extent();
00143 double cw = e.width() / 10; double ch = e.height() / 10;
00144 QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
00145
00146 for ( unsigned int idx = 0; idx < numRings; idx++ )
00147 {
00148 unsigned int nPoints = *(( int* )wkb );
00149 wkb += sizeof( unsigned int );
00150
00151 QPolygonF poly( nPoints );
00152
00153
00154 for ( unsigned int jdx = 0; jdx < nPoints; jdx++ )
00155 {
00156 x = *(( double * ) wkb ); wkb += sizeof( double );
00157 y = *(( double * ) wkb ); wkb += sizeof( double );
00158
00159 poly[jdx] = QPointF( x, y );
00160
00161 if ( hasZValue )
00162 wkb += sizeof( double );
00163 }
00164
00165 if ( nPoints < 1 )
00166 continue;
00167
00168
00169 QgsClipper::trimPolygon( poly, clipRect );
00170
00171
00172 for ( int i = 0; i < poly.size(); ++i )
00173 {
00174 if ( ct )
00175 {
00176 z = 0;
00177 ct->transformInPlace( poly[i].rx(), poly[i].ry(), z );
00178 }
00179 mtp.transformInPlace( poly[i].rx(), poly[i].ry() );
00180 }
00181
00182 if ( idx == 0 )
00183 pts = poly;
00184 else
00185 holes.append( poly );
00186 }
00187
00188 return wkb;
00189 }
00190
00191
00192 QgsFeatureRendererV2::QgsFeatureRendererV2( QString type )
00193 : mType( type ), mUsingSymbolLevels( false ),
00194 mCurrentVertexMarkerType( QgsVectorLayer::Cross ),
00195 mCurrentVertexMarkerSize( 3 )
00196 {
00197 }
00198
00199 QgsFeatureRendererV2* QgsFeatureRendererV2::defaultRenderer( QGis::GeometryType geomType )
00200 {
00201 return new QgsSingleSymbolRendererV2( QgsSymbolV2::defaultSymbol( geomType ) );
00202 }
00203
00204
00205 bool QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
00206 {
00207 QgsSymbolV2* symbol = symbolForFeature( feature );
00208 if ( symbol == NULL )
00209 return false;
00210
00211 renderFeatureWithSymbol( feature, symbol, context, layer, selected, drawVertexMarker );
00212 return true;
00213 }
00214
00215 void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
00216 {
00217 QgsSymbolV2::SymbolType symbolType = symbol->type();
00218
00219 QgsGeometry* geom = feature.geometry();
00220 switch ( geom->wkbType() )
00221 {
00222 case QGis::WKBPoint:
00223 case QGis::WKBPoint25D:
00224 {
00225 if ( symbolType != QgsSymbolV2::Marker )
00226 {
00227 QgsDebugMsg( "point can be drawn only with marker symbol!" );
00228 break;
00229 }
00230 QPointF pt;
00231 _getPoint( pt, context, geom->asWkb() );
00232 (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected );
00233
00234
00235
00236 }
00237 break;
00238
00239 case QGis::WKBLineString:
00240 case QGis::WKBLineString25D:
00241 {
00242 if ( symbolType != QgsSymbolV2::Line )
00243 {
00244 QgsDebugMsg( "linestring can be drawn only with line symbol!" );
00245 break;
00246 }
00247 QPolygonF pts;
00248 _getLineString( pts, context, geom->asWkb() );
00249 (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected );
00250
00251 if ( drawVertexMarker )
00252 renderVertexMarkerPolyline( pts, context );
00253 }
00254 break;
00255
00256 case QGis::WKBPolygon:
00257 case QGis::WKBPolygon25D:
00258 {
00259 if ( symbolType != QgsSymbolV2::Fill )
00260 {
00261 QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
00262 break;
00263 }
00264 QPolygonF pts;
00265 QList<QPolygonF> holes;
00266 _getPolygon( pts, holes, context, geom->asWkb() );
00267 (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected );
00268
00269 if ( drawVertexMarker )
00270 renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context );
00271 }
00272 break;
00273
00274 case QGis::WKBMultiPoint:
00275 case QGis::WKBMultiPoint25D:
00276 {
00277 if ( symbolType != QgsSymbolV2::Marker )
00278 {
00279 QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
00280 break;
00281 }
00282
00283 unsigned char* wkb = geom->asWkb();
00284 unsigned int num = *(( int* )( wkb + 5 ) );
00285 unsigned char* ptr = wkb + 9;
00286 QPointF pt;
00287
00288 for ( unsigned int i = 0; i < num; ++i )
00289 {
00290 ptr = _getPoint( pt, context, ptr );
00291 (( QgsMarkerSymbolV2* )symbol )->renderPoint( pt, &feature, context, layer, selected );
00292
00293
00294
00295 }
00296 }
00297 break;
00298
00299 case QGis::WKBMultiLineString:
00300 case QGis::WKBMultiLineString25D:
00301 {
00302 if ( symbolType != QgsSymbolV2::Line )
00303 {
00304 QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
00305 break;
00306 }
00307
00308 unsigned char* wkb = geom->asWkb();
00309 unsigned int num = *(( int* )( wkb + 5 ) );
00310 unsigned char* ptr = wkb + 9;
00311 QPolygonF pts;
00312
00313 for ( unsigned int i = 0; i < num; ++i )
00314 {
00315 ptr = _getLineString( pts, context, ptr );
00316 (( QgsLineSymbolV2* )symbol )->renderPolyline( pts, &feature, context, layer, selected );
00317
00318 if ( drawVertexMarker )
00319 renderVertexMarkerPolyline( pts, context );
00320 }
00321 }
00322 break;
00323
00324 case QGis::WKBMultiPolygon:
00325 case QGis::WKBMultiPolygon25D:
00326 {
00327 if ( symbolType != QgsSymbolV2::Fill )
00328 {
00329 QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
00330 break;
00331 }
00332
00333 unsigned char* wkb = geom->asWkb();
00334 unsigned int num = *(( int* )( wkb + 5 ) );
00335 unsigned char* ptr = wkb + 9;
00336 QPolygonF pts;
00337 QList<QPolygonF> holes;
00338
00339 for ( unsigned int i = 0; i < num; ++i )
00340 {
00341 ptr = _getPolygon( pts, holes, context, ptr );
00342 (( QgsFillSymbolV2* )symbol )->renderPolygon( pts, ( holes.count() ? &holes : NULL ), &feature, context, layer, selected );
00343
00344 if ( drawVertexMarker )
00345 renderVertexMarkerPolygon( pts, ( holes.count() ? &holes : NULL ), context );
00346 }
00347 }
00348 break;
00349
00350 default:
00351 QgsDebugMsg( "unsupported wkb type for rendering" );
00352 }
00353 }
00354
00355 QString QgsFeatureRendererV2::dump()
00356 {
00357 return "UNKNOWN RENDERER\n";
00358 }
00359
00360
00361 QgsFeatureRendererV2* QgsFeatureRendererV2::load( QDomElement& element )
00362 {
00363
00364
00365 if ( element.isNull() )
00366 return NULL;
00367
00368
00369 QString rendererType = element.attribute( "type" );
00370
00371 QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererType );
00372 if ( m == NULL )
00373 return NULL;
00374
00375 QgsFeatureRendererV2* r = m->createRenderer( element );
00376 if ( r )
00377 {
00378 r->setUsingSymbolLevels( element.attribute( "symbollevels", "0" ).toInt() );
00379 }
00380 return r;
00381 }
00382
00383 QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
00384 {
00385
00386 return doc.createElement( RENDERER_TAG_NAME );
00387 }
00388
00389 QgsFeatureRendererV2* QgsFeatureRendererV2::loadSld( const QDomNode &node, QGis::GeometryType geomType, QString &errorMessage )
00390 {
00391 QDomElement element = node.toElement();
00392 if ( element.isNull() )
00393 return NULL;
00394
00395
00396 QDomElement userStyleElem = element.firstChildElement( "UserStyle" );
00397 if ( userStyleElem.isNull() )
00398 {
00399
00400 errorMessage = "Info: UserStyle element not found.";
00401 return NULL;
00402 }
00403
00404
00405 QDomElement featTypeStyleElem = userStyleElem.firstChildElement( "FeatureTypeStyle" );
00406 if ( featTypeStyleElem.isNull() )
00407 {
00408 errorMessage = "Info: FeatureTypeStyle element not found.";
00409 return NULL;
00410 }
00411
00412
00413
00414
00415 bool needRuleRenderer = false;
00416 int ruleCount = 0;
00417
00418 QDomElement ruleElem = featTypeStyleElem.firstChildElement( "Rule" );
00419 while ( !ruleElem.isNull() )
00420 {
00421 ruleCount++;
00422
00423
00424 if ( ruleCount > 1 )
00425 {
00426 QgsDebugMsg( "more Rule elements found: need a RuleRenderer" );
00427 needRuleRenderer = true;
00428 break;
00429 }
00430
00431 QDomElement ruleChildElem = ruleElem.firstChildElement();
00432 while ( !ruleChildElem.isNull() )
00433 {
00434
00435 if ( ruleChildElem.localName() == "Filter" ||
00436 ruleChildElem.localName() == "MinScaleDenominator" ||
00437 ruleChildElem.localName() == "MaxScaleDenominator" )
00438 {
00439 QgsDebugMsg( "Filter or Min/MaxScaleDenominator element found: need a RuleRenderer" );
00440 needRuleRenderer = true;
00441 break;
00442 }
00443
00444 ruleChildElem = ruleChildElem.nextSiblingElement();
00445 }
00446
00447 if ( needRuleRenderer )
00448 {
00449 break;
00450 }
00451
00452 ruleElem = ruleElem.nextSiblingElement( "Rule" );
00453 }
00454
00455 QString rendererType;
00456 if ( needRuleRenderer )
00457 {
00458 rendererType = "RuleRenderer";
00459 }
00460 else
00461 {
00462 rendererType = "singleSymbol";
00463 }
00464 QgsDebugMsg( QString( "Instantiating a '%1' renderer..." ).arg( rendererType ) );
00465
00466
00467 QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererType );
00468 if ( m == NULL )
00469 {
00470 errorMessage = QString( "Error: Unable to get metadata for '%1' renderer." ).arg( rendererType );
00471 return NULL;
00472 }
00473
00474 QgsFeatureRendererV2* r = m->createRendererFromSld( featTypeStyleElem, geomType );
00475 return r;
00476 }
00477
00478 QDomElement QgsFeatureRendererV2::writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const
00479 {
00480 QDomElement userStyleElem = doc.createElement( "UserStyle" );
00481
00482 QDomElement nameElem = doc.createElement( "se:Name" );
00483 nameElem.appendChild( doc.createTextNode( layer.name() ) );
00484 userStyleElem.appendChild( nameElem );
00485
00486 QDomElement featureTypeStyleElem = doc.createElement( "se:FeatureTypeStyle" );
00487 toSld( doc, featureTypeStyleElem );
00488 userStyleElem.appendChild( featureTypeStyleElem );
00489
00490 return userStyleElem;
00491 }
00492
00493 QgsLegendSymbologyList QgsFeatureRendererV2::legendSymbologyItems( QSize iconSize )
00494 {
00495 Q_UNUSED( iconSize );
00496
00497 return QgsLegendSymbologyList();
00498 }
00499
00500 QgsLegendSymbolList QgsFeatureRendererV2::legendSymbolItems()
00501 {
00502 return QgsLegendSymbolList();
00503 }
00504
00505 void QgsFeatureRendererV2::setVertexMarkerAppearance( int type, int size )
00506 {
00507 mCurrentVertexMarkerType = type;
00508 mCurrentVertexMarkerSize = size;
00509 }
00510
00511 void QgsFeatureRendererV2::renderVertexMarker( QPointF& pt, QgsRenderContext& context )
00512 {
00513 QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(),
00514 ( QgsVectorLayer::VertexMarkerType ) mCurrentVertexMarkerType,
00515 mCurrentVertexMarkerSize );
00516 }
00517
00518 void QgsFeatureRendererV2::renderVertexMarkerPolyline( QPolygonF& pts, QgsRenderContext& context )
00519 {
00520 foreach( QPointF pt, pts )
00521 renderVertexMarker( pt, context );
00522 }
00523
00524 void QgsFeatureRendererV2::renderVertexMarkerPolygon( QPolygonF& pts, QList<QPolygonF>* rings, QgsRenderContext& context )
00525 {
00526 foreach( QPointF pt, pts )
00527 renderVertexMarker( pt, context );
00528
00529 if ( rings )
00530 {
00531 foreach( QPolygonF ring, *rings )
00532 {
00533 foreach( QPointF pt, ring )
00534 renderVertexMarker( pt, context );
00535 }
00536 }
00537 }
00538
00539 QgsSymbolV2List QgsFeatureRendererV2::symbolsForFeature( QgsFeature& feat )
00540 {
00541 QgsSymbolV2List lst;
00542 QgsSymbolV2* s = symbolForFeature( feat );
00543 if ( s ) lst.append( s );
00544 return lst;
00545 }