Skip to content
Permalink
Browse files

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
  • Loading branch information
etiennesky committed Jun 24, 2012
1 parent 498575e commit 02beea314afcac386b49d0dc4df4cbe0efd09fc5
@@ -2022,6 +2022,7 @@ void QgisApp::createDecorations()
addDecorationItem( mDecorationNorthArrow );
addDecorationItem( mDecorationScaleBar );
connect( mMapCanvas, SIGNAL( renderComplete( QPainter * ) ), this, SLOT( renderDecorationItems( QPainter * ) ) );
connect( this, SIGNAL( newProject() ), this, SLOT( projectReadDecorationItems() ) );
connect( this, SIGNAL( projectRead() ), this, SLOT( projectReadDecorationItems() ) );
}

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

QgsCoordinateReferenceSystem crs = mMapLegend->currentLayer()->crs();
QgsMapRenderer* myRenderer = mMapCanvas->mapRenderer();
mMapCanvas->freeze();
myRenderer->setDestinationCrs( crs );
if ( crs.mapUnits() != QGis::UnknownUnit )
{
myRenderer->setMapUnits( crs.mapUnits() );
}
mMapCanvas->freeze( false );
mMapCanvas->refresh();
}

@@ -21,14 +21,16 @@

#include "qgisapp.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmaplayer.h"
#include "qgsrasterlayer.h"
#include "qgsmaptopixel.h"
#include "qgspoint.h"
#include "qgsproject.h"
#include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
#include "qgssymbolv2.h" //for symbology
#include "qgsrendercontext.h"
#include "qgsmapcanvas.h"
#include "qgsmaprenderer.h"

#include <QPainter>
#include <QAction>
@@ -42,6 +44,7 @@
#include <QFile>
#include <QLocale>
#include <QDomDocument>
#include <QMessageBox>

//non qt includes
#include <cmath>
@@ -58,9 +61,13 @@ QgsDecorationGrid::QgsDecorationGrid( QObject* parent )
: QgsDecorationItem( parent )
{
setName( "Grid" );

mLineSymbol = 0;
mMarkerSymbol = 0;
projectRead();

connect( QgisApp::instance()->mapCanvas()->mapRenderer(), SIGNAL( mapUnitsChanged() ),
this, SLOT( checkMapUnitsChanged() ) );
}

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

void QgsDecorationGrid::setLineSymbol( QgsLineSymbolV2* symbol )
{
delete mLineSymbol;
if ( mLineSymbol )
delete mLineSymbol;
mLineSymbol = symbol;
}

void QgsDecorationGrid::setMarkerSymbol( QgsMarkerSymbolV2* symbol )
{
delete mMarkerSymbol;
if ( mMarkerSymbol )
delete mMarkerSymbol;
mMarkerSymbol = symbol;
}

void QgsDecorationGrid::projectRead()
{
QgsDecorationItem::projectRead();

mEnabled = QgsProject::instance()->readBoolEntry( mNameConfig, "/Enabled", false );
mMapUnits = ( QGis::UnitType ) QgsProject::instance()->readNumEntry( mNameConfig, "/MapUnits",
QGis::UnknownUnit );
mGridStyle = ( GridStyle ) QgsProject::instance()->readNumEntry( mNameConfig, "/Style",
QgsDecorationGrid::Solid );
mGridIntervalX = QgsProject::instance()->readDoubleEntry( mNameConfig, "/IntervalX", 10 );
@@ -94,8 +107,10 @@ void QgsDecorationGrid::projectRead()
mGridOffsetY = QgsProject::instance()->readDoubleEntry( mNameConfig, "/OffsetY", 0 );
mCrossLength = QgsProject::instance()->readDoubleEntry( mNameConfig, "/CrossLength", 3 );
mShowGridAnnotation = QgsProject::instance()->readBoolEntry( mNameConfig, "/ShowAnnotation", false );
mGridAnnotationPosition = ( GridAnnotationPosition ) QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationPosition", 0 );
mGridAnnotationDirection = ( GridAnnotationDirection ) QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationDirection", 0 );
mGridAnnotationPosition = ( GridAnnotationPosition ) QgsProject::instance()->readNumEntry( mNameConfig,
"/AnnotationPosition", 0 );
mGridAnnotationDirection = ( GridAnnotationDirection ) QgsProject::instance()->readNumEntry( mNameConfig,
"/AnnotationDirection", 0 );
mGridAnnotationFont.fromString( QgsProject::instance()->readEntry( mNameConfig, "/AnnotationFont", "" ) );
mAnnotationFrameDistance = QgsProject::instance()->readDoubleEntry( mNameConfig, "/AnnotationFrameDistance", 0 );
mGridAnnotationPrecision = QgsProject::instance()->readNumEntry( mNameConfig, "/AnnotationPrecision", 3 );
@@ -105,25 +120,25 @@ void QgsDecorationGrid::projectRead()
QDomElement elem;
QString xml;

if ( mLineSymbol )
setLineSymbol( 0 );
xml = QgsProject::instance()->readEntry( mNameConfig, "/LineSymbol" );
if ( xml != "" )
{
doc.setContent( xml );
elem = doc.documentElement();
if ( mLineSymbol )
delete mLineSymbol;
mLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( elem ) );
}
if ( ! mLineSymbol )
mLineSymbol = new QgsLineSymbolV2();

if ( mMarkerSymbol )
setMarkerSymbol( 0 );
xml = QgsProject::instance()->readEntry( mNameConfig, "/MarkerSymbol" );
if ( xml != "" )
{
doc.setContent( xml );
elem = doc.documentElement();
if ( mMarkerSymbol )
delete mMarkerSymbol;
mMarkerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( elem ) );
}
if ( ! mMarkerSymbol )
@@ -133,6 +148,8 @@ void QgsDecorationGrid::projectRead()
void QgsDecorationGrid::saveToProject()
{
QgsDecorationItem::saveToProject();
QgsProject::instance()->writeEntry( mNameConfig, "/Enabled", mEnabled );
QgsProject::instance()->writeEntry( mNameConfig, "/MapUnits", ( int ) mMapUnits );
QgsProject::instance()->writeEntry( mNameConfig, "/Style", ( int ) mGridStyle );
QgsProject::instance()->writeEntry( mNameConfig, "/IntervalX", mGridIntervalX );
QgsProject::instance()->writeEntry( mNameConfig, "/IntervalY", mGridIntervalY );
@@ -709,3 +726,159 @@ QFont QgsDecorationGrid::scaledFontPixelSize( const QFont& font ) const
return scaledFont;
}

void QgsDecorationGrid::checkMapUnitsChanged()
{
// disable grid if units changed and grid is enabled, and update the canvas
// this is to avoid problems when CRS changes to/from geographic and projected
// a better solution would be to change the grid interval, but this is a little tricky
// note: we could be less picky (e.g. from degrees to DMS)
QGis::UnitType mapUnits = QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits();
if ( mEnabled && ( mMapUnits != mapUnits ) )
{
mEnabled = false;
mMapUnits = QGis::UnknownUnit; // make sure isDirty() returns true
if ( ! QgisApp::instance()->mapCanvas()->isFrozen() )
{
update();
}
}
}

bool QgsDecorationGrid::isDirty()
{
// checks if stored map units is undefined or different from canvas map units
// or if interval is 0
if ( mMapUnits == QGis::UnknownUnit ||
mMapUnits != QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits() ||
mGridIntervalX == 0 || mGridIntervalY == 0 )
return true;
return false;
}

void QgsDecorationGrid::setDirty( bool dirty )
{
if ( dirty )
{
mMapUnits = QGis::UnknownUnit;
}
else
{
mMapUnits = QgisApp::instance()->mapCanvas()->mapRenderer()->mapUnits();
}
}

bool QgsDecorationGrid::getIntervalFromExtent( double* values, bool useXAxis )
{
// get default interval from current extents
// calculate a default interval that is approx (extent width)/5 , adjusted so that it is a rounded number
// e.g. 12.7 -> 10 66556 -> 70000
double interval = 0;
QgsRectangle extent = QgisApp::instance()->mapCanvas()->extent();
if ( useXAxis )
interval = ( extent.xMaximum() - extent.xMinimum() ) / 5;
else
interval = ( extent.yMaximum() - extent.yMinimum() ) / 5;
QgsDebugMsg( QString( "interval: %1" ).arg( interval ) );
if ( interval != 0 )
{
double interval2 = 0;
int factor = pow( 10, floor( log10( interval ) ) );
if ( factor != 0 )
{
interval2 = round( interval / factor ) * factor;
QgsDebugMsg( QString( "interval2: %1" ).arg( interval2 ) );
if ( interval2 != 0 )
interval = interval2;
}
}
values[0] = values[1] = interval;
values[2] = values[3] = 0;
return true;
}

