Skip to content

Commit

Permalink
Merge pull request #1030 from alexbruy/fill-ring
Browse files Browse the repository at this point in the history
[FEATURE] fill ring digitinzing tool
  • Loading branch information
3nids committed Dec 17, 2013
2 parents ba9936e + dbb48f2 commit 052b2eb
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 2 deletions.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -132,6 +132,7 @@
<file>themes/default/mActionAddPart.png</file>
<file>themes/default/mActionAddRasterLayer.svg</file>
<file>themes/default/mActionAddRing.png</file>
<file>themes/default/mActionFillRing.png</file>
<file>themes/default/mActionAddSpatiaLiteLayer.svg</file>
<file>themes/default/mActionAddVertex.png</file>
<file>themes/default/mActionAddWcsLayer.svg</file>
Expand Down
Binary file added images/themes/default/mActionFillRing.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -49,6 +49,7 @@ SET(QGIS_APP_SRCS
qgsmaptooladdfeature.cpp
qgsmaptooladdpart.cpp
qgsmaptooladdring.cpp
qgsmaptoolfillring.cpp
qgsmaptoolannotation.cpp
qgsmaptoolcapture.cpp
qgsmaptoolchangelabelproperties.cpp
Expand Down Expand Up @@ -210,6 +211,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmaptoolcapture.h
qgsmaptooladdpart.h
qgsmaptooladdring.h
qgsmaptoolfillring.h
qgsmaptoolchangelabelproperties.h
qgsmaptooldeletepart.h
qgsmaptooldeletering.h
Expand Down
22 changes: 22 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -225,6 +225,7 @@
#include "qgsmaptooladdfeature.h"
#include "qgsmaptooladdpart.h"
#include "qgsmaptooladdring.h"
#include "qgsmaptoolfillring.h"
#include "qgsmaptoolannotation.h"
#include "qgsmaptooldeletering.h"
#include "qgsmaptooldeletepart.h"
Expand Down Expand Up @@ -793,6 +794,7 @@ QgisApp::~QgisApp()
delete mMapTools.mAddFeature;
delete mMapTools.mAddPart;
delete mMapTools.mAddRing;
delete mMapTools.mFillRing;
delete mMapTools.mAnnotation;
delete mMapTools.mChangeLabelProperties;
delete mMapTools.mDeletePart;
Expand Down Expand Up @@ -982,6 +984,7 @@ void QgisApp::createActions()
connect( mActionSplitParts, SIGNAL( triggered() ), this, SLOT( splitParts() ) );
connect( mActionDeleteSelected, SIGNAL( triggered() ), this, SLOT( deleteSelected() ) );
connect( mActionAddRing, SIGNAL( triggered() ), this, SLOT( addRing() ) );
connect( mActionFillRing, SIGNAL( triggered() ), this, SLOT( fillRing() ) );
connect( mActionAddPart, SIGNAL( triggered() ), this, SLOT( addPart() ) );
connect( mActionSimplifyFeature, SIGNAL( triggered() ), this, SLOT( simplifyFeature() ) );
connect( mActionDeleteRing, SIGNAL( triggered() ), this, SLOT( deleteRing() ) );
Expand Down Expand Up @@ -1253,6 +1256,7 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionSplitParts );
mMapToolGroup->addAction( mActionDeleteSelected );
mMapToolGroup->addAction( mActionAddRing );
mMapToolGroup->addAction( mActionFillRing );
mMapToolGroup->addAction( mActionAddPart );
mMapToolGroup->addAction( mActionSimplifyFeature );
mMapToolGroup->addAction( mActionDeleteRing );
Expand Down Expand Up @@ -1799,6 +1803,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionUndo->setIcon( QgsApplication::getThemeIcon( "/mActionUndo.png" ) );
mActionRedo->setIcon( QgsApplication::getThemeIcon( "/mActionRedo.png" ) );
mActionAddRing->setIcon( QgsApplication::getThemeIcon( "/mActionAddRing.png" ) );
mActionFillRing->setIcon( QgsApplication::getThemeIcon( "/mActionFillRing.png" ) );
mActionAddPart->setIcon( QgsApplication::getThemeIcon( "/mActionAddPart.png" ) );
mActionDeleteRing->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteRing.png" ) );
mActionDeletePart->setIcon( QgsApplication::getThemeIcon( "/mActionDeletePart.png" ) );
Expand Down Expand Up @@ -2030,6 +2035,8 @@ void QgisApp::createCanvasTools()
mMapTools.mSelectRadius->setAction( mActionSelectRadius );
mMapTools.mAddRing = new QgsMapToolAddRing( mMapCanvas );
mMapTools.mAddRing->setAction( mActionAddRing );
mMapTools.mFillRing = new QgsMapToolFillRing( mMapCanvas );
mMapTools.mFillRing->setAction( mActionFillRing );
mMapTools.mAddPart = new QgsMapToolAddPart( mMapCanvas );
mMapTools.mSimplifyFeature = new QgsMapToolSimplify( mMapCanvas );
mMapTools.mSimplifyFeature->setAction( mActionSimplifyFeature );
Expand Down Expand Up @@ -5573,6 +5580,16 @@ void QgisApp::addRing()
mMapCanvas->setMapTool( mMapTools.mAddRing );
}

