Quantum GIS API Documentation  master-2bfffaa
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                : 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 "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       QString name = f.attribute( mSymbol0->symbolField() ).toString();
00121       QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 );
00122 
00123       if ( !mSymbols.contains( name ) )
00124       {
00125         sy = new QgsSymbol( mGeometryType );
00126         sy->setNamedPointSymbol( name );
00127         mSymbols[ name ] = sy;
00128       }
00129       else
00130       {
00131         sy = mSymbols[ name ];
00132       }
00133 
00134       sy->setPointSize( mSymbol0->pointSize() );
00135       sy->setPointSizeUnits( mSymbol0->pointSizeUnits() );
00136     }
00137 
00138     if ( mSymbol0->scaleClassificationField() >= 0 )
00139     {
00140       //first find out the value for the scale classification attribute
00141       fieldScale = sqrt( qAbs( f.attribute( mSymbol0->scaleClassificationField() ).toDouble() ) );
00142       QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 );
00143     }
00144     if ( mSymbol0->rotationClassificationField() >= 0 )
00145     {
00146       rotation = f.attribute( mSymbol0->rotationClassificationField() ).toDouble();
00147       QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 );
00148     }
00149 
00150     double scale = renderContext.scaleFactor();
00151 
00152     if ( sy->pointSizeUnits() )
00153     {
00154       scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
00155     }
00156 
00157     *img = sy->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, rotation, renderContext.rasterScaleFactor(), opacity );
00158   }
00159 
00160   // Line, polygon
00161   if ( mGeometryType != QGis::Point )
00162   {
00163     if ( !selected )
00164     {
00165       QPen pen = mSymbol0->pen();
00166       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00167       p->setPen( pen );
00168 
00169       if ( mGeometryType == QGis::Polygon )
00170       {
00171         QBrush brush = mSymbol0->brush();
00172         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00173         p->setBrush( brush );
00174       }
00175     }
00176     else
00177     {
00178       QPen pen = mSymbol0->pen();
00179       pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
00180       if ( mGeometryType == QGis::Polygon )
00181       {
00182         QBrush brush = mSymbol0->brush();
00183         scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
00184         brush.setColor( mSelectionColor );
00185         p->setBrush( brush );
00186       }
00187       else //for lines we draw in selection color
00188       {
00189         // We set pen color in case it is an area with no brush (transparent).
00190         // Previously, this was only done for lines. Why?
00191         pen.setColor( mSelectionColor );
00192       }
00193       p->setPen( pen );
00194     }
00195   }
00196 }
00197 
00198 int QgsSingleSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
00199 {
00200   mGeometryType = vl.geometryType();
00201   QgsSymbol* sy = new QgsSymbol( mGeometryType );
00202 
00203   QDomNode synode = rnode.namedItem( "symbol" );
00204 
00205   if ( synode.isNull() )
00206   {
00207     QgsDebugMsg( "No symbol node in project file's renderitem Dom" );
00208     // XXX abort?
00209   }
00210   else
00211   {
00212     sy->readXML( synode, &vl );
00213   }
00214   updateSymbolAttributes();
00215 
00216   //create a renderer and add it to the vector layer
00217   addSymbol( sy );
00218   vl.setRenderer( this );
00219   return 0;
00220 }
00221 
00222 bool QgsSingleSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
00223 {
00224   bool returnval = false;
00225   QDomElement singlesymbol = document.createElement( "singlesymbol" );
00226   layer_node.appendChild( singlesymbol );
00227 
00228   if ( mSymbol0 )
00229   {
00230     returnval = mSymbol0->writeXML( singlesymbol, document, &vl );
00231   }
00232   return returnval;
00233 }
00234 
00235 
00236 QgsAttributeList QgsSingleSymbolRenderer::classificationAttributes() const
00237 {
00238   return mSymbolAttributes;
00239 }
00240 
00241 void QgsSingleSymbolRenderer::updateSymbolAttributes()
00242 {
00243   // This function is only called after changing field specifier in the GUI.
00244   // Timing is not so important.
00245 
00246   mSymbolAttributes.clear();
00247   int rotationField = mSymbol0->rotationClassificationField();
00248   if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) )
00249   {
00250     mSymbolAttributes.append( rotationField );
00251   }
00252   int scaleField = mSymbol0->scaleClassificationField();
00253   if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) )
00254   {
00255     mSymbolAttributes.append( scaleField );
00256   }
00257   int symbolField = mSymbol0->symbolField();
00258   if ( symbolField >= 0 && !( mSymbolAttributes.contains( symbolField ) ) )
00259   {
00260     mSymbolAttributes.append( symbolField );
00261   }
00262 }
00263 
00264 QString QgsSingleSymbolRenderer::name() const
00265 {
00266   return "Single Symbol";
00267 }
00268 
00269 const QList<QgsSymbol*> QgsSingleSymbolRenderer::symbols() const
00270 {
00271   return mSymbols.values();
00272 }
00273 
00274 QgsRenderer* QgsSingleSymbolRenderer::clone() const
00275 {
00276   QgsSingleSymbolRenderer* r = new QgsSingleSymbolRenderer( *this );
00277   return r;
00278 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines