Skip to content

Commit

Permalink
Allow to delete ring by clicking inside the ring
Browse files Browse the repository at this point in the history
  • Loading branch information
leyan committed Apr 30, 2014
1 parent 717ef84 commit 6b0796e
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 49 deletions.
19 changes: 8 additions & 11 deletions src/app/qgsmaptooldeletepart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <QMessageBox>

QgsMapToolDeletePart::QgsMapToolDeletePart( QgsMapCanvas* canvas )
: QgsMapToolEdit( canvas ), mCross( 0 )
: QgsMapToolEdit( canvas )
{
}

Expand Down Expand Up @@ -88,10 +88,10 @@ void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
g = f.geometry();
if ( !g )
return;
if ( ( g->type() == QGis::Point && g->asMultiPoint().size() == 1) ||
( g->type() == QGis::Line && g->asMultiPolyline().size() == 1 ) )
if ( g->wkbType() == QGis::WKBPoint25D || g->wkbType() == QGis::WKBPoint ||
g->wkbType() == QGis::WKBLineString25D || g->wkbType() == QGis::WKBLineString)
{
notifySinglePart();
emit messageEmitted( tr( "The Delete part tool cannot be used on single part features." ) );
return;
}
int vertex = sr.snappedVertexNr;
Expand All @@ -110,9 +110,10 @@ void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
g = f.geometry();
if ( !g )
return;
if ( g->asMultiPolygon().size() == 1 )

if ( g->wkbType() == QGis::WKBPolygon25D || g->wkbType() == QGis::WKBPolygon)
{
notifySinglePart();
emit messageEmitted( tr( "The Delete part tool cannot be used on single part features." ) );
return;
}
partNum = partNumberOfPoint( g, p );
Expand All @@ -135,11 +136,7 @@ void QgsMapToolDeletePart::canvasReleaseEvent( QMouseEvent *e )
}
else
{
QgisApp::instance()->messageBar()->pushMessage(
tr( "Delete part" ),
tr( "Couldn't remove the selected part." ),
QgsMessageBar::WARNING,
QgisApp::instance()->messageTimeout() );
emit messageEmitted( tr( "Couldn't remove the selected part." ) );
}
return;
}
Expand Down
131 changes: 94 additions & 37 deletions src/app/qgsmaptooldeletering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@
#include "qgsmapcanvas.h"
#include "qgsvertexmarker.h"
#include "qgsvectorlayer.h"
#include "qgsmessagebar.h"
#include "qgisapp.h"

#include <QMouseEvent>
#include <QMessageBox>

QgsMapToolDeleteRing::QgsMapToolDeleteRing( QgsMapCanvas* canvas )
: QgsMapToolVertexEdit( canvas )
, mCross( 0 )
{
mToolName = tr( "Delete ring" );
}

QgsMapToolDeleteRing::~QgsMapToolDeleteRing()
{
delete mCross;
}

void QgsMapToolDeleteRing::canvasMoveEvent( QMouseEvent *e )
Expand All @@ -42,62 +42,110 @@ void QgsMapToolDeleteRing::canvasMoveEvent( QMouseEvent *e )

void QgsMapToolDeleteRing::canvasPressEvent( QMouseEvent *e )
{
delete mCross;
mCross = 0;

mRecentSnappingResults.clear();
//do snap -> new recent snapping results
if ( mSnapper.snapToCurrentLayer( e->pos(), mRecentSnappingResults, QgsSnapper::SnapToVertexAndSegment ) != 0 )
{
//error
}

if ( mRecentSnappingResults.size() > 0 )
{
// remove previous warning
emit messageDiscarded();

QgsPoint markerPoint = mRecentSnappingResults.begin()->snappedVertex;

//show vertex marker
mCross = new QgsVertexMarker( mCanvas );
mCross->setIconType( QgsVertexMarker::ICON_X );
mCross->setCenter( markerPoint );
}
else
{
emit messageEmitted( tr( "could not snap to a ring on the current layer." ) );
}
}

void QgsMapToolDeleteRing::canvasReleaseEvent( QMouseEvent *e )
{
Q_UNUSED( e );
delete mCross;
mCross = 0;

QgsMapLayer* currentLayer = mCanvas->currentLayer();
if ( !currentLayer )
return;

QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
vlayer = qobject_cast<QgsVectorLayer *>( currentLayer );
if ( !vlayer )
{
notifyNotVectorLayer();
return;
}

if ( vlayer->geometryType() != QGis::Polygon )
{
emit messageEmitted( tr( "Delete ring can only be used in a polygon layer." ) );
return;
}

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

QgsPoint p = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(),e->y());
p = toLayerCoordinates(vlayer, p);

