Skip to content

Commit 3e89c69

Browse files
committedSep 10, 2013
split part of multi-geometry
1 parent 641359d commit 3e89c69

19 files changed

+1189
-25
lines changed
 

‎images/images.qrc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,8 @@
273273
<file>themes/default/mActionSignMinus.png</file>
274274
<file>themes/default/mActionSignPlus.png</file>
275275
<file>themes/default/mActionSimplify.png</file>
276-
<file>themes/default/mActionSplitFeatures.png</file>
277276
<file>themes/default/mActionSplitFeatures.svg</file>
277+
<file>themes/default/mActionSplitParts.svg</file>
278278
<file>themes/default/mActionSum.png</file>
279279
<file>themes/default/mActionTextAnnotation.png</file>
280280
<file>themes/default/mActionToggleEditing.png</file>
-1.54 KB
Binary file not shown.

‎images/themes/default/mActionSplitParts.svg‎

Lines changed: 790 additions & 0 deletions
Loading

‎python/gui/qgisinterface.sip‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ class QgisInterface : QObject
388388
virtual QAction *actionDeleteSelected() = 0;
389389
virtual QAction *actionMoveFeature() = 0;
390390
virtual QAction *actionSplitFeatures() = 0;
391+
virtual QAction *actionSplitParts() = 0;
391392
virtual QAction *actionAddRing() = 0;
392393
virtual QAction *actionAddPart() = 0;
393394
virtual QAction *actionSimplifyFeature() = 0;

‎src/app/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ SET(QGIS_APP_SRCS
7676
qgsmaptoolselectutils.cpp
7777
qgsmaptoolsimplify.cpp
7878
qgsmaptoolsplitfeatures.cpp
79+
qgsmaptoolsplitparts.cpp
7980
qgsmaptoolsvgannotation.cpp
8081
qgsmaptooltextannotation.cpp
8182
qgsmaptoolvertexedit.cpp
@@ -226,6 +227,7 @@ SET (QGIS_APP_MOC_HDRS
226227
qgsmaptoolselectrectangle.h
227228
qgsmaptoolsimplify.h
228229
qgsmaptoolsplitfeatures.h
230+
qgsmaptoolsplitparts.h
229231
qgsmaptoolvertexedit.h
230232

231233
nodetool/qgsmaptoolnodetool.h

‎src/app/qgisapp.cpp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@
245245
#include "qgsmaptoolreshape.h"
246246
#include "qgsmaptoolrotatepointsymbols.h"
247247
#include "qgsmaptoolsplitfeatures.h"
248+
#include "qgsmaptoolsplitparts.h"
248249
#include "qgsmaptooltextannotation.h"
249250
#include "qgsmaptoolvertexedit.h"
250251
#include "qgsmaptoolzoom.h"
@@ -806,6 +807,7 @@ QgisApp::~QgisApp()
806807
delete mMapTools.mShowHideLabels;
807808
delete mMapTools.mSimplifyFeature;
808809
delete mMapTools.mSplitFeatures;
810+
delete mMapTools.mSplitParts;
809811
delete mMapTools.mSvgAnnotation;
810812
delete mMapTools.mTextAnnotation;
811813

@@ -963,6 +965,7 @@ void QgisApp::createActions()
963965

964966
connect( mActionReshapeFeatures, SIGNAL( triggered() ), this, SLOT( reshapeFeatures() ) );
965967
connect( mActionSplitFeatures, SIGNAL( triggered() ), this, SLOT( splitFeatures() ) );
968+
connect( mActionSplitParts, SIGNAL( triggered() ), this, SLOT( splitParts() ) );
966969
connect( mActionDeleteSelected, SIGNAL( triggered() ), this, SLOT( deleteSelected() ) );
967970
connect( mActionAddRing, SIGNAL( triggered() ), this, SLOT( addRing() ) );
968971
connect( mActionAddPart, SIGNAL( triggered() ), this, SLOT( addPart() ) );
@@ -1233,6 +1236,7 @@ void QgisApp::createActionGroups()
12331236
#endif
12341237
mMapToolGroup->addAction( mActionReshapeFeatures );
12351238
mMapToolGroup->addAction( mActionSplitFeatures );
1239+
mMapToolGroup->addAction( mActionSplitParts );
12361240
mMapToolGroup->addAction( mActionDeleteSelected );
12371241
mMapToolGroup->addAction( mActionAddRing );
12381242
mMapToolGroup->addAction( mActionAddPart );
@@ -1774,6 +1778,7 @@ void QgisApp::setTheme( QString theThemeName )
17741778
mActionRotateFeature->setIcon( QgsApplication::getThemeIcon( "/mActionRotateFeature.png" ) );
17751779
mActionReshapeFeatures->setIcon( QgsApplication::getThemeIcon( "/mActionReshape.png" ) );
17761780
mActionSplitFeatures->setIcon( QgsApplication::getThemeIcon( "/mActionSplitFeatures.svg" ) );
1781+
mActionSplitParts->setIcon( QgsApplication::getThemeIcon( "/mActionSplitParts.svg" ) );
17771782
mActionDeleteSelected->setIcon( QgsApplication::getThemeIcon( "/mActionDeleteSelected.svg" ) );
17781783
mActionNodeTool->setIcon( QgsApplication::getThemeIcon( "/mActionNodeTool.png" ) );
17791784
mActionSimplifyFeature->setIcon( QgsApplication::getThemeIcon( "/mActionSimplify.png" ) );
@@ -1997,6 +2002,8 @@ void QgisApp::createCanvasTools()
19972002
mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures );
19982003
mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures( mMapCanvas );
19992004
mMapTools.mSplitFeatures->setAction( mActionSplitFeatures );
2005+
mMapTools.mSplitParts = new QgsMapToolSplitParts( mMapCanvas );
2006+
mMapTools.mSplitParts->setAction( mActionSplitParts );
20002007
mMapTools.mSelect = new QgsMapToolSelect( mMapCanvas );
20012008
mMapTools.mSelect->setAction( mActionSelect );
20022009
mMapTools.mSelectRectangle = new QgsMapToolSelectRectangle( mMapCanvas );
@@ -5369,6 +5376,11 @@ void QgisApp::splitFeatures()
53695376
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
53705377
}
53715378

