Skip to content

Commit 02beea3

Browse files
committed
set default interval to approx. 1/5 of map extent ; add option to set interval from raster layer ; disable grid when map units change ; reset grid (and disable) when project changes
1 parent 498575e commit 02beea3

8 files changed

+387
-136
lines changed

src/app/qgisapp.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,7 @@ void QgisApp::createDecorations()
20222022
addDecorationItem( mDecorationNorthArrow );
20232023
addDecorationItem( mDecorationScaleBar );
20242024
connect( mMapCanvas, SIGNAL( renderComplete( QPainter * ) ), this, SLOT( renderDecorationItems( QPainter * ) ) );
2025+
connect( this, SIGNAL( newProject() ), this, SLOT( projectReadDecorationItems() ) );
20252026
connect( this, SIGNAL( projectRead() ), this, SLOT( projectReadDecorationItems() ) );
20262027
}
20272028

@@ -5026,11 +5027,13 @@ void QgisApp::setProjectCRSFromLayer()
50265027

50275028
QgsCoordinateReferenceSystem crs = mMapLegend->currentLayer()->crs();
50285029
QgsMapRenderer* myRenderer = mMapCanvas->mapRenderer();
5030+
mMapCanvas->freeze();
50295031
myRenderer->setDestinationCrs( crs );
50305032
if ( crs.mapUnits() != QGis::UnknownUnit )
50315033
{
50325034
myRenderer->setMapUnits( crs.mapUnits() );
50335035
}
5036+
mMapCanvas->freeze( false );
50345037
mMapCanvas->refresh();
50355038
}
50365039

src/app/qgsdecorationgrid.cpp

+182-9
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@
2121

2222
#include "qgisapp.h"
2323
#include "qgslogger.h"
24-
#include "qgsmapcanvas.h"
2524
#include "qgsmaplayer.h"
25+
#include "qgsrasterlayer.h"
2626
#include "qgsmaptopixel.h"
2727
#include "qgspoint.h"
2828
#include "qgsproject.h"
2929
#include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
3030
#include "qgssymbolv2.h" //for symbology
3131
#include "qgsrendercontext.h"
32+
#include "qgsmapcanvas.h"
33+
#include "qgsmaprenderer.h"
3234

3335
#include <QPainter>
3436
#include <QAction>
@@ -42,6 +44,7 @@
4244
#include <QFile>
4345
#include <QLocale>
4446
#include <QDomDocument>
47+
#include <QMessageBox>
4548

4649
//non qt includes
4750
#include <cmath>
@@ -58,9 +61,13 @@ QgsDecorationGrid::QgsDecorationGrid( QObject* parent )
5861
: QgsDecorationItem( parent )
5962
{
6063
setName( "Grid" );
64+
6165
mLineSymbol = 0;
6266
mMarkerSymbol = 0;
6367
projectRead();
68+
69+
connect( QgisApp::instance()->mapCanvas()->mapRenderer(), SIGNAL( mapUnitsChanged() ),
70+
this, SLOT( checkMapUnitsChanged() ) );
6471
}
6572

6673
QgsDecorationGrid::~QgsDecorationGrid()
@@ -73,19 +80,25 @@ QgsDecorationGrid::~QgsDecorationGrid()
7380

7481
void QgsDecorationGrid::setLineSymbol( QgsLineSymbolV2* symbol )
7582
{
76-
delete mLineSymbol;
83+
if ( mLineSymbol )
84+
delete mLineSymbol;
7785
mLineSymbol = symbol;
7886
}
7987

8088
void QgsDecorationGrid::setMarkerSymbol( QgsMarkerSymbolV2* symbol )
8189
{
82-
delete mMarkerSymbol;
90+
if ( mMarkerSymbol )
91+
delete mMarkerSymbol;
8392
mMarkerSymbol = symbol;
8493
}
8594

