Update decorators to avoid relying on map canvas when rendering (#4388)

This commit is contained in:
Mathieu Pellerin 2017-04-21 12:06:24 +07:00 committed by GitHub
parent db848a3f1a
commit e0d20e537d
15 changed files with 215 additions and 245 deletions

View File

@ -82,6 +82,7 @@
%Include qgslegendsettings.sip
%Include qgslegendstyle.sip
%Include qgslogger.sip
%Include qgsmapdecoration.sip
%Include qgsmaphittest.sip
%Include qgsmaplayer.sip
%Include qgsmaplayerdependency.sip

View File

@ -0,0 +1,46 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsmapdecoration.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsMapDecoration
{
%Docstring
Interface for map decorations.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsmapdecoration.h"
%End
public:
QgsMapDecoration();
%Docstring
Constructor for QgsMapDecoration.
%End
virtual ~QgsMapDecoration();
virtual void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) = 0;
%Docstring
Renders a map decoration.
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsmapdecoration.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -3484,9 +3484,12 @@ void QgisApp::createDecorations()
void QgisApp::renderDecorationItems( QPainter *p )
{
QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapCanvas->mapSettings() );
context.setPainter( p );
Q_FOREACH ( QgsDecorationItem *item, mDecorationItems )
{
item->render( p );
item->render( mMapCanvas->mapSettings(), context );
}
}

View File

@ -91,14 +91,15 @@ void QgsDecorationCopyright::run()
}
void QgsDecorationCopyright::render( QPainter *theQPainter )
void QgsDecorationCopyright::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
Q_UNUSED( mapSettings );
//Large IF statement to enable/disable copyright label
if ( enabled() )
{
// need width/height of paint device
int myHeight = theQPainter->device()->height();
int myWidth = theQPainter->device()->width();
int myHeight = context.painter()->device()->height();
int myWidth = context.painter()->device()->width();
QTextDocument text;
text.setDefaultFont( mQFont );
@ -115,8 +116,8 @@ void QgsDecorationCopyright::render( QPainter *theQPainter )
{
case QgsUnitTypes::RenderMillimeters:
{
int myPixelsInchX = theQPainter->device()->logicalDpiX();
int myPixelsInchY = theQPainter->device()->logicalDpiY();
int myPixelsInchX = context.painter()->device()->logicalDpiX();
int myPixelsInchY = context.painter()->device()->logicalDpiY();
myXOffset = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal;
myYOffset = myPixelsInchY * INCHES_TO_MM * mMarginVertical;
break;
@ -156,11 +157,11 @@ void QgsDecorationCopyright::render( QPainter *theQPainter )
}
//Paint label to canvas
QMatrix worldMatrix = theQPainter->worldMatrix();
theQPainter->translate( myXOffset, myYOffset );
text.drawContents( theQPainter );
QMatrix worldMatrix = context.painter()->worldMatrix();
context.painter()->translate( myXOffset, myYOffset );
text.drawContents( context.painter() );
// Put things back how they were
theQPainter->setWorldMatrix( worldMatrix );
context.painter()->setWorldMatrix( worldMatrix );
}
}

View File

@ -47,7 +47,7 @@ class APP_EXPORT QgsDecorationCopyright : public QgsDecorationItem
//! Show the dialog box
void run() override;
//! render the copyright label
void render( QPainter * ) override;
void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) override;
private:
//! This is the font that will be used for the copyright label

View File

