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