Skip to content

Commit a24884c

Browse files
author
mhugent
committed
[FEATURE]: Avoid intersections for polygons is now also possible to background layers
git-svn-id: http://svn.osgeo.org/qgis/trunk@11839 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 9dba0ae commit a24884c

9 files changed

+274
-37
lines changed

src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ SET(QGIS_APP_SRCS
99
qgsattributeeditor.cpp
1010
qgsattributetypedialog.cpp
1111
qgsattributetypeloaddialog.cpp
12+
qgsavoidintersectionsdialog.cpp
1213
qgsbookmarkitem.cpp
1314
qgsbookmarks.cpp
1415
qgsclipboard.cpp
@@ -119,6 +120,7 @@ SET (QGIS_APP_MOC_HDRS
119120
qgsattributeeditor.h
120121
qgsattributetypedialog.h
121122
qgsattributetypeloaddialog.h
123+
qgsavoidintersectionsdialog.h
122124
qgsbookmarks.h
123125
qgscontinuouscolordialog.h
124126
qgsconfigureshortcutsdialog.h
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "qgsavoidintersectionsdialog.h"
2+
#include "qgsmapcanvas.h"
3+
#include "qgsvectorlayer.h"
4+
5+
QgsAvoidIntersectionsDialog::QgsAvoidIntersectionsDialog( QgsMapCanvas* canvas, const QSet<QString>& enabledLayers, QWidget * parent, Qt::WindowFlags f ): \
6+
QDialog( parent, f ), mMapCanvas( canvas )
7+
{
8+
setupUi( this );
9+
10+
int nLayers = mMapCanvas->layerCount();
11+
QgsVectorLayer* currentLayer = 0;
12+
QListWidgetItem* newItem = 0;
13+
14+
for ( int i = 0; i < nLayers; ++i )
15+
{
16+
currentLayer = dynamic_cast<QgsVectorLayer*>( mMapCanvas->layer( i ) );
17+
if ( currentLayer )
18+
{
19+
//only consider polygon or multipolygon layers
20+
if ( currentLayer->geometryType() == QGis::Polygon )
21+
{
22+
newItem = new QListWidgetItem( mLayersListWidget );
23+
newItem->setText( currentLayer->name() );
24+
newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
25+
newItem->setData( Qt::UserRole, currentLayer->getLayerID() );
26+
if ( enabledLayers.contains( currentLayer->getLayerID() ) )
27+
{
28+
newItem->setCheckState( Qt::Checked );
29+
}
30+
else
31+
{
32+
newItem->setCheckState( Qt::Unchecked );
33+
}
34+
}
35+
}
36+
}
37+
}
38+
39+
QgsAvoidIntersectionsDialog::~QgsAvoidIntersectionsDialog()
40+
{
41+
42+
}
43+
44+
void QgsAvoidIntersectionsDialog::enabledLayers( QSet<QString>& enabledLayers )
45+
{
46+
enabledLayers.clear();
47+
48+
int itemCount = mLayersListWidget->count();
49+
QListWidgetItem* currentItem = 0;
50+
51+
for ( int i = 0; i < itemCount; ++i )
52+
{
53+
currentItem = mLayersListWidget->item( i );
54+
if ( currentItem->checkState() == Qt::Checked )
55+
{
56+
enabledLayers.insert( currentItem->data( Qt::UserRole ).toString() );
57+
}
58+
}
59+
}
60+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef QGSAVOIDINTERSECTIONSDIALOG_H
2+
#define QGSAVOIDINTERSECTIONSDIALOG_H
3+
4+
#include "ui_qgsavoidintersectionsdialogbase.h"
5+
6+
class QgsMapCanvas;
7+
8+
class QgsAvoidIntersectionsDialog: public QDialog, private Ui::QgsAvoidIntersectionsDialogBase
9+
{
10+
Q_OBJECT
11+
public:
12+
QgsAvoidIntersectionsDialog( QgsMapCanvas* canvas, const QSet<QString>& enabledLayers, QWidget * parent = 0, Qt::WindowFlags f = 0 );
13+
~QgsAvoidIntersectionsDialog();
14+
/**Returns ids of layers that are considered for the avoid intersection function*/
15+
void enabledLayers( QSet<QString>& enabledLayers );
16+
17+
private:
18+
QgsMapCanvas* mMapCanvas;
19+
};
20+
21+
#endif // QGSAVOIDINTERSECTIONSDIALOG_H

src/app/qgsmaptooladdfeature.cpp

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgsfield.h"
2222
#include "qgsgeometry.h"
2323
#include "qgsmapcanvas.h"
24+
#include "qgsmaplayerregistry.h"
2425
#include "qgsproject.h"
2526
#include "qgsrubberband.h"
2627
#include "qgsvectordataprovider.h"
@@ -442,16 +443,27 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
442443
}
443444
f->setGeometryAndOwnership( &wkb[0], size );
444445

445-
//is automatic polygon intersection removal activated?
446-
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry( "Digitizing", "/AvoidPolygonIntersections", 0 );
447-
448-
if ( avoidPolygonIntersections != 0 )
446+
int avoidIntersectionsReturn = avoidIntersectons( f->geometry() );
447+
if ( avoidIntersectionsReturn == 1 )
449448
{
450-
if ( vlayer->removePolygonIntersections( f->geometry() ) != 0 )
451-
{
452-
QMessageBox::critical( 0, tr( "Error" ), tr( "Could not remove polygon intersection" ) );
453-
}
449+
//not a polygon type. Impossible to get there
454450
}
451+
else if ( avoidIntersectionsReturn == 2 )
452+
{
453+
//bail out...
454+
QMessageBox::critical( 0, tr( "Error" ), tr( "The feature could not be added because removing the polygon intersections would change the geometry type" ) );
455+
delete f;
456+
delete mRubberBand;
457+
mRubberBand = 0;
458+
mCaptureList.clear();
459+
return;
460+
}
461+
else if ( avoidIntersectionsReturn == 3 )
462+
{
463+
QMessageBox::critical( 0, tr( "Error" ), tr( "An error was reported during intersection removal" ) );
464+
}
465+
466+
455467
}
456468

457469
// add the fields to the QgsFeature
@@ -507,3 +519,47 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
507519
}
508520
}
509521
}
522+
523+
int QgsMapToolAddFeature::avoidIntersectons( QgsGeometry* g )
524+
{
525+
int returnValue = 0;
526+
527+
//check if g has polygon type
528+
if ( !g || g->type() != QGis::Polygon )
529+
{
530+
return 1;
531+
}
532+
533+
QGis::WkbType geomTypeBeforeModification = g->wkbType();
534+
535+
//read avoid intersections list from project properties
536+
bool listReadOk;
537+
QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", &listReadOk );
538+
if ( !listReadOk )
539+
{
540+
return true; //no intersections stored in project does not mean error
541+
}
542+
543+
//go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
544+
QgsVectorLayer* currentLayer = 0;
545+
QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
546+
for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
547+
{
548+
currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) );
549+
if ( currentLayer )
550+
{
551+
if ( currentLayer->removePolygonIntersections( g ) != 0 )
552+
{
553+
returnValue = 3;
554+
}
555+
}
556+
}
557+
558+
//make sure the geometry still has the same type (e.g. no change from polygon to multipolygon)
559+
if ( g->wkbType() != geomTypeBeforeModification )
560+
{
561+
return 2;
562+
}
563+
564+
return returnValue;
565+
}

src/app/qgsmaptooladdfeature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,9 @@ class QgsMapToolAddFeature: public QgsMapToolCapture
2424
QgsMapToolAddFeature( QgsMapCanvas* canvas, enum CaptureTool tool );
2525
virtual ~QgsMapToolAddFeature();
2626
void canvasReleaseEvent( QMouseEvent * e );
27+
private:
28+
/**Modifies geometry to avoid intersections with the layers specified in project properties
29+
@return 0 in case of success, 1 if geometry is not of polygon type, 2 if avoid intersection would change the geometry type, \
30+
3 other error during intersection removal*/
31+
int avoidIntersectons( QgsGeometry* g );
2732
};

src/app/qgsprojectproperties.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgsprojectproperties.h"
2121

2222
//qgis includes
23+
#include "qgsavoidintersectionsdialog.h"
2324
#include "qgscontexthelp.h"
2425
#include "qgscoordinatetransform.h"
2526
#include "qgslogger.h"
@@ -113,14 +114,16 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
113114
mEnableTopologicalEditingCheckBox->setCheckState( Qt::Unchecked );
114115
}
115116

116-
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry( "Digitizing", "/AvoidPolygonIntersections", 0 );
117-
if ( avoidPolygonIntersections != 0 )
117+
bool avoidIntersectionListOk;
118+
mAvoidIntersectionsSettings.clear();
119+
QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", &avoidIntersectionListOk );
120+
if ( avoidIntersectionListOk )
118121
{
119-
mAvoidIntersectionsCheckBox->setCheckState( Qt::Checked );
120-
}
121-
else
122-
{
123-
mAvoidIntersectionsCheckBox->setCheckState( Qt::Unchecked );
122+
QStringList::const_iterator avoidIt = avoidIntersectionsList.constBegin();
123+
for ( ; avoidIt != avoidIntersectionsList.constEnd(); ++avoidIt )
124+
{
125+
mAvoidIntersectionsSettings.insert( *avoidIt );
126+
}
124127
}
125128

