[convert to curve] avancement

This commit is contained in:
Olivier Dalang 2021-05-07 16:23:21 +02:00 committed by Nyall Dawson
parent 351df3ef9f
commit 9739e07c38
10 changed files with 254 additions and 219 deletions

View File

@ -91,6 +91,7 @@ Returns the curve polygon's exterior ring.
%End %End
SIP_PYOBJECT interiorRing( int i ) /HoldGIL,TypeHint="QgsCurve"/; SIP_PYOBJECT interiorRing( int i ) /HoldGIL,TypeHint="QgsCurve"/;
%Docstring %Docstring
Retrieves an interior ring from the curve polygon. The first interior ring has index 0. Retrieves an interior ring from the curve polygon. The first interior ring has index 0.

View File

@ -727,6 +727,16 @@ Deletes the vertex at the given position number and item
object to help make the distinction?) object to help make the distinction?)
%End %End
bool convertVertex( int atVertex );
%Docstring
Converts the vertex at the given position from/to circular
:return: ``False`` if atVertex does not correspond to a valid vertex
on this geometry (including if this geometry is a Point),
or if the specified vertex can't be converted (e.g. start/end points).
.. versionadded:: 3.20
%End
QgsPoint vertexAt( int atVertex ) const; QgsPoint vertexAt( int atVertex ) const;
%Docstring %Docstring

View File

@ -2564,8 +2564,6 @@ void QgsVertexTool::deleteVertex()
void QgsVertexTool::toggleVertexCurve() void QgsVertexTool::toggleVertexCurve()
{ {
std::cout << "test";
QgsMessageLog::logMessage( "test", "DEBUG" );
Vertex toConvert = Vertex( nullptr, -1, -1 ); Vertex toConvert = Vertex( nullptr, -1, -1 );
if ( mSelectedVertices.size() == 1 ) if ( mSelectedVertices.size() == 1 )
@ -2578,47 +2576,27 @@ void QgsVertexTool::toggleVertexCurve()
} }
else else
{ {
// We only support converting one vertex at a time // TODO support more than just 1 vertex
QgsMessageLog::logMessage( "Need exactly 1 selected/editted vertex", "DEBUG" ); QgsMessageLog::logMessage( "Need exactly 1 selected/editted vertex", "DEBUG" );
return; return;
} }
QgsVectorLayer *layer = toConvert.layer; QgsVectorLayer *layer = toConvert.layer;
QgsFeatureId fId = toConvert.fid;
int vNr = toConvert.vertexId;
QgsVertexId vId;
QgsFeature feature = layer->getFeature( fId );
QgsGeometry geom = feature.geometry();
geom.vertexIdFromVertexNr( vNr, vId );
if ( ! QgsWkbTypes::isCurvedType( layer->wkbType() ) ) if ( ! QgsWkbTypes::isCurvedType( layer->wkbType() ) )
{ {
// The layer is not a curved type
QgsMessageLog::logMessage( "Layer is not curved", "DEBUG" ); QgsMessageLog::logMessage( "Layer is not curved", "DEBUG" );
return; return;
} }
layer->beginEditCommand( tr( "Converting vertex type" ) ); layer->beginEditCommand( tr( "Converting vertex type" ) );
QgsGeometry geom = layer->getFeature( toConvert.fid ).geometry();
bool success = geom.convertVertex( toConvert.vertexId );
// TODO : implement convertVertex on QgsGeometry instead of following block, like this :
// bool success = geom.convertVertex(vId );
QgsAbstractGeometry *geomTmp = geom.constGet()->clone();
if ( ! geomTmp->convertTo( QgsWkbTypes::CompoundCurve ) )
{
QgsMessageLog::logMessage( "Could not convert " + geomTmp->wktTypeStr() + " to CompoundCurve", "DEBUG" );
return;
}
QgsCompoundCurve *cpdCurve = ( QgsCompoundCurve * )geomTmp;
bool success = cpdCurve->convertVertex( vId );
if ( success ) if ( success )
{ {
QgsMessageLog::logMessage( "Should be OK", "DEBUG" ); QgsMessageLog::logMessage( "Should be OK", "DEBUG" );
geom.set( cpdCurve ); layer->changeGeometry( toConvert.fid, geom );
layer->changeGeometry( fId, geom );
layer->endEditCommand(); layer->endEditCommand();
layer->triggerRepaint(); layer->triggerRepaint();
} }

