QGIS API Documentation  2.12.0-Lyon
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 
27 #include <QPainter>
28 #include <QDomDocument>
29 #include <QDomElement>
30 
31 #include <cmath>
32 
33 QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2( const QColor& color, double width, Qt::PenStyle penStyle )
34  : mPenStyle( penStyle )
35  , mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE )
36  , mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE )
37  , mUseCustomDashPattern( false )
38  , mCustomDashPatternUnit( QgsSymbolV2::MM )
39  , mDrawInsidePolygon( false )
40 {
41  mColor = color;
42  mWidth = width;
43  mCustomDashVector << 5 << 2;
44 }
45 
47 {
49  mWidthUnit = unit;
50  mOffsetUnit = unit;
52 }
53 
55 {
57  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
58  {
59  return QgsSymbolV2::Mixed;
60  }
61  return unit;
62 }
63 
65 {
67  mWidthMapUnitScale = scale;
68  mOffsetMapUnitScale = scale;
70 }
71 
73 {
77  {
78  return mWidthMapUnitScale;
79  }
80  return QgsMapUnitScale();
81 }
82 
84 {
88 
89  if ( props.contains( "line_color" ) )
90  {
91  color = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
92  }
93  else if ( props.contains( "outline_color" ) )
94  {
95  color = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
96  }
97  else if ( props.contains( "color" ) )
98  {
99  //pre 2.5 projects used "color"
100  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
101  }
102  if ( props.contains( "line_width" ) )
103  {
104  width = props["line_width"].toDouble();
105  }
106  else if ( props.contains( "outline_width" ) )
107  {
108  width = props["outline_width"].toDouble();
109  }
110  else if ( props.contains( "width" ) )
111  {
112  //pre 2.5 projects used "width"
113  width = props["width"].toDouble();
114  }
115  if ( props.contains( "line_style" ) )
116  {
117  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] );
118  }
119  else if ( props.contains( "outline_style" ) )
120  {
121  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] );
122  }
123  else if ( props.contains( "penstyle" ) )
124  {
125  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["penstyle"] );
126  }
127 
128  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
129  if ( props.contains( "line_width_unit" ) )
130  {
131  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
132  }
133  else if ( props.contains( "outline_width_unit" ) )
134  {
135  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
136  }
137  else if ( props.contains( "width_unit" ) )
138  {
139  //pre 2.5 projects used "width_unit"
140  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["width_unit"] ) );
141  }
142  if ( props.contains( "width_map_unit_scale" ) )
143  l->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["width_map_unit_scale"] ) );
144  if ( props.contains( "offset" ) )
145  l->setOffset( props["offset"].toDouble() );
146  if ( props.contains( "offset_unit" ) )
147  l->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
148  if ( props.contains( "offset_map_unit_scale" ) )
149  l->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
150  if ( props.contains( "joinstyle" ) )
152  if ( props.contains( "capstyle" ) )
153  l->setPenCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( props["capstyle"] ) );
154 
155  if ( props.contains( "use_custom_dash" ) )
156  {
157  l->setUseCustomDashPattern( props["use_custom_dash"].toInt() );
158  }
159  if ( props.contains( "customdash" ) )
160  {
162  }
163  if ( props.contains( "customdash_unit" ) )
164  {
165  l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
166  }
167  if ( props.contains( "customdash_map_unit_scale" ) )
168  {
169  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["customdash_map_unit_scale"] ) );
170  }
171 
172  if ( props.contains( "draw_inside_polygon" ) )
173  {
174  l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
175  }
176 
177  l->restoreDataDefinedProperties( props );
178 
179  return l;
180 }
181 
182 
184 {
185  return "SimpleLine";
186 }
187 
189 {
190  QColor penColor = mColor;
191  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
192  mPen.setColor( penColor );
194  mPen.setWidthF( scaledWidth );
195  if ( mUseCustomDashPattern && scaledWidth != 0 )
196  {
197  mPen.setStyle( Qt::CustomDashLine );
198 
199  //scale pattern vector
200  double dashWidthDiv = scaledWidth;
201  //fix dash pattern width in Qt 4.8
202  QStringList versionSplit = QString( qVersion() ).split( "." );
203  if ( versionSplit.size() > 1
204  && versionSplit.at( 1 ).toInt() >= 8
205  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
206  {
207  dashWidthDiv = 1.0;
208  }
209  QVector<qreal> scaledVector;
211  for ( ; it != mCustomDashVector.constEnd(); ++it )
212  {
213  //the dash is specified in terms of pen widths, therefore the division
215  }
216  mPen.setDashPattern( scaledVector );
217  }
218  else
219  {
221  }
224 
225  mSelPen = mPen;
226  QColor selColor = context.renderContext().selectionColor();
227  if ( ! selectionIsOpaque )
228  selColor.setAlphaF( context.alpha() );
229  mSelPen.setColor( selColor );
230 
231  //prepare expressions for data defined properties
232  prepareExpressions( context );
233 }
234 
236 {
237  Q_UNUSED( context );
238 }
239 
241 {
242  QPainter* p = context.renderContext().painter();
243  if ( !p )
244  {
245  return;
246  }
247 
248  if ( mDrawInsidePolygon )
249  {
250  //only drawing the line on the interior of the polygon, so set clip path for painter
251  p->save();
252  QPainterPath clipPath;
253  clipPath.addPolygon( points );
254 
255  if ( rings != NULL )
256  {
257  //add polygon rings
259  for ( ; it != rings->constEnd(); ++it )
260  {
261  QPolygonF ring = *it;
262  clipPath.addPolygon( ring );
263  }
264  }
265 
266  //use intersect mode, as a clip path may already exist (eg, for composer maps)
267  p->setClipPath( clipPath, Qt::IntersectClip );
268  }
269 
270  renderPolyline( points, context );
271  if ( rings )
272  {
273  mOffset = -mOffset; // invert the offset for rings!
274  Q_FOREACH ( const QPolygonF& ring, *rings )
275  renderPolyline( ring, context );
276  mOffset = -mOffset;
277  }
278 
279  if ( mDrawInsidePolygon )
280  {
281  //restore painter to reset clip path
282  p->restore();
283  }
284 
285 }
286 
288 {
289  QPainter* p = context.renderContext().painter();
290  if ( !p )
291  {
292  return;
293  }
294 
295  //size scaling by field
297  {
298  applySizeScale( context, mPen, mSelPen );
299  }
300 
301  double offset = mOffset;
302  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
303 
304  p->setPen( context.selected() ? mSelPen : mPen );
305 
306  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
307  if ( points.size() <= 2 &&
310  ( p->renderHints() & QPainter::Antialiasing ) )
311  {
312  p->setRenderHint( QPainter::Antialiasing, false );
313  p->drawPolyline( points );
314  p->setRenderHint( QPainter::Antialiasing, true );
315  return;
316  }
317 
318  if ( qgsDoubleNear( offset, 0 ) )
319  {
320  p->drawPolyline( points );
321  }
322  else
323  {
325  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );
326  for ( int part = 0; part < mline.count(); ++part )
327  p->drawPolyline( mline[ part ] );
328  }
329 }
330 
332 {
333  QgsStringMap map;
334  map["line_color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
335  map["line_width"] = QString::number( mWidth );
336  map["line_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
337  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
338  map["line_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mPenStyle );
341  map["offset"] = QString::number( mOffset );
343  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
344  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
348  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
350  return map;
351 }
352 
354 {
356  l->setWidthUnit( mWidthUnit );
362  l->setOffset( mOffset );
369  copyPaintEffect( l );
370  return l;
371 }
372 
373 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
374 {
375  if ( mPenStyle == Qt::NoPen )
376  return;
377 
378  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
379  if ( !props.value( "uom", "" ).isEmpty() )
380  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
381  element.appendChild( symbolizerElem );
382 
383  // <Geometry>
384  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
385 
386  // <Stroke>
387  QDomElement strokeElem = doc.createElement( "se:Stroke" );
388  symbolizerElem.appendChild( strokeElem );
389 
390  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
391  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
393 
394  // <se:PerpendicularOffset>
395  if ( mOffset != 0 )
396  {
397  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
398  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
399  symbolizerElem.appendChild( perpOffsetElem );
400  }
401 }
402 
403 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
404 {
405  if ( mUseCustomDashPattern )
406  {
407  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
410  }
411  else
412  {
413  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
415  }
416 }
417 
419 {
420  QgsDebugMsg( "Entered." );
421 
422  QDomElement strokeElem = element.firstChildElement( "Stroke" );
423  if ( strokeElem.isNull() )
424  return NULL;
425 
426  Qt::PenStyle penStyle;
427  QColor color;
428  double width;
429  Qt::PenJoinStyle penJoinStyle;
430  Qt::PenCapStyle penCapStyle;
432 
433  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
434  color, width,
435  &penJoinStyle, &penCapStyle,
436  &customDashVector ) )
437  return NULL;
438 
439  double offset = 0.0;
440  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
441  if ( !perpOffsetElem.isNull() )
442  {
443  bool ok;
444  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
445  if ( ok )
446  offset = d;
447  }
448 
449  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
450  l->setOffset( offset );
451  l->setPenJoinStyle( penJoinStyle );
452  l->setPenCapStyle( penCapStyle );
453  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
454  l->setCustomDashVector( customDashVector );
455  return l;
456 }
457 
458 void QgsSimpleLineSymbolLayerV2::applySizeScale( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen )
459 {
461  pen.setWidthF( scaledWidth );
462  selPen.setWidthF( scaledWidth );
463 }
464 
465 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
466 {
467  if ( !hasDataDefinedProperties() )
468  return; // shortcut
469 
470  //data defined properties
471  bool hasStrokeWidthExpression = false;
473  {
474  context.setOriginalValueVariable( mWidth );
475  double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(),
478  pen.setWidthF( scaledWidth );
479  selPen.setWidthF( scaledWidth );
480  hasStrokeWidthExpression = true;
481  }
482 
483  //color
484  bool ok;
486  {
489  if ( ok )
490  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
491  }
492 
493  //offset
495  {
498  }
499 
500  //dash dot vector
502  {
504  double dashWidthDiv = mPen.widthF();
505 
506  if ( hasStrokeWidthExpression )
507  {
508  dashWidthDiv = pen.widthF();
509  scaledWidth = pen.widthF();
510  }
511 
512  //fix dash pattern width in Qt 4.8
513  QStringList versionSplit = QString( qVersion() ).split( "." );
514  if ( versionSplit.size() > 1
515  && versionSplit.at( 1 ).toInt() >= 8
516  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
517  {
518  dashWidthDiv = 1.0;
519  }
520 
521  QVector<qreal> dashVector;
523  if ( ok )
524  {
525  QStringList::const_iterator dashIt = dashList.constBegin();
526  for ( ; dashIt != dashList.constEnd(); ++dashIt )
527  {
529  }
530  pen.setDashPattern( dashVector );
531  }
532  }
533 
534  //line style
536  {
539  if ( ok )
540  pen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( lineStyleString ) );
541  }
542 
543  //join style
545  {
548  if ( ok )
550  }
551 
552  //cap style
554  {
557  if ( ok )
558  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
559  }
560 }
561 
563 {
564  if ( mDrawInsidePolygon )
565  {
566  //set to clip line to the interior of polygon, so we expect no bleed
567  return 0;
568  }
569  else
570  {
571  return ( mWidth / 2.0 ) + mOffset;
572  }
573 }
574 
576 {
577  unit = mCustomDashPatternUnit;
579 }
580 
582 {
583  return mPenStyle;
584 }
585 
587 {
588  double width = mWidth;
589 
591  {
592  context.setOriginalValueVariable( mWidth );
594  }
595  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
596  {
598  }
599 
600  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
601 }
602 
604 {
606  {
607  bool ok;
610  if ( ok )
611  return ( QgsSymbolLayerV2Utils::decodeColor( colorString ) );
612  }
613  return mColor;
614 }
615 
617 {
618  Q_UNUSED( e );
619  double offset = mOffset;
620 
622  {
625  }
626  return offset;
627 }
628 
630 
631 
632 class MyLine
633 {
634  public:
635  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
636  {
637  if ( p1 == p2 )
638  return; // invalid
639 
640  // tangent and direction
641  if ( p1.x() == p2.x() )
642  {
643  // vertical line - tangent undefined
644  mVertical = true;
645  mIncreasing = ( p2.y() > p1.y() );
646  }
647  else
648  {
649  mVertical = false;
650  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
651  mIncreasing = ( p2.x() > p1.x() );
652  }
653 
654  // length
655  double x = ( p2.x() - p1.x() );
656  double y = ( p2.y() - p1.y() );
657  mLength = sqrt( x * x + y * y );
658  }
659 
660  // return angle in radians
661  double angle()
662  {
663  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
664 
665  if ( !mIncreasing )
666  a += M_PI;
667  return a;
668  }
669 
670  // return difference for x,y when going along the line with specified interval
671  QPointF diffForInterval( double interval )
672  {
673  if ( mVertical )
674  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
675 
676  double alpha = atan( mT );
677  double dx = cos( alpha ) * interval;
678  double dy = sin( alpha ) * interval;
679  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
680  }
681 
682  double length() { return mLength; }
683 
684  protected:
685  bool mVertical;
687  double mT;
688  double mLength;
689 };
690 
691 
692 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
693 {
697  mMarker = NULL;
699  mOffsetAlongLine = 0;
701 
703 }
704 
706 {
707  delete mMarker;
708 }
709 
711 {
712  bool rotate = DEFAULT_MARKERLINE_ROTATE;
714 
715 
716  if ( props.contains( "interval" ) )
717  interval = props["interval"].toDouble();
718  if ( props.contains( "rotate" ) )
719  rotate = ( props["rotate"] == "1" );
720 
721  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
722  if ( props.contains( "offset" ) )
723  {
724  x->setOffset( props["offset"].toDouble() );
725  }
726  if ( props.contains( "offset_unit" ) )
727  {
728  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
729  }
730  if ( props.contains( "interval_unit" ) )
731  {
732  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
733  }
734  if ( props.contains( "offset_along_line" ) )
735  {
736  x->setOffsetAlongLine( props["offset_along_line"].toDouble() );
737  }
738  if ( props.contains( "offset_along_line_unit" ) )
739  {
740  x->setOffsetAlongLineUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_along_line_unit"] ) );
741  }
742  if ( props.contains(( "offset_along_line_map_unit_scale" ) ) )
743  {
744  x->setOffsetAlongLineMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_along_line_map_unit_scale"] ) );
745  }
746 
747  if ( props.contains( "offset_map_unit_scale" ) )
748  {
749  x->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
750  }
751  if ( props.contains( "interval_map_unit_scale" ) )
752  {
753  x->setIntervalMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["interval_map_unit_scale"] ) );
754  }
755 
756  if ( props.contains( "placement" ) )
757  {
758  if ( props["placement"] == "vertex" )
759  x->setPlacement( Vertex );
760  else if ( props["placement"] == "lastvertex" )
761  x->setPlacement( LastVertex );
762  else if ( props["placement"] == "firstvertex" )
764  else if ( props["placement"] == "centralpoint" )
766  else if ( props["placement"] == "curvepoint" )
767  x->setPlacement( CurvePoint );
768  else
769  x->setPlacement( Interval );
770  }
771 
772  x->restoreDataDefinedProperties( props );
773 
774  return x;
775 }
776 
778 {
779  return "MarkerLine";
780 }
781 
783 {
784  mMarker->setColor( color );
785  mColor = color;
786 }
787 
789 {
790  mMarker->setAlpha( context.alpha() );
791 
792  // if being rotated, it gets initialized with every line segment
793  int hints = 0;
794  if ( mRotateMarker )
798  mMarker->setRenderHints( hints );
799 
800  mMarker->startRender( context.renderContext(), context.fields() );
801 
802  //prepare expressions for data defined properties
803  prepareExpressions( context );
804 }
805 
807 {
808  mMarker->stopRender( context.renderContext() );
809 }
810 
812 {
813  double offset = mOffset;
814 
816  {
819  }
820 
822 
823  bool ok;
825  {
827  if ( ok )
828  {
829  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
830  {
831  placement = Vertex;
832  }
833  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
834  {
835  placement = LastVertex;
836  }
837  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
838  {
839  placement = FirstVertex;
840  }
841  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
842  {
843  placement = CentralPoint;
844  }
845  else if ( placementString.compare( "curvepoint", Qt::CaseInsensitive ) == 0 )
846  {
847  placement = CurvePoint;
848  }
849  else
850  {
851  placement = Interval;
852  }
853  }
854  }
855 
856  if ( offset == 0 )
857  {
858  if ( placement == Interval )
859  renderPolylineInterval( points, context );
860  else if ( placement == CentralPoint )
861  renderPolylineCentral( points, context );
862  else
863  renderPolylineVertex( points, context, placement );
864  }
865  else
866  {
867  context.renderContext().setGeometry( 0 ); //always use segmented geometry with offset
869 
870  for ( int part = 0; part < mline.count(); ++part )
871  {
872  const QPolygonF &points2 = mline[ part ];
873 
874  if ( placement == Interval )
875  renderPolylineInterval( points2, context );
876  else if ( placement == CentralPoint )
877  renderPolylineCentral( points2, context );
878  else
879  renderPolylineVertex( points2, context, placement );
880  }
881  }
882 }
883 
885 {
886  const QgsCurvePolygonV2* curvePolygon = dynamic_cast<const QgsCurvePolygonV2*>( context.renderContext().geometry() );
887 
888  if ( curvePolygon )
889  {
890  context.renderContext().setGeometry( curvePolygon->exteriorRing() );
891  }
892  renderPolyline( points, context );
893  if ( rings )
894  {
895  mOffset = -mOffset; // invert the offset for rings!
896  for ( int i = 0; i < rings->size(); ++i )
897  {
898  if ( curvePolygon )
899  {
900  context.renderContext().setGeometry( curvePolygon->interiorRing( i ) );
901  }
902  renderPolyline( rings->at( i ), context );
903  }
904  mOffset = -mOffset;
905  }
906 }
907 
909 {
910  if ( points.isEmpty() )
911  return;
912 
913  QPointF lastPt = points[0];
914  double lengthLeft = 0; // how much is left until next marker
915  bool first = mOffsetAlongLine ? false : true; //only draw marker at first vertex when no offset along line is set
916 
917  QgsRenderContext& rc = context.renderContext();
918  double interval = mInterval;
919 
921  {
924  }
925  if ( interval <= 0 )
926  {
927  interval = 0.1;
928  }
931  {
934  }
935 
936  double painterUnitInterval = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, interval, mIntervalUnit, mIntervalMapUnitScale );
937  lengthLeft = painterUnitInterval - QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mIntervalUnit, mIntervalMapUnitScale );
938 
939  for ( int i = 1; i < points.count(); ++i )
940  {
941  const QPointF& pt = points[i];
942 
943  if ( lastPt == pt ) // must not be equal!
944  continue;
945 
946  // for each line, find out dx and dy, and length
947  MyLine l( lastPt, pt );
948  QPointF diff = l.diffForInterval( painterUnitInterval );
949 
950  // if there's some length left from previous line
951  // use only the rest for the first point in new line segment
952  double c = 1 - lengthLeft / painterUnitInterval;
953 
954  lengthLeft += l.length();
955 
956  // rotate marker (if desired)
957  if ( mRotateMarker )
958  {
959  mMarker->setLineAngle( l.angle() * 180 / M_PI );
960  }
961 
962  // draw first marker
963  if ( first )
964  {
965  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
966  first = false;
967  }
968 
969  // while we're not at the end of line segment, draw!
970  while ( lengthLeft > painterUnitInterval )
971  {
972  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
973  lastPt += c * diff;
974  lengthLeft -= painterUnitInterval;
975  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
976  c = 1; // reset c (if wasn't 1 already)
977  }
978 
979  lastPt = pt;
980  }
981 }
982 
983 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
984 {
985  // calc average angle between the previous and next point
986  double a1 = MyLine( prevPt, pt ).angle();
987  double a2 = MyLine( pt, nextPt ).angle();
988  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
989 
990  return atan2( unitY, unitX );
991 }
992 
994 {
995  if ( points.isEmpty() )
996  return;
997 
998  QgsRenderContext& rc = context.renderContext();
999 
1000  double origAngle = mMarker->angle();
1001  int i, maxCount;
1002  bool isRing = false;
1003 
1006  {
1009  }
1010  if ( offsetAlongLine != 0 )
1011  {
1012  //scale offset along line
1014  }
1015 
1016  if ( offsetAlongLine == 0 && context.renderContext().geometry()
1017  && context.renderContext().geometry()->hasCurvedSegments() && ( placement == Vertex || placement == CurvePoint ) )
1018  {
1020  const QgsMapToPixel& mtp = context.renderContext().mapToPixel();
1021 
1022  QgsVertexId vId;
1023  QgsPointV2 vPoint;
1024  double x, y, z;
1025  QPointF mapPoint;
1026  while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
1027  {
1028  if (( placement == Vertex && vId.type == QgsVertexId::SegmentVertex )
1029  || ( placement == CurvePoint && vId.type == QgsVertexId::CurveVertex ) )
1030  {
1031  //transform
1032  x = vPoint.x(), y = vPoint.y(); z = vPoint.z();
1033  if ( ct )
1034  {
1035  ct->transformInPlace( x, y, z );
1036  }
1037  mapPoint.setX( x ); mapPoint.setY( y );
1038  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1039  if ( mRotateMarker )
1040  {
1041  double angle = context.renderContext().geometry()->vertexAngle( vId );
1042  mMarker->setAngle( angle * 180 / M_PI );
1043  }
1044  mMarker->renderPoint( mapPoint, context.feature(), rc, -1, context.selected() );
1045  }
1046  }
1047  return;
1048  }
1049 
1050  if ( placement == FirstVertex )
1051  {
1052  i = 0;
1053  maxCount = 1;
1054  }
1055  else if ( placement == LastVertex )
1056  {
1057  i = points.count() - 1;
1058  maxCount = points.count();
1059  }
1060  else if ( placement == Vertex )
1061  {
1062  i = 0;
1063  maxCount = points.count();
1064  if ( points.first() == points.last() )
1065  isRing = true;
1066  }
1067  else
1068  {
1069  return;
1070  }
1071 
1072  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
1073  {
1074  double distance;
1075  distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
1076  renderOffsetVertexAlongLine( points, i, distance, context );
1077  // restore original rotation
1078  mMarker->setAngle( origAngle );
1079  return;
1080  }
1081 
1082  for ( ; i < maxCount; ++i )
1083  {
1084  if ( isRing && placement == Vertex && i == points.count() - 1 )
1085  {
1086  continue; // don't draw the last marker - it has been drawn already
1087  }
1088  // rotate marker (if desired)
1089  if ( mRotateMarker )
1090  {
1091  double angle = markerAngle( points, isRing, i );
1092  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1093  }
1094 
1095  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
1096  }
1097 
1098  // restore original rotation
1099  mMarker->setAngle( origAngle );
1100 }
1101 
1102 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
1103 {
1104  double angle = 0;
1105  const QPointF& pt = points[vertex];
1106 
1107  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1108  {
1109  int prevIndex = vertex - 1;
1110  int nextIndex = vertex + 1;
1111 
1112  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1113  {
1114  prevIndex = points.count() - 2;
1115  nextIndex = 1;
1116  }
1117 
1118  QPointF prevPoint, nextPoint;
1119  while ( prevIndex >= 0 )
1120  {
1121  prevPoint = points[ prevIndex ];
1122  if ( prevPoint != pt )
1123  {
1124  break;
1125  }
1126  --prevIndex;
1127  }
1128 
1129  while ( nextIndex < points.count() )
1130  {
1131  nextPoint = points[ nextIndex ];
1132  if ( nextPoint != pt )
1133  {
1134  break;
1135  }
1136  ++nextIndex;
1137  }
1138 
1139  if ( prevIndex >= 0 && nextIndex < points.count() )
1140  {
1141  angle = _averageAngle( prevPoint, pt, nextPoint );
1142  }
1143  }
1144  else //no ring and vertex is at start / at end
1145  {
1146  if ( vertex == 0 )
1147  {
1148  while ( vertex < points.size() - 1 )
1149  {
1150  const QPointF& nextPt = points[vertex+1];
1151  if ( pt != nextPt )
1152  {
1153  angle = MyLine( pt, nextPt ).angle();
1154  return angle;
1155  }
1156  ++vertex;
1157  }
1158  }
1159  else
1160  {
1161  // use last segment's angle
1162  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1163  {
1164  const QPointF& prevPt = points[vertex-1];
1165  if ( pt != prevPt )
1166  {
1167  angle = MyLine( prevPt, pt ).angle();
1168  return angle;
1169  }
1170  --vertex;
1171  }
1172  }
1173  }
1174  return angle;
1175 }
1176 
1177 void QgsMarkerLineSymbolLayerV2::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext& context )
1178 {
1179  if ( points.isEmpty() )
1180  return;
1181 
1182  QgsRenderContext& rc = context.renderContext();
1183  double origAngle = mMarker->angle();
1184  if ( distance == 0 )
1185  {
1186  // rotate marker (if desired)
1187  if ( mRotateMarker )
1188  {
1189  bool isRing = false;
1190  if ( points.first() == points.last() )
1191  isRing = true;
1192  double angle = markerAngle( points, isRing, vertex );
1193  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1194  }
1195  mMarker->renderPoint( points[vertex], context.feature(), rc, -1, context.selected() );
1196  return;
1197  }
1198 
1199  int pointIncrement = distance > 0 ? 1 : -1;
1200  QPointF previousPoint = points[vertex];
1201  int startPoint = distance > 0 ? qMin( vertex + 1, points.count() - 1 ) : qMax( vertex - 1, 0 );
1202  int endPoint = distance > 0 ? points.count() - 1 : 0;
1203  double distanceLeft = qAbs( distance );
1204 
1205  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1206  {
1207  const QPointF& pt = points[i];
1208 
1209  if ( previousPoint == pt ) // must not be equal!
1210  continue;
1211 
1212  // create line segment
1213  MyLine l( previousPoint, pt );
1214 
1215  if ( distanceLeft < l.length() )
1216  {
1217  //destination point is in current segment
1218  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1219  // rotate marker (if desired)
1220  if ( mRotateMarker )
1221  {
1222  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1223  }
1224  mMarker->renderPoint( markerPoint, context.feature(), rc, -1, context.selected() );
1225  return;
1226  }
1227 
1228  distanceLeft -= l.length();
1229  previousPoint = pt;
1230  }
1231 
1232  //didn't find point
1233  return;
1234 }
1235 
1237 {
1238  if ( points.size() > 0 )
1239  {
1240  // calc length
1241  qreal length = 0;
1242  QPolygonF::const_iterator it = points.constBegin();
1243  QPointF last = *it;
1244  for ( ++it; it != points.constEnd(); ++it )
1245  {
1246  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1247  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1248  last = *it;
1249  }
1250 
1251  // find the segment where the central point lies
1252  it = points.constBegin();
1253  last = *it;
1254  qreal last_at = 0, next_at = 0;
1255  QPointF next;
1256  int segment = 0;
1257  for ( ++it; it != points.constEnd(); ++it )
1258  {
1259  next = *it;
1260  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1261  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1262  if ( next_at >= length / 2 )
1263  break; // we have reached the center
1264  last = *it;
1265  last_at = next_at;
1266  segment++;
1267  }
1268 
1269  // find out the central point on segment
1270  MyLine l( last, next ); // for line angle
1271  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1272  QPointF pt = last + ( next - last ) * k;
1273 
1274  // draw the marker
1275  double origAngle = mMarker->angle();
1276  if ( mRotateMarker )
1277  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
1278  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
1279  if ( mRotateMarker )
1280  mMarker->setAngle( origAngle );
1281  }
1282 }
1283 
1284 
1286 {
1287  QgsStringMap map;
1288  map["rotate"] = ( mRotateMarker ? "1" : "0" );
1289  map["interval"] = QString::number( mInterval );
1290  map["offset"] = QString::number( mOffset );
1291  map["offset_along_line"] = QString::number( mOffsetAlongLine );
1292  map["offset_along_line_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetAlongLineUnit );
1293  map["offset_along_line_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetAlongLineMapUnitScale );
1294  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1295  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1296  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
1297  map["interval_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mIntervalMapUnitScale );
1298  if ( mPlacement == Vertex )
1299  map["placement"] = "vertex";
1300  else if ( mPlacement == LastVertex )
1301  map["placement"] = "lastvertex";
1302  else if ( mPlacement == FirstVertex )
1303  map["placement"] = "firstvertex";
1304  else if ( mPlacement == CentralPoint )
1305  map["placement"] = "centralpoint";
1306  else if ( mPlacement == CurvePoint )
1307  map["placement"] = "curvepoint";
1308  else
1309  map["placement"] = "interval";
1310 
1312  return map;
1313 }
1314 
1316 {
1317  return mMarker;
1318 }
1319 
1321 {
1322  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1323  {
1324  delete symbol;
1325  return false;
1326  }
1327 
1328  delete mMarker;
1329  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1330  mColor = mMarker->color();
1331  return true;
1332 }
1333 
1335 {
1337  x->setSubSymbol( mMarker->clone() );
1338  x->setOffset( mOffset );
1339  x->setPlacement( mPlacement );
1340  x->setOffsetUnit( mOffsetUnit );
1348  copyPaintEffect( x );
1349  return x;
1350 }
1351 
1353 {
1354  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1355  {
1356  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1357  if ( !props.value( "uom", "" ).isEmpty() )
1358  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1359  element.appendChild( symbolizerElem );
1360 
1361  // <Geometry>
1362  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1363 
1364  QString gap;
1365  switch ( mPlacement )
1366  {
1367  case FirstVertex:
1368  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1369  break;
1370  case LastVertex:
1371  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1372  break;
1373  case CentralPoint:
1374  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1375  break;
1376  case Vertex:
1377  // no way to get line/polygon's vertices, use a VendorOption
1378  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1379  break;
1380  default:
1381  gap = QString::number( mInterval );
1382  break;
1383  }
1384 
1385  if ( !mRotateMarker )
1386  {
1387  // markers in LineSymbolizer must be drawn following the line orientation,
1388  // use a VendorOption when no marker rotation
1389  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1390  }
1391 
1392  // <Stroke>
1393  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1394  symbolizerElem.appendChild( strokeElem );
1395 
1396  // <GraphicStroke>
1397  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1398  strokeElem.appendChild( graphicStrokeElem );
1399 
1400  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1401  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1402  if ( !markerLayer )
1403  {
1404  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
1405  }
1406  else
1407  {
1408  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1409  }
1410 
1411  if ( !gap.isEmpty() )
1412  {
1413  QDomElement gapElem = doc.createElement( "se:Gap" );
1414  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1415  graphicStrokeElem.appendChild( gapElem );
1416  }
1417 
1418  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1419  {
1420  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1421  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1422  symbolizerElem.appendChild( perpOffsetElem );
1423  }
1424  }
1425 }
1426 
1428 {
1429  QgsDebugMsg( "Entered." );
1430 
1431  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1432  if ( strokeElem.isNull() )
1433  return NULL;
1434 
1435  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1436  if ( graphicStrokeElem.isNull() )
1437  return NULL;
1438 
1439  // retrieve vendor options
1440  bool rotateMarker = true;
1442 
1443  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1444  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1445  {
1446  if ( it.key() == "placement" )
1447  {
1448  if ( it.value() == "points" ) placement = Vertex;
1449  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1450  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1451  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1452  }
1453  else if ( it.value() == "rotateMarker" )
1454  {
1455  rotateMarker = it.value() == "0";
1456  }
1457  }
1458 
1459  QgsMarkerSymbolV2 *marker = 0;
1460 
1462  if ( l )
1463  {
1464  QgsSymbolLayerV2List layers;
1465  layers.append( l );
1466  marker = new QgsMarkerSymbolV2( layers );
1467  }
1468 
1469  if ( !marker )
1470  return NULL;
1471 
1472  double interval = 0.0;
1473  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1474  if ( !gapElem.isNull() )
1475  {
1476  bool ok;
1477  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1478  if ( ok )
1479  interval = d;
1480  }
1481 
1482  double offset = 0.0;
1483  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1484  if ( !perpOffsetElem.isNull() )
1485  {
1486  bool ok;
1487  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1488  if ( ok )
1489  offset = d;
1490  }
1491 
1492  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1493  x->setPlacement( placement );
1494  x->setInterval( interval );
1495  x->setSubSymbol( marker );
1496  x->setOffset( offset );
1497  return x;
1498 }
1499 
1501 {
1502  mMarker->setSize( width );
1503 }
1504 
1506 {
1507  return mMarker->size();
1508 }
1509 
1511 {
1513  mIntervalUnit = unit;
1514  mOffsetUnit = unit;
1515  mOffsetAlongLineUnit = unit;
1516 }
1517 
1519 {
1521  if ( mIntervalUnit != unit || mOffsetUnit != unit || mOffsetAlongLineUnit != unit )
1522  {
1523  return QgsSymbolV2::Mixed;
1524  }
1525  return unit;
1526 }
1527 
1529 {
1531  mIntervalMapUnitScale = scale;
1532  mOffsetMapUnitScale = scale;
1534 }
1535 
1537 {
1541  {
1542  return mOffsetMapUnitScale;
1543  }
1544  return QgsMapUnitScale();
1545 }
1546 
1548 {
1550  if ( mMarker )
1551  attr.unite( mMarker->usedAttributes() );
1552  return attr;
1553 }
1554 
1556 {
1557  return ( mMarker->size() / 2.0 ) + mOffset;
1558 }
1559 
1560 
1561 
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
Qt::PenStyle style() const
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:55
float threshold() const
Gets the simplification threshold of the vector layer managed.
virtual double vertexAngle(const QgsVertexId &vertex) const =0
Returns approximate rotation angle for a vertex.
int renderHints() const
Definition: qgssymbolv2.h:278
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
double x() const
Definition: qgspointv2.h:42
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
SymbolType type() const
Definition: qgssymbolv2.h:95
RenderHints renderHints() const
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
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
static QString encodeColor(const QColor &color)
QgsMapUnitScale mCustomDashPatternMapUnitScale
double size() 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)
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
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()
QgsCurveV2 * exteriorRing() const
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
Qt::PenJoinStyle joinStyle() const
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
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
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:268
static const QString EXPR_OFFSET
Qt::PenStyle penStyle() const
QgsSymbolV2::OutputUnit mOffsetUnit
void setWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mOffsetAlongLineMapUnitScale
Marker symbol.
Definition: qgssymbolv2.h:70
int size() const
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the marker placement.
void setInterval(double interval)
double y() const
Definition: qgspointv2.h:43
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:271
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
QPointF diffForInterval(double interval)
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
QColor color() const
QgsSymbolLayerV2 * clone() const override
Mixed units in symbol layers.
Definition: qgssymbolv2.h:59
QgsSymbolLayerV2 * clone() const override
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
void transformInPlace(double &x, double &y) const
Transform device coordinates to map (world) coordinates.
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
The output shall be in millimeters.
Definition: qgssymbolv2.h:57
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:283
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.
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
double z() const
Definition: qgspointv2.h:44
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'...
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setPen(const QColor &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.
Definition: qgspointv2.h:29
#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)
double angle() const
void setAngle(double angle)
#define DEFAULT_SIMPLELINE_CAPSTYLE
virtual QgsSymbolV2 * clone() const override
#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:122
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
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...
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
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 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)
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 Qt::PenStyle decodePenStyle(const QString &str)
static const QString EXPR_CAPSTYLE
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
static QString encodeRealVector(const QVector< qreal > &v)
QgsSymbolV2::OutputUnit outputUnit() const override
QgsSymbolV2::OutputUnit mCustomDashPatternUnit
virtual QString layerType() const =0
double symbologyScaleDenominator() const
Definition: qgsdxfexport.h:51
bool isNull() const
void restore()
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
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
QSet< T > & unite(const QSet< T > &other)
virtual Q_DECL_DEPRECATED 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.
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
Qt::PenCapStyle capStyle() 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:254
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:70
qreal & rx()
qreal & ry()
QDomComment createComment(const QString &value)
Class for doing transforms between two map coordinate systems.
qreal widthF() const
void setColor(const QColor &color) override
const QgsMapToPixel & mapToPixel() const
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:289
void push_back(const T &value)
void setRenderHints(int hints)
Definition: qgssymbolv2.h:195
MyLine(QPointF p1, QPointF p2)
void setAlphaF(qreal alpha)
bool selected() const
Definition: qgssymbolv2.h:275
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=0, const Qt::PenCapStyle *penCapStyle=0, const QVector< qreal > *customDashPattern=0, double dashOffset=0.0)
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
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
QString toString() const
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:193
void renderPolylineCentral(const QPolygonF &points, QgsSymbolV2RenderContext &context)
void setGeometry(const QgsAbstractGeometryV2 *geometry)
Sets pointer to original (unsegmentized) geometry.
QgsCurveV2 * interiorRing(int i) const
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.
Qt::PenCapStyle penCapStyle() const
const T value(const Key &key) const
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
QgsStringMap properties() const override