Quantum GIS API Documentation  1.8
src/core/renderer/qgssinglesymbolrenderer.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                : [email protected]
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 "qgssinglesymbolrenderer.h"
00020 
00021 #include "qgsfeature.h"
00022 #include "qgslogger.h"
00023 #include "qgssymbol.h"
00024 #include "qgssymbologyutils.h"
00025 #include "qgsvectorlayer.h"
00026 #include "qgsrendercontext.h"
00027 
00028 #include <QDomNode>
00029 #include <QImage>
00030 #include <QPainter>
00031 #include <QString>
00032 #include <cmath>
00033 
00034 QgsSingleSymbolRenderer::QgsSingleSymbolRenderer( QGis::GeometryType type )
00035 {
00036   mGeometryType = type;
00037 
00038   //initial setting based on random color
00039   QgsSymbol* sy = new QgsSymbol( mGeometryType );
00040 
00041   //random fill colors for points and polygons and pen colors for lines
00042   int red = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
00043   int green = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
00044   int blue = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
00045 
00046   if ( type == QGis::Line )
00047   {
00048     sy->setColor( QColor( red, green, blue ) );
00049   }
00050   else
00051   {
00052     sy->setFillColor( QColor( red, green, blue ) );
00053     sy->setFillStyle( Qt::SolidPattern );
00054     sy->setColor( QColor( 0, 0, 0 ) );
00055   }
00056   mSymbol0 = sy;
00057   mSymbols[ QString()] = sy;
00058   updateSymbolAttributes();
00059 }
00060 
00061 QgsSingleSymbolRenderer::QgsSingleSymbolRenderer( const QgsSingleSymbolRenderer& other )
00062 {
00063   *this = other;
00064 }
00065 
00066 QgsSingleSymbolRenderer& QgsSingleSymbolRenderer::operator=( const QgsSingleSymbolRenderer & other )
00067 {
00068   if ( this != &other )
00069   {
00070     mGeometryType = other.mGeometryType;
00071 
00072     for ( QMap<QString, QgsSymbol *>::const_iterator it = other.mSymbols.begin(); it != other.mSymbols.end(); it++ )
00073       mSymbols[ it.key()] = new QgsSymbol( *it.value() );
00074 
00075     if ( mSymbols.size() > 0 )
00076     {
00077       mSymbol0 = mSymbols[0];
00078     }
00079     else
00080     {
00081       mSymbol0 = 0;
00082     }
00083   }
00084   updateSymbolAttributes();
00085   return *this;
00086 }
00087 
00088 QgsSingleSymbolRenderer::~QgsSingleSymbolRenderer()
00089 {
00090   for ( QMap<QString, QgsSymbol *>::iterator it = mSymbols.begin(); it != mSymbols.end(); it++ )
00091     delete it.value();
00092 }
00093 
00094 void QgsSingleSymbolRenderer::addSymbol( QgsSymbol *sy )
00095 {
00096   for ( QMap<QString, QgsSymbol *>::iterator it = mSymbols.begin(); it != mSymbols.end(); it++ )
00097     delete it.value();
00098 
00099   mSymbol0 = sy;
00100   mSymbols[ QString()] = sy;
00101 
00102   updateSymbolAttributes();
00103 }
00104 
00105 void QgsSingleSymbolRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature & f, QImage* img, bool selected, double opacity )
00106 {
00107   QPainter *p = renderContext.painter();
00108 
00109   // Point
00110   if ( img && mGeometryType == QGis::Point )
00111   {
00112 
00113     // If scale field is non-negative, use it to scale.
00114     double fieldScale = 1.0;
00115     double rotation = 0.0;
00116     QgsSymbol *sy = mSymbol0;
00117 
00118     if ( mSymbol0->symbolField() >= 0 )
00119     {
00120       const QgsAttributeMap& attrs = f.attributeMap();
00121       QString name = attrs[ mSymbol0->symbolField()].toString();
00122       QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 );
00123 
00124       if ( !mSymbols.contains( name ) )
00125       {
00126         sy = new QgsSymbol( mGeometryType );
00127         sy->setNamedPointSymbol( name );
00128         mSymbols[ name ] = sy;
00129       }
00130       else
00131       {
00132         sy = mSymbols[ name ];
00133       }
00134 
00135       sy->setPointSize( mSymbol0->pointSize() );
00136       sy->setPointSizeUnits( mSymbol0->pointSizeUnits() );
00137     }
00138 
00139     if ( mSymbol0->scaleClassificationField() >= 0 )
00140     {
00141       //first find out the value for the scale classification attribute
00142       const QgsAttributeMap& attrs = f.attributeMap();
00143       fieldScale = sqrt( qAbs( attrs[ mSymbol0->scaleClassificationField()].toDouble() ) );
00144       QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 );
00145     }
00146     if ( mSymbol0->rotationClassificationField() >= 0 )
00147     {
00148       const QgsAttributeMap& attrs = f.attributeMap();
00149       rotation = attrs[ mSymbol0->rotationClassificationField()].toDouble();
00150       QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 );
00151     }
00152 
00153     double scale = renderContext.scaleFactor();
00154 
00155     if ( sy->pointSizeUnits() )
00156     {
00157       scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
00158     }
00159 
00160     *img = sy->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, rotation, renderContext.rasterScaleFactor(), opacity );
00161   }
00162 
00163   // Line, polygon
00164   if ( mGeometryType != QGis::Point )
00165   {
00166     if ( !selected )
00167     {
00168       QPen pen = mSymbol0->pen();
00169       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00170       p->setPen( pen );
00171 
00172       if ( mGeometryType == QGis::Polygon )
00173       {
00174         QBrush brush = mSymbol0->brush();
00175         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00176         p->setBrush( brush );
00177       }
00178     }
00179     else
00180     {
00181       QPen pen = mSymbol0->pen();
00182       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00183       if ( mGeometryType == QGis::Polygon )
00184       {
00185         QBrush brush = mSymbol0->brush();
00186         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00187         brush.setColor( mSelectionColor );
00188         p->setBrush( brush );
00189       }
00190       else //for lines we draw in selection color
00191       {
00192         // We set pen color in case it is an area with no brush (transparent).
00193         // Previously, this was only done for lines. Why?
00194         pen.setColor( mSelectionColor );
00195       }
00196       p->setPen( pen );
00197     }
00198   }
00199 }
00200 
00201 int QgsSingleSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
00202 {
00203   mGeometryType = vl.geometryType();
00204   QgsSymbol* sy = new QgsSymbol( mGeometryType );
00205 
00206   QDomNode synode = rnode.namedItem( "symbol" );
00207 
00208   if ( synode.isNull() )
00209   {
00210     QgsDebugMsg( "No symbol node in project file's renderitem Dom" );
00211     // XXX abort?
00212   }
00213   else
00214   {
00215     sy->readXML( synode, &vl );
00216   }
00217   updateSymbolAttributes();
00218 
00219   //create a renderer and add it to the vector layer
00220   addSymbol( sy );
00221   vl.setRenderer( this );
00222   return 0;
00223 }
00224 
00225 bool QgsSingleSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
00226 {
00227   bool returnval = false;
00228   QDomElement singlesymbol = document.createElement( "singlesymbol" );
00229   layer_node.appendChild( singlesymbol );
00230 
00231   if ( mSymbol0 )
00232   {
00233     returnval = mSymbol0->writeXML( singlesymbol, document, &vl );
00234   }
00235   return returnval;
00236 }
00237 
00238 
00239 QgsAttributeList QgsSingleSymbolRenderer::classificationAttributes() const
00240 {
00241   return mSymbolAttributes;
00242 }
00243 
00244 void QgsSingleSymbolRenderer::updateSymbolAttributes()
00245 {
00246   // This function is only called after changing field specifier in the GUI.
00247   // Timing is not so important.
00248 
00249   mSymbolAttributes.clear();
00250   int rotationField = mSymbol0->rotationClassificationField();
00251   if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) )
00252   {
00253     mSymbolAttributes.append( rotationField );
00254   }
00255   int scaleField = mSymbol0->scaleClassificationField();
00256   if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) )
00257   {
00258     mSymbolAttributes.append( scaleField );
00259   }
00260   int symbolField = mSymbol0->symbolField();
00261   if ( symbolField >= 0 && !( mSymbolAttributes.contains( symbolField ) ) )
00262   {
00263     mSymbolAttributes.append( symbolField );
00264   }
00265 }
00266 
00267 QString QgsSingleSymbolRenderer::name() const
00268 {
00269   return "Single Symbol";
00270 }
00271 
00272 const QList<QgsSymbol*> QgsSingleSymbolRenderer::symbols() const
00273 {
00274   return mSymbols.values();
00275 }
00276 
00277 QgsRenderer* QgsSingleSymbolRenderer::clone() const
00278 {
00279   QgsSingleSymbolRenderer* r = new QgsSingleSymbolRenderer( *this );
00280   return r;
00281 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines