Skip to content

Commit

Permalink
[convert to curve] avancement
Browse files Browse the repository at this point in the history
  • Loading branch information
olivierdalang authored and nyalldawson committed Jun 18, 2021
1 parent 351df3e commit 9739e07
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 223 deletions.
1 change: 1 addition & 0 deletions python/core/auto_generated/geometry/qgscurvepolygon.sip.in
Expand Up @@ -91,6 +91,7 @@ Returns the curve polygon's exterior ring.
%End



SIP_PYOBJECT interiorRing( int i ) /HoldGIL,TypeHint="QgsCurve"/;
%Docstring
Retrieves an interior ring from the curve polygon. The first interior ring has index 0.
Expand Down
10 changes: 10 additions & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -727,6 +727,16 @@ Deletes the vertex at the given position number and item
object to help make the distinction?)
%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;
%Docstring
Expand Down
30 changes: 4 additions & 26 deletions src/app/vertextool/qgsvertextool.cpp
Expand Up @@ -2564,8 +2564,6 @@ void QgsVertexTool::deleteVertex()

void QgsVertexTool::toggleVertexCurve()
{
std::cout << "test";
QgsMessageLog::logMessage( "test", "DEBUG" );

Vertex toConvert = Vertex( nullptr, -1, -1 );
if ( mSelectedVertices.size() == 1 )
Expand All @@ -2578,47 +2576,27 @@ void QgsVertexTool::toggleVertexCurve()
}
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" );
return;
}


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() ) )
{
// The layer is not a curved type
QgsMessageLog::logMessage( "Layer is not curved", "DEBUG" );
return;
}

layer->beginEditCommand( tr( "Converting vertex type" ) );


// 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 );

QgsGeometry geom = layer->getFeature( toConvert.fid ).geometry();
bool success = geom.convertVertex( toConvert.vertexId );

if ( success )
{
QgsMessageLog::logMessage( "Should be OK", "DEBUG" );
geom.set( cpdCurve );
layer->changeGeometry( fId, geom );
layer->changeGeometry( toConvert.fid, geom );
layer->endEditCommand();
layer->triggerRepaint();
}
Expand Down
23 changes: 1 addition & 22 deletions src/core/geometry/qgscompoundcurve.cpp
Expand Up @@ -1011,28 +1011,7 @@ bool QgsCompoundCurve::convertVertex( QgsVertexId position )
}

// We merge consecutive LineStrings
// TODO ? : move this to a new QgsCompoundCurve::mergeConsecutiveLineStrings() method;
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;
condenseCurves();

clearCache();
return true;
Expand Down
29 changes: 29 additions & 0 deletions src/core/geometry/qgscurvepolygon.h
Expand Up @@ -91,6 +91,18 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
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

/**
Expand All @@ -107,6 +119,23 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface
}
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

/**
Expand Down
128 changes: 101 additions & 27 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -538,41 +538,115 @@ bool QgsGeometry::deleteVertex( int atVertex )
return d->geometry->deleteVertex( id );
}

// bool QgsGeometry::convertVertex( int atVertex )
// {
// if ( !d->geometry )
// {
// return false;
// }
bool QgsGeometry::convertVertex( int atVertex )
{

if ( !d->geometry )
return false;

QgsVertexId id;
if ( !vertexIdFromVertexNr( atVertex, id ) )
return false;

detach();

QgsAbstractGeometry *geom = d->geometry.get();

// If the geom is a collection, we get the concerned part, otherwise, the part is just the whole geom
QgsAbstractGeometry *part = nullptr;
QgsGeometryCollection *owningCollection = dynamic_cast<QgsGeometryCollection *>( geom );
if ( owningCollection != nullptr )
part = owningCollection->geometryN( id.part );
else
part = geom;

// 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;
}

bool success = 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 );

// QgsVertexId id;
// if ( !vertexIdFromVertexNr( atVertex, id ) )
// {
// return false;
// }
// // 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

// QgsAbstractGeometry* geom = d->geometry.get();
}
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 ) );

// // If the geom is a compound curve, we take it as is
// if( QgsCompoundCurve *cpdCurve = dynamic_cast<QgsCompoundCurve *>( geom ) )
// {
// return cpdCurve->convertVertex(id);
// }
// In that case, we must also reassign the instances
if ( success )
{
QgsMessageLog::logMessage( "Success", "DEBUG" );

// // If the geom is a linestring or cirularstring, we convert to compound curve
// if( dynamic_cast<const QgsCircularString *>( geom ) != nullptr || dynamic_cast<const QgsLineString *>( geom ) != nullptr ){
// QgsCompoundCurve *cpdCurve = new QgsCompoundCurve();
// cpdCurve->addCurve(((QgsCurve*)geom)->clone());
// return cpdCurve->convertVertex(id);
// }
if ( owningPolygon == nullptr && owningCollection == nullptr )
{
// Standalone linestring
QgsMessageLog::logMessage( "case A", "DEBUG" );
reset( std::make_unique<QgsCompoundCurve>( *cpdCurve ) ); // <- REVIEW PLZ
}

// // TODO other cases (multi-geoms, polygons...)
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" );

}
}

// // Otherwise, it failed
// return false
// }
return success;
}

bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
{
Expand Down
16 changes: 8 additions & 8 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -785,14 +785,14 @@ class CORE_EXPORT QgsGeometry
*/
bool deleteVertex( int atVertex );

// /**
// * Converts the vertex at the given position from/to circular
// * \returns 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).
// * \since QGIS 3.20
// */
// bool convertVertex( int atVertex );
/**
* Converts the vertex at the given position from/to circular
* \returns 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).
* \since QGIS 3.20
*/
bool convertVertex( int atVertex );

/**
* Returns coordinates of a vertex.
Expand Down
14 changes: 7 additions & 7 deletions test_digicurve.py
Expand Up @@ -23,19 +23,19 @@
QgsProject.instance().addMapLayer(l2)

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.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.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.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.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.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.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])

for f in l.getFeatures():
Expand Down

0 comments on commit 9739e07

Please sign in to comment.