29 #include <QSvgRenderer> 
   31 #include <QGraphicsPathItem> 
   37   createDefaultPolylineStyleSymbol();
 
   43   createDefaultPolylineStyleSymbol();
 
   70   if ( indexPoint == ( 
mPolygon.size() - 1 ) )
 
   72     if ( distEnd < radius )
 
   74     else if ( distStart < radius )
 
   78     mPolygon.insert( indexPoint + 1, newPoint );
 
   85   if ( index < 0 || index >= 
mPolygon.size() )
 
   94     int newSelectNode = index;
 
  103 void QgsLayoutItemPolyline::createDefaultPolylineStyleSymbol()
 
  105   QVariantMap properties;
 
  106   properties.insert( QStringLiteral( 
"color" ), QStringLiteral( 
"0,0,0,255" ) );
 
  107   properties.insert( QStringLiteral( 
"width" ), QStringLiteral( 
"0.3" ) );
 
  108   properties.insert( QStringLiteral( 
"capstyle" ), QStringLiteral( 
"square" ) );
 
  114 void QgsLayoutItemPolyline::refreshSymbol()
 
  116   if ( 
auto *lLayout = 
layout() )
 
  127 void QgsLayoutItemPolyline::drawStartMarker( QPainter *painter )
 
  132   switch ( mStartMarker )
 
  134     case MarkerMode::NoMarker:
 
  137     case MarkerMode::ArrowHead:
 
  141       double angle = startLine.angle();
 
  146     case MarkerMode::SvgMarker:
 
  150       double angle = startLine.angle();
 
  151       drawSvgMarker( painter, 
mPolygon.at( 0 ), 
angle, mStartMarkerFile, mStartArrowHeadHeight );
 
  158 void QgsLayoutItemPolyline::drawEndMarker( QPainter *painter )
 
  163   switch ( mEndMarker )
 
  165     case MarkerMode::NoMarker:
 
  168     case MarkerMode::ArrowHead:
 
  172       double angle = endLine.angle();
 
  175       QVector2D dir = QVector2D( endLine.dx(), endLine.dy() ).normalized();
 
  176       QPointF endPoint = endLine.p2();
 
  177       endPoint += ( dir * 0.5 * mArrowHeadWidth ).toPointF();
 
  179       drawArrow( painter, endPoint, 
angle );
 
  182     case MarkerMode::SvgMarker:
 
  186       double angle = endLine.angle();
 
  187       drawSvgMarker( painter, endLine.p2(), 
angle, mEndMarkerFile, mEndArrowHeadHeight );
 
  193 void QgsLayoutItemPolyline::drawArrow( QPainter *painter, QPointF center, 
double angle )
 
  198   p.setColor( mArrowHeadStrokeColor );
 
  199   p.setWidthF( mArrowHeadStrokeWidth );
 
  200   painter->setPen( p );
 
  202   b.setColor( mArrowHeadFillColor );
 
  203   painter->setBrush( b );
 
  205   drawArrowHead( painter, center.x(), center.y(), 
angle, mArrowHeadWidth );
 
  208 void QgsLayoutItemPolyline::updateMarkerSvgSizes()
 
  214 void QgsLayoutItemPolyline::drawArrowHead( QPainter *p, 
const double x, 
const double y, 
const double angle, 
const double arrowHeadWidth )
 
  219   double angleRad = 
angle / 180.0 * M_PI;
 
  220   QPointF middlePoint( x, y );
 
  226   QPointF p1Rotated, p2Rotated;
 
  227   p1Rotated.setX( p1.x() * std::cos( angleRad ) + p1.y() * -std::sin( angleRad ) );
 
  228   p1Rotated.setY( p1.x() * std::sin( angleRad ) + p1.y() * std::cos( angleRad ) );
 
  229   p2Rotated.setX( p2.x() * std::cos( angleRad ) + p2.y() * -std::sin( angleRad ) );
 
  230   p2Rotated.setY( p2.x() * std::sin( angleRad ) + p2.y() * std::cos( angleRad ) );
 
  232   QPolygonF arrowHeadPoly;
 
  233   arrowHeadPoly << middlePoint;
 
  234   arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
 
  235   arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
 
  236   QPen arrowPen = p->pen();
 
  237   arrowPen.setJoinStyle( Qt::RoundJoin );
 
  238   QBrush arrowBrush = p->brush();
 
  239   arrowBrush.setStyle( Qt::SolidPattern );
 
  240   p->setPen( arrowPen );
 
  241   p->setBrush( arrowBrush );
 
  242   arrowBrush.setStyle( Qt::SolidPattern );
 
  243   p->drawPolygon( arrowHeadPoly );
 
  246 void QgsLayoutItemPolyline::drawSvgMarker( QPainter *p, QPointF point, 
double angle, 
const QString &markerPath, 
double height )
 const 
  251   if ( mArrowHeadWidth <= 0 || height <= 0 )
 
  257   if ( markerPath.isEmpty() )
 
  261   const QByteArray &svgContent = 