8695
void QgsDecorationGrid::projectRead()
8796
{
8897
QgsDecorationItem::projectRead();
98+
99+
mEnabled = QgsProject::instance()->readBoolEntry( mNameConfig, "/Enabled", false );
100+
mMapUnits = ( QGis::UnitType ) QgsProject::instance()->readNumEntry( mNameConfig, "/MapUnits",
101+
QGis::UnknownUnit );
89102
mGridStyle = ( GridStyle ) QgsProject::instance()->readNumEntry( mNameConfig, "/Style",
90103
QgsDecorationGrid::Solid );
91104
mGridIntervalX = QgsProject::instance()->readDoubleEntry( mNameConfig, "/IntervalX", 10 );
@@ -94,8 +107,10 @@ void QgsDecorationGrid::projectRead()
94107
mGridOffsetY = QgsProject::instance()->readDoubleEntry( mNameConfig, "/OffsetY", 0 );
95108
mCrossLength = QgsProject::instance()->readDoubleEntry( mNameConfig, "/CrossLength", 3 );
96109
mShowGridAnnotation = QgsProject::instance()->readBoolEntry( mNameConfig, "/ShowAnnotation", false );
97-
mGridAnnotationPosition = ( GridAnnotationPosition ) QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationPosition", 0 );
98-
mGridAnnotationDirection = ( GridAnnotationDirection ) QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationDirection", 0 );
110+
mGridAnnotationPosition = ( GridAnnotationPosition ) QgsProject::instance()->readNumEntry( mNameConfig,
111+
"/AnnotationPosition", 0 );
112+
mGridAnnotationDirection = ( GridAnnotationDirection ) QgsProject::instance()->readNumEntry( mNameConfig,
113+
"/AnnotationDirection", 0 );
99114
mGridAnnotationFont.fromString( QgsProject::instance()->readEntry( mNameConfig, "/AnnotationFont", "" ) );
100115
mAnnotationFrameDistance = QgsProject::instance()->readDoubleEntry( mNameConfig, "/AnnotationFrameDistance", 0 );
101116
mGridAnnotationPrecision = QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationPrecision", 3 );
@@ -105,25 +120,25 @@ void QgsDecorationGrid::projectRead()
105120
QDomElement elem;
106121
QString xml;
107122

123+
if ( mLineSymbol )
124+
setLineSymbol( 0 );
108125
xml = QgsProject::instance()->readEntry( mNameConfig, "/LineSymbol" );
109126
if ( xml != "" )
110127
{
111128
doc.setContent( xml );
112129
elem = doc.documentElement();
113-
if ( mLineSymbol )
114-
delete mLineSymbol;
115130
mLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( elem ) );
116131
}
117132
if ( ! mLineSymbol )
118133
mLineSymbol = new QgsLineSymbolV2();
119134

135+
if ( mMarkerSymbol )
136+
setMarkerSymbol( 0 );
120137
xml = QgsProject::instance()->readEntry( mNameConfig, "/MarkerSymbol" );
121138
if ( xml != "" )
122139
{
123140
doc.setContent( xml );
124141
elem = doc.documentElement();
125-
if ( mMarkerSymbol )
126-
delete mMarkerSymbol;
127142
mMarkerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( elem ) );
128143
}
129144
if ( ! mMarkerSymbol )
@@ -133,6 +148,8 @@ void QgsDecorationGrid::projectRead()
133148
void QgsDecorationGrid::saveToProject()
134149
{
135150
QgsDecorationItem::saveToProject();
151+
QgsProject::instance()->writeEntry( mNameConfig, "/Enabled", mEnabled );
152+
QgsProject::instance()->writeEntry( mNameConfig, "/MapUnits", ( int ) mMapUnits );
136153
QgsProject::instance()->writeEntry( mNameConfig, "/Style", ( int ) mGridStyle );
137154
QgsProject::instance()->writeEntry( mNameConfig, "/IntervalX", mGridIntervalX );
138155
QgsProject::instance()->writeEntry( mNameConfig, "/IntervalY", mGridIntervalY );
@@ -709,3 +726,159 @@ QFont QgsDecorationGrid::scaledFontPixelSize( const QFont& font ) const
709726
return scaledFont;
710727
}
711728

