Quantum GIS API Documentation  master-2bfffaa
src/core/renderer/qgsgraduatedsymbolrenderer.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines