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 &&
264  ( p->renderHints() & QPainter::Antialiasing ) )
265  {
266  p->setRenderHint( QPainter::Antialiasing, false );
267  p->drawPolyline( points );
268  p->setRenderHint( QPainter::Antialiasing, true );
269  return;
270  }
271 
272  if ( offset == 0 )
273  {
274  p->drawPolyline( points );
275  }
276  else
277  {
279  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->geometry()->type() : QGis::Line );
280  for ( int part = 0; part < mline.count(); ++part )
281  p->drawPolyline( mline[ part ] );
282  }
283 }
284 
286 {
287  QgsStringMap map;
288  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
289  map["width"] = QString::number( mWidth );
291  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
295  map["offset"] = QString::number( mOffset );
297  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
298  map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
302  map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
304  return map;
305 }
306 
308 {
310  l->setWidthUnit( mWidthUnit );
316  l->setOffset( mOffset );
323  return l;
324 }
325 
326 void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
327 {
328  if ( mPenStyle == Qt::NoPen )
329  return;
330 
331  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
332  if ( !props.value( "uom", "" ).isEmpty() )
333  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
334  element.appendChild( symbolizerElem );
335 
336  // <Geometry>
337  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
338 
339  // <Stroke>
340  QDomElement strokeElem = doc.createElement( "se:Stroke" );
341  symbolizerElem.appendChild( strokeElem );
342 
343  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
344  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
346 
347  // <se:PerpendicularOffset>
348  if ( mOffset != 0 )
349  {
350  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
351  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
352  symbolizerElem.appendChild( perpOffsetElem );
353  }
354 }
355 
356 QString QgsSimpleLineSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
357 {
358  if ( mUseCustomDashPattern )
359  {
360  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
361  mPen.color(), mPenJoinStyle,
363  }
364  else
365  {
366  return QgsSymbolLayerV2Utils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
368  }
369 }
370 
372 {
373  QgsDebugMsg( "Entered." );
374 
375  QDomElement strokeElem = element.firstChildElement( "Stroke" );
376  if ( strokeElem.isNull() )
377  return NULL;
378 
379  Qt::PenStyle penStyle;
380  QColor color;
381  double width;
382  Qt::PenJoinStyle penJoinStyle;
383  Qt::PenCapStyle penCapStyle;
384  QVector<qreal> customDashVector;
385 
386  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
387  color, width,
388  &penJoinStyle, &penCapStyle,
389  &customDashVector ) )
390  return NULL;
391 
392  double offset = 0.0;
393  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
394  if ( !perpOffsetElem.isNull() )
395  {
396  bool ok;
397  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
398  if ( ok )
399  offset = d;
400  }
401 
402  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
403  l->setOffset( offset );
404  l->setPenJoinStyle( penJoinStyle );
405  l->setPenCapStyle( penCapStyle );
406  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
407  l->setCustomDashVector( customDashVector );
408  return l;
409 }
410 
411 void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset )
412 {
413  //data defined properties
414  double scaledWidth = 0;
415  QgsExpression* strokeWidthExpression = expression( "width" );
416  if ( strokeWidthExpression )
417  {
418  scaledWidth = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble()
420  pen.setWidthF( scaledWidth );
421  selPen.setWidthF( scaledWidth );
422  }
423  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
424  {
426  pen.setWidthF( scaledWidth );
427  selPen.setWidthF( scaledWidth );
428  }
429 
430  //color
431  QgsExpression* strokeColorExpression = expression( "color" );
432  if ( strokeColorExpression )
433  {
434  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
435  }
436 
437  //offset
438  offset = mOffset;
439  QgsExpression* lineOffsetExpression = expression( "offset" );
440  if ( lineOffsetExpression )
441  {
442  offset = lineOffsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
443  }
444 
445  //dash dot vector
446  QgsExpression* dashPatternExpression = expression( "customdash" );
447  if ( dashPatternExpression )
448  {
449 
451 
452  double dashWidthDiv = mPen.widthF();
453 
454  if ( strokeWidthExpression )
455  {
456  dashWidthDiv = pen.widthF();
457  scaledWidth = pen.widthF();
458  }
459 
460  //fix dash pattern width in Qt 4.8
461  QStringList versionSplit = QString( qVersion() ).split( "." );
462  if ( versionSplit.size() > 1
463  && versionSplit.at( 1 ).toInt() >= 8
464  && ( scaledWidth * context.renderContext().rasterScaleFactor() ) < 1.0 )
465  {
466  dashWidthDiv = 1.0;
467  }
468 
469  QVector<qreal> dashVector;
470  QStringList dashList = dashPatternExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString().split( ";" );
471  QStringList::const_iterator dashIt = dashList.constBegin();
472  for ( ; dashIt != dashList.constEnd(); ++dashIt )
473  {
474  dashVector.push_back( dashIt->toDouble() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
475  }
476  pen.setDashPattern( dashVector );
477  }
478 
479  //join style
480  QgsExpression* joinStyleExpression = expression( "joinstyle" );
481  if ( joinStyleExpression )
482  {
483  QString joinStyleString = joinStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
484  pen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( joinStyleString ) );
485  }
486 
487  //cap style
488  QgsExpression* capStyleExpression = expression( "capstyle" );
489  if ( capStyleExpression )
490  {
491  QString capStyleString = capStyleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
492  pen.setCapStyle( QgsSymbolLayerV2Utils::decodePenCapStyle( capStyleString ) );
493  }
494 }
495 
497 {
498  if ( mDrawInsidePolygon )
499  {
500  //set to clip line to the interior of polygon, so we expect no bleed
501  return 0;
502  }
503  else
504  {
505  return ( mWidth / 2.0 ) + mOffset;
506  }
507 }
508 
510 {
511  unit = mCustomDashPatternUnit;
512  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>() ;
513 }
514 
516 {
517  return mPenStyle;
518 }
519 
521 {
522  double width = mWidth;
523  QgsExpression* strokeWidthExpression = expression( "width" );
524  if ( strokeWidthExpression )
525  {
526  width = strokeWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble() * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
527  }
528  else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
529  {
531  }
532 
533  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
534 }
535 
537 {
538  QgsExpression* strokeColorExpression = expression( "color" );
539  if ( strokeColorExpression )
540  {
541  return ( QgsSymbolLayerV2Utils::decodeColor( strokeColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
542  }
543  return mColor;
544 }
545 
547 
548 
549 class MyLine
550 {
551  public:
552  MyLine( QPointF p1, QPointF p2 ) : mVertical( false ), mIncreasing( false ), mT( 0.0 ), mLength( 0.0 )
553  {
554  if ( p1 == p2 )
555  return; // invalid
556 
557  // tangent and direction
558  if ( p1.x() == p2.x() )
559  {
560  // vertical line - tangent undefined
561  mVertical = true;
562  mIncreasing = ( p2.y() > p1.y() );
563  }
564  else
565  {
566  mVertical = false;
567  mT = float( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
568  mIncreasing = ( p2.x() > p1.x() );
569  }
570 
571  // length
572  double x = ( p2.x() - p1.x() );
573  double y = ( p2.y() - p1.y() );
574  mLength = sqrt( x * x + y * y );
575  }
576 
577  // return angle in radians
578  double angle()
579  {
580  double a = ( mVertical ? M_PI / 2 : atan( mT ) );
581 
582  if ( !mIncreasing )
583  a += M_PI;
584  return a;
585  }
586 
587  // return difference for x,y when going along the line with specified interval
588  QPointF diffForInterval( double interval )
589  {
590  if ( mVertical )
591  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
592 
593  double alpha = atan( mT );
594  double dx = cos( alpha ) * interval;
595  double dy = sin( alpha ) * interval;
596  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
597  }
598 
599  double length() { return mLength; }
600 
601  protected:
602  bool mVertical;
604  double mT;
605  double mLength;
606 };
607 
608 
609 QgsMarkerLineSymbolLayerV2::QgsMarkerLineSymbolLayerV2( bool rotateMarker, double interval )
610 {
614  mMarker = NULL;
615  mOffset = 0;
618  mOffsetAlongLine = 0;
620 
622 }
623 
625 {
626  delete mMarker;
627 }
628 
630 {
631  bool rotate = DEFAULT_MARKERLINE_ROTATE;
633 
634 
635  if ( props.contains( "interval" ) )
636  interval = props["interval"].toDouble();
637  if ( props.contains( "rotate" ) )
638  rotate = ( props["rotate"] == "1" );
639 
640  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotate, interval );
641  if ( props.contains( "offset" ) )
642  {
643  x->setOffset( props["offset"].toDouble() );
644  }
645  if ( props.contains( "offset_unit" ) )
646  {
647  x->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
648  }
649  if ( props.contains( "interval_unit" ) )
650  {
651  x->setIntervalUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["interval_unit"] ) );
652  }
653  if ( props.contains( "offset_along_line" ) )
654  {
655  x->setOffsetAlongLine( props["offset_along_line"].toDouble() );
656  }
657  if ( props.contains( "offset_along_line_unit" ) )
658  {
659  x->setOffsetAlongLineUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_along_line_unit"] ) );
660  }
661  if ( props.contains(( "offset_along_line_map_unit_scale" ) ) )
662  {
663  x->setOffsetAlongLineMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_along_line_map_unit_scale"] ) );
664  }
665 
666  if ( props.contains( "offset_map_unit_scale" ) )
667  {
668  x->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
669  }
670  if ( props.contains( "interval_map_unit_scale" ) )
671  {
672  x->setIntervalMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["interval_map_unit_scale"] ) );
673  }
674 
675  if ( props.contains( "placement" ) )
676  {
677  if ( props["placement"] == "vertex" )
678  x->setPlacement( Vertex );
679  else if ( props["placement"] == "lastvertex" )
680  x->setPlacement( LastVertex );
681  else if ( props["placement"] == "firstvertex" )
683  else if ( props["placement"] == "centralpoint" )
685  else
686  x->setPlacement( Interval );
687  }
688 
689  //data defined properties
690  if ( props.contains( "interval_expression" ) )
691  {
692  x->setDataDefinedProperty( "interval", props["interval_expression"] );
693  }
694  if ( props.contains( "offset_expression" ) )
695  {
696  x->setDataDefinedProperty( "offset", props["offset_expression"] );
697  }
698  if ( props.contains( "placement_expression" ) )
699  {
700  x->setDataDefinedProperty( "placement", props["placement_expression"] );
701  }
702  if ( props.contains( "offset_along_line_expression" ) )
703  {
704  x->setDataDefinedProperty( "offset_along_line", props["offset_along_line_expression"] );
705  }
706 
707  return x;
708 }
709 
711 {
712  return "MarkerLine";
713 }
714 
715 void QgsMarkerLineSymbolLayerV2::setColor( const QColor& color )
716 {
717  mMarker->setColor( color );
718  mColor = color;
719 }
720 
722 {
723  mMarker->setAlpha( context.alpha() );
724 
725  // if being rotated, it gets initialized with every line segment
726  int hints = 0;
727  if ( mRotateMarker )
731  mMarker->setRenderHints( hints );
732 
733  mMarker->startRender( context.renderContext(), context.fields() );
734 
735  //prepare expressions for data defined properties
736  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
737 }
738 
740 {
741  mMarker->stopRender( context.renderContext() );
742 }
743 
745 {
746  double offset = mOffset;
747  QgsExpression* offsetExpression = expression( "offset" );
748  if ( offsetExpression )
749  {
750  offset = offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
751  }
752 
754  QgsExpression* placementExpression = expression( "placement" );
755  if ( placementExpression )
756  {
757  QString placementString = placementExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
758  if ( placementString.compare( "vertex", Qt::CaseInsensitive ) == 0 )
759  {
760  placement = Vertex;
761  }
762  else if ( placementString.compare( "lastvertex", Qt::CaseInsensitive ) == 0 )
763  {
764  placement = LastVertex;
765  }
766  else if ( placementString.compare( "firstvertex", Qt::CaseInsensitive ) == 0 )
767  {
768  placement = FirstVertex;
769  }
770  else if ( placementString.compare( "centerpoint", Qt::CaseInsensitive ) == 0 )
771  {
772  placement = CentralPoint;
773  }
774  else
775  {
776  placement = Interval;
777  }
778  }
779 
780  if ( offset == 0 )
781  {
782  if ( placement == Interval )
783  renderPolylineInterval( points, context );
784  else if ( placement == CentralPoint )
785  renderPolylineCentral( points, context );
786  else
787  renderPolylineVertex( points, context, placement );
788  }
789  else
790  {
791  QList<QPolygonF> mline = ::offsetLine( points, offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ), context.feature() ? context.feature()->geometry()->type() : QGis::Line );
792 
793  for ( int part = 0; part < mline.count(); ++part )
794  {
795  const QPolygonF &points2 = mline[ part ];
796 
797  if ( placement == Interval )
798  renderPolylineInterval( points2, context );
799  else if ( placement == CentralPoint )
800  renderPolylineCentral( points2, context );
801  else
802  renderPolylineVertex( points2, context, placement );
803  }
804  }
805 }
806 
808 {
809  if ( points.isEmpty() )
810  return;
811 
812  QPointF lastPt = points[0];
813  double lengthLeft = 0; // how much is left until next marker
814  bool first = mOffsetAlongLine ? false : true; //only draw marker at first vertex when no offset along line is set
815  double origAngle = mMarker->angle();
816 
817  QgsRenderContext& rc = context.renderContext();
818  double interval = mInterval;
819 
820  QgsExpression* intervalExpression = expression( "interval" );
821  if ( intervalExpression )
822  {
823  interval = intervalExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
824  }
825  if ( interval <= 0 )
826  {
827  interval = 0.1;
828  }
830  QgsExpression* offsetAlongLineExpression = expression( "offset_along_line" );
831  if ( offsetAlongLineExpression )
832  {
833  offsetAlongLine = offsetAlongLineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
834  }
835 
836  double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
837  lengthLeft = painterUnitInterval - offsetAlongLine * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
838 
839  for ( int i = 1; i < points.count(); ++i )
840  {
841  const QPointF& pt = points[i];
842 
843  if ( lastPt == pt ) // must not be equal!
844  continue;
845 
846  // for each line, find out dx and dy, and length
847  MyLine l( lastPt, pt );
848  QPointF diff = l.diffForInterval( painterUnitInterval );
849 
850  // if there's some length left from previous line
851  // use only the rest for the first point in new line segment
852  double c = 1 - lengthLeft / painterUnitInterval;
853 
854  lengthLeft += l.length();
855 
856  // rotate marker (if desired)
857  if ( mRotateMarker )
858  {
859  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
860  }
861 
862  // draw first marker
863  if ( first )
864  {
865  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
866  first = false;
867  }
868 
869  // while we're not at the end of line segment, draw!
870  while ( lengthLeft > painterUnitInterval )
871  {
872  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
873  lastPt += c * diff;
874  lengthLeft -= painterUnitInterval;
875  mMarker->renderPoint( lastPt, context.feature(), rc, -1, context.selected() );
876  c = 1; // reset c (if wasn't 1 already)
877  }
878 
879  lastPt = pt;
880  }
881 
882  // restore original rotation
883  mMarker->setAngle( origAngle );
884 
885 }
886 
887 static double _averageAngle( const QPointF& prevPt, const QPointF& pt, const QPointF& nextPt )
888 {
889  // calc average angle between the previous and next point
890  double a1 = MyLine( prevPt, pt ).angle();
891  double a2 = MyLine( pt, nextPt ).angle();
892  double unitX = cos( a1 ) + cos( a2 ), unitY = sin( a1 ) + sin( a2 );
893 
894  return atan2( unitY, unitX );
895 }
896 
897 void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points, QgsSymbolV2RenderContext& context, Placement placement )
898 {
899  if ( points.isEmpty() )
900  return;
901 
902  QgsRenderContext& rc = context.renderContext();
903 
904  double origAngle = mMarker->angle();
905  int i, maxCount;
906  bool isRing = false;
907 
909  QgsExpression* offsetAlongLineExpression = expression( "offset_along_line" );
910  if ( offsetAlongLineExpression )
911  {
912  offsetAlongLine = offsetAlongLineExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
913  }
914  if ( offsetAlongLine != 0 )
915  {
916  //scale offset along line
918  }
919 
920  if ( placement == FirstVertex )
921  {
922  i = 0;
923  maxCount = 1;
924  }
925  else if ( placement == LastVertex )
926  {
927  i = points.count() - 1;
928  maxCount = points.count();
929  }
930  else
931  {
932  i = 0;
933  maxCount = points.count();
934  if ( points.first() == points.last() )
935  isRing = true;
936  }
937 
938  if ( offsetAlongLine > 0 && ( placement == FirstVertex || placement == LastVertex ) )
939  {
940  double distance;
941  distance = placement == FirstVertex ? offsetAlongLine : -offsetAlongLine;
942  renderOffsetVertexAlongLine( points, i, distance, context );
943  // restore original rotation
944  mMarker->setAngle( origAngle );
945  return;
946  }
947 
948  for ( ; i < maxCount; ++i )
949  {
950  if ( isRing && placement == Vertex && i == points.count() - 1 )
951  {
952  continue; // don't draw the last marker - it has been drawn already
953  }
954  // rotate marker (if desired)
955  if ( mRotateMarker )
956  {
957  double angle = markerAngle( points, isRing, i );
958  mMarker->setAngle( origAngle + angle * 180 / M_PI );
959  }
960 
961  mMarker->renderPoint( points.at( i ), context.feature(), rc, -1, context.selected() );
962  }
963 
964  // restore original rotation
965  mMarker->setAngle( origAngle );
966 }
967 
968 double QgsMarkerLineSymbolLayerV2::markerAngle( const QPolygonF& points, bool isRing, int vertex )
969 {
970  double angle = 0;
971  const QPointF& pt = points[vertex];
972 
973  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
974  {
975  int prevIndex = vertex - 1;
976  int nextIndex = vertex + 1;
977 
978  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
979  {
980  prevIndex = points.count() - 2;
981  nextIndex = 1;
982  }
983 
984  QPointF prevPoint, nextPoint;
985  while ( prevIndex >= 0 )
986  {
987  prevPoint = points[ prevIndex ];
988  if ( prevPoint != pt )
989  {
990  break;
991  }
992  --prevIndex;
993  }
994 
995  while ( nextIndex < points.count() )
996  {
997  nextPoint = points[ nextIndex ];
998  if ( nextPoint != pt )
999  {
1000  break;
1001  }
1002  ++nextIndex;
1003  }
1004 
1005  if ( prevIndex >= 0 && nextIndex < points.count() )
1006  {
1007  angle = _averageAngle( prevPoint, pt, nextPoint );
1008  }
1009  }
1010  else //no ring and vertex is at start / at end
1011  {
1012  if ( vertex == 0 )
1013  {
1014  while ( vertex < points.size() - 1 )
1015  {
1016  const QPointF& nextPt = points[vertex+1];
1017  if ( pt != nextPt )
1018  {
1019  angle = MyLine( pt, nextPt ).angle();
1020  return angle;
1021  }
1022  ++vertex;
1023  }
1024  }
1025  else
1026  {
1027  // use last segment's angle
1028  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1029  {
1030  const QPointF& prevPt = points[vertex-1];
1031  if ( pt != prevPt )
1032  {
1033  angle = MyLine( prevPt, pt ).angle();
1034  return angle;
1035  }
1036  --vertex;
1037  }
1038  }
1039  }
1040  return angle;
1041 }
1042 
1043 void QgsMarkerLineSymbolLayerV2::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolV2RenderContext& context )
1044 {
1045  if ( points.isEmpty() )
1046  return;
1047 
1048  QgsRenderContext& rc = context.renderContext();
1049  double origAngle = mMarker->angle();
1050  if ( distance == 0 )
1051  {
1052  // rotate marker (if desired)
1053  if ( mRotateMarker )
1054  {
1055  bool isRing = false;
1056  if ( points.first() == points.last() )
1057  isRing = true;
1058  double angle = markerAngle( points, isRing, vertex );
1059  mMarker->setAngle( origAngle + angle * 180 / M_PI );
1060  }
1061  mMarker->renderPoint( points[vertex], context.feature(), rc, -1, context.selected() );
1062  return;
1063  }
1064 
1065  int pointIncrement = distance > 0 ? 1 : -1;
1066  QPointF previousPoint = points[vertex];
1067  int startPoint = distance > 0 ? qMin( vertex + 1, points.count() - 1 ) : qMax( vertex - 1, 0 );
1068  int endPoint = distance > 0 ? points.count() - 1 : 0;
1069  double distanceLeft = qAbs( distance );
1070 
1071  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1072  {
1073  const QPointF& pt = points[i];
1074 
1075  if ( previousPoint == pt ) // must not be equal!
1076  continue;
1077 
1078  // create line segment
1079  MyLine l( previousPoint, pt );
1080 
1081  if ( distanceLeft < l.length() )
1082  {
1083  //destination point is in current segment
1084  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1085  // rotate marker (if desired)
1086  if ( mRotateMarker )
1087  {
1088  mMarker->setAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1089  }
1090  mMarker->renderPoint( markerPoint, context.feature(), rc, -1, context.selected() );
1091  return;
1092  }
1093 
1094  distanceLeft -= l.length();
1095  previousPoint = pt;
1096  }
1097 
1098  //didn't find point
1099  return;
1100 }
1101 
1103 {
1104  if ( points.size() > 0 )
1105  {
1106  // calc length
1107  qreal length = 0;
1108  QPolygonF::const_iterator it = points.constBegin();
1109  QPointF last = *it;
1110  for ( ++it; it != points.constEnd(); ++it )
1111  {
1112  length += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1113  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1114  last = *it;
1115  }
1116 
1117  // find the segment where the central point lies
1118  it = points.constBegin();
1119  last = *it;
1120  qreal last_at = 0, next_at = 0;
1121  QPointF next;
1122  int segment = 0;
1123  for ( ++it; it != points.constEnd(); ++it )
1124  {
1125  next = *it;
1126  next_at += sqrt(( last.x() - it->x() ) * ( last.x() - it->x() ) +
1127  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1128  if ( next_at >= length / 2 )
1129  break; // we have reached the center
1130  last = *it;
1131  last_at = next_at;
1132  segment++;
1133  }
1134 
1135  // find out the central point on segment
1136  MyLine l( last, next ); // for line angle
1137  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1138  QPointF pt = last + ( next - last ) * k;
1139 
1140  // draw the marker
1141  double origAngle = mMarker->angle();
1142  if ( mRotateMarker )
1143  mMarker->setAngle( origAngle + l.angle() * 180 / M_PI );
1144  mMarker->renderPoint( pt, context.feature(), context.renderContext(), -1, context.selected() );
1145  if ( mRotateMarker )
1146  mMarker->setAngle( origAngle );
1147  }
1148 }
1149 
1150 
1152 {
1153  QgsStringMap map;
1154  map["rotate"] = ( mRotateMarker ? "1" : "0" );
1155  map["interval"] = QString::number( mInterval );
1156  map["offset"] = QString::number( mOffset );
1157  map["offset_along_line"] = QString::number( mOffsetAlongLine );
1158  map["offset_along_line_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetAlongLineUnit );
1159  map["offset_along_line_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetAlongLineMapUnitScale );
1160  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1161  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1162  map["interval_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mIntervalUnit );
1163  map["interval_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mIntervalMapUnitScale );
1164  if ( mPlacement == Vertex )
1165  map["placement"] = "vertex";
1166  else if ( mPlacement == LastVertex )
1167  map["placement"] = "lastvertex";
1168  else if ( mPlacement == FirstVertex )
1169  map["placement"] = "firstvertex";
1170  else if ( mPlacement == CentralPoint )
1171  map["placement"] = "centralpoint";
1172  else
1173  map["placement"] = "interval";
1174 
1176  return map;
1177 }
1178 
1180 {
1181  return mMarker;
1182 }
1183 
1185 {
1186  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
1187  {
1188  delete symbol;
1189  return false;
1190  }
1191 
1192  delete mMarker;
1193  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
1194  mColor = mMarker->color();
1195  return true;
1196 }
1197 
1199 {
1201  x->setSubSymbol( mMarker->clone() );
1202  x->setOffset( mOffset );
1203  x->setPlacement( mPlacement );
1204  x->setOffsetUnit( mOffsetUnit );
1212  return x;
1213 }
1214 
1215 void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1216 {
1217  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1218  {
1219  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
1220  if ( !props.value( "uom", "" ).isEmpty() )
1221  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1222  element.appendChild( symbolizerElem );
1223 
1224  // <Geometry>
1225  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1226 
1227  QString gap;
1228  switch ( mPlacement )
1229  {
1230  case FirstVertex:
1231  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
1232  break;
1233  case LastVertex:
1234  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
1235  break;
1236  case CentralPoint:
1237  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
1238  break;
1239  case Vertex:
1240  // no way to get line/polygon's vertices, use a VendorOption
1241  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
1242  break;
1243  default:
1244  gap = QString::number( mInterval );
1245  break;
1246  }
1247 
1248  if ( !mRotateMarker )
1249  {
1250  // markers in LineSymbolizer must be drawn following the line orientation,
1251  // use a VendorOption when no marker rotation
1252  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
1253  }
1254 
1255  // <Stroke>
1256  QDomElement strokeElem = doc.createElement( "se:Stroke" );
1257  symbolizerElem.appendChild( strokeElem );
1258 
1259  // <GraphicStroke>
1260  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
1261  strokeElem.appendChild( graphicStrokeElem );
1262 
1263  QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
1264  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
1265  if ( !markerLayer )
1266  {
1267  graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
1268  }
1269  else
1270  {
1271  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1272  }
1273 
1274  if ( !gap.isEmpty() )
1275  {
1276  QDomElement gapElem = doc.createElement( "se:Gap" );
1277  QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
1278  graphicStrokeElem.appendChild( gapElem );
1279  }
1280 
1281  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1282  {
1283  QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
1284  perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
1285  symbolizerElem.appendChild( perpOffsetElem );
1286  }
1287  }
1288 }
1289 
1291 {
1292  QgsDebugMsg( "Entered." );
1293 
1294  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1295  if ( strokeElem.isNull() )
1296  return NULL;
1297 
1298  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
1299  if ( graphicStrokeElem.isNull() )
1300  return NULL;
1301 
1302  // retrieve vendor options
1303  bool rotateMarker = true;
1305 
1306  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
1307  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1308  {
1309  if ( it.key() == "placement" )
1310  {
1311  if ( it.value() == "points" ) placement = Vertex;
1312  else if ( it.value() == "firstPoint" ) placement = FirstVertex;
1313  else if ( it.value() == "lastPoint" ) placement = LastVertex;
1314  else if ( it.value() == "centralPoint" ) placement = CentralPoint;
1315  }
1316  else if ( it.value() == "rotateMarker" )
1317  {
1318  rotateMarker = it.value() == "0";
1319  }
1320  }
1321 
1322  QgsMarkerSymbolV2 *marker = 0;
1323 
1325  if ( l )
1326  {
1327  QgsSymbolLayerV2List layers;
1328  layers.append( l );
1329  marker = new QgsMarkerSymbolV2( layers );
1330  }
1331 
1332  if ( !marker )
1333  return NULL;
1334 
1335  double interval = 0.0;
1336  QDomElement gapElem = graphicStrokeElem.firstChildElement( "Gap" );
1337  if ( !gapElem.isNull() )
1338  {
1339  bool ok;
1340  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1341  if ( ok )
1342  interval = d;
1343  }
1344 
1345  double offset = 0.0;
1346  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( "PerpendicularOffset" );
1347  if ( !perpOffsetElem.isNull() )
1348  {
1349  bool ok;
1350  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1351  if ( ok )
1352  offset = d;
1353  }
1354 
1355  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
1356  x->setPlacement( placement );
1357  x->setInterval( interval );
1358  x->setSubSymbol( marker );
1359  x->setOffset( offset );
1360  return x;
1361 }
1362 
1364 {
1365  mMarker->setSize( width );
1366 }
1367 
1369 {
1370  return mMarker->size();
1371 }
1372 
1374 {
1376  mIntervalUnit = unit;
1377  mOffsetUnit = unit;
1378  mOffsetAlongLineUnit = unit;
1379 }
1380 
1382 {
1384  if ( mIntervalUnit != unit || mOffsetUnit != unit || mOffsetAlongLineUnit != unit )
1385  {
1386  return QgsSymbolV2::Mixed;
1387  }
1388  return unit;
1389 }
1390 
1392 {
1394  mIntervalMapUnitScale = scale;
1395  mOffsetMapUnitScale = scale;
1397 }
1398 
1400 {
1404  {
1405  return mOffsetMapUnitScale;
1406  }
1407  return QgsMapUnitScale();
1408 }
1409 
1411 {
1412  return ( mMarker->size() / 2.0 ) + mOffset;
1413 }
1414 
1415 
1416 
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)
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...
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
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)