QGIS API Documentation  master-6227475
src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgssinglesymbolrendererv2.cpp
00003     ---------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgssinglesymbolrendererv2.h"
00017 
00018 #include "qgssymbolv2.h"
00019 #include "qgssymbollayerv2utils.h"
00020 
00021 #include "qgslogger.h"
00022 #include "qgsfeature.h"
00023 #include "qgsvectorlayer.h"
00024 #include "qgssymbollayerv2.h"
00025 
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 
00029 QgsSingleSymbolRendererV2::QgsSingleSymbolRendererV2( QgsSymbolV2* symbol )
00030     : QgsFeatureRendererV2( "singleSymbol" ), mScaleMethod( DEFAULT_SCALE_METHOD ), mRotationFieldIdx( -1 ),
00031     mSizeScaleFieldIdx( -1 ), mTempSymbol( NULL )
00032 {
00033   Q_ASSERT( symbol );
00034   mSymbol = symbol;
00035 }
00036 
00037 QgsSingleSymbolRendererV2::~QgsSingleSymbolRendererV2()
00038 {
00039   delete mSymbol;
00040 }
00041 
00042 QgsSymbolV2* QgsSingleSymbolRendererV2::symbolForFeature( QgsFeature& feature )
00043 {
00044   if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
00045     return mSymbol;
00046 
00047   double rotation = 0;
00048   double sizeScale = 1;
00049   if ( mRotationFieldIdx != -1 )
00050   {
00051     rotation = feature.attribute( mRotationFieldIdx ).toDouble();
00052   }
00053   if ( mSizeScaleFieldIdx != -1 )
00054   {
00055     sizeScale = feature.attribute( mSizeScaleFieldIdx ).toDouble();
00056   }
00057 
00058   if ( mTempSymbol->type() == QgsSymbolV2::Marker )
00059   {
00060     QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol );
00061     if ( mRotationFieldIdx != -1 )
00062       markerSymbol->setAngle( rotation );
00063     if ( mSizeScaleFieldIdx != -1 )
00064       markerSymbol->setSize( sizeScale * mOrigSize );
00065     markerSymbol->setScaleMethod( mScaleMethod );
00066   }
00067   else if ( mTempSymbol->type() == QgsSymbolV2::Line )
00068   {
00069     QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol );
00070     if ( mSizeScaleFieldIdx != -1 )
00071       lineSymbol->setWidth( sizeScale * mOrigSize );
00072   }
00073   else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
00074   {
00075     QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol );
00076     if ( mRotationFieldIdx != -1 )
00077       fillSymbol->setAngle( rotation );
00078   }
00079 
00080   return mTempSymbol;
00081 }
00082 
00083 void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
00084 {
00085   if ( !mSymbol )
00086   {
00087     return;
00088   }
00089   mRotationFieldIdx  = mRotationField.isEmpty()  ? -1 : vlayer->fieldNameIndex( mRotationField );
00090   mSizeScaleFieldIdx = mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField );
00091 
00092   mSymbol->startRender( context, vlayer );
00093 
00094   if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
00095   {
00096     // we are going to need a temporary symbol
00097     mTempSymbol = mSymbol->clone();
00098 
00099     int hints = 0;
00100     if ( mRotationFieldIdx != -1 )
00101       hints |= QgsSymbolV2::DataDefinedRotation;
00102     if ( mSizeScaleFieldIdx != -1 )
00103       hints |= QgsSymbolV2::DataDefinedSizeScale;
00104     mTempSymbol->setRenderHints( hints );
00105 
00106     mTempSymbol->startRender( context, vlayer );
00107 
00108     if ( mSymbol->type() == QgsSymbolV2::Marker )
00109     {
00110       mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol )->size();
00111     }
00112     else if ( mSymbol->type() == QgsSymbolV2::Line )
00113     {
00114       mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol )->width();
00115     }
00116     else
00117     {
00118       mOrigSize = 0;
00119     }
00120   }
00121 }
00122 
00123 void QgsSingleSymbolRendererV2::stopRender( QgsRenderContext& context )
00124 {
00125   if ( !mSymbol )
00126   {
00127     return;
00128   }
00129   mSymbol->stopRender( context );
00130 
00131   if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
00132   {
00133     // we are going to need a temporary symbol
00134     mTempSymbol->stopRender( context );
00135     delete mTempSymbol;
00136     mTempSymbol = NULL;
00137   }
00138 }
00139 
00140 QList<QString> QgsSingleSymbolRendererV2::usedAttributes()
00141 {
00142   QSet<QString> attributes;
00143   if ( mSymbol )
00144   {
00145     attributes.unite( mSymbol->usedAttributes() );
00146   }
00147   if ( !mRotationField.isEmpty() )
00148   {
00149     attributes.insert( mRotationField );
00150   }
00151   if ( !mSizeScaleField.isEmpty() )
00152   {
00153     attributes.insert( mSizeScaleField );
00154   }
00155   return attributes.toList();
00156 }
00157 
00158 QgsSymbolV2* QgsSingleSymbolRendererV2::symbol() const
00159 {
00160   return mSymbol;
00161 }
00162 
00163 void QgsSingleSymbolRendererV2::setSymbol( QgsSymbolV2* s )
00164 {
00165   Q_ASSERT( s );
00166   delete mSymbol;
00167   mSymbol = s;
00168 }
00169 
00170 void QgsSingleSymbolRendererV2::setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod )
00171 {
00172   mScaleMethod = scaleMethod;
00173   setScaleMethodToSymbol( mSymbol, scaleMethod );
00174 }
00175 
00176 QString QgsSingleSymbolRendererV2::dump()
00177 {
00178   if ( mSymbol )
00179   {
00180     return QString( "SINGLE: %1" ).arg( mSymbol->dump() );
00181   }
00182   else
00183   {
00184     return "";
00185   }
00186 }
00187 
00188 QgsFeatureRendererV2* QgsSingleSymbolRendererV2::clone()
00189 {
00190   QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( mSymbol->clone() );
00191   r->setUsingSymbolLevels( usingSymbolLevels() );
00192   r->setRotationField( rotationField() );
00193   r->setSizeScaleField( sizeScaleField() );
00194   r->setScaleMethod( scaleMethod() );
00195   return r;
00196 }
00197 
00198 void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
00199 {
00200   QgsStringMap props;
00201   if ( !mRotationField.isEmpty() )
00202     props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
00203   if ( !mSizeScaleField.isEmpty() )
00204     props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
00205 
00206   QDomElement ruleElem = doc.createElement( "se:Rule" );
00207   element.appendChild( ruleElem );
00208 
00209   QDomElement nameElem = doc.createElement( "se:Name" );
00210   nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
00211   ruleElem.appendChild( nameElem );
00212 
00213   mSymbol->toSld( doc, ruleElem, props );
00214 }
00215 
00216 QgsSymbolV2List QgsSingleSymbolRendererV2::symbols()
00217 {
00218   QgsSymbolV2List lst;
00219   lst.append( mSymbol );
00220   return lst;
00221 }
00222 
00223 QgsFeatureRendererV2* QgsSingleSymbolRendererV2::create( QDomElement& element )
00224 {
00225   QDomElement symbolsElem = element.firstChildElement( "symbols" );
00226   if ( symbolsElem.isNull() )
00227     return NULL;
00228 
00229   QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
00230 
00231   if ( !symbolMap.contains( "0" ) )
00232     return NULL;
00233 
00234   QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
00235 
00236   // delete symbols if there are any more
00237   QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
00238 
00239   QDomElement rotationElem = element.firstChildElement( "rotation" );
00240   if ( !rotationElem.isNull() )
00241     r->setRotationField( rotationElem.attribute( "field" ) );
00242 
00243   QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
00244   if ( !sizeScaleElem.isNull() )
00245   {
00246     r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
00247     r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
00248   }
00249 
00250   // TODO: symbol levels
00251   return r;
00252 }
00253 
00254 QgsFeatureRendererV2* QgsSingleSymbolRendererV2::createFromSld( QDomElement& element, QGis::GeometryType geomType )
00255 {
00256   // XXX this renderer can handle only one Rule!
00257 
00258   // get the first Rule element
00259   QDomElement ruleElem = element.firstChildElement( "Rule" );
00260   if ( ruleElem.isNull() )
00261   {
00262     QgsDebugMsg( "no Rule elements found!" );
00263     return NULL;
00264   }
00265 
00266   QString label, description;
00267   QgsSymbolLayerV2List layers;
00268 
00269   // retrieve the Rule element child nodes
00270   QDomElement childElem = ruleElem.firstChildElement();
00271   while ( !childElem.isNull() )
00272   {
00273     if ( childElem.localName() == "Name" )
00274     {
00275       // <se:Name> tag contains the rule identifier,
00276       // so prefer title tag for the label property value
00277       if ( label.isEmpty() )
00278         label = childElem.firstChild().nodeValue();
00279     }
00280     else if ( childElem.localName() == "Description" )
00281     {
00282       // <se:Description> can contains a title and an abstract
00283       QDomElement titleElem = childElem.firstChildElement( "Title" );
00284       if ( !titleElem.isNull() )
00285       {
00286         label = titleElem.firstChild().nodeValue();
00287       }
00288 
00289       QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
00290       if ( !abstractElem.isNull() )
00291       {
00292         description = abstractElem.firstChild().nodeValue();
00293       }
00294     }
00295     else if ( childElem.localName() == "Abstract" )
00296     {
00297       // <sld:Abstract> (v1.0)
00298       description = childElem.firstChild().nodeValue();
00299     }
00300     else if ( childElem.localName() == "Title" )
00301     {
00302       // <sld:Title> (v1.0)
00303       label = childElem.firstChild().nodeValue();
00304     }
00305     else if ( childElem.localName().endsWith( "Symbolizer" ) )
00306     {
00307       // create symbol layers for this symbolizer
00308       QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
00309     }
00310 
00311     childElem = childElem.nextSiblingElement();
00312   }
00313 
00314   if ( layers.size() == 0 )
00315     return NULL;
00316 
00317   // now create the symbol
00318   QgsSymbolV2 *symbol;
00319   switch ( geomType )
00320   {
00321     case QGis::Line:
00322       symbol = new QgsLineSymbolV2( layers );
00323       break;
00324 
00325     case QGis::Polygon:
00326       symbol = new QgsFillSymbolV2( layers );
00327       break;
00328 
00329     case QGis::Point:
00330       symbol = new QgsMarkerSymbolV2( layers );
00331       break;
00332 
00333     default:
00334       QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
00335       return NULL;
00336   }
00337 
00338   // and finally return the new renderer
00339   return new QgsSingleSymbolRendererV2( symbol );
00340 }
00341 
00342 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
00343 {
00344   QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
00345   rendererElem.setAttribute( "type", "singleSymbol" );
00346   rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
00347 
00348   QgsSymbolV2Map symbols;
00349   symbols["0"] = mSymbol;
00350   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
00351   rendererElem.appendChild( symbolsElem );
00352 
00353   QDomElement rotationElem = doc.createElement( "rotation" );
00354   rotationElem.setAttribute( "field", mRotationField );
00355   rendererElem.appendChild( rotationElem );
00356 
00357   QDomElement sizeScaleElem = doc.createElement( "sizescale" );
00358   sizeScaleElem.setAttribute( "field", mSizeScaleField );
00359   sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
00360   rendererElem.appendChild( sizeScaleElem );
00361 
00362   return rendererElem;
00363 }
00364 
00365 QgsLegendSymbologyList QgsSingleSymbolRendererV2::legendSymbologyItems( QSize iconSize )
00366 {
00367   QgsLegendSymbologyList lst;
00368   if ( mSymbol )
00369   {
00370     QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol, iconSize );
00371     lst << qMakePair( QString(), pix );
00372   }
00373   return lst;
00374 }
00375 
00376 QgsLegendSymbolList QgsSingleSymbolRendererV2::legendSymbolItems()
00377 {
00378   QgsLegendSymbolList lst;
00379   lst << qMakePair( QString(), mSymbol );
00380   return lst;
00381 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines