QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgslinesymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinesymbollayerv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgslinesymbollayerv2.h"
17 #include "qgsdxfexport.h"
18 #include "qgssymbollayerv2utils.h"
19 #include "qgsexpression.h"
20 #include "qgsrendercontext.h"
21 #include "qgslogger.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsgeometrysimplifier.h"
24 
25 #include <QPainter>
26 #include <QDomDocument>
27 #include <QDomElement>
28 
29 #include <cmath>
30 
31 QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2( QColor color, double width, Qt::PenStyle penStyle )
32  : mPenStyle( penStyle ), mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE ), mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE ), mOffset( 0 ), mOffsetUnit( QgsSymbolV2::MM ),
33  mUseCustomDashPattern( false ), mCustomDashPatternUnit( QgsSymbolV2::MM ), mDrawInsidePolygon( false )
34 {
35  mColor = color;
36  mWidth = width;
37  mCustomDashVector << 5 << 2;
38 }
39 
41 {
43  mWidthUnit = unit;
44  mOffsetUnit = unit;
46 }
47 
49 {
51  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
52  {
53  return QgsSymbolV2::Mixed;
54  }
55  return unit;
56 }
57 
59 {
61  mWidthMapUnitScale = scale;
62  mOffsetMapUnitScale = scale;
64 }
65 
67 {
71  {
72  return mWidthMapUnitScale;
73  }
74  return QgsMapUnitScale();
75 }
76 
78 {
82 
83  if ( props.contains( "color" ) )
84  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
85  if ( props.contains( "width" ) )
86  width = props["width"].toDouble();
87  if ( props.contains( "penstyle" ) )
88  penStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["penstyle"] );
89 
90 
91  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
92  if ( props.contains( "width_unit" ) )
93  l->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["width_unit"] ) );
94  if ( props.contains( "offset" ) )
95  l->setOffset( props["offset"].toDouble() );
96  if ( props.contains( "offset_unit" ) )
97  l->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
98  if ( props.contains( "offset_map_unit_scale" ) )
99  l->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
100  if ( props.contains( "joinstyle" ) )
102  if ( props.contains( "capstyle" ) )
103  l->setPenCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( props["capstyle"] ) );
104 
105  if ( props.contains( "use_custom_dash" ) )
106  {
107  l->setUseCustomDashPattern( props["use_custom_dash"].toInt() );
108  }
109  if ( props.contains( "customdash" ) )
110  {
112  }
113  if ( props.contains( "customdash_unit" ) )
114  {
115  l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
116  }
117  if ( props.contains( "customdash_map_unit_scale" ) )
118  {
119  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["customdash_map_unit_scale"] ) );
120  }
121 
122  if ( props.contains( "draw_inside_polygon" ) )
123  {
124  l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
125  }
126 
127  //data defined properties
128  if ( props.contains( "color_expression" ) )
129  l->setDataDefinedProperty( "color", props["color_expression"] );
130  if ( props.contains( "width_expression" ) )
131  l->setDataDefinedProperty( "width", props["width_expression"] );
132  if ( props.contains( "offset_expression" ) )
133  l->setDataDefinedProperty( "offset", props["offset_expression"] );
134  if ( props.contains( "customdash_expression" ) )
135  l->setDataDefinedProperty( "customdash", props["customdash_expression"] );
136  if ( props.contains( "joinstyle_expression" ) )
137  l->setDataDefinedProperty( "joinstyle", props["joinstyle_expression"] );
138  if ( props.contains( "capstyle_expression" ) )
139  l->setDataDefinedProperty( "capstyle", props["capstyle_expression"] );
140 
141  return l;
142 }
143 
144 
146 {
147  return "SimpleLine";
148 }
149 
151 {
152  QColor penColor = mColor;
153  penColor.setAlphaF( mColor.alphaF() * context.alpha() );
154  mPen.setColor( penColor );
156  mPen.setWidthF( scaledWidth );
157  if ( mUseCustomDashPattern && scaledWidth != 0 )
158  {
159  mPen.setStyle( Qt::CustomDashLine );
160 
161  //scale pattern vector
162  double dashWidthDiv = scaledWidth;
163  //fix dash pattern width in Qt 4.8
164  QStringList versionSplit = QString( qVersion() ).split( "." );
165  if ( versionSplit.size() > 1
166  && versionSplit.at( 1 ).toInt() >= 8
167  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
168  {
169  dashWidthDiv = 1.0;
170  }
171  QVector<qreal> scaledVector;
172  QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
173  for ( ; it != mCustomDashVector.constEnd(); ++it )
174  {
175  //the dash is specified in terms of pen widths, therefore the division
177  }
178  mPen.setDashPattern( scaledVector );
179  }
180  else
181  {
182  mPen.setStyle( mPenStyle );
183  }
184  mPen.setJoinStyle( mPenJoinStyle );
185  mPen.setCapStyle( mPenCapStyle );
186 
187  mSelPen = mPen;
188  QColor selColor = context.renderContext().selectionColor();
189  if ( ! selectionIsOpaque )
190  selColor.setAlphaF( context.alpha() );
191  mSelPen.setColor( selColor );
192 
193  //prepare expressions for data defined properties
194  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
195 }
196 
198 {
199  Q_UNUSED( context );
200 }
201 
202 void QgsSimpleLineSymbolLayerV2::renderPolygonOutline( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
203 {
204  QPainter* p = context.renderContext().painter();
205  if ( !p )
206  {
207  return;
208  }
209 
210  if ( mDrawInsidePolygon )
211  {
212  //only drawing the line on the interior of the polygon, so set clip path for painter
213  p->save();
214  QPainterPath clipPath;
215  clipPath.addPolygon( points );
216 
217  if ( rings != NULL )
218  {
219  //add polygon rings
220  QList<QPolygonF>::const_iterator it = rings->constBegin();
221  for ( ; it != rings->constEnd(); ++it )
222  {
223  QPolygonF ring = *it;
224  clipPath.addPolygon( ring );
225  }
226  }
227 
228  //use intersect mode, as a clip path may already exist (eg, for composer maps)
229  p->setClipPath( clipPath, Qt::IntersectClip );
230  }
231 
232  renderPolyline( points, context );
233  if ( rings )
234  {
235  foreach ( const QPolygonF& ring, *rings )
236  renderPolyline( ring, context );
237  }
238 
239  if ( mDrawInsidePolygon )
240  {
241  //restore painter to reset clip path
242  p->restore();
243  }
244 
245 }
246 
248 {
249  QPainter* p = context.renderContext().painter();
250  if ( !p )
251  {
252  return;
253  }
254 
255  double offset = 0.0;
256  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
257 
258  p->setPen( context.selected() ? mSelPen : mPen );
259 
260  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
261  if ( points.size() <= 2 && ( context.renderContext().vectorSimplifyMethod().simplifyHints() & QgsVectorSimplifyMethod::AntialiasingSimplification ) && QgsAbstractGeometrySimplifier::canbeGeneralizedByDeviceBoundingBox( points, context.renderContext().vectorSimplifyMethod().threshold() ) && ( p->renderHints() & QPainter::Antialiasing ) )
262  {
263  p->setRenderHint( QPainter::Antialiasing, false );
264  p->drawPolyline( points );
265  p->setRenderHint( QPainter::Antialiasing, true );
266  return;
267  }
268 
269  if ( offset == 0 )
270  {
271  p->drawPolyline( points );
272  }
273  else
274  {
276  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->geometry()->type() : QGis::Line );
277  for ( int part = 0; part < mline.count(); ++part )
278  p->drawPolyline( mline[ part ] );
279  }
280 }
281 
283 {
284  QgsStringMap map;
285  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
286  map["width"] = QString::number( mWidth );
288  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
292  map["offset"] = QString::number( mOffset );
294  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
295  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
299  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
301  return map;
302 }
303 
305 {
307  l->setWidthUnit( mWidthUnit );
313  l->setOffset( mOffset );
320  return l;
321 }
322 
323 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
324 {
325  if ( mPenStyle == Qt::NoPen )
326  return;
327 
328  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
329  if ( !props.value( "uom", "" ).isEmpty() )
330  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
331  element.appendChild( symbolizerElem );
332 
333  // <Geometry>
334  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
335 
336  // <Stroke>
337  QDomElement strokeElem = doc.createElement( "se:Stroke" );
338  symbolizerElem.appendChild( strokeElem );
339 
340  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
341  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
343 
344  // <se:PerpendicularOffset>
345  if ( mOffset != 0 )
346  {
347  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
348  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
349  symbolizerElem.appendChild( perpOffsetElem );
350  }
351 }
352 
353 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
354 {
355  if ( mUseCustomDashPattern )
356  {
357  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
358  mPen.color(), mPenJoinStyle,
360  }
361  else
362  {
363  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
365  }
366 }
367 
369 {
370  QgsDebugMsg( "Entered." );
371 
372  QDomElement strokeElem = element.firstChildElement( "Stroke" );
373  if ( strokeElem.isNull() )
374  return NULL;
375 
376  Qt::PenStyle penStyle;
377  QColor color;
378  double width;
379  Qt::PenJoinStyle penJoinStyle;
380  Qt::PenCapStyle penCapStyle;
381  QVector<qreal> customDashVector;
382 
383  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
384  color, width,
385  &penJoinStyle, &penCapStyle,
386  &customDashVector ) )
387  return NULL;
388 
389  double offset = 0.0;
390  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
391  if ( !perpOffsetElem.isNull() )
392  {
393  bool ok;
394  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
395  if ( ok )
396  offset = d;
397  }
398 
399  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
400  l->setOffset( offset );
401  l->setPenJoinStyle( penJoinStyle );
402  l->setPenCapStyle( penCapStyle );
403  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
404  l->setCustomDashVector( customDashVector );
405  return l;
406 }
407 
408 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
409 {
410  //data defined properties
411  double scaledWidth = 0;
412  QgsExpression* strokeWidthExpression = expression( "width" );
413  if ( strokeWidthExpression )
414  {
415  scaledWidth = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble()
417  pen.setWidthF( scaledWidth );
418  selPen.setWidthF( scaledWidth );
419  }
420  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
421  {
423  pen.setWidthF( scaledWidth );
424  selPen.setWidthF( scaledWidth );
425  }
426 
427  //color
428  QgsExpression* strokeColorExpression = expression( "color" );
429  if ( strokeColorExpression )
430  {
431  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
432  }
433 
434  //offset
435  offset = mOffset;
436  QgsExpression* lineOffsetExpression = expression( "offset" );
437  if ( lineOffsetExpression )
438  {
439  offset = lineOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
440  }
441 
442  //dash dot vector
443  QgsExpression* dashPatternExpression = expression( "customdash" );
444  if ( dashPatternExpression )
445  {
446 
448 
449  double dashWidthDiv = mPen.widthF();
450 
451  if ( strokeWidthExpression )
452  {
453  dashWidthDiv = pen.widthF();
454  scaledWidth = pen.widthF();
455  }
456 
457  //fix dash pattern width in Qt 4.8
458  QStringList versionSplit = QString( qVersion() ).split( "." );
459  if ( versionSplit.size() > 1
460  && versionSplit.at( 1 ).toInt() >= 8
461  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
462  {
463  dashWidthDiv = 1.0;
464  }
465 
466  QVector<qreal> dashVector;
467  QStringList dashList = dashPatternExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString().split( ";" );
468  QStringList::const_iterator dashIt = dashList.constBegin();
469  for ( ; dashIt != dashList.constEnd(); ++dashIt )
470  {
471  dashVector.push_back( dashIt->toDouble() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
472  }
473  pen.setDashPattern( dashVector );
474  }
475 
476  //join style
477  QgsExpression* joinStyleExpression = expression( "joinstyle" );
478  if ( joinStyleExpression )
479  {
480  QString joinStyleString = joinStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
481  pen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( joinStyleString ) );
482  }
483 
484  //cap style
485  QgsExpression* capStyleExpression = expression( "capstyle" );
486  if ( capStyleExpression )
487  {
488  QString capStyleString = capStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
489  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
490  }
491 }
492 
494 {
495  if ( mDrawInsidePolygon )
496  {
497  //set to clip line to the interior of polygon, so we expect no bleed
498  return 0;
499  }
500  else
501  {
502  return ( mWidth / 2.0 ) + mOffset;
503  }
504 }
505 
507 {
508  unit = mCustomDashPatternUnit;
509  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>() ;
510 }
511 
513 {
514  return mPenStyle;
515 }
516 
518 {
519  double width = mWidth;
520  QgsExpression* strokeWidthExpression = expression( "width" );
521  if ( strokeWidthExpression )
522  {
523  width = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
524  }
525  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
526  {
528  }
529 
530  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
531 }
532 
534 {
535  QgsExpression* strokeColorExpression = expression( "color" );
536  if ( strokeColorExpression )
537  {
538  return ( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
539  }
540  return mColor;
541 }
542 
544 
545 
546 class MyLine
547 {
548  public:
549  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
550  {
551  if ( p1 == p2 )
552  return; // invalid
553 
554  // tangent and direction
555  if ( p1.x() == p2.x() )
556  {
557  // vertical line - tangent undefined
558  mVertical = true;
559  mIncreasing = ( p2.y() > p1.y() );
560  }
561  else
562  {
563  mVertical = false;
564  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
565  mIncreasing = ( p2.x() > p1.x() );
566  }
567 
568  // length
569  double x = ( p2.x() - p1.x() );
570  double y = ( p2.y() - p1.y() );
571  mLength = sqrt( x * x + y * y );
572  }
573 
574  // return angle in radians
575  double angle()
576  {
577  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
578 
579  if ( !mIncreasing )
580  a += M_PI;
581  return a;
582  }
583 
584  // return difference for x,y when going along the line with specified interval
585  QPointF diffForInterval( double interval )
586  {
587  if ( mVertical )
588  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
589 
590  double alpha = atan( mT );
591  double dx = cos( alpha ) * interval;
592  double dy = sin( alpha ) * interval;
593  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
594  }
595 
596  double length() { return mLength; }
597 
598  protected:
599  bool mVertical;
601  double mT;
602  double mLength;
603 };
604 
605 
606 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
607 {
611  mMarker = NULL;
612  mOffset = 0;
615  mOffsetAlongLine = 0;
617 
619 }
620 
622 {
623  delete mMarker;
624 }
625 
627 {
628  bool rotate = DEFAULT_MARKERLINE_ROTATE;
630 
631 
632  if ( props.contains( "interval" ) )
633  interval = props["interval"].toDouble();
634  if ( props.contains( "rotate" ) )
635  rotate = ( props["rotate"] == "1" );
636 
637  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
638  if ( props.contains( "offset" ) )
639  {
640  x->setOffset( props["offset"].toDouble() );
641  }
642  if ( props.contains( "offset_unit" ) )
643  {
644  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
645  }
646  if ( props.contains( "interval_unit" ) )
647  {
648  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
649  }
650  if ( props.contains( "offset_along_line" ) )
651  {
652  x->setOffsetAlongLine( props["offset_along_line"].toDouble() );
653  }
654  if ( props.contains( "offset_along_line_unit" ) )
655  {
656  x->setOffsetAlongLineUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_along_line_unit"] ) );
657  }
658  if ( props.contains(( "offset_along_line_map_unit_scale" ) ) )
659  {
660  x->setOffsetAlongLineMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_along_line_map_unit_scale"] ) );
661  }
662 
663  if ( props.contains( "offset_map_unit_scale" ) )
664  {
665  x->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
666  }
667  if ( props.contains( "interval_map_unit_scale" ) )
668  {
669  x->setIntervalMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["interval_map_unit_scale"] ) );
670  }
671 
672  if ( props.contains( "placement" ) )
673  {
674  if ( props["placement"] == "vertex" )
675  x->setPlacement( Vertex );
676  else if ( props["placement"] == "lastvertex" )
677  x->setPlacement( LastVertex );
678  else if ( props["placement"] == "firstvertex" )
680  else if ( props["placement"] == "centralpoint" )
682  else
683  x->setPlacement( Interval );
684  }
685 
686  //data defined properties
687  if ( props.contains( "interval_expression" ) )
688  {
689  x->setDataDefinedProperty( "interval", props["interval_expression"] );
690  }
691  if ( props.contains( "offset_expression" ) )
692  {
693  x->setDataDefinedProperty( "offset", props["offset_expression"] );
694  }
695  if ( props.contains( "placement_expression" ) )
696  {
697  x->setDataDefinedProperty( "placement", props["placement_expression"] );
698  }
699  if ( props.contains( "offset_along_line_expression" ) )
700  {
701  x->setDataDefinedProperty( "offset_along_line", props["offset_along_line_expression"] );
702  }
703 
704  return x;
705 }
706 
708 {
709  return "MarkerLine";
710 }
711 
712 void QgsMarkerLineSymbolLayerV2::setColor( const QColor& color )
713 {
714  mMarker->setColor( color );
715  mColor = color;
716 }
717 
719 {
720  mMarker->setAlpha( context.alpha() );
721 
722  // if being rotated, it gets initialized with every line segment
723  int hints = 0;
724  if ( mRotateMarker )
728  mMarker->setRenderHints( hints );
729 
730  mMarker->startRender( context.renderContext(), context.fields() );
731 
732  //prepare expressions for data defined properties
733  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
734 }
735 
737 {
738  mMarker->stopRender( context.renderContext() );
739 }
740 
742 {
743  double offset = mOffset;
744  QgsExpression* offsetExpression = expression( "offset" );
745  if ( offsetExpression )
746  {
747  offset = offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
748  }
749 
751  QgsExpression* placementExpression = expression( "placement" );
752  if ( placementExpression )
753  {
754  QString placementString = placementExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
755  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
756  {
757  placement = Vertex;
758  }
759  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
760  {
761  placement = LastVertex;
762  }
763  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
764  {
765  placement = FirstVertex;
766  }
767  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
768  {
769  placement = CentralPoint;
770  }
771  else
772  {
773  placement = Interval;
774  }
775  }
776 
777  if ( offset == 0 )
778  {
779  if ( placement == Interval )
780  renderPolylineInterval( points, context );
781  else if ( placement == CentralPoint )
782  renderPolylineCentral( points, context );
783  else
784  renderPolylineVertex( points, context, placement );
785  }
786  else
787  {
788  QList<QPolygonF> mline = ::offsetLine( points, offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ), context.feature() ? context.feature()->geometry()->type() : QGis::Line );
789 
790  for ( int part = 0; part < mline.count(); ++part )
791  {
792  const QPolygonF &points2 = mline[ part ];
793 
794  if ( placement == Interval )
795  renderPolylineInterval( points2, context );
796  else if ( placement == CentralPoint )
797  renderPolylineCentral( points2, context );
798  else
799  renderPolylineVertex( points2, context, placement );
800  }
801  }
802 }
803 
805 {
806  if ( points.isEmpty() )
807  return;
808 
809  QPointF lastPt = points[0];
810  double lengthLeft = 0; // how much is left until next marker
811  bool first = mOffsetAlongLine ? false : true; //only draw marker at first vertex when no offset along line is set
812  double origAngle = mMarker->angle();
813 
814  QgsRenderContext& rc = context.renderContext();
815  double interval = mInterval;
816 
817  QgsExpression* intervalExpression = expression( "interval" );
818  if ( intervalExpression )
819  {
820  interval = intervalExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
821  }
822  if ( interval <= 0 )
823  {
824  interval = 0.1;
825  }
827  QgsExpression* offsetAlongLineExpression = expression( "offset_along_line" );
828  if ( offsetAlongLineExpression )
829  {
830  offsetAlongLine = offsetAlongLineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
831  }
832 
833  double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
834  lengthLeft = painterUnitInterval - offsetAlongLine * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
835 
836  for ( int i = 1; i < points.count(); ++i )
837  {
838  const QPointF& pt = points[i];
839 
840  if ( lastPt == pt ) // must not be equal!
841  continue;
842 
843  // for each line, find out dx and dy, and length
844  MyLine l( lastPt, pt );
845  QPointF diff = l.diffForInterval( painterUnitInterval );
846 
847  // if there's some length left from previous line
848  // use only the rest for the first point in new line segment
849  double c = 1 - lengthLeft / painterUnitInterval;
850 
851  lengthLeft += l.length();
852 
853  // rotate marker (if desired)
854  if ( mRotateMarker )
855  {
856  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
857  }
858 
859  // draw first marker
860  if ( first )
861  {
862  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
863  first = false;
864  }
865 
866  // while we're not at the end of line segment, draw!
867  while ( lengthLeft > painterUnitInterval )
868  {
869  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
870  lastPt += c * diff;
871  lengthLeft -= painterUnitInterval;
872  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
873  c = 1; // reset c (if wasn't 1 already)
874  }
875 
876  lastPt = pt;
877  }
878 
879  // restore original rotation
880  mMarker->setAngle( origAngle );
881 
882 }
883 
884 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
885 {
886  // calc average angle between the previous and next point
887  double a1 = MyLine( prevPt, pt ).angle();
888  double a2 = MyLine( pt, nextPt ).angle();
889  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
890 
891  return atan2( unitY, unitX );
892 }
893 
894 void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement )
895 {
896  if ( points.isEmpty() )
897  return;
898 
899  QgsRenderContext& rc = context.renderContext();
900 
901  double origAngle = mMarker->angle();
902  int i, maxCount;
903  bool isRing = false;
904 
906  QgsExpression* offsetAlongLineExpression = expression( "offset_along_line" );
907  if ( offsetAlongLineExpression )
908  {
909  offsetAlongLine = offsetAlongLineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
910  }
911  if ( offsetAlongLine != 0 )
912  {
913  //scale offset along line
915  }
916 
917  if ( placement == FirstVertex )
918  {
919  i = 0;
920  maxCount = 1;
921  }
922  else if ( placement == LastVertex )
923  {
924  i = points.count() - 1;
925  maxCount = points.count();
926  }
927  else
928  {
929  i = 0;
930  maxCount = points.count();
931  if ( points.first() == points.last() )
932  isRing = true;
933  }
934 
935  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
936  {
937  double distance;
938  distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
939  renderOffsetVertexAlongLine( points, i, distance, context );
940  // restore original rotation
941  mMarker->setAngle( origAngle );
942  return;
943  }
944 
945  for ( ; i < maxCount; ++i )
946  {
947  if ( isRing && placement == Vertex && i == points.count() - 1 )
948  {
949  continue; // don't draw the last marker - it has been drawn already
950  }
951  // rotate marker (if desired)
952  if ( mRotateMarker )
953  {
954  double angle = markerAngle( points, isRing, i );
955  mMarker->setAngle( origAngle + angle * 180 / M_PI );
956  }
957 
958  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
959  }
960 
961  // restore original rotation
962  mMarker->setAngle( origAngle );
963 }
964 
965 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
966 {
967  double angle = 0;
968  const QPointF& pt = points[vertex];
969 
970  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
971  {
972  int prevIndex = vertex - 1;
973  int nextIndex = vertex + 1;
974 
975  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
976  {
977  prevIndex = points.count() - 2;
978  nextIndex = 1;
979  }
980 
981  QPointF prevPoint, nextPoint;
982  while ( prevIndex >= 0 )
983  {
984  prevPoint = points[ prevIndex ];
985  if ( prevPoint != pt )
986  {
987  break;
988  }
989  --prevIndex;
990  }
991 
992  while ( nextIndex < points.count() )
993  {
994  nextPoint = points[ nextIndex ];
995  if ( nextPoint != pt )
996  {
997  break;
998  }
999  ++nextIndex;
1000  }
1001 
1002  if ( prevIndex >= 0 && nextIndex < points.count() )
1003  {
1004  angle = _averageAngle( prevPoint, pt, nextPoint );
1005  }
1006  }
1007  else //no ring and vertex is at start / at end
1008  {
1009  if ( vertex == 0 )
1010  {
1011  while ( vertex < points.size() - 1 )
1012  {
1013  const QPointF& nextPt = points[vertex+1];
1014  if ( pt != nextPt )
1015  {
1016  angle = MyLine( pt, nextPt ).angle();
1017  return angle;
1018  }
1019  ++vertex;
1020  }
1021  }
1022  else
1023  {
1024  // use last segment's angle
1025  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1026  {
1027  const QPointF& prevPt = points[vertex-1];
1028  if ( pt != prevPt )
1029  {
1030  angle = MyLine( prevPt, pt ).angle();
1031  return angle;
1032  }
1033  --vertex;
1034  }
1035  }
1036  }
1037  return angle;
1038 }
1039 
1040 void QgsMarkerLineSymbolLayerV2::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext& context )
1041 {
1042  if ( points.isEmpty() )
1043  return;
1044 
1045  QgsRenderContext& rc = context.renderContext();
1046  double origAngle = mMarker->angle();
1047  if ( distance == 0 )
1048  {
1049  // rotate marker (if desired)
1050  if ( mRotateMarker )
1051  {
1052  bool isRing = false;
1053  if ( points.first() == points.last() )
1054  isRing = true;
1055  double angle = markerAngle( points, isRing, vertex );
1056  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1057  }
1058  mMarker->renderPoint( points[vertex], context.feature(), rc, -1, context.selected() );
1059  return;
1060  }
1061 
1062  int pointIncrement = distance > 0 ? 1 : -1;
1063  QPointF previousPoint = points[vertex];
1064  int startPoint = distance > 0 ? qMin( vertex + 1, points.count() - 1 ) : qMax( vertex - 1, 0 );
1065  int endPoint = distance > 0 ? points.count() - 1 : 0;
1066  double distanceLeft = qAbs( distance );
1067 
1068  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1069  {
1070  const QPointF& pt = points[i];
1071 
1072  if ( previousPoint == pt ) // must not be equal!
1073  continue;
1074 
1075  // create line segment
1076  MyLine l( previousPoint, pt );
1077 
1078  if ( distanceLeft < l.length() )
1079  {
1080  //destination point is in current segment
1081  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1082  // rotate marker (if desired)
1083  if ( mRotateMarker )
1084  {
1085  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1086  }
1087  mMarker->renderPoint( markerPoint, context.feature(), rc, -1, context.selected() );
1088  return;
1089  }
1090 
1091  distanceLeft -= l.length();
1092  previousPoint = pt;
1093  }
1094 
1095  //didn't find point
1096  return;
1097 }
1098 
1100 {
1101  if ( points.size() > 0 )
1102  {
1103  // calc length
1104  qreal length = 0;
1105  QPolygonF::const_iterator it = points.constBegin();
1106  QPointF last = *it;
1107  for ( ++it; it != points.constEnd(); ++it )
1108  {
1109  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1110  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1111  last = *it;
1112  }
1113 
1114  // find the segment where the central point lies
1115  it = points.constBegin();
1116  last = *it;
1117  qreal last_at = 0, next_at = 0;
1118  QPointF next;
1119  int segment = 0;
1120  for ( ++it; it != points.constEnd(); ++it )
1121  {
1122  next = *it;
1123  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1124  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1125  if ( next_at >= length / 2 )
1126  break; // we have reached the center
1127  last = *it;
1128  last_at = next_at;
1129  segment++;
1130  }
1131 
1132  // find out the central point on segment
1133  MyLine l( last, next ); // for line angle
1134  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1135  QPointF pt = last + ( next - last ) * k;
1136 
1137  // draw the marker
1138  double origAngle = mMarker->angle();
1139  if ( mRotateMarker )
1140  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
1141  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
1142  if ( mRotateMarker )
1143  mMarker->setAngle( origAngle );
1144  }
1145 }
1146 
1147 
1149 {
1150  QgsStringMap map;
1151  map["rotate"] = ( mRotateMarker ? "1" : "0" );
1152  map["interval"] = QString::number( mInterval );
1153  map["offset"] = QString::number( mOffset );
1154  map["offset_along_line"] = QString::number( mOffsetAlongLine );
1155  map["offset_along_line_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetAlongLineUnit );
1156  map["offset_along_line_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetAlongLineMapUnitScale );
1157  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1158  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1159  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
1160  map["interval_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mIntervalMapUnitScale );
1161  if ( mPlacement == Vertex )
1162  map["placement"] = "vertex";
1163  else if ( mPlacement == LastVertex )
1164  map["placement"] = "lastvertex";
1165  else if ( mPlacement == FirstVertex )
1166  map["placement"] = "firstvertex";
1167  else if ( mPlacement == CentralPoint )
1168  map["placement"] = "centralpoint";
1169  else
1170  map["placement"] = "interval";
1171 
1173  return map;
1174 }
1175 
1177 {
1178  return mMarker;
1179 }
1180 
1182 {
1183  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1184  {
1185  delete symbol;
1186  return false;
1187  }
1188 
1189  delete mMarker;
1190  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1191  mColor = mMarker->color();
1192  return true;
1193 }
1194 
1196 {
1198  x->setSubSymbol( mMarker->clone() );
1199  x->setOffset( mOffset );
1200  x->setPlacement( mPlacement );
1201  x->setOffsetUnit( mOffsetUnit );
1209  return x;
1210 }
1211 
1212 void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1213 {
1214  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1215  {
1216  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1217  if ( !props.value( "uom", "" ).isEmpty() )
1218  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1219  element.appendChild( symbolizerElem );
1220 
1221  // <Geometry>
1222  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1223 
1224  QString gap;
1225  switch ( mPlacement )
1226  {
1227  case FirstVertex:
1228  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1229  break;
1230  case LastVertex:
1231  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1232  break;
1233  case CentralPoint:
1234  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1235  break;
1236  case Vertex:
1237  // no way to get line/polygon's vertices, use a VendorOption
1238  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1239  break;
1240  default:
1241  gap = QString::number( mInterval );
1242  break;
1243  }
1244 
1245  if ( !mRotateMarker )
1246  {
1247  // markers in LineSymbolizer must be drawn following the line orientation,
1248  // use a VendorOption when no marker rotation
1249  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1250  }
1251 
1252  // <Stroke>
1253  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1254  symbolizerElem.appendChild( strokeElem );
1255 
1256  // <GraphicStroke>
1257  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1258  strokeElem.appendChild( graphicStrokeElem );
1259 
1260  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1261  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1262  if ( !markerLayer )
1263  {
1264  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
1265  }
1266  else
1267  {
1268  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1269  }
1270 
1271  if ( !gap.isEmpty() )
1272  {
1273  QDomElement gapElem = doc.createElement( "se:Gap" );
1274  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1275  graphicStrokeElem.appendChild( gapElem );
1276  }
1277 
1278  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1279  {
1280  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1281  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1282  symbolizerElem.appendChild( perpOffsetElem );
1283  }
1284  }
1285 }
1286 
1288 {
1289  QgsDebugMsg( "Entered." );
1290 
1291  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1292  if ( strokeElem.isNull() )
1293  return NULL;
1294 
1295  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1296  if ( graphicStrokeElem.isNull() )
1297  return NULL;
1298 
1299  // retrieve vendor options
1300  bool rotateMarker = true;
1302 
1303  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1304  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1305  {
1306  if ( it.key() == "placement" )
1307  {
1308  if ( it.value() == "points" ) placement = Vertex;
1309  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1310  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1311  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1312  }
1313  else if ( it.value() == "rotateMarker" )
1314  {
1315  rotateMarker = it.value() == "0";
1316  }
1317  }
1318 
1319  QgsMarkerSymbolV2 *marker = 0;
1320 
1322  if ( l )
1323  {
1324  QgsSymbolLayerV2List layers;
1325  layers.append( l );
1326  marker = new QgsMarkerSymbolV2( layers );
1327  }
1328 
1329  if ( !marker )
1330  return NULL;
1331 
1332  double interval = 0.0;
1333  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1334  if ( !gapElem.isNull() )
1335  {
1336  bool ok;
1337  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1338  if ( ok )
1339  interval = d;
1340  }
1341 
1342  double offset = 0.0;
1343  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1344  if ( !perpOffsetElem.isNull() )
1345  {
1346  bool ok;
1347  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1348  if ( ok )
1349  offset = d;
1350  }
1351 
1352  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1353  x->setPlacement( placement );
1354  x->setInterval( interval );
1355  x->setSubSymbol( marker );
1356  x->setOffset( offset );
1357  return x;
1358 }
1359 
1361 {
1362  mMarker->setSize( width );
1363 }
1364 
1366 {
1367  return mMarker->size();
1368 }
1369 
1371 {
1373  mIntervalUnit = unit;
1374  mOffsetUnit = unit;
1375  mOffsetAlongLineUnit = unit;
1376 }
1377 
1379 {
1381  if ( mIntervalUnit != unit || mOffsetUnit != unit || mOffsetAlongLineUnit != unit )
1382  {
1383  return QgsSymbolV2::Mixed;
1384  }
1385  return unit;
1386 }
1387 
1389 {
1391  mIntervalMapUnitScale = scale;
1392  mOffsetMapUnitScale = scale;
1394 }
1395 
1397 {
1401  {
1402  return mOffsetMapUnitScale;
1403  }
1404  return QgsMapUnitScale();
1405 }
1406 
1408 {
1409  return ( mMarker->size() / 2.0 ) + mOffset;
1410 }
1411 
1412 
1413 
static double _averageAngle(const QPointF &prevPt, const QPointF &pt, const QPointF &nextPt)
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
void setIntervalUnit(QgsSymbolV2::OutputUnit unit)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
#define DEFAULT_SIMPLELINE_PENSTYLE
void startRender(QgsSymbolV2RenderContext &context)
#define DEFAULT_MARKERLINE_ROTATE
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
float threshold() const
Gets the simplification threshold of the vector layer managed.
int renderHints() const
Definition: qgssymbolv2.h:187
virtual double width() const
double markerAngle(const QPolygonF &points, bool isRing, int vertex)
QgsMapUnitScale mapUnitScale() const
QgsSymbolV2::OutputUnit outputUnit() const
#define DEFAULT_MARKERLINE_INTERVAL
SymbolType type() const
Definition: qgssymbolv2.h:79
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
QColor selectionColor() const
Added in QGIS v2.0.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void setCustomDashPatternUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mCustomDashPatternMapUnitScale
double rendererScale() const
static QgsStringMap getVendorOptionList(QDomElement &element)
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:112
QGis::UnitType mapUnits() const
Definition: qgsdxfexport.h:54
static QVector< qreal > decodeRealVector(const QString &s)
void renderPolylineInterval(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QVector< qreal > customDashVector() const
void setPenJoinStyle(Qt::PenJoinStyle style)
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
QgsSymbolV2::OutputUnit outputUnit() const
QGis::GeometryType type()
Returns type of the vector.
QgsSymbolV2::OutputUnit outputUnit() const
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
static QColor decodeColor(QString str)
QgsSymbolLayerV2 * clone() const
static const bool selectionIsOpaque
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
bool setSubSymbol(QgsSymbolV2 *symbol)
QVector< qreal > dxfCustomDashPattern(QgsSymbolV2::OutputUnit &unit) const
QgsMapUnitScale mWidthMapUnitScale
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
Qt::PenStyle penStyle() const
void setWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsMapUnitScale mOffsetAlongLineMapUnitScale
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the marker placement.
static QString encodeColor(QColor color)
void setInterval(double interval)
virtual QgsExpression * expression(const QString &property) const
QgsSymbolV2::OutputUnit mOffsetUnit
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:179
void setDrawInsidePolygon(bool drawInsidePolygon)
static QString encodePenStyle(Qt::PenStyle style)
QPointF diffForInterval(double interval)
void setColor(const QColor &color)
QgsSymbolV2::OutputUnit mIntervalUnit
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
QgsStringMap properties() const
double offsetAlongLine() const
Returns the offset along the line for the marker placement.
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=0)
Create ogr feature style string for pen.
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:193
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'...
static Qt::PenCapStyle decodePenCapStyle(QString str)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static Qt::PenStyle decodePenStyle(QString str)
QgsSymbolV2::OutputUnit mWidthUnit
void setMapUnitScale(const QgsMapUnitScale &scale)
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
QVector< qreal > mCustomDashVector
Vector with an even number of entries for the.
#define DEFAULT_SIMPLELINE_WIDTH
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
#define M_PI
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setAngle(double angle)
#define DEFAULT_SIMPLELINE_CAPSTYLE
#define DEFAULT_SIMPLELINE_JOINSTYLE
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
int symbolLayerCount()
Definition: qgssymbolv2.h:85
void setSize(double size)
double rasterScaleFactor() const
void startRender(QgsSymbolV2RenderContext &context)
QgsMapUnitScale mapUnitScale() const
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...
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const
void renderOffsetVertexAlongLine(const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext &context)
Renders a marker by offseting a vertex along the line by a specified distance.
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)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
void setPenCapStyle(Qt::PenCapStyle style)
void setCustomDashVector(const QVector< qreal > &vector)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const
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 setOffsetMapUnitScale(const QgsMapUnitScale &scale)
virtual void setWidth(double width)
void setColor(const QColor &color)
static QString encodeRealVector(const QVector< qreal > &v)
QgsSymbolV2::OutputUnit mCustomDashPatternUnit
virtual QString layerType() const =0
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)
double symbologyScaleDenominator() const
Definition: qgsdxfexport.h:51
QgsSymbolLayerV2 * clone() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void applyDataDefinedSymbology(QgsSymbolV2RenderContext &context, QPen &pen, QPen &selPen, double &offset)
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, QColor color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=0, const Qt::PenCapStyle *penCapStyle=0, const QVector< qreal > *customDashPattern=0, double dashOffset=0.0)
#define DEFAULT_SIMPLELINE_COLOR
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
QgsSymbolV2::OutputUnit mOffsetAlongLineUnit
QPainter * painter()
void stopRender(QgsRenderContext &context)
QgsSimpleLineSymbolLayerV2(QColor color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
void stopRender(QgsSymbolV2RenderContext &context)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QGis::GeometryType geometryType)
calculate geometry shifted by a specified distance
virtual QgsSymbolV2 * clone() const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:39
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:168
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:199
void setRenderHints(int hints)
Definition: qgssymbolv2.h:130
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
MyLine(QPointF p1, QPointF p2)
bool selected() const
Definition: qgssymbolv2.h:183
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsSymbolV2::OutputUnit mOffsetUnit
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsSymbolLayerV2 * symbolLayer(int layer)
Qt::PenStyle dxfPenStyle() const
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=0, Qt::PenCapStyle *penCapStyle=0, QVector< qreal > *customDashPattern=0, double *dashOffset=0)
QgsMarkerLineSymbolLayerV2(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:127
void renderPolylineCentral(const QPolygonF &points, QgsSymbolV2RenderContext &context)
QColor dxfColor(const QgsSymbolV2RenderContext &context) const
static bool canbeGeneralizedByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
void stopRender(QgsSymbolV2RenderContext &context)
QgsSymbolV2::OutputUnit widthUnit() const
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
Qt::PenJoinStyle penJoinStyle() const
void renderPolylineVertex(const QPolygonF &points, QgsSymbolV2RenderContext &context, Placement placement=Vertex)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
void setMapUnitScale(const QgsMapUnitScale &scale)
Qt::PenCapStyle penCapStyle() const
QColor color() const
static QString encodePenCapStyle(Qt::PenCapStyle style)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)