QGIS API Documentation  2.8.2-Wien
 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 {
65  if ( mLayers.empty() )
66  {
67  return QgsSymbolV2::Mixed;
68  }
69 
70  QgsSymbolLayerV2List::const_iterator it = mLayers.constBegin();
71 
72  QgsSymbolV2::OutputUnit unit = ( *it )->outputUnit();
73 
74  for ( ; it != mLayers.constEnd(); ++it )
75  {
76  if (( *it )->outputUnit() != unit )
77  {
78  return QgsSymbolV2::Mixed;
79  }
80  }
81  return unit;
82 }
83 
85 {
86  if ( mLayers.empty() )
87  {
88  return QgsMapUnitScale();
89  }
90 
91  QgsSymbolLayerV2List::const_iterator it = mLayers.constBegin();
92  if ( it == mLayers.constEnd() )
93  return QgsMapUnitScale();
94 
95  QgsMapUnitScale scale = ( *it )->mapUnitScale();
96  ++it;
97 
98  for ( ; it != mLayers.constEnd(); ++it )
99  {
100  if (( *it )->mapUnitScale() != scale )
101  {
102  return QgsMapUnitScale();
103  }
104  }
105  return scale;
106 }
107 
109 {
110  QgsSymbolLayerV2List::iterator it = mLayers.begin();
111  for ( ; it != mLayers.end(); ++it )
112  {
113  ( *it )->setOutputUnit( u );
114  }
115 }
116 
118 {
119  QgsSymbolLayerV2List::iterator it = mLayers.begin();
120  for ( ; it != mLayers.end(); ++it )
121  {
122  ( *it )->setMapUnitScale( scale );
123  }
124 }
125 
127 {
128  QgsSymbolV2* s = 0;
129 
130  // override global default if project has a default for this type
131  QString defaultSymbol;
132  switch ( geomType )
133  {
134  case QGis::Point :
135  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Marker", "" );
136  break;
137  case QGis::Line :
138  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Line", "" );
139  break;
140  case QGis::Polygon :
141  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Fill", "" );
142  break;
143  default: defaultSymbol = ""; break;
144  }
145  if ( defaultSymbol != "" )
146  s = QgsStyleV2::defaultStyle()->symbol( defaultSymbol );
147 
148  // if no default found for this type, get global default (as previously)
149  if ( ! s )
150  {
151  switch ( geomType )
152  {
153  case QGis::Point: s = new QgsMarkerSymbolV2(); break;
154  case QGis::Line: s = new QgsLineSymbolV2(); break;
155  case QGis::Polygon: s = new QgsFillSymbolV2(); break;
156  default: QgsDebugMsg( "unknown layer's geometry type" ); return NULL;
157  }
158  }
159 
160  // set alpha transparency
161  s->setAlpha( QgsProject::instance()->readDoubleEntry( "DefaultStyles", "/AlphaInt", 255 ) / 255.0 );
162 
163  // set random color, it project prefs allow
164  if ( defaultSymbol == "" ||
165  QgsProject::instance()->readBoolEntry( "DefaultStyles", "/RandomColors", true ) )
166  {
167  s->setColor( QColor::fromHsv( qrand() % 360, 64 + qrand() % 192, 128 + qrand() % 128 ) );
168  }
169 
170  return s;
171 }
172 
174 {
175  if ( layer < 0 || layer >= mLayers.count() )
176  return NULL;
177 
178  return mLayers[layer];
179 }
180 
181 
183 {
184  // fill symbol can contain also line symbol layers for drawing of outlines
185  if ( mType == Fill && t == Line )
186  return true;
187 
188  return mType == t;
189 }
190 
191 
193 {
194  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
195  return false;
196  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
197  return false;
198 
199  mLayers.insert( index, layer );
200  return true;
201 }
202 
203 
205 {
206  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
207  return false;
208 
209  mLayers.append( layer );
210  return true;
211 }
212 
213 
215 {
216  if ( index < 0 || index >= mLayers.count() )
217  return false;
218 
219  delete mLayers[index];
220  mLayers.removeAt( index );
221  return true;
222 }
223 
224 
226 {
227  if ( index < 0 || index >= mLayers.count() )
228  return NULL;
229 
230  return mLayers.takeAt( index );
231 }
232 
233 
235 {
236  if ( index < 0 || index >= mLayers.count() )
237  return false;
238  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
239  return false;
240 
241  delete mLayers[index]; // first delete the original layer
242  mLayers[index] = layer; // set new layer
243  return true;
244 }
245 
246 
247 void QgsSymbolV2::startRender( QgsRenderContext& context, const QgsFields* fields )
248 {
249  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, fields, mapUnitScale() );
250 
251 
252  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
253  ( *it )->startRender( symbolContext );
254 }
255 
257 {
258  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() );
259 
260  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
261  ( *it )->stopRender( symbolContext );
262 
263  mLayer = NULL;
264 }
265 
266 void QgsSymbolV2::setColor( const QColor& color )
267 {
268  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
269  {
270  if ( !( *it )->isLocked() )
271  ( *it )->setColor( color );
272  }
273 }
274 
275 QColor QgsSymbolV2::color() const
276 {
277  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
278  {
279  // return color of the first unlocked layer
280  if ( !( *it )->isLocked() )
281  return ( *it )->color();
282  }
283  return QColor( 0, 0, 0 );
284 }
285 
286 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext )
287 {
288  QgsRenderContext context = customContext ? *customContext : QgsSymbolLayerV2Utils::createRenderContext( painter );
289  context.setForceVectorOutput( true );
290  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() );
291 
292  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
293  {
294  if ( mType == Fill && ( *it )->type() == Line )
295  {
296  // line symbol layer would normally draw just a line
297  // so we override this case to force it to draw a polygon outline
299 
300  // from QgsFillSymbolLayerV2::drawPreviewIcon()
301  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
302  lsl->startRender( symbolContext );
303  lsl->renderPolygonOutline( poly, NULL, symbolContext );
304  lsl->stopRender( symbolContext );
305  }
306  else
307  ( *it )->drawPreviewIcon( symbolContext, size );
308  }
309 }
310 
311 QImage QgsSymbolV2::asImage( QSize size, QgsRenderContext* customContext )
312 {
313  QImage image( size, QImage::Format_ARGB32_Premultiplied );
314  image.fill( 0 );
315 
316  QPainter p( &image );
317  p.setRenderHint( QPainter::Antialiasing );
318 
319  drawPreviewIcon( &p, size, customContext );
320 
321  return image;
322 }
323 
324 
326 {
327  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
328  preview.fill( 0 );
329 
330  QPainter p( &preview );
331  p.setRenderHint( QPainter::Antialiasing );
332  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
333 
334  if ( mType == QgsSymbolV2::Marker )
335  {
336  p.setPen( QPen( Qt::gray ) );
337  p.drawLine( 0, 50, 100, 50 );
338  p.drawLine( 50, 0, 50, 100 );
339  }
340 
342  startRender( context );
343 
344  if ( mType == QgsSymbolV2::Line )
345  {
346  QPolygonF poly;
347  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
348  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, 0, context );
349  }
350  else if ( mType == QgsSymbolV2::Fill )
351  {
352  QPolygonF polygon;
353  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
354  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, NULL, 0, context );
355  }
356  else // marker
357  {
358  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), 0, context );
359  }
360 
361  stopRender( context );
362  return preview;
363 }
364 
365 
366 QString QgsSymbolV2::dump() const
367 {
368  QString t;
369  switch ( type() )
370  {
371  case QgsSymbolV2::Marker: t = "MARKER"; break;
372  case QgsSymbolV2::Line: t = "LINE"; break;
373  case QgsSymbolV2::Fill: t = "FILL"; break;
374  default: Q_ASSERT( 0 && "unknown symbol type" );
375  }
376  QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
377 
378  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
379  {
380  // TODO:
381  }
382  return s;
383 }
384 
385 void QgsSymbolV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
386 {
387  props[ "alpha" ] = QString::number( alpha() );
388  double scaleFactor = 1.0;
389  props[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
390  props[ "uomScale" ] = scaleFactor != 1 ? QString::number( scaleFactor ) : "";
391 
392  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
393  {
394  ( *it )->toSld( doc, element, props );
395  }
396 }
397 
399 {
401  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
402  {
403  QgsSymbolLayerV2* layer = ( *it )->clone();
404  layer->setLocked(( *it )->isLocked() );
405  layer->setRenderingPass(( *it )->renderingPass() );
406  lst.append( layer );
407  }
408  return lst;
409 }
410 
411 QSet<QString> QgsSymbolV2::usedAttributes() const
412 {
413  QSet<QString> attributes;
414  QgsSymbolLayerV2List::const_iterator sIt = mLayers.constBegin();
415  for ( ; sIt != mLayers.constEnd(); ++sIt )
416  {
417  if ( *sIt )
418  {
419  attributes.unite(( *sIt )->usedAttributes() );
420  }
421  }
422  return attributes;
423 }
424 
426 
427 
428 QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected, int renderHints, const QgsFeature* f, const QgsFields* fields, const QgsMapUnitScale& mapUnitScale )
429  : mRenderContext( c ), mOutputUnit( u ), mMapUnitScale( mapUnitScale ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints ), mFeature( f ), mFields( fields )
430 {
431 
432 }
433 
435 {
436 
437 }
438 
439 
440 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
441 {
442  return width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
443 }
444 
446 {
447  return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
448 }
449 
451 {
452  // This is just a dummy implementation of assignment.
453  // sip 4.7 generates a piece of code that needs this function to exist.
454  // It's not generated automatically by the compiler because of
455  // mRenderContext member which is a reference (and thus can't be changed).
456  Q_ASSERT( false );
457  return *this;
458 }
459 
461 
463 {
465  if ( sl == NULL )
466  return NULL;
467 
468  QgsSymbolLayerV2List layers;
469  layers.append( sl );
470  return new QgsMarkerSymbolV2( layers );
471 }
472 
474 {
476  if ( sl == NULL )
477  return NULL;
478 
479  QgsSymbolLayerV2List layers;
480  layers.append( sl );
481  return new QgsLineSymbolV2( layers );
482 }
483 
485 {
487  if ( sl == NULL )
488  return NULL;
489 
490  QgsSymbolLayerV2List layers;
491  layers.append( sl );
492  return new QgsFillSymbolV2( layers );
493 }
494 
496 
497 
499  : QgsSymbolV2( Marker, layers )
500 {
501  if ( mLayers.count() == 0 )
502  mLayers.append( new QgsSimpleMarkerSymbolLayerV2() );
503 }
504 
505 void QgsMarkerSymbolV2::setAngle( double ang )
506 {
507  double origAngle = angle();
508  double angleDiff = ang - origAngle;
509  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
510  {
512  layer->setAngle( layer->angle() + angleDiff );
513  }
514 }
515 
517 {
518  QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
519 
520  if ( it == mLayers.end() )
521  return 0;
522 
523  // return angle of the first symbol layer
524  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
525  return layer->angle();
526 }
527 
529 {
530  double origSize = size();
531 
532  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
533  {
534  QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
535  if ( layer->size() == origSize )
536  layer->setSize( s );
537  else
538  {
539  // proportionally scale size
540  if ( origSize != 0 )
541  layer->setSize( layer->size() * s / origSize );
542  }
543  }
544 }
545 
547 {
548  // return size of the largest symbol
549  double maxSize = 0;
550  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
551  {
552  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
553  double lsize = layer->size();
554  if ( lsize > maxSize )
555  maxSize = lsize;
556  }
557  return maxSize;
558 }
559 
560 
562 {
563  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
564  {
565  QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
566  layer->setScaleMethod( scaleMethod );
567  }
568 }
569 
571 {
572  QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
573 
574  if ( it == mLayers.end() )
575  return DEFAULT_SCALE_METHOD;
576 
577  // return scale method of the first symbol layer
578  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
579  return layer->scaleMethod();
580 }
581 
582 void QgsMarkerSymbolV2::renderPoint( const QPointF& point, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
583 {
584  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, 0, mapUnitScale() );
585 
586  if ( layer != -1 )
587  {
588  if ( layer >= 0 && layer < mLayers.count() )
589  (( QgsMarkerSymbolLayerV2* ) mLayers[layer] )->renderPoint( point, symbolContext );
590  return;
591  }
592 
593  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
594  {
596  layer->renderPoint( point, symbolContext );
597  }
598 }
599 
601 {
602  QgsSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
603  cloneSymbol->setAlpha( mAlpha );
604  cloneSymbol->setLayer( mLayer );
605  return cloneSymbol;
606 }
607 
608 
610 // LINE
611 
613  : QgsSymbolV2( Line, layers )
614 {
615  if ( mLayers.count() == 0 )
616  mLayers.append( new QgsSimpleLineSymbolLayerV2() );
617 }
618 
620 {
621  double origWidth = width();
622 
623  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
624  {
626  if ( layer->width() == origWidth )
627  {
628  layer->setWidth( w );
629  }
630  else
631  {
632  // proportionally scale the width
633  if ( origWidth != 0 )
634  layer->setWidth( layer->width() * w / origWidth );
635  }
636  }
637 }
638 
640 {
641  double maxWidth = 0;
642  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
643  {
644  const QgsLineSymbolLayerV2* layer = ( const QgsLineSymbolLayerV2* ) * it;
645  double width = layer->width();
646  if ( width > maxWidth )
647  maxWidth = width;
648  }
649  return maxWidth;
650 }
651 
652 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
653 {
654  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, 0, mapUnitScale() );
655 
656  if ( layer != -1 )
657  {
658  if ( layer >= 0 && layer < mLayers.count() )
659  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolyline( points, symbolContext );
660  return;
661  }
662 
663  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
664  {
665  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
666  layer->renderPolyline( points, symbolContext );
667  }
668 }
669 
670 
672 {
673  QgsSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
674  cloneSymbol->setAlpha( mAlpha );
675  cloneSymbol->setLayer( mLayer );
676  return cloneSymbol;
677 }
678 
680 // FILL
681 
683  : QgsSymbolV2( Fill, layers )
684 {
685  if ( mLayers.count() == 0 )
686  mLayers.append( new QgsSimpleFillSymbolLayerV2() );
687 }
688 
689 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layer, bool selected )
690 {
691  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, 0, mapUnitScale() );
692 
693  if ( layer != -1 )
694  {
695  if ( layer >= 0 && layer < mLayers.count() )
696  {
697  QgsSymbolV2::SymbolType layertype = mLayers.at( layer )->type();
698  if ( layertype == QgsSymbolV2::Fill )
699  (( QgsFillSymbolLayerV2* ) mLayers[layer] )->renderPolygon( points, rings, symbolContext );
700  else if ( layertype == QgsSymbolV2::Line )
701  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolygonOutline( points, rings, symbolContext );
702  }
703  return;
704  }
705 
706  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
707  {
708  QgsSymbolV2::SymbolType layertype = ( *it )->type();
709  if ( layertype == QgsSymbolV2::Fill )
710  {
711  QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
712  layer->renderPolygon( points, rings, symbolContext );
713  }
714  else if ( layertype == QgsSymbolV2::Line )
715  {
716  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
717  layer->renderPolygonOutline( points, rings, symbolContext );
718  }
719  }
720 }
721 
722 
724 {
725  QgsSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
726  cloneSymbol->setAlpha( mAlpha );
727  cloneSymbol->setLayer( mLayer );
728  return cloneSymbol;
729 }
730 
732 {
733  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
734  {
736  layer->setAngle( angle );
737  }
738 }
739 
740