Skip to content

Commit

Permalink
Keep shape and composer picture size during rotation. Adapt the item …
Browse files Browse the repository at this point in the history
…size instead

git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@12262 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent committed Nov 26, 2009
1 parent 7e01bf9 commit eaec7ac
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 55 deletions.
9 changes: 8 additions & 1 deletion python/core/qgscomposeritem.sip
Expand Up @@ -145,7 +145,7 @@ class QgsComposerItem: QObject, QGraphicsRectItem
double rotation() const;

public slots:
void setRotation( double r);
virtual void setRotation( double r);

protected:

Expand Down Expand Up @@ -200,6 +200,13 @@ class QgsComposerItem: QObject, QGraphicsRectItem
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;
/**Returns a point on the line from startPoint to directionPoint that is a certain distance away from the starting point*/
QPointF pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance ) const;
/**Calculates width / height of the bounding box of a rotated rectangle (mRotation)*/
void sizeChangedByRotation(double& width, double& height);
/**Rotates a point / vector
@param angle rotation angle in degrees, counterclockwise
@param x in/out: x coordinate before / after the rotation
@param y in/out: y cooreinate before / after the rotation*/
void rotate( double angle, double& x, double& y ) const;

signals:
/**Is emitted on rotation change to notify north arrow pictures*/
Expand Down
3 changes: 3 additions & 0 deletions python/core/qgscomposerpicture.sip
Expand Up @@ -41,6 +41,9 @@ class QgsComposerPicture: QgsComposerItem
/**True if the rotation is taken from a map item*/
bool useRotationMap() const;

public slots:
virtual void setRotation( double r );


signals:
/**Tell the configuration widget that the settings need to be updated*/
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -202,6 +202,7 @@ composer/qgscomposerpicture.h
composer/qgscomposerscalebar.h
composer/qgscomposeritem.h
composer/qgscomposeritemgroup.h
composer/qgscomposershape.h
composer/qgscomposition.h
composer/qgslegendmodel.h
symbology/qgsmarkercatalogue.h
Expand Down
47 changes: 47 additions & 0 deletions src/core/composer/qgscomposeritem.cpp
Expand Up @@ -948,3 +948,50 @@ QPointF QgsComposerItem::pointOnLineWithDistance( const QPointF& startPoint, con
double scaleFactor = distance / length;
return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
}

void QgsComposerItem::sizeChangedByRotation( double& width, double& height )
{
if ( mRotation == 0.0 )
{
return;
}

//vector to p1
double x1 = -width / 2.0;
double y1 = -height / 2.0;
rotate( mRotation, x1, y1 );
//vector to p2
double x2 = width / 2.0;
double y2 = -height / 2.0;
rotate( mRotation, x2, y2 );
//vector to p3
double x3 = width / 2.0;
double y3 = height / 2.0;
rotate( mRotation, x3, y3 );
//vector to p4
double x4 = -width / 2.0;
double y4 = height / 2.0;
rotate( mRotation, x4, y4 );

//double midpoint
QPointF midpoint( width / 2.0, height / 2.0 );

QPolygonF rotatedRectPoly;
rotatedRectPoly << QPointF( midpoint.x() + x1, midpoint.y() + y1 );
rotatedRectPoly << QPointF( midpoint.x() + x2, midpoint.y() + y2 );
rotatedRectPoly << QPointF( midpoint.x() + x3, midpoint.y() + y3 );
rotatedRectPoly << QPointF( midpoint.x() + x4, midpoint.y() + y4 );
QRectF boundingRect = rotatedRectPoly.boundingRect();
width = boundingRect.width();
height = boundingRect.height();
}

void QgsComposerItem::rotate( double angle, double& x, double& y ) const
{
double rotToRad = angle * M_PI / 180.0;
double xRot, yRot;
xRot = x * cos( rotToRad ) - y * sin( rotToRad );
yRot = x * sin( rotToRad ) + y * cos( rotToRad );
x = xRot;
y = yRot;
}
11 changes: 10 additions & 1 deletion src/core/composer/qgscomposeritem.h
Expand Up @@ -172,7 +172,7 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
double rotation() const {return mRotation;}

public slots:
void setRotation( double r );
virtual void setRotation( double r );

protected:

Expand Down Expand Up @@ -245,12 +245,21 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
@note: this function was introduced in version 1.2*/
double horizontalViewScaleFactor() const;

//some utility functions

