|
Quantum GIS API Documentation
master-2bfffaa
|
00001 /*************************************************************************** 00002 qgssinglesymbolrenderer.cpp - description 00003 ------------------- 00004 begin : Oct 2003 00005 copyright : (C) 2003 by Marco Hugentobler 00006 email : mhugent@geo.unizh.ch 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 fieldScale = sqrt( qAbs( f.attribute( theSymbol->scaleClassificationField() ).toDouble() ) ); 00149 QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 ); 00150 } 00151 if ( theSymbol->rotationClassificationField() >= 0 ) 00152 { 00153 rotation = f.attribute( theSymbol->rotationClassificationField() ).toDouble(); 00154 QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 ); 00155 } 00156 00157 QString oldName; 00158 00159 if ( theSymbol->symbolField() >= 0 ) 00160 { 00161 QString name = f.attribute( theSymbol->symbolField() ).toString(); 00162 QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 ); 00163 oldName = theSymbol->pointSymbolName(); 00164 theSymbol->setNamedPointSymbol( name ); 00165 } 00166 00167 double scale = renderContext.scaleFactor(); 00168 00169 if ( theSymbol->pointSizeUnits() ) 00170 { 00171 scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel(); 00172 } 00173 00174 *img = theSymbol->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, 00175 rotation, renderContext.rasterScaleFactor(), opacity ); 00176 00177 if ( !oldName.isNull() ) 00178 { 00179 theSymbol->setNamedPointSymbol( oldName ); 00180 } 00181 } 00182 00183 // Line, polygon 00184 if ( mGeometryType != QGis::Point ) 00185 { 00186 if ( !selected ) 00187 { 00188 QPen pen = theSymbol->pen(); 00189 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00190 p->setPen( pen ); 00191 00192 if ( mGeometryType == QGis::Polygon ) 00193 { 00194 QBrush brush = theSymbol->brush(); 00195 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00196 p->setBrush( brush ); 00197 } 00198 } 00199 else 00200 { 00201 QPen pen = theSymbol->pen(); 00202 pen.setWidthF( renderContext.scaleFactor() * pen.widthF() ); 00203 00204 if ( mGeometryType == QGis::Polygon ) 00205 { 00206 QBrush brush = theSymbol->brush(); 00207 scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout 00208 brush.setColor( mSelectionColor ); 00209 p->setBrush( brush ); 00210 } 00211 else //don't draw outlines in selection color for polys otherwise they appear merged 00212 { 00213 pen.setColor( mSelectionColor ); 00214 } 00215 p->setPen( pen ); 00216 } 00217 } 00218 } 00219 00220 QgsSymbol *QgsGraduatedSymbolRenderer::symbolForFeature( const QgsFeature* f ) 00221 { 00222 //first find out the value for the classification attribute 00223 double value = f->attribute( mClassificationField ).toDouble(); 00224 00225 QList<QgsSymbol*>::iterator it; 00226 //find the first render item which contains the feature 00227 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00228 { 00229 if ( value >= ( *it )->lowerValue().toDouble() && value <= ( *it )->upperValue().toDouble() ) 00230 { 00231 break; 00232 } 00233 } 00234 00235 if ( it == mSymbols.end() ) //only draw features which are covered by a render item 00236 { 00237 return 0; 00238 } 00239 return ( *it ); 00240 } 00241 00242 int QgsGraduatedSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl ) 00243 { 00244 mGeometryType = vl.geometryType(); 00245 QDomNode modeNode = rnode.namedItem( "mode" ); 00246 QString modeValue = modeNode.toElement().text(); 00247 QDomNode classnode = rnode.namedItem( "classificationfield" ); 00248 QString classificationField = classnode.toElement().text(); 00249 00250 QgsVectorDataProvider* theProvider = vl.dataProvider(); 00251 if ( !theProvider ) 00252 { 00253 return 1; 00254 } 00255 if ( modeValue == "Empty" ) 00256 { 00257 mMode = QgsGraduatedSymbolRenderer::Empty; 00258 } 00259 else if ( modeValue == "Quantile" ) 00260 { 00261 mMode = QgsGraduatedSymbolRenderer::Quantile; 00262 } 00263 else //default 00264 { 00265 mMode = QgsGraduatedSymbolRenderer::EqualInterval; 00266 } 00267 00268 int classificationId = vl.fieldNameIndex( classificationField ); 00269 if ( classificationId == -1 ) 00270 { 00271 //go on. Because with joins, it might be the joined layer is not loaded yet 00272 } 00273 setClassificationField( classificationId ); 00274 00275 QDomNode symbolnode = rnode.namedItem( "symbol" ); 00276 while ( !symbolnode.isNull() ) 00277 { 00278 QgsSymbol* sy = new QgsSymbol( mGeometryType ); 00279 sy->readXML( symbolnode, &vl ); 00280 addSymbol( sy ); 00281 00282 symbolnode = symbolnode.nextSibling(); 00283 } 00284 updateSymbolAttributes(); 00285 vl.setRenderer( this ); 00286 return 0; 00287 } 00288 00289 QgsAttributeList QgsGraduatedSymbolRenderer::classificationAttributes() const 00290 { 00291 QgsAttributeList list( mSymbolAttributes ); 00292 if ( ! list.contains( mClassificationField ) ) 00293 { 00294 list.append( mClassificationField ); 00295 } 00296 return list; 00297 } 00298 00299 void QgsGraduatedSymbolRenderer::updateSymbolAttributes() 00300 { 00301 // This function is only called after changing field specifier in the GUI. 00302 // Timing is not so important. 00303 00304 mSymbolAttributes.clear(); 00305 00306 QList<QgsSymbol*>::iterator it; 00307 for ( it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00308 { 00309 int rotationField = ( *it )->rotationClassificationField(); 00310 if ( rotationField >= 0 && !mSymbolAttributes.contains( rotationField ) ) 00311 { 00312 mSymbolAttributes.append( rotationField ); 00313 } 00314 int scaleField = ( *it )->scaleClassificationField(); 00315 if ( scaleField >= 0 && !mSymbolAttributes.contains( scaleField ) ) 00316 { 00317 mSymbolAttributes.append( scaleField ); 00318 } 00319 int symbolField = ( *it )->symbolField(); 00320 if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) ) 00321 { 00322 mSymbolAttributes.append( symbolField ); 00323 } 00324 } 00325 } 00326 00327 QString QgsGraduatedSymbolRenderer::name() const 00328 { 00329 return "Graduated Symbol"; 00330 } 00331 00332 bool QgsGraduatedSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const 00333 { 00334 bool returnval = true; 00335 QDomElement graduatedsymbol = document.createElement( "graduatedsymbol" ); 00336 layer_node.appendChild( graduatedsymbol ); 00337 00338 // 00339 // Mode field first ... 00340 // 00341 00342 QString modeValue = ""; 00343 if ( mMode == QgsGraduatedSymbolRenderer::Empty ) 00344 { 00345 modeValue = "Empty"; 00346 } 00347 else if ( QgsGraduatedSymbolRenderer::Quantile ) 00348 { 00349 modeValue = "Quantile"; 00350 } 00351 else //default 00352 { 00353 modeValue = "Equal Interval"; 00354 } 00355 QDomElement modeElement = document.createElement( "mode" ); 00356 QDomText modeText = document.createTextNode( modeValue ); 00357 modeElement.appendChild( modeText ); 00358 graduatedsymbol.appendChild( modeElement ); 00359 00360 00361 00362 // 00363 // classification field now ... 00364 // 00365 00366 QDomElement classificationfield = document.createElement( "classificationfield" ); 00367 00368 const QgsVectorDataProvider* theProvider = vl.dataProvider(); 00369 if ( !theProvider ) 00370 { 00371 return false; 00372 } 00373 00374 QString classificationFieldName; 00375 const QgsFields& fields = vl.pendingFields(); 00376 if ( mClassificationField >= 0 && mClassificationField < fields.count() ) 00377 { 00378 classificationFieldName = fields[ mClassificationField ].name(); 00379 } 00380 00381 QDomText classificationfieldtxt = document.createTextNode( classificationFieldName ); 00382 classificationfield.appendChild( classificationfieldtxt ); 00383 graduatedsymbol.appendChild( classificationfield ); 00384 for ( QList<QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it ) 00385 { 00386 if ( !( *it )->writeXML( graduatedsymbol, document, &vl ) ) 00387 { 00388 returnval = false; 00389 } 00390 } 00391 return returnval; 00392 } 00393 00394 QgsRenderer* QgsGraduatedSymbolRenderer::clone() const 00395 { 00396 QgsGraduatedSymbolRenderer* r = new QgsGraduatedSymbolRenderer( *this ); 00397 return r; 00398 }