729+
void QgsDecorationGrid::checkMapUnitsChanged()
730+
{
731+
// disable grid if units changed and grid is enabled, and update the canvas
732+
// this is to avoid problems when CRS changes to/from geographic and projected
733+
// a better solution would be to change the grid interval, but this is a little tricky
734+
// note: we could be less picky (e.g. from degrees to DMS)
735+
QGis::UnitType mapUnits = QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits();
736+
if ( mEnabled && ( mMapUnits != mapUnits ) )
737+
{
738+
mEnabled = false;
739+
mMapUnits = QGis::UnknownUnit; // make sure isDirty() returns true
740+
if ( ! QgisApp::instance()->mapCanvas()->isFrozen() )
741+
{
742+
update();
743+
}
744+
}
745+
}
746+
747+
bool QgsDecorationGrid::isDirty()
748+
{
749+
// checks if stored map units is undefined or different from canvas map units
750+
// or if interval is 0
751+
if ( mMapUnits == QGis::UnknownUnit ||
752+
mMapUnits != QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits() ||
753+
mGridIntervalX == 0 || mGridIntervalY == 0 )
754+
return true;
755+
return false;
756+
}
757+
758+
void QgsDecorationGrid::setDirty( bool dirty )
759+
{
760+
if ( dirty )
761+
{
762+
mMapUnits = QGis::UnknownUnit;
763+
}
764+
else
765+
{
766+
mMapUnits = QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits();
767+
}
768+
}
769+
770+
bool QgsDecorationGrid::getIntervalFromExtent( double* values, bool useXAxis )
771+
{
772+
// get default interval from current extents
773+
// calculate a default interval that is approx (extent width)/5 , adjusted so that it is a rounded number
774+
// e.g. 12.7 -> 10 66556 -> 70000
775+
double interval = 0;
776+
QgsRectangle extent = QgisApp::instance()->mapCanvas()->extent();
777+
if ( useXAxis )
778+
interval = ( extent.xMaximum() - extent.xMinimum() ) / 5;
779+
else
780+
interval = ( extent.yMaximum() - extent.yMinimum() ) / 5;
781+
QgsDebugMsg( QString( "interval: %1" ).arg( interval ) );
782+
if ( interval != 0 )
783+
{
784+
double interval2 = 0;
785+
int factor = pow( 10, floor( log10( interval ) ) );
786+
if ( factor != 0 )
787+
{
788+
interval2 = round( interval / factor ) * factor;
789+
QgsDebugMsg( QString( "interval2: %1" ).arg( interval2 ) );
790+
if ( interval2 != 0 )
791+
interval = interval2;
792+
}
793+
}
794+
values[0] = values[1] = interval;
795+
values[2] = values[3] = 0;
796+
return true;
797+
}
798+
799+
bool QgsDecorationGrid::getIntervalFromCurrentLayer( double* values )
800+
{
801+
// get current layer and make sure it is a raster layer and CRSs match
802+
QgsMapLayer* layer = QgisApp::instance()->mapCanvas()->currentLayer();
803+
if ( ! layer )
804+
{
805+
QMessageBox::warning( 0, tr( "Error" ), tr( "No active layer" ) );
806+
return false;
807+
}
808+
if ( layer->type() != QgsMapLayer::RasterLayer )
809+
{
810+
QMessageBox::warning( 0, tr( "Error" ), tr( "Please select a raster layer" ) );
811+
return false;
812+
}
813+
QgsRasterLayer* rlayer = dynamic_cast<QgsRasterLayer*>( layer );
814+
if ( !rlayer )
815+
{
816+
QMessageBox::warning( 0, tr( "Error" ), tr( "Invalid raster layer" ) );
817+
return false;
818+
}
819+
const QgsCoordinateReferenceSystem& layerCRS = layer->crs();
820+
const QgsCoordinateReferenceSystem& mapCRS =
821+
QgisApp::instance()->mapCanvas()->mapRenderer()->destinationCrs();
822+
// is this the best way to compare CRS? should we also make sure map has OTF enabled?
823+
// TODO calculate transformed values if necessary
824+
if ( layerCRS != mapCRS )
825+
{
826+
QMessageBox::warning( 0, tr( "Error" ), tr( "Layer CRS must be equal to project CRS" ) );
827+
return false;
828+
}
829+
830+
// TODO add a function in QgsRasterLayer to get x/y resolution from provider
831+
QgsRectangle extent = rlayer->extent();
832+
values[0] = fabs( extent.xMaximum() - extent.xMinimum() ) / rlayer->width();
833+
values[1] = fabs( extent.yMaximum() - extent.yMinimum() ) / rlayer->height();
834+
// TODO calculate offset - this is a little tricky...
835+
values[2] = values[3] = 0;
836+
837+
QgsDebugMsg( QString( "xmax: %1 xmin: %2 width: %3 xInterval: %4" ).arg( extent.xMaximum() ).arg( extent.xMinimum() ).arg( rlayer->width() ).arg( values[0] ) );
838+
839+
return true;
840+
}
841+
842+
843+
// TODO preliminary code to calculate offset
844+
// double diff = getClosestPixel( extent.xMaximum(), boundBox2.xMinimum(), boundBox.xMinimum(), dx, True )
845+
846+
// // function ported from ftools doVectorGrid.py
847+
// double getClosestPixel( double startVal, double targetVal, double step, bool isMin )
848+
// {
849+
// bool foundVal = false;
850+
// double tmpVal = startVal;
851+
// bool backOneStep;
852+
// // find pixels covering the extent - slightly inneficient b/c loop on all elements before xMin
853+
// if ( targetVal < startVal )
854+
// {
855+
// backOneStep = ! isMin;
856+
// step = - step;
857+
// // should make sure we don't go into an infinite loop (shouldn't happen)
858+
// while ( ! foundVal )
859+
// {
860+
// if ( tmpVal <= targetVal )
861+
// {
862+
// if ( backOneStep )
863+
// tmpVal -= step;
864+
// return tmpVal;
865+
// }
866+
// tmpVal += step;
867+
// }
868+
// }
869+
// else
870+
// {
871+
// backOneStep = isMin;
872+
// while ( ! foundVal )
873+
// {
874+
// if ( tmpVal >= targetVal )
875+
// {
876+
// if ( backOneStep )
877+
// tmpVal -= step;
878+
// return tmpVal;
879+
// }
880+
// tmpVal += step;
881+
// }
882+
// }
883+
// return 0;
884+
// }

