diff --git a/images/images.qrc b/images/images.qrc
index 93e8d66b3ee..c171859de5b 100644
--- a/images/images.qrc
+++ b/images/images.qrc
@@ -273,8 +273,8 @@
themes/default/mActionSignMinus.png
themes/default/mActionSignPlus.png
themes/default/mActionSimplify.png
- themes/default/mActionSplitFeatures.png
themes/default/mActionSplitFeatures.svg
+ themes/default/mActionSplitParts.svg
themes/default/mActionSum.png
themes/default/mActionTextAnnotation.png
themes/default/mActionToggleEditing.png
diff --git a/images/themes/default/mActionSplitFeatures.png b/images/themes/default/mActionSplitFeatures.png
deleted file mode 100644
index 583c65b63f1..00000000000
Binary files a/images/themes/default/mActionSplitFeatures.png and /dev/null differ
diff --git a/images/themes/default/mActionSplitParts.svg b/images/themes/default/mActionSplitParts.svg
new file mode 100644
index 00000000000..e917c38d501
--- /dev/null
+++ b/images/themes/default/mActionSplitParts.svg
@@ -0,0 +1,790 @@
+
+
+
+
diff --git a/python/gui/qgisinterface.sip b/python/gui/qgisinterface.sip
index 6659c69bad9..08a48e1fb7d 100644
--- a/python/gui/qgisinterface.sip
+++ b/python/gui/qgisinterface.sip
@@ -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;
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index a54cea7ea27..a335f482df5 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -76,6 +76,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolselectutils.cpp
qgsmaptoolsimplify.cpp
qgsmaptoolsplitfeatures.cpp
+ qgsmaptoolsplitparts.cpp
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp
qgsmaptoolvertexedit.cpp
@@ -226,6 +227,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmaptoolselectrectangle.h
qgsmaptoolsimplify.h
qgsmaptoolsplitfeatures.h
+ qgsmaptoolsplitparts.h
qgsmaptoolvertexedit.h
nodetool/qgsmaptoolnodetool.h
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 096d5b158e8..e4db5171431 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -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"
@@ -806,6 +807,7 @@ QgisApp::~QgisApp()
delete mMapTools.mShowHideLabels;
delete mMapTools.mSimplifyFeature;
delete mMapTools.mSplitFeatures;
+ delete mMapTools.mSplitParts;
delete mMapTools.mSvgAnnotation;
delete mMapTools.mTextAnnotation;
@@ -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() ) );
@@ -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 );
@@ -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" ) );
@@ -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 );
@@ -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 );
@@ -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 );
@@ -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 );
@@ -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 );
@@ -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 );
@@ -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
diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h
index 49e256bcee6..0942891b281 100644
--- a/src/app/qgisapp.h
+++ b/src/app/qgisapp.h
@@ -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; }
@@ -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
@@ -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;
diff --git a/src/app/qgisappinterface.cpp b/src/app/qgisappinterface.cpp
index 0abfb0654ad..6f38b8afa42 100644
--- a/src/app/qgisappinterface.cpp
+++ b/src/app/qgisappinterface.cpp
@@ -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(); }
diff --git a/src/app/qgisappinterface.h b/src/app/qgisappinterface.h
index 840e2998787..61fdffec0e3 100644
--- a/src/app/qgisappinterface.h
+++ b/src/app/qgisappinterface.h
@@ -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();
diff --git a/src/app/qgsmaptoolsplitparts.cpp b/src/app/qgsmaptoolsplitparts.cpp
new file mode 100644
index 00000000000..d24bdaf7a38
--- /dev/null
+++ b/src/app/qgsmaptoolsplitparts.cpp
@@ -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
+
+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( 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();
+ }
+}
diff --git a/src/app/qgsmaptoolsplitparts.h b/src/app/qgsmaptoolsplitparts.h
new file mode 100644
index 00000000000..d6b34498d7a
--- /dev/null
+++ b/src/app/qgsmaptoolsplitparts.h
@@ -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
diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp
index 96593b49bd8..6044fbfd25e 100644
--- a/src/core/qgsgeometry.cpp
+++ b/src/core/qgsgeometry.cpp
@@ -2935,25 +2935,6 @@ int QgsGeometry::addPart( const QList &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 )
@@ -2996,6 +2977,39 @@ int QgsGeometry::addPart( const QList &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
@@ -3023,8 +3037,8 @@ int QgsGeometry::addPart( const QList &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 );
@@ -3036,11 +3050,16 @@ int QgsGeometry::addPart( const QList &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 );
diff --git a/src/core/qgsgeometry.h b/src/core/qgsgeometry.h
index 54604628ed4..23e17c0238f 100644
--- a/src/core/qgsgeometry.h
+++ b/src/core/qgsgeometry.h
@@ -267,6 +267,16 @@ class CORE_EXPORT QgsGeometry
not disjoint with existing polygons of the feature*/
int addPart( const QList &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 );
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index 025cf146302..1e96e20d2c5 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -1378,6 +1378,15 @@ int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double
return utils.translateFeature( featureId, dx, dy );
}
+int QgsVectorLayer::splitParts( const QList& splitLine, bool topologicalEditing )
+{
+ if ( !mEditBuffer || !mDataProvider )
+ return -1;
+
+ QgsVectorLayerEditUtils utils( this );
+ return utils.splitParts( splitLine, topologicalEditing );
+}
+
int QgsVectorLayer::splitFeatures( const QList& splitLine, bool topologicalEditing )
{
if ( !mEditBuffer || !mDataProvider )
diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h
index 5fbeff8c55e..ee1ff0d90b0 100644
--- a/src/core/qgsvectorlayer.h
+++ b/src/core/qgsvectorlayer.h
@@ -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& 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
diff --git a/src/core/qgsvectorlayereditutils.cpp b/src/core/qgsvectorlayereditutils.cpp
index 6f1660ff854..dfcde35fde5 100644
--- a/src/core/qgsvectorlayereditutils.cpp
+++ b/src/core/qgsvectorlayereditutils.cpp
@@ -17,6 +17,7 @@
#include "qgsvectordataprovider.h"
#include "qgsgeometrycache.h"
#include "qgsvectorlayereditbuffer.h"
+#include "qgslogger.h"
#include
@@ -295,6 +296,132 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList& splitLine, bo
return returnCode;
}
+int QgsVectorLayerEditUtils::splitParts( const QList& 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 newGeometries;
+ QList 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::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 )
diff --git a/src/core/qgsvectorlayereditutils.h b/src/core/qgsvectorlayereditutils.h
index c2e3a4b6e17..7ce5b013bd8 100644
--- a/src/core/qgsvectorlayereditutils.h
+++ b/src/core/qgsvectorlayereditutils.h
@@ -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& 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
diff --git a/src/gui/qgisinterface.h b/src/gui/qgisinterface.h
index 798652db55a..cdacf578419 100644
--- a/src/gui/qgisinterface.h
+++ b/src/gui/qgisinterface.h
@@ -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;
diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui
index ee005ee8fb1..2158e6cad3f 100644
--- a/src/ui/qgisapp.ui
+++ b/src/ui/qgisapp.ui
@@ -245,6 +245,7 @@
+
@@ -342,6 +343,7 @@
+
@@ -679,12 +681,24 @@
- :/images/themes/default/mActionSplitFeatures.png:/images/themes/default/mActionSplitFeatures.png
+ :/images/themes/default/mActionSplitFeatures.svg:/images/themes/default/mActionSplitFeatures.svg
Split Features
+
+
+ true
+
+
+
+ :/images/themes/default/mActionSplitFeatures.svg:/images/themes/default/mActionSplitFeatures.svg
+
+
+ Split Parts
+
+