5379+
void QgisApp::splitParts()
5380+
{
5381+
mMapCanvas->setMapTool( mMapTools.mSplitParts );
5382+
}
5383+
53725384
void QgisApp::reshapeFeatures()
53735385
{
53745386
mMapCanvas->setMapTool( mMapTools.mReshapeFeatures );
@@ -8257,6 +8269,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
82578269
mActionReshapeFeatures->setEnabled( false );
82588270
mActionOffsetCurve->setEnabled( false );
82598271
mActionSplitFeatures->setEnabled( false );
8272+
mActionSplitParts->setEnabled( false );
82608273
mActionMergeFeatures->setEnabled( false );
82618274
mActionMergeFeatureAttributes->setEnabled( false );
82628275
mActionRotatePointSymbols->setEnabled( false );
@@ -8384,6 +8397,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
83848397
mActionAddRing->setEnabled( false );
83858398
mActionReshapeFeatures->setEnabled( false );
83868399
mActionSplitFeatures->setEnabled( false );
8400+
mActionSplitParts->setEnabled( false );
83878401
mActionSimplifyFeature->setEnabled( false );
83888402
mActionDeleteRing->setEnabled( false );
83898403
mActionRotatePointSymbols->setEnabled( false );
@@ -8405,6 +8419,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
84058419

84068420
mActionReshapeFeatures->setEnabled( isEditable && canAddFeatures );
84078421
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
8422+
mActionSplitParts->setEnabled( isEditable && canAddFeatures );
84088423
mActionSimplifyFeature->setEnabled( isEditable && canAddFeatures );
84098424
mActionOffsetCurve->setEnabled( isEditable && canAddFeatures && canChangeAttributes );
84108425

@@ -8418,6 +8433,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
84188433
mActionAddRing->setEnabled( isEditable && canAddFeatures );
84198434
mActionReshapeFeatures->setEnabled( isEditable && canAddFeatures );
84208435
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
8436+
mActionSplitParts->setEnabled( isEditable && canAddFeatures );
84218437
mActionSimplifyFeature->setEnabled( isEditable && canAddFeatures );
84228438
mActionDeleteRing->setEnabled( isEditable && canAddFeatures );
84238439
mActionOffsetCurve->setEnabled( false );
@@ -8502,6 +8518,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
85028518
mActionSimplifyFeature->setEnabled( false );
85038519
mActionReshapeFeatures->setEnabled( false );
85048520
mActionSplitFeatures->setEnabled( false );
8521+
mActionSplitParts->setEnabled( false );
85058522
mActionLabeling->setEnabled( false );
85068523

85078524
//NOTE: This check does not really add any protection, as it is called on load not on layer select/activate

‎src/app/qgisapp.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
262262
QAction *actionMoveFeature() { return mActionMoveFeature; }
263263
QAction *actionRotateFeature() { return mActionRotateFeature;}
264264
QAction *actionSplitFeatures() { return mActionSplitFeatures; }
265+
QAction *actionSplitParts() { return mActionSplitParts; }
265266
QAction *actionAddRing() { return mActionAddRing; }
266267
QAction *actionAddPart() { return mActionAddPart; }
267268
QAction *actionSimplifyFeature() { return mActionSimplifyFeature; }
@@ -919,6 +920,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
919920
void reshapeFeatures();
920921
//! activates the split features tool
921922
void splitFeatures();
923+
//! activates the split parts tool
924+
void splitParts();
922925
//! activates the add ring tool
923926
void addRing();
924927
//! activates the add part tool
@@ -1332,6 +1335,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
13321335
QgsMapTool* mOffsetCurve;
13331336
QgsMapTool* mReshapeFeatures;
13341337
QgsMapTool* mSplitFeatures;
1338+
QgsMapTool* mSplitParts;
13351339
QgsMapTool* mSelect;
13361340
QgsMapTool* mSelectRectangle;
13371341
QgsMapTool* mSelectPolygon;

‎src/app/qgisappinterface.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ QAction *QgisAppInterface::actionAddFeature() { return qgis->actionAddFeature();
482482
QAction *QgisAppInterface::actionDeleteSelected() { return qgis->actionDeleteSelected(); }
483483
QAction *QgisAppInterface::actionMoveFeature() { return qgis->actionMoveFeature(); }
484484
QAction *QgisAppInterface::actionSplitFeatures() { return qgis->actionSplitFeatures(); }
485+
QAction *QgisAppInterface::actionSplitParts() { return qgis->actionSplitParts(); }
485486
QAction *QgisAppInterface::actionAddRing() { return qgis->actionAddRing(); }
486487
QAction *QgisAppInterface::actionAddPart() { return qgis->actionAddPart(); }
487488
QAction *QgisAppInterface::actionSimplifyFeature() { return qgis->actionSimplifyFeature(); }

‎src/app/qgisappinterface.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
332332
virtual QAction *actionDeleteSelected();
333333
virtual QAction *actionMoveFeature();
334334
virtual QAction *actionSplitFeatures();
335+
virtual QAction *actionSplitParts();
335336
virtual QAction *actionAddRing();
336337
virtual QAction *actionAddPart();
337338
virtual QAction *actionSimplifyFeature();

‎src/app/qgsmaptoolsplitparts.cpp‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/***************************************************************************
2+
qgsmaptoolsplitparts.h
3+
---------------------
4+
begin : April 2013
5+
copyright : (C) 2013 Denis Rouzaud
6+
email : denis.rouzaud@gmail.com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgisapp.h"
17+
#include "qgsmessagebar.h"
18+
#include "qgsmapcanvas.h"
19+
#include "qgsproject.h"
20+
#include "qgsmaptoolsplitparts.h"
21+
#include "qgsvectorlayer.h"
22+
23+
#include <QMouseEvent>
24+
25+
QgsMapToolSplitParts::QgsMapToolSplitParts( QgsMapCanvas* canvas ): QgsMapToolCapture( canvas, QgsMapToolCapture::CaptureLine )
26+
{
27+
28+
}
29+
30+
QgsMapToolSplitParts::~QgsMapToolSplitParts()
31+
{
32+
33+
}
34+
35+
void QgsMapToolSplitParts::canvasReleaseEvent( QMouseEvent * e )
36+
{
37+
//check if we operate on a vector layer
38+
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
39+
40+
if ( !vlayer )
41+
{
42+
notifyNotVectorLayer();
43+
return;
44+
}
45+
46+
if ( !vlayer->isEditable() )
47+
{
48+
notifyNotEditableLayer();
49+
return;
50+
}
51+
52+
//add point to list and to rubber band
53+
if ( e->button() == Qt::LeftButton )
54+
{
55+
int error = addVertex( e->pos() );
56+
if ( error == 1 )
57+
{
58+
//current layer is not a vector layer
59+
return;
60+
}
61+
else if ( error == 2 )
62+
{
63+
//problem with coordinate transformation
64+
QgisApp::instance()->messageBar()->pushMessage(
65+
tr( "Coordinate transform error" ),
66+
tr( "Cannot transform the point to the layers coordinate system" ),
67+
QgsMessageBar::INFO,
68+
QgisApp::instance()->messageTimeout() );
69+
return;
70+
}
71+
72+
startCapturing();
73+
}
74+
else if ( e->button() == Qt::RightButton )
75+
{
76+
deleteTempRubberBand();
77+
78+
//bring up dialog if a split was not possible (polygon) or only done once (line)
79+
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
80+
vlayer->beginEditCommand( tr( "Parts split" ) );
81+
int returnCode = vlayer->splitParts( points(), topologicalEditing );
82+
vlayer->endEditCommand();
83+
if ( returnCode == 4 )
84+
{
85+
QgisApp::instance()->messageBar()->pushMessage(
86+
tr( "No part split done" ),
87+
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" ),
88+
QgsMessageBar::WARNING,
89+
QgisApp::instance()->messageTimeout() );
90+
}
91+
else if ( returnCode == 3 )
92+
{
93+
QgisApp::instance()->messageBar()->pushMessage(
94+
tr( "No part split done" ),
95+
tr( "Cut edges detected. Make sure the line splits parts into multiple parts." ),
96+
QgsMessageBar::WARNING,
97+
QgisApp::instance()->messageTimeout() );
98+
}
99+
else if ( returnCode == 7 )
100+
{
101+
QgisApp::instance()->messageBar()->pushMessage(
102+
tr( "No part split done" ),
103+
tr( "The geometry is invalid. Please repair before trying to split it." ) ,
104+
QgsMessageBar::WARNING,
105+
QgisApp::instance()->messageTimeout() );
106+
}
107+
else if ( returnCode != 0 )
108+
{
109+
//several intersections but only one split (most likely line)
110+
QgisApp::instance()->messageBar()->pushMessage(
111+
tr( "Split error" ),
112+
tr( "An error occured during feature splitting" ),
113+
QgsMessageBar::WARNING,
114+
QgisApp::instance()->messageTimeout() );
115+
}
116+
117+
stopCapturing();
118+
}
119+
}

‎src/app/qgsmaptoolsplitparts.h‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/***************************************************************************
2+
qgsmaptoolsplitparts.h
3+
---------------------
4+
begin : April 2013
5+
copyright : (C) 2013 Denis Rouzaud
6+
email : denis.rouzaud@gmail.com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSMAPTOOLSPLITPARTS_H
17+
#define QGSMAPTOOLSPLITPARTS_H
18+
19+
#include "qgsmaptoolcapture.h"
20+
21+
/**A map tool that draws a line and splits the parts cut by the line*/
22+
class QgsMapToolSplitParts: public QgsMapToolCapture
23+
{
24+
Q_OBJECT
25+
public:
26+
QgsMapToolSplitParts( QgsMapCanvas* canvas );
27+
virtual ~QgsMapToolSplitParts();
28+
void canvasReleaseEvent( QMouseEvent * e );
29+
};
30+
31+
#endif

‎src/core/qgsgeometry.cpp‎

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,25 +2935,6 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
29352935
return 2;
29362936
}
29372937

2938-
if ( !isMultipart() && !convertToMultiType() )
2939-
{
2940-
QgsDebugMsg( "could not convert to multipart" );
2941-
return 1;
2942-
}
2943-
2944-
//create geos geometry from wkb if not already there
2945-
if ( mDirtyGeos )
2946-
{
2947-
exportWkbToGeos();
2948-
}
2949-
2950-
if ( !mGeos )
2951-
{
2952-
QgsDebugMsg( "GEOS geometry not available!" );
2953-
return 4;
2954-
}
2955-
2956-
int geosType = GEOSGeomTypeId( mGeos );
29572938
GEOSGeometry *newPart = 0;
29582939

29592940
switch ( geomType )
@@ -2996,6 +2977,39 @@ int QgsGeometry::addPart( const QList<QgsPoint> &points )
29962977
return 2;
29972978
}
29982979

