Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgsgraduatedsymbolrenderer.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: qgsgraduatedsymbolrenderer.cpp 5371 2006-04-25 01:52:13Z wonder $ */
18 
19 #include "qgis.h"
20 #include "qgslogger.h"
21 #include "qgsfeature.h"
23 #include "qgssymbol.h"
24 #include "qgssymbologyutils.h"
25 #include "qgsvectordataprovider.h"
26 #include "qgsvectorlayer.h"
27 #include "qgsrendercontext.h"
28 #include <cmath>
29 #include <QDomNode>
30 #include <QDomElement>
31 #include <QImage>
32 #include <QPainter>
33 
34 
36 {
37  mGeometryType = type;
38 }
39 
41 {
42  mMode = other.mMode;
45  const QList<QgsSymbol*> s = other.symbols();
46  for ( QList<QgsSymbol*>::const_iterator it = s.begin(); it != s.end(); ++it )
47  {
48  addSymbol( new QgsSymbol( **it ) );
49  }
51 }
52 
54 {
55  if ( this != &other )
56  {
57  mMode = other.mMode;
60  removeSymbols();
61  const QList<QgsSymbol*> s = other.symbols();
62  for ( QList<QgsSymbol*>::const_iterator it = s.begin(); it != s.end(); ++it )
63  {
64  addSymbol( new QgsSymbol( **it ) );
65  }
67  }
68 
69  return *this;
70 }
71 
73 {
74 
75 }
76 
77 
79 {
80  //mode is only really used to be able to reinstate
81  //the graduated dialog properties properly, so we
82  //don't do anything else besides accessors and mutators in
83  //this class
84  return mMode;
85 }
86 
88 {
89  //mode is only really used to be able to reinstate
90  //the graduated dialog properties properly, so we
91  //don't do anything else besides accessors and mutators in
92  //this class
93  mMode = theMode;
94 }
95 
96 const QList<QgsSymbol*> QgsGraduatedSymbolRenderer::symbols() const
97 {
98  return mSymbols;
99 }
100 
102 {
103  //free the memory first
104  for ( QList<QgsSymbol*>::iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
105  {
106  delete *it;
107  }
108 
109  //and remove the pointers then
110  mSymbols.clear();
112 }
113 
115 {
116  return ( symbolForFeature( f ) != 0 );
117 }
118 
119 void QgsGraduatedSymbolRenderer::renderFeature( QgsRenderContext &renderContext, QgsFeature & f, QImage* img, bool selected, double opacity )
120 {
121  QPainter *p = renderContext.painter();
122  QgsSymbol* theSymbol = symbolForFeature( &f );
123  if ( !theSymbol )
124  {
125  if ( img && mGeometryType == QGis::Point )
126  {
127  img->fill( 0 );
128  }
129  else if ( mGeometryType != QGis::Point )
130  {
131  p->setPen( Qt::NoPen );
132  p->setBrush( Qt::NoBrush );
133  }
134  return;
135  }
136 
137  //set the qpen and qpainter to the right values
138  // Point
139  if ( img && mGeometryType == QGis::Point )
140  {
141  double fieldScale = 1.0;
142  double rotation = 0.0;
143 
144  if ( theSymbol->scaleClassificationField() >= 0 )
145  {
146  //first find out the value for the scale classification attribute
147  const QgsAttributeMap& attrs = f.attributeMap();
148  fieldScale = sqrt( qAbs( attrs[theSymbol->scaleClassificationField()].toDouble() ) );
149  QgsDebugMsgLevel( QString( "Feature has field scale factor %1" ).arg( fieldScale ), 3 );
150  }
151  if ( theSymbol->rotationClassificationField() >= 0 )
152  {
153  const QgsAttributeMap& attrs = f.attributeMap();
154  rotation = attrs[theSymbol->rotationClassificationField()].toDouble();
155  QgsDebugMsgLevel( QString( "Feature has rotation factor %1" ).arg( rotation ), 3 );
156  }
157 
158  QString oldName;
159 
160  if ( theSymbol->symbolField() >= 0 )
161  {
162  const QgsAttributeMap& attrs = f.attributeMap();
163  QString name = attrs[theSymbol->symbolField()].toString();
164  QgsDebugMsgLevel( QString( "Feature has name %1" ).arg( name ), 3 );
165  oldName = theSymbol->pointSymbolName();
166  theSymbol->setNamedPointSymbol( name );
167  }
168 
169  double scale = renderContext.scaleFactor();
170 
171  if ( theSymbol->pointSizeUnits() )
172  {
173  scale = 1.0 / renderContext.mapToPixel().mapUnitsPerPixel();
174  }
175 
176  *img = theSymbol->getPointSymbolAsImage( scale, selected, mSelectionColor, fieldScale,
177  rotation, renderContext.rasterScaleFactor(), opacity );
178 
179  if ( !oldName.isNull() )
180  {
181  theSymbol->setNamedPointSymbol( oldName );
182  }
183  }
184 
185  // Line, polygon
186  if ( mGeometryType != QGis::Point )
187  {
188  if ( !selected )
189  {
190  QPen pen = theSymbol->pen();
191  pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
192  p->setPen( pen );
193 
194  if ( mGeometryType == QGis::Polygon )
195  {
196  QBrush brush = theSymbol->brush();
197  scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
198  p->setBrush( brush );
199  }
200  }
201  else
202  {
203  QPen pen = theSymbol->pen();
204  pen.setWidthF( renderContext.scaleFactor() * pen.widthF() );
205 
206  if ( mGeometryType == QGis::Polygon )
207  {
208  QBrush brush = theSymbol->brush();
209  scaleBrush( brush, renderContext.rasterScaleFactor() ); //scale brush content for printout
210  brush.setColor( mSelectionColor );
211  p->setBrush( brush );
212  }
213  else //don't draw outlines in selection color for polys otherwise they appear merged
214  {
215  pen.setColor( mSelectionColor );
216  }
217  p->setPen( pen );
218  }
219  }
220 }
221 
223 {
224  //first find out the value for the classification attribute
225  const QgsAttributeMap& attrs = f->attributeMap();
226  double value = attrs[mClassificationField].toDouble();
227 
228  QList<QgsSymbol*>::iterator it;
229  //find the first render item which contains the feature
230  for ( it = mSymbols.begin(); it != mSymbols.end(); ++it )
231  {
232  if ( value >= ( *it )->lowerValue().toDouble() && value <= ( *it )->upperValue().toDouble() )
233  {
234  break;
235  }
236  }
237 
238  if ( it == mSymbols.end() ) //only draw features which are covered by a render item
239  {
240  return 0;
241  }
242  return ( *it );
243 }
244 
245 int QgsGraduatedSymbolRenderer::readXML( const QDomNode& rnode, QgsVectorLayer& vl )
246 {
248  QDomNode modeNode = rnode.namedItem( "mode" );
249  QString modeValue = modeNode.toElement().text();
250  QDomNode classnode = rnode.namedItem( "classificationfield" );
251  QString classificationField = classnode.toElement().text();
252 
253  QgsVectorDataProvider* theProvider = vl.dataProvider();
254  if ( !theProvider )
255  {
256  return 1;
257  }
258  if ( modeValue == "Empty" )
259  {
261  }
262  else if ( modeValue == "Quantile" )
263  {
265  }
266  else //default
267  {
269  }
270 
271  int classificationId = vl.fieldNameIndex( classificationField );
272  if ( classificationId == -1 )
273  {
274  //go on. Because with joins, it might be the joined layer is not loaded yet
275  }
276  setClassificationField( classificationId );
277 
278  QDomNode symbolnode = rnode.namedItem( "symbol" );
279  while ( !symbolnode.isNull() )
280  {
281  QgsSymbol* sy = new QgsSymbol( mGeometryType );
282  sy->readXML( symbolnode, &vl );
283  addSymbol( sy );
284 
285  symbolnode = symbolnode.nextSibling();
286  }
288  vl.setRenderer( this );
289  return 0;
290 }
291 
293 {
295  if ( ! list.contains( mClassificationField ) )
296  {
297  list.append( mClassificationField );
298  }
299  return list;
300 }
301 
303 {
304  // This function is only called after changing field specifier in the GUI.
305  // Timing is not so important.
306 
307  mSymbolAttributes.clear();
308 
309  QList<QgsSymbol*>::iterator it;
310  for ( it = mSymbols.begin(); it != mSymbols.end(); ++it )
311  {
312  int rotationField = ( *it )->rotationClassificationField();
313  if ( rotationField >= 0 && !mSymbolAttributes.contains( rotationField ) )
314  {
315  mSymbolAttributes.append( rotationField );
316  }
317  int scaleField = ( *it )->scaleClassificationField();
318  if ( scaleField >= 0 && !mSymbolAttributes.contains( scaleField ) )
319  {
320  mSymbolAttributes.append( scaleField );
321  }
322  int symbolField = ( *it )->symbolField();
323  if ( symbolField >= 0 && !mSymbolAttributes.contains( symbolField ) )
324  {
325  mSymbolAttributes.append( symbolField );
326  }
327  }
328 }
329 
331 {
332  return "Graduated Symbol";
333 }
334 
335 bool QgsGraduatedSymbolRenderer::writeXML( QDomNode & layer_node, QDomDocument & document, const QgsVectorLayer& vl ) const
336 {
337  bool returnval = true;
338  QDomElement graduatedsymbol = document.createElement( "graduatedsymbol" );
339  layer_node.appendChild( graduatedsymbol );
340 
341  //
342  // Mode field first ...
343  //
344 
345  QString modeValue = "";
347  {
348  modeValue == "Empty";
349  }
351  {
352  modeValue = "Quantile";
353  }
354  else //default
355  {
356  modeValue = "Equal Interval";
357  }
358  QDomElement modeElement = document.createElement( "mode" );
359  QDomText modeText = document.createTextNode( modeValue );
360  modeElement.appendChild( modeText );
361  graduatedsymbol.appendChild( modeElement );
362 
363 
364 
365  //
366  // classification field now ...
367  //
368 
369  QDomElement classificationfield = document.createElement( "classificationfield" );
370 
371  const QgsVectorDataProvider* theProvider = vl.dataProvider();
372  if ( !theProvider )
373  {
374  return false;
375  }
376 
377  QString classificationFieldName;
378  if ( vl.pendingFields().contains( mClassificationField ) )
379  {
380  classificationFieldName = vl.pendingFields()[ mClassificationField ].name();
381  }
382 
383  QDomText classificationfieldtxt = document.createTextNode( classificationFieldName );
384  classificationfield.appendChild( classificationfieldtxt );
385  graduatedsymbol.appendChild( classificationfield );
386  for ( QList<QgsSymbol*>::const_iterator it = mSymbols.begin(); it != mSymbols.end(); ++it )
387  {
388  if ( !( *it )->writeXML( graduatedsymbol, document, &vl ) )
389  {
390  returnval = false;
391  }
392  }
393  return returnval;
394 }
395 
397 {
399  return r;
400 }