126129
bool layerIdListOk, enabledListOk, toleranceListOk, toleranceUnitListOk, snapToListOk;
@@ -399,8 +402,16 @@ void QgsProjectProperties::apply()
399402
//write the digitizing settings
400403
int topologicalEditingEnabled = ( mEnableTopologicalEditingCheckBox->checkState() == Qt::Checked ) ? 1 : 0;
401404
QgsProject::instance()->writeEntry( "Digitizing", "/TopologicalEditing", topologicalEditingEnabled );
402-
int avoidPolygonIntersectionsEnabled = ( mAvoidIntersectionsCheckBox->checkState() == Qt::Checked ) ? 1 : 0;
403-
QgsProject::instance()->writeEntry( "Digitizing", "/AvoidPolygonIntersections", avoidPolygonIntersectionsEnabled );
405+
406+
//store avoid intersection layers
407+
QStringList avoidIntersectionList;
408+
QSet<QString>::const_iterator avoidIt = mAvoidIntersectionsSettings.constBegin();
409+
for ( ; avoidIt != mAvoidIntersectionsSettings.constEnd(); ++avoidIt )
410+
{
411+
avoidIntersectionList.append( *avoidIt );
412+
}
413+
QgsProject::instance()->writeEntry( "Digitizing", "/AvoidIntersectionsList", avoidIntersectionList );
414+
404415

405416
QMap<QString, LayerEntry>::const_iterator layerEntryIt;
406417

@@ -498,6 +509,15 @@ void QgsProjectProperties::on_buttonBox_helpRequested()
498509
QgsContextHelp::run( context_id );
499510
}
500511

512+
void QgsProjectProperties::on_mAvoidIntersectionsPushButton_clicked()
513+
{
514+
QgsAvoidIntersectionsDialog d( mMapCanvas, mAvoidIntersectionsSettings );
515+
if ( d.exec() == QDialog::Accepted )
516+
{
517+
d.enabledLayers( mAvoidIntersectionsSettings );
518+
}
519+
}
520+
501521
void QgsProjectProperties::on_mSnappingOptionsPushButton_clicked()
502522
{
503523
QgsSnappingDialog d( mMapCanvas, mSnappingLayerSettings );

src/app/qgsprojectproperties.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas
8989
void on_buttonBox_helpRequested();
9090

9191
/*!
92-
* Slot to show dialog for advanced editing options
92+
*
93+
*/
94+
void on_mAvoidIntersectionsPushButton_clicked();
95+
96+
/*!
97+
* Slot to show dialog for the layer snapping options
9398
*/
9499
void on_mSnappingOptionsPushButton_clicked();
95100

@@ -114,6 +119,9 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas
114119
snapping tolerance*/
115120
QMap<QString, LayerEntry> mSnappingLayerSettings;
116121

122+
/**Stores ids of layers where intersections of new polygons is considered. Is passed to / read from QgsAvoidIntersectionsDialog*/
123+
QSet<QString> mAvoidIntersectionsSettings;
124+
117125

118126
/*!
119127
* Function to save dialog window state
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<ui version="4.0" >
2+
<class>QgsAvoidIntersectionsDialogBase</class>
3+
<widget class="QDialog" name="QgsAvoidIntersectionsDialogBase" >
4+
<property name="geometry" >
5+
<rect>
6+
<x>0</x>
7+
<y>0</y>
8+
<width>365</width>
9+
<height>300</height>
10+
</rect>
11+
</property>
12+
<property name="windowTitle" >
13+
<string>Dialog</string>
14+
</property>
15+
<layout class="QGridLayout" name="gridLayout" >
16+
<item row="0" column="0" >
17+
<widget class="QListWidget" name="mLayersListWidget" />
18+
</item>
19+
<item row="1" column="0" >
20+
<widget class="QDialogButtonBox" name="mButtonBox" >
21+
<property name="orientation" >
22+
<enum>Qt::Horizontal</enum>
23+
</property>
24+
<property name="standardButtons" >
25+
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
26+
</property>
27+
</widget>
28+
</item>
29+
</layout>
30+
</widget>
31+
<resources/>
32+
<connections>
33+
<connection>
34+
<sender>mButtonBox</sender>
35+
<signal>accepted()</signal>
36+
<receiver>QgsAvoidIntersectionsDialogBase</receiver>
37+
<slot>accept()</slot>
38+
<hints>
39+
<hint type="sourcelabel" >
40+
<x>248</x>
41+
<y>254</y>
42+
</hint>
43+
<hint type="destinationlabel" >
44+
<x>157</x>
45+
<y>274</y>
46+
</hint>
47+
</hints>
48+
</connection>
49+
<connection>
50+
<sender>mButtonBox</sender>
51+
<signal>rejected()</signal>
52+
<receiver>QgsAvoidIntersectionsDialogBase</receiver>
53+
<slot>reject()</slot>
54+
<hints>
55+
<hint type="sourcelabel" >
56+
<x>316</x>
57+
<y>260</y>
58+
</hint>
59+
<hint type="destinationlabel" >
60+
<x>286</x>
61+
<y>274</y>
62+
</hint>
63+
</hints>
64+
</connection>
65+
</connections>
66+
</ui>

0 commit comments

Comments
 (0)