void QgisApp::fillRing()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
mMapCanvas->setMapTool( mMapTools.mFillRing );
}


void QgisApp::addPart()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
Expand Down Expand Up @@ -8382,6 +8399,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionRedo->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
mActionAddPart->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionDeletePart->setEnabled( false );
Expand Down Expand Up @@ -8514,6 +8532,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( "/mActionCapturePoint.png" ) );

mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSplitParts->setEnabled( false );
Expand Down Expand Up @@ -8541,13 +8560,15 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes );

mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
mActionDeleteRing->setEnabled( false );
}
else if ( vlayer->geometryType() == QGis::Polygon )
{
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( "/mActionCapturePolygon.png" ) );

mActionAddRing->setEnabled( isEditable && canAddFeatures );
mActionFillRing->setEnabled( isEditable && canAddFeatures );
mActionReshapeFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitParts->setEnabled( isEditable && canAddFeatures );
Expand Down Expand Up @@ -8621,6 +8642,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddFeature->setEnabled( false );
mActionDeleteSelected->setEnabled( false );
mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
mActionAddPart->setEnabled( false );
mActionNodeTool->setEnabled( false );
mActionMoveFeature->setEnabled( false );
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -272,6 +272,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionSplitFeatures() { return mActionSplitFeatures; }
QAction *actionSplitParts() { return mActionSplitParts; }
QAction *actionAddRing() { return mActionAddRing; }
QAction *actionFillRing() { return mActionFillRing; }
QAction *actionAddPart() { return mActionAddPart; }
QAction *actionSimplifyFeature() { return mActionSimplifyFeature; }
QAction *actionDeleteRing() { return mActionDeleteRing; }
Expand Down Expand Up @@ -937,6 +938,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void splitParts();
//! activates the add ring tool
void addRing();
//! activates the fill ring tool
void fillRing();
//! activates the add part tool
void addPart();
//! simplifies feature
Expand Down Expand Up @@ -1358,6 +1361,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMapTool* mVertexMove;
QgsMapTool* mVertexDelete;
QgsMapTool* mAddRing;
QgsMapTool* mFillRing;
QgsMapTool* mAddPart;
QgsMapTool* mSimplifyFeature;
QgsMapTool* mDeleteRing;
Expand Down
190 changes: 190 additions & 0 deletions src/app/qgsmaptoolfillring.cpp
@@ -0,0 +1,190 @@
/***************************************************************************
qgsmaptoolfillring.h - map tool to cut rings in polygon and multipolygon
features and fill them with new feature
---------------------
begin : December 2013
copyright : (C) 2013 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsmaptoolfillring.h"
#include "qgsgeometry.h"
#include "qgsmapcanvas.h"
#include "qgsvectorlayer.h"
#include "qgsattributedialog.h"
#include <qgsapplication.h>

#include <QMessageBox>
#include <QMouseEvent>

#include <limits>

QgsMapToolFillRing::QgsMapToolFillRing( QgsMapCanvas* canvas ): QgsMapToolCapture( canvas, QgsMapToolCapture::CapturePolygon )
{

}

QgsMapToolFillRing::~QgsMapToolFillRing()
{

}

void QgsMapToolFillRing::canvasReleaseEvent( QMouseEvent * e )
{
//check if we operate on a vector layer
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );

if ( !vlayer )
{
notifyNotVectorLayer();
return;
}

if ( !vlayer->isEditable() )
{
notifyNotEditableLayer();
return;
}

//add point to list and to rubber band
if ( e->button() == Qt::LeftButton )
{
int error = addVertex( e->pos() );
if ( error == 1 )
{
//current layer is not a vector layer
return;
}
else if ( error == 2 )
{
//problem with coordinate transformation
QMessageBox::information( 0, tr( "Coordinate transform error" ),
tr( "Cannot transform the point to the layers coordinate system" ) );
return;
}

startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
deleteTempRubberBand();

closePolygon();

vlayer->beginEditCommand( tr( "Ring added and filled" ) );
int addRingReturnCode = vlayer->addRing( points() );
if ( addRingReturnCode != 0 )
{
QString errorMessage;
//todo: open message box to communicate errors
if ( addRingReturnCode == 1 )
{
errorMessage = tr( "A problem with geometry type occured" );
}
else if ( addRingReturnCode == 2 )
{
errorMessage = tr( "The inserted Ring is not closed" );
}
else if ( addRingReturnCode == 3 )
{
errorMessage = tr( "The inserted Ring is not a valid geometry" );
}
else if ( addRingReturnCode == 4 )
{
errorMessage = tr( "The inserted Ring crosses existing rings" );
}
else if ( addRingReturnCode == 5 )
{
errorMessage = tr( "The inserted Ring is not contained in a feature" );
}
else
{
errorMessage = tr( "An unknown error occured" );
}
QMessageBox::critical( 0, tr( "Error, could not add ring" ), errorMessage );
vlayer->destroyEditCommand();
}
else
{
// find parent feature and get it attributes
double xMin, xMax, yMin, yMax;
QgsRectangle bBox;

xMin = std::numeric_limits<double>::max();
xMax = -std::numeric_limits<double>::max();
yMin = std::numeric_limits<double>::max();
yMax = -std::numeric_limits<double>::max();

for ( QList<QgsPoint>::const_iterator it = points().constBegin(); it != points().constEnd(); ++it )
{
if ( it->x() < xMin )
{
xMin = it->x();
}
if ( it->x() > xMax )
{
xMax = it->x();
}
if ( it->y() < yMin )
{
yMin = it->y();
}
if ( it->y() > yMax )
{
yMax = it->y();
}
}
bBox.setXMinimum( xMin );
bBox.setYMinimum( yMin );
bBox.setXMaximum( xMax );
bBox.setYMaximum( yMax );

QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );

QgsFeature f;
bool res = false;
while ( fit.nextFeature( f ) )
{
//create QgsFeature with wkb representation
QgsFeature* ft = new QgsFeature( vlayer->pendingFields(), 0 );

QgsGeometry *g;
g = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() );
ft->setGeometry( g );
ft->setAttributes( f.attributes() );

if ( QgsApplication::keyboardModifiers() == Qt::ControlModifier )
{
res = vlayer->addFeature( *ft );
}
else
{
QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true );
if ( dialog->exec() )
{
res = vlayer->addFeature( *ft );
}
}

if ( res )
{
vlayer->endEditCommand();
}
else
{
delete ft;
vlayer->destroyEditCommand();
}
res = false;
}
}
stopCapturing();
}
}
29 changes: 29 additions & 0 deletions src/app/qgsmaptoolfillring.h
@@ -0,0 +1,29 @@
/***************************************************************************
qgsmaptoolfillring.h - map tool to cut rings in polygon and multipolygon
features and fill them with new feature
---------------------
begin : December 2013
copyright : (C) 2013 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsmaptoolcapture.h"

/** A tool to cut holes into polygon and multipolygon features and fill them
* with new feature. Attributes are copied from parent feature.
* */
class APP_EXPORT QgsMapToolFillRing: public QgsMapToolCapture
{
Q_OBJECT
public:
QgsMapToolFillRing( QgsMapCanvas* canvas );
virtual ~QgsMapToolFillRing();
void canvasReleaseEvent( QMouseEvent * e );
};

0 comments on commit 052b2eb

Please sign in to comment.