Quantum GIS API Documentation  1.7.4
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 /* $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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines