Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgssinglesymbolrenderer.cpp - description 00003 ------------------- 00004 begin : Oct 2003 00005 copyright : (C) 2003 by Marco Hugentobler 00006 email : [email protected] 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgis.h" 00019 #include "qgslogger.h" 00020 #include "qgsfeature.h" 00021 #include "qgsgraduatedsymbolrenderer.h" 00022 #include "qgssymbol.h" 00023 #include "qgssymbologyutils.h" 00024 #include "qgsvectordataprovider.h" 00025 #include "qgsvectorlayer.h" 00026 #include "qgsrendercontext.h" 00027 #include <cmath> 00028 #include <QDomNode> 00029 #include <QDomElement> 00030 #include <QImage> 00031 #include <QPainter> 00032 00033 00034 QgsGraduatedSymbolRenderer::QgsGraduatedSymbolRenderer( QGis::GeometryType type, Mode mode ) 00035 { 00036 Q_UNUSED( mode ); 00037 00038 mGeometryType = type; 00039 } 00040 00041 QgsGraduatedSymbolRenderer::QgsGraduatedSymbolRenderer( const QgsGraduatedSymbolRenderer& other ) 00042 { 00043 mMode = other.mMode; 00044 mGeometryType = other.mGeometryType; 00045 mClassificationField = other.mClassificationField; 00046 const QList<QgsSymbol*> s = other.symbols(); 00047 for ( QList<QgsSymbol*>::const_iterator it = s.begin(); it != s.end(); ++it ) 00048 { 00049 addSymbol( new QgsSymbol( **it ) ); 00050 } 00051 updateSymbolAttributes(); 00052 } 00053 00054 QgsGraduatedSymbolRenderer& QgsGraduatedSymbolRenderer::operator=( const QgsGraduatedSymbolRenderer & other ) 00055 { 00056 if ( this != &other ) 00057 { 00058 mMode = other.mMode; 00059 mGeometryType = other.mGeometryType; 00060 mClassificationField = other.mClassificationField; 00061 removeSymbols(); 00062 const QList<QgsSymbol*> s = other.symbols(); 00063 for ( QList<QgsSymbol*>::const_iterator it = s.begin(); it != s.end(); ++it ) 00064 { 00065 addSymbol( new QgsSymbol( **it ) ); 00066 } 00067 updateSymbolAttributes(); 00068 } 00069 00070 return *this; 00071 } 00072 00073 QgsGraduatedSymbolRenderer::~QgsGraduatedSymbolRenderer() 00074 { 00075 00076 } 00077 00078 00079 QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::mode() const 00080 { 00081 //mode is only really used to be able to reinstate 00082 //the graduated dialog properties properly, so we 00083 //don't do anything else besides accessors and mutators in 00084 //this class 00085 return mMode; 00086 } 00087 00088 void QgsGraduatedSymbolRenderer::setMode( QgsGraduatedSymbolRenderer::Mode theMode ) 00089 { 00090 //mode is only really used to be able to reinstate 00091 //the graduated dialog properties properly, so we 00092 //don't do anything else besides accessors and mutators in 00093 //this class 00094 mMode = theMode; 00095 } 00096 00097 const QList<QgsSymbol*> QgsGraduatedSymbolRenderer::symbols() const 00098 { 00099 return mSymbols; 00100 } 00101 00102 void QgsGraduatedSymbolRenderer::removeSymbols() 00103 { 00104 //free the memory first 00105 for ( QList<QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00106 { 00107 delete *it; 00108 } 00109 00110 //and remove the pointers then 00111 mSymbols.clear(); 00112 updateSymbolAttributes(); 00113 } 00114 00115 bool QgsGraduatedSymbolRenderer::willRenderFeature( QgsFeature *f ) 00116 { 00117 return ( symbolForFeature( f ) != 0 ); 00118 } 00119 00120 void QgsGraduatedSymbolRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature & f, QImage* img, bool selected, double opacity ) 00121 { 00122 QPainter *p = renderContext.painter(); 00123 QgsSymbol* theSymbol = symbolForFeature( &f ); 00124 if ( !theSymbol ) 00125 { 00126 if ( img && mGeometryType == QGis::Point ) 00127 { 00128 img->fill( 0 ); 00129 } 00130 else if ( mGeometryType != QGis::Point ) 00131 { 00132 p->setPen( Qt::NoPen ); 00133 p->setBrush( Qt::NoBrush ); 00134 } 00135 return; 00136 } 00137 00138 //set the qpen and qpainter to the right values 00139 // Point 00140 if ( img && mGeometryType == QGis::Point ) 00141 { 00142 double fieldScale = 1.0; 00143 double rotation = 0.0; 00144 00145 if ( theSymbol->scaleClassificationField() >= 0 ) 00146 { 00147 //first find out the value for the scale classification attribute 00148 const QgsAttributeMap& attrs = f.attributeMap(); 00149 fieldScale = sqrt( qAbs( attrs[theSymbol->scaleClassificationField()].toDouble() ) ); 00150 QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 ); 00151 } 00152 if ( theSymbol->rotationClassificationField() >= 0 ) 00153 { 00154 const QgsAttributeMap& attrs = f.attributeMap(); 00155 rotation = attrs[theSymbol->rotationClassificationField()].toDouble(); 00156 QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 ); 00157 } 00158 00159 QString oldName; 00160 00161 if ( theSymbol->symbolField() >= 0 ) 00162 { 00163 const QgsAttributeMap& attrs = f.attributeMap(); 00164 QString name = attrs[theSymbol->symbolField()].toString(); 00165 QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 ); 00166 oldName = theSymbol->pointSymbolName(); 00167 theSymbol->setNamedPointSymbol( name ); 00168 } 00169 00170 double scale = renderContext.scaleFactor(); 00171 00172 if ( theSymbol->pointSizeUnits() ) 00173 { 00174 scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); 00175 } 00176 00177 *img = theSymbol->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, 00178 rotation, renderContext.rasterScaleFactor(), opacity ); 00179 00180 if ( !oldName.isNull() ) 00181 { 00182 theSymbol->setNamedPointSymbol( oldName ); 00183 } 00184 } 00185 00186 // Line, polygon 00187 if ( mGeometryType != QGis::Point ) 00188 { 00189 if ( !selected ) 00190 { 00191 QPen pen = theSymbol->pen(); 00192 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00193 p->setPen( pen ); 00194 00195 if ( mGeometryType == QGis::Polygon ) 00196 { 00197 QBrush brush = theSymbol->brush(); 00198 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00199 p->setBrush( brush ); 00200 } 00201 } 00202 else 00203 { 00204 QPen pen = theSymbol->pen(); 00205 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00206 00207 if ( mGeometryType == QGis::Polygon ) 00208 { 00209 QBrush brush = theSymbol->brush(); 00210 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00211 brush.setColor( mSelectionColor ); 00212 p->setBrush( brush ); 00213 } 00214 else //don't draw outlines in selection color for polys otherwise they appear merged 00215 { 00216 pen.setColor( mSelectionColor ); 00217 } 00218 p->setPen( pen ); 00219 } 00220 } 00221 } 00222 00223 QgsSymbol *QgsGraduatedSymbolRenderer::symbolForFeature( const QgsFeature* f ) 00224 { 00225 //first find out the value for the classification attribute 00226 const QgsAttributeMap& attrs = f->attributeMap(); 00227 double value = attrs[mClassificationField].toDouble(); 00228 00229 QList<QgsSymbol*>::iterator it; 00230 //find the first render item which contains the feature 00231 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00232 { 00233 if ( value >= ( *it )->lowerValue().toDouble() && value <= ( *it )->upperValue().toDouble() ) 00234 { 00235 break; 00236 } 00237 } 00238 00239 if ( it == mSymbols.end() ) //only draw features which are covered by a render item 00240 { 00241 return 0; 00242 } 00243 return ( *it ); 00244 } 00245 00246 int QgsGraduatedSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl ) 00247 { 00248 mGeometryType = vl.geometryType(); 00249 QDomNode modeNode = rnode.namedItem( "mode" ); 00250 QString modeValue = modeNode.toElement().text(); 00251 QDomNode classnode = rnode.namedItem( "classificationfield" ); 00252 QString classificationField = classnode.toElement().text(); 00253 00254 QgsVectorDataProvider* theProvider = vl.dataProvider(); 00255 if ( !theProvider ) 00256 { 00257 return 1; 00258 } 00259 if ( modeValue == "Empty" ) 00260 { 00261 mMode = QgsGraduatedSymbolRenderer::Empty; 00262 } 00263 else if ( modeValue == "Quantile" ) 00264 { 00265 mMode = QgsGraduatedSymbolRenderer::Quantile; 00266 } 00267 else //default 00268 { 00269 mMode = QgsGraduatedSymbolRenderer::EqualInterval; 00270 } 00271 00272 int classificationId = vl.fieldNameIndex( classificationField ); 00273 if ( classificationId == -1 ) 00274 { 00275 //go on. Because with joins, it might be the joined layer is not loaded yet 00276 } 00277 setClassificationField( classificationId ); 00278 00279 QDomNode symbolnode = rnode.namedItem( "symbol" ); 00280 while ( !symbolnode.isNull() ) 00281 { 00282 QgsSymbol* sy = new QgsSymbol( mGeometryType ); 00283 sy->readXML( symbolnode, &vl ); 00284 addSymbol( sy ); 00285 00286 symbolnode = symbolnode.nextSibling(); 00287 } 00288 updateSymbolAttributes(); 00289 vl.setRenderer( this ); 00290 return 0; 00291 } 00292 00293 QgsAttributeList QgsGraduatedSymbolRenderer::classificationAttributes() const 00294 { 00295 QgsAttributeList list( mSymbolAttributes ); 00296 if ( ! list.contains( mClassificationField ) ) 00297 { 00298 list.append( mClassificationField ); 00299 } 00300 return list; 00301 } 00302 00303 void QgsGraduatedSymbolRenderer::updateSymbolAttributes() 00304 { 00305 // This function is only called after changing field specifier in the GUI. 00306 // Timing is not so important. 00307 00308 mSymbolAttributes.clear(); 00309 00310 QList<QgsSymbol*>::iterator it; 00311 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00312 { 00313 int rotationField = ( *it )->rotationClassificationField(); 00314 if ( rotationField >= 0 && !mSymbolAttributes.contains( rotationField ) ) 00315 { 00316 mSymbolAttributes.append( rotationField ); 00317 } 00318 int scaleField = ( *it )->scaleClassificationField(); 00319 if ( scaleField >= 0 && !mSymbolAttributes.contains( scaleField ) ) 00320 { 00321 mSymbolAttributes.append( scaleField ); 00322 } 00323 int symbolField = ( *it )->symbolField(); 00324 if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) ) 00325 { 00326 mSymbolAttributes.append( symbolField ); 00327 } 00328 } 00329 } 00330 00331 QString QgsGraduatedSymbolRenderer::name() const 00332 { 00333 return "Graduated Symbol"; 00334 } 00335 00336 bool QgsGraduatedSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const 00337 { 00338 bool returnval = true; 00339 QDomElement graduatedsymbol = document.createElement( "graduatedsymbol" ); 00340 layer_node.appendChild( graduatedsymbol ); 00341 00342 // 00343 // Mode field first ... 00344 // 00345 00346 QString modeValue = ""; 00347 if ( mMode == QgsGraduatedSymbolRenderer::Empty ) 00348 { 00349 modeValue = "Empty"; 00350 } 00351 else if ( QgsGraduatedSymbolRenderer::Quantile ) 00352 { 00353 modeValue = "Quantile"; 00354 } 00355 else //default 00356 { 00357 modeValue = "Equal Interval"; 00358 } 00359 QDomElement modeElement = document.createElement( "mode" ); 00360 QDomText modeText = document.createTextNode( modeValue ); 00361 modeElement.appendChild( modeText ); 00362 graduatedsymbol.appendChild( modeElement ); 00363 00364 00365 00366 // 00367 // classification field now ... 00368 // 00369 00370 QDomElement classificationfield = document.createElement( "classificationfield" ); 00371 00372 const QgsVectorDataProvider* theProvider = vl.dataProvider(); 00373 if ( !theProvider ) 00374 { 00375 return false; 00376 } 00377 00378 QString classificationFieldName; 00379 if ( vl.pendingFields().contains( mClassificationField ) ) 00380 { 00381 classificationFieldName = vl.pendingFields()[ mClassificationField ].name(); 00382 } 00383 00384 QDomText classificationfieldtxt = document.createTextNode( classificationFieldName ); 00385 classificationfield.appendChild( classificationfieldtxt ); 00386 graduatedsymbol.appendChild( classificationfield ); 00387 for ( QList<QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00388 { 00389 if ( !( *it )->writeXML( graduatedsymbol, document, &vl ) ) 00390 { 00391 returnval = false; 00392 } 00393 } 00394 return returnval; 00395 } 00396 00397 QgsRenderer* QgsGraduatedSymbolRenderer::clone() const 00398 { 00399 QgsGraduatedSymbolRenderer* r = new QgsGraduatedSymbolRenderer( *this ); 00400 return r; 00401 }