@ -208,7 +208,7 @@ void QgsDecorationGrid::run()
}
}
void QgsDecorationGrid::render( QPainter *p )
void QgsDecorationGrid::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
if ( ! mEnabled )
return;
@ -216,9 +216,9 @@ void QgsDecorationGrid::render( QPainter *p )
// p->setPen( mGridPen );
QList< QPair< qreal, QLineF > > verticalLines;
yGridLines( verticalLines );
yGridLines( mapSettings, verticalLines );
QList< QPair< qreal, QLineF > > horizontalLines;
xGridLines( horizontalLines );
xGridLines( mapSettings, horizontalLines );
//QgsDebugMsg( QString("grid has %1 vertical and %2 horizontal lines").arg( verticalLines.size() ).arg( horizontalLines.size() ) );
QList< QPair< qreal, QLineF > >::const_iterator vIt = verticalLines.constBegin();
@ -230,13 +230,11 @@ void QgsDecorationGrid::render( QPainter *p )
if ( ! mLineSymbol )
return;
QgsRenderContext context = QgsRenderContext::fromMapSettings( QgisApp::instance()->mapCanvas()->mapSettings() );
context.setPainter( p );
mLineSymbol->startRender( context );
for ( ; vIt != verticalLines.constEnd(); ++vIt )
{
// p->drawLine( vIt->second );
// context.painter()->drawLine( vIt->second );
// need to convert QLineF to QPolygonF ...
QVector<QPointF> poly;
poly << vIt->second.p1() << vIt->second.p2();
@ -245,7 +243,7 @@ void QgsDecorationGrid::render( QPainter *p )
for ( ; hIt != horizontalLines.constEnd(); ++hIt )
{
// p->drawLine( hIt->second );
// context.painter()->drawLine( hIt->second );
// need to convert QLineF to QPolygonF ...
QVector<QPointF> poly;
poly << hIt->second.p1() << hIt->second.p2();
@ -262,7 +260,7 @@ void QgsDecorationGrid::render( QPainter *p )
{
//start mark
crossEnd1 = QgsSymbolLayerUtils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
p->drawLine( vIt->second.p1(), crossEnd1 );
context.painter()->drawLine( vIt->second.p1(), crossEnd1 );
//test for intersection with every horizontal line
hIt = horizontalLines.constBegin();
@ -272,12 +270,12 @@ void QgsDecorationGrid::render( QPainter *p )
{
crossEnd1 = QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
crossEnd2 = QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
p->drawLine( crossEnd1, crossEnd2 );
context.painter()->drawLine( crossEnd1, crossEnd2 );
}
}
//end mark
QPointF crossEnd2 = QgsSymbolLayerUtils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
p->drawLine( vIt->second.p2(), crossEnd2 );
context.painter()->drawLine( vIt->second.p2(), crossEnd2 );
}
hIt = horizontalLines.constBegin();
@ -285,7 +283,7 @@ void QgsDecorationGrid::render( QPainter *p )
{
//start mark
crossEnd1 = QgsSymbolLayerUtils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
p->drawLine( hIt->second.p1(), crossEnd1 );
context.painter()->drawLine( hIt->second.p1(), crossEnd1 );
vIt = verticalLines.constBegin();
for ( ; vIt != verticalLines.constEnd(); ++vIt )
@ -294,12 +292,12 @@ void QgsDecorationGrid::render( QPainter *p )
{
crossEnd1 = QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
crossEnd2 = QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
p->drawLine( crossEnd1, crossEnd2 );
context.painter()->drawLine( crossEnd1, crossEnd2 );
}
}
//end mark
crossEnd1 = QgsSymbolLayerUtils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
p->drawLine( hIt->second.p2(), crossEnd1 );
context.painter()->drawLine( hIt->second.p2(), crossEnd1 );
}
}
#endif
@ -308,8 +306,6 @@ void QgsDecorationGrid::render( QPainter *p )
if ( ! mMarkerSymbol )
return;
QgsRenderContext context = QgsRenderContext::fromMapSettings( QgisApp::instance()->mapCanvas()->mapSettings() );
context.setPainter( p );
mMarkerSymbol->startRender( context );
QPointF intersectionPoint;
@ -332,7 +328,7 @@ void QgsDecorationGrid::render( QPainter *p )
if ( mShowGridAnnotation )
{
drawCoordinateAnnotations( p, horizontalLines, verticalLines );
drawCoordinateAnnotations( context.painter(), horizontalLines, verticalLines );
}
}
@ -511,17 +507,9 @@ void QgsDecorationGrid::drawAnnotation( QPainter *p, QPointF pos, int rotation,
p->restore();
}
const QgsMapCanvas &canvas()
{
return *QgisApp::instance()->mapCanvas();
}
QPolygonF canvasPolygon()
QPolygonF canvasPolygon( const QgsMapSettings &mapSettings )
{
QPolygonF poly;
const QgsMapCanvas &mapCanvas = canvas();
const QgsMapSettings &mapSettings = mapCanvas.mapSettings();
return mapSettings.visiblePolygon();
}
@ -553,10 +541,10 @@ bool clipByRect( QLineF &line, const QPolygonF &rect )
return true;
}
QPolygonF canvasExtent()
QPolygonF canvasExtent( const QgsMapSettings &mapSettings )
{
QPolygonF poly;
QgsRectangle extent = canvas().extent();
QgsRectangle extent = mapSettings.visibleExtent();
poly << QPointF( extent.xMinimum(), extent.yMaximum() );
poly << QPointF( extent.xMaximum(), extent.yMaximum() );
poly << QPointF( extent.xMaximum(), extent.yMinimum() );
@ -564,7 +552,7 @@ QPolygonF canvasExtent()
return poly;
}
int QgsDecorationGrid::xGridLines( QList< QPair< qreal, QLineF > > &lines ) const
int QgsDecorationGrid::xGridLines( const QgsMapSettings &mapSettings, QList< QPair< qreal, QLineF > > &lines ) const
{
// prepare horizontal lines
lines.clear();
@ -573,8 +561,6 @@ int QgsDecorationGrid::xGridLines( QList< QPair< qreal, QLineF > > &lines ) cons
return 1;
}
const QgsMapCanvas &mapCanvas = canvas();
const QgsMapSettings &mapSettings = mapCanvas.mapSettings();
const QgsMapToPixel &m2p = mapSettings.mapToPixel();
// draw nothing if the distance between grid lines would be less than 1px
@ -583,8 +569,8 @@ int QgsDecorationGrid::xGridLines( QList< QPair< qreal, QLineF > > &lines ) cons
if ( mGridIntervalY / mapSettings.mapUnitsPerPixel() < 1 )
return 1;
const QPolygonF &canvasPoly = canvasPolygon();
const QPolygonF &mapPolygon = canvasExtent();
const QPolygonF &canvasPoly = canvasPolygon( mapSettings );
const QPolygonF &mapPolygon = canvasExtent( mapSettings );
const QRectF &mapBoundingRect = mapPolygon.boundingRect();
QLineF lineEast( mapPolygon[2], mapPolygon[1] );
QLineF lineWest( mapPolygon[3], mapPolygon[0] );
@ -610,7 +596,7 @@ int QgsDecorationGrid::xGridLines( QList< QPair< qreal, QLineF > > &lines ) cons
return 0;
}
int QgsDecorationGrid::yGridLines( QList< QPair< qreal, QLineF > > &lines ) const
int QgsDecorationGrid::yGridLines( const QgsMapSettings &mapSettings, QList< QPair< qreal, QLineF > > &lines ) const
{
// prepare vertical lines
@ -620,8 +606,6 @@ int QgsDecorationGrid::yGridLines( QList< QPair< qreal, QLineF > > &lines ) cons
return 1;
}
const QgsMapCanvas &mapCanvas = canvas();
const QgsMapSettings &mapSettings = mapCanvas.mapSettings();
const QgsMapToPixel &m2p = mapSettings.mapToPixel();
// draw nothing if the distance between grid lines would be less than 1px
@ -630,8 +614,8 @@ int QgsDecorationGrid::yGridLines( QList< QPair< qreal, QLineF > > &lines ) cons
if ( mGridIntervalX / mapSettings.mapUnitsPerPixel() < 1 )
return 1;
const QPolygonF &canvasPoly = canvasPolygon();
const QPolygonF &mapPolygon = canvasExtent();
const QPolygonF &canvasPoly = canvasPolygon( mapSettings );
const QPolygonF &mapPolygon = canvasExtent( mapSettings );
QLineF lineSouth( mapPolygon[3], mapPolygon[2] );
QLineF lineNorth( mapPolygon[0], mapPolygon[1] );

