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 82f93d0 commit 351df3e
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 69 deletions.
1 change: 1 addition & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -727,6 +727,7 @@ Deletes the vertex at the given position number and item
object to help make the distinction?)
%End


QgsPoint vertexAt( int atVertex ) const;
%Docstring
Returns coordinates of a vertex.
Expand Down
85 changes: 20 additions & 65 deletions src/app/vertextool/qgsvertextool.cpp
Expand Up @@ -17,6 +17,8 @@

#include "qgsadvanceddigitizingdockwidget.h"
#include "qgscurve.h"
#include "qgslinestring.h"
#include "qgscircularstring.h"
#include "qgscurvepolygon.h"
#include "qgsgeometryutils.h"
#include "qgsgeometryvalidator.h"
Expand Down Expand Up @@ -2508,7 +2510,7 @@ void QgsVertexTool::deleteVertex()
std::sort( vertexIds.begin(), vertexIds.end(), std::greater<int>() );
for ( int vertexId : vertexIds )
{
QgsMessageLog::logMessage("DELETE : fid:"+QString::number(fid)+" ; vertexId:"+QString::number(vertexId), "DEBUG");
QgsMessageLog::logMessage( "DELETE : fid:" + QString::number( fid ) + " ; vertexId:" + QString::number( vertexId ), "DEBUG" );
if ( res != QgsVectorLayer::EmptyGeometry )
res = layer->deleteVertex( fid, vertexId );
if ( res != QgsVectorLayer::EmptyGeometry && res != QgsVectorLayer::Success )
Expand Down Expand Up @@ -2563,21 +2565,21 @@ void QgsVertexTool::deleteVertex()
void QgsVertexTool::toggleVertexCurve()
{
std::cout << "test";
QgsMessageLog::logMessage("test", "DEBUG");
QgsMessageLog::logMessage( "test", "DEBUG" );

Vertex toConvert = Vertex(nullptr, -1, -1);
Vertex toConvert = Vertex( nullptr, -1, -1 );
if ( mSelectedVertices.size() == 1 )
{
toConvert = mSelectedVertices.first();
}
else if( mDraggingVertexType == AddingVertex || mDraggingVertexType == MovingVertex )
else if ( mDraggingVertexType == AddingVertex || mDraggingVertexType == MovingVertex )
{
toConvert = *mDraggingVertex;
}
else
{
// We only support converting one vertex at a time
QgsMessageLog::logMessage("Need exactly 1 selected/editted vertex", "DEBUG");
QgsMessageLog::logMessage( "Need exactly 1 selected/editted vertex", "DEBUG" );
return;
}

Expand All @@ -2593,83 +2595,36 @@ void QgsVertexTool::toggleVertexCurve()
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;
}

// We get the vertex ID and the point
// QgsPoint vPt = geom.constGet()->vertexAt(vId);

// QgsVertexId vIdPrev;
// QgsVertexId vIdNext;
// geom.constGet()->adjacentVertices(vId, vIdPrev, vIdNext);
// if( ! vIdPrev.isValid() || ! vIdNext.isValid() ){
// QgsMessageLog::logMessage("Can't work on first or last point", "DEBUG");
// return;
// }

// QgsCompoundCurve *compoundCurve = dynamic_cast<QgsCompoundCurve *>( geom.get() );
// if( ! compoundCurve ){
// compoundCurve->convertTo(QgsWkbTypes::CompoundCurve);
// QgsMessageLog::logMessage("Only compound curves supported (for now)", "DEBUG");
// return;
// }

// const QgsCurve *c0 = compoundCurve->curveAt(0);
// QgsMessageLog::logMessage("Curve 0 : " + c0->asWkt(), "DEBUG");
// const QgsCurve *c1 = compoundCurve->curveAt(1);
// QgsMessageLog::logMessage("Curve 1 : " + c1->asWkt(), "DEBUG");



// QgsCircularString arc = new QgsCircularString(prevVid, vid, nextVid);

// QgsGeometry geomPartA = geom.clone();
// QgsGeometry geomPartB = geom.clone();

// geomPartA.splitFeature()

// QgsMessageLog::logMessage("Geom is of type : " + geom.constGet()->wktTypeStr(), "DEBUG");

// vid.part;
// vid.ring;
// vid.vertex;
// QgsCompoundCurve *compoundCurveCopy = compoundCurve->clone();

// QgsVectorLayerEditUtils
// bool success;
// QgsMessageLog::logMessage("CONVERT : fid:"+QString::number(fId)+" ; vertexId:"+QString::number(vNr), "DEBUG");

// QVector< QPair<int, QgsVertexId> > curveVertexId = compoundCurve->curveVertexId(vId);
// QgsMessageLog::logMessage("curveVertexId (sic!)", "DEBUG");
// for ( auto it = curveVertexId.constBegin(); it != curveVertexId.constEnd(); ++it )
// {
// QgsMessageLog::logMessage("Curve : "+QString::number(it->first)+" Point : "+QString::number(it->second.part)+"/"+QString::number(it->second.ring)+"/"+QString::number(it->second.vertex), "DEBUG");
// }
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;
if ( ! geomTmp->convertTo( QgsWkbTypes::CompoundCurve ) )
{
QgsMessageLog::logMessage( "Could not convert " + geomTmp->wktTypeStr() + " to CompoundCurve", "DEBUG" );
return;
}
QgsCompoundCurve *compoundCurveCopy = (QgsCompoundCurve*)geomTmp;

layer->beginEditCommand( tr( "Converting vertex type" ) );
QgsCompoundCurve *cpdCurve = ( QgsCompoundCurve * )geomTmp;
bool success = cpdCurve->convertVertex( vId );

bool success = compoundCurveCopy->convertVertex(vId );

if ( success )
{
QgsMessageLog::logMessage("Should be OK", "DEBUG");
geom.set( compoundCurveCopy );
QgsMessageLog::logMessage( "Should be OK", "DEBUG" );
geom.set( cpdCurve );
layer->changeGeometry( fId, geom );
layer->endEditCommand();
layer->triggerRepaint();
}
else
{
QgsMessageLog::logMessage("Has failed :-/", "DEBUG");
QgsMessageLog::logMessage( "Has failed :-/", "DEBUG" );
layer->destroyEditCommand();
}

Expand Down
36 changes: 36 additions & 0 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -538,6 +538,42 @@ bool QgsGeometry::deleteVertex( int atVertex )
return d->geometry->deleteVertex( id );
}

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

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

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


