790 changes: 790 additions & 0 deletions images/themes/default/mActionSplitParts.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/gui/qgisinterface.sip
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ class QgisInterface : QObject
virtual QAction *actionDeleteSelected() = 0;
virtual QAction *actionMoveFeature() = 0;
virtual QAction *actionSplitFeatures() = 0;
virtual QAction *actionSplitParts() = 0;
virtual QAction *actionAddRing() = 0;
virtual QAction *actionAddPart() = 0;
virtual QAction *actionSimplifyFeature() = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolselectutils.cpp
qgsmaptoolsimplify.cpp
qgsmaptoolsplitfeatures.cpp
qgsmaptoolsplitparts.cpp
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp
qgsmaptoolvertexedit.cpp
Expand Down Expand Up @@ -226,6 +227,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmaptoolselectrectangle.h
qgsmaptoolsimplify.h
qgsmaptoolsplitfeatures.h
qgsmaptoolsplitparts.h
qgsmaptoolvertexedit.h

nodetool/qgsmaptoolnodetool.h
Expand Down
17 changes: 17 additions & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
#include "qgsmaptoolreshape.h"
#include "qgsmaptoolrotatepointsymbols.h"
#include "qgsmaptoolsplitfeatures.h"
#include "qgsmaptoolsplitparts.h"
#include "qgsmaptooltextannotation.h"
#include "qgsmaptoolvertexedit.h"
#include "qgsmaptoolzoom.h"
Expand Down Expand Up @@ -806,6 +807,7 @@ QgisApp::~QgisApp()
delete mMapTools.mShowHideLabels;
delete mMapTools.mSimplifyFeature;
delete mMapTools.mSplitFeatures;
delete mMapTools.mSplitParts;
delete mMapTools.mSvgAnnotation;
delete mMapTools.mTextAnnotation;

Expand Down Expand Up @@ -963,6 +965,7 @@ void QgisApp::createActions()

connect( mActionReshapeFeatures, SIGNAL( triggered() ), this, SLOT( reshapeFeatures() ) );
connect( mActionSplitFeatures, SIGNAL( triggered() ), this, SLOT( splitFeatures() ) );
connect( mActionSplitParts, SIGNAL( triggered() ), this, SLOT( splitParts() ) );
connect( mActionDeleteSelected, SIGNAL( triggered() ), this, SLOT( deleteSelected() ) );
connect( mActionAddRing, SIGNAL( triggered() ), this, SLOT( addRing() ) );
connect( mActionAddPart, SIGNAL( triggered() ), this, SLOT( addPart() ) );
Expand Down Expand Up @@ -1233,6 +1236,7 @@ void QgisApp::createActionGroups()
#endif
mMapToolGroup->addAction( mActionReshapeFeatures );
mMapToolGroup->addAction( mActionSplitFeatures );
mMapToolGroup->addAction( mActionSplitParts );
mMapToolGroup->addAction( mActionDeleteSelected );
mMapToolGroup->addAction( mActionAddRing );
mMapToolGroup->addAction( mActionAddPart );
Expand Down Expand Up @@ -1774,6 +1778,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionRotateFeature->setIcon( QgsApplication::getThemeIcon( "/mActionRotateFeature.png" ) );
mActionReshapeFeatures->setIcon( QgsApplication::getThemeIcon( "/mActionReshape.png" ) );
mActionSplitFeatures->setIcon( QgsApplication::getThemeIcon( "/mActionSplitFeatures.svg" ) );
mActionSplitParts->setIcon( QgsApplication::getThemeIcon( "/mActionSplitParts.svg" ) );
mActionDeleteSelected->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteSelected.svg" ) );
mActionNodeTool->setIcon( QgsApplication::getThemeIcon( "/mActionNodeTool.png" ) );
mActionSimplifyFeature->setIcon( QgsApplication::getThemeIcon( "/mActionSimplify.png" ) );
Expand Down Expand Up @@ -1997,6 +2002,8 @@ void QgisApp::createCanvasTools()
mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures );
mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures( mMapCanvas );
mMapTools.mSplitFeatures->setAction( mActionSplitFeatures );
mMapTools.mSplitParts = new QgsMapToolSplitParts( mMapCanvas );
mMapTools.mSplitParts->setAction( mActionSplitParts );
mMapTools.mSelect = new QgsMapToolSelect( mMapCanvas );
mMapTools.mSelect->setAction( mActionSelect );
mMapTools.mSelectRectangle = new QgsMapToolSelectRectangle( mMapCanvas );
Expand Down Expand Up @@ -5369,6 +5376,11 @@ void QgisApp::splitFeatures()
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
}

