Skip to content

Commit db328fe

Browse files
committed
Merge pull request #1344 from leyan/splitFeature
Split line feature with a single point when snapped to a line
2 parents 59129c4 + 4768a8f commit db328fe

5 files changed

+132
-5
lines changed

src/app/qgsmaptoolsplitfeatures.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,26 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent( QMouseEvent * e )
5050
return;
5151
}
5252

53+
bool split = false;
54+
55+
5356
//add point to list and to rubber band
5457
if ( e->button() == Qt::LeftButton )
5558
{
59+
QList<QgsSnappingResult> snapResults;
60+
61+
//If we snap the first point on a vertex of a line layer, we directly split the feature at this point
62+
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
63+
{
64+
if ( mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex ) == 0 )
65+
{
66+
if ( snapResults.size() > 0 )
67+
{
68+
split = true;
69+
}
70+
}
71+
}
72+
5673
int error = addVertex( e->pos() );
5774
if ( error == 1 )
5875
{
@@ -73,6 +90,11 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent( QMouseEvent * e )
7390
startCapturing();
7491
}
7592
else if ( e->button() == Qt::RightButton )
93+
{
94+
split = true;
95+
}
96+
97+
if ( split )
7698
{
7799
deleteTempRubberBand();
78100

src/app/qgsmaptoolsplitparts.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,25 @@ void QgsMapToolSplitParts::canvasReleaseEvent( QMouseEvent * e )
4949
return;
5050
}
5151