// // If the geom is a compound curve, we take it as is
// 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( 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);
// }

// // TODO other cases (multi-geoms, polygons...)


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

bool QgsGeometry::insertVertex( double x, double y, int beforeVertex )
{
if ( !d->geometry )
Expand Down
9 changes: 9 additions & 0 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -785,6 +785,15 @@ 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 );

/**
* Returns coordinates of a vertex.
* \param atVertex index of the vertex
Expand Down
25 changes: 21 additions & 4 deletions test_digicurve.py
@@ -1,8 +1,7 @@
from itertools import count

l = QgsVectorLayer("CompoundCurve?crs=epsg:4326", "test layer", "memory")
QgsProject.instance().addMapLayer(l)

l1 = QgsVectorLayer("CompoundCurve?crs=epsg:4326", "test layer", "memory")
QgsProject.instance().addMapLayer(l1)

f1 = QgsFeature()
f1.setGeometry(QgsGeometry.fromWkt("COMPOUNDCURVE((0 0, 5 5, 10 0, 15 5, 20 0))"))
Expand All @@ -18,8 +17,26 @@
f6.setGeometry(QgsGeometry.fromWkt("COMPOUNDCURVE(CIRCULARSTRING(0 60, 5 65, 10 60), (10 60, 15 65), CIRCULARSTRING(15 65, 20 60, 25 65))"))
f7 = QgsFeature()
f7.setGeometry(QgsGeometry.fromWkt("LINESTRING(0 70, 5 75, 10 70, 15 75, 20 70)"))
l.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7])
l1.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7])

l2 = QgsVectorLayer("CurvePolygon?crs=epsg:4326", "test layer", "memory")
QgsProject.instance().addMapLayer(l2)

f1 = QgsFeature()
f1.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 0, 5 5, 10 0, 15 5, 20 0)))"))
f2 = QgsFeature()
f2.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 10, 5 15), CIRCULARSTRING(5 15, 10 10, 15 15), (15 15, 20 10)))"))
f3 = QgsFeature()
f3.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 20, 5 25, 10 20, 15 25, 20 20, 25 25, 30 20)))"))
f4 = QgsFeature()
f4.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 30, 5 35, 10 30), (10 30, 15 35, 20 30)))"))
f5 = QgsFeature()
f5.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(COMPOUNDCURVE((0 50, 5 55), (5 55, 10 50, 15 55, 20 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)))"))
f7 = QgsFeature()
f7.setGeometry(QgsGeometry.fromWkt("CURVEPOLYGON(LINESTRING(0 70, 5 75, 10 70, 15 75, 20 70))"))
l2.dataProvider().addFeatures([f1, f2, f3, f4, f5, f6, f7])

for f in l.getFeatures():
print(f"Feature {f.id()}")
Expand Down
30 changes: 30 additions & 0 deletions tests/src/app/testqgsvertextool.cpp
Expand Up @@ -83,6 +83,7 @@ class TestQgsVertexTool : public QObject
void testActiveLayerPriority();
void testSelectedFeaturesPriority();
void testVertexToolCompoundCurve();
void testConvertVertex();


private:
Expand Down Expand Up @@ -1322,5 +1323,34 @@ void TestQgsVertexTool::testSelectVerticesByPolygon()
QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 5.5, 1.25 6, 1.75 6, 1.75 5.5, 1.25 5.5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
}

void TestQgsVertexTool::testConvertVertex()
{
// convert vertex in linestring

mouseClick( 1, 1, Qt::LeftButton );
keyClick( Qt::Key_C );

QCOMPARE( mLayerLine->undoStack()->index(), 2 );
QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "COMPOUNDCURVE(CIRCULARSTRING(2 1, 1 1, 1 3))" ) );

mLayerLine->undoStack()->undo();

QCOMPARE( mLayerLine->undoStack()->index(), 1 );
QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );


// convert vertex in polygon

mouseClick( 7, 4, Qt::LeftButton );
keyClick( Qt::Key_C );

QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "CURVEPOLYGON(COMPOUNDCURVE((4 1, 7 1), CIRCULARSTRING(7 1, 7 4, 4 4), (4 4, 4 1)))" ) );

mLayerPolygon->undoStack()->undo();

QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
}

QGSTEST_MAIN( TestQgsVertexTool )
#include "testqgsvertextool.moc"
81 changes: 81 additions & 0 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -4553,6 +4553,87 @@ def testDeleteVertexCurvePolygon(self):
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):

wkt = "LineString( 0 0, 10 0)"
Expand Down

0 comments on commit 351df3e

Please sign in to comment.