QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgslinesymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinesymbollayerv2.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 "qgslinesymbollayerv2.h"
17 #include "qgsdxfexport.h"
18 #include "qgssymbollayerv2utils.h"
19 #include "qgsexpression.h"
20 #include "qgsrendercontext.h"
21 #include "qgslogger.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsgeometrysimplifier.h"
24 
25 #include <QPainter>
26 #include <QDomDocument>
27 #include <QDomElement>
28 
29 #include <cmath>
30 
31 QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2( QColor color, double width, Qt::PenStyle penStyle )
32  : mPenStyle( penStyle ), mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE ), mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE ), mOffset( 0 ), mOffsetUnit( QgsSymbolV2::MM ),
33  mUseCustomDashPattern( false ), mCustomDashPatternUnit( QgsSymbolV2::MM ), mDrawInsidePolygon( false )
34 {
35  mColor = color;
36  mWidth = width;
37  mCustomDashVector << 5 << 2;
38 }
39 
41 {
42  mWidthUnit = unit;
43  mOffsetUnit = unit;
45 }
46 
48 {
50  if ( mOffsetUnit != unit || mCustomDashPatternUnit != unit )
51  {
52  return QgsSymbolV2::Mixed;
53  }
54  return unit;
55 }
56 
57 
59 {
63 
64  if ( props.contains( "color" ) )
65  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
66  if ( props.contains( "width" ) )
67  width = props["width"].toDouble();
68  if ( props.contains( "penstyle" ) )
69  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["penstyle"] );
70 
71 
72  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
73  if ( props.contains( "width_unit" ) )
74  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["width_unit"] ) );
75  if ( props.contains( "offset" ) )
76  l->setOffset( props["offset"].toDouble() );
77  if ( props.contains( "offset_unit" ) )
78  l->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
79  if ( props.contains( "joinstyle" ) )
81  if ( props.contains( "capstyle" ) )
83 
84  if ( props.contains( "use_custom_dash" ) )
85  {
86  l->setUseCustomDashPattern( props["use_custom_dash"].toInt() );
87  }
88  if ( props.contains( "customdash" ) )
89  {
91  }
92  if ( props.contains( "customdash_unit" ) )
93  {
94  l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
95  }
96 
97  if ( props.contains( "draw_inside_polygon" ) )
98  {
99  l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
100  }
101 
102  //data defined properties
103  if ( props.contains( "color_expression" ) )
104  l->setDataDefinedProperty( "color", props["color_expression"] );
105  if ( props.contains( "width_expression" ) )
106  l->setDataDefinedProperty( "width", props["width_expression"] );
107  if ( props.contains( "offset_expression" ) )
108  l->setDataDefinedProperty( "offset", props["offset_expression"] );
109  if ( props.contains( "customdash_expression" ) )
110  l->setDataDefinedProperty( "customdash", props["customdash_expression"] );
111  if ( props.contains( "joinstyle_expression" ) )
112  l->setDataDefinedProperty( "joinstyle", props["joinstyle_expression"] );
113  if ( props.contains( "capstyle_expression" ) )
114  l->setDataDefinedProperty( "capstyle", props["capstyle_expression"] );
115 
116  return l;
117 }
118 
119 
121 {
122  return "SimpleLine";
123 }
124 
126 {
127  QColor penColor = mColor;
128  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
129  mPen.setColor( penColor );
130  double scaledWidth = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit );
131  mPen.setWidthF( scaledWidth );
132  if ( mUseCustomDashPattern && scaledWidth != 0 )
133  {
134  mPen.setStyle( Qt::CustomDashLine );
135 
136  //scale pattern vector
137  double dashWidthDiv = scaledWidth;
138  //fix dash pattern width in Qt 4.8
139  QStringList versionSplit = QString( qVersion() ).split( "." );
140  if ( versionSplit.size() > 1
141  && versionSplit.at( 1 ).toInt() >= 8
142  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
143  {
144  dashWidthDiv = 1.0;
145  }
146  QVector<qreal> scaledVector;
147  QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
148  for ( ; it != mCustomDashVector.constEnd(); ++it )
149  {
150  //the dash is specified in terms of pen widths, therefore the division
151  scaledVector << ( *it ) * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit ) / dashWidthDiv;
152  }
153  mPen.setDashPattern( scaledVector );
154  }
155  else
156  {
157  mPen.setStyle( mPenStyle );
158  }
159  mPen.setJoinStyle( mPenJoinStyle );
160  mPen.setCapStyle( mPenCapStyle );
161 
162  mSelPen = mPen;
163  QColor selColor = context.renderContext().selectionColor();
164  if ( ! selectionIsOpaque )
165  selColor.setAlphaF( context.alpha() );
166  mSelPen.setColor( selColor );
167 
168  //prepare expressions for data defined properties
169  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
170 }
171 
173 {
174  Q_UNUSED( context );
175 }
176 
177 void QgsSimpleLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
178 {
179  QPainter* p = context.renderContext().painter();
180  if ( !p )
181  {
182  return;
183  }
184 
185  if ( mDrawInsidePolygon )
186  {
187  //only drawing the line on the interior of the polygon, so set clip path for painter
188  p->save();
189  QPainterPath clipPath;
190  clipPath.addPolygon( points );
191 
192  if ( rings != NULL )
193  {
194  //add polygon rings
195  QList<QPolygonF>::const_iterator it = rings->constBegin();
196  for ( ; it != rings->constEnd(); ++it )
197  {
198  QPolygonF ring = *it;
199  clipPath.addPolygon( ring );
200  }
201  }
202 
203  //use intersect mode, as a clip path may already exist (eg, for composer maps)
204  p->setClipPath( clipPath, Qt::IntersectClip );
205  }
206 
207  renderPolyline( points, context );
208  if ( rings )
209  {
210  foreach ( const QPolygonF& ring, *rings )
211  renderPolyline( ring, context );
212  }
213 
214  if ( mDrawInsidePolygon )
215  {
216  //restore painter to reset clip path
217  p->restore();
218  }
219 
220 }
221 
223 {
224  QPainter* p = context.renderContext().painter();
225  if ( !p )
226  {
227  return;
228  }
229 
230  double offset = 0.0;
231  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
232 
233  p->setPen( context.selected() ? mSelPen : mPen );
234 
235  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
236 #if 0 // TODO[MD]: after merge
237  if ( points.size() <= 2 && context.layer() && context.layer()->simplifyDrawingCanbeApplied( context.renderContext(), QgsVectorSimplifyMethod::AntialiasingSimplification ) && QgsAbstractGeometrySimplifier::canbeGeneralizedByDeviceBoundingBox( points, context.layer()->simplifyMethod().threshold() ) && ( p->renderHints() & QPainter::Antialiasing ) )
238  {
239  p->setRenderHint( QPainter::Antialiasing, false );
240  p->drawPolyline( points );
241  p->setRenderHint( QPainter::Antialiasing, true );
242  return;
243  }
244 #endif
245 
246  if ( offset == 0 )
247  {
248  p->drawPolyline( points );
249  }
250  else
251  {
252  double scaledOffset = offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
253  p->drawPolyline( ::offsetLine( points, scaledOffset ) );
254  }
255 }
256 
258 {
259  QgsStringMap map;
260  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
261  map["width"] = QString::number( mWidth );
266  map["offset"] = QString::number( mOffset );
268  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
271  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
273  return map;
274 }
275 
277 {
279  l->setWidthUnit( mWidthUnit );
282  l->setOffset( mOffset );
289  return l;
290 }
291 
292 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
293 {
294  if ( mPenStyle == Qt::NoPen )
295  return;
296 
297  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
298  if ( !props.value( "uom", "" ).isEmpty() )
299  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
300  element.appendChild( symbolizerElem );
301 
302  // <Geometry>
303  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
304 
305  // <Stroke>
306  QDomElement strokeElem = doc.createElement( "se:Stroke" );
307  symbolizerElem.appendChild( strokeElem );
308 
309  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
310  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
312 
313  // <se:PerpendicularOffset>
314  if ( mOffset != 0 )
315  {
316  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
317  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
318  symbolizerElem.appendChild( perpOffsetElem );
319  }
320 }
321 
322 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
323 {
324  if ( mUseCustomDashPattern )
325  {
326  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
327  mPen.color(), mPenJoinStyle,
329  }
330  else
331  {
332  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
334  }
335 }
336 
338 {
339  QgsDebugMsg( "Entered." );
340 
341  QDomElement strokeElem = element.firstChildElement( "Stroke" );
342  if ( strokeElem.isNull() )
343  return NULL;
344 
345  Qt::PenStyle penStyle;
346  QColor color;
347  double width;
348  Qt::PenJoinStyle penJoinStyle;
349  Qt::PenCapStyle penCapStyle;
350  QVector<qreal> customDashVector;
351 
352  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
353  color, width,
354  &penJoinStyle, &penCapStyle,
355  &customDashVector ) )
356  return NULL;
357 
358  double offset = 0.0;
359  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
360  if ( !perpOffsetElem.isNull() )
361  {
362  bool ok;
363  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
364  if ( ok )
365  offset = d;
366  }
367 
368  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
369  l->setOffset( offset );
370  l->setPenJoinStyle( penJoinStyle );
371  l->setPenCapStyle( penCapStyle );
372  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
373  l->setCustomDashVector( customDashVector );
374  return l;
375 }
376 
377 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
378 {
379  //data defined properties
380  double scaledWidth = 0;
381  QgsExpression* strokeWidthExpression = expression( "width" );
382  if ( strokeWidthExpression )
383  {
384  scaledWidth = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble()
386  pen.setWidthF( scaledWidth );
387  selPen.setWidthF( scaledWidth );
388  }
389  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
390  {
392  pen.setWidthF( scaledWidth );
393  selPen.setWidthF( scaledWidth );
394  }
395 
396  //color
397  QgsExpression* strokeColorExpression = expression( "color" );
398  if ( strokeColorExpression )
399  {
400  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
401  }
402 
403  //offset
404  offset = mOffset;
405  QgsExpression* lineOffsetExpression = expression( "offset" );
406  if ( lineOffsetExpression )
407  {
408  offset = lineOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
409  }
410 
411  //dash dot vector
412  QgsExpression* dashPatternExpression = expression( "customdash" );
413  if ( dashPatternExpression )
414  {
415  QVector<qreal> dashVector;
416  QStringList dashList = dashPatternExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString().split( ";" );
417  QStringList::const_iterator dashIt = dashList.constBegin();
418  for ( ; dashIt != dashList.constEnd(); ++dashIt )
419  {
420  dashVector.push_back( dashIt->toDouble() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit ) / mPen.widthF() );
421  }
422  pen.setDashPattern( dashVector );
423  }
424 
425  //join style
426  QgsExpression* joinStyleExpression = expression( "joinstyle" );
427  if ( joinStyleExpression )
428  {
429  QString joinStyleString = joinStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
430  pen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( joinStyleString ) );
431  }
432 
433  //cap style
434  QgsExpression* capStyleExpression = expression( "capstyle" );
435  if ( capStyleExpression )
436  {
437  QString capStyleString = capStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
438  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
439  }
440 }
441 
443 {
444  if ( mDrawInsidePolygon )
445  {
446  //set to clip line to the interior of polygon, so we expect no bleed
447  return 0;
448  }
449  else
450  {
451  return ( mWidth / 2.0 ) + mOffset;
452  }
453 }
454 
456 {
457  unit = mCustomDashPatternUnit;
458  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>() ;
459 }
460 
462 {
463  return mPenStyle;
464 }
465 
466 double QgsSimpleLineSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
467 {
468  double width = mWidth;
469  QgsExpression* strokeWidthExpression = expression( "width" );
470  if ( strokeWidthExpression )
471  {
472  width = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
473  }
474  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
475  {
477  }
478 
479  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
480 }
481 
483 {
484  QgsExpression* strokeColorExpression = expression( "color" );
485  if ( strokeColorExpression )
486  {
487  return ( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
488  }
489  return mColor;
490 }
491 
493 
494 
495 class MyLine
496 {
497  public:
498  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
499  {
500  if ( p1 == p2 )
501  return; // invalid
502 
503  // tangent and direction
504  if ( p1.x() == p2.x() )
505  {
506  // vertical line - tangent undefined
507  mVertical = true;
508  mIncreasing = ( p2.y() > p1.y() );
509  }
510  else
511  {
512  mVertical = false;
513  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
514  mIncreasing = ( p2.x() > p1.x() );
515  }
516 
517  // length
518  double x = ( p2.x() - p1.x() );
519  double y = ( p2.y() - p1.y() );
520  mLength = sqrt( x * x + y * y );
521  }
522 
523  // return angle in radians
524  double angle()
525  {
526  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
527 
528  if ( !mIncreasing )
529  a += M_PI;
530  return a;
531  }
532 
533  // return difference for x,y when going along the line with specified interval
534  QPointF diffForInterval( double interval )
535  {
536  if ( mVertical )
537  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
538 
539  double alpha = atan( mT );
540  double dx = cos( alpha ) * interval;
541  double dy = sin( alpha ) * interval;
542  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
543  }
544 
545  double length() { return mLength; }
546 
547  protected:
548  bool mVertical;
550  double mT;
551  double mLength;
552 };
553 
554 
555 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
556 {
560  mMarker = NULL;
561  mOffset = 0;
564 
566 }
567 
569 {
570  delete mMarker;
571 }
572 
574 {
575  bool rotate = DEFAULT_MARKERLINE_ROTATE;
577 
578  if ( props.contains( "interval" ) )
579  interval = props["interval"].toDouble();
580  if ( props.contains( "rotate" ) )
581  rotate = ( props["rotate"] == "1" );
582 
583  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
584  if ( props.contains( "offset" ) )
585  {
586  x->setOffset( props["offset"].toDouble() );
587  }
588  if ( props.contains( "offset_unit" ) )
589  {
590  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
591  }
592  if ( props.contains( "interval_unit" ) )
593  {
594  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
595  }
596 
597  if ( props.contains( "placement" ) )
598  {
599  if ( props["placement"] == "vertex" )
600  x->setPlacement( Vertex );
601  else if ( props["placement"] == "lastvertex" )
602  x->setPlacement( LastVertex );
603  else if ( props["placement"] == "firstvertex" )
605  else if ( props["placement"] == "centralpoint" )
607  else
608  x->setPlacement( Interval );
609  }
610 
611  //data defined properties
612  if ( props.contains( "interval_expression" ) )
613  {
614  x->setDataDefinedProperty( "interval", props["interval_expression"] );
615  }
616  if ( props.contains( "offset_expression" ) )
617  {
618  x->setDataDefinedProperty( "offset", props["offset_expression"] );
619  }
620  if ( props.contains( "placement_expression" ) )
621  {
622  x->setDataDefinedProperty( "placement", props["placement_expression"] );
623  }
624 
625  return x;
626 }
627 
629 {
630  return "MarkerLine";
631 }
632 
633 void QgsMarkerLineSymbolLayerV2::setColor( const QColor& color )
634 {
635  mMarker->setColor( color );
636  mColor = color;
637 }
638 
640 {
641  mMarker->setAlpha( context.alpha() );
642 
643  // if being rotated, it gets initialized with every line segment
644  int hints = 0;
645  if ( mRotateMarker )
649  mMarker->setRenderHints( hints );
650 
651  mMarker->startRender( context.renderContext(), context.fields() );
652 
653  //prepare expressions for data defined properties
654  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
655 }
656 
658 {
659  mMarker->stopRender( context.renderContext() );
660 }
661 
663 {
664  double offset = mOffset;
665  QgsExpression* offsetExpression = expression( "offset" );
666  if ( offsetExpression )
667  {
668  offset = offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
669  }
670 
672  QgsExpression* placementExpression = expression( "placement" );
673  if ( placementExpression )
674  {
675  QString placementString = placementExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
676  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
677  {
678  placement = Vertex;
679  }
680  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
681  {
682  placement = LastVertex;
683  }
684  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
685  {
686  placement = FirstVertex;
687  }
688  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
689  {
690  placement = CentralPoint;
691  }
692  else
693  {
694  placement = Interval;
695  }
696  }
697 
698  if ( offset == 0 )
699  {
700  if ( placement == Interval )
701  renderPolylineInterval( points, context );
702  else if ( placement == CentralPoint )
703  renderPolylineCentral( points, context );
704  else
705  renderPolylineVertex( points, context, placement );
706  }
707  else
708  {
709  QPolygonF points2 = ::offsetLine( points, offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit ) );
710  if ( placement == Interval )
711  renderPolylineInterval( points2, context );
712  else if ( placement == CentralPoint )
713  renderPolylineCentral( points2, context );
714  else
715  renderPolylineVertex( points2, context, placement );
716  }
717 }
718 
720 {
721  if ( points.isEmpty() )
722  return;
723 
724  QPointF lastPt = points[0];
725  double lengthLeft = 0; // how much is left until next marker
726  bool first = true;
727  double origAngle = mMarker->angle();
728 
729  QgsRenderContext& rc = context.renderContext();
730  double interval = mInterval;
731 
732  QgsExpression* intervalExpression = expression( "interval" );
733  if ( intervalExpression )
734  {
735  interval = intervalExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
736  }
737  if ( interval <= 0 )
738  {
739  interval = 0.1;
740  }
741 
742  double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit );
743 
744  for ( int i = 1; i < points.count(); ++i )
745  {
746  const QPointF& pt = points[i];
747 
748  if ( lastPt == pt ) // must not be equal!
749  continue;
750 
751  // for each line, find out dx and dy, and length
752  MyLine l( lastPt, pt );
753  QPointF diff = l.diffForInterval( painterUnitInterval );
754 
755  // if there's some length left from previous line
756  // use only the rest for the first point in new line segment
757  double c = 1 - lengthLeft / painterUnitInterval;
758 
759  lengthLeft += l.length();
760 
761  // rotate marker (if desired)
762  if ( mRotateMarker )
763  {
764  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
765  }
766 
767  // draw first marker
768  if ( first )
769  {
770  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
771  first = false;
772  }
773 
774  // while we're not at the end of line segment, draw!
775  while ( lengthLeft > painterUnitInterval )
776  {
777  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
778  lastPt += c * diff;
779  lengthLeft -= painterUnitInterval;
780  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
781  c = 1; // reset c (if wasn't 1 already)
782  }
783 
784  lastPt = pt;
785  }
786 
787  // restore original rotation
788  mMarker->setAngle( origAngle );
789 
790 }
791 
792 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
793 {
794  // calc average angle between the previous and next point
795  double a1 = MyLine( prevPt, pt ).angle();
796  double a2 = MyLine( pt, nextPt ).angle();
797  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
798 
799  return atan2( unitY, unitX );
800 }
801 
802 void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement )
803 {
804  if ( points.isEmpty() )
805  return;
806 
807  QgsRenderContext& rc = context.renderContext();
808 
809  double origAngle = mMarker->angle();
810  int i, maxCount;
811  bool isRing = false;
812 
813  if ( placement == FirstVertex )
814  {
815  i = 0;
816  maxCount = 1;
817  }
818  else if ( placement == LastVertex )
819  {
820  i = points.count() - 1;
821  maxCount = points.count();
822  }
823  else
824  {
825  i = 0;
826  maxCount = points.count();
827  if ( points.first() == points.last() )
828  isRing = true;
829  }
830 
831  for ( ; i < maxCount; ++i )
832  {
833  if ( isRing && placement == Vertex && i == points.count() - 1 )
834  {
835  continue; // don't draw the last marker - it has been drawn already
836  }
837  // rotate marker (if desired)
838  if ( mRotateMarker )
839  {
840  double angle = markerAngle( points, isRing, i );
841  mMarker->setAngle( origAngle + angle * 180 / M_PI );
842  }
843 
844  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
845  }
846 
847  // restore original rotation
848  mMarker->setAngle( origAngle );
849 }
850 
851 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
852 {
853  double angle = 0;
854  const QPointF& pt = points[vertex];
855 
856  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
857  {
858  int prevIndex = vertex - 1;
859  int nextIndex = vertex + 1;
860 
861  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
862  {
863  prevIndex = points.count() - 2;
864  nextIndex = 1;
865  }
866 
867  QPointF prevPoint, nextPoint;
868  while ( prevIndex >= 0 )
869  {
870  prevPoint = points[ prevIndex ];
871  if ( prevPoint != pt )
872  {
873  break;
874  }
875  --prevIndex;
876  }
877 
878  while ( nextIndex < points.count() )
879  {
880  nextPoint = points[ nextIndex ];
881  if ( nextPoint != pt )
882  {
883  break;
884  }
885  ++nextIndex;
886  }
887 
888  if ( prevIndex >= 0 && nextIndex < points.count() )
889  {
890  angle = _averageAngle( prevPoint, pt, nextPoint );
891  }
892  }
893  else //no ring and vertex is at start / at end
894  {
895  if ( vertex == 0 )
896  {
897  while ( vertex < points.size() - 1 )
898  {
899  const QPointF& nextPt = points[vertex+1];
900  if ( pt != nextPt )
901  {
902  angle = MyLine( pt, nextPt ).angle();
903  return angle;
904  }
905  ++vertex;
906  }
907  }
908  else
909  {
910  // use last segment's angle
911  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
912  {
913  const QPointF& prevPt = points[vertex-1];
914  if ( pt != prevPt )
915  {
916  angle = MyLine( prevPt, pt ).angle();
917  return angle;
918  }
919  --vertex;
920  }
921  }
922  }
923  return angle;
924 }
925 
927 {
928  if ( points.size() > 0 )
929  {
930  // calc length
931  qreal length = 0;
932  QPolygonF::const_iterator it = points.constBegin();
933  QPointF last = *it;
934  for ( ++it; it != points.constEnd(); ++it )
935  {
936  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
937  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
938  last = *it;
939  }
940 
941  // find the segment where the central point lies
942  it = points.constBegin();
943  last = *it;
944  qreal last_at = 0, next_at = 0;
945  QPointF next;
946  int segment = 0;
947  for ( ++it; it != points.constEnd(); ++it )
948  {
949  next = *it;
950  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
951  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
952  if ( next_at >= length / 2 )
953  break; // we have reached the center
954  last = *it;
955  last_at = next_at;
956  segment++;
957  }
958 
959  // find out the central point on segment
960  MyLine l( last, next ); // for line angle
961  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
962  QPointF pt = last + ( next - last ) * k;
963 
964  // draw the marker
965  double origAngle = mMarker->angle();
966  if ( mRotateMarker )
967  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
968  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
969  if ( mRotateMarker )
970  mMarker->setAngle( origAngle );
971  }
972 }
973 
974 
976 {
977  QgsStringMap map;
978  map["rotate"] = ( mRotateMarker ? "1" : "0" );
979  map["interval"] = QString::number( mInterval );
980  map["offset"] = QString::number( mOffset );
982  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
983  if ( mPlacement == Vertex )
984  map["placement"] = "vertex";
985  else if ( mPlacement == LastVertex )
986  map["placement"] = "lastvertex";
987  else if ( mPlacement == FirstVertex )
988  map["placement"] = "firstvertex";
989  else if ( mPlacement == CentralPoint )
990  map["placement"] = "centralpoint";
991  else
992  map["placement"] = "interval";
993 
995  return map;
996 }
997 
999 {
1000  return mMarker;
1001 }
1002 
1004 {
1005  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1006  {
1007  delete symbol;
1008  return false;
1009  }
1010 
1011  delete mMarker;
1012  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1013  mColor = mMarker->color();
1014  return true;
1015 }
1016 
1018 {
1020  x->setSubSymbol( mMarker->clone() );
1021  x->setOffset( mOffset );
1022  x->setPlacement( mPlacement );
1023  x->setOffsetUnit( mOffsetUnit );
1026  return x;
1027 }
1028 
1029 void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1030 {
1031  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1032  {
1033  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1034  if ( !props.value( "uom", "" ).isEmpty() )
1035  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1036  element.appendChild( symbolizerElem );
1037 
1038  // <Geometry>
1039  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1040 
1041  QString gap;
1042  switch ( mPlacement )
1043  {
1044  case FirstVertex:
1045  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1046  break;
1047  case LastVertex:
1048  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1049  break;
1050  case CentralPoint:
1051  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1052  break;
1053  case Vertex:
1054  // no way to get line/polygon's vertices, use a VendorOption
1055  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1056  break;
1057  default:
1058  gap = QString::number( mInterval );
1059  break;
1060  }
1061 
1062  if ( !mRotateMarker )
1063  {
1064  // markers in LineSymbolizer must be drawn following the line orientation,
1065  // use a VendorOption when no marker rotation
1066  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1067  }
1068 
1069  // <Stroke>
1070  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1071  symbolizerElem.appendChild( strokeElem );
1072 
1073  // <GraphicStroke>
1074  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1075  strokeElem.appendChild( graphicStrokeElem );
1076 
1077  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1078  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1079  if ( !markerLayer )
1080  {
1081  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
1082  }
1083  else
1084  {
1085  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1086  }
1087 
1088  if ( !gap.isEmpty() )
1089  {
1090  QDomElement gapElem = doc.createElement( "se:Gap" );
1091  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1092  graphicStrokeElem.appendChild( gapElem );
1093  }
1094 
1095  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1096  {
1097  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1098  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1099  symbolizerElem.appendChild( perpOffsetElem );
1100  }
1101  }
1102 }
1103 
1105 {
1106  QgsDebugMsg( "Entered." );
1107 
1108  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1109  if ( strokeElem.isNull() )
1110  return NULL;
1111 
1112  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1113  if ( graphicStrokeElem.isNull() )
1114  return NULL;
1115 
1116  // retrieve vendor options
1117  bool rotateMarker = true;
1119 
1120  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1121  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1122  {
1123  if ( it.key() == "placement" )
1124  {
1125  if ( it.value() == "points" ) placement = Vertex;
1126  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1127  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1128  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1129  }
1130  else if ( it.value() == "rotateMarker" )
1131  {
1132  rotateMarker = it.value() == "0";
1133  }
1134  }
1135 
1136  QgsMarkerSymbolV2 *marker = 0;
1137 
1139  if ( l )
1140  {
1141  QgsSymbolLayerV2List layers;
1142  layers.append( l );
1143  marker = new QgsMarkerSymbolV2( layers );
1144  }
1145 
1146  if ( !marker )
1147  return NULL;
1148 
1149  double interval = 0.0;
1150  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1151  if ( !gapElem.isNull() )
1152  {
1153  bool ok;
1154  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1155  if ( ok )
1156  interval = d;
1157  }
1158 
1159  double offset = 0.0;
1160  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1161  if ( !perpOffsetElem.isNull() )
1162  {
1163  bool ok;
1164  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1165  if ( ok )
1166  offset = d;
1167  }
1168 
1169  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1170  x->setPlacement( placement );
1171  x->setInterval( interval );
1172  x->setSubSymbol( marker );
1173  x->setOffset( offset );
1174  return x;
1175 }
1176 
1178 {
1179  mMarker->setSize( width );
1180 }
1181 
1183 {
1184  return mMarker->size();
1185 }
1186 
1188 {
1189  mIntervalUnit = unit;
1190  mOffsetUnit = unit;
1191 }
1192 
1194 {
1196  if ( mOffsetUnit != unit )
1197  {
1198  return QgsSymbolV2::Mixed;
1199  }
1200  return unit;
1201 }
1202 
1204 {
1205  return ( mMarker->size() / 2.0 ) + mOffset;
1206 }
1207 
static double _averageAngle(const QPointF &prevPt, const QPointF &pt, const QPointF &nextPt)
void setIntervalUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
#define DEFAULT_SIMPLELINE_PENSTYLE
void startRender(QgsSymbolV2RenderContext &context)
#define DEFAULT_MARKERLINE_ROTATE
int renderHints() const
Definition: qgssymbolv2.h:180
virtual double width() const
double markerAngle(const QPolygonF &points, bool isRing, int vertex)
#define DEFAULT_MARKERLINE_INTERVAL
SymbolType type() const
Definition: qgssymbolv2.h:78
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
QColor selectionColor() const
Added in QGIS v2.0.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void setCustomDashPatternUnit(QgsSymbolV2::OutputUnit unit)
double rendererScale() const
static QgsStringMap getVendorOptionList(QDomElement &element)
static QVector< qreal > decodeRealVector(const QString &s)
void renderPolylineInterval(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QVector< qreal > customDashVector() const
void setPenJoinStyle(Qt::PenJoinStyle style)
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
QgsSymbolV2::OutputUnit outputUnit() const
QgsSymbolV2::OutputUnit outputUnit() const
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
static QColor decodeColor(QString str)
QgsSymbolLayerV2 * clone() const
static const bool selectionIsOpaque
bool setSubSymbol(QgsSymbolV2 *symbol)
QVector< qreal > dxfCustomDashPattern(QgsSymbolV2::OutputUnit &unit) const
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
Qt::PenStyle penStyle() const
void setWidthUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeColor(QColor color)
void setInterval(double interval)
virtual QgsExpression * expression(const QString &property) const
QgsSymbolV2::OutputUnit mOffsetUnit
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:172
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
QPointF diffForInterval(double interval)
void setColor(const QColor &color)
QgsSymbolV2::OutputUnit mIntervalUnit
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
QgsStringMap properties() const
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=0)
Create ogr feature style string for pen.
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:186
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'...
static Qt::PenCapStyle decodePenCapStyle(QString str)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static Qt::PenStyle decodePenStyle(QString str)
QgsSymbolV2::OutputUnit mWidthUnit
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
QVector< qreal > mCustomDashVector
Vector with an even number of entries for the.
#define DEFAULT_SIMPLELINE_WIDTH
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
#define M_PI
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setAngle(double angle)
#define DEFAULT_SIMPLELINE_CAPSTYLE
#define DEFAULT_SIMPLELINE_JOINSTYLE
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
int symbolLayerCount()
Definition: qgssymbolv2.h:84
void setSize(double size)
double rasterScaleFactor() const
void startRender(QgsSymbolV2RenderContext &context)
virtual QColor color() const
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
QgsStringMap properties() const
void setPenCapStyle(Qt::PenCapStyle style)
void setCustomDashVector(const QVector< qreal > &vector)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
virtual void setWidth(double width)
void setColor(const QColor &color)
static QString encodeRealVector(const QVector< qreal > &v)
QgsSymbolV2::OutputUnit mCustomDashPatternUnit
virtual QString layerType() const =0
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QgsSymbolLayerV2 * clone() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void applyDataDefinedSymbology(QgsSymbolV2RenderContext &context, QPen &pen, QPen &selPen, double &offset)
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, QColor color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=0, const Qt::PenCapStyle *penCapStyle=0, const QVector< qreal > *customDashPattern=0, double dashOffset=0.0)
#define DEFAULT_SIMPLELINE_COLOR
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
QPainter * painter()
void stopRender(QgsRenderContext &context)
QgsSimpleLineSymbolLayerV2(QColor color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
void stopRender(QgsSymbolV2RenderContext &context)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
virtual QgsSymbolV2 * clone() const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:38
double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:164
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u)
Returns the line width scale factor depending on the unit and the paint device.
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:192
void setRenderHints(int hints)
Definition: qgssymbolv2.h:126
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
MyLine(QPointF p1, QPointF p2)
bool selected() const
Definition: qgssymbolv2.h:176
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsSymbolV2::OutputUnit mOffsetUnit
QPolygonF offsetLine(QPolygonF polyline, double dist)
calculate line shifted by a specified distance
QgsSymbolLayerV2 * symbolLayer(int layer)
Qt::PenStyle dxfPenStyle() const
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=0, Qt::PenCapStyle *penCapStyle=0, QVector< qreal > *customDashPattern=0, double *dashOffset=0)
QgsMarkerLineSymbolLayerV2(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:123
void renderPolylineCentral(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QColor dxfColor(const QgsSymbolV2RenderContext &context) const
static bool canbeGeneralizedByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
void stopRender(QgsSymbolV2RenderContext &context)
QgsSymbolV2::OutputUnit widthUnit() const
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
Qt::PenJoinStyle penJoinStyle() const
void renderPolylineVertex(const QPolygonF &points, QgsSymbolV2RenderContext &context, Placement placement=Vertex)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
Qt::PenCapStyle penCapStyle() const
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)