23 #include <QSvgRenderer>
34 , mMarkerMode( DefaultMarker )
35 , mArrowHeadOutlineWidth( 1.0 )
36 , mArrowHeadOutlineColor( Qt::black )
37 , mArrowHeadFillColor( Qt::black )
38 , mBoundsBehaviour( 24 )
46 , mStartPoint( startPoint )
47 , mStopPoint( stopPoint )
48 , mMarkerMode( DefaultMarker )
49 , mArrowHeadOutlineWidth( 1.0 )
50 , mArrowHeadOutlineColor( Qt::black )
51 , mArrowHeadFillColor( Qt::black )
52 , mBoundsBehaviour( 24 )
55 mStartXIdx = mStopPoint.x() < mStartPoint.x();
56 mStartYIdx = mStopPoint.y() < mStartPoint.y();
66 void QgsComposerArrow::init()
69 mPen.setColor( mArrowHeadOutlineColor );
71 mBrush.setColor( mArrowHeadFillColor );
72 createDefaultLineSymbol();
79 void QgsComposerArrow::createDefaultLineSymbol()
83 properties.insert(
"color",
"0,0,0,255" );
84 properties.insert(
"width",
"1" );
85 properties.insert(
"capstyle",
"square" );
91 Q_UNUSED( itemStyle );
93 if ( !painter || !painter->device() )
106 painter->setRenderHint( QPainter::Antialiasing,
true );
114 painter->setBrush( mBrush );
115 painter->setPen( mPen );
119 drawHardcodedMarker( painter, EndMarker );
123 drawSVGMarker( painter, StartMarker, mStartMarkerFile );
124 drawSVGMarker( painter, EndMarker, mEndMarkerFile );
142 if ( evaluatedRect.width() < 0 )
144 mStartXIdx = 1 - mStartXIdx;
146 if ( evaluatedRect.height() < 0 )
148 mStartYIdx = 1 - mStartYIdx;
151 double margin = computeMarkerMargin();
154 QRectF rect = rectangle.united( QRectF( evaluatedRect.x(), evaluatedRect.y(), 2. * margin, 2. * margin ) );
157 double x[2] = {rect.x(), rect.x() + rect.width()};
158 double y[2] = {rect.y(), rect.y() + rect.height()};
160 double xsign = x[mStartXIdx] < x[1 - mStartXIdx] ? 1.0 : -1.0;
161 double ysign = y[mStartYIdx] < y[1 - mStartYIdx] ? 1.0 : -1.0;
163 mStartPoint = QPointF( x[mStartXIdx] + xsign * margin, y[mStartYIdx] + ysign * margin );
164 mStopPoint = QPointF( x[1 - mStartXIdx] - xsign * margin, y[1 - mStartYIdx] - ysign * margin );
169 void QgsComposerArrow::drawLine( QPainter *painter )
176 QPaintDevice* thePaintDevice = painter->device();
179 double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
180 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM );
192 line << QPointF( mStartPoint.x() - pos().x(), mStartPoint.y() - pos().y() ) * dotsPerMM
193 << QPointF( mStopPoint.x() - pos().x(), mStopPoint.y() - pos().y() ) * dotsPerMM;
202 void QgsComposerArrow::drawHardcodedMarker( QPainter *p, MarkerType type )
205 if ( mBoundsBehaviour == 22 )
212 QVector2D dir = QVector2D( mStopPoint - mStartPoint ).normalized();
213 QPointF stop = mStopPoint + ( dir * 0.5 * mArrowHeadWidth ).toPointF();
218 void QgsComposerArrow::drawSVGMarker( QPainter* p, MarkerType type,
const QString &markerPath )
220 Q_UNUSED( markerPath );
223 double arrowHeadHeight;
224 if ( type == StartMarker )
226 arrowHeadHeight = mStartArrowHeadHeight;
230 arrowHeadHeight = mStopArrowHeadHeight;
232 if ( mArrowHeadWidth <= 0 || arrowHeadHeight <= 0 )
238 QPointF imageFixPoint;
239 imageFixPoint.setX( mArrowHeadWidth / 2.0 );
241 if ( type == StartMarker )
243 canvasPoint = QPointF( mStartPoint.x() - pos().x(), mStartPoint.y() - pos().y() );
244 imageFixPoint.setY( mStartArrowHeadHeight );
248 canvasPoint = QPointF( mStopPoint.x() - pos().x(), mStopPoint.y() - pos().y() );
249 imageFixPoint.setY( 0 );
254 if ( type == StartMarker )
256 if ( mStartMarkerFile.isEmpty() || !r.load( mStartMarkerFile ) )
263 if ( mEndMarkerFile.isEmpty() || !r.load( mEndMarkerFile ) )
270 p->setRenderHint( QPainter::Antialiasing );
271 if ( mBoundsBehaviour == 22 )
276 if ( type == StartMarker )
278 fixPoint.setX( 0 ); fixPoint.setY( arrowHeadHeight / 2.0 );
282 fixPoint.setX( 0 ); fixPoint.setY( -arrowHeadHeight / 2.0 );
284 QPointF rotatedFixPoint;
285 double angleRad = ang / 180 *
M_PI;
286 rotatedFixPoint.setX( fixPoint.x() * cos( angleRad ) + fixPoint.y() * -sin( angleRad ) );
287 rotatedFixPoint.setY( fixPoint.x() * sin( angleRad ) + fixPoint.y() * cos( angleRad ) );
288 p->translate( canvasPoint.x() - rotatedFixPoint.x(), canvasPoint.y() - rotatedFixPoint.y() );
292 p->translate( canvasPoint.x(), canvasPoint.y() );
296 p->translate( -mArrowHeadWidth / 2.0, -arrowHeadHeight / 2.0 );
297 r.render( p, QRectF( 0, 0, mArrowHeadWidth, arrowHeadHeight ) );
306 mStartMarkerFile = svgPath;
307 if ( svgPath.isEmpty() || !r.load( svgPath ) )
309 mStartArrowHeadHeight = 0;
314 QRect viewBox = r.viewBox();
315 mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
317 adaptItemSceneRect();
323 mEndMarkerFile = svgPath;
324 if ( svgPath.isEmpty() || !r.load( svgPath ) )
326 mStopArrowHeadHeight = 0;
331 QRect viewBox = r.viewBox();
332 mStopArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
334 adaptItemSceneRect();
341 return mLineSymbol->
color();
353 mArrowHeadOutlineColor = c;
354 mArrowHeadFillColor = c;
356 mBrush.setColor( c );
361 mArrowHeadOutlineColor = color;
362 mPen.setColor( color );
367 mArrowHeadFillColor = color;
368 mBrush.setColor( color );
377 mArrowHeadOutlineWidth = width;
378 mPen.setWidthF( mArrowHeadOutlineWidth );
380 adaptItemSceneRect();
387 return mLineSymbol->
width();
395 mArrowHeadOutlineWidth = width;
396 mPen.setWidthF( mArrowHeadOutlineWidth );
398 adaptItemSceneRect();
404 mLineSymbol = symbol;
409 mArrowHeadWidth = width;
412 adaptItemSceneRect();
415 double QgsComposerArrow::computeMarkerMargin()
const
419 if ( mBoundsBehaviour == 22 )
424 margin = mPen.widthF() / 2.0 + mArrowHeadWidth / 2.0;
428 margin = mPen.widthF() / 2.0;
432 double maxArrowHeight = qMax( mStartArrowHeadHeight, mStopArrowHeadHeight );
433 margin = mPen.widthF() / 2 + qMax( mArrowHeadWidth / 2.0, maxArrowHeight / 2.0 );
440 margin = mPen.widthF() / std::sqrt( 2.0 ) + mArrowHeadWidth / 2.0;
444 margin = mPen.widthF() / std::sqrt( 2.0 );
448 double startMarkerMargin = std::sqrt( 0.25 * ( mStartArrowHeadHeight * mStartArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
449 double stopMarkerMargin = std::sqrt( 0.25 * ( mStopArrowHeadHeight * mStopArrowHeadHeight + mArrowHeadWidth * mArrowHeadWidth ) );
450 double markerMargin = qMax( startMarkerMargin, stopMarkerMargin );
451 margin = qMax( mPen.widthF() / std::sqrt( 2.0 ), markerMargin );
457 void QgsComposerArrow::adaptItemSceneRect()
460 QRectF rect = QRectF( qMin( mStartPoint.x(), mStopPoint.x() ), qMin( mStartPoint.y(), mStopPoint.y() ),
461 qAbs( mStopPoint.x() - mStartPoint.x() ), qAbs( mStopPoint.y() - mStartPoint.y() ) );
462 double enlarge = computeMarkerMargin();
463 rect.adjust( -enlarge, -enlarge, enlarge, enlarge );
470 adaptItemSceneRect();
475 QDomElement composerArrowElem = doc.createElement(
"ComposerArrow" );
476 composerArrowElem.setAttribute(
"arrowHeadWidth", QString::number( mArrowHeadWidth ) );
479 composerArrowElem.setAttribute(
"outlineWidth", QString::number( mArrowHeadOutlineWidth ) );
480 composerArrowElem.setAttribute(
"markerMode", mMarkerMode );
481 composerArrowElem.setAttribute(
"startMarkerFile", mStartMarkerFile );
482 composerArrowElem.setAttribute(
"endMarkerFile", mEndMarkerFile );
483 composerArrowElem.setAttribute(
"boundsBehaviourVersion", QString::number( mBoundsBehaviour ) );
485 QDomElement styleElem = doc.createElement(
"lineStyle" );
487 styleElem.appendChild( lineStyleElem );
488 composerArrowElem.appendChild( styleElem );
491 QDomElement startPointElem = doc.createElement(
"StartPoint" );
492 startPointElem.setAttribute(
"x", QString::number( mStartPoint.x() ) );
493 startPointElem.setAttribute(
"y", QString::number( mStartPoint.y() ) );
494 composerArrowElem.appendChild( startPointElem );
497 QDomElement stopPointElem = doc.createElement(
"StopPoint" );
498 stopPointElem.setAttribute(
"x", QString::number( mStopPoint.x() ) );
499 stopPointElem.setAttribute(
"y", QString::number( mStopPoint.y() ) );
500 composerArrowElem.appendChild( stopPointElem );
502 elem.appendChild( composerArrowElem );
503 return _writeXML( composerArrowElem, doc );
508 mArrowHeadWidth = itemElem.attribute(
"arrowHeadWidth",
"2.0" ).toDouble();
511 mArrowHeadOutlineWidth = itemElem.attribute(
"outlineWidth",
"1.0" ).toDouble();
513 setEndMarker( itemElem.attribute(
"endMarkerFile",
"" ) );
516 mBoundsBehaviour = itemElem.attribute(
"boundsBehaviourVersion",
"22" ).toInt();
519 QDomElement styleElem = itemElem.firstChildElement(
"lineStyle" );
520 if ( !styleElem.isNull() )
522 QDomElement lineStyleElem = styleElem.firstChildElement(
"symbol" );
523 if ( !lineStyleElem.isNull() )
526 mLineSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsLineSymbolV2>( lineStyleElem );
535 properties.insert(
"width", itemElem.attribute(
"outlineWidth",
"1.0" ) );
537 if ( mBoundsBehaviour == 22 )
540 properties.insert(
"capstyle",
"flat" );
544 properties.insert(
"capstyle",
"square" );
551 QDomNodeList arrowColorList = itemElem.elementsByTagName(
"ArrowColor" );
552 if ( arrowColorList.size() > 0 )
554 QDomElement arrowColorElem = arrowColorList.at( 0 ).toElement();
555 red = arrowColorElem.attribute(
"red",
"0" ).toInt();
556 green = arrowColorElem.attribute(
"green",
"0" ).toInt();
557 blue = arrowColorElem.attribute(
"blue",
"0" ).toInt();
558 alpha = arrowColorElem.attribute(
"alpha",
"255" ).toInt();
559 mArrowHeadFillColor = QColor( red, green, blue, alpha );
560 mArrowHeadOutlineColor = QColor( red, green, blue, alpha );
562 properties.insert(
"color", QString(
"%1,%2,%3,%4" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
566 mPen.setColor( mArrowHeadOutlineColor );
567 mPen.setWidthF( mArrowHeadOutlineWidth );
568 mBrush.setColor( mArrowHeadFillColor );
572 QDomNodeList composerItemList = itemElem.elementsByTagName(
"ComposerItem" );
573 if ( composerItemList.size() > 0 )
575 QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
580 QDomNodeList startPointList = itemElem.elementsByTagName(
"StartPoint" );
581 if ( startPointList.size() > 0 )
583 QDomElement startPointElem = startPointList.at( 0 ).toElement();
584 mStartPoint.setX( startPointElem.attribute(
"x",
"0.0" ).toDouble() );
585 mStartPoint.setY( startPointElem.attribute(
"y",
"0.0" ).toDouble() );
589 QDomNodeList stopPointList = itemElem.elementsByTagName(
"StopPoint" );
590 if ( stopPointList.size() > 0 )
592 QDomElement stopPointElem = stopPointList.at( 0 ).toElement();
593 mStopPoint.setX( stopPointElem.attribute(
"x",
"0.0" ).toDouble() );
594 mStopPoint.setY( stopPointElem.attribute(
"y",
"0.0" ).toDouble() );
597 mStartXIdx = mStopPoint.x() < mStartPoint.x();
598 mStartYIdx = mStopPoint.y() < mStartPoint.y();
600 adaptItemSceneRect();