52+
bool split = false;
53+
5254
//add point to list and to rubber band
5355
if ( e->button() == Qt::LeftButton )
5456
{
57+
QList<QgsSnappingResult> snapResults;
58+
59+
//If we snap the first point on a vertex of a line layer, we directly split the feature at this point
60+
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
61+
{
62+
if ( mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex ) == 0 )
63+
{
64+
if ( snapResults.size() > 0 )
65+
{
66+
split = true;
67+
}
68+
}
69+
}
70+
5571
int error = addVertex( e->pos() );
5672
if ( error == 1 )
5773
{
@@ -72,6 +88,10 @@ void QgsMapToolSplitParts::canvasReleaseEvent( QMouseEvent * e )
7288
startCapturing();
7389
}
7490
else if ( e->button() == Qt::RightButton )
91+
{
92+
split = true;
93+
}
94+
if ( split )
7595
{
7696
deleteTempRubberBand();
7797

src/core/qgsgeometry.cpp

+71-3
Original file line numberDiff line numberDiff line change
@@ -2878,14 +2878,27 @@ int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeome
28782878
return 7;
28792879

28802880
//make sure splitLine is valid
2881-
if ( splitLine.size() < 2 )
2881+
if (( type() == QGis::Line && splitLine.size() < 1 ) ||
2882+
( type() == QGis::Polygon && splitLine.size() < 2 ) )
28822883
return 1;
28832884

28842885
newGeometries.clear();
28852886

28862887
try
28872888
{
2888-
GEOSGeometry *splitLineGeos = createGeosLineString( splitLine.toVector() );
2889+
GEOSGeometry* splitLineGeos;
2890+
if ( splitLine.size() > 1 )
2891+
{
2892+
splitLineGeos = createGeosLineString( splitLine.toVector() );
2893+
}
2894+
else if ( splitLine.size() == 1 )
2895+
{
2896+
splitLineGeos = createGeosPoint( splitLine.at( 0 ) );
2897+
}
2898+
else
2899+
{
2900+
return 1;
2901+
}
28892902
if ( !GEOSisValid( splitLineGeos ) || !GEOSisSimple( splitLineGeos ) )
28902903
{
28912904
GEOSGeom_destroy( splitLineGeos );
@@ -4549,6 +4562,51 @@ void QgsGeometry::transformVertex( QgsWkbPtr &wkbPtr, const QgsCoordinateTransfo
45494562

45504563
}
45514564

4565+
GEOSGeometry* QgsGeometry::linePointDifference( GEOSGeometry* GEOSsplitPoint )
4566+
{
4567+
int type = GEOSGeomTypeId( mGeos );
4568+
QgsMultiPolyline multiLine;
4569+
4570+
if ( type == GEOS_MULTILINESTRING )
4571+
multiLine = asMultiPolyline();
4572+
else if ( type == GEOS_LINESTRING )
4573+
multiLine = QgsMultiPolyline() << asPolyline();
4574+
else
4575+
return 0;
4576+
4577+
QgsPoint splitPoint = fromGeosGeom( GEOSsplitPoint )->asPoint();
4578+
4579+
QgsMultiPolyline lines;
4580+
QgsPolyline line;
4581+
QgsPolyline newline;
4582+
4583+
//For each part
4584+
for ( int i = 0; i < multiLine.size() ; ++i )
4585+
{
4586+
line = multiLine[i];
4587+
newline = QgsPolyline();
4588+
newline.append( line[0] );
4589+
//For each segment
4590+
for ( int j = 1; j < line.size() - 1 ; ++j )
4591+
{
4592+
newline.append( line[j] );
4593+
if ( line[j] == splitPoint )
4594+
{
4595+
lines.append( newline );
4596+
newline = QgsPolyline();
4597+
newline.append( line[j] );
4598+
}
4599+
}
4600+
newline.append( line.last() );
4601+
lines.append( newline );
4602+
}
4603+
QgsGeometry* splitLines = fromMultiPolyline( lines );
4604+
GEOSGeometry* splitGeom = GEOSGeom_clone( splitLines->asGeos() );
4605+
4606+
return splitGeom;
4607+
4608+
}
4609+
45524610
int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries )
45534611
{
45544612
if ( !splitLine )
@@ -4569,7 +4627,17 @@ int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry
45694627
if ( linearIntersect > 0 )
45704628
return 3;
45714629

4572-
GEOSGeometry* splitGeom = GEOSDifference( mGeos, splitLine );
4630+
int splitGeomType = GEOSGeomTypeId( splitLine );
4631+
4632+
GEOSGeometry* splitGeom;
4633+
if ( splitGeomType == GEOS_POINT )
4634+
{
4635+
splitGeom = linePointDifference( splitLine );
4636+
}
4637+
else
4638+
{
4639+
splitGeom = GEOSDifference( mGeos, splitLine );
4640+
}
45734641
QVector<GEOSGeometry*> lineGeoms;
45744642

45754643
int splitType = GEOSGeomTypeId( splitGeom );

src/core/qgsgeometry.h

+3
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,9 @@ class CORE_EXPORT QgsGeometry
562562
/**Splits polygon/multipolygon geometries
563563
@return 0 in case of success, 1 if geometry has not been split, error else*/
564564
int splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries );
565+
/**Splits line/multiline geometries following a single point*/
566+
GEOSGeometry* linePointDifference( GEOSGeometry* GEOSsplitPoint );
567+
565568
/**Finds out the points that need to be tested for topological correctnes if this geometry will be split
566569
@return 0 in case of success*/
567570
int topologicalTestPointsSplit( const GEOSGeometry* splitLine, QList<QgsPoint>& testPoints ) const;

src/core/qgsvectorlayereditutils.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,14 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
232232
}
233233
else
234234
{
235-
return 2;
235+
//If we have a single point, we still create a non-null box
236+
double bufferDistance = 0.000001;
237+
if ( L->crs().geographicFlag() )
238+
bufferDistance = 0.00000001;
239+
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
240+
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
241+
bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
242+
bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
236243
}
237244
}
238245

@@ -362,7 +369,14 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
362369
}
363370
else
364371
{
365-
return 2;
372+
//If we have a single point, we still create a non-null box
373+
double bufferDistance = 0.000001;
374+
if ( L->crs().geographicFlag() )
375+
bufferDistance = 0.00000001;
376+
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
377+
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
378+
bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
379+
bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
366380
}
367381
}
368382

0 commit comments

Comments
 (0)