void QgisApp::splitParts()
{
mMapCanvas->setMapTool( mMapTools.mSplitParts );
}

void QgisApp::reshapeFeatures()
{
mMapCanvas->setMapTool( mMapTools.mReshapeFeatures );
Expand Down Expand Up @@ -8257,6 +8269,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionReshapeFeatures->setEnabled( false );
mActionOffsetCurve->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSplitParts->setEnabled( false );
mActionMergeFeatures->setEnabled( false );
mActionMergeFeatureAttributes->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
Expand Down Expand Up @@ -8384,6 +8397,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddRing->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSplitParts->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
Expand All @@ -8405,6 +8419,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )

mActionReshapeFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitParts->setEnabled( isEditable && canAddFeatures );
mActionSimplifyFeature->setEnabled( isEditable && canAddFeatures );
mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes );

Expand All @@ -8418,6 +8433,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddRing->setEnabled( isEditable && canAddFeatures );
mActionReshapeFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
mActionSplitParts->setEnabled( isEditable && canAddFeatures );
mActionSimplifyFeature->setEnabled( isEditable && canAddFeatures );
mActionDeleteRing->setEnabled( isEditable && canAddFeatures );
mActionOffsetCurve->setEnabled( false );
Expand Down Expand Up @@ -8502,6 +8518,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionSimplifyFeature->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSplitParts->setEnabled( false );
mActionLabeling->setEnabled( false );

