Fix for problem where splitting was slow for large polygons and with topological editing enabled (bug #1161)

git-svn-id: http://svn.osgeo.org/qgis/trunk@9351 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
mhugent 2008-09-19 06:54:12 +00:00
parent 6cc1f3d3a0
commit 6506e6d176
4 changed files with 93 additions and 24 deletions

View File

@ -192,15 +192,14 @@ not disjoint with existing polygons of the feature*/
@return 0 in case of success*/ @return 0 in case of success*/
int translate(double dx, double dy); int translate(double dx, double dy);
/**Splits this geometry according to a given line. Note that the geometry is only splitted once. If there are several intersections /**Splits this geometry according to a given line. Note that the geometry is only splitted once. If there are several intersections
between geometry and splitLine, only the first one is considered. between geometry and splitLine, only the first one is considered.
@param splitLine the line that splits the geometry @param splitLine the line that splits the geometry
@param newGeometrys OUT: list of new geometries that have been created with the split @param newGeometrys OUT: list of new geometries that have been created with the split
@return 0 in case of success, which means the geometry has been split in two parts, \ @param topological true if topological editing is enabled
1 if line intersects multiple times but only one split could be done, \ @topologyTestPoints OUT: points that need to be tested for topological completeness in the dataset
2 if intersection too complicated to proceed (several polygon intersections), \ \ @return 0 in case of success, 1 if geometry has not been split, error else*/
else other error*/ int splitGeometry(const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint>& topologyTestPoints);
int splitGeometry(const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries);
/**Changes this geometry such that it does not intersect the other geometry /**Changes this geometry such that it does not intersect the other geometry
@param other geometry that should not be intersect @param other geometry that should not be intersect

View File

@ -3119,7 +3119,7 @@ int QgsGeometry::transform( QgsCoordinateTransform& ct )
return 0; return 0;
} }
int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries ) int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint>& topologyTestPoints )
{ {
int returnCode = 0; int returnCode = 0;
@ -3156,7 +3156,16 @@ int QgsGeometry::splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeome
return 1; return 1;
} }
//for line/multiline: call splitLinearGeometry if(topological)
{
//find out candidate points for topological corrections
if(topologicalTestPointsSplit(splitLineGeos, topologyTestPoints) != 0)
{
return 1;
}
}
//call split function depending on geometry type
if ( vectorType() == QGis::Line ) if ( vectorType() == QGis::Line )
{ {
returnCode = splitLinearGeometry( splitLineGeos, newGeometries ); returnCode = splitLinearGeometry( splitLineGeos, newGeometries );
@ -4885,6 +4894,64 @@ int QgsGeometry::splitPolygonGeometry( GEOSGeometry* splitLine, QList<QgsGeometr
return 0; return 0;
} }
int QgsGeometry::topologicalTestPointsSplit( const GEOSGeometry* splitLine, QList<QgsPoint>& testPoints) const
{
//Find out the intersection points between splitLineGeos and this geometry.
//These points need to be tested for topological correctness by the calling function
//if topological editing is enabled
testPoints.clear();
GEOSGeometry* intersectionGeom = GEOSIntersection(mGeos, splitLine);
if(intersectionGeom == NULL)
{
return 1;
}
bool simple = false;
int nIntersectGeoms = 1;
if(GEOSGeomTypeId(intersectionGeom) == (GEOS_LINESTRING) || GEOSGeomTypeId(intersectionGeom) == (GEOS_POINT))
{
simple = true;
}
if(!simple)
{
nIntersectGeoms = GEOSGetNumGeometries(intersectionGeom);
}
for(int i = 0; i < nIntersectGeoms; ++i)
{
GEOSGeometry* currentIntersectGeom;
if(simple)
{
currentIntersectGeom = intersectionGeom;
}
else
{
currentIntersectGeom = GEOSGetGeometryN(intersectionGeom, i);
}
GEOSCoordSequence* lineSequence = GEOSGeom_getCoordSeq(currentIntersectGeom);
unsigned int sequenceSize = 0;
double x, y;
if(GEOSCoordSeq_getSize(lineSequence, &sequenceSize) != 0)
{
for(int i = 0; i < sequenceSize; ++i)
{
if(GEOSCoordSeq_getX(lineSequence, i, &x) != 0)
{
if(GEOSCoordSeq_getY(lineSequence, i, &y) != 0)
{
testPoints.push_back(QgsPoint(x, y));
}
}
}
}
}
GEOSGeom_destroy(intersectionGeom);
return 0;
}
GEOSGeometry *QgsGeometry::nodeGeometries( const GEOSGeometry *splitLine, GEOSGeometry *geom ) const GEOSGeometry *QgsGeometry::nodeGeometries( const GEOSGeometry *splitLine, GEOSGeometry *geom ) const
{ {
if ( !splitLine || !geom ) if ( !splitLine || !geom )

View File

@ -242,8 +242,10 @@ class CORE_EXPORT QgsGeometry
between geometry and splitLine, only the first one is considered. between geometry and splitLine, only the first one is considered.
@param splitLine the line that splits the geometry @param splitLine the line that splits the geometry
@param newGeometrys OUT: list of new geometries that have been created with the split @param newGeometrys OUT: list of new geometries that have been created with the split
@param topological true if topological editing is enabled
@topologyTestPoints OUT: points that need to be tested for topological completeness in the dataset
@return 0 in case of success, 1 if geometry has not been split, error else*/ @return 0 in case of success, 1 if geometry has not been split, error else*/
int splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries ); int splitGeometry( const QList<QgsPoint>& splitLine, QList<QgsGeometry*>& newGeometries, bool topological, QList<QgsPoint>& topologyTestPoints);
/**Changes this geometry such that it does not intersect the other geometry /**Changes this geometry such that it does not intersect the other geometry
@param other geometry that should not be intersect @param other geometry that should not be intersect
@ -398,12 +400,13 @@ class CORE_EXPORT QgsGeometry
@splitLine the line that splits the feature @splitLine the line that splits the feature
@newGeometry new geometry if splitting was successful @newGeometry new geometry if splitting was successful
@return 0 in case of success, 1 if geometry has not been split, error else*/ @return 0 in case of success, 1 if geometry has not been split, error else*/
int splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries ); int splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries);
/**Splits polygon/multipolygon geometries /**Splits polygon/multipolygon geometries
@return 0 in case of success, 1 if geometry has not been split, error else*/ @return 0 in case of success, 1 if geometry has not been split, error else*/
int splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries ); int splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsGeometry*>& newGeometries );
/**Finds the vertices next to point where the line is split. If it is split at a vertex, beforeVertex /**Finds out the points that need to be tested for topological correctnes if this geometry will be split
and afterVertex are the same*/ @return 0 in case of success*/
int topologicalTestPointsSplit( const GEOSGeometry* splitLine, QList<QgsPoint>& testPoints) const;
/**Nodes together a split line and a (multi-) polygon geometry in a multilinestring /**Nodes together a split line and a (multi-) polygon geometry in a multilinestring
@return the noded multiline geometry or 0 in case of error. The calling function takes ownership of the node geometry*/ @return the noded multiline geometry or 0 in case of error. The calling function takes ownership of the node geometry*/