2980+
return addPart( newPart );
2981+
}
2982+
2983+
int QgsGeometry::addPart( QgsGeometry * newPart )
2984+
{
2985+
const GEOSGeometry * geosPart = newPart->asGeos();
2986+
return addPart( GEOSGeom_clone( geosPart ) );
2987+
}
2988+
2989+
int QgsGeometry::addPart( GEOSGeometry * newPart )
2990+
{
2991+
QGis::GeometryType geomType = type();
2992+
2993+
if ( !isMultipart() && !convertToMultiType() )
2994+
{
2995+
QgsDebugMsg( "could not convert to multipart" );
2996+
return 1;
2997+
}
2998+
2999+
//create geos geometry from wkb if not already there
3000+
if ( mDirtyGeos )
3001+
{
3002+
exportWkbToGeos();
3003+
}
3004+
3005+
if ( !mGeos )
3006+
{
3007+
QgsDebugMsg( "GEOS geometry not available!" );
3008+
return 4;
3009+
}
3010+
3011+
int geosType = GEOSGeomTypeId( mGeos );
3012+
29993013
Q_ASSERT( newPart );
30003014

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

3026-
if ( geomType == QGis::Polygon && !GEOSDisjoint( partN, newPart ) )
3027-
//bail out if new polygon is not disjoint with existing ones
3040+
if ( geomType == QGis::Polygon && GEOSOverlaps( partN, newPart ) )
3041+
//bail out if new polygon overlaps with existing ones
30283042
break;
30293043

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

3039-
QgsDebugMsg( "new polygon part not disjoint" );
3053+
QgsDebugMsg( "new polygon part overlaps" );
30403054
return 3;
30413055
}
30423056

