Quantum GIS API Documentation  1.8
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       const QgsAttributeMap& attrs = f.attributeMap();
00125       fieldScale = sqrt( qAbs( attrs[symbol->scaleClassificationField()].toDouble() ) );
00126     }
00127     if ( symbol->rotationClassificationField() >= 0 )
00128     {
00129       const QgsAttributeMap& attrs = f.attributeMap();
00130       rotation = attrs[symbol->rotationClassificationField()].toDouble();
00131     }
00132 
00133     QString oldName;
00134 
00135     if ( symbol->symbolField() >= 0 )
00136     {
00137       const QgsAttributeMap& attrs = f.attributeMap();
00138       QString name = attrs[symbol->symbolField()].toString();
00139       oldName = symbol->pointSymbolName();
00140       symbol->setNamedPointSymbol( name );
00141     }
00142 
00143     double scale = renderContext.scaleFactor();
00144 
00145     if ( symbol->pointSizeUnits() )
00146     {
00147       scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
00148     }
00149 
00150     *img = symbol->getPointSymbolAsImage( scale, selected, mSelectionColor,
00151                                           fieldScale, rotation, renderContext.rasterScaleFactor(),
00152                                           opacity );
00153     if ( !oldName.isNull() )
00154     {
00155       symbol->setNamedPointSymbol( oldName );
00156     }
00157   }
00158   // Line, polygon
00159   else if ( mGeometryType != QGis::Point )
00160   {
00161     if ( !selected )
00162     {
00163       QPen pen = symbol->pen();
00164       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00165       p->setPen( pen );
00166       if ( mGeometryType == QGis::Polygon )
00167       {
00168         QBrush brush = symbol->brush();
00169         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00170         p->setBrush( brush );
00171       }
00172     }
00173     else
00174     {
00175       QPen pen = symbol->pen();
00176       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00177       if ( mGeometryType == QGis::Polygon )
00178       {
00179         QBrush brush = symbol->brush();
00180         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00181         brush.setColor( mSelectionColor );
00182         p->setBrush( brush );
00183       }
00184       else //don't draw outlines of polygons in selection color otherwise they appear merged
00185       {
00186         pen.setColor( mSelectionColor );
00187       }
00188       p->setPen( pen );
00189     }
00190   }
00191 }
00192 
00193 QgsSymbol *QgsUniqueValueRenderer::symbolForFeature( const QgsFeature *f )
00194 {
00195   //first find out the value
00196   const QgsAttributeMap& attrs = f->attributeMap();
00197   QString value = attrs[mClassificationField].toString();
00198 
00199   QMap<QString, QgsSymbol*>::iterator it = mSymbols.find( value );
00200   if ( it == mSymbols.end() )
00201   {
00202     it = mSymbols.find( QString::null );
00203   }
00204 
00205   if ( it == mSymbols.end() )
00206   {
00207     return 0;
00208   }
00209   else
00210   {
00211     return it.value();
00212   }
00213 }
00214 
00215 int QgsUniqueValueRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
00216 {
00217   mGeometryType = vl.geometryType();
00218   QDomNode classnode = rnode.namedItem( "classificationfield" );
00219   QString classificationField = classnode.toElement().text();
00220 
00221   QgsVectorDataProvider* theProvider = vl.dataProvider();
00222   if ( !theProvider )
00223   {
00224     return 1;
00225   }
00226 
00227   int classificationId = theProvider->fieldNameIndex( classificationField );
00228   if ( classificationId == -1 )
00229   {
00230     //go on. Because with joins, it might be the joined layer is not loaded yet
00231   }
00232   setClassificationField( classificationId );
00233 
00234   QDomNode symbolnode = rnode.namedItem( "symbol" );
00235   while ( !symbolnode.isNull() )
00236   {
00237     QgsSymbol* msy = new QgsSymbol( mGeometryType );
00238     msy->readXML( symbolnode, &vl );
00239     insertValue( msy->lowerValue(), msy );
00240     symbolnode = symbolnode.nextSibling();
00241   }
00242   updateSymbolAttributes();
00243   vl.setRenderer( this );
00244   return 0;
00245 }
00246 
00247 void QgsUniqueValueRenderer::clearValues()
00248 {
00249   for ( QMap<QString, QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00250   {
00251     delete it.value();
00252   }
00253   mSymbols.clear();
00254   updateSymbolAttributes();
00255 }
00256 
00257 void QgsUniqueValueRenderer::updateSymbolAttributes()
00258 {
00259   mSymbolAttributesDirty = false;
00260 
00261   mSymbolAttributes.clear();
00262 
00263   QMap<QString, QgsSymbol*>::iterator it;
00264   for ( it = mSymbols.begin(); it != mSymbols.end(); ++it )
00265   {
00266     int rotationField = ( *it )->rotationClassificationField();
00267     if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) )
00268     {
00269       mSymbolAttributes.append( rotationField );
00270     }
00271     int scaleField = ( *it )->scaleClassificationField();
00272     if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) )
00273     {
00274       mSymbolAttributes.append( scaleField );
00275     }
00276     int symbolField = ( *it )->symbolField();
00277     if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) )
00278     {
00279       mSymbolAttributes.append( symbolField );
00280     }
00281   }
00282 }
00283 
00284 QString QgsUniqueValueRenderer::name() const
00285 {
00286   return "Unique Value";
00287 }
00288 
00289 QgsAttributeList QgsUniqueValueRenderer::classificationAttributes() const
00290 {
00291   QgsAttributeList list( mSymbolAttributes );
00292   if ( ! list.contains( mClassificationField ) )
00293   {
00294     list.append( mClassificationField );
00295   }
00296   return list;
00297 }
00298 
00299 bool QgsUniqueValueRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
00300 {
00301   const QgsVectorDataProvider* theProvider = vl.dataProvider();
00302   if ( !theProvider )
00303   {
00304     return false;
00305   }
00306 
00307   QString classificationFieldName;
00308   QgsFieldMap::const_iterator field_it = theProvider->fields().find( mClassificationField );
00309   if ( field_it != theProvider->fields().constEnd() )
00310   {
00311     classificationFieldName = field_it.value().name();
00312   }
00313 
00314   bool returnval = true;
00315   QDomElement uniquevalue = document.createElement( "uniquevalue" );
00316   layer_node.appendChild( uniquevalue );
00317   QDomElement classificationfield = document.createElement( "classificationfield" );
00318   QDomText classificationfieldtxt = document.createTextNode( classificationFieldName );
00319   classificationfield.appendChild( classificationfieldtxt );
00320   uniquevalue.appendChild( classificationfield );
00321   for ( QMap<QString, QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
00322   {
00323     if ( !( it.value()->writeXML( uniquevalue, document, &vl ) ) )
00324     {
00325       returnval = false;
00326     }
00327   }
00328   return returnval;
00329 }
00330 
00331 QgsRenderer* QgsUniqueValueRenderer::clone() const
00332 {
00333   QgsUniqueValueRenderer* r = new QgsUniqueValueRenderer( *this );
00334   return r;
00335 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines