|
QGIS API Documentation
master-6227475
|
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 }