33#include <QGraphicsPathItem>
35#include <QSvgRenderer>
38#include "moc_qgslayoutitempolyline.cpp"
40using namespace Qt::StringLiterals;
45 createDefaultPolylineStyleSymbol();
51 createDefaultPolylineStyleSymbol();
76 if ( indexPoint == (
mPolygon.size() - 1 ) )
78 if ( distEnd < radius )
80 else if ( distStart < radius )
84 mPolygon.insert( indexPoint + 1, newPoint );
96 int newSelectNode = index;
104void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
106 QVariantMap properties;
107 properties.insert( u
"color"_s, u
"0,0,0,255"_s );
108 properties.insert( u
"width"_s, u
"0.3"_s );
109 properties.insert( u
"capstyle"_s, u
"square"_s );
115void QgsLayoutItemPolyline::refreshSymbol()
117 if (
auto *lLayout =
layout() )
128void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
133 switch ( mStartMarker )
144 const double angle = startLine.angle();
147 const QVector2D dir = QVector2D( startLine.dx(), startLine.dy() ).normalized();
148 QPointF startPoint = startLine.p2();
149 startPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
151 drawArrow( painter, startPoint, angle );
153 else if ( mVersion == 1 )
156 const double angle = startLine.angle();
157 drawArrow( painter,
mPolygon.at( 0 ), angle );
171 else if ( mVersion == 1 )
175 const double angle = startLine.angle();
176 drawSvgMarker( painter,
mPolygon.at( 0 ), angle, mStartMarkerFile, mStartArrowHeadHeight );
182void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
187 switch ( mEndMarker )
196 const double angle = endLine.angle();
199 const QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
200 QPointF endPoint = endLine.p2();
201 endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
203 drawArrow( painter, endPoint, angle );
210 const double angle = endLine.angle();
211 drawSvgMarker( painter, endLine.p2(), angle, mEndMarkerFile, mEndArrowHeadHeight );
217void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center,
double angle )
222 p.setColor( mArrowHeadStrokeColor );
223 p.setWidthF( mArrowHeadStrokeWidth );
224 painter->setPen( p );
226 b.setColor( mArrowHeadFillColor );
227 painter->setBrush( b );
229 drawArrowHead( painter, center.x(), center.y(), angle, mArrowHeadWidth );
232void QgsLayoutItemPolyline::updateMarkerSvgSizes()
238void QgsLayoutItemPolyline::drawArrowHead( QPainter *p,
const double x,
const double y,
const double angle,
const double arrowHeadWidth )
243 const double angleRad =
angle / 180.0 * M_PI;
244 const QPointF middlePoint( x, y );
250 QPointF p1Rotated, p2Rotated;
251 p1Rotated.setX( p1.x() * std::cos( angleRad ) + p1.y() * -std::sin( angleRad ) );
252 p1Rotated.setY( p1.x() * std::sin( angleRad ) + p1.y() * std::cos( angleRad ) );
253 p2Rotated.setX( p2.x() * std::cos( angleRad ) + p2.y() * -std::sin( angleRad ) );
254 p2Rotated.setY( p2.x() * std::sin( angleRad ) + p2.y() * std::cos( angleRad ) );
256 QPolygonF arrowHeadPoly;
257 arrowHeadPoly << middlePoint;
258 arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
259 arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
260 QPen arrowPen = p->pen();
261 arrowPen.setJoinStyle( Qt::RoundJoin );
262 QBrush arrowBrush = p->brush();
263 arrowBrush.setStyle( Qt::SolidPattern );
264 p->setPen( arrowPen );
265 p->setBrush( arrowBrush );
266 arrowBrush.setStyle( Qt::SolidPattern );
267 p->drawPolygon( arrowHeadPoly );
270void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point,
double angle,
const QString &markerPath,
double height )
const
275 if ( mArrowHeadWidth <= 0 || height <= 0 )
281 if ( markerPath.isEmpty() )
285 const QByteArray &svgContent =
QgsApplication::svgCache()->
svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth, 1.0 );
286 r.load( svgContent );
288 const QgsScopedQPainterState painterState( p );
289 p->translate( point.x(), point.y() );
291 p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
292 r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
297 if ( !
id().isEmpty() )
300 return tr(
"<Polyline>" );
313 const QTransform t = QTransform::fromScale( scale, scale );
315 mPolylineStyleSymbol->startRender( renderContext );
316 mPolylineStyleSymbol->renderPolyline( t.map(
mPolygon ),
nullptr, renderContext );
317 mPolylineStyleSymbol->stopRender( renderContext );
322 drawStartMarker( renderContext.
painter() );
323 drawEndMarker( renderContext.
painter() );
351 mArrowHeadWidth = width;
352 updateMarkerSvgSizes();
361 QPainterPathStroker ps;
364 const QPainterPath strokedOutline = ps.createStroke( path );
366 return strokedOutline;
372 QList<QPointF> uniquePoints;
376 if ( !uniquePoints.contains( point ) )
378 uniquePoints.append( point );
388 return mPolylineStyleSymbol.get();
394 mStartMarkerFile = path;
395 if ( path.isEmpty() || !r.load( path ) )
397 mStartArrowHeadHeight = 0;
402 const QRect viewBox = r.viewBox();
403 mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
411 mEndMarkerFile = path;
412 if ( path.isEmpty() || !r.load( path ) )
414 mEndArrowHeadHeight = 0;
419 const QRect viewBox = r.viewBox();
420 mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
427 mArrowHeadStrokeColor = color;
433 mArrowHeadFillColor = color;
439 mArrowHeadStrokeWidth = width;
446 if ( mPolylineStyleSymbol )
459 elmt.appendChild( pe );
470 elmt.setAttribute( u
"arrowHeadWidth"_s, QString::number( mArrowHeadWidth ) );
473 elmt.setAttribute( u
"outlineWidth"_s, QString::number( mArrowHeadStrokeWidth ) );
474 elmt.setAttribute( u
"markerMode"_s, mEndMarker );
475 elmt.setAttribute( u
"startMarkerMode"_s, mStartMarker );
476 elmt.setAttribute( u
"startMarkerFile"_s, startMarkerPath );
477 elmt.setAttribute( u
"endMarkerFile"_s, endMarkerPath );
478 elmt.setAttribute( u
"version"_s, mVersion );
485 mArrowHeadWidth = elmt.attribute( u
"arrowHeadWidth"_s, u
"2.0"_s ).toDouble();
488 mArrowHeadStrokeWidth = elmt.attribute( u
"outlineWidth"_s, u
"1.0"_s ).toDouble();
490 const QString startMarkerPath = elmt.attribute( u
"startMarkerFile"_s, QString() );
491 const QString endMarkerPath = elmt.attribute( u
"endMarkerFile"_s, QString() );
496 mVersion = elmt.attribute( u
"version"_s, u
"1"_s ).toInt();
511 margin += 0.5 * mArrowHeadWidth;
513 br.adjust( -margin, -margin, margin, margin );
514 prepareGeometryChange();
522double QgsLayoutItemPolyline::computeMarkerMargin()
const
528 margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
533 const double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
534 margin = std::max( startMarkerMargin, margin );
539 const double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
540 margin = std::max( endMarkerMargin, margin );
@ 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.
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 updateBoundingRect() override
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.
@ SvgMarker
Show SVG marker.
@ NoMarker
Don't show marker.
int type() const override
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.
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.
QgsLayoutNodesItem(QgsLayout *layout)
Constructor for QgsLayoutNodesItem, attached to the specified layout.
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.
A line symbol type, for rendering LineString and MultiLineString geometries.
static std::unique_ptr< QgsLineSymbol > createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
A container for the context for various read/write operations on 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.
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 > ¶meters=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 std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
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.