bool QgsDecorationGrid::getIntervalFromCurrentLayer( double* values )
{
// get current layer and make sure it is a raster layer and CRSs match
QgsMapLayer* layer = QgisApp::instance()->mapCanvas()->currentLayer();
if ( ! layer )
{
QMessageBox::warning( 0, tr( "Error" ), tr( "No active layer" ) );
return false;
}
if ( layer->type() != QgsMapLayer::RasterLayer )
{
QMessageBox::warning( 0, tr( "Error" ), tr( "Please select a raster layer" ) );
return false;
}
QgsRasterLayer* rlayer = dynamic_cast<QgsRasterLayer*>( layer );
if ( !rlayer )
{
QMessageBox::warning( 0, tr( "Error" ), tr( "Invalid raster layer" ) );
return false;
}
const QgsCoordinateReferenceSystem& layerCRS = layer->crs();
const QgsCoordinateReferenceSystem& mapCRS =
QgisApp::instance()->mapCanvas()->mapRenderer()->destinationCrs();
// is this the best way to compare CRS? should we also make sure map has OTF enabled?
// TODO calculate transformed values if necessary
if ( layerCRS != mapCRS )
{
QMessageBox::warning( 0, tr( "Error" ), tr( "Layer CRS must be equal to project CRS" ) );
return false;
}

// TODO add a function in QgsRasterLayer to get x/y resolution from provider
QgsRectangle extent = rlayer->extent();
values[0] = fabs( extent.xMaximum() - extent.xMinimum() ) / rlayer->width();
values[1] = fabs( extent.yMaximum() - extent.yMinimum() ) / rlayer->height();
// TODO calculate offset - this is a little tricky...
values[2] = values[3] = 0;

QgsDebugMsg( QString( "xmax: %1 xmin: %2 width: %3 xInterval: %4" ).arg( extent.xMaximum() ).arg( extent.xMinimum() ).arg( rlayer->width() ).arg( values[0] ) );

return true;
}


// TODO preliminary code to calculate offset
// double diff = getClosestPixel( extent.xMaximum(), boundBox2.xMinimum(), boundBox.xMinimum(), dx, True )

// // function ported from ftools doVectorGrid.py
// double getClosestPixel( double startVal, double targetVal, double step, bool isMin )
// {
// bool foundVal = false;
// double tmpVal = startVal;
// bool backOneStep;
// // find pixels covering the extent - slightly inneficient b/c loop on all elements before xMin
// if ( targetVal < startVal )
// {
// backOneStep = ! isMin;
// step = - step;
// // should make sure we don't go into an infinite loop (shouldn't happen)
// while ( ! foundVal )
// {
// if ( tmpVal <= targetVal )
// {
// if ( backOneStep )
// tmpVal -= step;
// return tmpVal;
// }
// tmpVal += step;
// }
// }
// else
// {
// backOneStep = isMin;
// while ( ! foundVal )
// {
// if ( tmpVal >= targetVal )
// {
// if ( backOneStep )
// tmpVal -= step;
// return tmpVal;
// }
// tmpVal += step;
// }
// }
// return 0;
// }
@@ -19,6 +19,7 @@
#define QGSDECORATIONGRID_H

#include "qgsdecorationitem.h"
#include <qgis.h>

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

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

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

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

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

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

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

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

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

/**Sets map unit type */
void setMapUnits( QGis::UnitType t ) { mMapUnits = t; }
QGis::UnitType mapUnits() { return mMapUnits; }

/**Set mapUnits value */
void setDirty( bool dirty = true );
bool isDirty();

/**Computes interval that is approx. 1/5 of canvas extent */
bool getIntervalFromExtent( double* values, bool useXAxis = true );
/**Computes interval from current raster layer */
bool getIntervalFromCurrentLayer( double* values );

double getDefaultInterval( bool useXAxis = true );

public slots:
//! set values on the gui when a project is read or the gui first loaded
void projectRead();
@@ -141,6 +150,9 @@ class QgsDecorationGrid: public QgsDecorationItem
//! Show the dialog box
void run();

//! check that map units changed and disable if necessary
void checkMapUnitsChanged();

private:

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

QGis::UnitType mMapUnits;

/**Draw coordinates for mGridAnnotationType Coordinate
@param p drawing painter
@param hLines horizontal coordinate lines in item coordinates

0 comments on commit 02beea3

Please sign in to comment.
You can’t perform that action at this time.