/**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation*/
bool imageSizeConsideringRotation( double& width, double& height ) const;
/**Calculates corner point after rotation and scaling*/
bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const;
/**Returns a point on the line from startPoint to directionPoint that is a certain distance away from the starting point*/
QPointF pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance ) const;
/**Calculates width / height of the bounding box of a rotated rectangle (mRotation)*/
void sizeChangedByRotation( double& width, double& height );
/**Rotates a point / vector
@param angle rotation angle in degrees, counterclockwise
@param x in/out: x coordinate before / after the rotation
@param y in/out: y cooreinate before / after the rotation*/
void rotate( double angle, double& x, double& y ) const;

signals:
/**Is emitted on rotation change to notify north arrow pictures*/
Expand Down
21 changes: 0 additions & 21 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -1383,24 +1383,3 @@ QgsComposerMap::Border QgsComposerMap::borderForLineCoord( const QPointF& p ) co
return Bottom;
}
}

void QgsComposerMap::rotate( double angle, double& x, double& y ) const
{
double rotToRad = angle * M_PI / 180.0;
double xRot, yRot;
xRot = x * cos( rotToRad ) - y * sin( rotToRad );
yRot = x * sin( rotToRad ) + y * cos( rotToRad );
x = xRot;
y = yRot;
}

#if 0
QPointF QgsComposerMap::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance ) const
{
double dx = directionPoint.x() - startPoint.x();
double dy = directionPoint.y() - startPoint.y();
double length = sqrt( dx * dx + dy * dy );
double scaleFactor = distance / length;
return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
}
#endif //0
9 changes: 0 additions & 9 deletions src/core/composer/qgscomposermap.h
Expand Up @@ -381,15 +381,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
QPointF mapToItemCoords( const QPointF& mapCoords ) const;
/**Returns the item border of a point (in item coordinates)*/
Border borderForLineCoord( const QPointF& p ) const;
/**Rotates a point / vector
@param angle rotation angle in degrees, counterclockwise
@param x in/out: x coordinate before / after the rotation
@param y in/out: y cooreinate before / after the rotation*/
void rotate( double angle, double& x, double& y ) const;
#if 0
/**Returns a point on the line from startPoint to directionPoint that is a certain distance away from the starting point*/
QPointF pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance ) const;
#endif //0
};

#endif
73 changes: 59 additions & 14 deletions src/core/composer/qgscomposerpicture.cpp
Expand Up @@ -30,11 +30,12 @@
QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ): QgsComposerItem( composition ), mMode( Unknown ), \
mSvgCacheUpToDate( false ), mCachedDpi( 0 ), mCachedRotation( 0 ), mCachedViewScaleFactor( -1 ), mRotationMap( 0 )
{
mPictureWidth = rect().width();
}

QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mSvgCacheUpToDate( false ), mCachedRotation( 0 ), mCachedViewScaleFactor( -1 ), mRotationMap( 0 )
{

mPictureHeight = rect().height();
}

QgsComposerPicture::~QgsComposerPicture()
Expand All @@ -61,8 +62,8 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte

if ( mMode != Unknown )
{
double rectPixelWidth = rect().width() * newDpi / 25.4;
double rectPixelHeight = rect().height() * newDpi / 25.4;
double rectPixelWidth = /*rect().width()*/mPictureWidth * newDpi / 25.4;
double rectPixelHeight = /*rect().height()*/ mPictureHeight * newDpi / 25.4;
QRectF boundRect;
if ( mMode == SVG )
{
Expand All @@ -75,11 +76,8 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte

double boundRectWidthMM = boundRect.width() / newDpi * 25.4;
double boundRectHeightMM = boundRect.height() / newDpi * 25.4;
double rotatedBoundImageWidth = boundRect.width();
double rotatedBoundImageHeight = boundRect.height();
imageSizeConsideringRotation( rotatedBoundImageWidth, rotatedBoundImageHeight );
double rotatedBoundImageWidthMM = rotatedBoundImageWidth / newDpi * 25.4;
double rotatedBoundImageHeightMM = rotatedBoundImageHeight / newDpi * 25.4;
double boundImageWidth = boundRect.width();
double boundImageHeight = boundRect.height();

if ( mMode == SVG )
{
Expand All @@ -88,20 +86,20 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte
//make nicer preview
if ( mComposition && mComposition->plotStyle() == QgsComposition::Preview )
{
rotatedBoundImageWidth *= std::min( viewScaleFactor, 10.0 );
rotatedBoundImageHeight *= std::min( viewScaleFactor, 10.0 );
boundImageWidth *= std::min( viewScaleFactor, 10.0 );
boundImageHeight *= std::min( viewScaleFactor, 10.0 );
}
mImage = QImage( rotatedBoundImageWidth, rotatedBoundImageHeight, QImage::Format_ARGB32 );
mImage = QImage( boundImageWidth, boundImageHeight, QImage::Format_ARGB32 );
updateImageFromSvg();
}
}

painter->save();
painter->translate( boundRectWidthMM / 2.0, boundRectHeightMM / 2.0 );
painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
painter->rotate( mRotation );
painter->translate( -rotatedBoundImageWidthMM / 2.0, -rotatedBoundImageHeightMM / 2.0 );
painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );

