QGIS API Documentation  master-59fd5e0
src/core/composer/qgscomposerarrow.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgscomposerarrow.cpp
00003                          ----------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Marco Hugentobler
00006     email                : marco@hugis.net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgscomposerarrow.h"
00019 #include "qgscomposition.h"
00020 #include <QPainter>
00021 #include <QSvgRenderer>
00022 
00023 #include <cmath>
00024 
00025 QgsComposerArrow::QgsComposerArrow( QgsComposition* c )
00026     : QgsComposerItem( c )
00027     , mStartPoint( 0, 0 )
00028     , mStopPoint( 0, 0 )
00029     , mMarkerMode( DefaultMarker )
00030     , mArrowColor( QColor( 0, 0, 0 ) )
00031 {
00032   initGraphicsSettings();
00033 }
00034 
00035 QgsComposerArrow::QgsComposerArrow( const QPointF& startPoint, const QPointF& stopPoint, QgsComposition* c )
00036     : QgsComposerItem( c )
00037     , mStartPoint( startPoint )
00038     , mStopPoint( stopPoint )
00039     , mMarkerMode( DefaultMarker )
00040     , mArrowColor( QColor( 0, 0, 0 ) )
00041 {
00042   initGraphicsSettings();
00043   adaptItemSceneRect();
00044 }
00045 
00046 QgsComposerArrow::~QgsComposerArrow()
00047 {
00048 
00049 }
00050 
00051 void QgsComposerArrow::initGraphicsSettings()
00052 {
00053   setArrowHeadWidth( 4 );
00054   mPen.setColor( QColor( 0, 0, 0 ) );
00055   mPen.setWidthF( 1 );
00056 
00057   //set composer item brush and pen to transparent white by default
00058   setPen( QPen( QColor( 255, 255, 255, 0 ) ) );
00059   setBrush( QBrush( QColor( 255, 255, 255, 0 ) ) );
00060 }
00061 
00062 void QgsComposerArrow::paint( QPainter* painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
00063 {
00064   Q_UNUSED( itemStyle );
00065   Q_UNUSED( pWidget );
00066   if ( !painter )
00067   {
00068     return;
00069   }
00070 
00071   drawBackground( painter );
00072 
00073   //draw arrow
00074   QPen arrowPen = mPen;
00075   arrowPen.setCapStyle( Qt::FlatCap );
00076   arrowPen.setColor( mArrowColor );
00077   painter->setPen( arrowPen );
00078   painter->setBrush( QBrush( mArrowColor ) );
00079   painter->drawLine( QPointF( mStartPoint.x() - transform().dx(), mStartPoint.y() - transform().dy() ), QPointF( mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy() ) );
00080 
00081   if ( mMarkerMode == DefaultMarker )
00082   {
00083     drawHardcodedMarker( painter, EndMarker );
00084   }
00085   else if ( mMarkerMode == SVGMarker )
00086   {
00087     drawSVGMarker( painter, StartMarker, mStartMarkerFile );
00088     drawSVGMarker( painter, EndMarker, mEndMarkerFile );
00089   }
00090 
00091   drawFrame( painter );
00092   if ( isSelected() )
00093   {
00094     drawSelectionBoxes( painter );
00095   }
00096 }
00097 
00098 void QgsComposerArrow::setSceneRect( const QRectF& rectangle )
00099 {
00100   //maintain the relative position of start and stop point in the rectangle
00101   double startPointXPos = ( mStartPoint.x() - transform().dx() ) / rect().width();
00102   double startPointYPos = ( mStartPoint.y() - transform().dy() ) / rect().height();
00103   double stopPointXPos = ( mStopPoint.x() - transform().dx() ) / rect().width();
00104   double stopPointYPos = ( mStopPoint.y() - transform().dy() ) / rect().height();
00105 
00106   mStartPoint.setX( rectangle.left() + startPointXPos * rectangle.width() );
00107   mStartPoint.setY( rectangle.top() + startPointYPos * rectangle.height() );
00108   mStopPoint.setX( rectangle.left() + stopPointXPos * rectangle.width() );
00109   mStopPoint.setY( rectangle.top() + stopPointYPos * rectangle.height() );
00110 
00111   adaptItemSceneRect();
00112 }
00113 
00114 void QgsComposerArrow::drawHardcodedMarker( QPainter *p, MarkerType type )
00115 {
00116   Q_UNUSED( type );
00117   QBrush arrowBrush = p->brush();
00118   arrowBrush.setColor( mArrowColor );
00119   p->setBrush( arrowBrush );
00120   drawArrowHead( p, mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy(), angle( mStartPoint, mStopPoint ), mArrowHeadWidth );
00121 }
00122 
00123 void QgsComposerArrow::drawSVGMarker( QPainter* p, MarkerType type, const QString &markerPath )
00124 {
00125   Q_UNUSED( markerPath );
00126   double ang = angle( mStartPoint, mStopPoint );
00127 
00128   double arrowHeadHeight;
00129   if ( type == StartMarker )
00130   {
00131     arrowHeadHeight = mStartArrowHeadHeight;
00132   }
00133   else
00134   {
00135     arrowHeadHeight = mStopArrowHeadHeight;
00136   }
00137 
00138   //prepare paint device
00139   int dpi = ( p->device()->logicalDpiX() + p->device()->logicalDpiY() ) / 2;
00140   double viewScaleFactor = horizontalViewScaleFactor();
00141   int imageWidth = mArrowHeadWidth / 25.4 * dpi;
00142   int imageHeight = arrowHeadHeight / 25.4 * dpi;
00143 
00144   //make nicer preview
00145   if ( mComposition && mComposition->plotStyle() == QgsComposition::Preview )
00146   {
00147     imageWidth *= qMin( viewScaleFactor, 10.0 );
00148     imageHeight *= qMin( viewScaleFactor, 10.0 );
00149   }
00150   QImage markerImage( imageWidth, imageHeight, QImage::Format_ARGB32 );
00151   QColor markerBG( 255, 255, 255, 0 ); //transparent white background
00152   markerImage.fill( markerBG.rgba() );
00153 
00154   QPointF imageFixPoint;
00155   imageFixPoint.setX( mArrowHeadWidth / 2.0 );
00156   QPointF canvasPoint;
00157   if ( type == StartMarker )
00158   {
00159     canvasPoint = QPointF( mStartPoint.x() - transform().dx(), mStartPoint.y() - transform().dy() );
00160     imageFixPoint.setY( mStartArrowHeadHeight );
00161   }
00162   else //end marker
00163   {
00164     canvasPoint = QPointF( mStopPoint.x() - transform().dx(), mStopPoint.y() - transform().dy() );
00165     imageFixPoint.setY( 0 );
00166   }
00167 
00168   //rasterize svg
00169   QSvgRenderer r;
00170   if ( type == StartMarker )
00171   {
00172     if ( !r.load( mStartMarkerFile ) )
00173     {
00174       return;
00175     }
00176   }
00177   else //end marker
00178   {
00179     if ( !r.load( mEndMarkerFile ) )
00180     {
00181       return;
00182     }
00183   }
00184 
00185   //rotate image fix point for backtransform
00186   QPointF fixPoint;
00187   if ( type == StartMarker )
00188   {
00189     fixPoint.setX( 0 ); fixPoint.setY( arrowHeadHeight / 2.0 );
00190   }
00191   else
00192   {
00193     fixPoint.setX( 0 ); fixPoint.setY( -arrowHeadHeight / 2.0 );
00194   }
00195   QPointF rotatedFixPoint;
00196   double angleRad = ang / 180 * M_PI;
00197   rotatedFixPoint.setX( fixPoint.x() * cos( angleRad ) + fixPoint.y() * -sin( angleRad ) );
00198   rotatedFixPoint.setY( fixPoint.x() * sin( angleRad ) + fixPoint.y() * cos( angleRad ) );
00199 
00200 
00201   QPainter imagePainter( &markerImage );
00202   r.render( &imagePainter );
00203 
00204   p->save();
00205   p->translate( canvasPoint.x() - rotatedFixPoint.x() , canvasPoint.y() - rotatedFixPoint.y() );
00206   p->rotate( ang );
00207   p->translate( -mArrowHeadWidth / 2.0, -arrowHeadHeight / 2.0 );
00208 
00209   p->drawImage( QRectF( 0, 0, mArrowHeadWidth, arrowHeadHeight ), markerImage, QRectF( 0, 0, imageWidth, imageHeight ) );
00210   p->restore();
00211 
00212   return;
00213 }
00214 
00215 void QgsComposerArrow::setStartMarker( const QString& svgPath )
00216 {
00217   QSvgRenderer r;
00218   if ( !r.load( svgPath ) )
00219   {
00220     return;
00221     // mStartArrowHeadHeight = 0;
00222   }
00223   mStartMarkerFile = svgPath;
00224 
00225   //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
00226   QRect viewBox = r.viewBox();
00227   mStartArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
00228   adaptItemSceneRect();
00229 }
00230 
00231 void QgsComposerArrow::setEndMarker( const QString& svgPath )
00232 {
00233   QSvgRenderer r;
00234   if ( !r.load( svgPath ) )
00235   {
00236     return;
00237     // mStopArrowHeadHeight = 0;
00238   }
00239   mEndMarkerFile = svgPath;
00240 
00241   //calculate mArrowHeadHeight from svg file and mArrowHeadWidth
00242   QRect viewBox = r.viewBox();
00243   mStopArrowHeadHeight = mArrowHeadWidth / viewBox.width() * viewBox.height();
00244   adaptItemSceneRect();
00245 }
00246 
00247 void QgsComposerArrow::setOutlineWidth( double width )
00248 {
00249   mPen.setWidthF( width );
00250   adaptItemSceneRect();
00251 }
00252 
00253 void QgsComposerArrow::setArrowHeadWidth( double width )
00254 {
00255   mArrowHeadWidth = width;
00256   setStartMarker( mStartMarkerFile );
00257   setEndMarker( mEndMarkerFile );
00258   adaptItemSceneRect();
00259 }
00260 
00261 void QgsComposerArrow::adaptItemSceneRect()
00262 {
00263   //rectangle containing start and end point
00264   QRectF rect = QRectF( qMin( mStartPoint.x(), mStopPoint.x() ), qMin( mStartPoint.y(), mStopPoint.y() ),
00265                         qAbs( mStopPoint.x() - mStartPoint.x() ), qAbs( mStopPoint.y() - mStartPoint.y() ) );
00266   double enlarge = 0;
00267   if ( mMarkerMode == DefaultMarker )
00268   {
00269     enlarge = mPen.widthF() / 2.0 + mArrowHeadWidth / 2.0;
00270   }
00271   else if ( mMarkerMode == NoMarker )
00272   {
00273     enlarge = mPen.widthF() / 2.0;
00274   }
00275   else if ( mMarkerMode == SVGMarker )
00276   {
00277     double maxArrowHeight = qMax( mStartArrowHeadHeight, mStopArrowHeadHeight );
00278     enlarge = mPen.widthF() / 2 + qMax( mArrowHeadWidth / 2.0, maxArrowHeight / 2.0 );
00279   }
00280 
00281   rect.adjust( -enlarge, -enlarge, enlarge, enlarge );
00282   QgsComposerItem::setSceneRect( rect );
00283 }
00284 
00285 bool QgsComposerArrow::writeXML( QDomElement& elem, QDomDocument & doc ) const
00286 {
00287   QDomElement composerArrowElem = doc.createElement( "ComposerArrow" );
00288   composerArrowElem.setAttribute( "outlineWidth", QString::number( outlineWidth() ) );
00289   composerArrowElem.setAttribute( "arrowHeadWidth", QString::number( mArrowHeadWidth ) );
00290   composerArrowElem.setAttribute( "markerMode", mMarkerMode );
00291   composerArrowElem.setAttribute( "startMarkerFile", mStartMarkerFile );
00292   composerArrowElem.setAttribute( "endMarkerFile", mEndMarkerFile );
00293 
00294   //arrow color
00295   QDomElement arrowColorElem = doc.createElement( "ArrowColor" );
00296   arrowColorElem.setAttribute( "red", mArrowColor.red() );
00297   arrowColorElem.setAttribute( "green", mArrowColor.green() );
00298   arrowColorElem.setAttribute( "blue", mArrowColor.blue() );
00299   arrowColorElem.setAttribute( "alpha", mArrowColor.alpha() );
00300   composerArrowElem.appendChild( arrowColorElem );
00301 
00302   //start point
00303   QDomElement startPointElem = doc.createElement( "StartPoint" );
00304   startPointElem.setAttribute( "x", QString::number( mStartPoint.x() ) );
00305   startPointElem.setAttribute( "y", QString::number( mStartPoint.y() ) );
00306   composerArrowElem.appendChild( startPointElem );
00307 
00308   //stop point
00309   QDomElement stopPointElem = doc.createElement( "StopPoint" );
00310   stopPointElem.setAttribute( "x", QString::number( mStopPoint.x() ) );
00311   stopPointElem.setAttribute( "y", QString::number( mStopPoint.y() ) );
00312   composerArrowElem.appendChild( stopPointElem );
00313 
00314   elem.appendChild( composerArrowElem );
00315   return _writeXML( composerArrowElem, doc );
00316 }
00317 
00318 bool QgsComposerArrow::readXML( const QDomElement& itemElem, const QDomDocument& doc )
00319 {
00320   mArrowHeadWidth = itemElem.attribute( "arrowHeadWidth", "2.0" ).toDouble();
00321   mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
00322   setStartMarker( itemElem.attribute( "startMarkerFile", "" ) );
00323   setEndMarker( itemElem.attribute( "endMarkerFile", "" ) );
00324   mMarkerMode = QgsComposerArrow::MarkerMode( itemElem.attribute( "markerMode", "0" ).toInt() );
00325 
00326   //arrow color
00327   QDomNodeList arrowColorList = itemElem.elementsByTagName( "ArrowColor" );
00328   if ( arrowColorList.size() > 0 )
00329   {
00330     QDomElement arrowColorElem = arrowColorList.at( 0 ).toElement();
00331     int red = arrowColorElem.attribute( "red", "0" ).toInt();
00332     int green = arrowColorElem.attribute( "green", "0" ).toInt();
00333     int blue = arrowColorElem.attribute( "blue", "0" ).toInt();
00334     int alpha = arrowColorElem.attribute( "alpha", "255" ).toInt();
00335     mArrowColor = QColor( red, green, blue, alpha );
00336   }
00337 
00338   //restore general composer item properties
00339   //needs to be before start point / stop point because setSceneRect()
00340   QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
00341   if ( composerItemList.size() > 0 )
00342   {
00343     QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
00344     _readXML( composerItemElem, doc );
00345   }
00346 
00347   //start point
00348   QDomNodeList startPointList = itemElem.elementsByTagName( "StartPoint" );
00349   if ( startPointList.size() > 0 )
00350   {
00351     QDomElement startPointElem = startPointList.at( 0 ).toElement();
00352     mStartPoint.setX( startPointElem.attribute( "x", "0.0" ).toDouble() );
00353     mStartPoint.setY( startPointElem.attribute( "y", "0.0" ).toDouble() );
00354   }
00355 
00356   //stop point
00357   QDomNodeList stopPointList = itemElem.elementsByTagName( "StopPoint" );
00358   if ( stopPointList.size() > 0 )
00359   {
00360     QDomElement stopPointElem = stopPointList.at( 0 ).toElement();
00361     mStopPoint.setX( stopPointElem.attribute( "x", "0.0" ).toDouble() );
00362     mStopPoint.setY( stopPointElem.attribute( "y", "0.0" ).toDouble() );
00363   }
00364 
00365   adaptItemSceneRect();
00366   emit itemChanged();
00367   return true;
00368 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines