QGIS API Documentation  2.14.11-Essen
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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 "qgscurvev2.h"
18 #include "qgscurvepolygonv2.h"
19 #include "qgsdxfexport.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgslogger.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsgeometrysimplifier.h"
26 #include "qgsunittypes.h"
27 
28 #include <QPainter>
29 #include <QDomDocument>
30 #include <QDomElement>
31 
32 #include <cmath>
33 
34 QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2( const QColor& color, double width, Qt::PenStyle penStyle )
35  : mPenStyle( penStyle )
36  , mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE )
37  , mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE )
38  , mUseCustomDashPattern( false )
39  , mCustomDashPatternUnit( QgsSymbolV2::MM )
40  , mDrawInsidePolygon( false )
41 {
42  mColor = color;
43  mWidth = width;
44  mCustomDashVector << 5 << 2;
45 }
46 
48 {
50  mWidthUnit = unit;
51  mOffsetUnit = unit;
53 }
54 
56 {
58  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
59  {
60  return QgsSymbolV2::Mixed;
61  }
62  return unit;
63 }
64 
66 {
68  mWidthMapUnitScale = scale;
69  mOffsetMapUnitScale = scale;
71 }
72 
74 {
78  {
79  return mWidthMapUnitScale;
80  }
81  return QgsMapUnitScale();
82 }
83 
85 {
89 
90  if ( props.contains( "line_color" ) )
91  {
92  color = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
93  }
94  else if ( props.contains( "outline_color" ) )
95  {
96  color = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
97  }
98  else if ( props.contains( "color" ) )
99  {
100  //pre 2.5 projects used "color"
101  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
102  }
103  if ( props.contains( "line_width" ) )
104  {
105  width = props["line_width"].toDouble();
106  }
107  else if ( props.contains( "outline_width" ) )
108  {
109  width = props["outline_width"].toDouble();
110  }
111  else if ( props.contains( "width" ) )
112  {
113  //pre 2.5 projects used "width"
114  width = props["width"].toDouble();
115  }
116  if ( props.contains( "line_style" ) )
117  {
118  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] );
119  }
120  else if ( props.contains( "outline_style" ) )
121  {
122  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] );
123  }
124  else if ( props.contains( "penstyle" ) )
125  {
126  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["penstyle"] );
127  }
128 
129  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
130  if ( props.contains( "line_width_unit" ) )
131  {
132  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
133  }
134  else if ( props.contains( "outline_width_unit" ) )
135  {
136  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
137  }
138  else if ( props.contains( "width_unit" ) )
139  {
140  //pre 2.5 projects used "width_unit"
141  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["width_unit"] ) );
142  }
143  if ( props.contains( "width_map_unit_scale" ) )
144  l->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["width_map_unit_scale"] ) );
145  if ( props.contains( "offset" ) )
146  l->setOffset( props["offset"].toDouble() );
147  if ( props.contains( "offset_unit" ) )
148  l->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
149  if ( props.contains( "offset_map_unit_scale" ) )
150  l->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
151  if ( props.contains( "joinstyle" ) )
153  if ( props.contains( "capstyle" ) )
154  l->setPenCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( props["capstyle"] ) );
155 
156  if ( props.contains( "use_custom_dash" ) )
157  {
158  l->setUseCustomDashPattern( props["use_custom_dash"].toInt() );
159  }
160  if ( props.contains( "customdash" ) )
161  {
163  }
164  if ( props.contains( "customdash_unit" ) )
165  {
166  l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
167  }
168  if ( props.contains( "customdash_map_unit_scale" ) )
169  {
170  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["customdash_map_unit_scale"] ) );
171  }
172 
173  if ( props.contains( "draw_inside_polygon" ) )
174  {
175  l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
176  }
177 
178  l->restoreDataDefinedProperties( props );
179 
180  return l;
181 }
182 
183 
185 {
186  return "SimpleLine";
187 }
188 
190 {
191  QColor penColor = mColor;
192  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
193  mPen.setColor( penColor );
195  mPen.setWidthF( scaledWidth );
196  if ( mUseCustomDashPattern && !qgsDoubleNear( scaledWidth, 0 ) )
197  {
198  mPen.setStyle( Qt::CustomDashLine );
199 
200  //scale pattern vector
201  double dashWidthDiv = scaledWidth;
202  //fix dash pattern width in Qt 4.8
203  QStringList versionSplit = QString( qVersion() ).split( '.' );
204  if ( versionSplit.size() > 1
205  && versionSplit.at( 1 ).toInt() >= 8
206  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
207  {
208  dashWidthDiv = 1.0;
209  }
210  QVector<qreal> scaledVector;
212  for ( ; it != mCustomDashVector.constEnd(); ++it )
213  {
214  //the dash is specified in terms of pen widths, therefore the division
216  }
217  mPen.setDashPattern( scaledVector );
218  }
219  else
220  {
222  }
225 
226  mSelPen = mPen;
227  QColor selColor = context.renderContext().selectionColor();
228  if ( ! selectionIsOpaque )
229  selColor.setAlphaF( context.alpha() );
230  mSelPen.setColor( selColor );
231 
232  //prepare expressions for data defined properties
233  prepareExpressions( context );
234 }
235 
237 {
238  Q_UNUSED( context );
239 }
240 
242 {
243  QPainter* p = context.renderContext().painter();
244  if ( !p )
245  {
246  return;
247  }
248 
249  if ( mDrawInsidePolygon )
250  {
251  //only drawing the line on the interior of the polygon, so set clip path for painter
252  p->save();
253  QPainterPath clipPath;
254  clipPath.addPolygon( points );
255 
256  if ( rings )
257  {
258  //add polygon rings
260  for ( ; it != rings->constEnd(); ++it )
261  {
262  QPolygonF ring = *it;
263  clipPath.addPolygon( ring );
264  }
265  }
266 
267  //use intersect mode, as a clip path may already exist (eg, for composer maps)
268  p->setClipPath( clipPath, Qt::IntersectClip );
269  }
270 
271  renderPolyline( points, context );
272  if ( rings )
273  {
274  mOffset = -mOffset; // invert the offset for rings!
275  Q_FOREACH ( const QPolygonF& ring, *rings )
276  renderPolyline( ring, context );
277  mOffset = -mOffset;
278  }
279 
280  if ( mDrawInsidePolygon )
281  {
282  //restore painter to reset clip path
283  p->restore();
284  }
285 
286 }
287 
289 {
290  QPainter* p = context.renderContext().painter();
291  if ( !p )
292  {
293  return;
294  }
295 
296  //size scaling by field
298  {
299  applySizeScale( context, mPen, mSelPen );
300  }
301 
302  double offset = mOffset;
303  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
304 
305  p->setPen( context.selected() ? mSelPen : mPen );
306  p->setBrush( Qt::NoBrush );
307 
308  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
309  if ( points.size() <= 2 &&
312  ( p->renderHints() & QPainter::Antialiasing ) )
313  {
314  p->setRenderHint( QPainter::Antialiasing, false );
315 #if 0
316  p->drawPolyline( points );
317 #else
318  QPainterPath path;
319  path.addPolygon( points );
320  p->drawPath( path );
321 #endif
322  p->setRenderHint( QPainter::Antialiasing, true );
323  return;
324  }
325 
326  if ( qgsDoubleNear( offset, 0 ) )
327  {
328 #if 0
329  p->drawPolyline( points );
330 #else
331  QPainterPath path;
332  path.addPolygon( points );
333  p->drawPath( path );
334 #endif
335  }
336  else
337  {
339  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );
340  for ( int part = 0; part < mline.count(); ++part )
341  {
342 #if 0
343  p->drawPolyline( mline );
344 #else
345  QPainterPath path;
346  path.addPolygon( mline[ part ] );
347  p->drawPath( path );
348 #endif
349  }
350  }
351 }
352 
354 {
355  QgsStringMap map;
356  map["line_color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
357  map["line_width"] = QString::number( mWidth );
358  map["line_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
359  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
360  map["line_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mPenStyle );
363  map["offset"] = QString::number( mOffset );
365  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
366  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
370  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
372  return map;
373 }
374 
376 {
378  l->setWidthUnit( mWidthUnit );
384  l->setOffset( mOffset );
391  copyPaintEffect( l );
392  return l;
393 }
394 
395 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
396 {
397  if ( mPenStyle == Qt::NoPen )
398  return;
399 
400  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
401  if ( !props.value( "uom", "" ).isEmpty() )
402  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
403  element.appendChild( symbolizerElem );
404 
405  // <Geometry>
406  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
407 
408  // <Stroke>
409  QDomElement strokeElem = doc.createElement( "se:Stroke" );
410  symbolizerElem.appendChild( strokeElem );
411 
412  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
415  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, width,
416  &mPenJoinStyle, &mPenCapStyle, &customDashVector );
417 
418  // <se:PerpendicularOffset>
419  if ( !qgsDoubleNear( mOffset, 0.0 ) )
420  {
421  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
423  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
424  symbolizerElem.appendChild( perpOffsetElem );
425  }
426 }
427 
428 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
429 {
430  if ( mUseCustomDashPattern )
431  {
432  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
435  }
436  else
437  {
438  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
440  }
441 }
442 
444 {
445  QgsDebugMsg( "Entered." );
446 
447  QDomElement strokeElem = element.firstChildElement( "Stroke" );
448  if ( strokeElem.isNull() )
449  return nullptr;
450 
451  Qt::PenStyle penStyle;
452  QColor color;
453  double width;
454  Qt::PenJoinStyle penJoinStyle;
455  Qt::PenCapStyle penCapStyle;
457 
458  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
459  color, width,
460  &penJoinStyle, &penCapStyle,
461  &customDashVector ) )
462  return nullptr;
463 
464  double offset = 0.0;
465  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
466  if ( !perpOffsetElem.isNull() )
467  {
468  bool ok;
469  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
470  if ( ok )
471  offset = d;
472  }
473 
474  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
475  l->setOffset( offset );
476  l->setPenJoinStyle( penJoinStyle );
477  l->setPenCapStyle( penCapStyle );
478  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
479  l->setCustomDashVector( customDashVector );
480  return l;
481 }
482 
483 void QgsSimpleLineSymbolLayerV2::applySizeScale( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen )
484 {
486  pen.setWidthF( scaledWidth );
487  selPen.setWidthF( scaledWidth );
488 }
489 
490 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
491 {
492  if ( !hasDataDefinedProperties() )
493  return; // shortcut
494 
495  //data defined properties
496  bool hasStrokeWidthExpression = false;
498  {
499  context.setOriginalValueVariable( mWidth );
500  double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(),
503  pen.setWidthF( scaledWidth );
504  selPen.setWidthF( scaledWidth );
505  hasStrokeWidthExpression = true;
506  }
507 
508  //color
509  bool ok;
511  {
514  if ( ok )
515  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
516  }
517 
518  //offset
520  {
523  }
524 
525  //dash dot vector
527  {
529  double dashWidthDiv = mPen.widthF();
530 
531  if ( hasStrokeWidthExpression )
532  {
533  dashWidthDiv = pen.widthF();
534  scaledWidth = pen.widthF();
535  }
536 
537  //fix dash pattern width in Qt 4.8
538  QStringList versionSplit = QString( qVersion() ).split( '.' );
539  if ( versionSplit.size() > 1
540  && versionSplit.at( 1 ).toInt() >= 8
541  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
542  {
543  dashWidthDiv = 1.0;
544  }
545 
546  QVector<qreal> dashVector;
548  if ( ok )
549  {
550  QStringList::const_iterator dashIt = dashList.constBegin();
551  for ( ; dashIt != dashList.constEnd(); ++dashIt )
552  {
554  }
555  pen.setDashPattern( dashVector );
556  }
557  }
558 
559  //line style
561  {
564  if ( ok )
565  pen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( lineStyleString ) );
566  }
567 
568  //join style
570  {
573  if ( ok )
575  }
576 
577  //cap style
579  {
582  if ( ok )
583  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
584  }
585 }
586 
588 {
589  if ( mDrawInsidePolygon )
590  {
591  //set to clip line to the interior of polygon, so we expect no bleed
592  return 0;
593  }
594  else
595  {
596  return ( mWidth / 2.0 ) + mOffset;
597  }
598 }
599 
601 {
602  unit = mCustomDashPatternUnit;
604 }
605 
607 {
608  return mPenStyle;
609 }
610 
612 {
613  double width = mWidth;
614 
616  {
617  context.setOriginalValueVariable( mWidth );
619  }
620  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
621  {
623  }
624 
625  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
626 }
627 
629 {
631  {
632  bool ok;
635  if ( ok )
636  return ( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
637  }
638  return mColor;
639 }
640 
642 {
643  Q_UNUSED( e );
644  double offset = mOffset;
645 
647  {
650  }
651  return offset;
652 }
653 
655 
657 
658 class MyLine
659 {
660  public:
661  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
662  {
663  if ( p1 == p2 )
664  return; // invalid
665 
666  // tangent and direction
667  if ( qgsDoubleNear( p1.x(), p2.x() ) )
668  {
669  // vertical line - tangent undefined
670  mVertical = true;
671  mIncreasing = ( p2.y() > p1.y() );
672  }
673  else
674  {
675  mVertical = false;
676  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
677  mIncreasing = ( p2.x() > p1.x() );
678  }
679 
680  // length
681  double x = ( p2.x() - p1.x() );
682  double y = ( p2.y() - p1.y() );
683  mLength = sqrt( x * x + y * y );
684  }
685 
686  // return angle in radians
687  double angle()
688  {
689  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
690 
691  if ( !mIncreasing )
692  a += M_PI;
693  return a;
694  }
695 
696  // return difference for x,y when going along the line with specified interval
697  QPointF diffForInterval( double interval )
698  {
699  if ( mVertical )
700  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
701 
702  double alpha = atan( mT );
703  double dx = cos( alpha ) * interval;
704  double dy = sin( alpha ) * interval;
705  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
706  }
707 
708  double length() { return mLength; }
709 
710  protected:
711  bool mVertical;
712  bool mIncreasing;
713  double mT;
714  double mLength;
715 };
716 
718 
719 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
720 {
724  mMarker = nullptr;
726  mOffsetAlongLine = 0;
728 
730 }
731 
733 {
734  delete mMarker;
735 }
736 
738 {
739  bool rotate = DEFAULT_MARKERLINE_ROTATE;
740  double interval = DEFAULT_MARKERLINE_INTERVAL;
741 
742 
743  if ( props.contains( "interval" ) )
744  interval = props["interval"].toDouble();
745  if ( props.contains( "rotate" ) )
746  rotate = ( props["rotate"] == "1" );
747 
748  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
749  if ( props.contains( "offset" ) )
750  {
751  x->setOffset( props["offset"].toDouble() );
752  }
753  if ( props.contains( "offset_unit" ) )
754  {
755  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
756  }
757  if ( props.contains( "interval_unit" ) )
758  {
759  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
760  }
761  if ( props.contains( "offset_along_line" ) )
762  {
763  x->setOffsetAlongLine( props["offset_along_line"].toDouble() );
764  }
765  if ( props.contains( "offset_along_line_unit" ) )
766  {
767  x->setOffsetAlongLineUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_along_line_unit"] ) );
768  }
769  if ( props.contains(( "offset_along_line_map_unit_scale" ) ) )
770  {
771  x->setOffsetAlongLineMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_along_line_map_unit_scale"] ) );
772  }
773 
774  if ( props.contains( "offset_map_unit_scale" ) )
775  {
776  x->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
777  }
778  if ( props.contains( "interval_map_unit_scale" ) )
779  {
780  x->setIntervalMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["interval_map_unit_scale"] ) );
781  }
782 
783  if ( props.contains( "placement" ) )
784  {
785  if ( props["placement"] == "vertex" )
786  x->setPlacement( Vertex );
787  else if ( props["placement"] == "lastvertex" )
788  x->setPlacement( LastVertex );
789  else if ( props["placement"] == "firstvertex" )
791  else if ( props["placement"] == "centralpoint" )
793  else if ( props["placement"] == "curvepoint" )
794  x->setPlacement( CurvePoint );
795  else
796  x->setPlacement( Interval );
797  }
798 
799  x->restoreDataDefinedProperties( props );
800 
801  return x;
802 }
803 
805 {
806  return "MarkerLine";
807 }
808 
810 {
811  mMarker->setColor( color );
812  mColor = color;
813 }
814 
816 {
817  return mMarker ? mMarker->color() : mColor;
818 }
819 
821 {
822  mMarker->setAlpha( context.alpha() );
823 
824  // if being rotated, it gets initialized with every line segment
825  int hints = 0;
826  if ( mRotateMarker )
830  mMarker->setRenderHints( hints );
831 
832  mMarker->startRender( context.renderContext(), context.fields() );
833 
834  //prepare expressions for data defined properties
835  prepareExpressions( context );
836 }
837 
839 {
840  mMarker->stopRender( context.renderContext() );
841 }
842 
844 {
845  double offset = mOffset;
846 
848  {
851  }
852 
854 
855  bool ok;
857  {
859  if ( ok )
860  {
861  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
862  {
863  placement = Vertex;
864  }
865  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
866  {
867  placement = LastVertex;
868  }
869  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
870  {
871  placement = FirstVertex;
872  }
873  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
874  {
875  placement = CentralPoint;
876  }
877  else if ( placementString.compare( "curvepoint", Qt::CaseInsensitive ) == 0 )
878  {
879  placement = CurvePoint;
880  }
881  else
882  {
883  placement = Interval;
884  }
885  }
886  }
887 
888 
889  context.renderContext().painter()->save();
890 
891  if ( qgsDoubleNear( offset, 0.0 ) )
892  {
893  if ( placement == Interval )
894  renderPolylineInterval( points, context );
895  else if ( placement == CentralPoint )
896  renderPolylineCentral( points, context );
897  else
898  renderPolylineVertex( points, context, placement );
899  }
900  else
901  {
902  context.renderContext().setGeometry( nullptr ); //always use segmented geometry with offset
904 
905  for ( int part = 0; part < mline.count(); ++part )
906  {
907  const QPolygonF &points2 = mline[ part ];
908 
909  if ( placement == Interval )
910  renderPolylineInterval( points2, context );
911  else if ( placement == CentralPoint )
912  renderPolylineCentral( points2, context );
913  else
914  renderPolylineVertex( points2, context, placement );
915  }
916  }
917 
918  context.renderContext().painter()->restore();
919 }
920 
922 {
923  const QgsCurvePolygonV2* curvePolygon = dynamic_cast<const QgsCurvePolygonV2*>( context.renderContext().geometry() );
924 
925  if ( curvePolygon )
926  {
927  context.renderContext().setGeometry( curvePolygon->exteriorRing() );
928  }
929  renderPolyline( points, context );
930  if ( rings )
931  {
932  mOffset = -mOffset; // invert the offset for rings!
933  for ( int i = 0; i < rings->size(); ++i )
934  {
935  if ( curvePolygon )
936  {
937  context.renderContext().setGeometry( curvePolygon->interiorRing( i ) );
938  }
939  renderPolyline( rings->at( i ), context );
940  }
941  mOffset = -mOffset;
942  }
943 }
944 
946 {
947  if ( points.isEmpty() )
948  return;
949 
950  QPointF lastPt = points[0];
951  double lengthLeft = 0; // how much is left until next marker
952 
953  QgsRenderContext& rc = context.renderContext();
954  double interval = mInterval;
955 
957  {
960  }
961  if ( interval <= 0 )
962  {
963  interval = 0.1;
964  }
967  {
970  }
971 
972  double painterUnitInterval = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, interval, mIntervalUnit, mIntervalMapUnitScale );
973  lengthLeft = painterUnitInterval - QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mIntervalUnit, mIntervalMapUnitScale );
974 
975  for ( int i = 1; i < points.count(); ++i )
976  {
977  const QPointF& pt = points[i];
978 
979  if ( lastPt == pt ) // must not be equal!
980  continue;
981 
982  // for each line, find out dx and dy, and length
983  MyLine l( lastPt, pt );
984  QPointF diff = l.diffForInterval( painterUnitInterval );
985 
986  // if there's some length left from previous line
987  // use only the rest for the first point in new line segment
988  double c = 1 - lengthLeft / painterUnitInterval;
989 
990  lengthLeft += l.length();
991 
992  // rotate marker (if desired)
993  if ( mRotateMarker )
994  {
995  mMarker->setLineAngle( l.angle() * 180 / M_PI );
996  }
997 
998 
999  // while we're not at the end of line segment, draw!
1000  while ( lengthLeft > painterUnitInterval )
1001  {
1002  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1003  lastPt += c * diff;
1004  lengthLeft -= painterUnitInterval;
1005  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
1006  c = 1; // reset c (if wasn't 1 already)
1007  }
1008 
1009  lastPt = pt;
1010  }
1011 }
1012 
1013 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1014 {
1015  // calc average angle between the previous and next point
1016  double a1 = MyLine( prevPt, pt ).angle();
1017  double a2 = MyLine( pt, nextPt ).angle();
1018  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
1019 
1020  return atan2( unitY, unitX );
1021 }
1022 
1024 {
1025  if ( points.isEmpty() )
1026  return;
1027 
1028  QgsRenderContext& rc = context.renderContext();
1029 
1030  double origAngle = mMarker->angle();
1031  int i, maxCount;
1032  bool isRing = false;
1033 
1036  {
1039  }
1040  if ( !qgsDoubleNear( offsetAlongLine, 0.0 ) )
1041  {
1042  //scale offset along line
1044  }
1045 
1046  if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
1047  && context.renderContext().geometry()->hasCurvedSegments() && ( placement == Vertex || placement == CurvePoint ) )
1048  {
1050  const QgsMapToPixel& mtp = context.renderContext().mapToPixel();
1051 
1052  QgsVertexId vId;
1053  QgsPointV2 vPoint;
1054  double x, y, z;
1055  QPointF mapPoint;
1056  while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
1057  {
1058  if (( placement == Vertex && vId.type == QgsVertexId::SegmentVertex )
1059  || ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
1060  {
1061  //transform
1062  x = vPoint.x(), y = vPoint.y();
1063  z = vPoint.z();
1064  if ( ct )
1065  {
1066  ct->transformInPlace( x, y, z );
1067  }
1068  mapPoint.setX( x );
1069  mapPoint.setY( y );
1070  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1071  if ( mRotateMarker )
1072  {
1073  double angle = context.renderContext().geometry()->vertexAngle( vId );
1074  mMarker->setAngle( angle * 180 / M_PI );
1075  }
1076  mMarker->renderPoint( mapPoint, context.feature(), rc, -1, context.selected() );
1077  }
1078  }
1079  return;
1080  }
1081 
1082  if ( placement == FirstVertex )
1083  {
1084  i = 0;
1085  maxCount = 1;
1086  }
1087  else if ( placement == LastVertex )
1088  {
1089  i = points.count() - 1;
1090  maxCount = points.count();
1091  }
1092  else if ( placement == Vertex )
1093  {
1094  i = 0;
1095  maxCount = points.count();
1096  if ( points.first() == points.last() )
1097  isRing = true;
1098  }
1099  else
1100  {
1101  return;
1102  }
1103 
1104  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
1105  {
1106  double distance;
1107  distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
1108  renderOffsetVertexAlongLine( points, i, distance, context );
1109  // restore original rotation
1110  mMarker->setAngle( origAngle );
1111  return;
1112  }
1113 
1114  for ( ; i < maxCount; ++i )
1115  {
1116  if ( isRing && placement == Vertex && i == points.count() - 1 )
1117  {
1118  continue; // don't draw the last marker - it has been drawn already
1119  }
1120  // rotate marker (if desired)
1121  if ( mRotateMarker )
1122  {
1123  double angle = markerAngle( points, isRing, i );
1124  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1125  }
1126 
1127  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
1128  }
1129 
1130  // restore original rotation
1131  mMarker->setAngle( origAngle );
1132 }
1133 
1134 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
1135 {
1136  double angle = 0;
1137  const QPointF& pt = points[vertex];
1138 
1139  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1140  {
1141  int prevIndex = vertex - 1;
1142  int nextIndex = vertex + 1;
1143 
1144  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1145  {
1146  prevIndex = points.count() - 2;
1147  nextIndex = 1;
1148  }
1149 
1150  QPointF prevPoint, nextPoint;
1151  while ( prevIndex >= 0 )
1152  {
1153  prevPoint = points[ prevIndex ];
1154  if ( prevPoint != pt )
1155  {
1156  break;
1157  }
1158  --prevIndex;
1159  }
1160 
1161  while ( nextIndex < points.count() )
1162  {
1163  nextPoint = points[ nextIndex ];
1164  if ( nextPoint != pt )
1165  {
1166  break;
1167  }
1168  ++nextIndex;
1169  }
1170 
1171  if ( prevIndex >= 0 && nextIndex < points.count() )
1172  {
1173  angle = _averageAngle( prevPoint, pt, nextPoint );
1174  }
1175  }
1176  else //no ring and vertex is at start / at end
1177  {
1178  if ( vertex == 0 )
1179  {
1180  while ( vertex < points.size() - 1 )
1181  {
1182  const QPointF& nextPt = points[vertex+1];
1183  if ( pt != nextPt )
1184  {
1185  angle = MyLine( pt, nextPt ).angle();
1186  return angle;
1187  }
1188  ++vertex;
1189  }
1190  }
1191  else
1192  {
1193  // use last segment's angle
1194  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1195  {
1196  const QPointF& prevPt = points[vertex-1];
1197  if ( pt != prevPt )
1198  {
1199  angle = MyLine( prevPt, pt ).angle();
1200  return angle;
1201  }
1202  --vertex;
1203  }
1204  }
1205  }
1206  return angle;
1207 }
1208 
1209 void QgsMarkerLineSymbolLayerV2::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext& context )
1210 {
1211  if ( points.isEmpty() )
1212  return;
1213 
1214  QgsRenderContext& rc = context.renderContext();
1215  double origAngle = mMarker->angle();
1216  if ( qgsDoubleNear( distance, 0.0 ) )
1217  {
1218  // rotate marker (if desired)
1219  if ( mRotateMarker )
1220  {
1221  bool isRing = false;
1222  if ( points.first() == points.last() )
1223  isRing = true;
1224  double angle = markerAngle( points, isRing, vertex );
1225  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1226  }
1227  mMarker->renderPoint( points[vertex], context.feature(), rc, -1, context.selected() );
1228  return;
1229  }
1230 
1231  int pointIncrement = distance > 0 ? 1 : -1;
1232  QPointF previousPoint = points[vertex];
1233  int startPoint = distance > 0 ? qMin( vertex + 1, points.count() - 1 ) : qMax( vertex - 1, 0 );
1234  int endPoint = distance > 0 ? points.count() - 1 : 0;
1235  double distanceLeft = qAbs( distance );
1236 
1237  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1238  {
1239  const QPointF& pt = points[i];
1240 
1241  if ( previousPoint == pt ) // must not be equal!
1242  continue;
1243 
1244  // create line segment
1245  MyLine l( previousPoint, pt );
1246 
1247  if ( distanceLeft < l.length() )
1248  {
1249  //destination point is in current segment
1250  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1251  // rotate marker (if desired)
1252  if ( mRotateMarker )
1253  {
1254  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1255  }
1256  mMarker->renderPoint( markerPoint, context.feature(), rc, -1, context.selected() );
1257  return;
1258  }
1259 
1260  distanceLeft -= l.length();
1261  previousPoint = pt;
1262  }
1263 
1264  //didn't find point
1265  return;
1266 }
1267 
1269 {
1270  if ( !points.isEmpty() )
1271  {
1272  // calc length
1273  qreal length = 0;
1274  QPolygonF::const_iterator it = points.constBegin();
1275  QPointF last = *it;
1276  for ( ++it; it != points.constEnd(); ++it )
1277  {
1278  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1279  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1280  last = *it;
1281  }
1282 
1283  // find the segment where the central point lies
1284  it = points.constBegin();
1285  last = *it;
1286  qreal last_at = 0, next_at = 0;
1287  QPointF next;
1288  int segment = 0;
1289  for ( ++it; it != points.constEnd(); ++it )
1290  {
1291  next = *it;
1292  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1293  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1294  if ( next_at >= length / 2 )
1295  break; // we have reached the center
1296  last = *it;
1297  last_at = next_at;
1298  segment++;
1299  }
1300 
1301  // find out the central point on segment
1302  MyLine l( last, next ); // for line angle
1303  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1304  QPointF pt = last + ( next - last ) * k;
1305 
1306  // draw the marker
1307  double origAngle = mMarker->angle();
1308  if ( mRotateMarker )
1309  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
1310  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
1311  if ( mRotateMarker )
1312  mMarker->setAngle( origAngle );
1313  }
1314 }
1315 
1316 
1318 {
1319  QgsStringMap map;
1320  map["rotate"] = ( mRotateMarker ? "1" : "0" );
1321  map["interval"] = QString::number( mInterval );
1322  map["offset"] = QString::number( mOffset );
1323  map["offset_along_line"] = QString::number( mOffsetAlongLine );
1324  map["offset_along_line_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetAlongLineUnit );
1325  map["offset_along_line_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetAlongLineMapUnitScale );
1326  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1327  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1328  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
1329  map["interval_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mIntervalMapUnitScale );
1330  if ( mPlacement == Vertex )
1331  map["placement"] = "vertex";
1332  else if ( mPlacement == LastVertex )
1333  map["placement"] = "lastvertex";
1334  else if ( mPlacement == FirstVertex )
1335  map["placement"] = "firstvertex";
1336  else if ( mPlacement == CentralPoint )
1337  map["placement"] = "centralpoint";
1338  else if ( mPlacement == CurvePoint )
1339  map["placement"] = "curvepoint";
1340  else
1341  map["placement"] = "interval";
1342 
1344  return map;
1345 }
1346 
1348 {
1349  return mMarker;
1350 }
1351 
1353 {
1354  if ( !symbol || symbol->type() != QgsSymbolV2::Marker )
1355  {
1356  delete symbol;
1357  return false;
1358  }
1359 
1360  delete mMarker;
1361  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1362  mColor = mMarker->color();
1363  return true;
1364 }
1365 
1367 {
1369  x->setSubSymbol( mMarker->clone() );
1370  x->setOffset( mOffset );
1371  x->setPlacement( mPlacement );
1372  x->setOffsetUnit( mOffsetUnit );
1380  copyPaintEffect( x );
1381  return x;
1382 }
1383 
1385 {
1386  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1387  {
1388  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1389  if ( !props.value( "uom", "" ).isEmpty() )
1390  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1391  element.appendChild( symbolizerElem );
1392 
1393  // <Geometry>
1394  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1395 
1396  QString gap;
1397  switch ( mPlacement )
1398  {
1399  case FirstVertex:
1400  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1401  break;
1402  case LastVertex:
1403  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1404  break;
1405  case CentralPoint:
1406  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1407  break;
1408  case Vertex:
1409  // no way to get line/polygon's vertices, use a VendorOption
1410  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1411  break;
1412  default:
1413  double interval = QgsSymbolLayerV2Utils::rescaleUom( mInterval, mIntervalUnit, props );
1414  gap = qgsDoubleToString( interval );
1415  break;
1416  }
1417 
1418  if ( !mRotateMarker )
1419  {
1420  // markers in LineSymbolizer must be drawn following the line orientation,
1421  // use a VendorOption when no marker rotation
1422  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1423  }
1424 
1425  // <Stroke>
1426  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1427  symbolizerElem.appendChild( strokeElem );
1428 
1429  // <GraphicStroke>
1430  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1431  strokeElem.appendChild( graphicStrokeElem );
1432 
1433  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1434  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1435  if ( !markerLayer )
1436  {
1437  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
1438  }
1439  else
1440  {
1441  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1442  }
1443 
1444  if ( !gap.isEmpty() )
1445  {
1446  QDomElement gapElem = doc.createElement( "se:Gap" );
1448  graphicStrokeElem.appendChild( gapElem );
1449  }
1450 
1451  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1452  {
1453  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1454  double offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
1455  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
1456  symbolizerElem.appendChild( perpOffsetElem );
1457  }
1458  }
1459 }
1460 
1462 {
1463  QgsDebugMsg( "Entered." );
1464 
1465  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1466  if ( strokeElem.isNull() )
1467  return nullptr;
1468 
1469  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1470  if ( graphicStrokeElem.isNull() )
1471  return nullptr;
1472 
1473  // retrieve vendor options
1474  bool rotateMarker = true;
1476 
1477  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1478  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1479  {
1480  if ( it.key() == "placement" )
1481  {
1482  if ( it.value() == "points" ) placement = Vertex;
1483  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1484  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1485  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1486  }
1487  else if ( it.value() == "rotateMarker" )
1488  {
1489  rotateMarker = it.value() == "0";
1490  }
1491  }
1492 
1493  QgsMarkerSymbolV2 *marker = nullptr;
1494 
1496  if ( l )
1497  {
1498  QgsSymbolLayerV2List layers;
1499  layers.append( l );
1500  marker = new QgsMarkerSymbolV2( layers );
1501  }
1502 
1503  if ( !marker )
1504  return nullptr;
1505 
1506  double interval = 0.0;
1507  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1508  if ( !gapElem.isNull() )
1509  {
1510  bool ok;
1511  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1512  if ( ok )
1513  interval = d;
1514  }
1515 
1516  double offset = 0.0;
1517  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1518  if ( !perpOffsetElem.isNull() )
1519  {
1520  bool ok;
1521  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1522  if ( ok )
1523  offset = d;
1524  }
1525 
1526  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1527  x->setPlacement( placement );
1528  x->setInterval( interval );
1529  x->setSubSymbol( marker );
1530  x->setOffset( offset );
1531  return x;
1532 }
1533 
1535 {
1536  mMarker->setSize( width );
1537 }
1538 
1540 {
1541  if ( property == QgsSymbolLayerV2::EXPR_WIDTH && mMarker && dataDefined )
1542  {
1543  mMarker->setDataDefinedSize( *dataDefined );
1544  }
1545  QgsLineSymbolLayerV2::setDataDefinedProperty( property, dataDefined );
1546 }
1547 
1549 {
1550  return mMarker->size();
1551 }
1552 
1554 {
1556  mMarker->setOutputUnit( unit );
1557  mIntervalUnit = unit;
1558  mOffsetUnit = unit;
1559  mOffsetAlongLineUnit = unit;
1560 }
1561 
1563 {
1565  if ( mIntervalUnit != unit || mOffsetUnit != unit || mOffsetAlongLineUnit != unit )
1566  {
1567  return QgsSymbolV2::Mixed;
1568  }
1569  return unit;
1570 }
1571 
1573 {
1575  mIntervalMapUnitScale = scale;
1576  mOffsetMapUnitScale = scale;
1578 }
1579 
1581 {
1585  {
1586  return mOffsetMapUnitScale;
1587  }
1588  return QgsMapUnitScale();
1589 }
1590 
1592 {
1594  if ( mMarker )
1595  attr.unite( mMarker->usedAttributes() );
1596  return attr;
1597 }
1598 
1600 {
1601  return ( mMarker->size() / 2.0 ) + mOffset;
1602 }
1603 
1604 
1605 
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)
const QgsCurveV2 * exteriorRing() const
#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)
double dxfWidth(const QgsDxfExport &e, QgsSymbolV2RenderContext &context) const override
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
float threshold() const
Gets the simplification threshold of the vector layer managed.
int renderHints() const
Definition: qgssymbolv2.h:370
QVector< qreal > dxfCustomDashPattern(QgsSymbolV2::OutputUnit &unit) const override
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
A container class for data source field mapping or expression.
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
static double _averageAngle(QPointF prevPt, QPointF pt, QPointF nextPt)
void setRenderHint(RenderHint hint, bool on)
QDomNode appendChild(const QDomNode &newChild)
#define DEFAULT_MARKERLINE_INTERVAL
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
double x() const
Returns the point's x-coordinate.
Definition: qgspointv2.h:68
static double rescaleUom(double size, QgsSymbolV2::OutputUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found, otherwise returns the value un-modified.
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
SymbolType type() const
Definition: qgssymbolv2.h:104
RenderHints renderHints() const
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
QColor selectionColor() const
QSet< QString > usedAttributes() const
Return a list of attributes required to render this feature.
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 setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
void setCustomDashPatternUnit(QgsSymbolV2::OutputUnit unit)
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QString encodeColor(const QColor &color)
Placement
Defines how/where the marker should be placed on the line.
QgsMapUnitScale mCustomDashPatternMapUnitScale
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
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)
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
QGis::UnitType mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.h:93
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
set layer's subsymbol. takes ownership of the passed symbol
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
void setPenJoinStyle(Qt::PenJoinStyle style)
void save()
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
double dxfOffset(const QgsDxfExport &e, QgsSymbolV2RenderContext &context) const override
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=nullptr)
Create ogr feature style string for pen.
void setJoinStyle(Qt::PenJoinStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const 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)
const QgsCoordinateTransform * coordinateTransform() const
QString layerType() const override
Returns a string that represents this layer type.
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:285
static const QString EXPR_OFFSET
Qt::PenStyle penStyle() const
QgsSymbolV2::OutputUnit mOffsetUnit
void setWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mOffsetAlongLineMapUnitScale
Marker symbol.
Definition: qgssymbolv2.h:78
int size() const
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the marker placement.
void setInterval(double interval)
The interval between individual markers.
double y() const
Returns the point's y-coordinate.
Definition: qgspointv2.h:74
QgsMapUnitScale mapUnitScale() const override
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:363
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
void setCapStyle(Qt::PenCapStyle style)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setColor(const QColor &color)
QgsSymbolV2::OutputUnit mIntervalUnit
QgsSimpleLineSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QColor color() const
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
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)
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:375
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
QgsSymbolV2::OutputUnit outputUnit() const override
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol's angle.
Utility class for identifying a unique vertex within a geometry.
double z() const
Returns the point's z-coordinate.
Definition: qgspointv2.h:80
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'...
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
void setPen(const QColor &color)
virtual QColor color() const override
The fill color.
QgsSymbolV2::OutputUnit mWidthUnit
void setAttribute(const QString &name, const QString &value)
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
QVector< qreal > mCustomDashVector
Vector with an even number of entries for the.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
QString qgsDoubleToString(double a, int precision=17)
Definition: qgis.h:274
#define DEFAULT_SIMPLELINE_WIDTH
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
#define M_PI
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
Create a new MarkerLineSymbolLayerV2 from SLD.
double angle() const
Returns the marker angle for the whole symbol.
void setAngle(double angle)
Sets the angle for the whole symbol.
bool rotateMarker() const
Shall the marker be rotated.
#define DEFAULT_SIMPLELINE_CAPSTYLE
#define DEFAULT_SIMPLELINE_JOINSTYLE
void setWidthF(qreal width)
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:131
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
void setBrush(const QBrush &brush)
QString layerType() const override
Returns a string that represents this layer type.
void setSize(double size)
Sets the size for the whole symbol.
double rasterScaleFactor() const
double interval() const
The interval between individual markers.
void stopRender(QgsSymbolV2RenderContext &context) override
virtual QColor color() const
The fill color.
void setOffsetAlongLineMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for calculating the offset in map units along line for markers...
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
iterator end()
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
void setOffsetAlongLineUnit(QgsSymbolV2::OutputUnit unit)
Sets the unit used for calculating the offset along line for markers.
void setColor(const QColor &color)
virtual Q_DECL_DEPRECATED 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)
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
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())
Create a new MarkerLineSymbolLayerV2.
iterator begin()
static Qt::PenStyle decodePenStyle(const QString &str)
static const QString EXPR_CAPSTYLE
QgsMarkerLineSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) 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
void setDataDefinedProperty(const QString &property, QgsDataDefined *dataDefined) override
Sets a data defined property for the layer.
static QString encodeRealVector(const QVector< qreal > &v)
QgsSymbolV2::OutputUnit outputUnit() const override
QgsSymbolV2::OutputUnit mCustomDashPatternUnit
virtual QString layerType() const =0
Returns a string that represents this layer type.
const QgsCurveV2 * interiorRing(int i) const
double symbologyScaleDenominator() const
Retrieve reference scale for output.
Definition: qgsdxfexport.h:80
bool isNull() const
void restore()
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
const T & at(int i) const
#define DEFAULT_SIMPLELINE_COLOR
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)
void setMapUnitScale(const QgsMapUnitScale &scale) override
void drawPath(const QPainterPath &path)
QSet< T > & unite(const QSet< T > &other)
void setPlacement(Placement p)
The placement of the markers.
Struct for storing maximum and minimum scales for measurements in map units.
Qt::PenStyle dxfPenStyle() const override
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QGis::GeometryType geometryType)
calculate geometry shifted by a specified distance
QgsSimpleLineSymbolLayerV2(const QColor &color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
bool isEmpty() const
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
double offset() const
const QgsAbstractGeometryV2 * geometry() const
Returns pointer to the unsegmentized geometry.
void stopRender(QgsSymbolV2RenderContext &context) override
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:346
void setX(qreal x)
void setY(qreal y)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QDomElement firstChildElement(const QString &tagName) const
QColor dxfColor(QgsSymbolV2RenderContext &context) const override
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:82
qreal & rx()
qreal & ry()
QDomComment createComment(const QString &value)
Class for doing transforms between two map coordinate systems.
qreal widthF() const
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void setColor(const QColor &color) override
The fill color.
const QgsMapToPixel & mapToPixel() const
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:381
void push_back(const T &value)
void setRenderHints(int hints)
Definition: qgssymbolv2.h:205
void setAlphaF(qreal alpha)
Placement placement() const
The placement of the markers.
bool selected() const
Definition: qgssymbolv2.h:367
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
typedef const_iterator
Curve polygon geometry type.
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
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
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
QString toString() const
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void setOutputUnit(QgsSymbolV2::OutputUnit u)
static const QString EXPR_INTERVAL
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:203
void renderPolylineCentral(const QPolygonF &points, QgsSymbolV2RenderContext &context)
void setGeometry(const QgsAbstractGeometryV2 *geometry)
Sets pointer to original (unsegmentized) geometry.
virtual double width() const override
QgsSymbolV2::OutputUnit widthUnit() const
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.
virtual QgsMarkerSymbolV2 * clone() const override
Qt::PenCapStyle penCapStyle() const
const T value(const Key &key) const
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
virtual Q_DECL_DEPRECATED void setDataDefinedProperty(const QString &property, const QString &expressionString)
Sets a data defined expression for a property.
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.