Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgssinglesymbolrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglesymbolrenderer.cpp - description
3  -------------------
4  begin : Oct 2003
5  copyright : (C) 2003 by Marco Hugentobler
6  email : mhugent@geo.unizh.ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 /* $Id: qgssinglesymbolrenderer.cpp 5371 2006-04-25 01:52:13Z wonder $ */
18 
19 #include "qgis.h"
21 
22 #include "qgsfeature.h"
23 #include "qgslogger.h"
24 #include "qgssymbol.h"
25 #include "qgssymbologyutils.h"
26 #include "qgsvectorlayer.h"
27 #include "qgsrendercontext.h"
28 
29 #include <QDomNode>
30 #include <QImage>
31 #include <QPainter>
32 #include <QString>
33 #include <cmath>
34 
36 {
37  mGeometryType = type;
38 
39  //initial setting based on random color
40  QgsSymbol* sy = new QgsSymbol( mGeometryType );
41 
42  //random fill colors for points and polygons and pen colors for lines
43  int red = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
44  int green = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
45  int blue = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
46 
47  if ( type == QGis::Line )
48  {
49  sy->setColor( QColor( red, green, blue ) );
50  }
51  else
52  {
53  sy->setFillColor( QColor( red, green, blue ) );
54  sy->setFillStyle( Qt::SolidPattern );
55  sy->setColor( QColor( 0, 0, 0 ) );
56  }
57  mSymbol0 = sy;
58  mSymbols[ QString()] = sy;
60 }
61 
63 {
64  *this = other;
65 }
66 
68 {
69  if ( this != &other )
70  {
72 
73  for ( QMap<QString, QgsSymbol *>::const_iterator it = other.mSymbols.begin(); it != other.mSymbols.end(); it++ )
74  mSymbols[ it.key()] = new QgsSymbol( *it.value() );
75 
76  if ( mSymbols.size() > 0 )
77  {
78  mSymbol0 = mSymbols[0];
79  }
80  else
81  {
82  mSymbol0 = 0;
83  }
84  }
86  return *this;
87 }
88 
90 {
91  for ( QMap<QString, QgsSymbol *>::iterator it = mSymbols.begin(); it != mSymbols.end(); it++ )
92  delete it.value();
93 }
94 
96 {
97  for ( QMap<QString, QgsSymbol *>::iterator it = mSymbols.begin(); it != mSymbols.end(); it++ )
98  delete it.value();
99 
100  mSymbol0 = sy;
101  mSymbols[ QString()] = sy;
102 
104 }
105 
106 void QgsSingleSymbolRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature & f, QImage* img, bool selected, double opacity )
107 {
108  QPainter *p = renderContext.painter();
109 
110  // Point
111  if ( img && mGeometryType == QGis::Point )
112  {
113 
114  // If scale field is non-negative, use it to scale.
115  double fieldScale = 1.0;
116  double rotation = 0.0;
117  QgsSymbol *sy = mSymbol0;
118 
119  if ( mSymbol0->symbolField() >= 0 )
120  {
121  const QgsAttributeMap& attrs = f.attributeMap();
122  QString name = attrs[ mSymbol0->symbolField()].toString();
123  QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 );
124 
125  if ( !mSymbols.contains( name ) )
126  {
127  sy = new QgsSymbol( mGeometryType );
128  sy->setNamedPointSymbol( name );
129  mSymbols[ name ] = sy;
130  }
131  else
132  {
133  sy = mSymbols[ name ];
134  }
135 
136  sy->setPointSize( mSymbol0->pointSize() );
138  }
139 
140  if ( mSymbol0->scaleClassificationField() >= 0 )
141  {
142  //first find out the value for the scale classification attribute
143  const QgsAttributeMap& attrs = f.attributeMap();
144  fieldScale = sqrt( qAbs( attrs[ mSymbol0->scaleClassificationField()].toDouble() ) );
145  QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 );
146  }
148  {
149  const QgsAttributeMap& attrs = f.attributeMap();
150  rotation = attrs[ mSymbol0->rotationClassificationField()].toDouble();
151  QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 );
152  }
153 
154  double scale = renderContext.scaleFactor();
155 
156  if ( sy->pointSizeUnits() )
157  {
158  scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
159  }
160 
161  *img = sy->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale, rotation, renderContext.rasterScaleFactor(), opacity );
162  }
163 
164  // Line, polygon
165  if ( mGeometryType != QGis::Point )
166  {
167  if ( !selected )
168  {
169  QPen pen = mSymbol0->pen();
170  pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
171  p->setPen( pen );
172 
173  if ( mGeometryType == QGis::Polygon )
174  {
175  QBrush brush = mSymbol0->brush();
176  scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
177  p->setBrush( brush );
178  }
179  }
180  else
181  {
182  QPen pen = mSymbol0->pen();
183  pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
184  if ( mGeometryType == QGis::Polygon )
185  {
186  QBrush brush = mSymbol0->brush();
187  scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
188  brush.setColor( mSelectionColor );
189  p->setBrush( brush );
190  }
191  else //for lines we draw in selection color
192  {
193  // We set pen color in case it is an area with no brush (transparent).
194  // Previously, this was only done for lines. Why?
195  pen.setColor( mSelectionColor );
196  }
197  p->setPen( pen );
198  }
199  }
200 }
201 
202 int QgsSingleSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
203 {
205  QgsSymbol* sy = new QgsSymbol( mGeometryType );
206 
207  QDomNode synode = rnode.namedItem( "symbol" );
208 
209  if ( synode.isNull() )
210  {
211  QgsDebugMsg( "No symbol node in project file's renderitem Dom" );
212  // XXX abort?
213  }
214  else
215  {
216  sy->readXML( synode, &vl );
217  }
219 
220  //create a renderer and add it to the vector layer
221  addSymbol( sy );
222  vl.setRenderer( this );
223  return 0;
224 }
225 
226 bool QgsSingleSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
227 {
228  bool returnval = false;
229  QDomElement singlesymbol = document.createElement( "singlesymbol" );
230  layer_node.appendChild( singlesymbol );
231 
232  if ( mSymbol0 )
233  {
234  returnval = mSymbol0->writeXML( singlesymbol, document, &vl );
235  }
236  return returnval;
237 }
238 
239 
241 {
242  return mSymbolAttributes;
243 }
244 
246 {
247  // This function is only called after changing field specifier in the GUI.
248  // Timing is not so important.
249 
250  mSymbolAttributes.clear();
251  int rotationField = mSymbol0->rotationClassificationField();
252  if ( rotationField >= 0 && !( mSymbolAttributes.contains( rotationField ) ) )
253  {
254  mSymbolAttributes.append( rotationField );
255  }
256  int scaleField = mSymbol0->scaleClassificationField();
257  if ( scaleField >= 0 && !( mSymbolAttributes.contains( scaleField ) ) )
258  {
259  mSymbolAttributes.append( scaleField );
260  }
261  int symbolField = mSymbol0->symbolField();
262  if ( symbolField >= 0 && !( mSymbolAttributes.contains( symbolField ) ) )
263  {
264  mSymbolAttributes.append( symbolField );
265  }
266 }
267 
269 {
270  return "Single Symbol";
271 }
272 
273 const QList<QgsSymbol*> QgsSingleSymbolRenderer::symbols() const
274 {
275  return mSymbols.values();
276 }
277 
279 {
281  return r;
282 }