Skip to content

Commit

Permalink
Add QgsSnapToGridCanvasItem
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Aug 26, 2018
1 parent fff743b commit 1e81e03
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 0 deletions.
91 changes: 91 additions & 0 deletions python/gui/auto_generated/qgssnaptogridcanvasitem.sip.in
@@ -0,0 +1,91 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssnaptogridcanvasitem.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsSnapToGridCanvasItem : QObject, QgsMapCanvasItem
{
%Docstring

Shows a grid on the map canvas given a spatial resolution.

.. versionadded:: 3.4
%End

%TypeHeaderCode
#include "qgssnaptogridcanvasitem.h"
%End
public:

QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas );
%Docstring
Will automatically be added to the ``mapCanvas``.
%End

virtual void paint( QPainter *painter );


QgsPointXY point() const;
%Docstring
A point that will be highlighted on the map canvas.
The point needs to be in map coordinates. The closest point on the
grid will be highlighted.
%End

void setPoint( const QgsPointXY &point );
%Docstring
A point that will be highlighted on the map canvas.
The point needs to be in map coordinates. The closest point on the
grid will be highlighted.
%End

double precision() const;
%Docstring
The resolution of the grid in map units.
If a crs has been specified it will be in CRS units.
%End

void setPrecision( double precision );
%Docstring
The resolution of the grid in map units.
If a crs has been specified it will be in CRS units.
%End

QgsCoordinateReferenceSystem crs() const;
%Docstring
The CRS in which the grid should be calculated.
By default will be an invalid QgsCoordinateReferenceSystem and
as such equal to the CRS of the map canvas.
%End

void setCrs( const QgsCoordinateReferenceSystem &crs );
%Docstring
The CRS in which the grid should be calculated.
By default will be an invalid QgsCoordinateReferenceSystem and
as such equal to the CRS of the map canvas.
%End

bool enabled() const;
%Docstring
Enable this item. It will be hidden if disabled.
%End

void setEnabled( bool enabled );
%Docstring
Enable this item. It will be hidden if disabled.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgssnaptogridcanvasitem.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Expand Up @@ -192,6 +192,7 @@
%Include auto_generated/qgssearchquerybuilder.sip
%Include auto_generated/qgsshortcutsmanager.sip
%Include auto_generated/qgsslider.sip
%Include auto_generated/qgssnaptogridcanvasitem.sip
%Include auto_generated/qgsstatusbar.sip
%Include auto_generated/qgssublayersdialog.sip
%Include auto_generated/qgssubstitutionlistwidget.sip
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -355,6 +355,7 @@ SET(QGIS_GUI_SRCS
qgsshortcutsmanager.cpp
qgsslider.cpp
qgssnapindicator.cpp
qgssnaptogridcanvasitem.cpp
qgssublayersdialog.cpp
qgssubstitutionlistwidget.cpp
qgssqlcomposerdialog.cpp
Expand Down Expand Up @@ -524,6 +525,7 @@ SET(QGIS_GUI_MOC_HDRS
qgssearchquerybuilder.h
qgsshortcutsmanager.h
qgsslider.h
qgssnaptogridcanvasitem.h
qgssqlcomposerdialog.h
qgsstatusbar.h
qgssublayersdialog.h
Expand Down
142 changes: 142 additions & 0 deletions src/gui/qgssnaptogridcanvasitem.cpp
@@ -0,0 +1,142 @@
#include "qgssnaptogridcanvasitem.h"
#include "qgsmapcanvas.h"

QgsSnapToGridCanvasItem::QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas )
: QgsMapCanvasItem( mapCanvas )
, mGridPen( QPen( QColor( 127, 127, 127, 150 ), 1 ) )
, mCurrentPointPen( QPen( QColor( 200, 200, 200, 150 ), 3 ) )
{
updateMapCanvasCrs();
connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsSnapToGridCanvasItem::updateZoomFactor );
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsSnapToGridCanvasItem::updateMapCanvasCrs );
}

void QgsSnapToGridCanvasItem::paint( QPainter *painter )
{
painter->save();
QgsRectangle mapRect = mMapCanvas->extent();
if ( rect() != mapRect )
setRect( mapRect );

painter->setRenderHints( QPainter::Antialiasing );
painter->setCompositionMode( QPainter::CompositionMode_Difference );

if ( mEnabled && mAvailableByZoomFactor )
{
const QgsRectangle layerExtent = mTransform.transformBoundingBox( mapRect, QgsCoordinateTransform::ReverseTransform );
const QgsPointXY layerPt = mTransform.transform( mPoint, QgsCoordinateTransform::ReverseTransform );

const double gridXMin = std::ceil( layerExtent.xMinimum() / mPrecision ) * mPrecision;
const double gridXMax = std::ceil( layerExtent.xMaximum() / mPrecision ) * mPrecision;
const double gridYMin = std::ceil( layerExtent.yMinimum() / mPrecision ) * mPrecision;
const double gridYMax = std::ceil( layerExtent.yMaximum() / mPrecision ) * mPrecision;

for ( int x = gridXMin ; x < gridXMax; x += mPrecision )
{
for ( int y = gridYMin ; y < gridYMax; y += mPrecision )
{
const QgsPointXY pt = mTransform.transform( x, y );
const QPointF canvasPt = toCanvasCoordinates( pt );

if ( qgsDoubleNear( layerPt.x(), x, mPrecision / 3 ) && qgsDoubleNear( layerPt.y(), y, mPrecision / 3 ) )
{
painter->setPen( mCurrentPointPen );
}
else
{
painter->setPen( mGridPen );
}
painter->drawLine( canvasPt.x() - 3, canvasPt.y(), canvasPt.x() + 3, canvasPt.y() );
painter->drawLine( canvasPt.x(), canvasPt.y() - 3, canvasPt.x(), canvasPt.y() + 3 );
}
}
}

painter->restore();
}

