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