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()
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 );