Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgssymbolv2.cpp
Go to the documentation of this file.
1 
2 #include "qgsrenderer.h"
3 #include "qgssymbolv2.h"
4 #include "qgssymbollayerv2.h"
5 
6 #include "qgslinesymbollayerv2.h"
8 #include "qgsfillsymbollayerv2.h"
9 
10 #include "qgslogger.h"
11 #include "qgsrendercontext.h" // for bigSymbolPreview
12 
13 #include <QColor>
14 #include <QImage>
15 #include <QPainter>
16 #include <QSize>
17 
18 #include <cmath>
19 
21  : mType( type ), mLayers( layers ), mOutputUnit( MM ), mAlpha( 1.0 ), mRenderHints( 0 )
22 {
23 
24  // check they're all correct symbol layers
25  for ( int i = 0; i < mLayers.count(); i++ )
26  {
27  if ( mLayers[i] == NULL )
28  {
29  mLayers.removeAt( i-- );
30  }
31  else if ( !isSymbolLayerCompatible( mLayers[i]->type() ) )
32  {
33  delete mLayers[i];
34  mLayers.removeAt( i-- );
35  }
36  }
37 
38 }
39 
41 {
42  // delete all symbol layers (we own them, so it's okay)
43  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
44  delete *it;
45 }
46 
48 {
49  QgsSymbolV2* s;
50  switch ( geomType )
51  {
52  case QGis::Point: s = new QgsMarkerSymbolV2(); break;
53  case QGis::Line: s = new QgsLineSymbolV2(); break;
54  case QGis::Polygon: s = new QgsFillSymbolV2(); break;
55  default: QgsDebugMsg( "unknown layer's geometry type" ); return NULL;
56  }
57 
58  s->setColor( QColor::fromHsv( rand() % 360, 64 + rand() % 192, 128 + rand() % 128 ) );
59  return s;
60 }
61 
62 
64 {
65  if ( layer < 0 || layer >= mLayers.count() )
66  return NULL;
67 
68  return mLayers[layer];
69 }
70 
71 
73 {
74  // fill symbol can contain also line symbol layers for drawing of outlines
75  if ( mType == Fill && t == Line )
76  return true;
77 
78  return mType == t;
79 }
80 
81 
83 {
84  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
85  return false;
86  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
87  return false;
88 
89  mLayers.insert( index, layer );
90  return true;
91 }
92 
93 
95 {
96  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
97  return false;
98 
99  mLayers.append( layer );
100  return true;
101 }
102 
103 
105 {
106  if ( index < 0 || index >= mLayers.count() )
107  return false;
108 
109  delete mLayers[index];
110  mLayers.removeAt( index );
111  return true;
112 }
113 
114 
116 {
117  if ( index < 0 || index >= mLayers.count() )
118  return NULL;
119 
120  return mLayers.takeAt( index );
121 }
122 
123 
125 {
126  if ( index < 0 || index >= mLayers.count() )
127  return false;
128  if ( layer == NULL || !isSymbolLayerCompatible( layer->type() ) )
129  return false;
130 
131  delete mLayers[index]; // first delete the original layer
132  mLayers[index] = layer; // set new layer
133  return true;
134 }
135 
136 
138 {
139  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
140  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
141  ( *it )->startRender( symbolContext );
142 }
143 
145 {
146  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
147  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
148  ( *it )->stopRender( symbolContext );
149 }
150 
151 void QgsSymbolV2::setColor( const QColor& color )
152 {
153  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
154  {
155  if ( !( *it )->isLocked() )
156  ( *it )->setColor( color );
157  }
158 }
159 
161 {
162  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
163  {
164  // return color of the first unlocked layer
165  if ( !( *it )->isLocked() )
166  return ( *it )->color();
167  }
168  return QColor( 0, 0, 0 );
169 }
170 
171 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size )
172 {
174  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
175  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
176  {
177  if ( mType == Fill && ( *it )->type() == Line )
178  {
179  // line symbol layer would normally draw just a line
180  // so we override this case to force it to draw a polygon outline
182 
183  // from QgsFillSymbolLayerV2::drawPreviewIcon()
184  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
185  lsl->startRender( symbolContext );
186  lsl->renderPolygonOutline( poly, NULL, symbolContext );
187  lsl->stopRender( symbolContext );
188  }
189  else
190  ( *it )->drawPreviewIcon( symbolContext, size );
191  }
192 }
193 
194 
196 {
197  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
198  preview.fill( 0 );
199 
200  QPainter p( &preview );
201  p.setRenderHint( QPainter::Antialiasing );
202  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
203 
204  if ( mType == QgsSymbolV2::Marker )
205  {
206  p.setPen( QPen( Qt::gray ) );
207  p.drawLine( 0, 50, 100, 50 );
208  p.drawLine( 50, 0, 50, 100 );
209  }
210 
212  startRender( context );
213 
214  if ( mType == QgsSymbolV2::Line )
215  {
216  QPolygonF poly;
217  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
218  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, context );
219  }
220  else if ( mType == QgsSymbolV2::Fill )
221  {
222  QPolygonF polygon;
223  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
224  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, NULL, context );
225  }
226  else // marker
227  {
228  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), context );
229  }
230 
231  stopRender( context );
232  return preview;
233 }
234 
235 
237 {
238  QString t;
239  switch ( type() )
240  {
241  case QgsSymbolV2::Marker: t = "MARKER"; break;
242  case QgsSymbolV2::Line: t = "LINE"; break;
243  case QgsSymbolV2::Fill: t = "FILL"; break;
244  default: Q_ASSERT( 0 && "unknown symbol type" );
245  }
246  QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
247 
248  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
249  {
250  // TODO:
251  }
252  return s;
253 }
254 
256 {
258  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
259  {
260  QgsSymbolLayerV2* layer = ( *it )->clone();
261  layer->setLocked(( *it )->isLocked() );
262  layer->setRenderingPass(( *it )->renderingPass() );
263  lst.append( layer );
264  }
265  return lst;
266 }
267 
269 
271  : mRenderContext( c ), mOutputUnit( u ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints )
272 {
273 
274 }
275 
277 {
278 
279 }
280 
282 {
284 }
285 
286 
287 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
288 {
290 }
291 
292 double QgsSymbolV2RenderContext::outputPixelSize( double size ) const
293 {
295 }
296 
298 {
299  // This is just a dummy implementation of assignment.
300  // sip 4.7 generates a piece of code that needs this function to exist.
301  // It's not generated automatically by the compiler because of
302  // mRenderContext member which is a reference (and thus can't be changed).
303  Q_ASSERT( false );
304  return *this;
305 }
306 
308 
310 {
312  if ( sl == NULL )
313  return NULL;
314 
315  QgsSymbolLayerV2List layers;
316  layers.append( sl );
317  return new QgsMarkerSymbolV2( layers );
318 }
319 
321 {
323  if ( sl == NULL )
324  return NULL;
325 
326  QgsSymbolLayerV2List layers;
327  layers.append( sl );
328  return new QgsLineSymbolV2( layers );
329 }
330 
332 {
334  if ( sl == NULL )
335  return NULL;
336 
337  QgsSymbolLayerV2List layers;
338  layers.append( sl );
339  return new QgsFillSymbolV2( layers );
340 }
341 
343 
344 
346  : QgsSymbolV2( Marker, layers )
347 {
348  if ( mLayers.count() == 0 )
349  mLayers.append( new QgsSimpleMarkerSymbolLayerV2() );
350 }
351 
353 {
354  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
355  {
357  layer->setAngle( angle );
358  }
359 }
360 
362 {
363  QgsSymbolLayerV2List::const_iterator it = mLayers.begin();
364 
365  if ( it == mLayers.end() )
366  return 0;
367 
368  // return angle of the first symbol layer
369  const QgsMarkerSymbolLayerV2 *layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
370  return layer->angle();
371 }
372 
374 {
375  double origSize = size();
376 
377  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
378  {
379  QgsMarkerSymbolLayerV2* layer = static_cast<QgsMarkerSymbolLayerV2*>( *it );
380  if ( layer->size() == origSize )
381  layer->setSize( s );
382  else
383  {
384  // proportionally scale size
385  if ( origSize != 0 )
386  layer->setSize( layer->size() * s / origSize );
387  }
388  }
389 }
390 
392 {
393  // return size of the largest symbol
394  double maxSize = 0;
395  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
396  {
397  const QgsMarkerSymbolLayerV2* layer = static_cast<const QgsMarkerSymbolLayerV2 *>( *it );
398  double lsize = layer->size();
399  if ( lsize > maxSize )
400  maxSize = lsize;
401  }
402  return maxSize;
403 }
404 
405 void QgsMarkerSymbolV2::renderPoint( const QPointF& point, QgsRenderContext& context, int layer, bool selected )
406 {
407  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
408  if ( layer != -1 )
409  {
410  if ( layer >= 0 && layer < mLayers.count() )
411  (( QgsMarkerSymbolLayerV2* ) mLayers[layer] )->renderPoint( point, symbolContext );
412  return;
413  }
414 
415  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
416  {
418  layer->renderPoint( point, symbolContext );
419  }
420 }
421 
423 {
424  QgsSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
425  cloneSymbol->setOutputUnit( mOutputUnit );
426  cloneSymbol->setAlpha( mAlpha );
427  return cloneSymbol;
428 }
429 
430 
432 // LINE
433 
435  : QgsSymbolV2( Line, layers )
436 {
437  if ( mLayers.count() == 0 )
438  mLayers.append( new QgsSimpleLineSymbolLayerV2() );
439 }
440 
442 {
443  double origWidth = width();
444 
445  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
446  {
447  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
448  if ( layer->width() == origWidth )
449  {
450  layer->setWidth( w );
451  }
452  else
453  {
454  // proportionally scale the width
455  if ( origWidth != 0 )
456  layer->setWidth( layer->width() * w / origWidth );
457  }
458  }
459 }
460 
462 {
463  double maxWidth = 0;
464  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
465  {
466  const QgsLineSymbolLayerV2* layer = ( const QgsLineSymbolLayerV2* ) * it;
467  double width = layer->width();
468  if ( width > maxWidth )
469  maxWidth = width;
470  }
471  return maxWidth;
472 }
473 
474 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, QgsRenderContext& context, int layer, bool selected )
475 {
476  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
477  if ( layer != -1 )
478  {
479  if ( layer >= 0 && layer < mLayers.count() )
480  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolyline( points, symbolContext );
481  return;
482  }
483 
484  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
485  {
486  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
487  layer->renderPolyline( points, symbolContext );
488  }
489 }
490 
491 
493 {
494  QgsSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
495  cloneSymbol->setOutputUnit( mOutputUnit );
496  cloneSymbol->setAlpha( mAlpha );
497  return cloneSymbol;
498 }
499 
501 // FILL
502 
504  : QgsSymbolV2( Fill, layers )
505 {
506  if ( mLayers.count() == 0 )
507  mLayers.append( new QgsSimpleFillSymbolLayerV2() );
508 }
509 
510 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsRenderContext& context, int layer, bool selected )
511 {
512  QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
513  if ( layer != -1 )
514  {
515  if ( layer >= 0 && layer < mLayers.count() )
516  {
517  QgsSymbolV2::SymbolType layertype = mLayers.at( layer )->type();
518  if ( layertype == QgsSymbolV2::Fill )
519  (( QgsFillSymbolLayerV2* ) mLayers[layer] )->renderPolygon( points, rings, symbolContext );
520  else if ( layertype == QgsSymbolV2::Line )
521  (( QgsLineSymbolLayerV2* ) mLayers[layer] )->renderPolygonOutline( points, rings, symbolContext );
522  }
523  return;
524  }
525 
526  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
527  {
528  QgsSymbolV2::SymbolType layertype = ( *it )->type();
529  if ( layertype == QgsSymbolV2::Fill )
530  {
531  QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
532  layer->renderPolygon( points, rings, symbolContext );
533  }
534  else if ( layertype == QgsSymbolV2::Line )
535  {
536  QgsLineSymbolLayerV2* layer = ( QgsLineSymbolLayerV2* ) * it;
537  layer->renderPolygonOutline( points, rings, symbolContext );
538  }
539  }
540 }
541 
542 
544 {
545  QgsSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
546  cloneSymbol->setOutputUnit( mOutputUnit );
547  cloneSymbol->setAlpha( mAlpha );
548  return cloneSymbol;
549 }
550 
552 {
553  for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
554  {
555  QgsFillSymbolLayerV2* layer = ( QgsFillSymbolLayerV2* ) * it;
556  layer->setAngle( angle );
557  }
558 }