View File

@ -1722,8 +1722,9 @@ int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topolo
for ( ; select_it != featureList.end(); ++select_it ) for ( ; select_it != featureList.end(); ++select_it )
{ {
QList<QgsGeometry*> newGeometries; QList<QgsGeometry*> newGeometries;
QList<QgsPoint> topologyTestPoints;
QgsGeometry* newGeometry = 0; QgsGeometry* newGeometry = 0;
splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries ); splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints);
if ( splitFunctionReturn == 0 ) if ( splitFunctionReturn == 0 )
{ {
//change this geometry //change this geometry
@ -1737,18 +1738,17 @@ int QgsVectorLayer::splitFeatures( const QList<QgsPoint>& splitLine, bool topolo
newFeature.setGeometry( newGeometry ); newFeature.setGeometry( newGeometry );
newFeature.setAttributeMap( select_it->attributeMap() ); newFeature.setAttributeMap( select_it->attributeMap() );
newFeatures.append( newFeature ); newFeatures.append( newFeature );
if ( topologicalEditing ) //add topological points for new feature
{
addTopologicalPoints( newGeometry );
}
} }
setModified( true, true );
//add topological points for this geometry if necessary setModified( true, true );
if ( topologicalEditing ) if(topologicalEditing)
{ {
addTopologicalPoints( select_it->geometry() ); QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin();
} for(; topol_it != topologyTestPoints.constEnd(); ++topol_it)
{
addTopologicalPoints(*topol_it);
}
}
} }
else if ( splitFunctionReturn > 1 ) //1 means no split but also no error else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
{ {