View File

@ -1011,28 +1011,7 @@ bool QgsCompoundCurve::convertVertex( QgsVertexId position )
} }
// We merge consecutive LineStrings // We merge consecutive LineStrings
// TODO ? : move this to a new QgsCompoundCurve::mergeConsecutiveLineStrings() method; condenseCurves();
QgsLineString *lastLineString = nullptr;
QVector<QgsCurve *> newCurves;
for ( int i = 0; i < mCurves.size(); ++i )
{
QgsCurve *curve = mCurves.at( i );
QgsLineString *curveAsLineString = dynamic_cast<QgsLineString *>( curve );
if ( curveAsLineString != nullptr && lastLineString != nullptr )
{
// We append to previous
lastLineString->append( curveAsLineString );
}
else
{
// We keep as is
newCurves.append( curve );
lastLineString = curveAsLineString;
}
}
mCurves = newCurves;
clearCache(); clearCache();
return true; return true;

View File

@ -91,6 +91,18 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
return mExteriorRing.get(); return mExteriorRing.get();
} }
/**
* Returns the curve polygon's exterior ring.
*
* \see interiorRing()
* \note Not available in Python.
* \since QGIS 3.20
*/
QgsCurve *exteriorRing() SIP_SKIP
{
return mExteriorRing.get();
}
#ifndef SIP_RUN #ifndef SIP_RUN
/** /**
@ -107,6 +119,23 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
} }
return mInteriorRings.at( i ); return mInteriorRings.at( i );
} }
/**
* Retrieves an interior ring from the curve polygon. The first interior ring has index 0.
*
* \see numInteriorRings()
* \see exteriorRing()
* \note Not available in Python.
* \since QGIS 3.20
*/
QgsCurve *interiorRing( int i ) SIP_SKIP
{
if ( i < 0 || i >= mInteriorRings.size() )
{
return nullptr;
}
return mInteriorRings.at( i );
}
#else #else
/** /**

View File

@ -538,41 +538,115 @@ bool QgsGeometry::deleteVertex( int atVertex )
return d->geometry->deleteVertex( id ); return d->geometry->deleteVertex( id );
} }
// bool QgsGeometry::convertVertex( int atVertex ) bool QgsGeometry::convertVertex( int atVertex )
// { {
// if ( !d->geometry )
// {
// return false;
// }
// QgsVertexId id; if ( !d->geometry )
// if ( !vertexIdFromVertexNr( atVertex, id ) ) return false;
// {
// return false;
// }
// QgsAbstractGeometry* geom = d->geometry.get(); QgsVertexId id;
if ( !vertexIdFromVertexNr( atVertex, id ) )
return false;
detach();
// // If the geom is a compound curve, we take it as is QgsAbstractGeometry *geom = d->geometry.get();
// if( QgsCompoundCurve *cpdCurve = dynamic_cast<QgsCompoundCurve *>( geom ) )
// {
// return cpdCurve->convertVertex(id);
// }
// // If the geom is a linestring or cirularstring, we convert to compound curve // If the geom is a collection, we get the concerned part, otherwise, the part is just the whole geom
// if( dynamic_cast<const QgsCircularString *>( geom ) != nullptr || dynamic_cast<const QgsLineString *>( geom ) != nullptr ){ QgsAbstractGeometry *part = nullptr;
// QgsCompoundCurve *cpdCurve = new QgsCompoundCurve(); QgsGeometryCollection *owningCollection = dynamic_cast<QgsGeometryCollection *>( geom );
// cpdCurve->addCurve(((QgsCurve*)geom)->clone()); if ( owningCollection != nullptr )
// return cpdCurve->convertVertex(id); part = owningCollection->geometryN( id.part );
// } else
part = geom;
// // TODO other cases (multi-geoms, polygons...) // If the part is a polygon, we get the concerned ring, otherwise, the ring is just the whole part
QgsAbstractGeometry *ring = nullptr;
QgsCurvePolygon *owningPolygon = dynamic_cast<QgsCurvePolygon *>( part );
if ( owningPolygon != nullptr )
ring = ( id.ring == 0 ) ? owningPolygon->exteriorRing() : owningPolygon->interiorRing( id.ring - 1 );
else
ring = part;
// If the ring is not a curve, we're probably on a point geometry
QgsCurve *curve = dynamic_cast<QgsCurve *>( ring ); // TODO dynamic_cast -> geom_cast
if ( curve == nullptr )
{
QgsMessageLog::logMessage( "Cannot execute convertVertex on " + geom->wktTypeStr(), "DEBUG" );
return false;
}
// // Otherwise, it failed bool success = false;
// return false QgsCompoundCurve *cpdCurve = dynamic_cast<QgsCompoundCurve *>( curve );
// } if ( cpdCurve != nullptr )
{
QgsMessageLog::logMessage( "Already compound", "DEBUG" );
// If the geom is a already compound curve, we convert inplace, and we're done
success = cpdCurve->convertVertex( id );
// // This doesn't work... Not sure how to get the geometry actuall update ? // <- REVIEW PLZ
// if ( success )
// if ( owningCollection != nullptr )
// reset( std::make_unique<QgsGeometryCollection>( *owningCollection ) ); // <- REVIEW PLZ
// else if ( owningPolygon != nullptr )
// reset( std::make_unique<QgsCurvePolygon>( *owningPolygon ) ); // <- REVIEW PLZ
// else
// reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
}
else
{
// TODO : move this block before the above, so we call convertVertex only in one place
QgsMessageLog::logMessage( "Convert to compound", "DEBUG" );
// If the geom is a linestring or cirularstring, we create a compound curve
QgsCompoundCurve *cpdCurve = new QgsCompoundCurve();
cpdCurve->addCurve( curve->clone() );
success = cpdCurve->convertVertex( QgsVertexId( -1, -1, id.vertex ) );
// In that case, we must also reassign the instances
if ( success )
{
QgsMessageLog::logMessage( "Success", "DEBUG" );
if ( owningPolygon == nullptr && owningCollection == nullptr )
{
// Standalone linestring
QgsMessageLog::logMessage( "case A", "DEBUG" );
reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
}
if ( owningPolygon != nullptr )
{
// Replace the ring in the owning polygon
QgsMessageLog::logMessage( "case B", "DEBUG" );
if ( id.ring == 0 )
{
owningPolygon->setExteriorRing( cpdCurve );
}
else
{
owningPolygon->removeInteriorRing( id.ring - 1 );
owningPolygon->addInteriorRing( cpdCurve );
}
}
else if ( owningCollection != nullptr )
{
// Replace the curve in the owning collection
QgsMessageLog::logMessage( "case C", "DEBUG" );
owningCollection->removeGeometry( id.part );
owningCollection->addGeometry( cpdCurve );
}
}
else
{
QgsMessageLog::logMessage( "failure ?!", "DEBUG" );
}
}
return success;
}
bool QgsGeometry::insertVertex( double x, double y, int beforeVertex ) bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
{ {

View File

@ -785,14 +785,14 @@ class CORE_EXPORT QgsGeometry
*/ */
bool deleteVertex( int atVertex ); bool deleteVertex( int atVertex );
// /** /**
// * Converts the vertex at the given position from/to circular * Converts the vertex at the given position from/to circular
// * \returns FALSE if atVertex does not correspond to a valid vertex * \returns FALSE if atVertex does not correspond to a valid vertex
// * on this geometry (including if this geometry is a Point), * on this geometry (including if this geometry is a Point),
// * or if the specified vertex can't be converted (e.g. start/end points). * or if the specified vertex can't be converted (e.g. start/end points).
// * \since QGIS 3.20 * \since QGIS 3.20
// */ */
// bool convertVertex( int atVertex ); bool convertVertex( int atVertex );
/** /**
* Returns coordinates of a vertex. * Returns coordinates of a vertex.

View File

@ -23,19 +23,19 @@ l2 = QgsVectorLayer("CurvePolygon?crs=epsg:4326", "test layer", "memory")
QgsProject.instance().addMapLayer(l2) QgsProject.instance().addMapLayer(l2)
f1 = QgsFeature() f1 = QgsFeature()
f1.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 0, 5 5, 10 0, 15 5, 20 0)))")) f1.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 0, 5 5, 10 0, 15 5, 20 0, 10, -2.5)))"))
f2 = QgsFeature() f2 = QgsFeature()
f2.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 10, 5 15), CIRCULARSTRING(5 15, 10 10, 15 15), (15 15, 20 10)))")) f2.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 10, 5 15), CIRCULARSTRING(5 15, 10 10, 15 15), (15 15, 20 10), (20 10, 10 7.5, 0 10)))"))
f3 = QgsFeature() f3 = QgsFeature()
f3.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 20, 5 25, 10 20, 15 25, 20 20, 25 25, 30 20)))")) f3.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 20, 5 25, 10 20, 15 25, 20 20, 25 25, 30 20), (30 20, 15 17.5, 0 20)))"))
f4 = QgsFeature() f4 = QgsFeature()
f4.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 30, 5 35, 10 30), (10 30, 15 35, 20 30)))")) f4.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 30, 5 35, 10 30), (10 30, 15 35, 20 30, 10 27.5, 0 30)))"))
f5 = QgsFeature() f5 = QgsFeature()
f5.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 50, 5 55), (5 55, 10 50, 15 55, 20 50)))")) f5.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 50, 5 55), (5 55, 10 50, 15 55, 20 50, 10 47.5, 0 50)))"))
f6 = QgsFeature() f6 = QgsFeature()
f6.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 60, 5 65, 10 60), (10 60, 15 65), CIRCULARSTRING(15 65, 20 60, 25 65)))")) f6.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 60, 5 65, 10 60), (10 60, 15 65), CIRCULARSTRING(15 65, 20 60, 25 65), (25 65, 17.5 57.5, 0 60))"))
f7 = QgsFeature() f7 = QgsFeature()
f7.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(LINESTRING(0 70, 5 75, 10 70, 15 75, 20 70))")) f7.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(LINESTRING(0 70, 5 75, 10 70, 15 75, 20 70, 10 67.5, 0 70))"))
l2.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7]) l2.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7])
for f in l.getFeatures(): for f in l.getFeatures():

65
test_digicurve2.py Normal file
View File

@ -0,0 +1,65 @@
from itertools import count
setup = {
'Linestring': {
'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)': 'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)',
'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))': 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))',
'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))': 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))',
},
'CompoundCurve': {
'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)': 'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)',
'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))': 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))',
'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))': 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))',
},
'MultiCurve': {
'MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))',
'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))',
'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))',
},
'Polygon': {
'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))': 'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))',
'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))',
'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))',
},
'CurvePolygon': {
'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))': 'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))',
'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))',
'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))',
},
'MultiSurface': {
'MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
},
}
for geomtype, wkts in setup.items():
layer = QgsVectorLayer(f"{geomtype}?crs=epsg:4326", geomtype, "memory")
i = 0
for wkt_before, wkt_expected in wkts.items():
feature = QgsFeature()
geom = QgsGeometry.fromWkt(wkt_before)
geom.translate(i * 15, 0)
feature.setGeometry(geom)
layer.dataProvider().addFeature(feature)
i += 1
QgsProject.instance().addMapLayer(layer)
for geomtype, wkts in setup.items():
layer = QgsVectorLayer(f"{geomtype}?crs=epsg:4326", geomtype, "memory")
i = 0
for wkt_before, wkt_expected in wkts.items():
feature = QgsFeature()
geom = QgsGeometry.fromWkt(wkt_before)
# Ensure convert has the expected result
geom.convertVertex(geom.closestVertex(QgsPointXY(10, 10))[1])
assert geom.asWkt() == QgsGeometry.fromWkt(wkt_expected).asWkt(), 'NOT AS EXPECTED'
# Ensure clicking again revers to previous
geom.convertVertex(geom.closestVertex(QgsPointXY(10, 10))[1])
assert geom.asWkt() == QgsGeometry.fromWkt(wkt_before).asWkt(), 'NOT IDEMPOTENT'
QgsProject.instance().addMapLayer(layer)

View File

@ -4499,140 +4499,39 @@ class TestQgsGeometry(unittest.TestCase):
expected_wkt = "CompoundCurve (CircularString (-1 -1, -1.5 -0.5, -2 0),(-2 0, 2 0),CircularString (2 0, 1.5 -0.5, 1 -1))" expected_wkt = "CompoundCurve (CircularString (-1 -1, -1.5 -0.5, -2 0),(-2 0, 2 0),CircularString (2 0, 1.5 -0.5, 1 -1))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt()) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
def testDeleteVertexCurvePolygon(self): def testDeleteVertex(self):
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))" # WKT BEFORE -> WKT AFTER A CONVERT ON POINT AT 10,10
geom = QgsGeometry.fromWkt(wkt) test_setup = {
assert not geom.deleteVertex(-1) # Curve
assert not geom.deleteVertex(4) 'LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)': 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))',
assert geom.deleteVertex(0) 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))': 'COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0))',
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt()) 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))': 'COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0))',
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))" # Multicurve
geom = QgsGeometry.fromWkt(wkt) 'MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(5 15, 10 20, 0 20, 5 15))',
assert geom.deleteVertex(1) 'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))',
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt()) 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))': 'MULTICURVE(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), LINESTRING(5 15, 10 20, 0 20, 5 15))',
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))" # Polygon
geom = QgsGeometry.fromWkt(wkt) 'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))': 'CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3))',
assert geom.deleteVertex(2) 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3)))',
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt()) 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))': 'CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3)))',
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))" # Multipolygon
geom = QgsGeometry.fromWkt(wkt) 'MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0), LINESTRING(3 3, 7 3, 7 7, 3 7, 3 3)), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
assert geom.deleteVertex(3) 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0, 10 0, 10 10, 0 10, 0 0)), COMPOUNDCURVE(CIRCULARSTRING(3 3, 7 3, 7 7, 3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt()) 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))': 'MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((0 0, 10 0), CIRCULARSTRING(10 0, 10 10, 0 10), (0 10, 0 0)), COMPOUNDCURVE((3 3, 7 3), CIRCULARSTRING(7 3, 7 7, 3 7), (3 7, 3 3))), CURVEPOLYGON(LINESTRING(5 15, 10 20, 0 20, 5 15)))',
}
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))" for wkt_before, wkt_expected in test_setup.items():
geom = QgsGeometry.fromWkt(wkt) geom = QgsGeometry.fromWkt(wkt_before)
assert geom.deleteVertex(0) # Ensure convert has the expected result
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (2 0, 1.5 -0.5, 1 -1),(1 -1, 2 0)))" geom.convertVertex(geom.closestVertex(QgsPointXY(10, 10))[1])
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt()) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(wkt_expected).asWkt(), 'First call to convertVertex did not create expected geometry.')
# Ensure converting again returns back to initial
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))" geom.convertVertex(geom.closestVertex(QgsPointXY(10, 10))[1])
geom = QgsGeometry.fromWkt(wkt) self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(wkt_before).asWkt(), 'Second call to convertVertex did not properly revert changes.')
assert geom.deleteVertex(1)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1.5 -0.5, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(2)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(3)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(4)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 2 0),(2 0, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
def testConvertVertexCircularLine(self):
wkt = "CircularString (0 0,1 1,2 0)"
geom = QgsGeometry.fromWkt(wkt)
assert geom.convertVertex(1)
expected_wkt = "Linestring (0 0, 1 1, 2 0)"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "Linestring (0 0, 1 1, 2 0)"
geom = QgsGeometry.fromWkt(wkt)
assert geom.convertVertex(1)
expected_wkt = "CircularString (0 0,1 1,2 0)"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CircularString (0 0,1 1,2 0,3 -1,4 0)"
geom = QgsGeometry.fromWkt(wkt)
assert geom.convertVertex(1)
expected_wkt = "CompoundCurve(CircularString (0 0,1 1,2 0), (3 -1,4 0))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CircularString (0 0,1 1,2 0,3 -1,4 0)"
geom = QgsGeometry.fromWkt(wkt)
assert not geom.deleteVertex(-1)
assert not geom.deleteVertex(0)
assert not geom.deleteVertex(4)
assert not geom.deleteVertex(5)
def testConvertVertexCircularPolygon(self):
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert not geom.deleteVertex(-1)
assert not geom.deleteVertex(4)
assert geom.deleteVertex(0)
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(1)
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(2)
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0),(2 0,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(3)
self.assertEqual(geom.asWkt(), QgsCurvePolygon().asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(0)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (2 0, 1.5 -0.5, 1 -1),(1 -1, 2 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(1)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1.5 -0.5, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(2)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(3)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 1 -1),(1 -1, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
wkt = "CurvePolygon (CompoundCurve (CircularString(0 0,1 1,2 0,1.5 -0.5,1 -1),(1 -1,0 0)))"
geom = QgsGeometry.fromWkt(wkt)
assert geom.deleteVertex(4)
expected_wkt = "CurvePolygon (CompoundCurve (CircularString (0 0, 1 1, 2 0),(2 0, 0 0)))"
self.assertEqual(geom.asWkt(), QgsGeometry.fromWkt(expected_wkt).asWkt())
def testSingleSidedBuffer(self): def testSingleSidedBuffer(self):