Skip to content

Commit 33343d6

Browse files
committed
Want to get split feature to work with a single point to split a line
1 parent dd739ef commit 33343d6

5 files changed

+190
-8
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 line layer, we directly split the feature at this point
62+
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
63+
{
64+
if ( mSnapper.snapToBackgroundLayers( e->pos(), snapResults ) == 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 line layer, we directly split the feature at this point
60+
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
61+
{
62+
if ( mSnapper.snapToBackgroundLayers( e->pos(), snapResults ) == 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

+135-6
Original file line numberDiff line numberDiff line change
@@ -2878,14 +2878,35 @@ 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 ( splitLine.size() < 1 )
28822882
return 1;
28832883

2884+
// Treat the special case of a single point to split a line without geos
2885+
if ( splitLine.size() == 1 )
2886+
{
2887+
//A point cannot split a polygon
2888+
if ( type() == QGis::Polygon )
2889+
return 1;
2890+
//return splitLinearGeometryAtPoint( splitLine[0], newGeometries );
2891+
}
2892+
28842893
newGeometries.clear();
28852894

28862895
try
28872896
{
2888-
GEOSGeometry *splitLineGeos = createGeosLineString( splitLine.toVector() );
2897+
GEOSGeometry* splitLineGeos;
2898+
if ( splitLine.size() > 1 )
2899+
{
2900+
splitLineGeos = createGeosLineString( splitLine.toVector() );
2901+
}
2902+
else if ( splitLine.size() == 1 )
2903+
{
2904+
splitLineGeos = createGeosPoint( splitLine.at( 0 ) );
2905+
}
2906+
else
2907+
{
2908+
return 1;
2909+
}
28892910
if ( !GEOSisValid( splitLineGeos ) || !GEOSisSimple( splitLineGeos ) )
28902911
{
28912912
GEOSGeom_destroy( splitLineGeos );
@@ -4549,6 +4570,105 @@ void QgsGeometry::transformVertex( QgsWkbPtr &wkbPtr, const QgsCoordinateTransfo
45494570

45504571
}
45514572

4573+
GEOSGeometry* QgsGeometry::linePointDifference( GEOSGeometry* GEOSsplitPoint )
4574+
{
4575+
int type = GEOSGeomTypeId( mGeos );
4576+
QgsMultiPolyline multiLine;
4577+
4578+
if ( type == GEOS_MULTILINESTRING )
4579+
multiLine = asMultiPolyline();
4580+
else if ( type == GEOS_LINESTRING )
4581+
multiLine = QgsMultiPolyline() << asPolyline();
4582+
else
4583+
return 0;
4584+
4585+
QgsPoint splitPoint = fromGeosGeom( GEOSsplitPoint )->asPoint();
4586+
4587+
QgsPoint p1, p2;
4588+
QgsGeometry* g;
4589+
QgsMultiPolyline lines;
4590+
QgsPolyline line;
4591+
QgsPolyline newline;
4592+
4593+
//For each part
4594+
for ( int i = 0; i < multiLine.size() ; ++i )
4595+
{
4596+
line = multiLine[i];
4597+
//For each segment
4598+
newline = QgsPolyline();
4599+
for ( int j = 1; j < line.size() ; ++j )
4600+
{
4601+
p1 = line[j-1];
4602+
p2 = line[j];
4603+
g = QgsGeometry::fromPolyline( QgsPolyline() << p1 << p2 );
4604+
QgsDebugMsg( g->exportToWkt() );
4605+
QgsDebugMsg( splitPoint.toString() );
4606+
4607+
newline.append( p1 );
4608+
4609+
double x1 = p1.x();
4610+
double y1 = p1.y();
4611+
double x2 = p2.x();
4612+
double y2 = p2.y();
4613+
double xt = splitPoint.x();
4614+
double yt = splitPoint.y();
4615+
double k;
4616+
double diff;
4617+
if ( x2 == x1 )
4618+
{
4619+
if ( y2 == y1 )
4620+
{
4621+
k = -1;
4622+
diff = 1e50;
4623+
}
4624+
else
4625+
{
4626+
k = ( yt - y1 ) / ( y2 - y1 );
4627+
diff = k * ( x2 - x1 ) - ( xt - x1 );
4628+
}
4629+
}
4630+
else
4631+
{
4632+
k = ( xt - x1 ) / ( x2 - x1 );
4633+
diff = k * ( y2 - y1 ) - ( yt - y1 );
4634+
}
4635+
if ( abs( diff ) < 1e-7 )
4636+
{
4637+
if ( k == 0 )
4638+
{
4639+
lines.append( newline );
4640+
newline = QgsPolyline();
4641+
newline.append( p1 );
4642+
}
4643+
if ( k == 1 )
4644+
{
4645+
newline.append( p2 );
4646+
lines.append( newline );
4647+
newline = QgsPolyline();
4648+
}
4649+
if ( k > 0 && k < 1 )
4650+
{
4651+
newline.append( splitPoint );
4652+
lines.append( newline );
4653+
newline = QgsPolyline();
4654+
newline.append( splitPoint );
4655+
}
4656+
if ( k < 0 || k > 1 )
4657+
{
4658+
//Nothing happens, we are on the line but not the segment
4659+
}
4660+
}
4661+
}
4662+
newline.append( line.last() );
4663+
lines.append( newline );
4664+
}
4665+
QgsGeometry* splitLines = fromMultiPolyline( lines );
4666+
GEOSGeometry* splitGeom = GEOSGeom_clone( splitLines->asGeos() );
4667+
4668+
return splitGeom;
4669+
4670+
}
4671+
45524672
int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries )
45534673
{
45544674
if ( !splitLine )
@@ -4560,16 +4680,25 @@ int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry
45604680
if ( !mGeos )
45614681
return 5;
45624682

4563-
//first test if linestring intersects geometry. If not, return straight away
4564-
if ( !GEOSIntersects( splitLine, mGeos ) )
4565-
return 1;
45664683

45674684
//check that split line has no linear intersection
45684685
int linearIntersect = GEOSRelatePattern( mGeos, splitLine, "1********" );
45694686
if ( linearIntersect > 0 )
45704687
return 3;
45714688

4572-
GEOSGeometry* splitGeom = GEOSDifference( mGeos, splitLine );
4689+
int splitGeomType = GEOSGeomTypeId( splitLine );
4690+
//first test if linestring intersects geometry. If not, return straight away
4691+
if ( splitGeomType == GEOS_LINESTRING && !GEOSIntersects( splitLine, mGeos ) )
4692+
return 1;
4693+
GEOSGeometry* splitGeom;
4694+
if ( splitGeomType == GEOS_LINESTRING )
4695+
{
4696+
splitGeom = GEOSDifference( mGeos, splitLine );
4697+
}
4698+
else
4699+
{
4700+
splitGeom = linePointDifference( splitLine );
4701+
}
45734702
QVector<GEOSGeometry*> lineGeoms;
45744703

45754704
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

+10-2
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,11 @@ 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+
bBox.setXMinimum( bBox.xMinimum() - 1 );
237+
bBox.setXMaximum( bBox.xMaximum() + 1 );
238+
bBox.setYMinimum( bBox.yMinimum() - 1 );
239+
bBox.setYMaximum( bBox.yMaximum() + 1 );
236240
}
237241
}
238242

@@ -362,7 +366,11 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
362366
}
363367
else
364368
{
365-
return 2;
369+
//If we have a single point, we still create a non-null box
370+
bBox.setXMinimum( bBox.xMinimum() - 1 );
371+
bBox.setXMaximum( bBox.xMaximum() + 1 );
372+
bBox.setYMinimum( bBox.yMinimum() - 1 );
373+
bBox.setYMaximum( bBox.yMaximum() + 1 );
366374
}
367375
}
368376

0 commit comments

Comments
 (0)