mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
topologicalEditing: Fix Z for add feature
This commit is contained in:
parent
6505e30fc4
commit
aaa6f65537
@ -190,6 +190,20 @@ editing.
|
||||
:param p: position of the vertex
|
||||
|
||||
:return: 0 in case of success
|
||||
%End
|
||||
|
||||
int addTopologicalPoints( const QgsPoint &p );
|
||||
%Docstring
|
||||
Adds a vertex to segments which intersect point p but don't
|
||||
already have a vertex there. If a feature already has a vertex at position p,
|
||||
no additional vertex is inserted. This method is useful for topological
|
||||
editing.
|
||||
|
||||
:param p: position of the vertex
|
||||
|
||||
:return: 0 in case of success
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -68,6 +68,17 @@ Adds vertices to other features to keep topology up to date, e.g. to neighbourin
|
||||
:param geom: list of points (in layer coordinate system)
|
||||
|
||||
:return: 0 in case of success
|
||||
%End
|
||||
|
||||
int addTopologicalPoints( const QVector<QgsPoint> &geom );
|
||||
%Docstring
|
||||
Adds vertices to other features to keep topology up to date, e.g. to neighbouring polygons.
|
||||
|
||||
:param geom: list of points (in layer coordinate system)
|
||||
|
||||
:return: 0 in case of success
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
void notifyNotVectorLayer();
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsgeometryoptions.h"
|
||||
#include "qgsabstractgeometry.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
@ -514,101 +515,20 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsGeometry &geom )
|
||||
|
||||
int returnVal = 0;
|
||||
|
||||
QgsWkbTypes::Type wkbType = geom.wkbType();
|
||||
|
||||
switch ( QgsWkbTypes::geometryType( wkbType ) )
|
||||
QgsAbstractGeometry::vertex_iterator it = geom.vertices_begin();
|
||||
while ( it != geom.vertices_end() )
|
||||
{
|
||||
//line
|
||||
case QgsWkbTypes::LineGeometry:
|
||||
if ( addTopologicalPoints( *it ) != 0 )
|
||||
{
|
||||
if ( !QgsWkbTypes::isMultiType( wkbType ) )
|
||||
{
|
||||
QgsPolylineXY line = geom.asPolyline();
|
||||
QgsPolylineXY::const_iterator line_it = line.constBegin();
|
||||
for ( ; line_it != line.constEnd(); ++line_it )
|
||||
{
|
||||
if ( addTopologicalPoints( *line_it ) != 0 )
|
||||
{
|
||||
returnVal = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMultiPolylineXY multiLine = geom.asMultiPolyline();
|
||||
QgsPolylineXY currentPolyline;
|
||||
|
||||
for ( int i = 0; i < multiLine.size(); ++i )
|
||||
{
|
||||
QgsPolylineXY::const_iterator line_it = currentPolyline.constBegin();
|
||||
for ( ; line_it != currentPolyline.constEnd(); ++line_it )
|
||||
{
|
||||
if ( addTopologicalPoints( *line_it ) != 0 )
|
||||
{
|
||||
returnVal = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
returnVal = 2;
|
||||
}
|
||||
|
||||
case QgsWkbTypes::PolygonGeometry:
|
||||
{
|
||||
if ( !QgsWkbTypes::isMultiType( wkbType ) )
|
||||
{
|
||||
QgsPolygonXY polygon = geom.asPolygon();
|
||||
QgsPolylineXY currentRing;
|
||||
|
||||
for ( int i = 0; i < polygon.size(); ++i )
|
||||
{
|
||||
currentRing = polygon.at( i );
|
||||
QgsPolylineXY::const_iterator line_it = currentRing.constBegin();
|
||||
for ( ; line_it != currentRing.constEnd(); ++line_it )
|
||||
{
|
||||
if ( addTopologicalPoints( *line_it ) != 0 )
|
||||
{
|
||||
returnVal = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMultiPolygonXY multiPolygon = geom.asMultiPolygon();
|
||||
QgsPolygonXY currentPolygon;
|
||||
QgsPolylineXY currentRing;
|
||||
|
||||
for ( int i = 0; i < multiPolygon.size(); ++i )
|
||||
{
|
||||
currentPolygon = multiPolygon.at( i );
|
||||
for ( int j = 0; j < currentPolygon.size(); ++j )
|
||||
{
|
||||
currentRing = currentPolygon.at( j );
|
||||
QgsPolylineXY::const_iterator line_it = currentRing.constBegin();
|
||||
for ( ; line_it != currentRing.constEnd(); ++line_it )
|
||||
{
|
||||
if ( addTopologicalPoints( *line_it ) != 0 )
|
||||
{
|
||||
returnVal = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsWkbTypes::PointGeometry:
|
||||
case QgsWkbTypes::UnknownGeometry:
|
||||
case QgsWkbTypes::NullGeometry:
|
||||
break;
|
||||
it++;
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
|
||||
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPoint &p )
|
||||
{
|
||||
if ( !mLayer->isSpatial() )
|
||||
return 1;
|
||||
@ -673,7 +593,7 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
if ( sqrDistVertexSnap < sqrSnappingTolerance )
|
||||
continue; // the vertex already exists - do not insert it
|
||||
|
||||
if ( !mLayer->insertVertex( p.x(), p.y(), fid, segmentAfterVertex ) )
|
||||
if ( !mLayer->insertVertex( p, fid, segmentAfterVertex ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "failed to insert topo point" ) );
|
||||
}
|
||||
@ -682,6 +602,11 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
{
|
||||
return addTopologicalPoints( QgsPoint( p ) );
|
||||
}
|
||||
|
||||
|
||||
bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QVector<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
|
||||
{
|
||||
|
@ -176,6 +176,17 @@ class CORE_EXPORT QgsVectorLayerEditUtils
|
||||
*/
|
||||
int addTopologicalPoints( const QgsPointXY &p );
|
||||
|
||||
/**
|
||||
* Adds a vertex to segments which intersect point p but don't
|
||||
* already have a vertex there. If a feature already has a vertex at position p,
|
||||
* no additional vertex is inserted. This method is useful for topological
|
||||
* editing.
|
||||
* \param p position of the vertex
|
||||
* \return 0 in case of success
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
int addTopologicalPoints( const QgsPoint &p );
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -92,6 +92,29 @@ QgsVectorLayer *QgsMapToolEdit::currentVectorLayer()
|
||||
}
|
||||
|
||||
|
||||
int QgsMapToolEdit::addTopologicalPoints( const QVector<QgsPoint> &geom )
|
||||
{
|
||||
if ( !mCanvas )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//find out current vector layer
|
||||
QgsVectorLayer *vlayer = currentVectorLayer();
|
||||
|
||||
if ( !vlayer )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
QVector<QgsPoint>::const_iterator list_it = geom.constBegin();
|
||||
for ( ; list_it != geom.constEnd(); ++list_it )
|
||||
{
|
||||
vlayer->addTopologicalPoints( *list_it );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QgsMapToolEdit::addTopologicalPoints( const QVector<QgsPointXY> &geom )
|
||||
{
|
||||
if ( !mCanvas )
|
||||
|
@ -74,6 +74,14 @@ class GUI_EXPORT QgsMapToolEdit: public QgsMapTool
|
||||
*/
|
||||
int addTopologicalPoints( const QVector<QgsPointXY> &geom );
|
||||
|
||||
/**
|
||||
* Adds vertices to other features to keep topology up to date, e.g. to neighbouring polygons.
|
||||
* \param geom list of points (in layer coordinate system)
|
||||
* \returns 0 in case of success
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
int addTopologicalPoints( const QVector<QgsPoint> &geom );
|
||||
|
||||
//! Display a timed message bar noting the active layer is not vector.
|
||||
void notifyNotVectorLayer();
|
||||
//! Display a timed message bar noting the active vector layer is not editable.
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "qgsmapmouseevent.h"
|
||||
#include "testqgsmaptoolutils.h"
|
||||
|
||||
|
||||
bool operator==( const QgsGeometry &g1, const QgsGeometry &g2 )
|
||||
{
|
||||
if ( g1.isNull() && g2.isNull() )
|
||||
@ -68,6 +67,7 @@ class TestQgsMapToolAddFeatureLine : public QObject
|
||||
void testTracingWithOffset();
|
||||
void testZ();
|
||||
void testZMSnapping();
|
||||
void testTopologicalEditingZ();
|
||||
|
||||
private:
|
||||
QgisApp *mQgisApp = nullptr;
|
||||
@ -78,6 +78,7 @@ class TestQgsMapToolAddFeatureLine : public QObject
|
||||
QgsVectorLayer *mLayerLine = nullptr;
|
||||
QgsVectorLayer *mLayerLineZ = nullptr;
|
||||
QgsVectorLayer *mLayerPointZM = nullptr;
|
||||
QgsVectorLayer *mLayerTopoZ = nullptr;
|
||||
QgsFeatureId mFidLineF1 = 0;
|
||||
};
|
||||
|
||||
@ -156,7 +157,22 @@ void TestQgsMapToolAddFeatureLine::initTestCase()
|
||||
mLayerPointZM->addFeature( pointF );
|
||||
QCOMPARE( mLayerPointZM->featureCount(), ( long )1 );
|
||||
|
||||
mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerLineZ << mLayerPointZM ); //<< mLayerPolygon << mLayerPoint );
|
||||
// make layer for topologicalEditing with Z
|
||||
mLayerTopoZ = new QgsVectorLayer( QStringLiteral( "MultiLineStringZ?crs=EPSG:27700" ), QStringLiteral( "layer topologicalEditing Z" ), QStringLiteral( "memory" ) );
|
||||
QVERIFY( mLayerTopoZ->isValid() );
|
||||
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mLayerTopoZ );
|
||||
|
||||
mLayerTopoZ->startEditing();
|
||||
QgsFeature topoFeat;
|
||||
topoFeat.setGeometry( QgsGeometry::fromWkt( "MultiLineStringZ ((7.25 6 0, 7.25 7 0, 7.5 7 0, 7.5 6 0, 7.25 6 0),(6 6 0, 6 7 0, 7 7 0, 7 6 0, 6 6 0),(6.25 6.25 0, 6.75 6.25 0, 6.75 6.75 0, 6.25 6.75 0, 6.25 6.25 0)));" ) );
|
||||
qDebug() << topoFeat.geometry().asWkt() << "\n";
|
||||
|
||||
mLayerTopoZ->addFeature( topoFeat );
|
||||
QCOMPARE( mLayerTopoZ->featureCount(), ( long ) 1 );
|
||||
|
||||
qDebug() << mLayerTopoZ->getFeature( 1 ).geometry().asWkt() << "\n";
|
||||
|
||||
mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerLineZ << mLayerPointZM << mLayerTopoZ );
|
||||
|
||||
mCanvas->setSnappingUtils( new QgsMapCanvasSnappingUtils( mCanvas, this ) );
|
||||
|
||||
@ -397,5 +413,46 @@ void TestQgsMapToolAddFeatureLine::testZMSnapping()
|
||||
mCanvas->snappingUtils()->setConfig( cfg );
|
||||
}
|
||||
|
||||
void TestQgsMapToolAddFeatureLine::testTopologicalEditingZ()
|
||||
{
|
||||
TestQgsMapToolAdvancedDigitizingUtils utils( mCaptureTool );
|
||||
|
||||
mCanvas->setCurrentLayer( mLayerTopoZ );
|
||||
|
||||
// test with default Z value = 333
|
||||
QgsSettings().setValue( QStringLiteral( "/qgis/digitizing/default_z_value" ), 333 );
|
||||
|
||||
QSet<QgsFeatureId> oldFids = utils.existingFeatureIds();
|
||||
|
||||
qDebug() << mLayerTopoZ->getFeature( 0 ).geometry().asWkt() << "\n";
|
||||
|
||||
QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
|
||||
bool topologicalEditing = cfg.project()->topologicalEditing();
|
||||
cfg.project()->setTopologicalEditing( true );
|
||||
|
||||
cfg.setMode( QgsSnappingConfig::AllLayers );
|
||||
cfg.setEnabled( true );
|
||||
mCanvas->snappingUtils()->setConfig( cfg );
|
||||
|
||||
oldFids = utils.existingFeatureIds();
|
||||
utils.mouseClick( 6, 6.5, Qt::LeftButton );
|
||||
utils.mouseClick( 6.25, 6.5, Qt::LeftButton );
|
||||
utils.mouseClick( 6.75, 6.5, Qt::LeftButton );
|
||||
utils.mouseClick( 7.25, 6.5, Qt::LeftButton );
|
||||
utils.mouseClick( 7.5, 6.5, Qt::LeftButton );
|
||||
utils.mouseClick( 8, 6.5, Qt::RightButton );
|
||||
QgsFeatureId newFid = utils.newFeatureId( oldFids );
|
||||
|
||||
QString wkt = "LineStringZ (6 6.5 333, 6.25 6.5 333, 6.75 6.5 333, 7.25 6.5 333, 7.5 6.5 333)";
|
||||
QCOMPARE( mLayerTopoZ->getFeature( newFid ).geometry(), QgsGeometry::fromWkt( wkt ) );
|
||||
wkt = "MultiLineStringZ ((7.25 6 0, 7.25 6.5 333, 7.25 7 0, 7.5 7 0, 7.5 6.5 333, 7.5 6 0, 7.25 6 0),(6 6 0, 6 6.5 333, 6 7 0, 7 7 0, 7 6 0, 6 6 0),(6.25 6.25 0, 6.75 6.25 0, 6.75 6.5 333, 6.75 6.75 0, 6.25 6.75 0, 6.25 6.5 333, 6.25 6.25 0))";
|
||||
QCOMPARE( mLayerTopoZ->getFeature( oldFids.toList().last() ).geometry(), QgsGeometry::fromWkt( wkt ) );
|
||||
|
||||
mLayerLine->undoStack()->undo();
|
||||
|
||||
cfg.setEnabled( false );
|
||||
mCanvas->snappingUtils()->setConfig( cfg );
|
||||
cfg.project()->setTopologicalEditing( topologicalEditing );
|
||||
}
|
||||
QGSTEST_MAIN( TestQgsMapToolAddFeatureLine )
|
||||
#include "testqgsmaptooladdfeatureline.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user