Add method to add a linestring to compound curves where we extend

the existing final part if it's a linestring and the newly added
curve is also a linestring, instead of adding a whole new curve
This commit is contained in:
Nyall Dawson 2021-03-04 13:53:37 +10:00
parent 0908a0990e
commit afccd31720
5 changed files with 89 additions and 31 deletions

View File

@ -93,9 +93,15 @@ Returns the number of curves in the geometry.
Returns the curve at the specified index.
%End
void addCurve( QgsCurve *c /Transfer/ );
void addCurve( QgsCurve *c /Transfer/, bool extendPrevious = false );
%Docstring
Adds a curve to the geometry (takes ownership)
Adds a curve to the geometry (takes ownership).
Since QGIS 3.20, if ``extendPrevious`` is ``True``, then adding a LineString when the last existing curve
in the compound curve is also a LineString will cause the existing linestring to be
extended with the newly added LineString vertices instead of appending a whole new
LineString curve to the compound curve. This can result in simplified compound curves with lesser number
of component curves while still being topologically identical to the desired result.
%End
void removeCurve( int i );

View File

@ -474,35 +474,49 @@ const QgsCurve *QgsCompoundCurve::curveAt( int i ) const
return mCurves.at( i );
}
void QgsCompoundCurve::addCurve( QgsCurve *c )
void QgsCompoundCurve::addCurve( QgsCurve *c, const bool extendPrevious )
{
if ( c )
if ( !c )
return;
if ( mCurves.empty() )
{
if ( mCurves.empty() )
{
setZMTypeFromSubGeometry( c, QgsWkbTypes::CompoundCurve );
}
mCurves.append( c );
if ( QgsWkbTypes::hasZ( mWkbType ) && !QgsWkbTypes::hasZ( c->wkbType() ) )
{
c->addZValue();
}
else if ( !QgsWkbTypes::hasZ( mWkbType ) && QgsWkbTypes::hasZ( c->wkbType() ) )
{
c->dropZValue();
}
if ( QgsWkbTypes::hasM( mWkbType ) && !QgsWkbTypes::hasM( c->wkbType() ) )
{
c->addMValue();
}
else if ( !QgsWkbTypes::hasM( mWkbType ) && QgsWkbTypes::hasM( c->wkbType() ) )
{
c->dropMValue();
}
clearCache();
setZMTypeFromSubGeometry( c, QgsWkbTypes::CompoundCurve );
}
if ( QgsWkbTypes::hasZ( mWkbType ) && !QgsWkbTypes::hasZ( c->wkbType() ) )
{
c->addZValue();
}
else if ( !QgsWkbTypes::hasZ( mWkbType ) && QgsWkbTypes::hasZ( c->wkbType() ) )
{
c->dropZValue();
}
if ( QgsWkbTypes::hasM( mWkbType ) && !QgsWkbTypes::hasM( c->wkbType() ) )
{
c->addMValue();
}
else if ( !QgsWkbTypes::hasM( mWkbType ) && QgsWkbTypes::hasM( c->wkbType() ) )
{
c->dropMValue();
}
QgsLineString *previousLineString = !mCurves.empty() ? qgsgeometry_cast< QgsLineString * >( mCurves.constLast() ) : nullptr;
const QgsLineString *newLineString = qgsgeometry_cast< const QgsLineString * >( c );
const bool canExtendPrevious = extendPrevious && previousLineString && newLineString;
if ( canExtendPrevious )
{
previousLineString->append( newLineString );
// we are taking ownership, so delete the input curve
delete c;
c = nullptr;
}
else
{
mCurves.append( c );
}
clearCache();
}
void QgsCompoundCurve::removeCurve( int i )

View File

@ -84,9 +84,15 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve
const QgsCurve *curveAt( int i ) const SIP_HOLDGIL;
/**
* Adds a curve to the geometry (takes ownership)
* Adds a curve to the geometry (takes ownership).
*
* Since QGIS 3.20, if \a extendPrevious is TRUE, then adding a LineString when the last existing curve
* in the compound curve is also a LineString will cause the existing linestring to be
* extended with the newly added LineString vertices instead of appending a whole new
* LineString curve to the compound curve. This can result in simplified compound curves with lesser number
* of component curves while still being topologically identical to the desired result.
*/
void addCurve( QgsCurve *c SIP_TRANSFER );
void addCurve( QgsCurve *c SIP_TRANSFER, bool extendPrevious = false );
/**
* Removes a curve from the geometry.

View File

@ -914,7 +914,7 @@ void QgsLineString::append( const QgsLineString *line )
setZMTypeFromSubGeometry( line, QgsWkbTypes::LineString );
}
// do not store duplicit points
// do not store duplicate points
if ( numPoints() > 0 &&
line->numPoints() > 0 &&
endPoint() == line->startPoint() )

View File

@ -10319,6 +10319,38 @@ void TestQgsGeometry::compoundCurve()
<< QgsPoint( QgsWkbTypes::PointM, 3, 4, 0, 9 ) );
c8.removeCurve( 1 );
// add curve and extend existing
QgsCompoundCurve c8j;
// try to extend empty compound curve
l8.setPoints( QgsPointSequence() << QgsPoint( 1, 2 ) << QgsPoint( 2, 3 ) << QgsPoint( 3, 4 ) );
c8j.addCurve( l8.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4))" ) );
// try to add another curve with extend existing as true - should be ignored.
l8.setPoints( QgsPointSequence() << QgsPoint( 6, 6 ) << QgsPoint( 7, 8 ) );
c8j.addCurve( l8.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8))" ) );
// try to add a linestring with extend existing as true - should be ignored because the last curve isn't a linestring
QgsLineString l8j;
l8j.setPoints( QgsPointSequence() << QgsPoint( 10, 8 ) << QgsPoint( 10, 12 ) );
c8j.addCurve( l8j.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12))" ) );
// try to extend with another linestring -- should add to final part
l8j.setPoints( QgsPointSequence() << QgsPoint( 11, 13 ) << QgsPoint( 12, 12 ) );
c8j.addCurve( l8j.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12))" ) );
// try to extend with another linestring -- should add to final part, with no duplicate points
l8j.setPoints( QgsPointSequence() << QgsPoint( 12, 12 ) << QgsPoint( 13, 12 ) << QgsPoint( 14, 15 ) );
c8j.addCurve( l8j.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12, 13 12, 14 15))" ) );
// not extending, should be added as new curve
l8j.setPoints( QgsPointSequence() << QgsPoint( 15, 16 ) << QgsPoint( 17, 12 ) );
c8j.addCurve( l8j.clone(), false );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve (CircularString (1 2, 2 3, 3 4),CircularString (6 6, 7 8),(10 8, 10 12, 11 13, 12 12, 13 12, 14 15),(15 16, 17 12))" ) );
c8j.clear();
// adding a linestring as first part, with extend as true
c8j.addCurve( l8j.clone(), true );
QCOMPARE( c8j.asWkt(), QStringLiteral( "CompoundCurve ((15 16, 17 12))" ) );
//test getters/setters
QgsCompoundCurve c9;