mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-17 00:04:02 -04:00
2395 lines
85 KiB
C++
2395 lines
85 KiB
C++
/***************************************************************************
|
|
qgscomposermapgrid.cpp
|
|
----------------------
|
|
begin : December 2013
|
|
copyright : (C) 2013 by Marco Hugentobler
|
|
email : marco dot hugentobler at sourcepole dot ch
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgscomposermapgrid.h"
|
|
#include "qgscomposerutils.h"
|
|
#include "qgsclipper.h"
|
|
#include "qgsgeometry.h"
|
|
#include "qgscomposermap.h"
|
|
#include "qgscomposition.h"
|
|
#include "qgsmapsettings.h"
|
|
#include "qgsrendercontext.h"
|
|
#include "qgssymbollayerutils.h"
|
|
#include "qgssymbol.h"
|
|
#include "qgscoordinatereferencesystem.h"
|
|
#include "qgslogger.h"
|
|
#include "qgsfontutils.h"
|
|
#include "qgsexpressioncontext.h"
|
|
#include "qgscsexception.h"
|
|
|
|
#include <QPainter>
|
|
#include <QPen>
|
|
|
|
#define MAX_GRID_LINES 1000 //maximum number of horizontal or vertical grid lines to draw
|
|
|
|
QgsComposerMapGridStack::QgsComposerMapGridStack( QgsComposerMap* map )
|
|
: QgsComposerMapItemStack( map )
|
|
{
|
|
|
|
}
|
|
|
|
void QgsComposerMapGridStack::addGrid( QgsComposerMapGrid* grid )
|
|
{
|
|
QgsComposerMapItemStack::addItem( grid );
|
|
}
|
|
|
|
void QgsComposerMapGridStack::removeGrid( const QString& gridId )
|
|
{
|
|
QgsComposerMapItemStack::removeItem( gridId );
|
|
}
|
|
|
|
void QgsComposerMapGridStack::moveGridUp( const QString& gridId )
|
|
{
|
|
QgsComposerMapItemStack::moveItemUp( gridId );
|
|
}
|
|
|
|
void QgsComposerMapGridStack::moveGridDown( const QString& gridId )
|
|
{
|
|
QgsComposerMapItemStack::moveItemDown( gridId );
|
|
}
|
|
|
|
const QgsComposerMapGrid* QgsComposerMapGridStack::constGrid( const QString& gridId ) const
|
|
{
|
|
const QgsComposerMapItem* item = QgsComposerMapItemStack::constItem( gridId );
|
|
return dynamic_cast<const QgsComposerMapGrid*>( item );
|
|
}
|
|
|
|
QgsComposerMapGrid* QgsComposerMapGridStack::grid( const QString& gridId ) const
|
|
{
|
|
QgsComposerMapItem* item = QgsComposerMapItemStack::item( gridId );
|
|
return dynamic_cast<QgsComposerMapGrid*>( item );
|
|
}
|
|
|
|
QgsComposerMapGrid *QgsComposerMapGridStack::grid( const int index ) const
|
|
{
|
|
QgsComposerMapItem* item = QgsComposerMapItemStack::item( index );
|
|
return dynamic_cast<QgsComposerMapGrid*>( item );
|
|
}
|
|
|
|
QList<QgsComposerMapGrid *> QgsComposerMapGridStack::asList() const
|
|
{
|
|
QList< QgsComposerMapGrid* > list;
|
|
QList< QgsComposerMapItem* >::const_iterator it = mItems.begin();
|
|
for ( ; it != mItems.end(); ++it )
|
|
{
|
|
QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( *it );
|
|
if ( grid )
|
|
{
|
|
list.append( grid );
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
QgsComposerMapGrid &QgsComposerMapGridStack::operator[]( int idx )
|
|
{
|
|
QgsComposerMapItem* item = mItems.at( idx );
|
|
QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( item );
|
|
return *grid;
|
|
}
|
|
|
|
bool QgsComposerMapGridStack::readXml( const QDomElement &elem, const QDomDocument &doc )
|
|
{
|
|
removeItems();
|
|
|
|
//read grid stack
|
|
QDomNodeList mapGridNodeList = elem.elementsByTagName( QStringLiteral( "ComposerMapGrid" ) );
|
|
for ( int i = 0; i < mapGridNodeList.size(); ++i )
|
|
{
|
|
QDomElement mapGridElem = mapGridNodeList.at( i ).toElement();
|
|
QgsComposerMapGrid* mapGrid = new QgsComposerMapGrid( mapGridElem.attribute( QStringLiteral( "name" ) ), mComposerMap );
|
|
mapGrid->readXml( mapGridElem, doc );
|
|
mItems.append( mapGrid );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
double QgsComposerMapGridStack::maxGridExtension() const
|
|
{
|
|
double top = 0.0;
|
|
double right = 0.0;
|
|
double bottom = 0.0;
|
|
double left = 0.0;
|
|
calculateMaxGridExtension( top, right, bottom, left );
|
|
return qMax( qMax( qMax( top, right ), bottom ), left );
|
|
}
|
|
|
|
void QgsComposerMapGridStack::calculateMaxGridExtension( double& top, double& right, double& bottom, double& left ) const
|
|
{
|
|
top = 0.0;
|
|
right = 0.0;
|
|
bottom = 0.0;
|
|
left = 0.0;
|
|
|
|
Q_FOREACH ( QgsComposerMapItem* item, mItems )
|
|
{
|
|
QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( item );
|
|
if ( grid )
|
|
{
|
|
double gridTop = 0.0;
|
|
double gridRight = 0.0;
|
|
double gridBottom = 0.0;
|
|
double gridLeft = 0.0;
|
|
grid->calculateMaxExtension( gridTop, gridRight, gridBottom, gridLeft );
|
|
top = qMax( top, gridTop );
|
|
right = qMax( right, gridRight );
|
|
bottom = qMax( bottom, gridBottom );
|
|
left = qMax( left, gridLeft );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// QgsComposerMapGrid
|
|
//
|
|
|
|
|
|
QgsComposerMapGrid::QgsComposerMapGrid( const QString& name, QgsComposerMap* map )
|
|
: QgsComposerMapItem( name, map )
|
|
{
|
|
init();
|
|
}
|
|
|
|
QgsComposerMapGrid::QgsComposerMapGrid()
|
|
: QgsComposerMapItem( QString(), nullptr )
|
|
{
|
|
init();
|
|
}
|
|
|
|
void QgsComposerMapGrid::init()
|
|
{
|
|
mTransformDirty = true;
|
|
mGridStyle = QgsComposerMapGrid::Solid;
|
|
mGridIntervalX = 0.0;
|
|
mGridIntervalY = 0.0;
|
|
mGridOffsetX = 0.0;
|
|
mGridOffsetY = 0.0;
|
|
mGridAnnotationFontColor = Qt::black;
|
|
mGridAnnotationPrecision = 3;
|
|
mShowGridAnnotation = false;
|
|
mLeftGridAnnotationDisplay = QgsComposerMapGrid::ShowAll;
|
|
mRightGridAnnotationDisplay = QgsComposerMapGrid::ShowAll;
|
|
mTopGridAnnotationDisplay = QgsComposerMapGrid::ShowAll;
|
|
mBottomGridAnnotationDisplay = QgsComposerMapGrid::ShowAll;
|
|
mLeftGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
|
|
mRightGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
|
|
mTopGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
|
|
mBottomGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
|
|
mAnnotationFrameDistance = 1.0;
|
|
mLeftGridAnnotationDirection = QgsComposerMapGrid::Horizontal;
|
|
mRightGridAnnotationDirection = QgsComposerMapGrid::Horizontal;
|
|
mTopGridAnnotationDirection = QgsComposerMapGrid::Horizontal;
|
|
mBottomGridAnnotationDirection = QgsComposerMapGrid::Horizontal;
|
|
mGridAnnotationFormat = QgsComposerMapGrid::Decimal;
|
|
mGridFrameStyle = QgsComposerMapGrid::NoFrame;
|
|
mGridFrameSides = QgsComposerMapGrid::FrameLeft | QgsComposerMapGrid::FrameRight |
|
|
QgsComposerMapGrid::FrameTop | QgsComposerMapGrid::FrameBottom;
|
|
mGridFrameWidth = 2.0;
|
|
mGridFramePenThickness = 0.3;
|
|
mGridFramePenColor = QColor( 0, 0, 0 );
|
|
mGridFrameFillColor1 = Qt::white;
|
|
mGridFrameFillColor2 = Qt::black;
|
|
mCrossLength = 3;
|
|
mLeftFrameDivisions = QgsComposerMapGrid::ShowAll;
|
|
mRightFrameDivisions = QgsComposerMapGrid::ShowAll;
|
|
mTopFrameDivisions = QgsComposerMapGrid::ShowAll;
|
|
mBottomFrameDivisions = QgsComposerMapGrid::ShowAll;
|
|
mGridLineSymbol = nullptr;
|
|
mGridMarkerSymbol = nullptr;
|
|
mGridUnit = MapUnit;
|
|
mBlendMode = QPainter::CompositionMode_SourceOver;
|
|
|
|
//get default composer font from settings
|
|
QSettings settings;
|
|
QString defaultFontString = settings.value( QStringLiteral( "/Composer/defaultFont" ) ).toString();
|
|
if ( !defaultFontString.isEmpty() )
|
|
{
|
|
mGridAnnotationFont.setFamily( defaultFontString );
|
|
}
|
|
|
|
createDefaultGridLineSymbol();
|
|
createDefaultGridMarkerSymbol();
|
|
}
|
|
|
|
QgsComposerMapGrid::~QgsComposerMapGrid()
|
|
{
|
|
delete mGridLineSymbol;
|
|
delete mGridMarkerSymbol;
|
|
}
|
|
|
|
void QgsComposerMapGrid::createDefaultGridLineSymbol()
|
|
{
|
|
delete mGridLineSymbol;
|
|
QgsStringMap properties;
|
|
properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
|
|
properties.insert( QStringLiteral( "width" ), QStringLiteral( "0.3" ) );
|
|
properties.insert( QStringLiteral( "capstyle" ), QStringLiteral( "flat" ) );
|
|
mGridLineSymbol = QgsLineSymbol::createSimple( properties );
|
|
}
|
|
|
|
void QgsComposerMapGrid::createDefaultGridMarkerSymbol()
|
|
{
|
|
delete mGridMarkerSymbol;
|
|
QgsStringMap properties;
|
|
properties.insert( QStringLiteral( "name" ), QStringLiteral( "circle" ) );
|
|
properties.insert( QStringLiteral( "size" ), QStringLiteral( "2.0" ) );
|
|
properties.insert( QStringLiteral( "color" ), QStringLiteral( "0,0,0,255" ) );
|
|
mGridMarkerSymbol = QgsMarkerSymbol::createSimple( properties );
|
|
}
|
|
|
|
void QgsComposerMapGrid::setGridLineWidth( const double width )
|
|
{
|
|
if ( mGridLineSymbol )
|
|
{
|
|
mGridLineSymbol->setWidth( width );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::setGridLineColor( const QColor& c )
|
|
{
|
|
if ( mGridLineSymbol )
|
|
{
|
|
mGridLineSymbol->setColor( c );
|
|
}
|
|
}
|
|
|
|
bool QgsComposerMapGrid::writeXml( QDomElement& elem, QDomDocument& doc ) const
|
|
{
|
|
if ( elem.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomElement mapGridElem = doc.createElement( QStringLiteral( "ComposerMapGrid" ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "gridStyle" ), mGridStyle );
|
|
mapGridElem.setAttribute( QStringLiteral( "intervalX" ), qgsDoubleToString( mGridIntervalX ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "intervalY" ), qgsDoubleToString( mGridIntervalY ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "offsetX" ), qgsDoubleToString( mGridOffsetX ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "offsetY" ), qgsDoubleToString( mGridOffsetY ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "crossLength" ), qgsDoubleToString( mCrossLength ) );
|
|
|
|
QDomElement lineStyleElem = doc.createElement( QStringLiteral( "lineStyle" ) );
|
|
QDomElement gridLineStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mGridLineSymbol, doc );
|
|
lineStyleElem.appendChild( gridLineStyleElem );
|
|
mapGridElem.appendChild( lineStyleElem );
|
|
|
|
QDomElement markerStyleElem = doc.createElement( QStringLiteral( "markerStyle" ) );
|
|
QDomElement gridMarkerStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mGridMarkerSymbol, doc );
|
|
markerStyleElem.appendChild( gridMarkerStyleElem );
|
|
mapGridElem.appendChild( markerStyleElem );
|
|
|
|
mapGridElem.setAttribute( QStringLiteral( "gridFrameStyle" ), mGridFrameStyle );
|
|
mapGridElem.setAttribute( QStringLiteral( "gridFrameSideFlags" ), mGridFrameSides );
|
|
mapGridElem.setAttribute( QStringLiteral( "gridFrameWidth" ), qgsDoubleToString( mGridFrameWidth ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "gridFramePenThickness" ), qgsDoubleToString( mGridFramePenThickness ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "gridFramePenColor" ), QgsSymbolLayerUtils::encodeColor( mGridFramePenColor ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "frameFillColor1" ), QgsSymbolLayerUtils::encodeColor( mGridFrameFillColor1 ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "frameFillColor2" ), QgsSymbolLayerUtils::encodeColor( mGridFrameFillColor2 ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "leftFrameDivisions" ), mLeftFrameDivisions );
|
|
mapGridElem.setAttribute( QStringLiteral( "rightFrameDivisions" ), mRightFrameDivisions );
|
|
mapGridElem.setAttribute( QStringLiteral( "topFrameDivisions" ), mTopFrameDivisions );
|
|
mapGridElem.setAttribute( QStringLiteral( "bottomFrameDivisions" ), mBottomFrameDivisions );
|
|
if ( mCRS.isValid() )
|
|
{
|
|
mCRS.writeXml( mapGridElem, doc );
|
|
}
|
|
|
|
mapGridElem.setAttribute( QStringLiteral( "annotationFormat" ), mGridAnnotationFormat );
|
|
mapGridElem.setAttribute( QStringLiteral( "showAnnotation" ), mShowGridAnnotation );
|
|
mapGridElem.setAttribute( QStringLiteral( "annotationExpression" ), mGridAnnotationExpressionString );
|
|
mapGridElem.setAttribute( QStringLiteral( "leftAnnotationDisplay" ), mLeftGridAnnotationDisplay );
|
|
mapGridElem.setAttribute( QStringLiteral( "rightAnnotationDisplay" ), mRightGridAnnotationDisplay );
|
|
mapGridElem.setAttribute( QStringLiteral( "topAnnotationDisplay" ), mTopGridAnnotationDisplay );
|
|
mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationDisplay" ), mBottomGridAnnotationDisplay );
|
|
mapGridElem.setAttribute( QStringLiteral( "leftAnnotationPosition" ), mLeftGridAnnotationPosition );
|
|
mapGridElem.setAttribute( QStringLiteral( "rightAnnotationPosition" ), mRightGridAnnotationPosition );
|
|
mapGridElem.setAttribute( QStringLiteral( "topAnnotationPosition" ), mTopGridAnnotationPosition );
|
|
mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationPosition" ), mBottomGridAnnotationPosition );
|
|
mapGridElem.setAttribute( QStringLiteral( "leftAnnotationDirection" ), mLeftGridAnnotationDirection );
|
|
mapGridElem.setAttribute( QStringLiteral( "rightAnnotationDirection" ), mRightGridAnnotationDirection );
|
|
mapGridElem.setAttribute( QStringLiteral( "topAnnotationDirection" ), mTopGridAnnotationDirection );
|
|
mapGridElem.setAttribute( QStringLiteral( "bottomAnnotationDirection" ), mBottomGridAnnotationDirection );
|
|
mapGridElem.setAttribute( QStringLiteral( "frameAnnotationDistance" ), QString::number( mAnnotationFrameDistance ) );
|
|
mapGridElem.appendChild( QgsFontUtils::toXmlElement( mGridAnnotationFont, doc, QStringLiteral( "annotationFontProperties" ) ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "annotationFontColor" ), QgsSymbolLayerUtils::encodeColor( mGridAnnotationFontColor ) );
|
|
mapGridElem.setAttribute( QStringLiteral( "annotationPrecision" ), mGridAnnotationPrecision );
|
|
mapGridElem.setAttribute( QStringLiteral( "unit" ), mGridUnit );
|
|
mapGridElem.setAttribute( QStringLiteral( "blendMode" ), mBlendMode );
|
|
|
|
bool ok = QgsComposerMapItem::writeXml( mapGridElem, doc );
|
|
elem.appendChild( mapGridElem );
|
|
return ok;
|
|
}
|
|
|
|
bool QgsComposerMapGrid::readXml( const QDomElement& itemElem, const QDomDocument& doc )
|
|
{
|
|
Q_UNUSED( doc );
|
|
if ( itemElem.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool ok = QgsComposerMapItem::readXml( itemElem, doc );
|
|
|
|
//grid
|
|
mGridStyle = QgsComposerMapGrid::GridStyle( itemElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() );
|
|
mGridIntervalX = itemElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble();
|
|
mGridIntervalY = itemElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble();
|
|
mGridOffsetX = itemElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble();
|
|
mGridOffsetY = itemElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble();
|
|
mCrossLength = itemElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble();
|
|
mGridFrameStyle = static_cast< QgsComposerMapGrid::FrameStyle >( itemElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() );
|
|
mGridFrameSides = static_cast< QgsComposerMapGrid::FrameSideFlags >( itemElem.attribute( QStringLiteral( "gridFrameSideFlags" ), QStringLiteral( "15" ) ).toInt() );
|
|
mGridFrameWidth = itemElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble();
|
|
mGridFramePenThickness = itemElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.3" ) ).toDouble();
|
|
mGridFramePenColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridFramePenColor" ), QStringLiteral( "0,0,0" ) ) );
|
|
mGridFrameFillColor1 = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) );
|
|
mGridFrameFillColor2 = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) );
|
|
mLeftFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "leftFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
|
|
mRightFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "rightFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
|
|
mTopFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "topFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
|
|
mBottomFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "bottomFrameDivisions" ), QStringLiteral( "0" ) ).toInt() );
|
|
|
|
QDomElement lineStyleElem = itemElem.firstChildElement( QStringLiteral( "lineStyle" ) );
|
|
if ( !lineStyleElem.isNull() )
|
|
{
|
|
QDomElement symbolElem = lineStyleElem.firstChildElement( QStringLiteral( "symbol" ) );
|
|
if ( !symbolElem.isNull() )
|
|
{
|
|
delete mGridLineSymbol;
|
|
mGridLineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
|
|
mGridLineSymbol = QgsLineSymbol::createSimple( QgsStringMap() );
|
|
mGridLineSymbol->setWidth( itemElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
|
|
mGridLineSymbol->setColor( QColor( itemElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
|
|
itemElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
|
|
itemElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
|
|
}
|
|
|
|
QDomElement markerStyleElem = itemElem.firstChildElement( QStringLiteral( "markerStyle" ) );
|
|
if ( !markerStyleElem.isNull() )
|
|
{
|
|
QDomElement symbolElem = markerStyleElem.firstChildElement( QStringLiteral( "symbol" ) );
|
|
if ( !symbolElem.isNull() )
|
|
{
|
|
delete mGridMarkerSymbol;
|
|
mGridMarkerSymbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem );
|
|
}
|
|
}
|
|
|
|
if ( !mCRS.readXml( itemElem ) )
|
|
mCRS = QgsCoordinateReferenceSystem();
|
|
|
|
mBlendMode = static_cast< QPainter::CompositionMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() );
|
|
|
|
//annotation
|
|
mShowGridAnnotation = ( itemElem.attribute( QStringLiteral( "showAnnotation" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
|
|
mGridAnnotationFormat = QgsComposerMapGrid::AnnotationFormat( itemElem.attribute( QStringLiteral( "annotationFormat" ), QStringLiteral( "0" ) ).toInt() );
|
|
mGridAnnotationExpressionString = itemElem.attribute( QStringLiteral( "annotationExpression" ) );
|
|
mGridAnnotationExpression.reset();
|
|
mLeftGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "leftAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
|
|
mRightGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "rightAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
|
|
mTopGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "topAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
|
|
mBottomGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( QStringLiteral( "bottomAnnotationPosition" ), QStringLiteral( "0" ) ).toInt() );
|
|
mLeftGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "leftAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
|
|
mRightGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "rightAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
|
|
mTopGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "topAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
|
|
mBottomGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( QStringLiteral( "bottomAnnotationDisplay" ), QStringLiteral( "0" ) ).toInt() );
|
|
|
|
mLeftGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "leftAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
|
|
mRightGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "rightAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
|
|
mTopGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "topAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
|
|
mBottomGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( QStringLiteral( "bottomAnnotationDirection" ), QStringLiteral( "0" ) ).toInt() );
|
|
mAnnotationFrameDistance = itemElem.attribute( QStringLiteral( "frameAnnotationDistance" ), QStringLiteral( "0" ) ).toDouble();
|
|
if ( !QgsFontUtils::setFromXmlChildNode( mGridAnnotationFont, itemElem, QStringLiteral( "annotationFontProperties" ) ) )
|
|
{
|
|
mGridAnnotationFont.fromString( itemElem.attribute( QStringLiteral( "annotationFont" ), QLatin1String( "" ) ) );
|
|
}
|
|
mGridAnnotationFontColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "annotationFontColor" ), QStringLiteral( "0,0,0,255" ) ) );
|
|
mGridAnnotationPrecision = itemElem.attribute( QStringLiteral( "annotationPrecision" ), QStringLiteral( "3" ) ).toInt();
|
|
int gridUnitInt = itemElem.attribute( QStringLiteral( "unit" ), QString::number( MapUnit ) ).toInt();
|
|
mGridUnit = ( gridUnitInt <= static_cast< int >( CM ) ) ? static_cast< GridUnit >( gridUnitInt ) : MapUnit;
|
|
return ok;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setCrs( const QgsCoordinateReferenceSystem &crs )
|
|
{
|
|
mCRS = crs;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
bool QgsComposerMapGrid::usesAdvancedEffects() const
|
|
{
|
|
return mBlendMode == QPainter::CompositionMode_SourceOver;
|
|
}
|
|
|
|
QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const double scale ) const
|
|
{
|
|
QTransform t = QTransform::fromScale( scale, scale );
|
|
return t.map( polygon );
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridCrsTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
|
|
QList< QPair< double, QLineF > > &verticalLines, bool calculateLinesOnly )
|
|
{
|
|
if ( !mComposerMap || !mEnabled )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//has map extent/scale changed?
|
|
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
|
|
if ( mapPolygon != mPrevMapPolygon )
|
|
{
|
|
mTransformDirty = true;
|
|
mPrevMapPolygon = mapPolygon;
|
|
}
|
|
|
|
if ( mTransformDirty )
|
|
{
|
|
calculateCrsTransformLines();
|
|
}
|
|
|
|
//draw lines
|
|
if ( !calculateLinesOnly )
|
|
{
|
|
if ( mGridStyle == QgsComposerMapGrid::Solid )
|
|
{
|
|
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
|
|
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
|
|
{
|
|
drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
|
|
}
|
|
|
|
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
|
|
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
|
|
{
|
|
drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
|
|
}
|
|
}
|
|
else if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
|
|
{
|
|
double maxX = mComposerMap->rect().width();
|
|
double maxY = mComposerMap->rect().height();
|
|
|
|
QList< QgsPoint >::const_iterator intersectionIt = mTransformedIntersections.constBegin();
|
|
for ( ; intersectionIt != mTransformedIntersections.constEnd(); ++intersectionIt )
|
|
{
|
|
double x = intersectionIt->x();
|
|
double y = intersectionIt->y();
|
|
if ( mGridStyle == QgsComposerMapGrid::Cross )
|
|
{
|
|
//ensure that crosses don't overshoot the map item bounds
|
|
QLineF line1 = QLineF( x - mCrossLength, y, x + mCrossLength, y );
|
|
line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
|
|
line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
|
|
QLineF line2 = QLineF( x, y - mCrossLength, x, y + mCrossLength );
|
|
line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
|
|
line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();
|
|
|
|
//draw line using coordinates scaled to dots
|
|
drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
|
|
drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
|
|
}
|
|
else if ( mGridStyle == QgsComposerMapGrid::Markers )
|
|
{
|
|
drawGridMarker( QPointF( x, y ) * dotsPerMM, context );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//convert QPolygonF to QLineF to draw grid frames and annotations
|
|
QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = mTransformedYLines.constBegin();
|
|
for ( ; yGridLineIt != mTransformedYLines.constEnd(); ++yGridLineIt )
|
|
{
|
|
verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
|
|
}
|
|
QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = mTransformedXLines.constBegin();
|
|
for ( ; xGridLineIt != mTransformedXLines.constEnd(); ++xGridLineIt )
|
|
{
|
|
horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::calculateCrsTransformLines()
|
|
{
|
|
QgsRectangle crsBoundingRect;
|
|
QgsCoordinateTransform inverseTr;
|
|
if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//calculate x grid lines
|
|
mTransformedXLines.clear();
|
|
xGridLinesCrsTransform( crsBoundingRect, inverseTr, mTransformedXLines );
|
|
|
|
//calculate y grid lines
|
|
mTransformedYLines.clear();
|
|
yGridLinesCrsTransform( crsBoundingRect, inverseTr, mTransformedYLines );
|
|
|
|
if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
|
|
{
|
|
//cross or markers style - we also need to calculate intersections of lines
|
|
|
|
//first convert lines to QgsGeometry
|
|
QList< QgsGeometry > yLines;
|
|
QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
|
|
for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
|
|
{
|
|
QgsPolyline yLine;
|
|
for ( int i = 0; i < ( *yGridIt ).second.size(); ++i )
|
|
{
|
|
yLine.append( QgsPoint(( *yGridIt ).second.at( i ).x(), ( *yGridIt ).second.at( i ).y() ) );
|
|
}
|
|
yLines << QgsGeometry::fromPolyline( yLine );
|
|
}
|
|
QList< QgsGeometry > xLines;
|
|
QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
|
|
for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
|
|
{
|
|
QgsPolyline xLine;
|
|
for ( int i = 0; i < ( *xGridIt ).second.size(); ++i )
|
|
{
|
|
xLine.append( QgsPoint(( *xGridIt ).second.at( i ).x(), ( *xGridIt ).second.at( i ).y() ) );
|
|
}
|
|
xLines << QgsGeometry::fromPolyline( xLine );
|
|
}
|
|
|
|
//now, loop through geometries and calculate intersection points
|
|
mTransformedIntersections.clear();
|
|
QList< QgsGeometry >::const_iterator yLineIt = yLines.constBegin();
|
|
for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
|
|
{
|
|
QList< QgsGeometry >::const_iterator xLineIt = xLines.constBegin();
|
|
for ( ; xLineIt != xLines.constEnd(); ++xLineIt )
|
|
{
|
|
//look for intersections between lines
|
|
QgsGeometry intersects = ( *yLineIt ).intersection(( *xLineIt ) );
|
|
if ( intersects.isNull() )
|
|
continue;
|
|
|
|
//go through all intersections and draw grid markers/crosses
|
|
int i = 0;
|
|
QgsPoint vertex = intersects.vertexAt( i );
|
|
while ( vertex != QgsPoint( 0, 0 ) )
|
|
{
|
|
mTransformedIntersections << vertex;
|
|
i = i + 1;
|
|
vertex = intersects.vertexAt( i );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mTransformDirty = false;
|
|
}
|
|
|
|
void QgsComposerMapGrid::draw( QPainter* p )
|
|
{
|
|
if ( !mComposerMap || !mEnabled )
|
|
{
|
|
return;
|
|
}
|
|
QPaintDevice* thePaintDevice = p->device();
|
|
if ( !thePaintDevice )
|
|
{
|
|
return;
|
|
}
|
|
|
|
p->save();
|
|
p->setCompositionMode( mBlendMode );
|
|
p->setRenderHint( QPainter::Antialiasing );
|
|
|
|
QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
|
|
p->setClipRect( thisPaintRect );
|
|
if ( thisPaintRect != mPrevPaintRect )
|
|
{
|
|
//rect has changed, so need to recalculate transform
|
|
mTransformDirty = true;
|
|
mPrevPaintRect = thisPaintRect;
|
|
}
|
|
|
|
//setup painter scaling to dots so that raster symbology is drawn to scale
|
|
double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
|
|
p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
|
|
|
|
//setup render context
|
|
QgsRenderContext context = QgsComposerUtils::createRenderContextForComposition( mComposition, p );
|
|
context.setForceVectorOutput( true );
|
|
QgsExpressionContext expressionContext = createExpressionContext();
|
|
context.setExpressionContext( expressionContext );
|
|
|
|
QList< QPair< double, QLineF > > verticalLines;
|
|
QList< QPair< double, QLineF > > horizontalLines;
|
|
|
|
//is grid in a different crs than map?
|
|
if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != mComposerMap->crs() )
|
|
{
|
|
drawGridCrsTransform( context, dotsPerMM, horizontalLines, verticalLines );
|
|
}
|
|
else
|
|
{
|
|
drawGridNoTransform( context, dotsPerMM, horizontalLines, verticalLines );
|
|
}
|
|
|
|
p->restore();
|
|
|
|
p->setClipping( false );
|
|
#ifdef Q_OS_MAC
|
|
//QPainter::setClipping(false) seems to be broken on OSX (#12747). So we hack around it by
|
|
//setting a larger clip rect
|
|
p->setClipRect( mComposerMap->mapRectFromScene( mComposerMap->sceneBoundingRect() ).adjusted( -10, -10, 10, 10 ) );
|
|
#endif
|
|
|
|
if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame )
|
|
{
|
|
drawGridFrame( p, horizontalLines, verticalLines );
|
|
}
|
|
|
|
if ( mShowGridAnnotation )
|
|
{
|
|
drawCoordinateAnnotations( p, horizontalLines, verticalLines, context.expressionContext() );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
|
|
QList< QPair< double, QLineF > > &verticalLines, bool calculateLinesOnly ) const
|
|
{
|
|
//get line positions
|
|
yGridLines( verticalLines );
|
|
xGridLines( horizontalLines );
|
|
|
|
if ( calculateLinesOnly )
|
|
return;
|
|
|
|
QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
|
|
QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
|
|
|
|
//simple approach: draw vertical lines first, then horizontal ones
|
|
if ( mGridStyle == QgsComposerMapGrid::Solid )
|
|
{
|
|
//we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
|
|
//this is done by multiplying each line coordinate by dotsPerMM
|
|
QLineF line;
|
|
for ( ; vIt != verticalLines.constEnd(); ++vIt )
|
|
{
|
|
line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM );
|
|
drawGridLine( line, context );
|
|
}
|
|
|
|
for ( ; hIt != horizontalLines.constEnd(); ++hIt )
|
|
{
|
|
line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM );
|
|
drawGridLine( line, context );
|
|
}
|
|
}
|
|
else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
|
|
{
|
|
QPointF intersectionPoint, crossEnd1, crossEnd2;
|
|
for ( ; vIt != verticalLines.constEnd(); ++vIt )
|
|
{
|
|
//test for intersection with every horizontal line
|
|
hIt = horizontalLines.constBegin();
|
|
for ( ; hIt != horizontalLines.constEnd(); ++hIt )
|
|
{
|
|
if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
|
|
{
|
|
if ( mGridStyle == QgsComposerMapGrid::Cross )
|
|
{
|
|
//apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
|
|
crossEnd1 = (( intersectionPoint - vIt->second.p1() ).manhattanLength() > 0.01 ) ?
|
|
QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength ) : intersectionPoint;
|
|
crossEnd2 = (( intersectionPoint - vIt->second.p2() ).manhattanLength() > 0.01 ) ?
|
|
QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength ) : intersectionPoint;
|
|
//draw line using coordinates scaled to dots
|
|
drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
|
|
}
|
|
else if ( mGridStyle == QgsComposerMapGrid::Markers )
|
|
{
|
|
drawGridMarker( intersectionPoint * dotsPerMM, context );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( mGridStyle == QgsComposerMapGrid::Markers )
|
|
{
|
|
//markers mode, so we have no need to process horizontal lines (we've already
|
|
//drawn markers on the intersections between horizontal and vertical lines)
|
|
return;
|
|
}
|
|
|
|
hIt = horizontalLines.constBegin();
|
|
for ( ; hIt != horizontalLines.constEnd(); ++hIt )
|
|
{
|
|
vIt = verticalLines.constBegin();
|
|
for ( ; vIt != verticalLines.constEnd(); ++vIt )
|
|
{
|
|
if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
|
|
{
|
|
//apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
|
|
crossEnd1 = (( intersectionPoint - hIt->second.p1() ).manhattanLength() > 0.01 ) ?
|
|
QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength ) : intersectionPoint;
|
|
crossEnd2 = (( intersectionPoint - hIt->second.p2() ).manhattanLength() > 0.01 ) ?
|
|
QgsSymbolLayerUtils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength ) : intersectionPoint;
|
|
//draw line using coordinates scaled to dots
|
|
drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, GridExtension* extension ) const
|
|
{
|
|
if ( p )
|
|
{
|
|
p->save();
|
|
p->setRenderHint( QPainter::Antialiasing );
|
|
}
|
|
|
|
//Sort the coordinate positions for each side
|
|
QMap< double, double > leftGridFrame;
|
|
QMap< double, double > rightGridFrame;
|
|
QMap< double, double > topGridFrame;
|
|
QMap< double, double > bottomGridFrame;
|
|
|
|
sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
|
|
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameLeft ) )
|
|
{
|
|
drawGridFrameBorder( p, leftGridFrame, QgsComposerMapGrid::Left, extension ? &extension->left : nullptr );
|
|
}
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameRight ) )
|
|
{
|
|
drawGridFrameBorder( p, rightGridFrame, QgsComposerMapGrid::Right, extension ? &extension->right : nullptr );
|
|
}
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameTop ) )
|
|
{
|
|
drawGridFrameBorder( p, topGridFrame, QgsComposerMapGrid::Top, extension ? &extension->top : nullptr );
|
|
}
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameBottom ) )
|
|
{
|
|
drawGridFrameBorder( p, bottomGridFrame, QgsComposerMapGrid::Bottom, extension ? &extension->bottom : nullptr );
|
|
}
|
|
if ( p )
|
|
p->restore();
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridLine( const QLineF& line, QgsRenderContext& context ) const
|
|
{
|
|
QPolygonF poly;
|
|
poly << line.p1() << line.p2();
|
|
drawGridLine( poly, context );
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridLine( const QPolygonF& line, QgsRenderContext& context ) const
|
|
{
|
|
if ( !mComposerMap || !mComposerMap->composition() || !mGridLineSymbol )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mGridLineSymbol->startRender( context );
|
|
mGridLineSymbol->renderPolyline( line, nullptr, context );
|
|
mGridLineSymbol->stopRender( context );
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridMarker( QPointF point, QgsRenderContext& context ) const
|
|
{
|
|
if ( !mComposerMap || !mComposerMap->composition() || !mGridMarkerSymbol )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mGridMarkerSymbol->startRender( context );
|
|
mGridMarkerSymbol->renderPoint( point, nullptr, context );
|
|
mGridMarkerSymbol->stopRender( context );
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border, double* extension ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch ( mGridFrameStyle )
|
|
{
|
|
case QgsComposerMapGrid::Zebra:
|
|
drawGridFrameZebraBorder( p, borderPos, border, extension );
|
|
break;
|
|
case QgsComposerMapGrid::InteriorTicks:
|
|
case QgsComposerMapGrid::ExteriorTicks:
|
|
case QgsComposerMapGrid::InteriorExteriorTicks:
|
|
drawGridFrameTicks( p, borderPos, border, extension );
|
|
break;
|
|
|
|
case QgsComposerMapGrid::LineBorder:
|
|
drawGridFrameLineBorder( p, border, extension );
|
|
break;
|
|
|
|
case QgsComposerMapGrid::NoFrame:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridFrameZebraBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border, double* extension ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( extension )
|
|
{
|
|
*extension = mGridFrameWidth + mGridFramePenThickness / 2.0;
|
|
return;
|
|
}
|
|
|
|
QMap< double, double > pos = borderPos;
|
|
|
|
double currentCoord = 0;
|
|
if (( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right ) && testFrameSideFlag( QgsComposerMapGrid::FrameTop ) )
|
|
{
|
|
currentCoord = - mGridFrameWidth;
|
|
pos.insert( 0, 0 );
|
|
}
|
|
else if (( border == QgsComposerMapGrid::Top || border == QgsComposerMapGrid::Bottom ) && testFrameSideFlag( QgsComposerMapGrid::FrameLeft ) )
|
|
{
|
|
currentCoord = - mGridFrameWidth;
|
|
pos.insert( 0, 0 );
|
|
}
|
|
bool color1 = true;
|
|
double x = 0;
|
|
double y = 0;
|
|
double width = 0;
|
|
double height = 0;
|
|
|
|
if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
|
|
{
|
|
pos.insert( mComposerMap->rect().height(), mComposerMap->rect().height() );
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameBottom ) )
|
|
{
|
|
pos.insert( mComposerMap->rect().height() + mGridFrameWidth, mComposerMap->rect().height() + mGridFrameWidth );
|
|
}
|
|
}
|
|
else if ( border == QgsComposerMapGrid::Top || border == QgsComposerMapGrid::Bottom )
|
|
{
|
|
pos.insert( mComposerMap->rect().width(), mComposerMap->rect().width() );
|
|
if ( testFrameSideFlag( QgsComposerMapGrid::FrameRight ) )
|
|
{
|
|
pos.insert( mComposerMap->rect().width() + mGridFrameWidth, mComposerMap->rect().width() + mGridFrameWidth );
|
|
}
|
|
}
|
|
|
|
//set pen to current frame pen
|
|
QPen framePen = QPen( mGridFramePenColor );
|
|
framePen.setWidthF( mGridFramePenThickness );
|
|
framePen.setJoinStyle( Qt::MiterJoin );
|
|
p->setPen( framePen );
|
|
|
|
QMap< double, double >::const_iterator posIt = pos.constBegin();
|
|
for ( ; posIt != pos.constEnd(); ++posIt )
|
|
{
|
|
p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
|
|
if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
|
|
{
|
|
height = posIt.key() - currentCoord;
|
|
width = mGridFrameWidth;
|
|
x = ( border == QgsComposerMapGrid::Left ) ? -mGridFrameWidth : mComposerMap->rect().width();
|
|
y = currentCoord;
|
|
}
|
|
else //top or bottom
|
|
{
|
|
height = mGridFrameWidth;
|
|
width = posIt.key() - currentCoord;
|
|
x = currentCoord;
|
|
y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
|
|
}
|
|
p->drawRect( QRectF( x, y, width, height ) );
|
|
currentCoord = posIt.key();
|
|
color1 = !color1;
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridFrameTicks( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border, double* extension ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( extension )
|
|
{
|
|
if ( mGridFrameStyle != QgsComposerMapGrid::InteriorTicks )
|
|
*extension = mGridFrameWidth;
|
|
return;
|
|
}
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
double width = 0;
|
|
double height = 0;
|
|
|
|
//set pen to current frame pen
|
|
QPen framePen = QPen( mGridFramePenColor );
|
|
framePen.setWidthF( mGridFramePenThickness );
|
|
framePen.setCapStyle( Qt::FlatCap );
|
|
p->setBrush( Qt::NoBrush );
|
|
p->setPen( framePen );
|
|
|
|
QMap< double, double >::const_iterator posIt = borderPos.constBegin();
|
|
for ( ; posIt != borderPos.constEnd(); ++posIt )
|
|
{
|
|
if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
|
|
{
|
|
y = posIt.key();
|
|
height = 0;
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
width = mGridFrameWidth;
|
|
x = ( border == QgsComposerMapGrid::Left ) ? 0 : mComposerMap->rect().width() - mGridFrameWidth;
|
|
}
|
|
else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
width = mGridFrameWidth;
|
|
x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width();
|
|
}
|
|
else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
|
|
{
|
|
width = mGridFrameWidth * 2;
|
|
x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width() - mGridFrameWidth;
|
|
}
|
|
}
|
|
else //top or bottom
|
|
{
|
|
x = posIt.key();
|
|
width = 0;
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
height = mGridFrameWidth;
|
|
y = ( border == QgsComposerMapGrid::Top ) ? 0 : mComposerMap->rect().height() - mGridFrameWidth;
|
|
}
|
|
else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
height = mGridFrameWidth;
|
|
y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
|
|
}
|
|
else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
|
|
{
|
|
height = mGridFrameWidth * 2;
|
|
y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height() - mGridFrameWidth;
|
|
}
|
|
}
|
|
p->drawLine( QLineF( x, y, x + width, y + height ) );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawGridFrameLineBorder( QPainter* p, QgsComposerMapGrid::BorderSide border, double* extension ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( extension )
|
|
{
|
|
*extension = mGridFramePenThickness / 2.0;
|
|
return;
|
|
}
|
|
|
|
//set pen to current frame pen
|
|
QPen framePen = QPen( mGridFramePenColor );
|
|
framePen.setWidthF( mGridFramePenThickness );
|
|
framePen.setCapStyle( Qt::SquareCap );
|
|
p->setBrush( Qt::NoBrush );
|
|
p->setPen( framePen );
|
|
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
p->drawLine( QLineF( 0, 0, 0, mComposerMap->rect().height() ) );
|
|
break;
|
|
case QgsComposerMapGrid::Right:
|
|
p->drawLine( QLineF( mComposerMap->rect().width(), 0, mComposerMap->rect().width(), mComposerMap->rect().height() ) );
|
|
break;
|
|
case QgsComposerMapGrid::Top:
|
|
p->drawLine( QLineF( 0, 0, mComposerMap->rect().width(), 0 ) );
|
|
break;
|
|
case QgsComposerMapGrid::Bottom:
|
|
p->drawLine( QLineF( 0, mComposerMap->rect().height(), mComposerMap->rect().width(), mComposerMap->rect().height() ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QgsExpressionContext &expressionContext,
|
|
GridExtension* extension ) const
|
|
{
|
|
QString currentAnnotationString;
|
|
QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
|
|
for ( ; it != hLines.constEnd(); ++it )
|
|
{
|
|
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, expressionContext );
|
|
drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Latitude, extension );
|
|
drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Latitude, extension );
|
|
}
|
|
|
|
it = vLines.constBegin();
|
|
for ( ; it != vLines.constEnd(); ++it )
|
|
{
|
|
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, expressionContext );
|
|
drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Longitude, extension );
|
|
drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Longitude, extension );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawCoordinateAnnotation( QPainter* p, QPointF pos, const QString& annotationString, const AnnotationCoordinate coordinateType, GridExtension* extension ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( pos, coordinateType );
|
|
double textWidth = QgsComposerUtils::textWidthMM( mGridAnnotationFont, annotationString );
|
|
//relevant for annotations is the height of digits
|
|
double textHeight = extension ? QgsComposerUtils::fontAscentMM( mGridAnnotationFont )
|
|
: QgsComposerUtils::fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
|
|
double xpos = pos.x();
|
|
double ypos = pos.y();
|
|
int rotation = 0;
|
|
|
|
double gridFrameDistance = 0;
|
|
if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame && mGridFrameStyle != QgsComposerMapGrid::LineBorder )
|
|
{
|
|
gridFrameDistance = mGridFrameWidth;
|
|
}
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::LineBorder )
|
|
{
|
|
gridFrameDistance += ( mGridFramePenThickness / 2.0 );
|
|
}
|
|
|
|
if ( frameBorder == QgsComposerMapGrid::Left )
|
|
{
|
|
if ( mLeftGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
|
|
( coordinateType == Longitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
|
|
( coordinateType == Latitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !testFrameSideFlag( QgsComposerMapGrid::FrameLeft ) )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
|
|
if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos += textWidth / 2.0;
|
|
rotation = 270;
|
|
}
|
|
else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos += ( mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos -= textWidth / 2.0;
|
|
rotation = 90;
|
|
}
|
|
else
|
|
{
|
|
xpos += mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos += textHeight / 2.0;
|
|
}
|
|
}
|
|
else if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //Outside map frame
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos += textWidth / 2.0;
|
|
rotation = 270;
|
|
if ( extension )
|
|
extension->left = qMax( extension->left, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos -= textWidth / 2.0;
|
|
rotation = 90;
|
|
if ( extension )
|
|
extension->left = qMax( extension->left, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else
|
|
{
|
|
xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos += textHeight / 2.0;
|
|
if ( extension )
|
|
extension->left = qMax( extension->left, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if ( frameBorder == QgsComposerMapGrid::Right )
|
|
{
|
|
if ( mRightGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
|
|
( coordinateType == Longitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
|
|
( coordinateType == Latitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !testFrameSideFlag( QgsComposerMapGrid::FrameRight ) )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
|
|
if ( mRightGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
|
|
{
|
|
xpos -= mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos += textWidth / 2.0;
|
|
rotation = 270;
|
|
}
|
|
else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos -= textWidth / 2.0;
|
|
rotation = 90;
|
|
}
|
|
else
|
|
{
|
|
xpos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
|
|
ypos += textHeight / 2.0;
|
|
}
|
|
}
|
|
else if ( mRightGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame )//OutsideMapFrame
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
|
|
{
|
|
xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos += textWidth / 2.0;
|
|
rotation = 270;
|
|
if ( extension )
|
|
extension->right = qMax( extension->right, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos += ( mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos -= textWidth / 2.0;
|
|
rotation = 90;
|
|
if ( extension )
|
|
extension->right = qMax( extension->right, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else //Horizontal
|
|
{
|
|
xpos += ( mAnnotationFrameDistance + gridFrameDistance );
|
|
ypos += textHeight / 2.0;
|
|
if ( extension )
|
|
extension->right = qMax( extension->right, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if ( frameBorder == QgsComposerMapGrid::Bottom )
|
|
{
|
|
if ( mBottomGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
|
|
( coordinateType == Longitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
|
|
( coordinateType == Latitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !testFrameSideFlag( QgsComposerMapGrid::FrameBottom ) )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
|
|
if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
ypos -= mAnnotationFrameDistance + gridFrameDistance;
|
|
xpos -= textWidth / 2.0;
|
|
}
|
|
else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos -= textHeight / 2.0;
|
|
ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
|
|
rotation = 90;
|
|
}
|
|
else //Vertical
|
|
{
|
|
xpos += textHeight / 2.0;
|
|
ypos -= mAnnotationFrameDistance + gridFrameDistance;
|
|
rotation = 270;
|
|
}
|
|
}
|
|
else if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
|
|
xpos -= textWidth / 2.0;
|
|
if ( extension )
|
|
extension->bottom = qMax( extension->bottom, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos -= textHeight / 2.0;
|
|
ypos += gridFrameDistance + mAnnotationFrameDistance;
|
|
rotation = 90;
|
|
if ( extension )
|
|
extension->bottom = qMax( extension->bottom, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
else //Vertical
|
|
{
|
|
xpos += textHeight / 2.0;
|
|
ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
|
|
rotation = 270;
|
|
if ( extension )
|
|
extension->bottom = qMax( extension->bottom, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else //top
|
|
{
|
|
if ( mTopGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
|
|
( coordinateType == Longitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
|
|
( coordinateType == Latitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
|
|
{
|
|
return;
|
|
}
|
|
if ( !testFrameSideFlag( QgsComposerMapGrid::FrameTop ) )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
|
|
if ( mTopGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos -= textWidth / 2.0;
|
|
ypos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
|
|
}
|
|
else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos -= textHeight / 2.0;
|
|
ypos += mAnnotationFrameDistance + gridFrameDistance;
|
|
rotation = 90;
|
|
}
|
|
else //Vertical
|
|
{
|
|
xpos += textHeight / 2.0;
|
|
ypos += textWidth + mAnnotationFrameDistance + gridFrameDistance;
|
|
rotation = 270;
|
|
}
|
|
}
|
|
else if ( mTopGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
|
|
{
|
|
if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
|
|
{
|
|
gridFrameDistance = 0;
|
|
}
|
|
if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
|
|
{
|
|
xpos -= textWidth / 2.0;
|
|
ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
|
|
if ( extension )
|
|
extension->top = qMax( extension->top, mAnnotationFrameDistance + gridFrameDistance + textHeight );
|
|
}
|
|
else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
|
|
{
|
|
xpos -= textHeight / 2.0;
|
|
ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
|
|
rotation = 90;
|
|
if ( extension )
|
|
extension->top = qMax( extension->top, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
else //Vertical
|
|
{
|
|
xpos += textHeight / 2.0;
|
|
ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
|
|
rotation = 270;
|
|
if ( extension )
|
|
extension->top = qMax( extension->top, mAnnotationFrameDistance + gridFrameDistance + textWidth );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( extension || !p )
|
|
return;
|
|
|
|
drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
|
|
}
|
|
|
|
void QgsComposerMapGrid::drawAnnotation( QPainter* p, QPointF pos, int rotation, const QString& annotationText ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
p->save();
|
|
p->translate( pos );
|
|
p->rotate( rotation );
|
|
QgsComposerUtils::drawText( p, QPointF( 0, 0 ), annotationText, mGridAnnotationFont, mGridAnnotationFontColor );
|
|
p->restore();
|
|
}
|
|
|
|
QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord, QgsExpressionContext &expressionContext ) const
|
|
{
|
|
//check if we are using degrees (ie, geographic crs)
|
|
bool geographic = false;
|
|
if ( mCRS.isValid() && mCRS.isGeographic() )
|
|
{
|
|
geographic = true;
|
|
}
|
|
else if ( mComposerMap && mComposerMap->composition() )
|
|
{
|
|
geographic = mComposerMap->crs().isGeographic();
|
|
}
|
|
|
|
if ( geographic && coord == QgsComposerMapGrid::Longitude &&
|
|
( mGridAnnotationFormat == QgsComposerMapGrid::Decimal || mGridAnnotationFormat == QgsComposerMapGrid::DecimalWithSuffix ) )
|
|
{
|
|
// wrap around longitudes > 180 or < -180 degrees, so that, e.g., "190E" -> "170W"
|
|
double wrappedX = fmod( value, 360.0 );
|
|
if ( wrappedX > 180.0 )
|
|
{
|
|
value = wrappedX - 360.0;
|
|
}
|
|
else if ( wrappedX < -180.0 )
|
|
{
|
|
value = wrappedX + 360.0;
|
|
}
|
|
}
|
|
|
|
if ( mGridAnnotationFormat == QgsComposerMapGrid::Decimal )
|
|
{
|
|
return QString::number( value, 'f', mGridAnnotationPrecision );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DecimalWithSuffix )
|
|
{
|
|
QString hemisphere;
|
|
|
|
double coordRounded = qRound( value * pow( 10.0, mGridAnnotationPrecision ) ) / pow( 10.0, mGridAnnotationPrecision );
|
|
if ( coord == QgsComposerMapGrid::Longitude )
|
|
{
|
|
//don't use E/W suffixes if ambiguous (e.g., 180 degrees)
|
|
if ( !geographic || ( coordRounded != 180.0 && coordRounded != 0.0 ) )
|
|
{
|
|
hemisphere = value < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//don't use N/S suffixes if ambiguous (e.g., 0 degrees)
|
|
if ( !geographic || coordRounded != 0.0 )
|
|
{
|
|
hemisphere = value < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
|
|
}
|
|
}
|
|
if ( geographic )
|
|
{
|
|
//insert degree symbol for geographic coordinates
|
|
return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + QChar( 176 ) + hemisphere;
|
|
}
|
|
else
|
|
{
|
|
return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
|
|
}
|
|
}
|
|
else if ( mGridAnnotationFormat == CustomFormat )
|
|
{
|
|
expressionContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_number" ), value, true ) );
|
|
expressionContext.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_axis" ), coord == QgsComposerMapGrid::Longitude ? "x" : "y", true ) );
|
|
if ( !mGridAnnotationExpression )
|
|
{
|
|
mGridAnnotationExpression.reset( new QgsExpression( mGridAnnotationExpressionString ) );
|
|
mGridAnnotationExpression->prepare( &expressionContext );
|
|
}
|
|
return mGridAnnotationExpression->evaluate( &expressionContext ).toString();
|
|
}
|
|
|
|
QgsPoint p;
|
|
p.setX( coord == QgsComposerMapGrid::Longitude ? value : 0 );
|
|
p.setY( coord == QgsComposerMapGrid::Longitude ? 0 : value );
|
|
|
|
QString annotationString;
|
|
if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinute )
|
|
{
|
|
annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteNoSuffix )
|
|
{
|
|
annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, false );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinutePadded )
|
|
{
|
|
annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, true, true );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecond )
|
|
{
|
|
annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondNoSuffix )
|
|
{
|
|
annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, false );
|
|
}
|
|
else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondPadded )
|
|
{
|
|
annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, true, true );
|
|
}
|
|
|
|
QStringList split = annotationString.split( ',' );
|
|
if ( coord == QgsComposerMapGrid::Longitude )
|
|
{
|
|
return split.at( 0 );
|
|
}
|
|
else
|
|
{
|
|
if ( split.size() < 2 )
|
|
{
|
|
return QLatin1String( "" );
|
|
}
|
|
return split.at( 1 );
|
|
}
|
|
}
|
|
|
|
int QgsComposerMapGrid::xGridLines( QList< QPair< double, QLineF > >& lines ) const
|
|
{
|
|
lines.clear();
|
|
if ( !mComposerMap || mGridIntervalY <= 0.0 )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
|
|
QRectF mapBoundingRect = mapPolygon.boundingRect();
|
|
double gridIntervalY = mGridIntervalY;
|
|
double gridOffsetY = mGridOffsetY;
|
|
double annotationScale = 1.0;
|
|
if ( mGridUnit != MapUnit )
|
|
{
|
|
mapBoundingRect = mComposerMap->rect();
|
|
mapPolygon = QPolygonF( mComposerMap->rect() );
|
|
if ( mGridUnit == CM )
|
|
{
|
|
annotationScale = 0.1;
|
|
gridIntervalY *= 10;
|
|
gridOffsetY *= 10;
|
|
}
|
|
}
|
|
|
|
//consider to round up to the next step in case the left boundary is > 0
|
|
double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
|
|
double currentLevel = static_cast< int >(( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
|
|
|
|
int gridLineCount = 0;
|
|
if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
|
|
{
|
|
//no rotation. Do it 'the easy way'
|
|
|
|
double yCanvasCoord;
|
|
while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
yCanvasCoord = mComposerMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
|
|
lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( 0, yCanvasCoord, mComposerMap->rect().width(), yCanvasCoord ) ) );
|
|
currentLevel += gridIntervalY;
|
|
gridLineCount++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//the four border lines
|
|
QVector<QLineF> borderLines;
|
|
borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
|
|
borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
|
|
borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
|
|
borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
|
|
|
|
QVector<QPointF> intersectionList; //intersects between border lines and grid lines
|
|
|
|
while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
intersectionList.clear();
|
|
QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
|
|
|
|
QVector<QLineF>::const_iterator it = borderLines.constBegin();
|
|
for ( ; it != borderLines.constEnd(); ++it )
|
|
{
|
|
QPointF intersectionPoint;
|
|
if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
|
|
{
|
|
intersectionList.push_back( intersectionPoint );
|
|
if ( intersectionList.size() >= 2 )
|
|
{
|
|
break; //we already have two intersections, skip further tests
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( intersectionList.size() >= 2 )
|
|
{
|
|
lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
|
|
gridLineCount++;
|
|
}
|
|
currentLevel += gridIntervalY;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QgsComposerMapGrid::yGridLines( QList< QPair< double, QLineF > >& lines ) const
|
|
{
|
|
lines.clear();
|
|
if ( !mComposerMap || mGridIntervalX <= 0.0 )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
|
|
QRectF mapBoundingRect = mapPolygon.boundingRect();
|
|
double gridIntervalX = mGridIntervalX;
|
|
double gridOffsetX = mGridOffsetX;
|
|
double annotationScale = 1.0;
|
|
if ( mGridUnit != MapUnit )
|
|
{
|
|
mapBoundingRect = mComposerMap->rect();
|
|
mapPolygon = QPolygonF( mComposerMap->rect() );
|
|
if ( mGridUnit == CM )
|
|
{
|
|
annotationScale = 0.1;
|
|
gridIntervalX *= 10;
|
|
gridOffsetX *= 10;
|
|
}
|
|
}
|
|
|
|
//consider to round up to the next step in case the left boundary is > 0
|
|
double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
|
|
double currentLevel = static_cast< int >(( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
|
|
|
|
int gridLineCount = 0;
|
|
if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
|
|
{
|
|
//no rotation. Do it 'the easy way'
|
|
double xCanvasCoord;
|
|
while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
xCanvasCoord = mComposerMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
|
|
lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( xCanvasCoord, 0, xCanvasCoord, mComposerMap->rect().height() ) ) );
|
|
currentLevel += gridIntervalX;
|
|
gridLineCount++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//the four border lines
|
|
QVector<QLineF> borderLines;
|
|
borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
|
|
borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
|
|
borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
|
|
borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
|
|
|
|
QVector<QPointF> intersectionList; //intersects between border lines and grid lines
|
|
|
|
while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
intersectionList.clear();
|
|
QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
|
|
|
|
QVector<QLineF>::const_iterator it = borderLines.constBegin();
|
|
for ( ; it != borderLines.constEnd(); ++it )
|
|
{
|
|
QPointF intersectionPoint;
|
|
if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
|
|
{
|
|
intersectionList.push_back( intersectionPoint );
|
|
if ( intersectionList.size() >= 2 )
|
|
{
|
|
break; //we already have two intersections, skip further tests
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( intersectionList.size() >= 2 )
|
|
{
|
|
lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
|
|
gridLineCount++;
|
|
}
|
|
currentLevel += gridIntervalX;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QgsComposerMapGrid::xGridLinesCrsTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
|
|
{
|
|
lines.clear();
|
|
if ( !mComposerMap || mGridIntervalY <= 0.0 )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
|
|
double currentLevel = static_cast< int >(( bbox.yMaximum() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
|
|
|
|
double minX = bbox.xMinimum();
|
|
double maxX = bbox.xMaximum();
|
|
double step = ( maxX - minX ) / 20;
|
|
|
|
bool crosses180 = false;
|
|
bool crossed180 = false;
|
|
if ( mCRS.isGeographic() && ( minX > maxX ) )
|
|
{
|
|
//handle 180 degree longitude crossover
|
|
crosses180 = true;
|
|
step = ( maxX + 360.0 - minX ) / 20;
|
|
}
|
|
|
|
if ( qgsDoubleNear( step, 0.0 ) )
|
|
return 1;
|
|
|
|
int gridLineCount = 0;
|
|
while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
QPolygonF gridLine;
|
|
double currentX = minX;
|
|
bool cont = true;
|
|
while ( cont )
|
|
{
|
|
if (( !crosses180 || crossed180 ) && ( currentX > maxX ) )
|
|
{
|
|
cont = false;
|
|
}
|
|
|
|
try
|
|
{
|
|
QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
|
|
gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
|
|
}
|
|
catch ( QgsCsException & cse )
|
|
{
|
|
Q_UNUSED( cse );
|
|
QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
|
|
}
|
|
|
|
currentX += step;
|
|
if ( crosses180 && currentX > 180.0 )
|
|
{
|
|
currentX -= 360.0;
|
|
crossed180 = true;
|
|
}
|
|
}
|
|
crossed180 = false;
|
|
|
|
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
|
|
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
|
|
for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
|
|
{
|
|
if ( !( *lineIt ).isEmpty() )
|
|
{
|
|
lines.append( qMakePair( currentLevel, *lineIt ) );
|
|
gridLineCount++;
|
|
}
|
|
}
|
|
currentLevel -= mGridIntervalY;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int QgsComposerMapGrid::yGridLinesCrsTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
|
|
{
|
|
lines.clear();
|
|
if ( !mComposerMap || mGridIntervalX <= 0.0 )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
|
|
double currentLevel = static_cast< int >(( bbox.xMinimum() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
|
|
|
|
double minY = bbox.yMinimum();
|
|
double maxY = bbox.yMaximum();
|
|
double step = ( maxY - minY ) / 20;
|
|
|
|
if ( qgsDoubleNear( step, 0.0 ) )
|
|
return 1;
|
|
|
|
bool crosses180 = false;
|
|
bool crossed180 = false;
|
|
if ( mCRS.isGeographic() && ( bbox.xMinimum() > bbox.xMaximum() ) )
|
|
{
|
|
//handle 180 degree longitude crossover
|
|
crosses180 = true;
|
|
}
|
|
|
|
int gridLineCount = 0;
|
|
while (( currentLevel <= bbox.xMaximum() || ( crosses180 && !crossed180 ) ) && gridLineCount < MAX_GRID_LINES )
|
|
{
|
|
QPolygonF gridLine;
|
|
double currentY = minY;
|
|
bool cont = true;
|
|
while ( cont )
|
|
{
|
|
if ( currentY > maxY )
|
|
{
|
|
cont = false;
|
|
}
|
|
try
|
|
{
|
|
//transform back to map crs
|
|
QgsPoint mapPoint = t.transform( currentLevel, currentY );
|
|
//transform back to composer coords
|
|
gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
|
|
}
|
|
catch ( QgsCsException & cse )
|
|
{
|
|
Q_UNUSED( cse );
|
|
QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
|
|
}
|
|
|
|
currentY += step;
|
|
}
|
|
//clip grid line to map polygon
|
|
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
|
|
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
|
|
for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
|
|
{
|
|
if ( !( *lineIt ).isEmpty() )
|
|
{
|
|
lines.append( qMakePair( currentLevel, *lineIt ) );
|
|
gridLineCount++;
|
|
}
|
|
}
|
|
currentLevel += mGridIntervalX;
|
|
if ( crosses180 && currentLevel > 180.0 )
|
|
{
|
|
currentLevel -= 360.0;
|
|
crossed180 = true;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void QgsComposerMapGrid::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
|
|
QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
|
|
{
|
|
QList< QgsMapAnnotation > borderPositions;
|
|
QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
|
|
for ( ; it != hLines.constEnd(); ++it )
|
|
{
|
|
QgsMapAnnotation p1;
|
|
p1.coordinate = it->first;
|
|
p1.itemPosition = it->second.p1();
|
|
p1.coordinateType = QgsComposerMapGrid::Latitude;
|
|
borderPositions << p1;
|
|
|
|
QgsMapAnnotation p2;
|
|
p2.coordinate = it->first;
|
|
p2.itemPosition = it->second.p2();
|
|
p2.coordinateType = QgsComposerMapGrid::Latitude;
|
|
borderPositions << p2;
|
|
}
|
|
it = vLines.constBegin();
|
|
for ( ; it != vLines.constEnd(); ++it )
|
|
{
|
|
QgsMapAnnotation p1;
|
|
p1.coordinate = it->first;
|
|
p1.itemPosition = it->second.p1();
|
|
p1.coordinateType = QgsComposerMapGrid::Longitude;
|
|
borderPositions << p1;
|
|
|
|
QgsMapAnnotation p2;
|
|
p2.coordinate = it->first;
|
|
p2.itemPosition = it->second.p2();
|
|
p2.coordinateType = QgsComposerMapGrid::Longitude;
|
|
borderPositions << p2;
|
|
}
|
|
|
|
QList< QgsMapAnnotation >::const_iterator bIt = borderPositions.constBegin();
|
|
for ( ; bIt != borderPositions.constEnd(); ++bIt )
|
|
{
|
|
QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( bIt->itemPosition, bIt->coordinateType );
|
|
if ( frameBorder == QgsComposerMapGrid::Left && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Left ) )
|
|
{
|
|
leftFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
|
|
}
|
|
else if ( frameBorder == QgsComposerMapGrid::Right && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Right ) )
|
|
{
|
|
rightFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
|
|
}
|
|
else if ( frameBorder == QgsComposerMapGrid::Top && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Top ) )
|
|
{
|
|
topFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
|
|
}
|
|
else if ( frameBorder == QgsComposerMapGrid::Bottom && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Bottom ) )
|
|
{
|
|
bottomFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool QgsComposerMapGrid::shouldShowDivisionForSide( QgsComposerMapGrid::AnnotationCoordinate coordinate, QgsComposerMapGrid::BorderSide side ) const
|
|
{
|
|
switch ( side )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
return shouldShowDivisionForDisplayMode( coordinate, mLeftFrameDivisions );
|
|
case QgsComposerMapGrid::Right:
|
|
return shouldShowDivisionForDisplayMode( coordinate, mRightFrameDivisions );
|
|
case QgsComposerMapGrid::Top:
|
|
return shouldShowDivisionForDisplayMode( coordinate, mTopFrameDivisions );
|
|
case QgsComposerMapGrid::Bottom:
|
|
default: //prevent warnings
|
|
return shouldShowDivisionForDisplayMode( coordinate, mBottomFrameDivisions );
|
|
}
|
|
}
|
|
|
|
bool QgsComposerMapGrid::shouldShowDivisionForDisplayMode( QgsComposerMapGrid::AnnotationCoordinate coordinate, QgsComposerMapGrid::DisplayMode mode ) const
|
|
{
|
|
return mode == QgsComposerMapGrid::ShowAll
|
|
|| ( mode == QgsComposerMapGrid::LatitudeOnly && coordinate == QgsComposerMapGrid::Latitude )
|
|
|| ( mode == QgsComposerMapGrid::LongitudeOnly && coordinate == QgsComposerMapGrid::Longitude );
|
|
}
|
|
|
|
bool sortByDistance( QPair<qreal , QgsComposerMapGrid::BorderSide> a, QPair<qreal , QgsComposerMapGrid::BorderSide> b )
|
|
{
|
|
return a.first < b.first;
|
|
}
|
|
|
|
QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( QPointF p, const AnnotationCoordinate coordinateType ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return QgsComposerMapGrid::Left;
|
|
}
|
|
|
|
double tolerance = qMax( mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.0, 1.0 );
|
|
|
|
//check for corner coordinates
|
|
if (( p.y() <= tolerance && p.x() <= tolerance ) // top left
|
|
|| ( p.y() <= tolerance && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //top right
|
|
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
|
|
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //bottom right
|
|
)
|
|
{
|
|
//coordinate is in corner - fall back to preferred side for coordinate type
|
|
if ( coordinateType == QgsComposerMapGrid::Latitude )
|
|
{
|
|
if ( p.x() <= tolerance )
|
|
{
|
|
return QgsComposerMapGrid::Left;
|
|
}
|
|
else
|
|
{
|
|
return QgsComposerMapGrid::Right;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( p.y() <= tolerance )
|
|
{
|
|
return QgsComposerMapGrid::Top;
|
|
}
|
|
else
|
|
{
|
|
return QgsComposerMapGrid::Bottom;
|
|
}
|
|
}
|
|
}
|
|
|
|
//otherwise, guess side based on closest map side to point
|
|
QList< QPair<qreal, QgsComposerMapGrid::BorderSide > > distanceToSide;
|
|
distanceToSide << qMakePair( p.x(), QgsComposerMapGrid::Left );
|
|
distanceToSide << qMakePair( mComposerMap->rect().width() - p.x(), QgsComposerMapGrid::Right );
|
|
distanceToSide << qMakePair( p.y(), QgsComposerMapGrid::Top );
|
|
distanceToSide << qMakePair( mComposerMap->rect().height() - p.y(), QgsComposerMapGrid::Bottom );
|
|
|
|
std::sort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
|
|
return distanceToSide.at( 0 ).second;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setLineSymbol( QgsLineSymbol* symbol )
|
|
{
|
|
delete mGridLineSymbol;
|
|
mGridLineSymbol = symbol;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setMarkerSymbol( QgsMarkerSymbol *symbol )
|
|
{
|
|
delete mGridMarkerSymbol;
|
|
mGridMarkerSymbol = symbol;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setAnnotationDisplay( const QgsComposerMapGrid::DisplayMode display, const QgsComposerMapGrid::BorderSide border )
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
mLeftGridAnnotationDisplay = display;
|
|
break;
|
|
case QgsComposerMapGrid::Right:
|
|
mRightGridAnnotationDisplay = display;
|
|
break;
|
|
case QgsComposerMapGrid::Top:
|
|
mTopGridAnnotationDisplay = display;
|
|
break;
|
|
case QgsComposerMapGrid::Bottom:
|
|
mBottomGridAnnotationDisplay = display;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ( mComposerMap )
|
|
{
|
|
mComposerMap->updateBoundingRect();
|
|
mComposerMap->update();
|
|
}
|
|
}
|
|
|
|
QgsComposerMapGrid::DisplayMode QgsComposerMapGrid::annotationDisplay( const QgsComposerMapGrid::BorderSide border ) const
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
return mLeftGridAnnotationDisplay;
|
|
case QgsComposerMapGrid::Right:
|
|
return mRightGridAnnotationDisplay;
|
|
case QgsComposerMapGrid::Top:
|
|
return mTopGridAnnotationDisplay;
|
|
case QgsComposerMapGrid::Bottom:
|
|
default:
|
|
return mBottomGridAnnotationDisplay;
|
|
}
|
|
}
|
|
|
|
double QgsComposerMapGrid::maxExtension()
|
|
{
|
|
double top = 0.0;
|
|
double right = 0.0;
|
|
double bottom = 0.0;
|
|
double left = 0.0;
|
|
calculateMaxExtension( top, right, bottom, left );
|
|
return qMax( qMax( qMax( top, right ), bottom ), left );
|
|
}
|
|
|
|
void QgsComposerMapGrid::calculateMaxExtension( double& top, double& right, double& bottom, double& left )
|
|
{
|
|
top = 0.0;
|
|
right = 0.0;
|
|
bottom = 0.0;
|
|
left = 0.0;
|
|
|
|
if ( !mComposerMap || !mEnabled )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//setup render context
|
|
QgsRenderContext context = QgsComposerUtils::createRenderContextForComposition( mComposition, nullptr );
|
|
QgsExpressionContext expressionContext = createExpressionContext();
|
|
context.setExpressionContext( expressionContext );
|
|
|
|
GridExtension extension;
|
|
|
|
//collect grid lines
|
|
QList< QPair< double, QLineF > > verticalLines;
|
|
QList< QPair< double, QLineF > > horizontalLines;
|
|
if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != mComposerMap->crs() )
|
|
{
|
|
drawGridCrsTransform( context, 0, horizontalLines, verticalLines, false );
|
|
}
|
|
else
|
|
{
|
|
drawGridNoTransform( context, 0, horizontalLines, verticalLines, false );
|
|
}
|
|
|
|
if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame )
|
|
{
|
|
drawGridFrame( nullptr, horizontalLines, verticalLines, &extension );
|
|
}
|
|
|
|
if ( mShowGridAnnotation )
|
|
{
|
|
drawCoordinateAnnotations( nullptr, horizontalLines, verticalLines, context.expressionContext(), &extension );
|
|
}
|
|
|
|
top = extension.top;
|
|
right = extension.right;
|
|
bottom = extension.bottom;
|
|
left = extension.left;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setUnits( const QgsComposerMapGrid::GridUnit unit )
|
|
{
|
|
if ( unit == mGridUnit )
|
|
{
|
|
return;
|
|
}
|
|
mGridUnit = unit;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setIntervalX( const double interval )
|
|
{
|
|
if ( qgsDoubleNear( interval, mGridIntervalX ) )
|
|
{
|
|
return;
|
|
}
|
|
mGridIntervalX = interval;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setIntervalY( const double interval )
|
|
{
|
|
if ( qgsDoubleNear( interval, mGridIntervalY ) )
|
|
{
|
|
return;
|
|
}
|
|
mGridIntervalY = interval;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setOffsetX( const double offset )
|
|
{
|
|
if ( qgsDoubleNear( offset, mGridOffsetX ) )
|
|
{
|
|
return;
|
|
}
|
|
mGridOffsetX = offset;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setOffsetY( const double offset )
|
|
{
|
|
if ( qgsDoubleNear( offset, mGridOffsetY ) )
|
|
{
|
|
return;
|
|
}
|
|
mGridOffsetY = offset;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setStyle( const QgsComposerMapGrid::GridStyle style )
|
|
{
|
|
if ( style == mGridStyle )
|
|
{
|
|
return;
|
|
}
|
|
mGridStyle = style;
|
|
mTransformDirty = true;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setAnnotationDirection( const QgsComposerMapGrid::AnnotationDirection direction, const QgsComposerMapGrid::BorderSide border )
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
mLeftGridAnnotationDirection = direction;
|
|
break;
|
|
case QgsComposerMapGrid::Right:
|
|
mRightGridAnnotationDirection = direction;
|
|
break;
|
|
case QgsComposerMapGrid::Top:
|
|
mTopGridAnnotationDirection = direction;
|
|
break;
|
|
case QgsComposerMapGrid::Bottom:
|
|
mBottomGridAnnotationDirection = direction;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ( mComposerMap )
|
|
{
|
|
mComposerMap->updateBoundingRect();
|
|
mComposerMap->update();
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::setFrameSideFlags( FrameSideFlags flags )
|
|
{
|
|
mGridFrameSides = flags;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setFrameSideFlag( QgsComposerMapGrid::FrameSideFlag flag, bool on )
|
|
{
|
|
if ( on )
|
|
mGridFrameSides |= flag;
|
|
else
|
|
mGridFrameSides &= ~flag;
|
|
}
|
|
|
|
QgsComposerMapGrid::FrameSideFlags QgsComposerMapGrid::frameSideFlags() const
|
|
{
|
|
return mGridFrameSides;
|
|
}
|
|
|
|
QgsExpressionContext QgsComposerMapGrid::createExpressionContext() const
|
|
{
|
|
QgsExpressionContext context = QgsComposerObject::createExpressionContext();
|
|
context.appendScope( new QgsExpressionContextScope( tr( "Grid" ) ) );
|
|
context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_number" ), 0, true ) );
|
|
context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "grid_axis" ), "x", true ) );
|
|
context.setHighlightedVariables( QStringList() << QStringLiteral( "grid_number" ) << QStringLiteral( "grid_axis" ) );
|
|
return context;
|
|
}
|
|
|
|
bool QgsComposerMapGrid::testFrameSideFlag( QgsComposerMapGrid::FrameSideFlag flag ) const
|
|
{
|
|
return mGridFrameSides.testFlag( flag );
|
|
}
|
|
|
|
void QgsComposerMapGrid::setAnnotationDirection( const AnnotationDirection direction )
|
|
{
|
|
mLeftGridAnnotationDirection = direction;
|
|
mRightGridAnnotationDirection = direction;
|
|
mTopGridAnnotationDirection = direction;
|
|
mBottomGridAnnotationDirection = direction;
|
|
}
|
|
|
|
void QgsComposerMapGrid::setAnnotationPosition( const AnnotationPosition position, const BorderSide border )
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
mLeftGridAnnotationPosition = position;
|
|
break;
|
|
case QgsComposerMapGrid::Right:
|
|
mRightGridAnnotationPosition = position;
|
|
break;
|
|
case QgsComposerMapGrid::Top:
|
|
mTopGridAnnotationPosition = position;
|
|
break;
|
|
case QgsComposerMapGrid::Bottom:
|
|
mBottomGridAnnotationPosition = position;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ( mComposerMap )
|
|
{
|
|
mComposerMap->updateBoundingRect();
|
|
mComposerMap->update();
|
|
}
|
|
}
|
|
|
|
QgsComposerMapGrid::AnnotationPosition QgsComposerMapGrid::annotationPosition( const QgsComposerMapGrid::BorderSide border ) const
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
return mLeftGridAnnotationPosition;
|
|
case QgsComposerMapGrid::Right:
|
|
return mRightGridAnnotationPosition;
|
|
case QgsComposerMapGrid::Top:
|
|
return mTopGridAnnotationPosition;
|
|
case QgsComposerMapGrid::Bottom:
|
|
default:
|
|
return mBottomGridAnnotationPosition;
|
|
}
|
|
}
|
|
|
|
QgsComposerMapGrid::AnnotationDirection QgsComposerMapGrid::annotationDirection( const BorderSide border ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return mLeftGridAnnotationDirection;
|
|
}
|
|
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
return mLeftGridAnnotationDirection;
|
|
case QgsComposerMapGrid::Right:
|
|
return mRightGridAnnotationDirection;
|
|
case QgsComposerMapGrid::Top:
|
|
return mTopGridAnnotationDirection;
|
|
case QgsComposerMapGrid::Bottom:
|
|
default:
|
|
return mBottomGridAnnotationDirection;
|
|
}
|
|
}
|
|
|
|
void QgsComposerMapGrid::setFrameDivisions( const QgsComposerMapGrid::DisplayMode divisions, const QgsComposerMapGrid::BorderSide border )
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
mLeftFrameDivisions = divisions;
|
|
break;
|
|
case QgsComposerMapGrid::Right:
|
|
mRightFrameDivisions = divisions;
|
|
break;
|
|
case QgsComposerMapGrid::Top:
|
|
mTopFrameDivisions = divisions;
|
|
break;
|
|
case QgsComposerMapGrid::Bottom:
|
|
mBottomFrameDivisions = divisions;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ( mComposerMap )
|
|
{
|
|
mComposerMap->update();
|
|
}
|
|
}
|
|
|
|
QgsComposerMapGrid::DisplayMode QgsComposerMapGrid::frameDivisions( const QgsComposerMapGrid::BorderSide border ) const
|
|
{
|
|
switch ( border )
|
|
{
|
|
case QgsComposerMapGrid::Left:
|
|
return mLeftFrameDivisions;
|
|
case QgsComposerMapGrid::Right:
|
|
return mRightFrameDivisions;
|
|
case QgsComposerMapGrid::Top:
|
|
return mTopFrameDivisions;
|
|
case QgsComposerMapGrid::Bottom:
|
|
default:
|
|
return mBottomFrameDivisions;
|
|
}
|
|
}
|
|
|
|
int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTransform& inverseTransform ) const
|
|
{
|
|
if ( !mComposerMap )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
try
|
|
{
|
|
QgsCoordinateTransform tr( mComposerMap->crs(), mCRS );
|
|
QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
|
|
QRectF mbr = mapPolygon.boundingRect();
|
|
QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
|
|
|
|
|
|
if ( mCRS.isGeographic() )
|
|
{
|
|
//handle crossing the 180 degree longitude line
|
|
QgsPoint lowerLeft( mapBoundingRect.xMinimum(), mapBoundingRect.yMinimum() );
|
|
QgsPoint upperRight( mapBoundingRect.xMaximum(), mapBoundingRect.yMaximum() );
|
|
|
|
lowerLeft = tr.transform( lowerLeft.x(), lowerLeft.y() );
|
|
upperRight = tr.transform( upperRight.x(), upperRight.y() );
|
|
|
|
if ( lowerLeft.x() > upperRight.x() )
|
|
{
|
|
//we've crossed the line
|
|
crsRect = tr.transformBoundingBox( mapBoundingRect, QgsCoordinateTransform::ForwardTransform, true );
|
|
}
|
|
else
|
|
{
|
|
//didn't cross the line
|
|
crsRect = tr.transformBoundingBox( mapBoundingRect );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
crsRect = tr.transformBoundingBox( mapBoundingRect );
|
|
}
|
|
|
|
inverseTransform.setSourceCrs( mCRS );
|
|
inverseTransform.setDestinationCrs( mComposerMap->crs() );
|
|
}
|
|
catch ( QgsCsException & cse )
|
|
{
|
|
Q_UNUSED( cse );
|
|
QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
QList<QPolygonF> QgsComposerMapGrid::trimLinesToMap( const QPolygonF& line, const QgsRectangle& rect )
|
|
{
|
|
QgsGeometry lineGeom = QgsGeometry::fromQPolygonF( line );
|
|
QgsGeometry rectGeom = QgsGeometry::fromRect( rect );
|
|
|
|
QgsGeometry intersected = lineGeom.intersection( rectGeom );
|
|
QList<QgsGeometry> intersectedParts = intersected.asGeometryCollection();
|
|
|
|
QList<QPolygonF> trimmedLines;
|
|
QList<QgsGeometry>::const_iterator geomIt = intersectedParts.constBegin();
|
|
for ( ; geomIt != intersectedParts.constEnd(); ++geomIt )
|
|
{
|
|
trimmedLines << ( *geomIt ).asQPolygonF();
|
|
}
|
|
return trimmedLines;
|
|
}
|