View File

@ -146,7 +146,7 @@ class APP_EXPORT QgsDecorationGrid: public QgsDecorationItem
void saveToProject() override;
//! this does the meaty bit of the work
void render( QPainter * ) override;
void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) override;
//! Show the dialog box
void run() override;
@ -212,11 +212,12 @@ class APP_EXPORT QgsDecorationGrid: public QgsDecorationItem
/** Returns the grid lines with associated coordinate value
\returns 0 in case of success*/
int xGridLines( QList< QPair< qreal, QLineF > > &lines ) const;
int xGridLines( const QgsMapSettings &mapSettings, QList< QPair< qreal, QLineF > > &lines ) const;
/** Returns the grid lines for the y-coordinates. Not vertical in case of rotation
\returns 0 in case of success*/
int yGridLines( QList< QPair< qreal, QLineF > > &lines ) const;
int yGridLines( const QgsMapSettings &mapSettings, QList< QPair< qreal, QLineF > > &lines ) const;
//! Returns the item border of a point (in item coordinates)
Border borderForLineCoord( QPointF point, QPainter *p ) const;

View File

@ -21,6 +21,7 @@
#include "qgisapp.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmapdecoration.h"
#include "qgsmaplayer.h"
#include "qgsmaptopixel.h"
#include "qgspoint.h"

