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