QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
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
18#include "moc_qgslayoutitempolyline.cpp"
20#include "qgssymbollayerutils.h"
21#include "qgscolorutils.h"
22#include "qgssymbol.h"
23#include "qgslayout.h"
25#include "qgslayoututils.h"
26#include "qgsreadwritecontext.h"
27#include "qgssvgcache.h"
29#include "qgslinesymbol.h"
30
31#include <QSvgRenderer>
32#include <limits>
33#include <QGraphicsPathItem>
34#include <QVector2D>
35
37 : QgsLayoutNodesItem( layout )
38{
39 createDefaultPolylineStyleSymbol();
40}
41
42QgsLayoutItemPolyline::QgsLayoutItemPolyline( const QPolygonF &polyline, QgsLayout *layout )
43 : QgsLayoutNodesItem( polyline, layout )
44{
45 createDefaultPolylineStyleSymbol();
46}
47
49
54
59
61{
62 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemPolyline.svg" ) );
63}
64
65bool QgsLayoutItemPolyline::_addNode( const int indexPoint,
66 QPointF newPoint,
67 const double radius )
68{
69 const double distStart = computeDistance( newPoint, mPolygon[0] );
70 const double distEnd = computeDistance( newPoint, mPolygon[mPolygon.size() - 1] );
71
72 if ( indexPoint == ( mPolygon.size() - 1 ) )
73 {
74 if ( distEnd < radius )
75 mPolygon.append( newPoint );
76 else if ( distStart < radius )
77 mPolygon.insert( 0, newPoint );
78 }
79 else
80 mPolygon.insert( indexPoint + 1, newPoint );
81
82 return true;
83}
84
86{
87 if ( index < 0 || index >= mPolygon.size() || mPolygon.size() <= 2 )
88 return false;
89
90 mPolygon.remove( index );
91
92 int newSelectNode = index;
93 if ( index >= mPolygon.size() )
94 newSelectNode = mPolygon.size() - 1;
95 setSelectedNode( newSelectNode );
96
97 return true;
98}
99
100void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
101{
102 QVariantMap properties;
103 properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
104 properties.insert( QStringLiteral( "width" ), QStringLiteral( "0.3" ) );
105 properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
106
107 mPolylineStyleSymbol.reset( QgsLineSymbol::createSimple( properties ) );
108 refreshSymbol();
109}
110
111void QgsLayoutItemPolyline::refreshSymbol()
112{
113 if ( auto *lLayout = layout() )
114 {
115 const QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( lLayout, nullptr, lLayout->renderContext().dpi() );
116 mMaxSymbolBleed = ( 25.4 / lLayout->renderContext().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mPolylineStyleSymbol.get(), rc );
117 }
118
120
121 emit frameChanged();
122}
123
124void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
125{
126 if ( mPolygon.size() < 2 )
127 return;
128
129 switch ( mStartMarker )
130 {
132 break;
133
135 {
136 // calculate angle at start of line
137 const QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
138 const double angle = startLine.angle();
139 drawArrow( painter, mPolygon.at( 0 ), angle );
140 break;
141 }
142
144 {
145 // calculate angle at start of line
146 const QLineF startLine( mPolygon.at( 0 ), mPolygon.at( 1 ) );
147 const double angle = startLine.angle();
148 drawSvgMarker( painter, mPolygon.at( 0 ), angle, mStartMarkerFile, mStartArrowHeadHeight );
149 break;
150 }
151 }
152
153}
154
155void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
156{
157 if ( mPolygon.size() < 2 )
158 return;
159
160 switch ( mEndMarker )
161 {
163 break;
164
166 {
167 // calculate angle at end of line
168 const QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
169 const double angle = endLine.angle();
170
171 //move end point depending on arrow width
172 const QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
173 QPointF endPoint = endLine.p2();
174 endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
175
176 drawArrow( painter, endPoint, angle );
177 break;
178 }
180 {
181 // calculate angle at end of line
182 const QLineF endLine( mPolygon.at( mPolygon.count() - 2 ), mPolygon.at( mPolygon.count() - 1 ) );
183 const double angle = endLine.angle();
184 drawSvgMarker( painter, endLine.p2(), angle, mEndMarkerFile, mEndArrowHeadHeight );
185 break;
186 }
187 }
188}
189
190void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center, double angle )
191{
192 // translate angle from ccw from axis to cw from north
193 angle = 90 - angle;
194 QPen p;
195 p.setColor( mArrowHeadStrokeColor );
196 p.setWidthF( mArrowHeadStrokeWidth );
197 painter->setPen( p );
198 QBrush b;
199 b.setColor( mArrowHeadFillColor );
200 painter->setBrush( b );
201
202 drawArrowHead( painter, center.x(), center.y(), angle, mArrowHeadWidth );
203}
204
205void QgsLayoutItemPolyline::updateMarkerSvgSizes()
206{
207 setStartSvgMarkerPath( mStartMarkerFile );
208 setEndSvgMarkerPath( mEndMarkerFile );
209}
210
211void QgsLayoutItemPolyline::drawArrowHead( QPainter *p, const double x, const double y, const double angle, const double arrowHeadWidth )
212{
213 if ( !p )
214 return;
215
216 const double angleRad = angle / 180.0 * M_PI;
217 const QPointF middlePoint( x, y );
218
219 //rotate both arrow points
220 const QPointF p1 = QPointF( -arrowHeadWidth / 2.0, arrowHeadWidth );
221 const QPointF p2 = QPointF( arrowHeadWidth / 2.0, arrowHeadWidth );
222
223 QPointF p1Rotated, p2Rotated;
224 p1Rotated.setX( p1.x() * std::cos( angleRad ) + p1.y() * -std::sin( angleRad ) );
225 p1Rotated.setY( p1.x() * std::sin( angleRad ) + p1.y() * std::cos( angleRad ) );
226 p2Rotated.setX( p2.x() * std::cos( angleRad ) + p2.y() * -std::sin( angleRad ) );
227 p2Rotated.setY( p2.x() * std::sin( angleRad ) + p2.y() * std::cos( angleRad ) );
228
229 QPolygonF arrowHeadPoly;
230 arrowHeadPoly << middlePoint;
231 arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
232 arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
233 QPen arrowPen = p->pen();
234 arrowPen.setJoinStyle( Qt::RoundJoin );
235 QBrush arrowBrush = p->brush();
236 arrowBrush.setStyle( Qt::SolidPattern );
237 p->setPen( arrowPen );
238 p->setBrush( arrowBrush );
239 arrowBrush.setStyle( Qt::SolidPattern );
240 p->drawPolygon( arrowHeadPoly );
241}
242
243void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point, double angle, const QString &markerPath, double height ) const
244{
245 // translate angle from ccw from axis to cw from north
246 angle = 90 - angle;
247
248 if ( mArrowHeadWidth <= 0 || height <= 0 )
249 {
250 //bad image size
251 return;
252 }
253
254 if ( markerPath.isEmpty() )
255 return;
256
257 QSvgRenderer r;
258 const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
259 1.0 );
260 r.load( svgContent );
261
262 const QgsScopedQPainterState painterState( p );
263 p->translate( point.x(), point.y() );
264 p->rotate( angle );
265 p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
266 r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
267}
268
270{
271 if ( !id().isEmpty() )
272 return id();
273
274 return tr( "<Polyline>" );
275}
276
277void QgsLayoutItemPolyline::_draw( QgsLayoutItemRenderContext &context, const QStyleOptionGraphicsItem * )
278{
279 QgsRenderContext renderContext = context.renderContext();
280 // symbol clipping messes with geometry generators used in the symbol for this item, and has no
281 // valid use here. See https://github.com/qgis/QGIS/issues/58909
283
284 const QgsScopedQPainterState painterState( renderContext.painter() );
285 //setup painter scaling to dots so that raster symbology is drawn to scale
286 const double scale = renderContext.convertToPainterUnits( 1, Qgis::RenderUnit::Millimeters );
287 const QTransform t = QTransform::fromScale( scale, scale );
288
289 mPolylineStyleSymbol->startRender( renderContext );
290 mPolylineStyleSymbol->renderPolyline( t.map( mPolygon ), nullptr, renderContext );
291 mPolylineStyleSymbol->stopRender( renderContext );
292
293 // painter is scaled to dots, so scale back to layout units
294 renderContext.painter()->scale( renderContext.scaleFactor(), renderContext.scaleFactor() );
295
296 drawStartMarker( renderContext.painter() );
297 drawEndMarker( renderContext.painter() );
298}
299
300void QgsLayoutItemPolyline::_readXmlStyle( const QDomElement &elmt, const QgsReadWriteContext &context )
301{
302 mPolylineStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( elmt, context ) );
303}
304
306{
307 mPolylineStyleSymbol.reset( static_cast<QgsLineSymbol *>( symbol->clone() ) );
308 refreshSymbol();
309}
310
312{
313 mStartMarker = mode;
314 update();
315}
316
318{
319 mEndMarker = mode;
320 update();
321}
322
324{
325 mArrowHeadWidth = width;
326 updateMarkerSvgSizes();
327 update();
328}
329
331{
332 QPainterPath path;
333 path.addPolygon( mPolygon );
334
335 QPainterPathStroker ps;
336
337 ps.setWidth( 2 * mMaxSymbolBleed );
338 const QPainterPath strokedOutline = ps.createStroke( path );
339
340 return strokedOutline;
341}
342
344{
345 // A Polyline is valid if it has at least 2 unique points
346 QList<QPointF> uniquePoints;
347 int seen = 0;
348 for ( QPointF point : mPolygon )
349 {
350 if ( !uniquePoints.contains( point ) )
351 {
352 uniquePoints.append( point );
353 if ( ++seen > 1 )
354 return true;
355 }
356 }
357 return false;
358}
359
361{
362 return mPolylineStyleSymbol.get();
363}
364
366{
367 QSvgRenderer r;
368 mStartMarkerFile = path;
369 if ( path.isEmpty() || !r.load( path ) )
370 {
371 mStartArrowHeadHeight = 0;
372 }
373 else
374 {
375 //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
376 const QRect viewBox = r.viewBox();
377 mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
378 }
380}
381
383{
384 QSvgRenderer r;
385 mEndMarkerFile = path;
386 if ( path.isEmpty() || !r.load( path ) )
387 {
388 mEndArrowHeadHeight = 0;
389 }
390 else
391 {
392 //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
393 const QRect viewBox = r.viewBox();
394 mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
395 }
397}
398
400{
401 mArrowHeadStrokeColor = color;
402 update();
403}
404
406{
407 mArrowHeadFillColor = color;
408 update();
409}
410
412{
413 mArrowHeadStrokeWidth = width;
415 update();
416}
417
419{
420 if ( mPolylineStyleSymbol )
421 {
422 QgsStyleSymbolEntity entity( mPolylineStyleSymbol.get() );
423 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
424 return false;
425 }
426
427 return true;
428}
429
430void QgsLayoutItemPolyline::_writeXmlStyle( QDomDocument &doc, QDomElement &elmt, const QgsReadWriteContext &context ) const
431{
432 const QDomElement pe = QgsSymbolLayerUtils::saveSymbol( QString(),
433 mPolylineStyleSymbol.get(),
434 doc,
435 context );
436 elmt.appendChild( pe );
437}
438
439bool QgsLayoutItemPolyline::writePropertiesToElement( QDomElement &elmt, QDomDocument &doc, const QgsReadWriteContext &context ) const
440{
442
443 // absolute paths to relative
444 const QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, context.pathResolver() );
445 const QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, context.pathResolver() );
446
447 elmt.setAttribute( QStringLiteral( "arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
448 elmt.setAttribute( QStringLiteral( "arrowHeadFillColor" ), QgsColorUtils::colorToString( mArrowHeadFillColor ) );
449 elmt.setAttribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsColorUtils::colorToString( mArrowHeadStrokeColor ) );
450 elmt.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
451 elmt.setAttribute( QStringLiteral( "markerMode" ), mEndMarker );
452 elmt.setAttribute( QStringLiteral( "startMarkerMode" ), mStartMarker );
453 elmt.setAttribute( QStringLiteral( "startMarkerFile" ), startMarkerPath );
454 elmt.setAttribute( QStringLiteral( "endMarkerFile" ), endMarkerPath );
455
456 return true;
457}
458
459bool QgsLayoutItemPolyline::readPropertiesFromElement( const QDomElement &elmt, const QDomDocument &doc, const QgsReadWriteContext &context )
460{
461 mArrowHeadWidth = elmt.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "2.0" ) ).toDouble();
462 mArrowHeadFillColor = QgsColorUtils::colorFromString( elmt.attribute( QStringLiteral( "arrowHeadFillColor" ), QStringLiteral( "0,0,0,255" ) ) );
463 mArrowHeadStrokeColor = QgsColorUtils::colorFromString( elmt.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QStringLiteral( "0,0,0,255" ) ) );
464 mArrowHeadStrokeWidth = elmt.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble();
465 // relative paths to absolute
466 const QString startMarkerPath = elmt.attribute( QStringLiteral( "startMarkerFile" ), QString() );
467 const QString endMarkerPath = elmt.attribute( QStringLiteral( "endMarkerFile" ), QString() );
470 mEndMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt() );
471 mStartMarker = static_cast< QgsLayoutItemPolyline::MarkerMode >( elmt.attribute( QStringLiteral( "startMarkerMode" ), QStringLiteral( "0" ) ).toInt() );
472
474
476 return true;
477}
478
480{
481 QRectF br = rect();
482
483 double margin = std::max( mMaxSymbolBleed, computeMarkerMargin() );
484 if ( mEndMarker == ArrowHead )
485 {
486 margin += 0.5 * mArrowHeadWidth;
487 }
488 br.adjust( -margin, -margin, margin, margin );
489 prepareGeometryChange();
491
492 // update
493 update();
494}
495
496
497double QgsLayoutItemPolyline::computeMarkerMargin() const
498{
499 double margin = 0;
500
501 if ( mStartMarker == ArrowHead || mEndMarker == ArrowHead )
502 {
503 margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
504 }
505
506 if ( mStartMarker == SvgMarker )
507 {
508 const double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
509 margin = std::max( startMarkerMargin, margin );
510 }
511
512 if ( mEndMarker == SvgMarker )
513 {
514 const double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
515 margin = std::max( endMarkerMargin, margin );
516 }
517
518 return margin;
519}
@ Millimeters
Millimeters.
@ DisableSymbolClippingToExtent
Force symbol clipping to map extent to be disabled in all situations. This will result in slower rend...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
Layout item for node based polyline shapes.
bool isValid() const override
Must be reimplemented in subclasses.
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.
QgsLineSymbol * symbol()
Returns the line symbol used to draw the shape.
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.
@ NoMarker
Don't show marker.
QPainterPath shape() const override
~QgsLayoutItemPolyline() 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.
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.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
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:49
A line symbol type, for rendering LineString and MultiLineString geometries.
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
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.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
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:1396
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 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 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.
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)
Contains information relating to the style entity currently being visited.