Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add QgsGeometry::convertToCurvedMultiType()
  • Loading branch information
rouault committed Jan 3, 2023
1 parent f4d2f27 commit 0c8f010
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 0 deletions.
17 changes: 17 additions & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -2307,6 +2307,23 @@ If it is already a multipart geometry, it will return ``True`` and
not change the geometry.

:return: ``True`` in case of success and ``False`` else
%End

bool convertToCurvedMultiType();
%Docstring
Converts a geometry into a multitype geometry of curve kind (when there
is a corresponding curve type).
e.g. a polygon into a multisurface geometry with one polygon,
a multipolygon into a multisurface, a linestring into a multicurve
geometry with one linestring, or a multilinestring into a multicurve.
If it is already a multipart curve geometry, it will return ``True`` and
not change the geometry. It will also return ``True`` and do nothing if
the current geometry is a multipoint or a geometry collection. A single
point will be transformed to a multipoint.

:return: ``True`` in case of success and ``False`` else

.. versionadded:: 3.30
%End

bool convertToSingleType();
Expand Down
52 changes: 52 additions & 0 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -1523,6 +1523,12 @@ QVector<QgsGeometry> QgsGeometry::coerceToType( const QgsWkbTypes::Type type, do
newGeom.get()->addMValue( defaultM );
}

// Straight -> curve
if ( QgsWkbTypes::isCurvedType( type ) && !QgsWkbTypes::isCurvedType( newGeom.wkbType() ) )
{
newGeom.convertToCurvedMultiType();
}

// Multi -> single
if ( ! QgsWkbTypes::isMultiType( type ) && newGeom.isMultipart( ) )
{
Expand Down Expand Up @@ -1590,6 +1596,52 @@ bool QgsGeometry::convertToMultiType()
return true;
}

bool QgsGeometry::convertToCurvedMultiType()
{
if ( !d->geometry )
{
return false;
}

switch ( QgsWkbTypes::flatType( d->geometry->wkbType() ) )
{
case QgsWkbTypes::MultiPoint:
case QgsWkbTypes::MultiCurve:
case QgsWkbTypes::MultiSurface:
case QgsWkbTypes::GeometryCollection:
{
return true;
}
default:
break;
}

std::unique_ptr< QgsAbstractGeometry >geom = QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::curveType( QgsWkbTypes::multiType( d->geometry->wkbType() ) ) );
QgsGeometryCollection *multiGeom = qgsgeometry_cast<QgsGeometryCollection *>( geom.get() );
if ( !multiGeom )
{
return false;
}

QgsGeometryCollection *sourceMultiGeom = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
if ( sourceMultiGeom )
{
for ( int i = 0; i < sourceMultiGeom->numGeometries(); ++i )
{
if ( !multiGeom->addGeometry( sourceMultiGeom->geometryN( i )->clone() ) )
return false;
}
}
else
{
if ( !multiGeom->addGeometry( d->geometry->clone() ) )
return false;
}

reset( std::move( geom ) );
return true;
}

bool QgsGeometry::convertToSingleType()
{
if ( !d->geometry )
Expand Down
17 changes: 17 additions & 0 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -2376,6 +2376,23 @@ class CORE_EXPORT QgsGeometry
*/
bool convertToMultiType();

/**
* Converts a geometry into a multitype geometry of curve kind (when there
* is a corresponding curve type).
* e.g. a polygon into a multisurface geometry with one polygon,
* a multipolygon into a multisurface, a linestring into a multicurve
* geometry with one linestring, or a multilinestring into a multicurve.
* If it is already a multipart curve geometry, it will return TRUE and
* not change the geometry. It will also return TRUE and do nothing if
* the current geometry is a multipoint or a geometry collection. A single
* point will be transformed to a multipoint.
*
* \returns TRUE in case of success and FALSE else
*
* \since QGIS 3.30
*/
bool convertToCurvedMultiType();

/**
* Converts multi type geometry into single type geometry
* e.g. a multipolygon into a polygon geometry. Only the first part of the
Expand Down
84 changes: 84 additions & 0 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -2867,6 +2867,85 @@ def testConvertToMultiType(self):
assert compareWkt(expWkt, wkt), "testConvertToMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

def testConvertToCurvedMultiType(self):
""" Test converting geometries to multi curve type """
point = QgsGeometry.fromWkt('Point (1 2)')
assert point.convertToCurvedMultiType()
expWkt = 'MultiPoint ((1 2))'
wkt = point.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiPoint
assert point.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

multipoint = QgsGeometry.fromWkt('MultiPoint ((1 2))')
assert multipoint.convertToCurvedMultiType()
expWkt = 'MultiPoint ((1 2))'
wkt = multipoint.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiPoint
assert multipoint.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

line = QgsGeometry.fromWkt('LineString (1 0, 2 0)')
assert line.convertToCurvedMultiType()
expWkt = 'MultiCurve (LineString (1 0, 2 0))'
wkt = line.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiCurve
assert line.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

circular = QgsGeometry.fromWkt('CircularString (0 0, 1 1, 2 0)')
assert circular.convertToCurvedMultiType()
expWkt = 'MultiCurve (CircularString (0 0, 1 1, 2 0))'
wkt = circular.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiCurve
assert circular.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

multiline = QgsGeometry.fromWkt('MultiLineString ((1 0, 2 0))')
assert multiline.convertToCurvedMultiType()
expWkt = 'MultiCurve (LineString (1 0, 2 0))'
wkt = multiline.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiCurve
assert multiline.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

poly = QgsGeometry.fromWkt('Polygon ((1 0, 2 0, 2 1, 1 1, 1 0))')
assert poly.convertToCurvedMultiType()
expWkt = 'MultiSurface (Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))'
wkt = poly.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiSurface
assert poly.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

multipoly = QgsGeometry.fromWkt('MultiPolygon (((1 0, 2 0, 2 1, 1 1, 1 0)))')
assert multipoly.convertToCurvedMultiType()
expWkt = 'MultiSurface ( Polygon((1 0, 2 0, 2 1, 1 1, 1 0)))'
wkt = multipoly.asWkt()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)
# test conversion of MultiSurface
assert multipoly.convertToCurvedMultiType()
assert compareWkt(expWkt, wkt), "testConvertToCurvedMultiType failed: mismatch Expected:\n%s\nGot:\n%s\n" % (
expWkt, wkt)

def testConvertToSingleType(self):
""" Test converting geometries to single type """
point = QgsGeometry.fromWkt('MultiPoint ((1 2),(2 3))')
Expand Down Expand Up @@ -6346,6 +6425,11 @@ def coerce_to_wkt(wkt, type, defaultZ=None, defaultM=None):
QgsWkbTypes.MultiLineString),
['MultiLineString ((1 1, 1 2, 2 2, 1 1),(3 3, 4 3, 4 4, 3 3))'])

# Straight to curve
self.assertEqual(coerce_to_wkt('LineString (0 0,1 1)',
QgsWkbTypes.MultiCurve),
['MultiCurve (LineString (0 0, 1 1))'])

def testTriangularWaves(self):
"""Test triangular waves"""
self.assertEqual(QgsGeometry.fromWkt('Point (1 1)').triangularWaves(1, 2).asWkt(3), 'Point (1 1)')
Expand Down

0 comments on commit 0c8f010

Please sign in to comment.