//NOTE: This check does not really add any protection, as it is called on load not on layer select/activate
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionMoveFeature() { return mActionMoveFeature; }
QAction *actionRotateFeature() { return mActionRotateFeature;}
QAction *actionSplitFeatures() { return mActionSplitFeatures; }
QAction *actionSplitParts() { return mActionSplitParts; }
QAction *actionAddRing() { return mActionAddRing; }
QAction *actionAddPart() { return mActionAddPart; }
QAction *actionSimplifyFeature() { return mActionSimplifyFeature; }
Expand Down Expand Up @@ -919,6 +920,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void reshapeFeatures();
//! activates the split features tool
void splitFeatures();
//! activates the split parts tool
void splitParts();
//! activates the add ring tool
void addRing();
//! activates the add part tool
Expand Down Expand Up @@ -1332,6 +1335,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMapTool* mOffsetCurve;
QgsMapTool* mReshapeFeatures;
QgsMapTool* mSplitFeatures;
QgsMapTool* mSplitParts;
QgsMapTool* mSelect;
QgsMapTool* mSelectRectangle;
QgsMapTool* mSelectPolygon;
Expand Down
1 change: 1 addition & 0 deletions src/app/qgisappinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ QAction *QgisAppInterface::actionAddFeature() { return qgis->actionAddFeature();
QAction *QgisAppInterface::actionDeleteSelected() { return qgis->actionDeleteSelected(); }
QAction *QgisAppInterface::actionMoveFeature() { return qgis->actionMoveFeature(); }
QAction *QgisAppInterface::actionSplitFeatures() { return qgis->actionSplitFeatures(); }
QAction *QgisAppInterface::actionSplitParts() { return qgis->actionSplitParts(); }
QAction *QgisAppInterface::actionAddRing() { return qgis->actionAddRing(); }
QAction *QgisAppInterface::actionAddPart() { return qgis->actionAddPart(); }
QAction *QgisAppInterface::actionSimplifyFeature() { return qgis->actionSimplifyFeature(); }
Expand Down
1 change: 1 addition & 0 deletions src/app/qgisappinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
virtual QAction *actionDeleteSelected();
virtual QAction *actionMoveFeature();
virtual QAction *actionSplitFeatures();
virtual QAction *actionSplitParts();
virtual QAction *actionAddRing();
virtual QAction *actionAddPart();
virtual QAction *actionSimplifyFeature();
Expand Down
119 changes: 119 additions & 0 deletions src/app/qgsmaptoolsplitparts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/***************************************************************************
qgsmaptoolsplitparts.h
---------------------
begin : April 2013
copyright : (C) 2013 Denis Rouzaud
email : denis.rouzaud@gmail.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 "qgisapp.h"
#include "qgsmessagebar.h"
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsmaptoolsplitparts.h"
#include "qgsvectorlayer.h"

#include <QMouseEvent>

QgsMapToolSplitParts::QgsMapToolSplitParts( QgsMapCanvas* canvas ): QgsMapToolCapture( canvas, QgsMapToolCapture::CaptureLine )
{

}

QgsMapToolSplitParts::~QgsMapToolSplitParts()
{

}

void QgsMapToolSplitParts::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
QgisApp::instance()->messageBar()->pushMessage(
tr( "Coordinate transform error" ),
tr( "Cannot transform the point to the layers coordinate system" ),
QgsMessageBar::INFO,
QgisApp::instance()->messageTimeout() );
return;
}

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

//bring up dialog if a split was not possible (polygon) or only done once (line)
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
vlayer->beginEditCommand( tr( "Parts split" ) );
int returnCode = vlayer->splitParts( points(), topologicalEditing );
vlayer->endEditCommand();
if ( returnCode == 4 )
{
QgisApp::instance()->messageBar()->pushMessage(
tr( "No part split done" ),
tr( "If there are selected parts, the split tool only applies to the selected ones. If you like to split all parts under the split line, clear the selection" ),
QgsMessageBar::WARNING,
QgisApp::instance()->messageTimeout() );
}
else if ( returnCode == 3 )
{
QgisApp::instance()->messageBar()->pushMessage(
tr( "No part split done" ),
tr( "Cut edges detected. Make sure the line splits parts into multiple parts." ),
QgsMessageBar::WARNING,
QgisApp::instance()->messageTimeout() );
}
else if ( returnCode == 7 )
{
QgisApp::instance()->messageBar()->pushMessage(
tr( "No part split done" ),
tr( "The geometry is invalid. Please repair before trying to split it." ) ,
QgsMessageBar::WARNING,
QgisApp::instance()->messageTimeout() );
}
else if ( returnCode != 0 )
{
//several intersections but only one split (most likely line)
QgisApp::instance()->messageBar()->pushMessage(
tr( "Split error" ),
tr( "An error occured during feature splitting" ),
QgsMessageBar::WARNING,
QgisApp::instance()->messageTimeout() );
}

stopCapturing();
}
}
31 changes: 31 additions & 0 deletions src/app/qgsmaptoolsplitparts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/***************************************************************************
qgsmaptoolsplitparts.h
---------------------
begin : April 2013
copyright : (C) 2013 Denis Rouzaud
email : denis.rouzaud@gmail.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. *
* *
***************************************************************************/

#ifndef QGSMAPTOOLSPLITPARTS_H
#define QGSMAPTOOLSPLITPARTS_H

#include "qgsmaptoolcapture.h"

/**A map tool that draws a line and splits the parts cut by the line*/
class QgsMapToolSplitParts: public QgsMapToolCapture
{
Q_OBJECT
public:
QgsMapToolSplitParts( QgsMapCanvas* canvas );
virtual ~QgsMapToolSplitParts();
void canvasReleaseEvent( QMouseEvent * e );
};

#endif
65 changes: 42 additions & 23 deletions src/core/qgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2935,25 +2935,6 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
return 2;
}

if ( !isMultipart() && !convertToMultiType() )
{
QgsDebugMsg( "could not convert to multipart" );
return 1;
}

//create geos geometry from wkb if not already there
if ( mDirtyGeos )
{
exportWkbToGeos();
}

if ( !mGeos )
{
QgsDebugMsg( "GEOS geometry not available!" );
return 4;
}

int geosType = GEOSGeomTypeId( mGeos );
GEOSGeometry *newPart = 0;

switch ( geomType )
Expand Down Expand Up @@ -2996,6 +2977,39 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
return 2;
}

return addPart( newPart );
}

int QgsGeometry::addPart( QgsGeometry * newPart )
{
const GEOSGeometry * geosPart = newPart->asGeos();
return addPart( GEOSGeom_clone( geosPart ) );
}