if ( mRecentSnappingResults.size() > 0 )
//There is no easy way to find if we are inside the ring of a feature,
//so we iterate over all the features visible in the canvas
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( mCanvas->extent() ) );
QgsFeature f;
QgsGeometry* g;
QgsMultiPolygon pol;
QgsPolygon tempPol;
QgsGeometry* tempGeom;
int fid, partNum, ringNum;
double area = std::numeric_limits<double>::max();
while ( fit.nextFeature( f ) )
{
QList<QgsSnappingResult>::iterator sr_it = mRecentSnappingResults.begin();
for ( ; sr_it != mRecentSnappingResults.end(); ++sr_it )
QgsDebugMsg(QString("Feature %1").arg(f.id()));
g = f.geometry();
if ( !g )
continue;
if ( g->wkbType() == QGis::WKBPolygon || g->wkbType() == QGis::WKBPolygon25D )
{
pol = QgsMultiPolygon() << g->asPolygon();
}
else
{
if ( sr_it->snappedVertexNr != -1 )
deleteRing( sr_it->snappedAtGeometry, sr_it->snappedVertexNr, vlayer );
else if ( sr_it->beforeVertexNr != -1 )
deleteRing( sr_it->snappedAtGeometry, sr_it->beforeVertexNr, vlayer );
else if ( sr_it->afterVertexNr != -1 )
deleteRing( sr_it->snappedAtGeometry, sr_it->afterVertexNr, vlayer );
pol = g->asMultiPolygon();
}

for (int i = 0; i < pol.size() ; ++i)
{//for each part
QgsDebugMsg(QString("Feature %1 part %2").arg(f.id()).arg(i));
if ( pol[i].size() > 1 )
{
QgsDebugMsg(QString("%1 has a ring in part %2").arg(f.id()).arg(i));
for ( int j = 1; j<pol[i].size();++j)
{
tempPol = QgsPolygon()<<pol[i][j];
tempGeom = QgsGeometry::fromPolygon( tempPol );
if (tempGeom->area() < area && tempGeom->contains(&p) )
{
QgsDebugMsg(QString("%1, part %2, ring %3 contains the cursor").arg(f.id()).arg(i).arg(j));
fid=f.id();
partNum=i;
ringNum=j;
area=tempGeom->area();
}
}
}
}
}

vlayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( f );

g = f.geometry();
if ( g->deleteRing( ringNum, partNum ) )
{
vlayer->beginEditCommand( tr( "Ring deleted" ) );
vlayer->changeGeometry( fid, g );
vlayer->endEditCommand();
mCanvas->refresh();
}
/*
if ( g->deleteRing( ringNum, partNum ) )
{
vlayer->beginEditCommand( tr( "Ring deleted" ) );
vlayer->changeGeometry( f.id(), g );
vlayer->endEditCommand();
mCanvas->refresh();
}
*/
}

void QgsMapToolDeleteRing::deleteRing( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer )
Expand Down Expand Up @@ -130,6 +178,17 @@ void QgsMapToolDeleteRing::deleteRing( QgsFeatureId fId, int beforeVertexNr, Qgs

}

int QgsMapToolDeleteRing::partNumberOfPoint(QgsGeometry* g, QgsPoint p)
{
return 0;
}

int QgsMapToolDeleteRing::ringNumberOfPoint(QgsGeometry* g, QgsPoint p, int partNum)
{
return 0;
}


int QgsMapToolDeleteRing::ringNumInPolygon( QgsGeometry* g, int vertexNr )
{
QgsPolygon polygon = g->asPolygon();
Expand Down Expand Up @@ -166,8 +225,6 @@ int QgsMapToolDeleteRing::ringNumInMultiPolygon( QgsGeometry* g, int vertexNr, i

void QgsMapToolDeleteRing::deactivate()
{
delete mCross;
mCross = 0;

QgsMapTool::deactivate();
}
6 changes: 5 additions & 1 deletion src/app/qgsmaptooldeletering.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class APP_EXPORT QgsMapToolDeleteRing : public QgsMapToolVertexEdit
void deactivate();

private:
QgsVertexMarker* mCross;
QgsVectorLayer* vlayer;

//! delete inner ring from the geometry
void deleteRing( QgsFeatureId fId, int beforeVertexNr, QgsVectorLayer* vlayer );
Expand All @@ -49,6 +49,10 @@ class APP_EXPORT QgsMapToolDeleteRing : public QgsMapToolVertexEdit

//! return ring number in multipolygon and set parNum to index of the part
int ringNumInMultiPolygon( QgsGeometry* g, int vertexNr, int& partNum );

int partNumberOfPoint(QgsGeometry* g, QgsPoint point );
int ringNumberOfPoint(QgsGeometry* g, QgsPoint point, int part );

};

#endif

0 comments on commit 6b0796e

Please sign in to comment.