27 #include <QSvgRenderer>
29 #include <QGraphicsPathItem>
35 createDefaultPolylineStyleSymbol();
41 createDefaultPolylineStyleSymbol();
66 if ( indexPoint == (
mPolygon.size() - 1 ) )
68 if ( distEnd < radius )
70 else if ( distStart < radius )
74 mPolygon.insert( indexPoint + 1, newPoint );
81 if ( index < 0 || index >=
mPolygon.size() )
90 int newSelectNode = index;
99 void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
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" ) );
110 void QgsLayoutItemPolyline::refreshSymbol()
112 if (
auto *lLayout =
layout() )
123 void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
128 switch ( mStartMarker )
130 case MarkerMode::NoMarker:
133 case MarkerMode::ArrowHead:
137 double angle = startLine.angle();
142 case MarkerMode::SvgMarker:
146 double angle = startLine.angle();
147 drawSvgMarker( painter,
mPolygon.at( 0 ),
angle, mStartMarkerFile, mStartArrowHeadHeight );
154 void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
159 switch ( mEndMarker )
161 case MarkerMode::NoMarker:
164 case MarkerMode::ArrowHead:
168 double angle = endLine.angle();
171 QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
172 QPointF endPoint = endLine.p2();
173 endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
175 drawArrow( painter, endPoint,
angle );
178 case MarkerMode::SvgMarker:
182 double angle = endLine.angle();
183 drawSvgMarker( painter, endLine.p2(),
angle, mEndMarkerFile, mEndArrowHeadHeight );
189 void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center,
double angle )
194 p.setColor( mArrowHeadStrokeColor );
195 p.setWidthF( mArrowHeadStrokeWidth );
196 painter->setPen( p );
198 b.setColor( mArrowHeadFillColor );
199 painter->setBrush( b );
201 drawArrowHead( painter, center.x(), center.y(),
angle, mArrowHeadWidth );
204 void QgsLayoutItemPolyline::updateMarkerSvgSizes()
210 void QgsLayoutItemPolyline::drawArrowHead( QPainter *p,
const double x,
const double y,
const double angle,
const double arrowHeadWidth )
215 double angleRad =
angle / 180.0 * M_PI;
216 QPointF middlePoint( x, y );
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 ) );
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 );
242 void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point,
double angle,
const QString &markerPath,
double height )
const
247 if ( mArrowHeadWidth <= 0 || height <= 0 )
253 if ( markerPath.isEmpty() )
257 const QByteArray &svgContent =
QgsApplication::svgCache()->
svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
259 r.load( svgContent );
262 p->translate( point.x(), point.y() );
264 p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
265 r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
270 if ( !
id().isEmpty() )
273 return tr(
"<Polyline>" );
281 QTransform t = QTransform::fromScale( scale, scale );
283 mPolylineStyleSymbol->startRender( context.
renderContext() );
296 mPolylineStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( elmt, context ) );
319 mArrowHeadWidth = width;
320 updateMarkerSvgSizes();
329 QPainterPathStroker ps;
332 QPainterPath strokedOutline = ps.createStroke( path );
334 return strokedOutline;
340 mStartMarkerFile = path;
341 if ( path.isEmpty() || !r.load( path ) )
343 mStartArrowHeadHeight = 0;
348 QRect viewBox = r.viewBox();
349 mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
357 mEndMarkerFile = path;
358 if ( path.isEmpty() || !r.load( path ) )
360 mEndArrowHeadHeight = 0;
365 QRect viewBox = r.viewBox();
366 mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
373 mArrowHeadStrokeColor = color;
379 mArrowHeadFillColor = color;
385 mArrowHeadStrokeWidth = width;
392 if ( mPolylineStyleSymbol )
405 mPolylineStyleSymbol.get(),
408 elmt.appendChild( pe );
419 elmt.setAttribute( QStringLiteral(
"arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
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 );
433 mArrowHeadWidth = elmt.attribute( QStringLiteral(
"arrowHeadWidth" ), QStringLiteral(
"2.0" ) ).toDouble();
436 mArrowHeadStrokeWidth = elmt.attribute( QStringLiteral(
"outlineWidth" ), QStringLiteral(
"1.0" ) ).toDouble();
438 QString startMarkerPath = elmt.attribute( QStringLiteral(
"startMarkerFile" ), QString() );
439 QString endMarkerPath = elmt.attribute( QStringLiteral(
"endMarkerFile" ), QString() );
458 margin += 0.5 * mArrowHeadWidth;
460 br.adjust( -margin, -margin, margin, margin );
464 prepareGeometryChange();
469 double QgsLayoutItemPolyline::computeMarkerMargin()
const
475 margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
480 double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
481 margin = std::max( startMarkerMargin, margin );
486 double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
487 margin = std::max( endMarkerMargin, margin );
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 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.
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.
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.
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.
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.
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 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.
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.