QGIS API Documentation  2.2.0-Valmiera
 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.layer(), 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 ( points.size() <= 2 && context.layer() && context.layer()->simplifyDrawingCanbeApplied( context.renderContext(), QgsVectorSimplifyMethod::AntialiasingSimplification ) && QgsAbstractGeometrySimplifier::canbeGeneralizedByDeviceBoundingBox( points, context.layer()->simplifyMethod().threshold() ) && ( p->renderHints() & QPainter::Antialiasing ) )
237  {
238  p->setRenderHint( QPainter::Antialiasing, false );
239  p->drawPolyline( points );
240  p->setRenderHint( QPainter::Antialiasing, true );
241  return;
242  }
243 
244  if ( offset == 0 )
245  {
246  p->drawPolyline( points );
247  }
248  else
249  {
250  double scaledOffset = offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
251  p->drawPolyline( ::offsetLine( points, scaledOffset ) );
252  }
253 }
254 
256 {
257  QgsStringMap map;
258  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
259  map["width"] = QString::number( mWidth );
264  map["offset"] = QString::number( mOffset );
266  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
269  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
271  return map;
272 }
273 
275 {
277  l->setWidthUnit( mWidthUnit );
280  l->setOffset( mOffset );
287  return l;
288 }
289 
290 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
291 {
292  if ( mPenStyle == Qt::NoPen )
293  return;
294 
295  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
296  if ( !props.value( "uom", "" ).isEmpty() )
297  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
298  element.appendChild( symbolizerElem );
299 
300  // <Geometry>
301  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
302 
303  // <Stroke>
304  QDomElement strokeElem = doc.createElement( "se:Stroke" );
305  symbolizerElem.appendChild( strokeElem );
306 
307  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
308  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
310 
311  // <se:PerpendicularOffset>
312  if ( mOffset != 0 )
313  {
314  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
315  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
316  symbolizerElem.appendChild( perpOffsetElem );
317  }
318 }
319 
320 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
321 {
322  if ( mUseCustomDashPattern )
323  {
324  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
325  mPen.color(), mPenJoinStyle,
327  }
328  else
329  {
330  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
332  }
333 }
334 
336 {
337  QgsDebugMsg( "Entered." );
338 
339  QDomElement strokeElem = element.firstChildElement( "Stroke" );
340  if ( strokeElem.isNull() )
341  return NULL;
342 
343  Qt::PenStyle penStyle;
344  QColor color;
345  double width;
346  Qt::PenJoinStyle penJoinStyle;
347  Qt::PenCapStyle penCapStyle;
348  QVector<qreal> customDashVector;
349 
350  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
351  color, width,
352  &penJoinStyle, &penCapStyle,
353  &customDashVector ) )
354  return NULL;
355 
356  double offset = 0.0;
357  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
358  if ( !perpOffsetElem.isNull() )
359  {
360  bool ok;
361  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
362  if ( ok )
363  offset = d;
364  }
365 
366  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
367  l->setOffset( offset );
368  l->setPenJoinStyle( penJoinStyle );
369  l->setPenCapStyle( penCapStyle );
370  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
371  l->setCustomDashVector( customDashVector );
372  return l;
373 }
374 
375 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
376 {
377  //data defined properties
378  double scaledWidth = 0;
379  QgsExpression* strokeWidthExpression = expression( "width" );
380  if ( strokeWidthExpression )
381  {
382  scaledWidth = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble()
384  pen.setWidthF( scaledWidth );
385  selPen.setWidthF( scaledWidth );
386  }
387  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
388  {
390  pen.setWidthF( scaledWidth );
391  selPen.setWidthF( scaledWidth );
392  }
393 
394  //color
395  QgsExpression* strokeColorExpression = expression( "color" );
396  if ( strokeColorExpression )
397  {
398  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
399  }
400 
401  //offset
402  offset = mOffset;
403  QgsExpression* lineOffsetExpression = expression( "offset" );
404  if ( lineOffsetExpression )
405  {
406  offset = lineOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
407  }
408 
409  //dash dot vector
410  QgsExpression* dashPatternExpression = expression( "customdash" );
411  if ( dashPatternExpression )
412  {
413  QVector<qreal> dashVector;
414  QStringList dashList = dashPatternExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString().split( ";" );
415  QStringList::const_iterator dashIt = dashList.constBegin();
416  for ( ; dashIt != dashList.constEnd(); ++dashIt )
417  {
418  dashVector.push_back( dashIt->toDouble() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit ) / mPen.widthF() );
419  }
420  pen.setDashPattern( dashVector );
421  }
422 
423  //join style
424  QgsExpression* joinStyleExpression = expression( "joinstyle" );
425  if ( joinStyleExpression )
426  {
427  QString joinStyleString = joinStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
428  pen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( joinStyleString ) );
429  }
430 
431  //cap style
432  QgsExpression* capStyleExpression = expression( "capstyle" );
433  if ( capStyleExpression )
434  {
435  QString capStyleString = capStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
436  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
437  }
438 }
439 
441 {
442  if ( mDrawInsidePolygon )
443  {
444  //set to clip line to the interior of polygon, so we expect no bleed
445  return 0;
446  }
447  else
448  {
449  return ( mWidth / 2.0 ) + mOffset;
450  }
451 }
452 
454 {
455  unit = mCustomDashPatternUnit;
456  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>() ;
457 }
458 
460 {
461  return mPenStyle;
462 }
463 
464 double QgsSimpleLineSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
465 {
466  double width = mWidth;
467  QgsExpression* strokeWidthExpression = expression( "width" );
468  if ( strokeWidthExpression )
469  {
470  width = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
471  }
472  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
473  {
475  }
476 
477  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
478 }
479 
481 {
482  QgsExpression* strokeColorExpression = expression( "color" );
483  if ( strokeColorExpression )
484  {
485  return ( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
486  }
487  return mColor;
488 }
489 
491 
492 
493 class MyLine
494 {
495  public:
496  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
497  {
498  if ( p1 == p2 )
499  return; // invalid
500 
501  // tangent and direction
502  if ( p1.x() == p2.x() )
503  {
504  // vertical line - tangent undefined
505  mVertical = true;
506  mIncreasing = ( p2.y() > p1.y() );
507  }
508  else
509  {
510  mVertical = false;
511  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
512  mIncreasing = ( p2.x() > p1.x() );
513  }
514 
515  // length
516  double x = ( p2.x() - p1.x() );
517  double y = ( p2.y() - p1.y() );
518  mLength = sqrt( x * x + y * y );
519  }
520 
521  // return angle in radians
522  double angle()
523  {
524  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
525 
526  if ( !mIncreasing )
527  a += M_PI;
528  return a;
529  }
530 
531  // return difference for x,y when going along the line with specified interval
532  QPointF diffForInterval( double interval )
533  {
534  if ( mVertical )
535  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
536 
537  double alpha = atan( mT );
538  double dx = cos( alpha ) * interval;
539  double dy = sin( alpha ) * interval;
540  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
541  }
542 
543  double length() { return mLength; }
544 
545  protected:
546  bool mVertical;
548  double mT;
549  double mLength;
550 };
551 
552 
553 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
554 {
558  mMarker = NULL;
559  mOffset = 0;
562 
564 }
565 
567 {
568  delete mMarker;
569 }
570 
572 {
573  bool rotate = DEFAULT_MARKERLINE_ROTATE;
575 
576  if ( props.contains( "interval" ) )
577  interval = props["interval"].toDouble();
578  if ( props.contains( "rotate" ) )
579  rotate = ( props["rotate"] == "1" );
580 
581  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
582  if ( props.contains( "offset" ) )
583  {
584  x->setOffset( props["offset"].toDouble() );
585  }
586  if ( props.contains( "offset_unit" ) )
587  {
588  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
589  }
590  if ( props.contains( "interval_unit" ) )
591  {
592  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
593  }
594 
595  if ( props.contains( "placement" ) )
596  {
597  if ( props["placement"] == "vertex" )
598  x->setPlacement( Vertex );
599  else if ( props["placement"] == "lastvertex" )
600  x->setPlacement( LastVertex );
601  else if ( props["placement"] == "firstvertex" )
603  else if ( props["placement"] == "centralpoint" )
605  else
606  x->setPlacement( Interval );
607  }
608 
609  //data defined properties
610  if ( props.contains( "interval_expression" ) )
611  {
612  x->setDataDefinedProperty( "interval", props["interval_expression"] );
613  }
614  if ( props.contains( "offset_expression" ) )
615  {
616  x->setDataDefinedProperty( "offset", props["offset_expression"] );
617  }
618  if ( props.contains( "placement_expression" ) )
619  {
620  x->setDataDefinedProperty( "placement", props["placement_expression"] );
621  }
622 
623  return x;
624 }
625 
627 {
628  return "MarkerLine";
629 }
630 
631 void QgsMarkerLineSymbolLayerV2::setColor( const QColor& color )
632 {
633  mMarker->setColor( color );
634  mColor = color;
635 }
636 
638 {
639  mMarker->setAlpha( context.alpha() );
640 
641  // if being rotated, it gets initialized with every line segment
642  int hints = 0;
643  if ( mRotateMarker )
647  mMarker->setRenderHints( hints );
648 
649  mMarker->startRender( context.renderContext(), context.layer() );
650 
651  //prepare expressions for data defined properties
652  prepareExpressions( context.layer(), context.renderContext().rendererScale() );
653 }
654 
656 {
657  mMarker->stopRender( context.renderContext() );
658 }
659 
661 {
662  double offset = mOffset;
663  QgsExpression* offsetExpression = expression( "offset" );
664  if ( offsetExpression )
665  {
666  offset = offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
667  }
668 
670  QgsExpression* placementExpression = expression( "placement" );
671  if ( placementExpression )
672  {
673  QString placementString = placementExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
674  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
675  {
676  placement = Vertex;
677  }
678  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
679  {
680  placement = LastVertex;
681  }
682  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
683  {
684  placement = FirstVertex;
685  }
686  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
687  {
688  placement = CentralPoint;
689  }
690  else
691  {
692  placement = Interval;
693  }
694  }
695 
696  if ( offset == 0 )
697  {
698  if ( placement == Interval )
699  renderPolylineInterval( points, context );
700  else if ( placement == CentralPoint )
701  renderPolylineCentral( points, context );
702  else
703  renderPolylineVertex( points, context, placement );
704  }
705  else
706  {
707  QPolygonF points2 = ::offsetLine( points, offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit ) );
708  if ( placement == Interval )
709  renderPolylineInterval( points2, context );
710  else if ( placement == CentralPoint )
711  renderPolylineCentral( points2, context );
712  else
713  renderPolylineVertex( points2, context, placement );
714  }
715 }
716 
718 {
719  if ( points.isEmpty() )
720  return;
721 
722  QPointF lastPt = points[0];
723  double lengthLeft = 0; // how much is left until next marker
724  bool first = true;
725  double origAngle = mMarker->angle();
726 
727  QgsRenderContext& rc = context.renderContext();
728  double interval = mInterval;
729 
730  QgsExpression* intervalExpression = expression( "interval" );
731  if ( intervalExpression )
732  {
733  interval = intervalExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
734  }
735  if ( interval <= 0 )
736  {
737  interval = 0.1;
738  }
739 
740  double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit );
741 
742  for ( int i = 1; i < points.count(); ++i )
743  {
744  const QPointF& pt = points[i];
745 
746  if ( lastPt == pt ) // must not be equal!
747  continue;
748 
749  // for each line, find out dx and dy, and length
750  MyLine l( lastPt, pt );
751  QPointF diff = l.diffForInterval( painterUnitInterval );
752 
753  // if there's some length left from previous line
754  // use only the rest for the first point in new line segment
755  double c = 1 - lengthLeft / painterUnitInterval;
756 
757  lengthLeft += l.length();
758 
759  // rotate marker (if desired)
760  if ( mRotateMarker )
761  {
762  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
763  }
764 
765  // draw first marker
766  if ( first )
767  {
768  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
769  first = false;
770  }
771 
772  // while we're not at the end of line segment, draw!
773  while ( lengthLeft > painterUnitInterval )
774  {
775  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
776  lastPt += c * diff;
777  lengthLeft -= painterUnitInterval;
778  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
779  c = 1; // reset c (if wasn't 1 already)
780  }
781 
782  lastPt = pt;
783  }
784 
785  // restore original rotation
786  mMarker->setAngle( origAngle );
787 
788 }
789 
790 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
791 {
792  // calc average angle between the previous and next point
793  double a1 = MyLine( prevPt, pt ).angle();
794  double a2 = MyLine( pt, nextPt ).angle();
795  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
796 
797  return atan2( unitY, unitX );
798 }
799 
800 void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement )
801 {
802  if ( points.isEmpty() )
803  return;
804 
805  QgsRenderContext& rc = context.renderContext();
806 
807  double origAngle = mMarker->angle();
808  int i, maxCount;
809  bool isRing = false;
810 
811  if ( placement == FirstVertex )
812  {
813  i = 0;
814  maxCount = 1;
815  }
816  else if ( placement == LastVertex )
817  {
818  i = points.count() - 1;
819  maxCount = points.count();
820  }
821  else
822  {
823  i = 0;
824  maxCount = points.count();
825  if ( points.first() == points.last() )
826  isRing = true;
827  }
828 
829  for ( ; i < maxCount; ++i )
830  {
831  if ( isRing && placement == Vertex && i == points.count() - 1 )
832  {
833  continue; // don't draw the last marker - it has been drawn already
834  }
835  // rotate marker (if desired)
836  if ( mRotateMarker )
837  {
838  double angle = markerAngle( points, isRing, i );
839  mMarker->setAngle( origAngle + angle * 180 / M_PI );
840  }
841 
842  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
843  }
844 
845  // restore original rotation
846  mMarker->setAngle( origAngle );
847 }
848 
849 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
850 {
851  double angle = 0;
852  const QPointF& pt = points[vertex];
853 
854  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
855  {
856  int prevIndex = vertex - 1;
857  int nextIndex = vertex + 1;
858 
859  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
860  {
861  prevIndex = points.count() - 2;
862  nextIndex = 1;
863  }
864 
865  QPointF prevPoint, nextPoint;
866  while ( prevIndex >= 0 )
867  {
868  prevPoint = points[ prevIndex ];
869  if ( prevPoint != pt )
870  {
871  break;
872  }
873  --prevIndex;
874  }
875 
876  while ( nextIndex < points.count() )
877  {
878  nextPoint = points[ nextIndex ];
879  if ( nextPoint != pt )
880  {
881  break;
882  }
883  ++nextIndex;
884  }
885 
886  if ( prevIndex >= 0 && nextIndex < points.count() )
887  {
888  angle = _averageAngle( prevPoint, pt, nextPoint );
889  }
890  }
891  else //no ring and vertex is at start / at end
892  {
893  if ( vertex == 0 )
894  {
895  while ( vertex < points.size() - 1 )
896  {
897  const QPointF& nextPt = points[vertex+1];
898  if ( pt != nextPt )
899  {
900  angle = MyLine( pt, nextPt ).angle();
901  return angle;
902  }
903  ++vertex;
904  }
905  }
906  else
907  {
908  // use last segment's angle
909  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
910  {
911  const QPointF& prevPt = points[vertex-1];
912  if ( pt != prevPt )
913  {
914  angle = MyLine( prevPt, pt ).angle();
915  return angle;
916  }
917  --vertex;
918  }
919  }
920  }
921  return angle;
922 }
923 
925 {
926  if ( points.size() > 0 )
927  {
928  // calc length
929  qreal length = 0;
930  QPolygonF::const_iterator it = points.constBegin();
931  QPointF last = *it;
932  for ( ++it; it != points.constEnd(); ++it )
933  {
934  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
935  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
936  last = *it;
937  }
938 
939  // find the segment where the central point lies
940  it = points.constBegin();
941  last = *it;
942  qreal last_at = 0, next_at = 0;
943  QPointF next;
944  int segment = 0;
945  for ( ++it; it != points.constEnd(); ++it )
946  {
947  next = *it;
948  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
949  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
950  if ( next_at >= length / 2 )
951  break; // we have reached the center
952  last = *it;
953  last_at = next_at;
954  segment++;
955  }
956 
957  // find out the central point on segment
958  MyLine l( last, next ); // for line angle
959  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
960  QPointF pt = last + ( next - last ) * k;
961 
962  // draw the marker
963  double origAngle = mMarker->angle();
964  if ( mRotateMarker )
965  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
966  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
967  if ( mRotateMarker )
968  mMarker->setAngle( origAngle );
969  }
970 }
971 
972 
974 {
975  QgsStringMap map;
976  map["rotate"] = ( mRotateMarker ? "1" : "0" );
977  map["interval"] = QString::number( mInterval );
978  map["offset"] = QString::number( mOffset );
980  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
981  if ( mPlacement == Vertex )
982  map["placement"] = "vertex";
983  else if ( mPlacement == LastVertex )
984  map["placement"] = "lastvertex";
985  else if ( mPlacement == FirstVertex )
986  map["placement"] = "firstvertex";
987  else if ( mPlacement == CentralPoint )
988  map["placement"] = "centralpoint";
989  else
990  map["placement"] = "interval";
991 
993  return map;
994 }
995 
997 {
998  return mMarker;
999 }
1000 
1002 {
1003  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1004  {
1005  delete symbol;
1006  return false;
1007  }
1008 
1009  delete mMarker;
1010  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1011  mColor = mMarker->color();
1012  return true;
1013 }
1014 
1016 {
1018  x->setSubSymbol( mMarker->clone() );
1019  x->setOffset( mOffset );
1020  x->setPlacement( mPlacement );
1021  x->setOffsetUnit( mOffsetUnit );
1024  return x;
1025 }
1026 
1027 void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1028 {
1029  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1030  {
1031  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1032  if ( !props.value( "uom", "" ).isEmpty() )
1033  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1034  element.appendChild( symbolizerElem );
1035 
1036  // <Geometry>
1037  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1038 
1039  QString gap;
1040  switch ( mPlacement )
1041  {
1042  case FirstVertex:
1043  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1044  break;
1045  case LastVertex:
1046  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1047  break;
1048  case CentralPoint:
1049  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1050  break;
1051  case Vertex:
1052  // no way to get line/polygon's vertices, use a VendorOption
1053  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1054  break;
1055  default:
1056  gap = QString::number( mInterval );
1057  break;
1058  }
1059 
1060  if ( !mRotateMarker )
1061  {
1062  // markers in LineSymbolizer must be drawn following the line orientation,
1063  // use a VendorOption when no marker rotation
1064  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1065  }
1066 
1067  // <Stroke>
1068  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1069  symbolizerElem.appendChild( strokeElem );
1070 
1071  // <GraphicStroke>
1072  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1073  strokeElem.appendChild( graphicStrokeElem );
1074 
1075  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1076  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1077  if ( !markerLayer )
1078  {
1079  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
1080  }
1081  else
1082  {
1083  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1084  }
1085 
1086  if ( !gap.isEmpty() )
1087  {
1088  QDomElement gapElem = doc.createElement( "se:Gap" );
1089  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1090  graphicStrokeElem.appendChild( gapElem );
1091  }
1092 
1093  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1094  {
1095  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1096  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1097  symbolizerElem.appendChild( perpOffsetElem );
1098  }
1099  }
1100 }
1101 
1103 {
1104  QgsDebugMsg( "Entered." );
1105 
1106  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1107  if ( strokeElem.isNull() )
1108  return NULL;
1109 
1110  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1111  if ( graphicStrokeElem.isNull() )
1112  return NULL;
1113 
1114  // retrieve vendor options
1115  bool rotateMarker = true;
1117 
1118  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1119  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1120  {
1121  if ( it.key() == "placement" )
1122  {
1123  if ( it.value() == "points" ) placement = Vertex;
1124  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1125  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1126  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1127  }
1128  else if ( it.value() == "rotateMarker" )
1129  {
1130  rotateMarker = it.value() == "0";
1131  }
1132  }
1133 
1134  QgsMarkerSymbolV2 *marker = 0;
1135 
1137  if ( l )
1138  {
1139  QgsSymbolLayerV2List layers;
1140  layers.append( l );
1141  marker = new QgsMarkerSymbolV2( layers );
1142  }
1143 
1144  if ( !marker )
1145  return NULL;
1146 
1147  double interval = 0.0;
1148  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1149  if ( !gapElem.isNull() )
1150  {
1151  bool ok;
1152  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1153  if ( ok )
1154  interval = d;
1155  }
1156 
1157  double offset = 0.0;
1158  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1159  if ( !perpOffsetElem.isNull() )
1160  {
1161  bool ok;
1162  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1163  if ( ok )
1164  offset = d;
1165  }
1166 
1167  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1168  x->setPlacement( placement );
1169  x->setInterval( interval );
1170  x->setSubSymbol( marker );
1171  x->setOffset( offset );
1172  return x;
1173 }
1174 
1176 {
1177  mMarker->setSize( width );
1178 }
1179 
1181 {
1182  return mMarker->size();
1183 }
1184 
1186 {
1187  mIntervalUnit = unit;
1188  mOffsetUnit = unit;
1189 }
1190 
1192 {
1194  if ( mOffsetUnit != unit )
1195  {
1196  return QgsSymbolV2::Mixed;
1197  }
1198  return unit;
1199 }
1200 
1202 {
1203  return ( mMarker->size() / 2.0 ) + mOffset;
1204 }
1205 
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
float threshold() const
Gets the simplification threshold of the vector layer managed.
int renderHints() const
Definition: qgssymbolv2.h:179
virtual double width() const
double markerAngle(const QPolygonF &points, bool isRing, int vertex)
#define DEFAULT_MARKERLINE_INTERVAL
SymbolType type() const
Definition: qgssymbolv2.h:77
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)
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
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:397
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:305
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:171
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
QPointF diffForInterval(double interval)
virtual void prepareExpressions(const QgsVectorLayer *vl, double scale=-1.0)
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
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, QgsVectorSimplifyMethod::SimplifyHint simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
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
Definition: qgssymbolv2.h:184
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:83
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)
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:37
double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:163
void startRender(QgsRenderContext &context, const QgsVectorLayer *layer=0)
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.
void setRenderHints(int hints)
Definition: qgssymbolv2.h:125
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
MyLine(QPointF p1, QPointF p2)
bool selected() const
Definition: qgssymbolv2.h:175
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:122
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
const QgsVectorLayer * layer() const
Definition: qgssymbolv2.h:187
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)