Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #1344 from leyan/splitFeature
Split line feature with a single point when snapped to a line
  • Loading branch information
3nids committed May 23, 2014
2 parents 59129c4 + 4768a8f commit db328fe
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 5 deletions.
22 changes: 22 additions & 0 deletions src/app/qgsmaptoolsplitfeatures.cpp
Expand Up @@ -50,9 +50,26 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent( QMouseEvent * e )
return;
}

bool split = false;


//add point to list and to rubber band
if ( e->button() == Qt::LeftButton )
{
QList<QgsSnappingResult> snapResults;

//If we snap the first point on a vertex of a line layer, we directly split the feature at this point
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
{
if ( mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex ) == 0 )
{
if ( snapResults.size() > 0 )
{
split = true;
}
}
}

int error = addVertex( e->pos() );
if ( error == 1 )
{
Expand All @@ -73,6 +90,11 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent( QMouseEvent * e )
startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
split = true;
}

if ( split )
{
deleteTempRubberBand();

Expand Down
20 changes: 20 additions & 0 deletions src/app/qgsmaptoolsplitparts.cpp
Expand Up @@ -49,9 +49,25 @@ void QgsMapToolSplitParts::canvasReleaseEvent( QMouseEvent * e )
return;
}

bool split = false;

//add point to list and to rubber band
if ( e->button() == Qt::LeftButton )
{
QList<QgsSnappingResult> snapResults;

//If we snap the first point on a vertex of a line layer, we directly split the feature at this point
if ( vlayer->geometryType() == QGis::Line && points().isEmpty() )
{
if ( mSnapper.snapToCurrentLayer( e->pos(), snapResults, QgsSnapper::SnapToVertex ) == 0 )
{
if ( snapResults.size() > 0 )
{
split = true;
}
}
}

int error = addVertex( e->pos() );
if ( error == 1 )
{
Expand All @@ -72,6 +88,10 @@ void QgsMapToolSplitParts::canvasReleaseEvent( QMouseEvent * e )
startCapturing();
}
else if ( e->button() == Qt::RightButton )
{
split = true;
}
if ( split )
{
deleteTempRubberBand();

Expand Down
74 changes: 71 additions & 3 deletions src/core/qgsgeometry.cpp
Expand Up @@ -2878,14 +2878,27 @@ int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeome
return 7;

//make sure splitLine is valid
if ( splitLine.size() < 2 )
if (( type() == QGis::Line && splitLine.size() < 1 ) ||
( type() == QGis::Polygon && splitLine.size() < 2 ) )
return 1;

newGeometries.clear();

try
{
GEOSGeometry *splitLineGeos = createGeosLineString( splitLine.toVector() );
GEOSGeometry* splitLineGeos;
if ( splitLine.size() > 1 )
{
splitLineGeos = createGeosLineString( splitLine.toVector() );
}
else if ( splitLine.size() == 1 )
{
splitLineGeos = createGeosPoint( splitLine.at( 0 ) );
}
else
{
return 1;
}
if ( !GEOSisValid( splitLineGeos ) || !GEOSisSimple( splitLineGeos ) )
{
GEOSGeom_destroy( splitLineGeos );
Expand Down Expand Up @@ -4549,6 +4562,51 @@ void QgsGeometry::transformVertex( QgsWkbPtr &wkbPtr, const QgsCoordinateTransfo

}

GEOSGeometry* QgsGeometry::linePointDifference( GEOSGeometry* GEOSsplitPoint )
{
int type = GEOSGeomTypeId( mGeos );
QgsMultiPolyline multiLine;

if ( type == GEOS_MULTILINESTRING )
multiLine = asMultiPolyline();
else if ( type == GEOS_LINESTRING )
multiLine = QgsMultiPolyline() << asPolyline();
else
return 0;

QgsPoint splitPoint = fromGeosGeom( GEOSsplitPoint )->asPoint();

QgsMultiPolyline lines;
QgsPolyline line;
QgsPolyline newline;

//For each part
for ( int i = 0; i < multiLine.size() ; ++i )
{
line = multiLine[i];
newline = QgsPolyline();
newline.append( line[0] );
//For each segment
for ( int j = 1; j < line.size() - 1 ; ++j )
{
newline.append( line[j] );
if ( line[j] == splitPoint )
{
lines.append( newline );
newline = QgsPolyline();
newline.append( line[j] );
}
}
newline.append( line.last() );
lines.append( newline );
}
QgsGeometry* splitLines = fromMultiPolyline( lines );
GEOSGeometry* splitGeom = GEOSGeom_clone( splitLines->asGeos() );

return splitGeom;

}

int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries )
{
if ( !splitLine )
Expand All @@ -4569,7 +4627,17 @@ int QgsGeometry::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry
if ( linearIntersect > 0 )
return 3;

GEOSGeometry* splitGeom = GEOSDifference( mGeos, splitLine );
int splitGeomType = GEOSGeomTypeId( splitLine );

GEOSGeometry* splitGeom;
if ( splitGeomType == GEOS_POINT )
{
splitGeom = linePointDifference( splitLine );
}
else
{
splitGeom = GEOSDifference( mGeos, splitLine );
}
QVector<GEOSGeometry*> lineGeoms;

int splitType = GEOSGeomTypeId( splitGeom );
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsgeometry.h
Expand Up @@ -562,6 +562,9 @@ class CORE_EXPORT QgsGeometry
/**Splits polygon/multipolygon geometries
@return 0 in case of success, 1 if geometry has not been split, error else*/
int splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries );
/**Splits line/multiline geometries following a single point*/
GEOSGeometry* linePointDifference( GEOSGeometry* GEOSsplitPoint );

/**Finds out the points that need to be tested for topological correctnes if this geometry will be split
@return 0 in case of success*/
int topologicalTestPointsSplit( const GEOSGeometry* splitLine, QList<QgsPoint>& testPoints ) const;
Expand Down
18 changes: 16 additions & 2 deletions src/core/qgsvectorlayereditutils.cpp
Expand Up @@ -232,7 +232,14 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bo
}
else
{
return 2;
//If we have a single point, we still create a non-null box
double bufferDistance = 0.000001;
if ( L->crs().geographicFlag() )
bufferDistance = 0.00000001;
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
}
}

Expand Down Expand Up @@ -362,7 +369,14 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool
}
else
{
return 2;
//If we have a single point, we still create a non-null box
double bufferDistance = 0.000001;
if ( L->crs().geographicFlag() )
bufferDistance = 0.00000001;
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
bBox.setYMinimum( bBox.yMinimum() - bufferDistance );
bBox.setYMaximum( bBox.yMaximum() + bufferDistance );
}
}

Expand Down

0 comments on commit db328fe

Please sign in to comment.