3043-
parts << newPart;
3057+
int nPartGeoms = GEOSGetNumGeometries( newPart );
3058+
for( int i = 0; i < nPartGeoms; ++i )
3059+
{
3060+
parts << GEOSGeom_clone( GEOSGetGeometryN( newPart, i ) );
3061+
}
3062+
GEOSGeom_destroy( newPart );
30443063

30453064
GEOSGeom_destroy( mGeos );
30463065

‎src/core/qgsgeometry.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,16 @@ class CORE_EXPORT QgsGeometry
267267
not disjoint with existing polygons of the feature*/
268268
int addPart( const QList<QgsPoint> &points );
269269

270+
/**Adds a new island polygon to a multipolygon feature
271+
@return 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
272+
not disjoint with existing polygons of the feature*/
273+
int addPart( GEOSGeometry *newPart );
274+
275+
/**Adds a new island polygon to a multipolygon feature
276+
@return 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
277+
not disjoint with existing polygons of the feature*/
278+
int addPart( QgsGeometry *newPart );
279+
270280
/**Translate this geometry by dx, dy
271281
@return 0 in case of success*/
272282
int translate( double dx, double dy );

‎src/core/qgsvectorlayer.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,15 @@ int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double
13781378
return utils.translateFeature( featureId, dx, dy );
13791379
}
13801380