src/app/qgsdecorationgrid.h

+28-14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define QGSDECORATIONGRID_H
2020

2121
#include "qgsdecorationitem.h"
22+
#include <qgis.h>
2223

2324
class QPainter;
2425
class QgsLineSymbolV2;
@@ -87,38 +88,31 @@ class QgsDecorationGrid: public QgsDecorationItem
8788
/**Sets the color of the grid pen */
8889
void setGridPenColor( const QColor& c ) { mGridPen.setColor( c ); }
8990

90-
/**Sets font for grid annotations
91-
@note this function was added in version 1.4*/
91+
/**Sets font for grid annotations */
9292
void setGridAnnotationFont( const QFont& f ) { mGridAnnotationFont = f; }
9393
QFont gridAnnotationFont() const { return mGridAnnotationFont; }
9494

95-
/**Sets coordinate precision for grid annotations
96-
@note this function was added in version 1.4*/
95+
/**Sets coordinate precision for grid annotations */
9796
void setGridAnnotationPrecision( int p ) {mGridAnnotationPrecision = p;}
9897
int gridAnnotationPrecision() const {return mGridAnnotationPrecision;}
9998

100-
/**Sets flag if grid annotation should be shown
101-
@note this function was added in version 1.4*/
99+
/**Sets flag if grid annotation should be shown */
102100
void setShowGridAnnotation( bool show ) {mShowGridAnnotation = show;}
103101
bool showGridAnnotation() const {return mShowGridAnnotation;}
104102

