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