QGIS API Documentation  2.10.1-Pisa
 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 )
33  , mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE )
34  , mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE )
35  , mUseCustomDashPattern( false )
36  , mCustomDashPatternUnit( QgsSymbolV2::MM )
37  , mDrawInsidePolygon( false )
38 {
39  mColor = color;
40  mWidth = width;
41  mCustomDashVector << 5 << 2;
42 }
43 
45 {
47  mWidthUnit = unit;
48  mOffsetUnit = unit;
50 }
51 
53 {
55  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
56  {
57  return QgsSymbolV2::Mixed;
58  }
59  return unit;
60 }
61 
63 {
65  mWidthMapUnitScale = scale;
66  mOffsetMapUnitScale = scale;
68 }
69 
71 {
75  {
76  return mWidthMapUnitScale;
77  }
78  return QgsMapUnitScale();
79 }
80 
82 {
86 
87  if ( props.contains( "line_color" ) )
88  {
89  color = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
90  }
91  else if ( props.contains( "outline_color" ) )
92  {
93  color = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
94  }
95  else if ( props.contains( "color" ) )
96  {
97  //pre 2.5 projects used "color"
98  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
99  }
100  if ( props.contains( "line_width" ) )
101  {
102  width = props["line_width"].toDouble();
103  }
104  else if ( props.contains( "outline_width" ) )
105  {
106  width = props["outline_width"].toDouble();
107  }
108  else if ( props.contains( "width" ) )
109  {
110  //pre 2.5 projects used "width"
111  width = props["width"].toDouble();
112  }
113  if ( props.contains( "line_style" ) )
114  {
115  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] );
116  }
117  else if ( props.contains( "outline_style" ) )
118  {
119  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] );
120  }
121  else if ( props.contains( "penstyle" ) )
122  {
123  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["penstyle"] );
124  }
125 
126  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
127  if ( props.contains( "line_width_unit" ) )
128  {
129  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
130  }
131  else if ( props.contains( "outline_width_unit" ) )
132  {
133  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
134  }
135  else if ( props.contains( "width_unit" ) )
136  {
137  //pre 2.5 projects used "width_unit"
138  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["width_unit"] ) );
139  }
140  if ( props.contains( "width_map_unit_scale" ) )
141  l->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["width_map_unit_scale"] ) );
142  if ( props.contains( "offset" ) )
143  l->setOffset( props["offset"].toDouble() );
144  if ( props.contains( "offset_unit" ) )
145  l->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
146  if ( props.contains( "offset_map_unit_scale" ) )
147  l->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
148  if ( props.contains( "joinstyle" ) )
150  if ( props.contains( "capstyle" ) )
151  l->setPenCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( props["capstyle"] ) );
152 
153  if ( props.contains( "use_custom_dash" ) )
154  {
155  l->setUseCustomDashPattern( props["use_custom_dash"].toInt() );
156  }
157  if ( props.contains( "customdash" ) )
158  {
160  }
161  if ( props.contains( "customdash_unit" ) )
162  {
163  l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
164  }
165  if ( props.contains( "customdash_map_unit_scale" ) )
166  {
167  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["customdash_map_unit_scale"] ) );
168  }
169 
170  if ( props.contains( "draw_inside_polygon" ) )
171  {
172  l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
173  }
174 
175  l->restoreDataDefinedProperties( props );
176 
177  return l;
178 }
179 
180 
182 {
183  return "SimpleLine";
184 }
185 
187 {
188  QColor penColor = mColor;
189  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
190  mPen.setColor( penColor );
192  mPen.setWidthF( scaledWidth );
193  if ( mUseCustomDashPattern && scaledWidth != 0 )
194  {
195  mPen.setStyle( Qt::CustomDashLine );
196 
197  //scale pattern vector
198  double dashWidthDiv = scaledWidth;
199  //fix dash pattern width in Qt 4.8
200  QStringList versionSplit = QString( qVersion() ).split( "." );
201  if ( versionSplit.size() > 1
202  && versionSplit.at( 1 ).toInt() >= 8
203  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
204  {
205  dashWidthDiv = 1.0;
206  }
207  QVector<qreal> scaledVector;
209  for ( ; it != mCustomDashVector.constEnd(); ++it )
210  {
211  //the dash is specified in terms of pen widths, therefore the division
213  }
214  mPen.setDashPattern( scaledVector );
215  }
216  else
217  {
219  }
222 
223  mSelPen = mPen;
224  QColor selColor = context.renderContext().selectionColor();
225  if ( ! selectionIsOpaque )
226  selColor.setAlphaF( context.alpha() );
227  mSelPen.setColor( selColor );
228 
229  //prepare expressions for data defined properties
230  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
231 }
232 
234 {
235  Q_UNUSED( context );
236 }
237 
239 {
240  QPainter* p = context.renderContext().painter();
241  if ( !p )
242  {
243  return;
244  }
245 
246  if ( mDrawInsidePolygon )
247  {
248  //only drawing the line on the interior of the polygon, so set clip path for painter
249  p->save();
250  QPainterPath clipPath;
251  clipPath.addPolygon( points );
252 
253  if ( rings != NULL )
254  {
255  //add polygon rings
257  for ( ; it != rings->constEnd(); ++it )
258  {
259  QPolygonF ring = *it;
260  clipPath.addPolygon( ring );
261  }
262  }
263 
264  //use intersect mode, as a clip path may already exist (eg, for composer maps)
265  p->setClipPath( clipPath, Qt::IntersectClip );
266  }
267 
268  renderPolyline( points, context );
269  if ( rings )
270  {
271  mOffset = -mOffset; // invert the offset for rings!
272  foreach ( const QPolygonF& ring, *rings )
273  renderPolyline( ring, context );
274  mOffset = -mOffset;
275  }
276 
277  if ( mDrawInsidePolygon )
278  {
279  //restore painter to reset clip path
280  p->restore();
281  }
282 
283 }
284 
286 {
287  QPainter* p = context.renderContext().painter();
288  if ( !p )
289  {
290  return;
291  }
292 
293  //size scaling by field
295  {
296  applySizeScale( context, mPen, mSelPen );
297  }
298 
299  double offset = mOffset;
300  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
301 
302  p->setPen( context.selected() ? mSelPen : mPen );
303 
304  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
305  if ( points.size() <= 2 &&
308  ( p->renderHints() & QPainter::Antialiasing ) )
309  {
310  p->setRenderHint( QPainter::Antialiasing, false );
311  p->drawPolyline( points );
312  p->setRenderHint( QPainter::Antialiasing, true );
313  return;
314  }
315 
316  if ( qgsDoubleNear( offset, 0 ) )
317  {
318  p->drawPolyline( points );
319  }
320  else
321  {
323  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );
324  for ( int part = 0; part < mline.count(); ++part )
325  p->drawPolyline( mline[ part ] );
326  }
327 }
328 
330 {
331  QgsStringMap map;
332  map["line_color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
333  map["line_width"] = QString::number( mWidth );
334  map["line_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
335  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
336  map["line_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mPenStyle );
339  map["offset"] = QString::number( mOffset );
341  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
342  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
346  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
348  return map;
349 }
350 
352 {
354  l->setWidthUnit( mWidthUnit );
360  l->setOffset( mOffset );
367  copyPaintEffect( l );
368  return l;
369 }
370 
372 {
373  if ( mPenStyle == Qt::NoPen )
374  return;
375 
376  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
377  if ( !props.value( "uom", "" ).isEmpty() )
378  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
379  element.appendChild( symbolizerElem );
380 
381  // <Geometry>
382  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
383 
384  // <Stroke>
385  QDomElement strokeElem = doc.createElement( "se:Stroke" );
386  symbolizerElem.appendChild( strokeElem );
387 
388  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
389  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
391 
392  // <se:PerpendicularOffset>
393  if ( mOffset != 0 )
394  {
395  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
396  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
397  symbolizerElem.appendChild( perpOffsetElem );
398  }
399 }
400 
401 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
402 {
403  if ( mUseCustomDashPattern )
404  {
405  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
408  }
409  else
410  {
411  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
413  }
414 }
415 
417 {
418  QgsDebugMsg( "Entered." );
419 
420  QDomElement strokeElem = element.firstChildElement( "Stroke" );
421  if ( strokeElem.isNull() )
422  return NULL;
423 
424  Qt::PenStyle penStyle;
425  QColor color;
426  double width;
427  Qt::PenJoinStyle penJoinStyle;
428  Qt::PenCapStyle penCapStyle;
430 
431  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
432  color, width,
433  &penJoinStyle, &penCapStyle,
434  &customDashVector ) )
435  return NULL;
436 
437  double offset = 0.0;
438  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
439  if ( !perpOffsetElem.isNull() )
440  {
441  bool ok;
442  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
443  if ( ok )
444  offset = d;
445  }
446 
447  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
448  l->setOffset( offset );
449  l->setPenJoinStyle( penJoinStyle );
450  l->setPenCapStyle( penCapStyle );
451  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
452  l->setCustomDashVector( customDashVector );
453  return l;
454 }
455 
456 void QgsSimpleLineSymbolLayerV2::applySizeScale( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen )
457 {
459  pen.setWidthF( scaledWidth );
460  selPen.setWidthF( scaledWidth );
461 }
462 
463 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
464 {
465  if ( !hasDataDefinedProperties() )
466  return; // shortcut
467 
468  //data defined properties
469  bool hasStrokeWidthExpression = false;
471  {
472  double scaledWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context.feature(), mWidth ).toDouble()
474  pen.setWidthF( scaledWidth );
475  selPen.setWidthF( scaledWidth );
476  hasStrokeWidthExpression = true;
477  }
478 
479  //color
480  bool ok;
482  {
484  if ( ok )
485  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
486  }
487 
488  //offset
490  {
491  offset = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET, context.feature(), offset ).toDouble();
492  }
493 
494  //dash dot vector
496  {
498  double dashWidthDiv = mPen.widthF();
499 
500  if ( hasStrokeWidthExpression )
501  {
502  dashWidthDiv = pen.widthF();
503  scaledWidth = pen.widthF();
504  }
505 
506  //fix dash pattern width in Qt 4.8
507  QStringList versionSplit = QString( qVersion() ).split( "." );
508  if ( versionSplit.size() > 1
509  && versionSplit.at( 1 ).toInt() >= 8
510  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
511  {
512  dashWidthDiv = 1.0;
513  }
514 
515  QVector<qreal> dashVector;
517  if ( ok )
518  {
519  QStringList::const_iterator dashIt = dashList.constBegin();
520  for ( ; dashIt != dashList.constEnd(); ++dashIt )
521  {
523  }
524  pen.setDashPattern( dashVector );
525  }
526  }
527 
528  //line style
530  {
532  if ( ok )
533  pen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( lineStyleString ) );
534  }
535 
536  //join style
538  {
540  if ( ok )
542  }
543 
544  //cap style
546  {
548  if ( ok )
549  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
550  }
551 }
552 
554 {
555  if ( mDrawInsidePolygon )
556  {
557  //set to clip line to the interior of polygon, so we expect no bleed
558  return 0;
559  }
560  else
561  {
562  return ( mWidth / 2.0 ) + mOffset;
563  }
564 }
565 
567 {
568  unit = mCustomDashPatternUnit;
570 }
571 
573 {
574  return mPenStyle;
575 }
576 
578 {
579  double width = mWidth;
580 
582  {
584  }
585  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
586  {
588  }
589 
590  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
591 }
592 
594 {
596  {
597  bool ok;
598  QString colorString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR, context.feature(), QVariant(), &ok ).toString();
599  if ( ok )
600  return ( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
601  }
602  return mColor;
603 }
604 
606 {
607  Q_UNUSED( e );
608  double offset = mOffset;
609 
611  {
613  }
614  return offset;
615 }
616 
618 
619 
620 class MyLine
621 {
622  public:
623  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
624  {
625  if ( p1 == p2 )
626  return; // invalid
627 
628  // tangent and direction
629  if ( p1.x() == p2.x() )
630  {
631  // vertical line - tangent undefined
632  mVertical = true;
633  mIncreasing = ( p2.y() > p1.y() );
634  }
635  else
636  {
637  mVertical = false;
638  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
639  mIncreasing = ( p2.x() > p1.x() );
640  }
641 
642  // length
643  double x = ( p2.x() - p1.x() );
644  double y = ( p2.y() - p1.y() );
645  mLength = sqrt( x * x + y * y );
646  }
647 
648  // return angle in radians
649  double angle()
650  {
651  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
652 
653  if ( !mIncreasing )
654  a += M_PI;
655  return a;
656  }
657 
658  // return difference for x,y when going along the line with specified interval
659  QPointF diffForInterval( double interval )
660  {
661  if ( mVertical )
662  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
663 
664  double alpha = atan( mT );
665  double dx = cos( alpha ) * interval;
666  double dy = sin( alpha ) * interval;
667  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
668  }
669 
670  double length() { return mLength; }
671 
672  protected:
673  bool mVertical;
675  double mT;
676  double mLength;
677 };
678 
679 
680 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
681 {
685  mMarker = NULL;
687  mOffsetAlongLine = 0;
689 
691 }
692 
694 {
695  delete mMarker;
696 }
697 
699 {
700  bool rotate = DEFAULT_MARKERLINE_ROTATE;
702 
703 
704  if ( props.contains( "interval" ) )
705  interval = props["interval"].toDouble();
706  if ( props.contains( "rotate" ) )
707  rotate = ( props["rotate"] == "1" );
708 
709  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
710  if ( props.contains( "offset" ) )
711  {
712  x->setOffset( props["offset"].toDouble() );
713  }
714  if ( props.contains( "offset_unit" ) )
715  {
716  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
717  }
718  if ( props.contains( "interval_unit" ) )
719  {
720  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
721  }
722  if ( props.contains( "offset_along_line" ) )
723  {
724  x->setOffsetAlongLine( props["offset_along_line"].toDouble() );
725  }
726  if ( props.contains( "offset_along_line_unit" ) )
727  {
728  x->setOffsetAlongLineUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_along_line_unit"] ) );
729  }
730  if ( props.contains(( "offset_along_line_map_unit_scale" ) ) )
731  {
732  x->setOffsetAlongLineMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_along_line_map_unit_scale"] ) );
733  }
734 
735  if ( props.contains( "offset_map_unit_scale" ) )
736  {
737  x->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
738  }
739  if ( props.contains( "interval_map_unit_scale" ) )
740  {
741  x->setIntervalMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["interval_map_unit_scale"] ) );
742  }
743 
744  if ( props.contains( "placement" ) )
745  {
746  if ( props["placement"] == "vertex" )
747  x->setPlacement( Vertex );
748  else if ( props["placement"] == "lastvertex" )
749  x->setPlacement( LastVertex );
750  else if ( props["placement"] == "firstvertex" )
752  else if ( props["placement"] == "centralpoint" )
754  else
755  x->setPlacement( Interval );
756  }
757 
758  x->restoreDataDefinedProperties( props );
759 
760  return x;
761 }
762 
764 {
765  return "MarkerLine";
766 }
767 
769 {
770  mMarker->setColor( color );
771  mColor = color;
772 }
773 
775 {
776  mMarker->setAlpha( context.alpha() );
777 
778  // if being rotated, it gets initialized with every line segment
779  int hints = 0;
780  if ( mRotateMarker )
784  mMarker->setRenderHints( hints );
785 
786  mMarker->startRender( context.renderContext(), context.fields() );
787 
788  //prepare expressions for data defined properties
789  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
790 }
791 
793 {
794  mMarker->stopRender( context.renderContext() );
795 }
796 
798 {
799  double offset = mOffset;
800 
802  {
804  }
805 
807 
808  bool ok;
810  {
811  QString placementString = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_PLACEMENT, context.feature(), QVariant(), &ok ).toString();
812  if ( ok )
813  {
814  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
815  {
816  placement = Vertex;
817  }
818  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
819  {
820  placement = LastVertex;
821  }
822  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
823  {
824  placement = FirstVertex;
825  }
826  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
827  {
828  placement = CentralPoint;
829  }
830  else
831  {
832  placement = Interval;
833  }
834  }
835  }
836 
837  if ( offset == 0 )
838  {
839  if ( placement == Interval )
840  renderPolylineInterval( points, context );
841  else if ( placement == CentralPoint )
842  renderPolylineCentral( points, context );
843  else
844  renderPolylineVertex( points, context, placement );
845  }
846  else
847  {
849 
850  for ( int part = 0; part < mline.count(); ++part )
851  {
852  const QPolygonF &points2 = mline[ part ];
853 
854  if ( placement == Interval )
855  renderPolylineInterval( points2, context );
856  else if ( placement == CentralPoint )
857  renderPolylineCentral( points2, context );
858  else
859  renderPolylineVertex( points2, context, placement );
860  }
861  }
862 }
863 
865 {
866  renderPolyline( points, context );
867  if ( rings )
868  {
869  mOffset = -mOffset; // invert the offset for rings!
870  foreach ( const QPolygonF& ring, *rings )
871  renderPolyline( ring, context );
872  mOffset = -mOffset;
873  }
874 }
875 
877 {
878  if ( points.isEmpty() )
879  return;
880 
881  QPointF lastPt = points[0];
882  double lengthLeft = 0; // how much is left until next marker
883  bool first = mOffsetAlongLine ? false : true; //only draw marker at first vertex when no offset along line is set
884 
885  QgsRenderContext& rc = context.renderContext();
886  double interval = mInterval;
887 
889  {
891  }
892  if ( interval <= 0 )
893  {
894  interval = 0.1;
895  }
898  {
900  }
901 
902  double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
903  lengthLeft = painterUnitInterval - offsetAlongLine * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
904 
905  for ( int i = 1; i < points.count(); ++i )
906  {
907  const QPointF& pt = points[i];
908 
909  if ( lastPt == pt ) // must not be equal!
910  continue;
911 
912  // for each line, find out dx and dy, and length
913  MyLine l( lastPt, pt );
914  QPointF diff = l.diffForInterval( painterUnitInterval );
915 
916  // if there's some length left from previous line
917  // use only the rest for the first point in new line segment
918  double c = 1 - lengthLeft / painterUnitInterval;
919 
920  lengthLeft += l.length();
921 
922  // rotate marker (if desired)
923  if ( mRotateMarker )
924  {
925  mMarker->setLineAngle( l.angle() * 180 / M_PI );
926  }
927 
928  // draw first marker
929  if ( first )
930  {
931  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
932  first = false;
933  }
934 
935  // while we're not at the end of line segment, draw!
936  while ( lengthLeft > painterUnitInterval )
937  {
938  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
939  lastPt += c * diff;
940  lengthLeft -= painterUnitInterval;
941  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
942  c = 1; // reset c (if wasn't 1 already)
943  }
944 
945  lastPt = pt;
946  }
947 }
948 
949 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
950 {
951  // calc average angle between the previous and next point
952  double a1 = MyLine( prevPt, pt ).angle();
953  double a2 = MyLine( pt, nextPt ).angle();
954  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
955 
956  return atan2( unitY, unitX );
957 }
958 
960 {
961  if ( points.isEmpty() )
962  return;
963 
964  QgsRenderContext& rc = context.renderContext();
965 
966  double origAngle = mMarker->angle();
967  int i, maxCount;
968  bool isRing = false;
969 
972  {
974  }
975  if ( offsetAlongLine != 0 )
976  {
977  //scale offset along line
979  }
980 
981  if ( placement == FirstVertex )
982  {
983  i = 0;
984  maxCount = 1;
985  }
986  else if ( placement == LastVertex )
987  {
988  i = points.count() - 1;
989  maxCount = points.count();
990  }
991  else
992  {
993  i = 0;
994  maxCount = points.count();
995  if ( points.first() == points.last() )
996  isRing = true;
997  }
998 
999  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
1000  {
1001  double distance;
1002  distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
1003  renderOffsetVertexAlongLine( points, i, distance, context );
1004  // restore original rotation
1005  mMarker->setAngle( origAngle );
1006  return;
1007  }
1008 
1009  for ( ; i < maxCount; ++i )
1010  {
1011  if ( isRing && placement == Vertex && i == points.count() - 1 )
1012  {
1013  continue; // don't draw the last marker - it has been drawn already
1014  }
1015  // rotate marker (if desired)
1016  if ( mRotateMarker )
1017  {
1018  double angle = markerAngle( points, isRing, i );
1019  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1020  }
1021 
1022  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
1023  }
1024 
1025  // restore original rotation
1026  mMarker->setAngle( origAngle );
1027 }
1028 
1029 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
1030 {
1031  double angle = 0;
1032  const QPointF& pt = points[vertex];
1033 
1034  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1035  {
1036  int prevIndex = vertex - 1;
1037  int nextIndex = vertex + 1;
1038 
1039  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1040  {
1041  prevIndex = points.count() - 2;
1042  nextIndex = 1;
1043  }
1044 
1045  QPointF prevPoint, nextPoint;
1046  while ( prevIndex >= 0 )
1047  {
1048  prevPoint = points[ prevIndex ];
1049  if ( prevPoint != pt )
1050  {
1051  break;
1052  }
1053  --prevIndex;
1054  }
1055 
1056  while ( nextIndex < points.count() )
1057  {
1058  nextPoint = points[ nextIndex ];
1059  if ( nextPoint != pt )
1060  {
1061  break;
1062  }
1063  ++nextIndex;
1064  }
1065 
1066  if ( prevIndex >= 0 && nextIndex < points.count() )
1067  {
1068  angle = _averageAngle( prevPoint, pt, nextPoint );
1069  }
1070  }
1071  else //no ring and vertex is at start / at end
1072  {
1073  if ( vertex == 0 )
1074  {
1075  while ( vertex < points.size() - 1 )
1076  {
1077  const QPointF& nextPt = points[vertex+1];
1078  if ( pt != nextPt )
1079  {
1080  angle = MyLine( pt, nextPt ).angle();
1081  return angle;
1082  }
1083  ++vertex;
1084  }
1085  }
1086  else
1087  {
1088  // use last segment's angle
1089  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1090  {
1091  const QPointF& prevPt = points[vertex-1];
1092  if ( pt != prevPt )
1093  {
1094  angle = MyLine( prevPt, pt ).angle();
1095  return angle;
1096  }
1097  --vertex;
1098  }
1099  }
1100  }
1101  return angle;
1102 }
1103 
1104 void QgsMarkerLineSymbolLayerV2::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext& context )
1105 {
1106  if ( points.isEmpty() )
1107  return;
1108 
1109  QgsRenderContext& rc = context.renderContext();
1110  double origAngle = mMarker->angle();
1111  if ( distance == 0 )
1112  {
1113  // rotate marker (if desired)
1114  if ( mRotateMarker )
1115  {
1116  bool isRing = false;
1117  if ( points.first() == points.last() )
1118  isRing = true;
1119  double angle = markerAngle( points, isRing, vertex );
1120  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1121  }
1122  mMarker->renderPoint( points[vertex], context.feature(), rc, -1, context.selected() );
1123  return;
1124  }
1125 
1126  int pointIncrement = distance > 0 ? 1 : -1;
1127  QPointF previousPoint = points[vertex];
1128  int startPoint = distance > 0 ? qMin( vertex + 1, points.count() - 1 ) : qMax( vertex - 1, 0 );
1129  int endPoint = distance > 0 ? points.count() - 1 : 0;
1130  double distanceLeft = qAbs( distance );
1131 
1132  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1133  {
1134  const QPointF& pt = points[i];
1135 
1136  if ( previousPoint == pt ) // must not be equal!
1137  continue;
1138 
1139  // create line segment
1140  MyLine l( previousPoint, pt );
1141 
1142  if ( distanceLeft < l.length() )
1143  {
1144  //destination point is in current segment
1145  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1146  // rotate marker (if desired)
1147  if ( mRotateMarker )
1148  {
1149  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1150  }
1151  mMarker->renderPoint( markerPoint, context.feature(), rc, -1, context.selected() );
1152  return;
1153  }
1154 
1155  distanceLeft -= l.length();
1156  previousPoint = pt;
1157  }
1158 
1159  //didn't find point
1160  return;
1161 }
1162 
1164 {
1165  if ( points.size() > 0 )
1166  {
1167  // calc length
1168  qreal length = 0;
1169  QPolygonF::const_iterator it = points.constBegin();
1170  QPointF last = *it;
1171  for ( ++it; it != points.constEnd(); ++it )
1172  {
1173  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1174  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1175  last = *it;
1176  }
1177 
1178  // find the segment where the central point lies
1179  it = points.constBegin();
1180  last = *it;
1181  qreal last_at = 0, next_at = 0;
1182  QPointF next;
1183  int segment = 0;
1184  for ( ++it; it != points.constEnd(); ++it )
1185  {
1186  next = *it;
1187  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1188  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1189  if ( next_at >= length / 2 )
1190  break; // we have reached the center
1191  last = *it;
1192  last_at = next_at;
1193  segment++;
1194  }
1195 
1196  // find out the central point on segment
1197  MyLine l( last, next ); // for line angle
1198  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1199  QPointF pt = last + ( next - last ) * k;
1200 
1201  // draw the marker
1202  double origAngle = mMarker->angle();
1203  if ( mRotateMarker )
1204  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
1205  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
1206  if ( mRotateMarker )
1207  mMarker->setAngle( origAngle );
1208  }
1209 }
1210 
1211 
1213 {
1214  QgsStringMap map;
1215  map["rotate"] = ( mRotateMarker ? "1" : "0" );
1216  map["interval"] = QString::number( mInterval );
1217  map["offset"] = QString::number( mOffset );
1218  map["offset_along_line"] = QString::number( mOffsetAlongLine );
1219  map["offset_along_line_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetAlongLineUnit );
1220  map["offset_along_line_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetAlongLineMapUnitScale );
1221  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1222  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1223  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
1224  map["interval_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mIntervalMapUnitScale );
1225  if ( mPlacement == Vertex )
1226  map["placement"] = "vertex";
1227  else if ( mPlacement == LastVertex )
1228  map["placement"] = "lastvertex";
1229  else if ( mPlacement == FirstVertex )
1230  map["placement"] = "firstvertex";
1231  else if ( mPlacement == CentralPoint )
1232  map["placement"] = "centralpoint";
1233  else
1234  map["placement"] = "interval";
1235 
1237  return map;
1238 }
1239 
1241 {
1242  return mMarker;
1243 }
1244 
1246 {
1247  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1248  {
1249  delete symbol;
1250  return false;
1251  }
1252 
1253  delete mMarker;
1254  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1255  mColor = mMarker->color();
1256  return true;
1257 }
1258 
1260 {
1262  x->setSubSymbol( mMarker->clone() );
1263  x->setOffset( mOffset );
1264  x->setPlacement( mPlacement );
1265  x->setOffsetUnit( mOffsetUnit );
1273  copyPaintEffect( x );
1274  return x;
1275 }
1276 
1278 {
1279  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1280  {
1281  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1282  if ( !props.value( "uom", "" ).isEmpty() )
1283  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1284  element.appendChild( symbolizerElem );
1285 
1286  // <Geometry>
1287  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1288 
1289  QString gap;
1290  switch ( mPlacement )
1291  {
1292  case FirstVertex:
1293  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1294  break;
1295  case LastVertex:
1296  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1297  break;
1298  case CentralPoint:
1299  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1300  break;
1301  case Vertex:
1302  // no way to get line/polygon's vertices, use a VendorOption
1303  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1304  break;
1305  default:
1306  gap = QString::number( mInterval );
1307  break;
1308  }
1309 
1310  if ( !mRotateMarker )
1311  {
1312  // markers in LineSymbolizer must be drawn following the line orientation,
1313  // use a VendorOption when no marker rotation
1314  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1315  }
1316 
1317  // <Stroke>
1318  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1319  symbolizerElem.appendChild( strokeElem );
1320 
1321  // <GraphicStroke>
1322  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1323  strokeElem.appendChild( graphicStrokeElem );
1324 
1325  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1326  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1327  if ( !markerLayer )
1328  {
1329  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
1330  }
1331  else
1332  {
1333  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1334  }
1335 
1336  if ( !gap.isEmpty() )
1337  {
1338  QDomElement gapElem = doc.createElement( "se:Gap" );
1339  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1340  graphicStrokeElem.appendChild( gapElem );
1341  }
1342 
1343  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1344  {
1345  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1346  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1347  symbolizerElem.appendChild( perpOffsetElem );
1348  }
1349  }
1350 }
1351 
1353 {
1354  QgsDebugMsg( "Entered." );
1355 
1356  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1357  if ( strokeElem.isNull() )
1358  return NULL;
1359 
1360  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1361  if ( graphicStrokeElem.isNull() )
1362  return NULL;
1363 
1364  // retrieve vendor options
1365  bool rotateMarker = true;
1367 
1368  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1369  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1370  {
1371  if ( it.key() == "placement" )
1372  {
1373  if ( it.value() == "points" ) placement = Vertex;
1374  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1375  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1376  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1377  }
1378  else if ( it.value() == "rotateMarker" )
1379  {
1380  rotateMarker = it.value() == "0";
1381  }
1382  }
1383 
1384  QgsMarkerSymbolV2 *marker = 0;
1385 
1387  if ( l )
1388  {
1389  QgsSymbolLayerV2List layers;
1390  layers.append( l );
1391  marker = new QgsMarkerSymbolV2( layers );
1392  }
1393 
1394  if ( !marker )
1395  return NULL;
1396 
1397  double interval = 0.0;
1398  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1399  if ( !gapElem.isNull() )
1400  {
1401  bool ok;
1402  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1403  if ( ok )
1404  interval = d;
1405  }
1406 
1407  double offset = 0.0;
1408  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1409  if ( !perpOffsetElem.isNull() )
1410  {
1411  bool ok;
1412  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1413  if ( ok )
1414  offset = d;
1415  }
1416 
1417  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1418  x->setPlacement( placement );
1419  x->setInterval( interval );
1420  x->setSubSymbol( marker );
1421  x->setOffset( offset );
1422  return x;
1423 }
1424 
1426 {
1427  mMarker->setSize( width );
1428 }
1429 
1431 {
1432  return mMarker->size();
1433 }
1434 
1436 {
1438  mIntervalUnit = unit;
1439  mOffsetUnit = unit;
1440  mOffsetAlongLineUnit = unit;
1441 }
1442 
1444 {
1446  if ( mIntervalUnit != unit || mOffsetUnit != unit || mOffsetAlongLineUnit != unit )
1447  {
1448  return QgsSymbolV2::Mixed;
1449  }
1450  return unit;
1451 }
1452 
1454 {
1456  mIntervalMapUnitScale = scale;
1457  mOffsetMapUnitScale = scale;
1459 }
1460 
1462 {
1466  {
1467  return mOffsetMapUnitScale;
1468  }
1469  return QgsMapUnitScale();
1470 }
1471 
1473 {
1475  if ( mMarker )
1476  attr.unite( mMarker->usedAttributes() );
1477  return attr;
1478 }
1479 
1481 {
1482  return ( mMarker->size() / 2.0 ) + mOffset;
1483 }
1484 
1485 
1486 
static double _averageAngle(const QPointF &prevPt, const QPointF &pt, const QPointF &nextPt)
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
void setIntervalUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
#define DEFAULT_SIMPLELINE_PENSTYLE
#define DEFAULT_MARKERLINE_ROTATE
static const QString EXPR_JOINSTYLE
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setStyle(Qt::PenStyle style)
float threshold() const
Gets the simplification threshold of the vector layer managed.
int renderHints() const
Definition: qgssymbolv2.h:238
QVector< qreal > dxfCustomDashPattern(QgsSymbolV2::OutputUnit &unit) const override
bool contains(const Key &key) const
virtual double width() const
void setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
double markerAngle(const QPolygonF &points, bool isRing, int vertex)
qreal alphaF() const
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context) override
void setRenderHint(RenderHint hint, bool on)
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_MARKERLINE_INTERVAL
QgsStringMap properties() const override
SymbolType type() const
Definition: qgssymbolv2.h:86
RenderHints renderHints() const
QColor selectionColor() const
QSet< QString > usedAttributes() const
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
QString nodeValue() const
virtual void setWidth(double width) override
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setCustomDashPatternUnit(QgsSymbolV2::OutputUnit unit)
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QgsMapUnitScale mCustomDashPatternMapUnitScale
double size() const
double rendererScale() const
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context) override
static const QString EXPR_WIDTH
static const QString EXPR_CUSTOMDASH
void drawPolyline(const QPointF *points, int pointCount)
static QgsStringMap getVendorOptionList(QDomElement &element)
QGis::UnitType mapUnits() const
Definition: qgsdxfexport.h:54
const_iterator constEnd() const
void startRender(QgsSymbolV2RenderContext &context) override
const T & at(int i) const
T & last()
static QVector< qreal > decodeRealVector(const QString &s)
void renderPolylineInterval(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QgsSymbolV2::OutputUnit outputUnit() const override
QVector< qreal > customDashVector() const
bool setSubSymbol(QgsSymbolV2 *symbol) override
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
void setPenJoinStyle(Qt::PenJoinStyle style)
void save()
void setJoinStyle(Qt::PenJoinStyle style)
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
static QColor decodeColor(QString str)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
static const bool selectionIsOpaque
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
T & first()
static const QString EXPR_OFFSET_ALONG_LINE
QgsMapUnitScale mWidthMapUnitScale
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
QString layerType() const override
double toDouble(bool *ok) const
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMapUnitScale mOffsetMapUnitScale
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:350
static const QString EXPR_OFFSET
Qt::PenStyle penStyle() const
QgsSymbolV2::OutputUnit mOffsetUnit
void setWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mOffsetAlongLineMapUnitScale
int size() const
double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const override
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the marker placement.
static QString encodeColor(QColor color)
void setInterval(double interval)
QgsMapUnitScale mapUnitScale() const override
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:231
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
QPointF diffForInterval(double interval)
void setCapStyle(Qt::PenCapStyle style)
void setColor(const QColor &color)
QgsSymbolV2::OutputUnit mIntervalUnit
QColor color() const
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsSymbolLayerV2 * clone() const override
QgsSymbolLayerV2 * clone() const override
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
static const QString EXPR_PLACEMENT
double offsetAlongLine() const
Returns the offset along the line for the marker placement.
QString number(int n, int base)
int count(const T &value) const
qreal x() const
qreal y() const
void append(const T &value)
void setDashPattern(const QVector< qreal > &pattern)
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.
void addPolygon(const QPolygonF &polygon)
void setOffset(double offset)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void setMapUnitScale(const QgsMapUnitScale &scale) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:243
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol's angle.
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)
void setPen(const QColor &color)
QgsSymbolV2::OutputUnit mWidthUnit
void setAttribute(const QString &name, const QString &value)
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
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)
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
#define M_PI
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
double angle() const
void setAngle(double angle)
#define DEFAULT_SIMPLELINE_CAPSTYLE
virtual QgsSymbolV2 * clone() const override
#define DEFAULT_SIMPLELINE_JOINSTYLE
void setWidthF(qreal width)
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:113
QString layerType() const override
void setSize(double size)
double rasterScaleFactor() const
void stopRender(QgsSymbolV2RenderContext &context) override
virtual QColor color() const
void setOffsetAlongLineMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for calculating the offset in map units along line for markers...
iterator end()
void setOffsetAlongLineUnit(QgsSymbolV2::OutputUnit unit)
Sets the unit used for calculating the offset along line for markers.
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void setColor(const QColor &color)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
QgsSymbolV2 * subSymbol() override
void setPenCapStyle(Qt::PenCapStyle style)
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
void setCustomDashVector(const QVector< qreal > &vector)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
iterator begin()
static const QString EXPR_CAPSTYLE
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
double dxfOffset(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const override
QDomText createTextNode(const QString &value)
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)
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_COLOR
static QString encodeRealVector(const QVector< qreal > &v)
QgsSymbolV2::OutputUnit outputUnit() const override
QgsSymbolV2::OutputUnit mCustomDashPatternUnit
virtual QString layerType() const =0
QColor dxfColor(const QgsSymbolV2RenderContext &context) const override
double symbologyScaleDenominator() const
Definition: qgsdxfexport.h:51
bool isNull() const
void restore()
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
const T & at(int i) const
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)
const_iterator constBegin() const
Contains information about the context of a rendering operation.
QgsMapUnitScale mapUnitScale() const override
QgsSymbolV2::OutputUnit mOffsetAlongLineUnit
QDomNode firstChild() const
QPainter * painter()
void stopRender(QgsRenderContext &context)
QgsSimpleLineSymbolLayerV2(QColor color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
void setMapUnitScale(const QgsMapUnitScale &scale) override
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
char * toString(const T &value)
QSet< T > & unite(const QSet< T > &other)
virtual QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=0) const
Evaluates the matching data defined property and returns the calculated value.
Qt::PenStyle dxfPenStyle() const override
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QGis::GeometryType geometryType)
calculate geometry shifted by a specified distance
bool isEmpty() const
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
double offset() const
void stopRender(QgsSymbolV2RenderContext &context) override
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:221
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QDomElement firstChildElement(const QString &tagName) const
int count(const T &value) const
QgsMapUnitScale mapUnitScale() const override
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:68
QDomComment createComment(const QString &value)
qreal widthF() const
void setColor(const QColor &color) override
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:249
void push_back(const T &value)
void setRenderHints(int hints)
Definition: qgssymbolv2.h:162
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
MyLine(QPointF p1, QPointF p2)
void setAlphaF(qreal alpha)
bool selected() const
Definition: qgssymbolv2.h:235
typedef const_iterator
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsSymbolLayerV2 * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
const_iterator constEnd() const
QDomElement createElement(const QString &tagName)
const_iterator constBegin() 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)
void startRender(QgsSymbolV2RenderContext &context) override
QgsMarkerLineSymbolLayerV2(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
int size() const
int compare(const QString &other) const
static const QString EXPR_LINE_STYLE
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
static const QString EXPR_INTERVAL
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:160
void renderPolylineCentral(const QPolygonF &points, QgsSymbolV2RenderContext &context)
virtual double width() const override
QgsSymbolV2::OutputUnit widthUnit() const
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
Qt::PenJoinStyle penJoinStyle() const
void renderPolylineVertex(const QPolygonF &points, QgsSymbolV2RenderContext &context, Placement placement=Vertex)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Qt::PenCapStyle penCapStyle() const
const T value(const Key &key) const
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
QgsStringMap properties() const override