QGIS API Documentation  2.99.0-Master (9fdd060)
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 : [email protected]
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 
433  // absolute paths to relative
434  QString startMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mStartMarkerFile, pathResolver );
435  QString endMarkerPath = QgsSymbolLayerUtils::svgSymbolPathToName( mEndMarkerFile, pathResolver );
436 
437  QDomElement composerArrowElem = doc.createElement( QStringLiteral( "ComposerArrow" ) );
438  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadWidth" ), QString::number( mArrowHeadWidth ) );
439  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadFillColor ) );
440  composerArrowElem.setAttribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( mArrowHeadStrokeColor ) );
441  composerArrowElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mArrowHeadStrokeWidth ) );
442  composerArrowElem.setAttribute( QStringLiteral( "markerMode" ), mMarkerMode );
443  composerArrowElem.setAttribute( QStringLiteral( "startMarkerFile" ), startMarkerPath );
444  composerArrowElem.setAttribute( QStringLiteral( "endMarkerFile" ), endMarkerPath );
445  composerArrowElem.setAttribute( QStringLiteral( "boundsBehaviorVersion" ), QString::number( mBoundsBehavior ) );
446 
447  QDomElement styleElem = doc.createElement( QStringLiteral( "lineStyle" ) );
448  QDomElement lineStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mLineSymbol, doc, context );
449  styleElem.appendChild( lineStyleElem );
450  composerArrowElem.appendChild( styleElem );
451 
452  //start point
453  QDomElement startPointElem = doc.createElement( QStringLiteral( "StartPoint" ) );
454  startPointElem.setAttribute( QStringLiteral( "x" ), QString::number( mStartPoint.x() ) );
455  startPointElem.setAttribute( QStringLiteral( "y" ), QString::number( mStartPoint.y() ) );
456  composerArrowElem.appendChild( startPointElem );
457 
458  //stop point
459  QDomElement stopPointElem = doc.createElement( QStringLiteral( "StopPoint" ) );
460  stopPointElem.setAttribute( QStringLiteral( "x" ), QString::number( mStopPoint.x() ) );
461  stopPointElem.setAttribute( QStringLiteral( "y" ), QString::number( mStopPoint.y() ) );
462  composerArrowElem.appendChild( stopPointElem );
463 
464  elem.appendChild( composerArrowElem );
465  return _writeXml( composerArrowElem, doc );
466 }
467 
468 bool QgsComposerArrow::readXml( const QDomElement &itemElem, const QDomDocument &doc )
469 {
470  QgsPathResolver pathResolver;
471  if ( mComposition )
472  pathResolver = mComposition->project()->pathResolver();
473 
474  QgsReadWriteContext context;
475  context.setPathResolver( pathResolver );
476 
477  mArrowHeadWidth = itemElem.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "2.0" ) ).toDouble();
478  mArrowHeadFillColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadFillColor" ), QStringLiteral( "0,0,0,255" ) ) );
479  mArrowHeadStrokeColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QStringLiteral( "0,0,0,255" ) ) );
480  mArrowHeadStrokeWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble();
481  // relative paths to absolute
482  QString startMarkerPath = itemElem.attribute( QStringLiteral( "startMarkerFile" ), QLatin1String( "" ) );
483  QString endMarkerPath = itemElem.attribute( QStringLiteral( "endMarkerFile" ), QLatin1String( "" ) );
484  setStartMarker( QgsSymbolLayerUtils::svgSymbolNameToPath( startMarkerPath, pathResolver ) );
485  setEndMarker( QgsSymbolLayerUtils::svgSymbolNameToPath( endMarkerPath, pathResolver ) );
486  mMarkerMode = QgsComposerArrow::MarkerMode( itemElem.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt() );
487  //if bounds behavior version is not set, default to 2.2 behavior
488  mBoundsBehavior = itemElem.attribute( QStringLiteral( "boundsBehaviorVersion" ), QStringLiteral( "22" ) ).toInt();
489 
490  //arrow style
491  QDomElement styleElem = itemElem.firstChildElement( QStringLiteral( "lineStyle" ) );
492  if ( !styleElem.isNull() )
493  {
494  QDomElement lineStyleElem = styleElem.firstChildElement( QStringLiteral( "symbol" ) );
495  if ( !lineStyleElem.isNull() )
496  {
497  delete mLineSymbol;
498  mLineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( lineStyleElem, context );
499  }
500  }
501  else
502  {
503  //old project file, read arrow width and color
504  delete mLineSymbol;
505 
506  QgsStringMap properties;
507  properties.insert( QStringLiteral( "width" ), itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ) );
508 
509  if ( mBoundsBehavior == 22 )
510  {
511  //if arrow was created in versions prior to 2.4, use the old rendering style
512  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "flat" ) );
513  }
514  else
515  {
516  properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "square" ) );
517  }
518  int red = 0;
519  int blue = 0;
520  int green = 0;
521  int alpha = 255;
522 
523  QDomNodeList arrowColorList = itemElem.elementsByTagName( QStringLiteral( "ArrowColor" ) );
524  if ( !arrowColorList.isEmpty() )
525  {
526  QDomElement arrowColorElem = arrowColorList.at( 0 ).toElement();
527  red = arrowColorElem.attribute( QStringLiteral( "red" ), QStringLiteral( "0" ) ).toInt();
528  green = arrowColorElem.attribute( QStringLiteral( "green" ), QStringLiteral( "0" ) ).toInt();
529  blue = arrowColorElem.attribute( QStringLiteral( "blue" ), QStringLiteral( "0" ) ).toInt();
530  alpha = arrowColorElem.attribute( QStringLiteral( "alpha" ), QStringLiteral( "255" ) ).toInt();
531  mArrowHeadFillColor = QColor( red, green, blue, alpha );
532  mArrowHeadStrokeColor = QColor( red, green, blue, alpha );
533  }
534  properties.insert( QStringLiteral( "color" ), QStringLiteral( "%1,%2,%3,%4" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
535  mLineSymbol = QgsLineSymbol::createSimple( properties );
536  }
537 
538  mPen.setColor( mArrowHeadStrokeColor );
539  mPen.setWidthF( mArrowHeadStrokeWidth );
540  mBrush.setColor( mArrowHeadFillColor );
541 
542  //restore general composer item properties
543  //needs to be before start point / stop point because setSceneRect()
544  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
545  if ( !composerItemList.isEmpty() )
546  {
547  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
548  _readXml( composerItemElem, doc );
549  }
550 
551  //start point
552  QDomNodeList startPointList = itemElem.elementsByTagName( QStringLiteral( "StartPoint" ) );
553  if ( !startPointList.isEmpty() )
554  {
555  QDomElement startPointElem = startPointList.at( 0 ).toElement();
556  mStartPoint.setX( startPointElem.attribute( QStringLiteral( "x" ), QStringLiteral( "0.0" ) ).toDouble() );
557  mStartPoint.setY( startPointElem.attribute( QStringLiteral( "y" ), QStringLiteral( "0.0" ) ).toDouble() );
558  }
559 
560  //stop point
561  QDomNodeList stopPointList = itemElem.elementsByTagName( QStringLiteral( "StopPoint" ) );
562  if ( !stopPointList.isEmpty() )
563  {
564  QDomElement stopPointElem = stopPointList.at( 0 ).toElement();
565  mStopPoint.setX( stopPointElem.attribute( QStringLiteral( "x" ), QStringLiteral( "0.0" ) ).toDouble() );
566  mStopPoint.setY( stopPointElem.attribute( QStringLiteral( "y" ), QStringLiteral( "0.0" ) ).toDouble() );
567  }
568 
569  mStartXIdx = mStopPoint.x() < mStartPoint.x();
570  mStartYIdx = mStopPoint.y() < mStartPoint.y();
571 
572  adaptItemSceneRect();
573  emit itemChanged();
574  return true;
575 }
576 
577 
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:1070
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:1656
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)