1381+
int QgsVectorLayer::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
1382+
{
1383+
if ( !mEditBuffer || !mDataProvider )
1384+
return -1;
1385+
1386+
QgsVectorLayerEditUtils utils( this );
1387+
return utils.splitParts( splitLine, topologicalEditing );
1388+
}
1389+
13811390
int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing )
13821391
{
13831392
if ( !mEditBuffer || !mDataProvider )

‎src/core/qgsvectorlayer.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
895895
@return 0 in case of success*/
896896
int translateFeature( QgsFeatureId featureId, double dx, double dy );
897897

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

‎src/core/qgsvectorlayereditutils.cpp‎

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "qgsvectordataprovider.h"
1818
#include "qgsgeometrycache.h"
1919
#include "qgsvectorlayereditbuffer.h"
20+
#include "qgslogger.h"
2021

2122
#include <limits>
2223

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

299+
int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing )
300+
{
301+
if ( !L->hasGeometryType() )
302+
return 4;
303+
304+
double xMin, yMin, xMax, yMax;
305+
QgsRectangle bBox; //bounding box of the split line
306+
int returnCode = 0;
307+
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
308+
int numberOfSplittedParts = 0;
309+
310+
QgsFeatureList featureList;
311+
const QgsFeatureIds selectedIds = L->selectedFeaturesIds();
312+
313+
if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection
314+
{
315+
featureList = L->selectedFeatures();
316+
}
317+
else //else consider all the feature that intersect the bounding box of the split line
318+
{
319+
if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 )
320+
{
321+
bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin );
322+
bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax );
323+
}
324+
else
325+
{
326+
return 1;
327+
}
328+
329+
if ( bBox.isEmpty() )
330+
{
331+
//if the bbox is a line, try to make a square out of it
332+
if ( bBox.width() == 0.0 && bBox.height() > 0 )
333+
{
334+
bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 );
335+
bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 );
336+
}
337+
else if ( bBox.height() == 0.0 && bBox.width() > 0 )
338+
{
339+
bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 );
340+
bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 );
341+
}
342+
else
343+
{
344+
return 2;
345+
}
346+
}
347+
348+
QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
349+
350+
QgsFeature f;
351+
while ( fit.nextFeature( f ) )
352+
featureList << QgsFeature( f );
353+
}
354+
355+
int addPartRet;
356+
foreach ( const QgsFeature& feat, featureList )
357+
{
358+
QList<QgsGeometry*> newGeometries;
359+
QList<QgsPoint> topologyTestPoints;
360+
splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
361+
if ( splitFunctionReturn == 0 )
362+
{
363+
//add new parts
364+
for ( int i = 0; i < newGeometries.size(); ++i )
365+
{
366+
addPartRet = feat.geometry()->addPart( newGeometries.at( i ) );
367+
if ( addPartRet != 0 )
368+
break;
369+
}
370+
371+
// For test only: Exception already thrown here...
372+
// feat.geometry()->asWkb();
373+
374+
if ( addPartRet == 0 )
375+
{
376+
L->editBuffer()->changeGeometry( feat.id(), feat.geometry() );
377+
}
378+
else
379+
{
380+
// Test addPartRet
381+
switch ( addPartRet )
382+
{
383+
case 1:
384+
QgsDebugMsg( "Not a multipolygon" );
385+
break;
386+
387+
case 2:
388+
QgsDebugMsg( "Not a valid geometry" );
389+
break;
390+
391+
case 3:
392+
QgsDebugMsg( "New polygon ring" );
393+
break;
394+
}
395+
}
396+
L->editBuffer()->changeGeometry( feat.id(), feat.geometry() );
397+
398+
if ( topologicalEditing )
399+
{
400+
QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
401+
for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
402+
{
403+
addTopologicalPoints( *topol_it );
404+
}
405+
}
406+
++numberOfSplittedParts;
407+
}
408+
else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
409+
{
410+
returnCode = splitFunctionReturn;
411+
}
412+
413+
qDeleteAll( newGeometries );
414+
}
415+
416+
if ( numberOfSplittedParts == 0 && selectedIds.size() > 0 )
417+
{
418+
//There is a selection but no feature has been split.
419+
//Maybe user forgot that only the selected features are split
420+
returnCode = 4;
421+
}
422+
423+
return returnCode;
424+
}
298425