View File

@ -19,6 +19,8 @@
#define QGSDECORATIONITEM_H
#include <QObject>
#include "qgsmapdecoration.h"
#include "qgsunittypes.h"
#include "qgis_app.h"
@ -26,9 +28,10 @@ class QPainter;
#define INCHES_TO_MM 0.0393700787402
class APP_EXPORT QgsDecorationItem: public QObject
class APP_EXPORT QgsDecorationItem : public QObject, public QgsMapDecoration
{
Q_OBJECT
public:
//! Item placements
@ -67,8 +70,6 @@ class APP_EXPORT QgsDecorationItem: public QObject
//! save values to the project
virtual void saveToProject();
//! this does the meaty bit of the work
virtual void render( QPainter * ) {}
//! Show the dialog box
virtual void run() {}

View File

@ -25,11 +25,11 @@ email : tim@linfiniti.com
#include "qgsdecorationnortharrowdialog.h"
#include "qgisapp.h"
#include "qgsbearingutils.h"
#include "qgscoordinatetransform.h"
#include "qgsmaplayer.h"
#include "qgsproject.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgscsexception.h"
// qt includes
@ -95,7 +95,7 @@ void QgsDecorationNorthArrow::run()
dlg.exec();
}
void QgsDecorationNorthArrow::render( QPainter *theQPainter )
void QgsDecorationNorthArrow::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
//Large IF statement controlled by enable check box
@ -110,7 +110,7 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
double centerXDouble = myQPixmap.width() / 2.0;
double centerYDouble = myQPixmap.height() / 2.0;
//save the current canvas rotation
theQPainter->save();
context.painter()->save();
//
//work out how to shift the image so that it rotates
// properly about its center
@ -120,7 +120,10 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
// could move this call to somewhere else so that it is only
// called when the projection or map extent changes
if ( mAutomatic )
calculateNorthDirection();
{
mRotationInt = QgsBearingUtils:: bearingTrueNorth( mapSettings.destinationCrs(), context.extent().center() );
mRotationInt += mapSettings.rotation();
}
double myRadiansDouble = mRotationInt * M_PI / 180.0;
int xShift = static_cast<int>( (
@ -133,8 +136,8 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
) - centerYDouble );
// need width/height of paint device
int myHeight = theQPainter->device()->height();
int myWidth = theQPainter->device()->width();
int myHeight = context.painter()->device()->height();
int myWidth = context.painter()->device()->width();
//QgsDebugMsg("Rendering north arrow at " + mPlacementLabels.at(mPlacementIndex));
@ -145,8 +148,8 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
{
case QgsUnitTypes::RenderMillimeters:
{
int myPixelsInchX = theQPainter->device()->logicalDpiX();
int myPixelsInchY = theQPainter->device()->logicalDpiY();
int myPixelsInchX = context.painter()->device()->logicalDpiX();
int myPixelsInchY = context.painter()->device()->logicalDpiY();
myXOffset = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal;
myYOffset = myPixelsInchY * INCHES_TO_MM * mMarginVertical;
break;
@ -169,17 +172,17 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
switch ( mPlacement )
{
case BottomLeft:
theQPainter->translate( myXOffset, myHeight - myYOffset - myQPixmap.height() );
context.painter()->translate( myXOffset, myHeight - myYOffset - myQPixmap.height() );
break;
case TopLeft:
theQPainter->translate( myXOffset, myYOffset );
context.painter()->translate( myXOffset, myYOffset );
break;
case TopRight:
theQPainter->translate( myWidth - myXOffset - myQPixmap.width(), myYOffset );
context.painter()->translate( myWidth - myXOffset - myQPixmap.width(), myYOffset );
break;
case BottomRight:
theQPainter->translate( myWidth - myXOffset - myQPixmap.width(),
myHeight - myYOffset - myQPixmap.height() );
context.painter()->translate( myWidth - myXOffset - myQPixmap.width(),
myHeight - myYOffset - myQPixmap.height() );
break;
default:
{
@ -188,136 +191,21 @@ void QgsDecorationNorthArrow::render( QPainter *theQPainter )
}
//rotate the canvas by the north arrow rotation amount
theQPainter->rotate( mRotationInt );
context.painter()->rotate( mRotationInt );
//Now we can actually do the drawing, and draw a smooth north arrow even when rotated
theQPainter->setRenderHint( QPainter::SmoothPixmapTransform );
theQPainter->drawPixmap( xShift, yShift, myQPixmap );
context.painter()->setRenderHint( QPainter::SmoothPixmapTransform );
context.painter()->drawPixmap( xShift, yShift, myQPixmap );
//unrotate the canvas again
theQPainter->restore();
context.painter()->restore();
}
else
{
QFont myQFont( QStringLiteral( "time" ), 12, QFont::Bold );
theQPainter->setFont( myQFont );
theQPainter->setPen( Qt::black );
theQPainter->drawText( 10, 20, tr( "North arrow pixmap not found" ) );
context.painter()->setFont( myQFont );
context.painter()->setPen( Qt::black );
context.painter()->drawText( 10, 20, tr( "North arrow pixmap not found" ) );
}
}
}
bool QgsDecorationNorthArrow::calculateNorthDirection()
{
QgsMapCanvas *mapCanvas = QgisApp::instance()->mapCanvas();
bool goodDirn = false;
// Get the shown extent...
QgsRectangle canvasExtent = mapCanvas->extent();
// ... and all layers extent, ...
QgsRectangle fullExtent = mapCanvas->fullExtent();
// ... and combine
QgsRectangle extent = canvasExtent.intersect( & fullExtent );
// If no layers are added or shown, we can't get any direction
if ( mapCanvas->layerCount() > 0 && ! extent.isEmpty() )
{
QgsCoordinateReferenceSystem outputCRS = mapCanvas->mapSettings().destinationCrs();
if ( outputCRS.isValid() && !outputCRS.isGeographic() )
{
// Use a geographic CRS to get lat/long to work out direction
QgsCoordinateReferenceSystem ourCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
assert( ourCRS.isValid() );
QgsCoordinateTransform transform( outputCRS, ourCRS );
QgsPoint p1( extent.center() );
// A point a bit above p1. XXX assumes that y increases up!!
// May need to involve the maptopixel transform if this proves
// to be a problem.
QgsPoint p2( p1.x(), p1.y() + extent.height() * 0.25 );
// project p1 and p2 to geographic coords
try
{
p1 = transform.transform( p1 );
p2 = transform.transform( p2 );
}
catch ( QgsCsException &e )
{
Q_UNUSED( e );
// just give up
QgsDebugMsg( "North Arrow: Transformation error, quitting" );
return false;
}
// Work out the value of the initial heading one takes to go
// from point p1 to point p2. The north direction is then that
// many degrees anti-clockwise or vertical.
// Take some care to not divide by zero, etc, and ensure that we
// get sensible results for all possible values for p1 and p2.
goodDirn = true;
double angle = 0.0;
// convert to radians for the equations below
p1.multiply( M_PI / 180.0 );
p2.multiply( M_PI / 180.0 );
double y = sin( p2.x() - p1.x() ) * cos( p2.y() );
double x = cos( p1.y() ) * sin( p2.y() ) -
sin( p1.y() ) * cos( p2.y() ) * cos( p2.x() - p1.x() );
// Use TOL to decide if the quotient is big enough.
// Both x and y can be very small, if heavily zoomed
// For small y/x, we set directly angle 0. Not sure
// if this is needed.
if ( y > 0.0 )
{
if ( x > 0.0 && ( y / x ) > TOL )
angle = atan( y / x );
else if ( x < 0.0 && ( y / x ) < -TOL )
angle = M_PI - atan( -y / x );
else
angle = 0.5 * M_PI;
}
else if ( y < 0.0 )
{
if ( x > 0.0 && ( y / x ) < -TOL )
angle = -atan( -y / x );
else if ( x < 0.0 && ( y / x ) > TOL )
angle = atan( y / x ) - M_PI;
else
angle = 1.5 * M_PI;
}
else
{
if ( x > TOL )
angle = 0.0;
else if ( x < -TOL )
angle = M_PI;
else
{
angle = 0.0; // p1 = p2
goodDirn = false;
}
}
// And set the angle of the north arrow. Perhaps do something
// different if goodDirn = false.
mRotationInt = qRound( fmod( 360.0 - angle * 180.0 / M_PI, 360.0 ) );
}
else
{
// For geographic CRS and for when there are no layers, set the
// direction back to the default
mRotationInt = 0;
}
}
mRotationInt += mapCanvas->mapSettings().rotation();
return goodDirn;
}

