Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add api to condense compound curves by merging adjacent parts of the
same type to single parts
  • Loading branch information
nyalldawson committed Apr 28, 2021
1 parent b65e37a commit 417d444
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
8 changes: 8 additions & 0 deletions python/core/auto_generated/geometry/qgscompoundcurve.sip.in
Expand Up @@ -117,6 +117,14 @@ Removes a curve from the geometry.
void addVertex( const QgsPoint &pt );
%Docstring
Adds a vertex to the end of the geometry.
%End

void condenseCurves();
%Docstring
Condenses the curves in this geometry by combining adjacent linestrings a to a single continuous linestring,
and combining adjacent circularstrings to a single continuous circularstring.

.. versionadded:: 3.20
%End

virtual void draw( QPainter &p ) const;
Expand Down
29 changes: 29 additions & 0 deletions src/core/geometry/qgscompoundcurve.cpp
Expand Up @@ -638,6 +638,35 @@ void QgsCompoundCurve::addVertex( const QgsPoint &pt )
clearCache();
}

void QgsCompoundCurve::condenseCurves()
{
QgsCurve *lastCurve = nullptr;
QVector< QgsCurve * > newCurves;
newCurves.reserve( mCurves.size() );
for ( QgsCurve *curve : std::as_const( mCurves ) )
{
if ( lastCurve && lastCurve->wkbType() == curve->wkbType() )
{
if ( QgsLineString *ls = qgsgeometry_cast< QgsLineString * >( lastCurve ) )
{
ls->append( qgsgeometry_cast< QgsLineString * >( curve ) );
delete curve;
}
else if ( QgsCircularString *cs = qgsgeometry_cast< QgsCircularString * >( lastCurve ) )
{
cs->append( qgsgeometry_cast< QgsCircularString * >( curve ) );
delete curve;
}
}
else
{
lastCurve = curve;
newCurves << curve;
}
}
mCurves = newCurves;
}

void QgsCompoundCurve::draw( QPainter &p ) const
{
for ( const QgsCurve *curve : mCurves )
Expand Down
8 changes: 8 additions & 0 deletions src/core/geometry/qgscompoundcurve.h
Expand Up @@ -107,6 +107,14 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve
*/
void addVertex( const QgsPoint &pt );

/**
* Condenses the curves in this geometry by combining adjacent linestrings a to a single continuous linestring,
* and combining adjacent circularstrings to a single continuous circularstring.
*
* \since QGIS 3.20
*/
void condenseCurves();

void draw( QPainter &p ) const override;
void transform( const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform, bool transformZ = false ) override SIP_THROW( QgsCsException );
void transform( const QTransform &t, double zTranslate = 0.0, double zScale = 1.0, double mTranslate = 0.0, double mScale = 1.0 ) override;
Expand Down
33 changes: 32 additions & 1 deletion tests/src/core/testqgsgeometry.cpp
Expand Up @@ -134,7 +134,11 @@ class TestQgsGeometry : public QObject
void ellipse();
void quadrilateral();
void regularPolygon();
void compoundCurve(); //test QgsCompoundCurve

void compoundCurve();
void compoundCurveCondense_data();
void compoundCurveCondense();

void multiPoint();
void multiLineString();
void multiCurve();
Expand Down Expand Up @@ -12629,6 +12633,33 @@ void TestQgsGeometry::compoundCurve()
QCOMPARE( orientation.orientation(), QgsCurve::CounterClockwise );
}

void TestQgsGeometry::compoundCurveCondense_data()
{
QTest::addColumn<QString>( "curve" );
QTest::addColumn<QString>( "expected" );

QTest::newRow( "compound curve empty" ) << QStringLiteral( "COMPOUNDCURVE()" ) << QStringLiteral( "CompoundCurve EMPTY" );
QTest::newRow( "compound curve one line" ) << QStringLiteral( "COMPOUNDCURVE((1 1, 1 2))" ) << QStringLiteral( "CompoundCurve ((1 1, 1 2))" );
QTest::newRow( "compound curve one circular string" ) << QStringLiteral( "COMPOUNDCURVE(CIRCULARSTRING(1 1, 1 2, 2 2))" ) << QStringLiteral( "CompoundCurve (CircularString (1 1, 1 2, 2 2))" );
QTest::newRow( "compound curve can't condense" ) << QStringLiteral( "COMPOUNDCURVE((1 5, 1 4, 1 1),CIRCULARSTRING(1 1, 1 2, 2 2),(2 2, 2 3),CIRCULARSTRING(2 3, 2 0, 2 1))" ) << QStringLiteral( "CompoundCurve ((1 5, 1 4, 1 1),CircularString (1 1, 1 2, 2 2),(2 2, 2 3),CircularString (2 3, 2 0, 2 1))" );
QTest::newRow( "compound curve two lines" ) << QStringLiteral( "COMPOUNDCURVE((1 5, 1 4, 1 1),(1 1, 1 0, 3 0))" ) << QStringLiteral( "CompoundCurve ((1 5, 1 4, 1 1, 1 0, 3 0))" );
QTest::newRow( "compound curve three lines" ) << QStringLiteral( "COMPOUNDCURVE((1 5, 1 4, 1 1),(1 1, 1 0, 3 0),(3 0, 4 0, 5 0))" ) << QStringLiteral( "CompoundCurve ((1 5, 1 4, 1 1, 1 0, 3 0, 4 0, 5 0))" );
QTest::newRow( "compound curve two lines and cs" ) << QStringLiteral( "COMPOUNDCURVE((1 5, 1 4, 1 1),(1 1, 1 0, 3 0),CIRCULARSTRING(3 0, 4 0, 5 0))" ) << QStringLiteral( "CompoundCurve ((1 5, 1 4, 1 1, 1 0, 3 0),CircularString (3 0, 4 0, 5 0))" );
QTest::newRow( "compound curve two cs" ) << QStringLiteral( "COMPOUNDCURVE(CIRCULARSTRING(1 5, 1 4, 1 1),CIRCULARSTRING(1 1, 1 0, 3 0))" ) << QStringLiteral( "CompoundCurve (CircularString (1 5, 1 4, 1 1, 1 0, 3 0))" );
QTest::newRow( "compound curve complex" ) << QStringLiteral( "COMPOUNDCURVE((1 5, 1 4, 1 1),(1 1, 1 0, 3 0),CIRCULARSTRING(3 0, 4 0, 5 0),(5 0, 6 0),(6 0, 7 0),CIRCULARSTRING(7 0, 8 0, 9 0),CIRCULARSTRING(9 0, 10 1, 10 0),(10 0, 10 -1))" ) << QStringLiteral( "CompoundCurve ((1 5, 1 4, 1 1, 1 0, 3 0),CircularString (3 0, 4 0, 5 0),(5 0, 6 0, 7 0),CircularString (7 0, 8 0, 9 0, 10 1, 10 0),(10 0, 10 -1))" );
}

void TestQgsGeometry::compoundCurveCondense()
{
QFETCH( QString, curve );
QFETCH( QString, expected );

QgsGeometry g = QgsGeometry::fromWkt( curve );
qgsgeometry_cast< QgsCompoundCurve * >( g.get() )->condenseCurves();

QCOMPARE( g.asWkt(), expected );
}

void TestQgsGeometry::multiPoint()
{
//test constructor
Expand Down

0 comments on commit 417d444

Please sign in to comment.