QgsPointXY QgsSnapToGridCanvasItem::point() const
{
return mPoint;
}

void QgsSnapToGridCanvasItem::setPoint( const QgsPointXY &point )
{
mPoint = point;
update();
}

double QgsSnapToGridCanvasItem::precision() const
{
return mPrecision;
}

void QgsSnapToGridCanvasItem::setPrecision( double precision )
{
mPrecision = precision;
updateZoomFactor();
}

QgsCoordinateReferenceSystem QgsSnapToGridCanvasItem::crs() const
{
return mTransform.sourceCrs();
}

void QgsSnapToGridCanvasItem::setCrs( const QgsCoordinateReferenceSystem &crs )
{
mTransform.setSourceCrs( crs );
updateZoomFactor();
}

bool QgsSnapToGridCanvasItem::enabled() const
{
return mEnabled;
}

void QgsSnapToGridCanvasItem::setEnabled( bool enabled )
{
mEnabled = enabled;
update();
}

void QgsSnapToGridCanvasItem::updateMapCanvasCrs()
{
mTransform.setContext( mMapCanvas->mapSettings().transformContext() );
mTransform.setDestinationCrs( mMapCanvas->mapSettings().destinationCrs() );
update();
}



void QgsSnapToGridCanvasItem::updateZoomFactor()
{
if ( !isVisible() )
return;

try
{
const int threshold = 5;

const QgsPointXY centerPoint = mMapCanvas->extent().center();
const QPointF canvasCenter = toCanvasCoordinates( centerPoint );

const QgsPointXY pt1 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() - threshold, canvasCenter.y() - threshold );
const QgsPointXY pt2 = mMapCanvas->mapSettings().mapToPixel().toMapCoordinates( canvasCenter.x() + threshold, canvasCenter.y() + threshold );

const QgsPointXY layerPt1 = mTransform.transform( pt1, QgsCoordinateTransform::ReverseTransform );
const QgsPointXY layerPt2 = mTransform.transform( pt2, QgsCoordinateTransform::ReverseTransform );

const double dist = layerPt1.distance( layerPt2 );

if ( dist < mPrecision )
mAvailableByZoomFactor = true;
else
mAvailableByZoomFactor = false;
}
catch ( QgsCsException &e )
{
// transform errors?
// you've probably got worse problems than the grid with your digitizing operations in the current projection.
mAvailableByZoomFactor = false;
}
}
98 changes: 98 additions & 0 deletions src/gui/qgssnaptogridcanvasitem.h
@@ -0,0 +1,98 @@
#ifndef QGSSNAPTOGRIDCANVASITEM_H
#define QGSSNAPTOGRIDCANVASITEM_H

#include <QObject>
#include <QPen>

#include "qgscoordinatereferencesystem.h"
#include "qgsmapcanvasitem.h"
#include "qgscoordinatetransform.h"

/**
* \ingroup gui
*
* Shows a grid on the map canvas given a spatial resolution.
*
* \since QGIS 3.4
*/
class GUI_EXPORT QgsSnapToGridCanvasItem : public QObject, public QgsMapCanvasItem
{
Q_OBJECT

public:

/**
* Will automatically be added to the \a mapCanvas.
*/
QgsSnapToGridCanvasItem( QgsMapCanvas *mapCanvas );

void paint( QPainter *painter ) override;

/**
* A point that will be highlighted on the map canvas.
* The point needs to be in map coordinates. The closest point on the
* grid will be highlighted.
*/
QgsPointXY point() const;

/**
* A point that will be highlighted on the map canvas.
* The point needs to be in map coordinates. The closest point on the
* grid will be highlighted.
*/
void setPoint( const QgsPointXY &point );

/**
* The resolution of the grid in map units.
* If a crs has been specified it will be in CRS units.
*/
double precision() const;

/**
* The resolution of the grid in map units.
* If a crs has been specified it will be in CRS units.
*/
void setPrecision( double precision );

/**
* The CRS in which the grid should be calculated.
* By default will be an invalid QgsCoordinateReferenceSystem and
* as such equal to the CRS of the map canvas.
*/
QgsCoordinateReferenceSystem crs() const;

/**
* The CRS in which the grid should be calculated.
* By default will be an invalid QgsCoordinateReferenceSystem and
* as such equal to the CRS of the map canvas.
*/
void setCrs( const QgsCoordinateReferenceSystem &crs );

/**
* Enable this item. It will be hidden if disabled.
*/
bool enabled() const;

/**
* Enable this item. It will be hidden if disabled.
*/
void setEnabled( bool enabled );

private slots:
void updateMapCanvasCrs();

void updateZoomFactor();

private:
QPen mGridPen;
QPen mCurrentPointPen;

bool mEnabled = true;
bool mAvailableByZoomFactor = false;

double mPrecision = 0.0;
QgsCoordinateTransform mTransform;
QgsPointXY mPoint;
};

#endif // QGSSNAPTOGRIDCANVASITEM_H

0 comments on commit 1e81e03

Please sign in to comment.