View File

@ -47,13 +47,7 @@ class APP_EXPORT QgsDecorationNorthArrow: public QgsDecorationItem
//! Show the dialog box
void run() override;
//! draw some arbitrary text to the screen
void render( QPainter * ) override;
//! try to calculate the direction for the north arrow. Sets the
//! private class rotation variable. If unable to calculate the
//! direction, the function returns false and leaves the rotation
//! variable as is.
bool calculateNorthDirection();
void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) override;
private:

View File

@ -104,24 +104,22 @@ void QgsDecorationScaleBar::run()
}
void QgsDecorationScaleBar::render( QPainter *theQPainter )
void QgsDecorationScaleBar::render( const QgsMapSettings &mapSettings, QgsRenderContext &context )
{
QgsMapCanvas *canvas = QgisApp::instance()->mapCanvas();
int myBufferSize = 1; //softcode this later
//Get canvas dimensions
int myCanvasHeight = theQPainter->device()->height();
int myCanvasWidth = theQPainter->device()->width();
int myCanvasHeight = context.painter()->device()->height();
int myCanvasWidth = context.painter()->device()->width();
//Get map units per pixel. This can be negative at times (to do with
//projections) and that just confuses the rest of the code in this
//function, so force to a positive number.
double myMapUnitsPerPixelDouble = qAbs( canvas->mapUnitsPerPixel() );
double myMapUnitsPerPixelDouble = qAbs( context.mapToPixel().mapUnitsPerPixel() );
double myActualSize = mPreferredSize;
// Exit if the canvas width is 0 or layercount is 0 or QGIS will freeze
int myLayerCount = canvas->layerCount();
int myLayerCount = mapSettings.layers().count();
if ( !myLayerCount || !myCanvasWidth || !myMapUnitsPerPixelDouble )
return;
@ -137,7 +135,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
QgsUnitTypes::DistanceUnit myPreferredUnits = QgsUnitTypes::decodeDistanceUnit( settings.value( QStringLiteral( "qgis/measure/displayunits" ) ).toString(), &ok );
if ( !ok )
myPreferredUnits = QgsUnitTypes::DistanceMeters;
QgsUnitTypes::DistanceUnit myMapUnits = canvas->mapUnits();
QgsUnitTypes::DistanceUnit myMapUnits = mapSettings.mapUnits();
// Adjust units meter/feet/... or vice versa
myMapUnitsPerPixelDouble *= QgsUnitTypes::fromUnitToUnitFactor( myMapUnits, myPreferredUnits );
@ -242,7 +240,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
//Set font and calculate width of unit label
int myFontSize = 10; //we use this later for buffering
QFont myFont( QStringLiteral( "helvetica" ), myFontSize );
theQPainter->setFont( myFont );
context.painter()->setFont( myFont );
QFontMetrics myFontMetrics( myFont );
double myFontWidth = myFontMetrics.width( myScaleBarUnitLabel );
double myFontHeight = myFontMetrics.height();
@ -263,8 +261,8 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
{
case QgsUnitTypes::RenderMillimeters:
{
int myPixelsInchX = theQPainter->device()->logicalDpiX();
int myPixelsInchY = theQPainter->device()->logicalDpiY();
int myPixelsInchX = context.painter()->device()->logicalDpiX();
int myPixelsInchY = context.painter()->device()->logicalDpiY();
myOriginX = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal;
myOriginY = myPixelsInchY * INCHES_TO_MM * mMarginVertical;
break;
@ -325,65 +323,65 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
{
QPolygon myTickDownArray( 4 );
//draw a buffer first so bar shows up on dark images
theQPainter->setPen( myBackgroundPen );
context.painter()->setPen( myBackgroundPen );
myTickDownArray.putPoints( 0, 4,
myOriginX, myOriginY + myMajorTickSize,
myOriginX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY + myMajorTickSize
);
theQPainter->drawPolyline( myTickDownArray );
context.painter()->drawPolyline( myTickDownArray );
//now draw the bar itself in user selected color
theQPainter->setPen( myForegroundPen );
context.painter()->setPen( myForegroundPen );
myTickDownArray.putPoints( 0, 4,
myOriginX, myOriginY + myMajorTickSize,
myOriginX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY + myMajorTickSize
);
theQPainter->drawPolyline( myTickDownArray );
context.painter()->drawPolyline( myTickDownArray );
break;
}
case 1: // tick up
{
QPolygon myTickUpArray( 4 );
//draw a buffer first so bar shows up on dark images
theQPainter->setPen( myBackgroundPen );
context.painter()->setPen( myBackgroundPen );
myTickUpArray.putPoints( 0, 4,
myOriginX, myOriginY,
myOriginX, myOriginY + myMajorTickSize,
myScaleBarWidthInt + myOriginX, myOriginY + myMajorTickSize,
myScaleBarWidthInt + myOriginX, myOriginY
);
theQPainter->drawPolyline( myTickUpArray );
context.painter()->drawPolyline( myTickUpArray );
//now draw the bar itself in user selected color
theQPainter->setPen( myForegroundPen );
context.painter()->setPen( myForegroundPen );
myTickUpArray.putPoints( 0, 4,
myOriginX, myOriginY,
myOriginX, myOriginY + myMajorTickSize,
myScaleBarWidthInt + myOriginX, myOriginY + myMajorTickSize,
myScaleBarWidthInt + myOriginX, myOriginY
);
theQPainter->drawPolyline( myTickUpArray );
context.painter()->drawPolyline( myTickUpArray );
break;
}
case 2: // Bar
{
QPolygon myBarArray( 2 );
//draw a buffer first so bar shows up on dark images
theQPainter->setPen( myBackgroundPen );
context.painter()->setPen( myBackgroundPen );
myBarArray.putPoints( 0, 2,
myOriginX, myOriginY + ( myMajorTickSize / 2 ),
myScaleBarWidthInt + myOriginX, myOriginY + ( myMajorTickSize / 2 )
);
theQPainter->drawPolyline( myBarArray );
context.painter()->drawPolyline( myBarArray );
//now draw the bar itself in user selected color
theQPainter->setPen( myForegroundPen );
context.painter()->setPen( myForegroundPen );
myBarArray.putPoints( 0, 2,
myOriginX, myOriginY + ( myMajorTickSize / 2 ),
myScaleBarWidthInt + myOriginX, myOriginY + ( myMajorTickSize / 2 )
);
theQPainter->drawPolyline( myBarArray );
context.painter()->drawPolyline( myBarArray );
break;
}
case 3: // box
@ -393,7 +391,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
myForegroundPen.setJoinStyle( Qt::MiterJoin );
QPolygon myBoxArray( 5 );
//draw a buffer first so bar shows up on dark images
theQPainter->setPen( myBackgroundPen );
context.painter()->setPen( myBackgroundPen );
myBoxArray.putPoints( 0, 5,
myOriginX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY,
@ -401,10 +399,10 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
myOriginX, myOriginY + myMajorTickSize,
myOriginX, myOriginY
);
theQPainter->drawPolyline( myBoxArray );
context.painter()->drawPolyline( myBoxArray );
//now draw the bar itself in user selected color
theQPainter->setPen( myForegroundPen );
theQPainter->setBrush( QBrush( mColor, Qt::SolidPattern ) );
context.painter()->setPen( myForegroundPen );
context.painter()->setBrush( QBrush( mColor, Qt::SolidPattern ) );
int midPointX = myScaleBarWidthInt / 2 + myOriginX;
myBoxArray.putPoints( 0, 5,
myOriginX, myOriginY,
@ -413,9 +411,9 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
myOriginX, myOriginY + myMajorTickSize,
myOriginX, myOriginY
);
theQPainter->drawPolygon( myBoxArray );
context.painter()->drawPolygon( myBoxArray );
theQPainter->setBrush( Qt::NoBrush );
context.painter()->setBrush( Qt::NoBrush );
myBoxArray.putPoints( 0, 5,
midPointX, myOriginY,
myScaleBarWidthInt + myOriginX, myOriginY,
@ -423,7 +421,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
midPointX, myOriginY + myMajorTickSize,
midPointX, myOriginY
);
theQPainter->drawPolygon( myBoxArray );
context.painter()->drawPolygon( myBoxArray );
break;
}
default:
@ -440,7 +438,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
QColor myForeColor = Qt::black;
//Draw the minimum label buffer
theQPainter->setPen( myBackColor );
context.painter()->setPen( myBackColor );
myFontWidth = myFontMetrics.width( QStringLiteral( "0" ) );
myFontHeight = myFontMetrics.height();
@ -448,16 +446,16 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
{
for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
{
theQPainter->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ),
int( j + ( myOriginY - ( myFontHeight / 4 ) ) ),
QStringLiteral( "0" ) );
context.painter()->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ),
int( j + ( myOriginY - ( myFontHeight / 4 ) ) ),
QStringLiteral( "0" ) );
}
}
//Draw minimum label
theQPainter->setPen( myForeColor );
context.painter()->setPen( myForeColor );
theQPainter->drawText(
context.painter()->drawText(
int( myOriginX - ( myFontWidth / 2 ) ),
int( myOriginY - ( myFontHeight / 4 ) ),
QStringLiteral( "0" )
@ -466,7 +464,7 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
//
//Draw maximum label
//
theQPainter->setPen( myBackColor );
context.painter()->setPen( myBackColor );
myFontWidth = myFontMetrics.width( myScaleBarMaxLabel );
myFontHeight = myFontMetrics.height();
//first the buffer
@ -474,14 +472,14 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
{
for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
{
theQPainter->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ),
int( j + ( myOriginY - ( myFontHeight / 4 ) ) ),
myScaleBarMaxLabel );
context.painter()->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ),
int( j + ( myOriginY - ( myFontHeight / 4 ) ) ),
myScaleBarMaxLabel );
}
}
//then the text itself
theQPainter->setPen( myForeColor );
theQPainter->drawText(
context.painter()->setPen( myForeColor );
context.painter()->drawText(
int( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ),
int( myOriginY - ( myFontHeight / 4 ) ),
myScaleBarMaxLabel
@ -490,20 +488,20 @@ void QgsDecorationScaleBar::render( QPainter *theQPainter )
//
//Draw unit label
//
theQPainter->setPen( myBackColor );
context.painter()->setPen( myBackColor );
//first the buffer
for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ )
{
for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ )
{
theQPainter->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ),
j + ( myOriginY + myMajorTickSize ),
myScaleBarUnitLabel );
context.painter()->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ),
j + ( myOriginY + myMajorTickSize ),
myScaleBarUnitLabel );
}
}
//then the text itself
theQPainter->setPen( myForeColor );
theQPainter->drawText(
context.painter()->setPen( myForeColor );
context.painter()->drawText(
( myOriginX + myScaleBarWidthInt + myTextOffsetX ), ( myOriginY + myMajorTickSize ),
myScaleBarUnitLabel
);

View File

@ -45,7 +45,7 @@ class APP_EXPORT QgsDecorationScaleBar: public QgsDecorationItem
void saveToProject() override;
//! this does the meaty bit of the work
void render( QPainter * ) override;
void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) override;
//! Show the dialog box
void run() override;

View File

@ -734,6 +734,7 @@ SET(QGIS_CORE_HDRS
qgslegendsettings.h
qgslegendstyle.h
qgslogger.h
qgsmapdecoration.h
qgsmaplayerref.h
qgsmaphittest.h
qgsmaplayerdependency.h

View File

@ -0,0 +1,51 @@
/***************************************************************************
qgsmapdecoration.h
----------------
begin : April 2017
copyright : (C) 2017 by Mathieu Pellerin
email : nirvn dot asia at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSMAPDECORATION_H
#define QGSMAPDECORATION_H
#include "qgis_core.h"
#include "qgsmapsettings.h"
#include "qgsrendercontext.h"
/**
* \ingroup core
* \class QgsMapDecoration
* \brief Interface for map decorations.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsMapDecoration
{
public:
/**
* Constructor for QgsMapDecoration.
*/
QgsMapDecoration() {}
virtual ~QgsMapDecoration() = default;
/**
* Renders a map decoration.
*/
virtual void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) = 0;
};
#endif //QGSMAPDECORATION_H