QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgslayoutitempolyline.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitempolyline.cpp
3  begin : March 2016
4  copyright : (C) 2016 Paul Blottiere, Oslandia
5  email : paul dot blottiere at oslandia dot com
6  ***************************************************************************/
7 
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgslayoutitempolyline.h"
18 #include "qgslayoutitemregistry.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgssymbol.h"
21 #include "qgslayout.h"
22 #include "qgsmapsettings.h"
23 #include "qgslayoututils.h"
24 #include "qgsreadwritecontext.h"
25 #include "qgssvgcache.h"
26 #include "qgsstyleentityvisitor.h"
27 #include <QSvgRenderer>
28 #include <limits>
29 #include <QGraphicsPathItem>
30 #include <QVector2D>
31 
33  : QgsLayoutNodesItem( layout )
34 {
35  createDefaultPolylineStyleSymbol();
36 }
37 
38 QgsLayoutItemPolyline::QgsLayoutItemPolyline( const QPolygonF &polyline, QgsLayout *layout )
39  : QgsLayoutNodesItem( polyline, layout )
40 {
41  createDefaultPolylineStyleSymbol();
42 }
43 
45 {
46  return new QgsLayoutItemPolyline( layout );
47 }
48 
50 {
52 }
53 
55 {
56  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemPolyline.svg" ) );
57 }
58 
59 bool QgsLayoutItemPolyline::_addNode( const int indexPoint,
60  QPointF newPoint,
61  const double radius )
62 {
63  const double distStart = computeDistance( newPoint, mPolygon[0] );
64  const double distEnd = computeDistance( newPoint, mPolygon[mPolygon.size() - 1] );
65 
66  if ( indexPoint == ( mPolygon.size() - 1 ) )
67  {
68  if ( distEnd < radius )
69  mPolygon.append( newPoint );
70  else if ( distStart < radius )
71  mPolygon.insert( 0, newPoint );
72  }
73  else
74  mPolygon.insert( indexPoint + 1, newPoint );
75 
76  return true;
77 }
78 
79 bool QgsLayoutItemPolyline::_removeNode( const int index )
80 {
81  if ( index < 0 || index >= mPolygon.size() )
82  return false;
83 
84  mPolygon.remove( index );
85 
86  if ( mPolygon.size() < 2 )
87  mPolygon.clear();
88  else
89  {
90  int newSelectNode = index;
91  if ( index >= mPolygon.size() )
92  newSelectNode = mPolygon.size() - 1;
93  setSelectedNode( newSelectNode );
94  }
95 
96  return true;
97 }
98 
99 void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
100 {
101  QVariantMap properties;
102  properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
103  properties.insert( QStringLiteral( "width" ), QStringLiteral( "0.3" ) );
104  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
105 
106  mPolylineStyleSymbol.reset( QgsLineSymbol::createSimple( properties ) );
107  refreshSymbol();
108 }
109 
110 void QgsLayoutItemPolyline::refreshSymbol()
111 {
112  if ( auto *lLayout = layout() )
113  {
114  QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( lLayout, nullptr, lLayout->renderContext().dpi() );
115  mMaxSymbolBleed = ( 25.4 / lLayout->renderContext().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mPolylineStyleSymbol.get(), rc );
116  }
117 
118  updateSceneRect();
119 
120  emit frameChanged();
121 }
122 
123 void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
124 {
125  if ( mPolygon.size() < 2 )
126  return;
127 
128  switch ( mStartMarker )
129  {
130  case MarkerMode::NoMarker:
131  break;
132 
133  case MarkerMode::ArrowHead:
134  {
135  // calculate angle at start of line
136  QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
137  double angle = startLine.angle();
138  drawArrow( painter, mPolygon.at( 0 ), angle );
139  break;
140  }
141 
142  case MarkerMode::SvgMarker:
143  {
144  // calculate angle at start of line
145  QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
146  double angle = startLine.angle();
147  drawSvgMarker( painter, mPolygon.at( 0 ), angle, mStartMarkerFile, mStartArrowHeadHeight );
148  break;
149  }
150  }
151 
152 }
153 
154 void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
155 {
156  if ( mPolygon.size() < 2 )
157  return;
158 
159  switch ( mEndMarker )
160  {
161  case MarkerMode::NoMarker:
162  break;
163 
164  case MarkerMode::ArrowHead:
165  {
166  // calculate angle at end of line
167  QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
168  double angle = endLine.angle();
169 
170  //move end point depending on arrow width
171  QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
172  QPointF endPoint = endLine.p2();
173  endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
174 
175  drawArrow( painter, endPoint, angle );
176  break;
177  }
178  case MarkerMode::SvgMarker:
179  {
180  // calculate angle at end of line
181  QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
182  double angle = endLine.angle();
183  drawSvgMarker( painter, endLine.p2(), angle, mEndMarkerFile, mEndArrowHeadHeight );
184  break;
185  }
186  }
187 }
188 
189 void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center, double angle )
190 {
191  // translate angle from ccw from axis to cw from north
192  angle = 90 - angle;
193  QPen p;
194  p.setColor( mArrowHeadStrokeColor );
195  p.setWidthF( mArrowHeadStrokeWidth );
196  painter->setPen( p );
197  QBrush b;
198  b.setColor( mArrowHeadFillColor );
199  painter->setBrush( b );
200 
201  drawArrowHead( painter, center.x(), center.y(), angle, mArrowHeadWidth );
202 }
203 
204 void QgsLayoutItemPolyline::updateMarkerSvgSizes()
205 {
206  setStartSvgMarkerPath( mStartMarkerFile );
207  setEndSvgMarkerPath( mEndMarkerFile );
208 }
209 
210 void QgsLayoutItemPolyline::drawArrowHead( QPainter *p, const double x, const double y, const double angle, const double arrowHeadWidth )
211 {
212  if ( !p )
213  return;
214 
215  double angleRad = angle / 180.0 * M_PI;
216  QPointF middlePoint( x, y );
217 
218  //rotate both arrow points
219  QPointF p1 = QPointF( -arrowHeadWidth / 2.0, arrowHeadWidth );
220  QPointF p2 = QPointF( arrowHeadWidth / 2.0, arrowHeadWidth );
221 
222  QPointF p1Rotated, p2Rotated;
223  p1Rotated.setX( p1.x() * std::cos( angleRad ) + p1.y() * -std::sin( angleRad ) );
224  p1Rotated.setY( p1.x() * std::sin( angleRad ) + p1.y() * std::cos( angleRad ) );
225  p2Rotated.setX( p2.x() * std::cos( angleRad ) + p2.y() * -std::sin( angleRad ) );
226  p2Rotated.setY( p2.x() * std::sin( angleRad ) + p2.y() * std::cos( angleRad ) );
227 
228  QPolygonF arrowHeadPoly;
229  arrowHeadPoly << middlePoint;
230  arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
231  arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
232  QPen arrowPen = p->pen();
233  arrowPen.setJoinStyle( Qt::RoundJoin );
234  QBrush arrowBrush = p->brush();
235  arrowBrush.setStyle( Qt::SolidPattern );
236  p->setPen( arrowPen );
237  p->setBrush( arrowBrush );
238  arrowBrush.setStyle( Qt::SolidPattern );
239  p->drawPolygon( arrowHeadPoly );
240 }
241 
242 void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point, double angle, const QString &markerPath, double height ) const
243 {
244  // translate angle from ccw from axis to cw from north
245  angle = 90 - angle;
246 
247  if ( mArrowHeadWidth <= 0 || height <= 0 )
248  {
249  //bad image size
250  return;
251  }
252 
253  if ( markerPath.isEmpty() )
254  return;
255 
256  QSvgRenderer r;
257  const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
258  1.0 );
259  r.load( svgContent );
260 
261  QgsScopedQPainterState painterState( p );
262  p->translate( point.x(), point.y() );
263  p->rotate( angle );
264  p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
265  r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
266 }
267 
269 {
270  if ( !id().isEmpty() )
271  return id();
272 
273  return tr( "<Polyline>" );
274 }
275 
276 void QgsLayoutItemPolyline::_draw( QgsLayoutItemRenderContext &context, const QStyleOptionGraphicsItem * )
277 {
278  QgsScopedQPainterState painterState( context.renderContext().painter() );
279  //setup painter scaling to dots so that raster symbology is drawn to scale
281  QTransform t = QTransform::fromScale( scale, scale );
282 
283  mPolylineStyleSymbol->startRender( context.renderContext() );
284  mPolylineStyleSymbol->renderPolyline( t.map( mPolygon ), nullptr, context.renderContext() );
285  mPolylineStyleSymbol->stopRender( context.renderContext() );
286 
287  // painter is scaled to dots, so scale back to layout units
288  context.renderContext().painter()->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );
289 
290  drawStartMarker( context.renderContext().painter() );
291  drawEndMarker( context.renderContext().painter() );
292 }
293 
294 void QgsLayoutItemPolyline::_readXmlStyle( const QDomElement &elmt, const QgsReadWriteContext &context )
295 {
296  mPolylineStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( elmt, context ) );
297 }
298 
300 {
301  mPolylineStyleSymbol.reset( static_cast<QgsLineSymbol *>( symbol->clone() ) );
302  refreshSymbol();
303 }
304 
306 {
307  mStartMarker = mode;
308  update();
309 }
310 
312 {
313  mEndMarker = mode;
314  update();
315 }
316 
318 {
319  mArrowHeadWidth = width;
320  updateMarkerSvgSizes();
321  update();
322 }
323 
324 QPainterPath QgsLayoutItemPolyline::shape() const
325 {
326  QPainterPath path;
327  path.addPolygon( mPolygon );
328 
329  QPainterPathStroker ps;
330 
331  ps.setWidth( 2 * mMaxSymbolBleed );
332  QPainterPath strokedOutline = ps.createStroke( path );
333 
334  return strokedOutline;
335 }
336 
338 {
339  QSvgRenderer r;
340  mStartMarkerFile = path;
341  if ( path.isEmpty() || !r.load( path ) )
342  {
343  mStartArrowHeadHeight = 0;
344  }
345  else
346  {
347  //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
348  QRect viewBox = r.viewBox();
349  mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
350  }
352 }
353 
355 {
356  QSvgRenderer r;
357  mEndMarkerFile = path;
358  if ( path.isEmpty() || !r.load( path ) )
359  {
360  mEndArrowHeadHeight = 0;
361  }
362  else
363  {
364  //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
365  QRect viewBox = r.viewBox();
366  mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
367  }
369 }
370 
372 {
373  mArrowHeadStrokeColor = color;
374  update();
375 }
376 
378 {
379  mArrowHeadFillColor = color;
380  update();
381 }
382 
384 {
385  mArrowHeadStrokeWidth = width;
387  update();
388 }
389 
391 {
392  if ( mPolylineStyleSymbol )
393  {
394  QgsStyleSymbolEntity entity( mPolylineStyleSymbol.get() );
395  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
396  return false;
397  }
398 
399  return true;
400 }
401 
402 void QgsLayoutItemPolyline::_writeXmlStyle( QDomDocument &doc, QDomElement &elmt, const QgsReadWriteContext &context ) const
403 {
404  const QDomElement pe = QgsSymbolLayerUtils::saveSymbol( QString(),
405  mPolylineStyleSymbol.get(),
406  doc,
407  context );
408  elmt.appendChild( pe );
409 }
410 
411 bool QgsLayoutItemPolyline::writePropertiesToElement( QDomElement &elmt, QDomDocument &doc, const QgsReadWriteContext &context ) const
412 {
413  QgsLayoutNodesItem::writePropertiesToElement( elmt, doc, context );
414 
415  // absolute paths to relative
416  QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, context.pathResolver() );
417  QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, context.pathResolver() );
418 
419  elmt.setAttribute( QStringLiteral( "arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
420  elmt.setAttribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadFillColor ) );
421  elmt.setAttribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadStrokeColor ) );
422  elmt.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
423  elmt.setAttribute( QStringLiteral( "markerMode" ), mEndMarker );
424  elmt.setAttribute( QStringLiteral( "startMarkerMode" ), mStartMarker );
425  elmt.setAttribute( QStringLiteral( "startMarkerFile" ), startMarkerPath );
426  elmt.setAttribute( QStringLiteral( "endMarkerFile" ), endMarkerPath );
427 
428  return true;
429 }
430 
431 bool QgsLayoutItemPolyline::readPropertiesFromElement( const QDomElement &elmt, const QDomDocument &doc, const QgsReadWriteContext &context )
432 {
433  mArrowHeadWidth = elmt.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "2.0" ) ).toDouble();
434  mArrowHeadFillColor = QgsSymbolLayerUtils::decodeColor( elmt.attribute( QStringLiteral( "arrowHeadFillColor" ), QStringLiteral( "0,0,0,255" ) ) );
435  mArrowHeadStrokeColor = QgsSymbolLayerUtils::decodeColor( elmt.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QStringLiteral( "0,0,0,255" ) ) );
436  mArrowHeadStrokeWidth = elmt.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble();
437  // relative paths to absolute
438  QString startMarkerPath = elmt.attribute( QStringLiteral( "startMarkerFile" ), QString() );
439  QString endMarkerPath = elmt.attribute( QStringLiteral( "endMarkerFile" ), QString() );
442  mEndMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt() );
443  mStartMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "startMarkerMode" ), QStringLiteral( "0" ) ).toInt() );
444 
445  QgsLayoutNodesItem::readPropertiesFromElement( elmt, doc, context );
446 
448  return true;
449 }
450 
452 {
453  QRectF br = rect();
454 
455  double margin = std::max( mMaxSymbolBleed, computeMarkerMargin() );
456  if ( mEndMarker == ArrowHead )
457  {
458  margin += 0.5 * mArrowHeadWidth;
459  }
460  br.adjust( -margin, -margin, margin, margin );
461  mCurrentRectangle = br;
462 
463  // update
464  prepareGeometryChange();
465  update();
466 }
467 
468 
469 double QgsLayoutItemPolyline::computeMarkerMargin() const
470 {
471  double margin = 0;
472 
473  if ( mStartMarker == ArrowHead || mEndMarker == ArrowHead )
474  {
475  margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
476  }
477 
478  if ( mStartMarker == SvgMarker )
479  {
480  double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
481  margin = std::max( startMarkerMargin, margin );
482  }
483 
484  if ( mEndMarker == SvgMarker )
485  {
486  double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
487  margin = std::max( endMarkerMargin, margin );
488  }
489 
490  return margin;
491 }
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Layout item for node based polyline shapes.
void setArrowHeadWidth(double width)
Sets the width of line arrow heads in mm.
void setEndMarker(MarkerMode mode)
Sets the end marker mode, which controls what marker is drawn at the end of the line.
void setEndSvgMarkerPath(const QString &path)
Sets the path to a SVG marker to draw at the end of the line.
void _writeXmlStyle(QDomDocument &doc, QDomElement &elmt, const QgsReadWriteContext &context) const override
Method called in writeXml.
void setArrowHeadStrokeWidth(double width)
Sets the pen width in millimeters for the stroke of the arrow head.
void _readXmlStyle(const QDomElement &elmt, const QgsReadWriteContext &context) override
Method called in readXml.
void setArrowHeadFillColor(const QColor &color)
Sets the color used to fill the arrow head.
bool _removeNode(int nodeIndex) override
Method called in removeNode.
void setArrowHeadStrokeColor(const QColor &color)
Sets the color used to draw the stroke around the arrow head.
void setStartMarker(MarkerMode mode)
Sets the start marker mode, which controls what marker is drawn at the start of the line.
MarkerMode
Vertex marker mode.
@ ArrowHead
Show arrow marker.
@ SvgMarker
Show SVG marker.
int type() const override
QPainterPath shape() const override
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
QString displayName() const override
Gets item display name.
static QgsLayoutItemPolyline * create(QgsLayout *layout)
Returns a new polyline item for the specified layout.
bool _addNode(int indexPoint, QPointF newPoint, double radius) override
Method called in addNode.
QgsLineSymbol * symbol()
Returns the line symbol used to draw the shape.
void setSymbol(QgsLineSymbol *symbol)
Sets the symbol used to draw the shape.
QIcon icon() const override
Returns the item's icon.
double arrowHeadWidth() const
Returns the width of line arrow heads in mm.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void _draw(QgsLayoutItemRenderContext &context, const QStyleOptionGraphicsItem *itemStyle=nullptr) override
Method called in paint.
void setStartSvgMarkerPath(const QString &path)
Sets the path to a SVG marker to draw at the start of the line.
QgsLayoutItemPolyline(QgsLayout *layout)
Constructor for QgsLayoutItemPolyline for the specified layout.
@ LayoutPolyline
Polyline shape item.
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:45
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
virtual QString uuid() const
Returns the item identification string.
QString id() const
Returns the item's ID name.
void frameChanged()
Emitted if the item's frame style changes.
An abstract layout item that provides generic methods for node based shapes such as polygon or polyli...
double mMaxSymbolBleed
Max symbol bleed.
QRectF mCurrentRectangle
Current bounding rectangle of shape.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
bool setSelectedNode(int index)
Selects a node by index.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void updateSceneRect()
Update the current scene rectangle for this item.
double computeDistance(QPointF pt1, QPointF pt2) const
Compute an euclidean distance between 2 nodes.
QPolygonF mPolygon
Shape's nodes.
const QgsLayout * layout() const
Returns the layout the object is attached to.
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1204
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2295
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Definition: qgssymbol.cpp:1567
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Scoped object for saving and restoring a QPainter object's state.
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1201
QByteArray svgContent(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >(), bool *isMissingImage=nullptr)
Gets the SVG content corresponding to the given path.
static QColor decodeColor(const QString &str)
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
static QString encodeColor(const QColor &color)
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
Contains information relating to the style entity currently being visited.