Quantum GIS API Documentation  master-2bfffaa
src/core/renderer/qgsuniquevaluerenderer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgsuniquevaluerenderer.cpp  -  description
00003                              -------------------
00004     begin                : July 2004
00005     copyright            : (C) 2004 by Marco Hugentobler
00006     email                : marco.hugentobler@autoform.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 "qgsuniquevaluerenderer.h"
00019 #include "qgsfeature.h"
00020 #include "qgsvectordataprovider.h"
00021 #include "qgsvectorlayer.h"
00022 #include "qgsrendercontext.h"
00023 #include "qgssymbol.h"
00024 #include "qgssymbologyutils.h"
00025 #include "qgslogger.h"
00026 #include <cmath>
00027 #include <QDomNode>
00028 #include <QPainter>
00029 #include <QImage>
00030 #include <vector>
00031 
00032 QgsUniqueValueRenderer::QgsUniqueValueRenderer( QGis::GeometryType type ): mClassificationField( 0 )
00033 {
00034   mGeometryType = type;
00035   mSymbolAttributesDirty = false;
00036 }
00037 
00038 QgsUniqueValueRenderer::QgsUniqueValueRenderer( const QgsUniqueValueRenderer& other )
00039 {
00040   mGeometryType = other.mGeometryType;
00041   mClassificationField = other.mClassificationField;
00042   QMap<QString, QgsSymbol*> s = other.mSymbols;
00043   for ( QMap<QString, QgsSymbol*>::iterator it = s.begin(); it != s.end(); ++it )
00044   {
00045     QgsSymbol* s = new QgsSymbol( * it.value() );
00046     insertValue( it.key(), s );
00047   }
00048   updateSymbolAttributes();
00049 }
00050 
00051 QgsUniqueValueRenderer& QgsUniqueValueRenderer::operator=( const QgsUniqueValueRenderer & other )
00052 {
00053   if ( this != &other )
00054   {
00055     mGeometryType = other.mGeometryType;
00056     mClassificationField = other.mClassificationField;
00057     clearValues();
00058     for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00059     {
00060       QgsSymbol* s = new QgsSymbol( *it.value() );
00061       insertValue( it.key(), s );
00062     }
00063     updateSymbolAttributes();
00064   }
00065   return *this;
00066 }
00067 
00068 QgsUniqueValueRenderer::~QgsUniqueValueRenderer()
00069 {
00070   for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00071   {
00072     delete it.value();
00073   }
00074 }
00075 
00076 void QgsUniqueValueRenderer::insertValue( QString name, QgsSymbol* symbol )
00077 {
00078   mSymbols.insert( name, symbol );
00079   mSymbolAttributesDirty = true;
00080 }
00081 
00082 void QgsUniqueValueRenderer::setClassificationField( int field )
00083 {
00084   mClassificationField = field;
00085 }
00086 
00087 int QgsUniqueValueRenderer::classificationField() const
00088 {
00089   return mClassificationField;
00090 }
00091 
00092 bool QgsUniqueValueRenderer::willRenderFeature( QgsFeature *f )
00093 {
00094   return ( symbolForFeature( f ) != 0 );
00095 }
00096 
00097 void QgsUniqueValueRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature& f, QImage* img, bool selected, double opacity )
00098 {
00099   QPainter *p = renderContext.painter();
00100   QgsSymbol* symbol = symbolForFeature( &f );
00101   if ( !symbol ) //no matching symbol
00102   {
00103     if ( img && mGeometryType == QGis::Point )
00104     {
00105       img->fill( 0 );
00106     }
00107     else if ( mGeometryType != QGis::Point )
00108     {
00109       p->setPen( Qt::NoPen );
00110       p->setBrush( Qt::NoBrush );
00111     }
00112     return;
00113   }
00114 
00115   // Point
00116   if ( img && mGeometryType == QGis::Point )
00117   {
00118     double fieldScale = 1.0;
00119     double rotation = 0.0;
00120 
00121     if ( symbol->scaleClassificationField() >= 0 )
00122     {
00123       //first find out the value for the scale classification attribute
00124       fieldScale = sqrt( qAbs( f.attribute( symbol->scaleClassificationField() ).toDouble() ) );
00125     }
00126     if ( symbol->rotationClassificationField() >= 0 )
00127     {
00128       rotation = f.attribute( symbol->rotationClassificationField() ).toDouble();
00129     }
00130 
00131     QString oldName;
00132 
00133     if ( symbol->symbolField() >= 0 )
00134     {
00135       QString name = f.attribute( symbol->symbolField() ).toString();
00136       oldName = symbol->pointSymbolName();
00137       symbol->setNamedPointSymbol( name );
00138     }
00139 
00140     double scale = renderContext.scaleFactor();
00141 
00142     if ( symbol->pointSizeUnits() )
00143     {
00144       scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
00145     }
00146 
00147     *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor,
00148                                           fieldScale, rotation, renderContext.rasterScaleFactor(),
00149                                           opacity );
00150     if ( !oldName.isNull() )
00151     {
00152       symbol->setNamedPointSymbol( oldName );
00153     }
00154   }
00155   // Line, polygon
00156   else if ( mGeometryType != QGis::Point )
00157   {
00158     if ( !selected )
00159     {
00160       QPen pen = symbol->pen();
00161       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00162       p->setPen( pen );
00163       if ( mGeometryType == QGis::Polygon )
00164       {
00165         QBrush brush = symbol->brush();
00166         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00167         p->setBrush( brush );
00168       }
00169     }
00170     else
00171     {
00172       QPen pen = symbol->pen();
00173       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00174       if ( mGeometryType == QGis::Polygon )
00175       {
00176         QBrush brush = symbol->brush();
00177         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00178         brush.setColor( mSelectionColor );
00179         p->setBrush( brush );
00180       }
00181       else //don't draw outlines of polygons in selection color otherwise they appear merged
00182       {
00183         pen.setColor( mSelectionColor );
00184       }
00185       p->setPen( pen );
00186     }
00187   }
00188 }
00189 
00190 QgsSymbol *QgsUniqueValueRenderer::symbolForFeature( const QgsFeature *f )
00191 {
00192   //first find out the value
00193   QString value = f->attribute( mClassificationField ).toString();
00194 
00195   QMap<QString, QgsSymbol*>::iterator it = mSymbols.find( value );
00196   if ( it == mSymbols.end() )
00197   {
00198     it = mSymbols.find( QString::null );
00199   }
00200 
00201   if ( it == mSymbols.end() )
00202   {
00203     return 0;
00204   }
00205   else
00206   {
00207     return it.value();
00208   }
00209 }
00210 
00211 int QgsUniqueValueRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
00212 {
00213   mGeometryType = vl.geometryType();
00214   QDomNode classnode = rnode.namedItem( "classificationfield" );
00215   QString classificationField = classnode.toElement().text();
00216 
00217   QgsVectorDataProvider* theProvider = vl.dataProvider();
00218   if ( !theProvider )
00219   {
00220     return 1;
00221   }
00222 
00223   int classificationId = vl.fieldNameIndex( classificationField );
00224   if ( classificationId == -1 )
00225   {
00226     //go on. Because with joins, it might be the joined layer is not loaded yet
00227   }
00228   setClassificationField( classificationId );
00229 
00230   QDomNode symbolnode = rnode.namedItem( "symbol" );
00231   while ( !symbolnode.isNull() )
00232   {
00233     QgsSymbol* msy = new QgsSymbol( mGeometryType );
00234     msy->readXML( symbolnode, &vl );
00235     insertValue( msy->lowerValue(), msy );
00236     symbolnode = symbolnode.nextSibling();
00237   }
00238   updateSymbolAttributes();
00239   vl.setRenderer( this );
00240   return 0;
00241 }
00242 
00243 void QgsUniqueValueRenderer::clearValues()
00244 {
00245   for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00246   {
00247     delete it.value();
00248   }
00249   mSymbols.clear();
00250   updateSymbolAttributes();
00251 }
00252 
00253 void QgsUniqueValueRenderer::updateSymbolAttributes()
00254 {
00255   mSymbolAttributesDirty = false;
00256 
00257   mSymbolAttributes.clear();
00258 
00259   QMap<QString, QgsSymbol*>::iterator it;
00260   for ( it = mSymbols.begin(); it != mSymbols.end(); ++it )
00261   {
00262     int rotationField = ( *it )->rotationClassificationField();
00263     if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) )
00264     {
00265       mSymbolAttributes.append( rotationField );
00266     }
00267     int scaleField = ( *it )->scaleClassificationField();
00268     if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) )
00269     {
00270       mSymbolAttributes.append( scaleField );
00271     }
00272     int symbolField = ( *it )->symbolField();
00273     if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) )
00274     {
00275       mSymbolAttributes.append( symbolField );
00276     }
00277   }
00278 }
00279 
00280 QString QgsUniqueValueRenderer::name() const
00281 {
00282   return "Unique Value";
00283 }
00284 
00285 QgsAttributeList QgsUniqueValueRenderer::classificationAttributes() const
00286 {
00287   QgsAttributeList list( mSymbolAttributes );
00288   if ( ! list.contains( mClassificationField ) )
00289   {
00290     list.append( mClassificationField );
00291   }
00292   return list;
00293 }
00294 
00295 bool QgsUniqueValueRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
00296 {
00297   const QgsVectorDataProvider* theProvider = vl.dataProvider();
00298   if ( !theProvider )
00299   {
00300     return false;
00301   }
00302 
00303   QString classificationFieldName;
00304   const QgsFields& fields = vl.pendingFields();
00305   if ( mClassificationField >= 0 && mClassificationField < fields.count() )
00306   {
00307     classificationFieldName = fields[ mClassificationField ].name();
00308   }
00309 
00310   bool returnval = true;
00311   QDomElement uniquevalue = document.createElement( "uniquevalue" );
00312   layer_node.appendChild( uniquevalue );
00313   QDomElement classificationfield = document.createElement( "classificationfield" );
00314   QDomText classificationfieldtxt = document.createTextNode( classificationFieldName );
00315   classificationfield.appendChild( classificationfieldtxt );
00316   uniquevalue.appendChild( classificationfield );
00317   for ( QMap<QString, QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00318   {
00319     if ( !( it.value()->writeXML( uniquevalue, document, &vl ) ) )
00320     {
00321       returnval = false;
00322     }
00323   }
00324   return returnval;
00325 }
00326 
00327 QgsRenderer* QgsUniqueValueRenderer::clone() const
00328 {
00329   QgsUniqueValueRenderer* r = new QgsUniqueValueRenderer( *this );
00330   return r;
00331 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines