QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgssymbolv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbolv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgssymbolv2.h"
17 #include "qgssymbollayerv2.h"
18 
19 #include "qgslinesymbollayerv2.h"
20 #include "qgsmarkersymbollayerv2.h"
21 #include "qgsfillsymbollayerv2.h"
22 
23 #include "qgslogger.h"
24 #include "qgsrendercontext.h" // for bigSymbolPreview
25 
26 #include "qgsproject.h"
27 #include "qgsstylev2.h"
28 
29 #include <QColor>
30 #include <QImage>
31 #include <QPainter>
32 #include <QSize>
33 
34 #include <cmath>
35 
37  : mType( type ), mLayers( layers ), mAlpha( 1.0 ), mRenderHints( 0 ), mLayer( NULL )
38 {
39 
40  // check they're all correct symbol layers
41  for ( int i = 0; i < mLayers.count(); i++ )
42  {
43  if ( mLayers[i] == NULL )
44  {
45  mLayers.removeAt( i-- );
46  }
47  else if ( !isSymbolLayerCompatible( mLayers[i]->type() ) )
48  {
49  delete mLayers[i];
50  mLayers.removeAt( i-- );
51  }
52  }
53 
54 }
55 
57 {
58  // delete all symbol layers (we own them, so it's okay)
59  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
60  delete *it;
61 }
62 
64 {
66 
67  QgsSymbolLayerV2List::const_iterator it = mLayers.constBegin();
68  for ( ; it != mLayers.constEnd(); ++it )
69  {
70  if ( it == mLayers.constBegin() )
71  {
72  unit = ( *it )->outputUnit();
73  }
74  else
75  {
76  if (( *it )->outputUnit() != unit )
77  {
78  return QgsSymbolV2::Mixed;
79  }
80  }
81  }
82 
83  return unit;
84 }
85 
87 {
88  QgsSymbolLayerV2List::iterator it = mLayers.begin();
89  for ( ; it != mLayers.end(); ++it )
90  {
91  ( *it )->setOutputUnit( u );
92  }
93 }
94 
96 {
97  QgsSymbolV2* s = 0;
98 
99  // override global default if project has a default for this type
100  QString defaultSymbol;
101  switch ( geomType )
102  {
103  case QGis::Point :
104  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Marker", "" );
105  break;
106  case QGis::Line :
107  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Line", "" );
108  break;
109  case QGis::Polygon :
110  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Fill", "" );
111  break;
112  default: defaultSymbol = ""; break;
113  }
114  if ( defaultSymbol != "" )
115  s = QgsStyleV2::defaultStyle()->symbol( defaultSymbol );
116 
117  // if no default found for this type, get global default (as previously)
118  if ( ! s )
119  {
120  switch ( geomType )
121  {
122  case QGis::Point: s = new QgsMarkerSymbolV2(); break;
123  case QGis::Line: s = new QgsLineSymbolV2(); break;
124  case QGis::Polygon: s = new QgsFillSymbolV2(); break;
125  default: QgsDebugMsg( "unknown layer's geometry type" ); return NULL;
126  }
127  }
128 
129  // set alpha transparency
130  s->setAlpha( QgsProject::instance()->readDoubleEntry( "DefaultStyles", "/AlphaInt", 255 ) / 255.0 );
131 
132  // set random color, it project prefs allow
133  if ( defaultSymbol == "" ||
134  QgsProject::instance()->readBoolEntry( "DefaultStyles", "/RandomColors", true ) )
135  {
136  s->setColor( QColor::fromHsv( rand() % 360, 64 + rand() % 192, 128 + rand() % 128 ) );
137  }
138 
139  return s;
140 }
141 
143 {
144  if ( layer < 0 || layer >= mLayers.count() )
145  return NULL;
146 
147  return mLayers[layer];
148 }
149 
150 
152 {
153  // fill symbol can contain also line symbol layers for drawing of outlines
154  if ( mType == Fill && t == Line )
155  return true;
156 
157  return mType == t;
158 }
159 
160 
162 {
163  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
164  return false;
165  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
166  return false;
167 
168  mLayers.insert( index, layer );
169  return true;
170 }
171 
172 
174 {
175  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
176  return false;
177 
178  mLayers.append( layer );
179  return true;
180 }
181 
182 
184 {
185  if ( index < 0 || index >= mLayers.count() )
186  return false;
187 
188  delete mLayers[index];
189  mLayers.removeAt( index );
190  return true;
191 }
192 
193 
195 {
196  if ( index < 0 || index >= mLayers.count() )
197  return NULL;
198 
199  return mLayers.takeAt( index );
200 }
201 
202 
204 {
205  if ( index < 0 || index >= mLayers.count() )
206  return false;
207  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
208  return false;
209 
210  delete mLayers[index]; // first delete the original layer
211  mLayers[index] = layer; // set new layer
212  return true;
213 }
214 
215 
217 {
218  mLayer = layer;
219 
220  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints );
221  symbolContext.setLayer( mLayer );
222 
223  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
224  ( *it )->startRender( symbolContext );
225 }
226 
228 {
229  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints );
230  symbolContext.setLayer( mLayer );
231 
232  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
233  ( *it )->stopRender( symbolContext );
234 
235  mLayer = NULL;
236 }
237 
238 void QgsSymbolV2::setColor( const QColor& color )
239 {
240  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
241  {
242  if ( !( *it )->isLocked() )
243  ( *it )->setColor( color );
244  }
245 }
246 
247 QColor QgsSymbolV2::color() const
248 {
249  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
250  {
251  // return color of the first unlocked layer
252  if ( !( *it )->isLocked() )
253  return ( *it )->color();
254  }
255  return QColor( 0, 0, 0 );
256 }
257 
258 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size )
259 {
261  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints );
262  symbolContext.setLayer( mLayer );
263 
264  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
265  {
266  if ( mType == Fill && ( *it )->type() == Line )
267  {
268  // line symbol layer would normally draw just a line
269  // so we override this case to force it to draw a polygon outline
271 
272  // from QgsFillSymbolLayerV2::drawPreviewIcon()
273  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
274  lsl->startRender( symbolContext );
275  lsl->renderPolygonOutline( poly, NULL, symbolContext );
276  lsl->stopRender( symbolContext );
277  }
278  else
279  ( *it )->drawPreviewIcon( symbolContext, size );
280  }
281 }
282 
283 
285 {
286  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
287  preview.fill( 0 );
288 
289  QPainter p( &preview );
290  p.setRenderHint( QPainter::Antialiasing );
291  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
292 
293  if ( mType == QgsSymbolV2::Marker )
294  {
295  p.setPen( QPen( Qt::gray ) );
296  p.drawLine( 0, 50, 100, 50 );
297  p.drawLine( 50, 0, 50, 100 );
298  }
299 
301  startRender( context );
302 
303  if ( mType == QgsSymbolV2::Line )
304  {
305  QPolygonF poly;
306  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
307  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, 0, context );
308  }
309  else if ( mType == QgsSymbolV2::Fill )
310  {
311  QPolygonF polygon;
312  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
313  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, NULL, 0, context );
314  }
315  else // marker
316  {
317  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), 0, context );
318  }
319 
320  stopRender( context );
321  return preview;
322 }
323 
324 
325 QString QgsSymbolV2::dump() const
326 {
327  QString t;
328  switch ( type() )
329  {
330  case QgsSymbolV2::Marker: t = "MARKER"; break;
331  case QgsSymbolV2::Line: t = "LINE"; break;
332  case QgsSymbolV2::Fill: t = "FILL"; break;
333  default: Q_ASSERT( 0 && "unknown symbol type" );
334  }
335  QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
336 
337  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
338  {
339  // TODO:
340  }
341  return s;
342 }
343 
344 void QgsSymbolV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
345 {
346  props[ "alpha" ] = QString::number( alpha() );
347  double scaleFactor = 1.0;
348  props[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
349  props[ "uomScale" ] = scaleFactor != 1 ? QString::number( scaleFactor ) : "";
350 
351  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
352  {
353  ( *it )->toSld( doc, element, props );
354  }
355 }
356 
358 {
360  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
361  {
362  QgsSymbolLayerV2* layer = ( *it )->clone();
363  layer->setLocked(( *it )->isLocked() );
364  layer->setRenderingPass(( *it )->renderingPass() );
365  lst.append( layer );
366  }
367  return lst;
368 }
369 
370 QSet<QString> QgsSymbolV2::usedAttributes() const
371 {
372  QSet<QString> attributes;
373  QgsSymbolLayerV2List::const_iterator sIt = mLayers.constBegin();
374  for ( ; sIt != mLayers.constEnd(); ++sIt )
375  {
376  if ( *sIt )
377  {
378  attributes.unite(( *sIt )->usedAttributes() );
379  }
380  }
381  return attributes;
382 }
383 
385 
386 
387 QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected, int renderHints, const QgsFeature* f )
388  : mRenderContext( c ), mOutputUnit( u ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints ), mFeature( f ), mLayer( 0 )
389 {
390 
391 }
392 
394 {
395 
396 }
397 
398 
399 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
400 {
402 }
403 
405 {
407 }
408 
410 {
411  // This is just a dummy implementation of assignment.
412  // sip 4.7 generates a piece of code that needs this function to exist.
413  // It's not generated automatically by the compiler because of
414  // mRenderContext member which is a reference (and thus can't be changed).
415  Q_ASSERT( false );
416  return *this;
417 }
418 
420 
422 {
424  if ( sl == NULL )
425  return NULL;
426 
427  QgsSymbolLayerV2List layers;
428  layers.append( sl );
429  return new QgsMarkerSymbolV2( layers );
430 }
431 
433 {
435  if ( sl == NULL )
436  return NULL;
437 
438  QgsSymbolLayerV2List layers;
439  layers.append( sl );
440  return new QgsLineSymbolV2( layers );
441 }
442 
444 {
446  if ( sl == NULL )
447  return NULL;
448 
449  QgsSymbolLayerV2List layers;
450  layers.append( sl );
451  return new QgsFillSymbolV2( layers );
452 }
453 
455 
456 
458  : QgsSymbolV2( Marker, layers )
459 {
460  if ( mLayers.count() == 0 )
461  mLayers.append( new QgsSimpleMarkerSymbolLayerV2() );
462 }
463 
464 void QgsMarkerSymbolV2::setAngle( double ang )
465 {
466  double origAngle = angle();
467  double angleDiff = ang - origAngle;
468  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
469  {
471  layer->setAngle( layer->angle() + angleDiff );
472  }
473 }
474 
476 {
477  QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
478 
479  if ( it == mLayers.end() )
480  return 0;
481 
482  // return angle of the first symbol layer
483  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
484  return layer->angle();
485 }
486 
488 {
489  double origSize = size();
490 
491  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
492  {
493  QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
494  if ( layer->size() == origSize )
495  layer->setSize( s );
496  else
497  {
498  // proportionally scale size
499  if ( origSize != 0 )
500  layer->setSize( layer->size() * s / origSize );
501  }
502  }
503 }
504 
506 {
507  // return size of the largest symbol
508  double maxSize = 0;
509  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
510  {
511  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
512  double lsize = layer->size();
513  if ( lsize > maxSize )
514  maxSize = lsize;
515  }
516  return maxSize;
517 }
518 
519 
521 {
522  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
523  {
524  QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
525  layer->setScaleMethod( scaleMethod );
526  }
527 }
528 
530 {
531  QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
532 
533  if ( it == mLayers.end() )
534  return DEFAULT_SCALE_METHOD;
535 
536  // return scale method of the first symbol layer
537  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
538  return layer->scaleMethod();
539 }
540 
541 void QgsMarkerSymbolV2::renderPoint( const QPointF& point, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
542 {
543  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f );
544  symbolContext.setLayer( mLayer );
545 
546  if ( layer != -1 )
547  {
548  if ( layer >= 0 && layer < mLayers.count() )
549  (( QgsMarkerSymbolLayerV2* ) mLayers[layer] )->renderPoint( point, symbolContext );
550  return;
551  }
552 
553  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
554  {
556  layer->renderPoint( point, symbolContext );
557  }
558 }
559 
561 {
562  QgsSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
563  cloneSymbol->setAlpha( mAlpha );
564  return cloneSymbol;
565 }
566 
567 
569 // LINE
570 
572  : QgsSymbolV2( Line, layers )
573 {
574  if ( mLayers.count() == 0 )
575  mLayers.append( new QgsSimpleLineSymbolLayerV2() );
576 }
577 
579 {
580  double origWidth = width();
581 
582  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
583  {
585  if ( layer->width() == origWidth )
586  {
587  layer->setWidth( w );
588  }
589  else
590  {
591  // proportionally scale the width
592  if ( origWidth != 0 )
593  layer->setWidth( layer->width() * w / origWidth );
594  }
595  }
596 }
597 
599 {
600  double maxWidth = 0;
601  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
602  {
603  const QgsLineSymbolLayerV2* layer = ( const QgsLineSymbolLayerV2* ) * it;
604  double width = layer->width();
605  if ( width > maxWidth )
606  maxWidth = width;
607  }
608  return maxWidth;
609 }
610 
611 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
612 {
613  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f );
614  symbolContext.setLayer( mLayer );
615 
616  if ( layer != -1 )
617  {
618  if ( layer >= 0 && layer < mLayers.count() )
619  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolyline( points, symbolContext );
620  return;
621  }
622 
623  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
624  {
625  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
626  layer->renderPolyline( points, symbolContext );
627  }
628 }
629 
630 
632 {
633  QgsSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
634  cloneSymbol->setAlpha( mAlpha );
635  return cloneSymbol;
636 }
637 
639 // FILL
640 
642  : QgsSymbolV2( Fill, layers )
643 {
644  if ( mLayers.count() == 0 )
645  mLayers.append( new QgsSimpleFillSymbolLayerV2() );
646 }
647 
648 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
649 {
650  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f );
651  symbolContext.setLayer( mLayer );
652 
653  if ( layer != -1 )
654  {
655  if ( layer >= 0 && layer < mLayers.count() )
656  {
657  QgsSymbolV2::SymbolType layertype = mLayers.at( layer )->type();
658  if ( layertype == QgsSymbolV2::Fill )
659  (( QgsFillSymbolLayerV2* ) mLayers[layer] )->renderPolygon( points, rings, symbolContext );
660  else if ( layertype == QgsSymbolV2::Line )
661  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolygonOutline( points, rings, symbolContext );
662  }
663  return;
664  }
665 
666  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
667  {
668  QgsSymbolV2::SymbolType layertype = ( *it )->type();
669  if ( layertype == QgsSymbolV2::Fill )
670  {
671  QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
672  layer->renderPolygon( points, rings, symbolContext );
673  }
674  else if ( layertype == QgsSymbolV2::Line )
675  {
676  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
677  layer->renderPolygonOutline( points, rings, symbolContext );
678  }
679  }
680 }
681 
682 
684 {
685  QgsSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
686  cloneSymbol->setAlpha( mAlpha );
687  return cloneSymbol;
688 }
689 
691 {
692  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
693  {
695  layer->setAngle( angle );
696  }
697 }