QGIS API Documentation  2.99.0-Master (19b062c)
qgscomposerarrow.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerarrow.cpp
3  ----------------------
4  begin : November 2009
5  copyright : (C) 2009 by Marco Hugentobler
6  email : marco@hugis.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscomposerarrow.h"
19 #include "qgscomposition.h"
20 #include "qgscomposerutils.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgssvgcache.h"
23 #include "qgsmapsettings.h"
24 #include "qgspathresolver.h"
25 #include "qgsreadwritecontext.h"
26 #include <QPainter>
27 #include <QSvgRenderer>
28 #include <QVector2D>
29 
30 #include <cmath>
31 
33  : QgsComposerItem( c )
34  , mStartPoint( 0, 0 )
35  , mStopPoint( 0, 0 )
36  , mStartXIdx( 0 )
37  , mStartYIdx( 0 )
38  , mMarkerMode( DefaultMarker )
39  , mArrowHeadStrokeWidth( 1.0 )
40  , mArrowHeadStrokeColor( Qt::black )
41  , mArrowHeadFillColor( Qt::black )
42  , mBoundsBehavior( 24 )
43 
44 {
45  init();
46 }
47 
48 QgsComposerArrow::QgsComposerArrow( QPointF startPoint, QPointF stopPoint, QgsComposition *c )
49  : QgsComposerItem( c )
50  , mStartPoint( startPoint )
51  , mStopPoint( stopPoint )
52  , mMarkerMode( DefaultMarker )
53  , mArrowHeadStrokeWidth( 1.0 )
54  , mArrowHeadStrokeColor( Qt::black )
55  , mArrowHeadFillColor( Qt::black )
56  , mBoundsBehavior( 24 )
57 
58 {
59  mStartXIdx = mStopPoint.x() < mStartPoint.x();
60  mStartYIdx = mStopPoint.y() < mStartPoint.y();
61  init();
62  adaptItemSceneRect();
63 }
64 
66 {
67  delete mLineSymbol;
68 }
69 
70 void QgsComposerArrow::init()
71 {
72  setArrowHeadWidth( 4 );
73  mPen.setColor( mArrowHeadStrokeColor );
74  mPen.setWidthF( 1 );
75  mBrush.setColor( mArrowHeadFillColor );
76  createDefaultLineSymbol();
77 
78  //default to no background
79  setBackgroundEnabled( false );
80 }
81 
82 
83 void QgsComposerArrow::createDefaultLineSymbol()
84 {
85  delete mLineSymbol;
86  QgsStringMap properties;
87  properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
88  properties.insert( QStringLiteral( "width" ), QStringLiteral( "1" ) );
89  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
90  mLineSymbol = QgsLineSymbol::createSimple( properties );
91 }
92 
93 void QgsComposerArrow::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
94 {
95  Q_UNUSED( itemStyle );
96  Q_UNUSED( pWidget );
97  if ( !painter || !painter->device() )
98  {
99  return;
100  }
101  if ( !shouldDrawItem() )
102  {
103  return;
104  }
105 
106  drawBackground( painter );
107 
108  painter->save();
109  //antialiasing on
110  painter->setRenderHint( QPainter::Antialiasing, true );
111 
112  //draw line section
113  drawLine( painter );
114 
115  //draw arrowhead if required
116  if ( mMarkerMode != NoMarker )
117  {
118  painter->setBrush( mBrush );
119  painter->setPen( mPen );
120 
121  if ( mMarkerMode == DefaultMarker )
122  {
123  drawHardcodedMarker( painter, EndMarker );
124  }
125  else if ( mMarkerMode == SVGMarker )
126  {
127  drawSVGMarker( painter, StartMarker, mStartMarkerFile );
128  drawSVGMarker( painter, EndMarker, mEndMarkerFile );
129  }
130  }
131 
132  painter->restore();
133 
134  drawFrame( painter );
135  if ( isSelected() )
136  {
137  drawSelectionBoxes( painter );
138  }
139 }
140 
141 void QgsComposerArrow::setSceneRect( const QRectF &rectangle )
142 {
143  //update rect for data defined size and position
144  QRectF evaluatedRect = evalItemRect( rectangle );
145 
146  if ( evaluatedRect.width() < 0 )
147  {
148  mStartXIdx = 1 - mStartXIdx;
149  }
150  if ( evaluatedRect.height() < 0 )
151  {
152  mStartYIdx = 1 - mStartYIdx;
153  }
154 
155  double margin = computeMarkerMargin();
156 
157  // Ensure the rectangle is at least as large as needed to include the markers
158  QRectF rect = rectangle.united( QRectF( evaluatedRect.x(), evaluatedRect.y(), 2. * margin, 2. * margin ) );
159 
160  // Compute new start and stop positions
161  double x[2] = {rect.x(), rect.x() + rect.width()};
162  double y[2] = {rect.y(), rect.y() + rect.height()};
163 
164  double xsign = x[mStartXIdx] < x[1 - mStartXIdx] ? 1.0 : -1.0;
165  double ysign = y[mStartYIdx] < y[1 - mStartYIdx] ? 1.0 : -1.0;
166 
167  mStartPoint = QPointF( x[mStartXIdx] + xsign * margin, y[mStartYIdx] + ysign * margin );
168  mStopPoint = QPointF( x[1 - mStartXIdx] - xsign * margin, y[1 - mStartYIdx] - ysign * margin );
169 
171 }
172 
173 void QgsComposerArrow::drawLine( QPainter *painter )
174 {
175  if ( ! mLineSymbol || ! mComposition )
176  {
177  return;
178  }
179 
180  QPaintDevice *paintDevice = painter->device();
181  painter->save();
182  //setup painter scaling to dots so that raster symbology is drawn to scale
183  double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
184  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
185 
186  //setup render context
188  context.setForceVectorOutput( true );
189 
190  QgsExpressionContext expressionContext = createExpressionContext();
191  context.setExpressionContext( expressionContext );
192 
193  //line scaled to dots
194  QPolygonF line;
195  line << QPointF( mStartPoint.x() - pos().x(), mStartPoint.y() - pos().y() ) * dotsPerMM
196  << QPointF( mStopPoint.x() - pos().x(), mStopPoint.y() - pos().y() ) * dotsPerMM;
197 
198  mLineSymbol->startRender( context );
199  mLineSymbol->renderPolyline( line, nullptr, context );
200  mLineSymbol->stopRender( context );
201  painter->restore();
202 
203 }
204 
205 void QgsComposerArrow::drawHardcodedMarker( QPainter *p, MarkerType type )
206 {
207  Q_UNUSED( type );
208  if ( mBoundsBehavior == 22 )
209  {
210  //if arrow was created in versions prior to 2.4, use the old rendering style
211  QgsComposerUtils::drawArrowHead( p, mStopPoint.x() - pos().x(), mStopPoint.y() - pos().y(), QgsComposerUtils::angle( mStartPoint, mStopPoint ), mArrowHeadWidth );
212  }
213  else
214  {
215  QVector2D dir = QVector2D( mStopPoint - mStartPoint ).normalized();
216  QPointF stop = mStopPoint + ( dir * 0.5 * mArrowHeadWidth ).toPointF();
217  QgsComposerUtils::drawArrowHead( p, stop.x() - pos().x(), stop.y() - pos().y(), QgsComposerUtils::angle( mStartPoint, stop ), mArrowHeadWidth );
218  }
219 }
220 
221 void QgsComposerArrow::drawSVGMarker( QPainter *p, MarkerType type, const QString &markerPath )
222 {
223  Q_UNUSED( markerPath );
224  double angle = QgsComposerUtils::angle( mStartPoint, mStopPoint );
225 
226  double arrowHeadHeight;
227  if ( type == StartMarker )
228  {
229  arrowHeadHeight = mStartArrowHeadHeight;
230  }
231  else
232  {
233  arrowHeadHeight = mStopArrowHeadHeight;
234  }
235  if ( mArrowHeadWidth <= 0 || arrowHeadHeight <= 0 )
236  {
237  //bad image size
238  return;
239  }
240 
241  QPointF imageFixPoint;
242  imageFixPoint.setX( mArrowHeadWidth / 2.0 );
243  QPointF canvasPoint;
244  if ( type == StartMarker )
245  {
246  canvasPoint = QPointF( mStartPoint.x() - pos().x(), mStartPoint.y() - pos().y() );
247  imageFixPoint.setY( mStartArrowHeadHeight );
248  }
249  else //end marker
250  {
251  canvasPoint = QPointF( mStopPoint.x() - pos().x(), mStopPoint.y() - pos().y() );
252  imageFixPoint.setY( 0 );
253  }
254 
255  QString svgFileName = ( type == StartMarker ? mStartMarkerFile : mEndMarkerFile );
256  if ( svgFileName.isEmpty() )
257  return;
258 
259  QSvgRenderer r;
260  const QByteArray &svgContent = QgsApplication::svgCache()->svgContent( svgFileName, mArrowHeadWidth, mArrowHeadFillColor, mArrowHeadStrokeColor, mArrowHeadStrokeWidth,
261  1.0 );
262  r.load( svgContent );
263 
264  p->save();
265  p->setRenderHint( QPainter::Antialiasing );
266  if ( mBoundsBehavior == 22 )
267  {
268  //if arrow was created in versions prior to 2.4, use the old rendering style
269  //rotate image fix point for backtransform
270  QPointF fixPoint;
271  if ( type == StartMarker )
272  {
273  fixPoint.setX( 0 );
274  fixPoint.setY( arrowHeadHeight / 2.0 );
275  }
276  else
277  {
278  fixPoint.setX( 0 );
279  fixPoint.setY( -arrowHeadHeight / 2.0 );
280  }
281  QPointF rotatedFixPoint;
282  double angleRad = angle / 180 * M_PI;
283  rotatedFixPoint.setX( fixPoint.x() * std::cos( angleRad ) + fixPoint.y() * -sin( angleRad ) );
284  rotatedFixPoint.setY( fixPoint.x() * std::sin( angleRad ) + fixPoint.y() * std::cos( angleRad ) );
285  p->translate( canvasPoint.x() - rotatedFixPoint.x(), canvasPoint.y() - rotatedFixPoint.y() );
286  }
287  else
288  {
289  p->translate( canvasPoint.x(), canvasPoint.y() );
290  }
291 
292  p->rotate( angle );
293  p->translate( -mArrowHeadWidth / 2.0, -arrowHeadHeight / 2.0 );
294  r.render( p, QRectF( 0, 0, mArrowHeadWidth, arrowHeadHeight ) );
295  p->restore();
296 }
297 
298 void QgsComposerArrow::setStartMarker( const QString &svgPath )
299 {
300  QSvgRenderer r;
301  mStartMarkerFile = svgPath;
302  if ( svgPath.isEmpty() || !r.load( svgPath ) )
303  {
304  mStartArrowHeadHeight = 0;
305  }
306  else
307  {
308  //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
309  QRect viewBox = r.viewBox();
310  mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
311  }
312  adaptItemSceneRect();
313 }
314 
315 void QgsComposerArrow::setEndMarker( const QString &svgPath )
316 {
317  QSvgRenderer r;
318  mEndMarkerFile = svgPath;
319  if ( svgPath.isEmpty() || !r.load( svgPath ) )
320  {
321  mStopArrowHeadHeight = 0;
322  }
323  else
324  {
325  //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
326  QRect viewBox = r.viewBox();
327  mStopArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
328  }
329  adaptItemSceneRect();
330 }
331 
332 void QgsComposerArrow::setArrowHeadStrokeColor( const QColor &color )
333 {
334  mArrowHeadStrokeColor = color;
335  mPen.setColor( color );
336 }
337 
338 void QgsComposerArrow::setArrowHeadFillColor( const QColor &color )
339 {
340  mArrowHeadFillColor = color;
341  mBrush.setColor( color );
342 }
343 
345 {
346  mArrowHeadStrokeWidth = width;
347  mPen.setWidthF( mArrowHeadStrokeWidth );
348 
349  adaptItemSceneRect();
350 }
351 
353 {
354  delete mLineSymbol;
355  mLineSymbol = symbol;
356 }
357 
359 {
360  mArrowHeadWidth = width;
361  setStartMarker( mStartMarkerFile );
362  setEndMarker( mEndMarkerFile );
363  adaptItemSceneRect();
364 }
365 
366 double QgsComposerArrow::computeMarkerMargin() const
367 {
368  double margin = 0;
369 
370  if ( mBoundsBehavior == 22 )
371  {
372  //if arrow was created in versions prior to 2.4, use the old rendering style
373  if ( mMarkerMode == DefaultMarker )
374  {
375  margin = mPen.widthF() / 2.0 + mArrowHeadWidth / 2.0;
376  }
377  else if ( mMarkerMode == NoMarker )
378  {
379  margin = mPen.widthF() / 2.0;
380  }
381  else if ( mMarkerMode == SVGMarker )
382  {
383  double maxArrowHeight = std::max( mStartArrowHeadHeight, mStopArrowHeadHeight );
384  margin = mPen.widthF() / 2 + std::max( mArrowHeadWidth / 2.0, maxArrowHeight / 2.0 );
385  }
386  }
387  else
388  {
389  if ( mMarkerMode == DefaultMarker )
390  {
391  margin = mPen.widthF() * M_SQRT1_2 + mArrowHeadWidth / 2.0;
392  }
393  else if ( mMarkerMode == NoMarker )
394  {
395  margin = mPen.widthF() * M_SQRT1_2;
396  }
397  else if ( mMarkerMode == SVGMarker )
398  {
399  double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
400  double stopMarkerMargin = std::sqrt( 0.25 * ( mStopArrowHeadHeight * mStopArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
401  double markerMargin = std::max( startMarkerMargin, stopMarkerMargin );
402  margin = std::max( mPen.widthF() * M_SQRT1_2, markerMargin );
403  }
404  }
405  return margin;
406 }
407 
408 void QgsComposerArrow::adaptItemSceneRect()
409 {
410  //rectangle containing start and end point
411  QRectF rect = QRectF( std::min( mStartPoint.x(), mStopPoint.x() ), std::min( mStartPoint.y(), mStopPoint.y() ),
412  std::fabs( mStopPoint.x() - mStartPoint.x() ), std::fabs( mStopPoint.y() - mStartPoint.y() ) );
413  double enlarge = computeMarkerMargin();
414  rect.adjust( -enlarge, -enlarge, enlarge, enlarge );
416 }
417 
419 {
420  mMarkerMode = mode;
421  adaptItemSceneRect();
422 }
423 
424 bool QgsComposerArrow::writeXml( QDomElement &elem, QDomDocument &doc ) const
425 {
426  QgsPathResolver pathResolver;
427  if ( mComposition )
428  pathResolver = mComposition->project()->pathResolver();
429 
430  QgsReadWriteContext context;
431  context.setPathResolver( pathResolver );
432  // absolute paths to relative
433  QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, pathResolver );
434  QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, pathResolver );
435 
436  QDomElement composerArrowElem = doc.createElement( QStringLiteral( "ComposerArrow" ) );
437  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
438  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadFillColor ) );
439  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadStrokeColor ) );
440  composerArrowElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
441  composerArrowElem.setAttribute( QStringLiteral( "markerMode" ), mMarkerMode );
442  composerArrowElem.setAttribute( QStringLiteral( "startMarkerFile" ), startMarkerPath );
443  composerArrowElem.setAttribute( QStringLiteral( "endMarkerFile" ), endMarkerPath );
444  composerArrowElem.setAttribute( QStringLiteral( "boundsBehaviorVersion" ), QString::number( mBoundsBehavior ) );
445 
446  QDomElement styleElem = doc.createElement( QStringLiteral( "lineStyle" ) );
447  QDomElement lineStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mLineSymbol, doc, context );
448  styleElem.appendChild( lineStyleElem );
449  composerArrowElem.appendChild( styleElem );
450 
451  //start point
452  QDomElement startPointElem = doc.createElement( QStringLiteral( "StartPoint" ) );
453  startPointElem.setAttribute( QStringLiteral( "x" ), QString::number( mStartPoint.x() ) );
454  startPointElem.setAttribute( QStringLiteral( "y" ), QString::number( mStartPoint.y() ) );
455  composerArrowElem.appendChild( startPointElem );
456 
457  //stop point
458  QDomElement stopPointElem = doc.createElement( QStringLiteral( "StopPoint" ) );
459  stopPointElem.setAttribute( QStringLiteral( "x" ), QString::number( mStopPoint.x() ) );
460  stopPointElem.setAttribute( QStringLiteral( "y" ), QString::number( mStopPoint.y() ) );
461  composerArrowElem.appendChild( stopPointElem );
462 
463  elem.appendChild( composerArrowElem );
464  return _writeXml( composerArrowElem, doc );
465 }
466 
467 bool QgsComposerArrow::readXml( const QDomElement &itemElem, const QDomDocument &doc )
468 {
469  QgsPathResolver pathResolver;
470  if ( mComposition )
471  pathResolver = mComposition->project()->pathResolver();
472 
473  QgsReadWriteContext context;
474  context.setPathResolver( pathResolver );
475 
476  mArrowHeadWidth = itemElem.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "2.0" ) ).toDouble();
477  mArrowHeadFillColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadFillColor" ), QStringLiteral( "0,0,0,255" ) ) );
478  mArrowHeadStrokeColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QStringLiteral( "0,0,0,255" ) ) );
479  mArrowHeadStrokeWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble();
480  // relative paths to absolute
481  QString startMarkerPath = itemElem.attribute( QStringLiteral( "startMarkerFile" ), QLatin1String( "" ) );
482  QString endMarkerPath = itemElem.attribute( QStringLiteral( "endMarkerFile" ), QLatin1String( "" ) );
483  setStartMarker( QgsSymbolLayerUtils::svgSymbolNameToPath( startMarkerPath, pathResolver ) );
484  setEndMarker( QgsSymbolLayerUtils::svgSymbolNameToPath( endMarkerPath, pathResolver ) );
485  mMarkerMode = QgsComposerArrow::MarkerMode( itemElem.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt() );
486  //if bounds behavior version is not set, default to 2.2 behavior
487  mBoundsBehavior = itemElem.attribute( QStringLiteral( "boundsBehaviorVersion" ), QStringLiteral( "22" ) ).toInt();
488 
489  //arrow style
490  QDomElement styleElem = itemElem.firstChildElement( QStringLiteral( "lineStyle" ) );
491  if ( !styleElem.isNull() )
492  {
493  QDomElement lineStyleElem = styleElem.firstChildElement( QStringLiteral( "symbol" ) );
494  if ( !lineStyleElem.isNull() )
495  {
496  delete mLineSymbol;
497  mLineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( lineStyleElem, context );
498  }
499  }
500  else
501  {
502  //old project file, read arrow width and color
503  delete mLineSymbol;
504 
505  QgsStringMap properties;
506  properties.insert( QStringLiteral( "width" ), itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ) );
507 
508  if ( mBoundsBehavior == 22 )
509  {
510  //if arrow was created in versions prior to 2.4, use the old rendering style
511  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "flat" ) );
512  }
513  else
514  {
515  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
516  }
517  int red = 0;
518  int blue = 0;
519  int green = 0;
520  int alpha = 255;
521 
522  QDomNodeList arrowColorList = itemElem.elementsByTagName( QStringLiteral( "ArrowColor" ) );
523  if ( !arrowColorList.isEmpty() )
524  {
525  QDomElement arrowColorElem = arrowColorList.at( 0 ).toElement();
526  red = arrowColorElem.attribute( QStringLiteral( "red" ), QStringLiteral( "0" ) ).toInt();
527  green = arrowColorElem.attribute( QStringLiteral( "green" ), QStringLiteral( "0" ) ).toInt();
528  blue = arrowColorElem.attribute( QStringLiteral( "blue" ), QStringLiteral( "0" ) ).toInt();
529  alpha = arrowColorElem.attribute( QStringLiteral( "alpha" ), QStringLiteral( "255" ) ).toInt();
530  mArrowHeadFillColor = QColor( red, green, blue, alpha );
531  mArrowHeadStrokeColor = QColor( red, green, blue, alpha );
532  }
533  properties.insert( QStringLiteral( "color" ), QStringLiteral( "%1,%2,%3,%4" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
534  mLineSymbol = QgsLineSymbol::createSimple( properties );
535  }
536 
537  mPen.setColor( mArrowHeadStrokeColor );
538  mPen.setWidthF( mArrowHeadStrokeWidth );
539  mBrush.setColor( mArrowHeadFillColor );
540 
541  //restore general composer item properties
542  //needs to be before start point / stop point because setSceneRect()
543  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
544  if ( !composerItemList.isEmpty() )
545  {
546  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
547  _readXml( composerItemElem, doc );
548  }
549 
550  //start point
551  QDomNodeList startPointList = itemElem.elementsByTagName( QStringLiteral( "StartPoint" ) );
552  if ( !startPointList.isEmpty() )
553  {
554  QDomElement startPointElem = startPointList.at( 0 ).toElement();
555  mStartPoint.setX( startPointElem.attribute( QStringLiteral( "x" ), QStringLiteral( "0.0" ) ).toDouble() );
556  mStartPoint.setY( startPointElem.attribute( QStringLiteral( "y" ), QStringLiteral( "0.0" ) ).toDouble() );
557  }
558 
559  //stop point
560  QDomNodeList stopPointList = itemElem.elementsByTagName( QStringLiteral( "StopPoint" ) );
561  if ( !stopPointList.isEmpty() )
562  {
563  QDomElement stopPointElem = stopPointList.at( 0 ).toElement();
564  mStopPoint.setX( stopPointElem.attribute( QStringLiteral( "x" ), QStringLiteral( "0.0" ) ).toDouble() );
565  mStopPoint.setY( stopPointElem.attribute( QStringLiteral( "y" ), QStringLiteral( "0.0" ) ).toDouble() );
566  }
567 
568  mStartXIdx = mStopPoint.x() < mStartPoint.x();
569  mStartYIdx = mStopPoint.y() < mStartPoint.y();
570 
571  adaptItemSceneRect();
572  emit itemChanged();
573  return true;
574 }
575 
576 
QgsComposerArrow(QgsComposition *c)
Constructor.
void setForceVectorOutput(bool force)
The class is used as a container of context for various read/write operations on other objects...
static QgsSvgCache * svgCache()
Returns the application&#39;s SVG cache, used for caching SVG images and handling parameter replacement w...
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
static QString svgSymbolPathToName(QString path, const QgsPathResolver &pathResolver)
Get SVG symbols&#39;s name from its path.
virtual int type() const override
Return composer item type.
static double angle(QPointF p1, QPointF p2)
Calculates the angle of the line from p1 to p2 (counter clockwise, starting from a line from north to...
static QgsLineSymbol * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
Definition: qgssymbol.cpp:1073
void itemChanged()
Emitted when the item changes.
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores state in DOM element.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1659
A item that forms part of a map composition.
QRectF evalItemRect(const QRectF &newRect, const bool resizeOnly=false, const QgsExpressionContext *context=nullptr)
Evaluates an item&#39;s bounding rect to consider data defined position and size of item and reference po...
void setStartMarker(const QString &svgPath)
Sets the marker to draw at the start of the line.
virtual void drawFrame(QPainter *p)
Draw black frame around item.
static QString svgSymbolNameToPath(QString name, const QgsPathResolver &pathResolver)
Get SVG symbol&#39;s path from its name.
void setArrowHeadWidth(double width)
Sets the width of the arrow head in mm.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:443
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)
Definition: MathUtils.cpp:786
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:383
static QString encodeColor(const QColor &color)
void setSceneRect(const QRectF &rectangle) override
Modifies position of start and endpoint and calls QgsComposerItem::setSceneRect.
static void drawArrowHead(QPainter *p, const double x, const double y, const double angle, const double arrowHeadWidth)
Draws an arrow head on to a QPainter.
bool _writeXml(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document. Usually called from writeXml methods of ...
bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from DOM document.
QgsPathResolver pathResolver() const
Return path resolver object with considering whether the project uses absolute or relative paths and ...
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setMarkerMode(MarkerMode mode)
Sets the marker mode, which controls how the arrow endpoints are drawn.
bool _readXml(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document. Usually called from readXml methods of su...
void setBackgroundEnabled(const bool drawBackground)
Set whether this item has a Background drawn around it or not.
void setArrowHeadFillColor(const QColor &color)
Sets the color used to fill the arrow head.
Graphics scene for map printing.
virtual QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
QgsComposition * mComposition
Contains information about the context of a rendering operation.
void setArrowHeadStrokeColor(const QColor &color)
Sets the color used to draw the stroke around the arrow head.
void setArrowHeadStrokeWidth(const double width)
Sets the pen width for the stroke of the arrow head.
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used for drawing the line portion of the arrow.
QgsProject * project() const
The project associated with the composition.
virtual void drawBackground(QPainter *p)
Draw background.
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
QByteArray svgContent(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio=0)
Get SVG content.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Resolves relative paths into absolute paths and vice versa.
static QgsRenderContext createRenderContextForComposition(QgsComposition *composition, QPainter *painter)
Creates a render context suitable for the specified composition and painter destination.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint - draw on canvas.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:405
void setEndMarker(const QString &svgPath)
Sets the marker to draw at the end of the line.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
static QColor decodeColor(const QString &str)