|
QGIS API Documentation
master-59fd5e0
|
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 }