QgsApplication::svgCache()->
svgContent( markerPath, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
 
  263   r.load( svgContent );
 
  266   p->translate( point.x(), point.y() );
 
  268   p->translate( -mArrowHeadWidth / 2.0, -height / 2.0 );
 
  269   r.render( p, QRectF( 0, 0, mArrowHeadWidth, height ) );
 
  274   if ( !
id().isEmpty() )
 
  277   return tr( 
"<Polyline>" );
 
  285   QTransform t = QTransform::fromScale( scale, scale );
 
  287   mPolylineStyleSymbol->startRender( context.
renderContext() );
 
  300   mPolylineStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( elmt, context ) );
 
  323   mArrowHeadWidth = width;
 
  324   updateMarkerSvgSizes();
 
  333   QPainterPathStroker ps;
 
  336   QPainterPath strokedOutline = ps.createStroke( path );
 
  338   return strokedOutline;
 
  343   return mPolylineStyleSymbol.get();
 
  349   mStartMarkerFile = path;
 
  350   if ( path.isEmpty() || !r.load( path ) )
 
  352     mStartArrowHeadHeight = 0;
 
  357     QRect viewBox = r.viewBox();
 
  358     mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
 
  366   mEndMarkerFile = path;
 
  367   if ( path.isEmpty() || !r.load( path ) )
 
  369     mEndArrowHeadHeight = 0;
 
  374     QRect viewBox = r.viewBox();
 
  375     mEndArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
 
  382   mArrowHeadStrokeColor = color;
 
  388   mArrowHeadFillColor = color;
 
  394   mArrowHeadStrokeWidth = width;
 
  401   if ( mPolylineStyleSymbol )
 
  414                          mPolylineStyleSymbol.get(),
 
  417   elmt.appendChild( pe );
 
  428   elmt.setAttribute( QStringLiteral( 
"arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
 
  431   elmt.setAttribute( QStringLiteral( 
"outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
 
  432   elmt.setAttribute( QStringLiteral( 
"markerMode" ), mEndMarker );
 
  433   elmt.setAttribute( QStringLiteral( 
"startMarkerMode" ), mStartMarker );
 
  434   elmt.setAttribute( QStringLiteral( 
"startMarkerFile" ), startMarkerPath );
 
  435   elmt.setAttribute( QStringLiteral( 
"endMarkerFile" ), endMarkerPath );
 
  442   mArrowHeadWidth = elmt.attribute( QStringLiteral( 
"arrowHeadWidth" ), QStringLiteral( 
"2.0" ) ).toDouble();
 
  445   mArrowHeadStrokeWidth = elmt.attribute( QStringLiteral( 
"outlineWidth" ), QStringLiteral( 
"1.0" ) ).toDouble();
 
  447   QString startMarkerPath = elmt.attribute( QStringLiteral( 
"startMarkerFile" ), QString() );
 
  448   QString endMarkerPath = elmt.attribute( QStringLiteral( 
"endMarkerFile" ), QString() );
 
  467     margin += 0.5 * mArrowHeadWidth;
 
  469   br.adjust( -margin, -margin, margin, margin );
 
  473   prepareGeometryChange();
 
  478 double QgsLayoutItemPolyline::computeMarkerMargin()
 const 
  484     margin = mArrowHeadStrokeWidth / 2.0 + mArrowHeadWidth * M_SQRT2;
 
  489     double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
 
  490     margin = std::max( startMarkerMargin, margin );
 
  495     double endMarkerMargin = std::sqrt( 0.25 * ( mEndArrowHeadHeight * mEndArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
 
  496     margin = std::max( endMarkerMargin, margin );
 
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...
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.
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.
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.
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.