painter->drawImage( QRectF( 0, 0, rotatedBoundImageWidthMM, rotatedBoundImageHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );

painter->restore();
}
Expand Down Expand Up @@ -183,6 +181,24 @@ QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHe
}
}

QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
{
double imageToSvgRatio;
if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
{
imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
double width = mDefaultSvgSize.width() * imageToSvgRatio;
return QRectF( 0, 0, width, deviceHeight );
}
else
{
imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
double height = mDefaultSvgSize.height() * imageToSvgRatio;
return QRectF( 0, 0, deviceWidth, height );
}
}

#if 0
QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
{
double imageToSvgRatio;
Expand All @@ -199,6 +215,7 @@ QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeig
return QRectF( 0, 0, width, deviceHeight );
}
}
#endif //0

void QgsComposerPicture::updateImageFromSvg()
{
Expand All @@ -216,9 +233,32 @@ void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
{
mSvgCacheUpToDate = false;
QgsComposerItem::setSceneRect( rectangle );

//consider to change size of the shape if the rectangle changes width and/or height
double newPictureWidth = rectangle.width();
double newPictureHeight = rectangle.height();
imageSizeConsideringRotation( newPictureWidth, newPictureHeight );
mPictureWidth = newPictureWidth;
mPictureHeight = newPictureHeight;

emit settingsChanged();
}

void QgsComposerPicture::setRotation( double r )
{
//adapt rectangle size
double width = mPictureWidth;
double height = mPictureHeight;
sizeChangedByRotation( width, height );

//adapt scene rect to have the same center and the new width / height
double x = transform().dx() + rect().width() / 2.0 - width / 2.0;
double y = transform().dy() + rect().height() / 2.0 - height / 2.0;
QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );

QgsComposerItem::setRotation( r );
}

void QgsComposerPicture::setRotationMap( int composerMapId )
{
if ( !mComposition )
Expand Down Expand Up @@ -260,6 +300,8 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
}
QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
composerPictureElem.setAttribute( "pictureWidth", mPictureWidth );
composerPictureElem.setAttribute( "pictureHeight", mPictureHeight );
if ( !mRotationMap )
{
composerPictureElem.setAttribute( "mapId", -1 );
Expand All @@ -281,6 +323,9 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
return false;
}

mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();

QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )
{
Expand Down
11 changes: 9 additions & 2 deletions src/core/composer/qgscomposerpicture.h
Expand Up @@ -39,7 +39,7 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
QString pictureFile() const;

/**Sets this items bound in scene coordinates such that 1 item size units
corresponds to 1 scene size unit*/
corresponds to 1 scene size unit and resizes the svg symbol / image*/
void setSceneRect( const QRectF& rectangle );

/** stores state in Dom node
Expand All @@ -60,6 +60,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
/**True if the rotation is taken from a map item*/
bool useRotationMap() const {return mRotationMap;}

public slots:
/**Sets the rotation and adapts the item rect*/
virtual void setRotation( double r );

private:

enum Mode //SVG or raster graphic format
Expand Down Expand Up @@ -94,7 +98,10 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem
QSize mDefaultSvgSize;
/**Map that sets the rotation (or 0 if this picture uses map independent rotation)*/
const QgsComposerMap* mRotationMap;

/**Width of the picture (in mm)*/
double mPictureWidth;
/**Height of the picture (in mm)*/
double mPictureHeight;

signals:
/**Tell the configuration widget that the settings need to be updated*/
Expand Down

0 comments on commit eaec7ac

Please sign in to comment.