105-
/**Sets position of grid annotations. Possibilities are inside or outside of the map frame
106-
@note this function was added in version 1.4*/
103+
/**Sets position of grid annotations. Possibilities are inside or outside of the map frame */
107104
void setGridAnnotationPosition( GridAnnotationPosition p ) {mGridAnnotationPosition = p;}
108105
GridAnnotationPosition gridAnnotationPosition() const {return mGridAnnotationPosition;}
109106

110-
/**Sets distance between map frame and annotations
111-
@note this function was added in version 1.4*/
107+
/**Sets distance between map frame and annotations */
112108
void setAnnotationFrameDistance( double d ) {mAnnotationFrameDistance = d;}
113109
double annotationFrameDistance() const {return mAnnotationFrameDistance;}
114110

115-
/**Sets grid annotation direction. Can be horizontal, vertical, direction of axis and horizontal and vertical
116-
@note this function was added in version 1.4*/
111+
/**Sets grid annotation direction. Can be horizontal, vertical, direction of axis and horizontal and vertical */
117112
void setGridAnnotationDirection( GridAnnotationDirection d ) {mGridAnnotationDirection = d;}
118113
GridAnnotationDirection gridAnnotationDirection() const {return mGridAnnotationDirection;}
119114

120-
/**Sets length of the cros segments (if grid style is cross)
121-
@note this function was added in version 1.4*/
115+
/**Sets length of the cros segments (if grid style is cross) */
122116
void setCrossLength( double l ) {mCrossLength = l;}
123117
double crossLength() {return mCrossLength;}
124118

@@ -130,6 +124,21 @@ class QgsDecorationGrid: public QgsDecorationItem
130124
void setMarkerSymbol( QgsMarkerSymbolV2* symbol );
131125
const QgsMarkerSymbolV2* markerSymbol() const { return mMarkerSymbol; }
132126

127+
/**Sets map unit type */
128+
void setMapUnits( QGis::UnitType t ) { mMapUnits = t; }
129+
QGis::UnitType mapUnits() { return mMapUnits; }
130+
131+
/**Set mapUnits value */
132+
void setDirty( bool dirty = true );
133+
bool isDirty();
134+
135+
/**Computes interval that is approx. 1/5 of canvas extent */
136+
bool getIntervalFromExtent( double* values, bool useXAxis = true );
137+
/**Computes interval from current raster layer */
138+
bool getIntervalFromCurrentLayer( double* values );
139+
140+
double getDefaultInterval( bool useXAxis = true );
141+
133142
public slots:
134143
//! set values on the gui when a project is read or the gui first loaded
135144
void projectRead();
@@ -141,6 +150,9 @@ class QgsDecorationGrid: public QgsDecorationItem
141150
//! Show the dialog box
142151
void run();
143152

153+
//! check that map units changed and disable if necessary
154+
void checkMapUnitsChanged();
155+
144156
private:
145157

146158
/**Enum for different frame borders*/
@@ -182,6 +194,8 @@ class QgsDecorationGrid: public QgsDecorationItem
182194
QgsLineSymbolV2* mLineSymbol;
183195
QgsMarkerSymbolV2* mMarkerSymbol;
184196

197+
QGis::UnitType mMapUnits;
198+
185199
/**Draw coordinates for mGridAnnotationType Coordinate
186200
@param p drawing painter
187201
@param hLines horizontal coordinate lines in item coordinates

0 commit comments

Comments
 (0)