int QgsGeometry::addPart( GEOSGeometry * newPart )
{
QGis::GeometryType geomType = type();

if ( !isMultipart() && !convertToMultiType() )
{
QgsDebugMsg( "could not convert to multipart" );
return 1;
}

//create geos geometry from wkb if not already there
if ( mDirtyGeos )
{
exportWkbToGeos();
}

if ( !mGeos )
{
QgsDebugMsg( "GEOS geometry not available!" );
return 4;
}

int geosType = GEOSGeomTypeId( mGeos );

Q_ASSERT( newPart );

try
Expand Down Expand Up @@ -3023,8 +3037,8 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
{
const GEOSGeometry *partN = GEOSGetGeometryN( mGeos, i );

if ( geomType == QGis::Polygon && !GEOSDisjoint( partN, newPart ) )
//bail out if new polygon is not disjoint with existing ones
if ( geomType == QGis::Polygon && GEOSOverlaps( partN, newPart ) )
//bail out if new polygon overlaps with existing ones
break;

parts << GEOSGeom_clone( partN );
Expand All @@ -3036,11 +3050,16 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
for ( int i = 0; i < parts.size(); i++ )
GEOSGeom_destroy( parts[i] );

QgsDebugMsg( "new polygon part not disjoint" );
QgsDebugMsg( "new polygon part overlaps" );
return 3;
}

parts << newPart;
int nPartGeoms = GEOSGetNumGeometries( newPart );
for( int i = 0; i < nPartGeoms; ++i )
{
parts << GEOSGeom_clone( GEOSGetGeometryN( newPart, i ) );
}
GEOSGeom_destroy( newPart );

GEOSGeom_destroy( mGeos );

Expand Down
10 changes: 10 additions & 0 deletions src/core/qgsgeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,16 @@ class CORE_EXPORT QgsGeometry
not disjoint with existing polygons of the feature*/
int addPart( const QList<QgsPoint> &points );

/**Adds a new island polygon to a multipolygon feature
@return 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
not disjoint with existing polygons of the feature*/
int addPart( GEOSGeometry *newPart );

/**Adds a new island polygon to a multipolygon feature
@return 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
not disjoint with existing polygons of the feature*/
int addPart( QgsGeometry *newPart );

/**Translate this geometry by dx, dy
@return 0 in case of success*/
int translate( double dx, double dy );
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,15 @@ int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double
return utils.translateFeature( featureId, dx, dy );
}

int QgsVectorLayer::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
{
if ( !mEditBuffer || !mDataProvider )
return -1;

QgsVectorLayerEditUtils utils( this );
return utils.splitParts( splitLine, topologicalEditing );
}

int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
{
if ( !mEditBuffer || !mDataProvider )
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
@return 0 in case of success*/
int translateFeature( QgsFeatureId featureId, double dx, double dy );

/**Splits parts cut by the given line
* @param splitLine line that splits the layer features
* @param topologicalEditing true if topological editing is enabled
* @return
* 0 in case of success,
* 4 if there is a selection but no feature split
*/
int splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );

/**Splits features cut by the given line
* @param splitLine line that splits the layer features
* @param topologicalEditing true if topological editing is enabled
Expand Down
127 changes: 127 additions & 0 deletions src/core/qgsvectorlayereditutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "qgsvectordataprovider.h"
#include "qgsgeometrycache.h"
#include "qgsvectorlayereditbuffer.h"
#include "qgslogger.h"

#include <limits>

Expand Down Expand Up @@ -295,6 +296,132 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
return returnCode;
}

int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
{
if ( !L->hasGeometryType() )
return 4;

double xMin, yMin, xMax, yMax;
QgsRectangle bBox; //bounding box of the split line
int returnCode = 0;
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
int numberOfSplittedParts = 0;

QgsFeatureList featureList;
const QgsFeatureIds selectedIds = L->selectedFeaturesIds();

if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection
{
featureList = L->selectedFeatures();
}
else //else consider all the feature that intersect the bounding box of the split line
{
if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
{
bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin );
bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax );
}
else
{
return 1;
}

if ( bBox.isEmpty() )
{
//if the bbox is a line, try to make a square out of it
if ( bBox.width() == 0.0 && bBox.height() > 0 )
{
bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
}
else if ( bBox.height() == 0.0 && bBox.width() > 0 )
{
bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
}
else
{
return 2;
}
}

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

QgsFeature f;
while ( fit.nextFeature( f ) )
featureList << QgsFeature( f );
}

int addPartRet;
foreach ( const QgsFeature& feat, featureList )
{
QList<QgsGeometry*> newGeometries;
QList<QgsPoint> topologyTestPoints;
splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
if ( splitFunctionReturn == 0 )
{
//add new parts
for ( int i = 0; i < newGeometries.size(); ++i )
{
addPartRet = feat.geometry()->addPart( newGeometries.at( i ) );
if ( addPartRet != 0 )
break;
}

// For test only: Exception already thrown here...
// feat.geometry()->asWkb();

if ( addPartRet == 0 )
{
L->editBuffer()->changeGeometry( feat.id(), feat.geometry() );
}
else
{
// Test addPartRet
switch ( addPartRet )
{
case 1:
QgsDebugMsg( "Not a multipolygon" );
break;

case 2:
QgsDebugMsg( "Not a valid geometry" );
break;

case 3:
QgsDebugMsg( "New polygon ring" );
break;
}
}
L->editBuffer()->changeGeometry( feat.id(), feat.geometry() );

if ( topologicalEditing )
{
QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
{
addTopologicalPoints( *topol_it );
}
}
++numberOfSplittedParts;
}
else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
{
returnCode = splitFunctionReturn;
}

qDeleteAll( newGeometries );
}

if ( numberOfSplittedParts == 0 && selectedIds.size() > 0 )
{
//There is a selection but no feature has been split.
//Maybe user forgot that only the selected features are split
returnCode = 4;
}

return returnCode;
}


int QgsVectorLayerEditUtils::addTopologicalPoints( QgsGeometry* geom )
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsvectorlayereditutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ class CORE_EXPORT QgsVectorLayerEditUtils
@return 0 in case of success*/
int translateFeature( QgsFeatureId featureId, double dx, double dy );

/** Splits parts cut by the given line
* @param splitLine line that splits the layer feature parts
* @param topologicalEditing true if topological editing is enabled
* @return
* 0 in case of success,
* 4 if there is a selection but no feature split
*/
int splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );

/** Splits features cut by the given line
* @param splitLine line that splits the layer features
* @param topologicalEditing true if topological editing is enabled
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgisinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ class GUI_EXPORT QgisInterface : public QObject
virtual QAction *actionDeleteSelected() = 0;
virtual QAction *actionMoveFeature() = 0;
virtual QAction *actionSplitFeatures() = 0;
virtual QAction *actionSplitParts() = 0;
virtual QAction *actionAddRing() = 0;
virtual QAction *actionAddPart() = 0;
virtual QAction *actionSimplifyFeature() = 0;
Expand Down
16 changes: 15 additions & 1 deletion src/ui/qgisapp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
<addaction name="mActionReshapeFeatures"/>
<addaction name="mActionOffsetCurve"/>
<addaction name="mActionSplitFeatures"/>
<addaction name="mActionSplitParts"/>
<addaction name="mActionMergeFeatures"/>
<addaction name="mActionMergeFeatureAttributes"/>
<addaction name="mActionNodeTool"/>
Expand Down Expand Up @@ -342,6 +343,7 @@
<addaction name="mActionReshapeFeatures"/>
<addaction name="mActionOffsetCurve"/>
<addaction name="mActionSplitFeatures"/>
<addaction name="mActionSplitParts"/>
<addaction name="mActionMergeFeatures"/>
<addaction name="mActionMergeFeatureAttributes"/>
<addaction name="mActionRotatePointSymbols"/>
Expand Down Expand Up @@ -679,12 +681,24 @@
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSplitFeatures.png</normaloff>:/images/themes/default/mActionSplitFeatures.png</iconset>
<normaloff>:/images/themes/default/mActionSplitFeatures.svg</normaloff>:/images/themes/default/mActionSplitFeatures.svg</iconset>
</property>
<property name="text">
<string>Split Features</string>
</property>
</action>
<action name="mActionSplitParts">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSplitFeatures.svg</normaloff>:/images/themes/default/mActionSplitFeatures.svg</iconset>
</property>
<property name="text">
<string>Split Parts</string>
</property>
</action>
<action name="mActionDeleteSelected">
<property name="icon">
<iconset resource="../../images/images.qrc">
Expand Down