mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Make QgsGeometry independent from QgsProject + better avoid intersections API
This commit is contained in:
parent
8c340f7144
commit
0513bb357c
@ -966,6 +966,7 @@ method to determine if a geometry is valid.
|
||||
- static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon ) has been renamed to comparePolygons
|
||||
- static bool compare( const QgsMultiPolygon& p1, const QgsMultiPolygon& p2, double epsilon ) has been renamed to compareMultiPolygons
|
||||
- smoothLine and smoothPolygon are no longer public API (use smooth() instead)
|
||||
- avoidIntersections() got an extra argument: list of layers to include in the operation (previously read from active QgsProject)
|
||||
|
||||
|
||||
QgsGeometryAnalyzer {#qgis_api_break_3_0_QgsGeometryAnalyzer}
|
||||
|
@ -741,10 +741,11 @@ class QgsGeometry
|
||||
* 1 if geometry is not of polygon type,
|
||||
* 2 if avoid intersection would change the geometry type,
|
||||
* 3 other error during intersection removal
|
||||
* @param avoidIntersectionsLayers list of layers to check for intersections
|
||||
* @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings)
|
||||
* @note added in 1.5
|
||||
*/
|
||||
int avoidIntersections();
|
||||
int avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers );
|
||||
|
||||
class Error
|
||||
{
|
||||
|
@ -396,14 +396,14 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
QStringList avoidIntersectionsList() const;
|
||||
QList<QgsVectorLayer*> avoidIntersectionsLayers() const;
|
||||
|
||||
/**
|
||||
* A list of layers with which intersections should be avoided.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList );
|
||||
void setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers );
|
||||
QVariantMap customVariables() const;
|
||||
void setCustomVariables( const QVariantMap& customVariables );
|
||||
int count() const;
|
||||
@ -646,11 +646,11 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
||||
void topologicalEditingChanged();
|
||||
|
||||
/**
|
||||
* Emitted whenever avoidIntersectionsList has changed.
|
||||
* Emitted whenever avoidIntersectionsLayers has changed.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
void avoidIntersectionsListChanged();
|
||||
void avoidIntersectionsLayersChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the map theme collection changes.
|
||||
|
@ -909,7 +909,7 @@ void QgsGPSInformationWidget::on_mBtnCloseFeature_clicked()
|
||||
f->setGeometry( g );
|
||||
|
||||
QgsGeometry featGeom = f->geometry();
|
||||
int avoidIntersectionsReturn = featGeom.avoidIntersections();
|
||||
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
|
||||
f->setGeometry( featGeom );
|
||||
if ( avoidIntersectionsReturn == 1 )
|
||||
{
|
||||
|
@ -7656,7 +7656,7 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
|
||||
geom = newGeometry;
|
||||
}
|
||||
// avoid intersection if enabled in digitize settings
|
||||
geom.avoidIntersections();
|
||||
geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
|
||||
}
|
||||
|
||||
// now create new feature using pasted feature as a template. This automatically handles default
|
||||
|
@ -273,7 +273,7 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
|
||||
delete g;
|
||||
|
||||
QgsGeometry featGeom = f->geometry();
|
||||
int avoidIntersectionsReturn = featGeom.avoidIntersections();
|
||||
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
|
||||
f->setGeometry( featGeom );
|
||||
if ( avoidIntersectionsReturn == 1 )
|
||||
{
|
||||
@ -295,17 +295,14 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
|
||||
|
||||
//use always topological editing for avoidIntersection.
|
||||
//Otherwise, no way to guarantee the geometries don't have a small gap in between.
|
||||
QStringList intersectionLayers = QgsProject::instance()->avoidIntersectionsList();
|
||||
QList<QgsVectorLayer*> intersectionLayers = QgsProject::instance()->avoidIntersectionsLayers();
|
||||
bool avoidIntersection = !intersectionLayers.isEmpty();
|
||||
if ( avoidIntersection ) //try to add topological points also to background layers
|
||||
{
|
||||
QStringList::const_iterator lIt = intersectionLayers.constBegin();
|
||||
for ( ; lIt != intersectionLayers.constEnd(); ++lIt )
|
||||
Q_FOREACH ( QgsVectorLayer* vl, intersectionLayers )
|
||||
{
|
||||
QgsMapLayer* ml = QgsProject::instance()->mapLayer( *lIt );
|
||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( ml );
|
||||
//can only add topological points if background layer is editable...
|
||||
if ( vl && vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() )
|
||||
if ( vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() )
|
||||
{
|
||||
vl->addTopologicalPoints( f->geometry() );
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
|
||||
QgsCurvePolygon* cp = new QgsCurvePolygon();
|
||||
cp->setExteriorRing( curveToAdd );
|
||||
QgsGeometry* geom = new QgsGeometry( cp );
|
||||
geom->avoidIntersections();
|
||||
geom->avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
|
||||
|
||||
const QgsCurvePolygon* cpGeom = dynamic_cast<const QgsCurvePolygon*>( geom->geometry() );
|
||||
if ( !cpGeom )
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgisapp.h"
|
||||
|
||||
@ -108,7 +109,7 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
|
||||
QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures;
|
||||
ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );
|
||||
|
||||
if ( geom.avoidIntersections( ignoreFeatures ) != 0 )
|
||||
if ( geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers(), ignoreFeatures ) != 0 )
|
||||
{
|
||||
emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
|
||||
vlayer->destroyEditCommand();
|
||||
|
@ -144,7 +144,7 @@ QgsSnappingLayerTreeModel::QgsSnappingLayerTreeModel( QgsProject* project, QObje
|
||||
, mLayerTreeModel( nullptr )
|
||||
{
|
||||
connect( project, &QgsProject::snappingConfigChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
|
||||
connect( project, &QgsProject::avoidIntersectionsListChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
|
||||
connect( project, &QgsProject::avoidIntersectionsLayersChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
|
||||
}
|
||||
|
||||
QgsSnappingLayerTreeModel::~QgsSnappingLayerTreeModel()
|
||||
@ -494,7 +494,7 @@ QVariant QgsSnappingLayerTreeModel::data( const QModelIndex& idx, int role ) con
|
||||
{
|
||||
if ( role == Qt::CheckStateRole && vl->geometryType() == QgsWkbTypes::PolygonGeometry )
|
||||
{
|
||||
if ( mProject->avoidIntersectionsList().contains( vl->id() ) )
|
||||
if ( mProject->avoidIntersectionsLayers().contains( vl ) )
|
||||
{
|
||||
return Qt::Checked;
|
||||
}
|
||||
@ -620,14 +620,14 @@ bool QgsSnappingLayerTreeModel::setData( const QModelIndex& index, const QVarian
|
||||
if ( !mIndividualLayerSettings.contains( vl ) )
|
||||
return false;
|
||||
|
||||
QStringList avoidIntersectionsList = mProject->avoidIntersectionsList();
|
||||
QList<QgsVectorLayer*> avoidIntersectionsList = mProject->avoidIntersectionsLayers();
|
||||
|
||||
if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl->id() ) )
|
||||
avoidIntersectionsList.append( vl->id() );
|
||||
if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl ) )
|
||||
avoidIntersectionsList.append( vl );
|
||||
else
|
||||
avoidIntersectionsList.removeAll( vl->id() );
|
||||
avoidIntersectionsList.removeAll( vl );
|
||||
|
||||
mProject->setAvoidIntersectionsList( avoidIntersectionsList );
|
||||
mProject->setAvoidIntersectionsLayers( avoidIntersectionsList );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1871,14 +1871,14 @@ bool QgsGeometry::deletePart( int partNum )
|
||||
return ok;
|
||||
}
|
||||
|
||||
int QgsGeometry::avoidIntersections( const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
|
||||
int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), ignoreFeatures );
|
||||
QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
|
||||
if ( diffGeom )
|
||||
{
|
||||
detach( false );
|
||||
|
@ -795,10 +795,12 @@ class CORE_EXPORT QgsGeometry
|
||||
* 1 if geometry is not of polygon type,
|
||||
* 2 if avoid intersection would change the geometry type,
|
||||
* 3 other error during intersection removal
|
||||
* @param avoidIntersectionsLayers list of layers to check for intersections
|
||||
* @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings)
|
||||
* @note added in 1.5
|
||||
*/
|
||||
int avoidIntersections( const QHash<QgsVectorLayer*, QSet<QgsFeatureId> >& ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
|
||||
int avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
|
||||
const QHash<QgsVectorLayer*, QSet<QgsFeatureId> >& ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
|
||||
|
||||
/** \ingroup core
|
||||
*/
|
||||
|
@ -224,7 +224,9 @@ bool QgsGeometryEditUtils::deletePart( QgsAbstractGeometry* geom, int partNum )
|
||||
return c->removeGeometry( partNum );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom, QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures )
|
||||
QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom,
|
||||
const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
|
||||
QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures )
|
||||
{
|
||||
QScopedPointer<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( &geom ) );
|
||||
if ( geomEngine.isNull() )
|
||||
@ -240,39 +242,32 @@ QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstract
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QStringList avoidIntersectionsList = QgsProject::instance()->avoidIntersectionsList();
|
||||
if ( avoidIntersectionsList.isEmpty() )
|
||||
if ( avoidIntersectionsLayers.isEmpty() )
|
||||
return nullptr; //no intersections stored in project does not mean error
|
||||
|
||||
QList< QgsAbstractGeometry* > nearGeometries;
|
||||
|
||||
//go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
|
||||
QgsVectorLayer* currentLayer = nullptr;
|
||||
QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
|
||||
for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
|
||||
Q_FOREACH ( QgsVectorLayer* currentLayer, avoidIntersectionsLayers )
|
||||
{
|
||||
currentLayer = dynamic_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( *aIt ) );
|
||||
if ( currentLayer )
|
||||
QgsFeatureIds ignoreIds;
|
||||
QHash<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
|
||||
if ( ignoreIt != ignoreFeatures.constEnd() )
|
||||
ignoreIds = ignoreIt.value();
|
||||
|
||||
QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
|
||||
.setFlags( QgsFeatureRequest::ExactIntersect )
|
||||
.setSubsetOfAttributes( QgsAttributeList() ) );
|
||||
QgsFeature f;
|
||||
while ( fi.nextFeature( f ) )
|
||||
{
|
||||
QgsFeatureIds ignoreIds;
|
||||
QHash<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
|
||||
if ( ignoreIt != ignoreFeatures.constEnd() )
|
||||
ignoreIds = ignoreIt.value();
|
||||
if ( ignoreIds.contains( f.id() ) )
|
||||
continue;
|
||||
|
||||
QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
|
||||
.setFlags( QgsFeatureRequest::ExactIntersect )
|
||||
.setSubsetOfAttributes( QgsAttributeList() ) );
|
||||
QgsFeature f;
|
||||
while ( fi.nextFeature( f ) )
|
||||
{
|
||||
if ( ignoreIds.contains( f.id() ) )
|
||||
continue;
|
||||
if ( !f.hasGeometry() )
|
||||
continue;
|
||||
|
||||
if ( !f.hasGeometry() )
|
||||
continue;
|
||||
|
||||
nearGeometries << f.geometry().geometry()->clone();
|
||||
}
|
||||
nearGeometries << f.geometry().geometry()->clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,9 +59,12 @@ class QgsGeometryEditUtils
|
||||
|
||||
/** Alters a geometry so that it avoids intersections with features from all open vector layers.
|
||||
* @param geom geometry to alter
|
||||
* @param avoidIntersectionsLayers list of layers to check for intersections
|
||||
* @param ignoreFeatures map of layer to feature id of features to ignore
|
||||
*/
|
||||
static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom, QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
|
||||
static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom,
|
||||
const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
|
||||
QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
|
||||
};
|
||||
|
||||
#endif // QGSGEOMETRYEDITUTILS_H
|
||||
|
@ -1023,15 +1023,25 @@ void QgsProject::setCustomVariables( const QVariantMap& variables )
|
||||
emit customVariablesChanged();
|
||||
}
|
||||
|
||||
QStringList QgsProject::avoidIntersectionsList() const
|
||||
QList<QgsVectorLayer*> QgsProject::avoidIntersectionsLayers() const
|
||||
{
|
||||
return readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() );
|
||||
QList<QgsVectorLayer*> layers;
|
||||
QStringList layerIds = readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() );
|
||||
Q_FOREACH ( const QString& layerId, layerIds )
|
||||
{
|
||||
if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mapLayer( layerId ) ) )
|
||||
layers << vlayer;
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
void QgsProject::setAvoidIntersectionsList( const QStringList& avoidIntersectionsList )
|
||||
void QgsProject::setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers )
|
||||
{
|
||||
writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), avoidIntersectionsList );
|
||||
emit avoidIntersectionsListChanged();
|
||||
QStringList list;
|
||||
Q_FOREACH ( QgsVectorLayer* layer, layers )
|
||||
list << layer->id();
|
||||
writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), list );
|
||||
emit avoidIntersectionsLayersChanged();
|
||||
}
|
||||
|
||||
QgsExpressionContext QgsProject::createExpressionContext() const
|
||||
|
@ -78,7 +78,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
Q_PROPERTY( QgsCoordinateReferenceSystem crs READ crs WRITE setCrs )
|
||||
Q_PROPERTY( QgsMapThemeCollection* mapThemeCollection READ mapThemeCollection NOTIFY mapThemeCollectionChanged )
|
||||
Q_PROPERTY( QgsSnappingConfig snappingConfig READ snappingConfig WRITE setSnappingConfig NOTIFY snappingConfigChanged )
|
||||
Q_PROPERTY( QStringList avoidIntersectionsList READ avoidIntersectionsList WRITE setAvoidIntersectionsList NOTIFY avoidIntersectionsListChanged )
|
||||
Q_PROPERTY( QList<QgsVectorLayer*> avoidIntersectionsLayers READ avoidIntersectionsLayers WRITE setAvoidIntersectionsLayers NOTIFY avoidIntersectionsLayersChanged )
|
||||
|
||||
public:
|
||||
//! Returns the QgsProject singleton instance
|
||||
@ -465,14 +465,14 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
QStringList avoidIntersectionsList() const;
|
||||
QList<QgsVectorLayer*> avoidIntersectionsLayers() const;
|
||||
|
||||
/**
|
||||
* A list of layers with which intersections should be avoided.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList );
|
||||
void setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers );
|
||||
|
||||
/**
|
||||
* A map of custom project variables.
|
||||
@ -760,11 +760,11 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
void topologicalEditingChanged();
|
||||
|
||||
/**
|
||||
* Emitted whenever avoidIntersectionsList has changed.
|
||||
* Emitted whenever avoidIntersectionsLayers has changed.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
void avoidIntersectionsListChanged();
|
||||
void avoidIntersectionsLayersChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the map theme collection changes.
|
||||
|
Loading…
x
Reference in New Issue
Block a user