299426

300427
int QgsVectorLayerEditUtils::addTopologicalPoints( QgsGeometry* geom )

‎src/core/qgsvectorlayereditutils.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ class CORE_EXPORT QgsVectorLayerEditUtils
7474
@return 0 in case of success*/
7575
int translateFeature( QgsFeatureId featureId, double dx, double dy );
7676

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

‎src/gui/qgisinterface.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ class GUI_EXPORT QgisInterface : public QObject
441441
virtual QAction *actionDeleteSelected() = 0;
442442
virtual QAction *actionMoveFeature() = 0;
443443
virtual QAction *actionSplitFeatures() = 0;
444+
virtual QAction *actionSplitParts() = 0;
444445
virtual QAction *actionAddRing() = 0;
445446
virtual QAction *actionAddPart() = 0;
446447
virtual QAction *actionSimplifyFeature() = 0;

‎src/ui/qgisapp.ui‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@
245245
<addaction name="mActionReshapeFeatures"/>
246246
<addaction name="mActionOffsetCurve"/>
247247
<addaction name="mActionSplitFeatures"/>
248+
<addaction name="mActionSplitParts"/>
248249
<addaction name="mActionMergeFeatures"/>
249250
<addaction name="mActionMergeFeatureAttributes"/>
250251
<addaction name="mActionNodeTool"/>
@@ -342,6 +343,7 @@
342343
<addaction name="mActionReshapeFeatures"/>
343344
<addaction name="mActionOffsetCurve"/>
344345
<addaction name="mActionSplitFeatures"/>
346+
<addaction name="mActionSplitParts"/>
345347
<addaction name="mActionMergeFeatures"/>
346348
<addaction name="mActionMergeFeatureAttributes"/>
347349
<addaction name="mActionRotatePointSymbols"/>
@@ -679,12 +681,24 @@
679681
</property>
680682
<property name="icon">
681683
<iconset resource="../../images/images.qrc">
682-
<normaloff>:/images/themes/default/mActionSplitFeatures.png</normaloff>:/images/themes/default/mActionSplitFeatures.png</iconset>
684+
<normaloff>:/images/themes/default/mActionSplitFeatures.svg</normaloff>:/images/themes/default/mActionSplitFeatures.svg</iconset>
683685
</property>
684686
<property name="text">
685687
<string>Split Features</string>
686688
</property>
687689
</action>
690+
<action name="mActionSplitParts">
691+
<property name="checkable">
692+
<bool>true</bool>
693+
</property>
694+
<property name="icon">
695+
<iconset resource="../../images/images.qrc">
696+
<normaloff>:/images/themes/default/mActionSplitFeatures.svg</normaloff>:/images/themes/default/mActionSplitFeatures.svg</iconset>
697+
</property>
698+
<property name="text">
699+
<string>Split Parts</string>
700+
</property>
701+
</action>
688702
<action name="mActionDeleteSelected">
689703
<property name="icon">
690704
<iconset resource="../../images/images.qrc">

0 commit comments

Comments
 (0)
Please sign in to comment.