Skip to content

Commit 2002f68

Browse files
author
mhugent
committedJan 9, 2008
More editing merges...
git-svn-id: http://svn.osgeo.org/qgis/trunk@7884 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 5d1af70 commit 2002f68

24 files changed

+1142
-797
lines changed
 

‎src/app/qgsmaptooladdfeature.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "qgsattributedialog.h"
2020
#include "qgscsexception.h"
2121
#include "qgsfield.h"
22+
#include "qgsgeometry.h"
2223
#include "qgsmapcanvas.h"
2324
#include "qgsproject.h"
2425
#include "qgsrubberband.h"
@@ -226,15 +227,15 @@ void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
226227
delete mRubberBand;
227228
mRubberBand = NULL;
228229

229-
//bail out if there are not at least two vertices
230-
if(mCaptureList.size() < 2)
230+
//lines: bail out if there are not at least two vertices
231+
if(mTool == CaptureLine && mCaptureList.size() < 2)
231232
{
232233
mCaptureList.clear();
233234
return;
234235
}
235236

236-
//bail out if there are not at least two vertices
237-
if(mCaptureList.size() < 2)
237+
//polygons: bail out if there are not at least two vertices
238+
if(mTool == CapturePolygon && mCaptureList.size() < 3)
238239
{
239240
mCaptureList.clear();
240241
return;
@@ -312,6 +313,7 @@ void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
312313
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
313314
return; //unknown wkbtype
314315
}
316+
f->setGeometryAndOwnership(&wkb[0],size);
315317
}
316318
else // polygon
317319
{
@@ -404,8 +406,18 @@ void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
404406
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
405407
return; //unknown wkbtype
406408
}
409+
f->setGeometryAndOwnership(&wkb[0],size);
410+
//is automatic polygon intersection removal activated?
411+
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
412+
413+
if(avoidPolygonIntersections != 0)
414+
{
415+
if(vlayer->removePolygonIntersections(f->geometry()) != 0)
416+
{
417+
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Could not remove polygon intersection"));
418+
}
419+
}
407420
}
408-
f->setGeometryAndOwnership(&wkb[0],size);
409421

410422
// add the fields to the QgsFeature
411423
const QgsFieldMap fields = provider->fields();
@@ -416,6 +428,12 @@ void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
416428

417429
if (QgsAttributeDialog::queryAttributes(fields, *f))
418430
{
431+
//add points to other features to keep topology up-to-date
432+
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
433+
if(topologicalEditing)
434+
{
435+
addTopologicalPoints(mCaptureList);
436+
}
419437
vlayer->addFeature(*f);
420438
}
421439
delete f;

‎src/app/qgsmaptooladdisland.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
/* $Id$ */
1616

1717
#include "qgsmaptooladdisland.h"
18+
#include "qgsgeometry.h"
1819
#include "qgsmapcanvas.h"
20+
#include "qgsproject.h"
1921
#include "qgsrubberband.h"
2022
#include "qgsvectorlayer.h"
2123
#include <QMessageBox>
@@ -77,6 +79,13 @@ void QgsMapToolAddIsland::canvasReleaseEvent(QMouseEvent * e)
7779

7880
//close polygon
7981
mCaptureList.push_back(*mCaptureList.begin());
82+
83+
//add points to other features to keep topology up-to-date
84+
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
85+
if(topologicalEditing)
86+
{
87+
addTopologicalPoints(mCaptureList);
88+
}
8089

8190
int errorCode = vlayer->addIsland(mCaptureList);
8291
QString errorMessage;

‎src/app/qgsmaptooladdvertex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void QgsMapToolAddVertex::canvasMoveEvent(QMouseEvent * e)
3838
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
3939
{
4040
QgsPoint posMapCoord = snapPointFromResults(snapResults, e->pos());
41-
mRubberBand->movePoint(1, posMapCoord);
41+
mRubberBand->movePoint(2, posMapCoord); //consider that the first rubber band point is added twice
4242
}
4343
}
4444
}

‎src/app/qgsmaptoolcapture.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "qgscoordinatetransform.h"
2020
#include "qgsfield.h"
2121
#include "qgslogger.h"
22+
#include "qgsgeometry.h"
2223
#include "qgsmaptoolcapture.h"
2324
#include "qgsmapcanvas.h"
2425
#include "qgsmaprender.h"
@@ -124,8 +125,6 @@ int QgsMapToolCapture::addVertex(const QPoint& p)
124125
}
125126
mRubberBand->addPoint(mapPoint);
126127
mCaptureList.push_back(layerPoint);
127-
//insert also vertices for adjacent features if topological editing is enabled
128-
insertSegmentVerticesForSnap(snapResults, vlayer);
129128
}
130129

131130
return 0;

‎src/app/qgsmaptoolcapture.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "qgsmaptooledit.h"
2222
#include "qgspoint.h"
2323

24-
24+
class QgsGeometry;
2525
class QgsRubberBand;
2626

2727
#include <QPoint>

‎src/app/qgsmaptooledit.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ int QgsMapToolEdit::insertSegmentVerticesForSnap(const QList<QgsSnappingResult>&
5757
//snap to edited layer?
5858
if(it->layer == editedLayer)
5959
{
60-
//segment snap?
6160
if(it->snappedVertexNr == -1) //segment snap
6261
{
6362
layerPoint = toLayerCoords(editedLayer, it->snappedVertex);
@@ -112,3 +111,62 @@ QgsVectorLayer* QgsMapToolEdit::currentVectorLayer()
112111
}
113112
return vlayer;
114113
}
114+
115+
116+
int QgsMapToolEdit::addTopologicalPoints(const QList<QgsPoint>& geom)
117+
{
118+
if(!mCanvas)
119+
{
120+
return 1;
121+
}
122+
123+
//find out current vector layer
124+
QgsVectorLayer *vlayer = currentVectorLayer();
125+
126+
if (!vlayer)
127+
{
128+
return 2;
129+
}
130+
131+
QList<QgsPoint>::const_iterator list_it = geom.constBegin();
132+
for(; list_it != geom.constEnd(); ++list_it)
133+
{
134+
addTopologicalPoints(*list_it, vlayer);
135+
}
136+
137+
return 0;
138+
}
139+
140+
int QgsMapToolEdit::addTopologicalPoints(const QgsPoint& p, QgsVectorLayer* vl)
141+
{
142+
if(!vl)
143+
{
144+
return 1;
145+
}
146+
147+
QMultiMap<double, QgsSnappingResult> snapResults; //results from the snapper object
148+
QList<QgsSnappingResult> filteredSnapResults; //we filter out the results that are on existing vertices
149+
150+
const double threshold = 0.00000001;
151+
152+
if(vl->snapWithContext(p, threshold, snapResults, QgsSnapper::SNAP_TO_SEGMENT) != 0)
153+
{
154+
return 2;
155+
}
156+
157+
QMultiMap<double, QgsSnappingResult>::const_iterator snap_it = snapResults.constBegin();
158+
159+
for(; snap_it != snapResults.constEnd(); ++snap_it)
160+
{
161+
//check if there is already an existing vertex at the position of p
162+
QgsPoint vertexPoint(p);
163+
if(vl->snapPoint(vertexPoint, threshold))
164+
{
165+
continue;
166+
}
167+
168+
filteredSnapResults.push_back(*snap_it);
169+
}
170+
insertSegmentVerticesForSnap(filteredSnapResults, vl);
171+
return 0;
172+
}

‎src/app/qgsmaptooledit.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ class QgsMapToolEdit: public QgsMapTool
5656

5757
/**Returns the current vector layer of the map canvas or 0*/
5858
QgsVectorLayer* currentVectorLayer();
59+
60+
/**Adds vertices to other features to keep topology up to date, e.g. to neighbouring polygons.
61+
Note that geom must be a geometry that is not yet inserted into the layer.
62+
@param geom a geometry that is to be inserted into the current vector layer
63+
@return 0 in case of success*/
64+
int addTopologicalPoints(const QList<QgsPoint>& geom);
65+
/**Adds topological points for one vertex
66+
@param p vertex in layer coordinates
67+
@return 0 in case of success*/
68+
int addTopologicalPoints(const QgsPoint& p, QgsVectorLayer* vl);
5969
};
6070

6171
#endif

‎src/app/qgsmaptoolidentify.cpp

Lines changed: 139 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,140 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
224224
viewer->showMessage(); // deletes itself on close
225225
}
226226

227+
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
228+
{
229+
if (!layer)
230+
return;
231+
232+
// load identify radius from settings
233+
QSettings settings;
234+
double identifyValue = settings.value("/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS).toDouble();
235+
QString ellipsoid = settings.readEntry("/qgis/measure/ellipsoid", "WGS84");
236+
237+
// create the search rectangle
238+
double searchRadius = mCanvas->extent().width() * (identifyValue/100.0);
239+
240+
QgsRect r;
241+
r.setXmin(point.x() - searchRadius);
242+
r.setXmax(point.x() + searchRadius);
243+
r.setYmin(point.y() - searchRadius);
244+
r.setYmax(point.y() + searchRadius);
245+
246+
r = toLayerCoords(layer, r);
247+
248+
int featureCount = 0;
249+
//QgsFeature feat;
250+
QgsAttributeAction& actions = *layer->actions();
251+
QString fieldIndex = layer->displayField();
252+
QgsVectorDataProvider* dataProvider = layer->getDataProvider();
253+
const QgsFieldMap& fields = dataProvider->fields();
254+
255+
// init distance/area calculator
256+
QgsDistanceArea calc;
257+
calc.setProjectionsEnabled(mCanvas->projectionsEnabled()); // project?
258+
calc.setEllipsoid(ellipsoid);
259+
calc.setSourceSRS(layer->srs().srsid());
260+
261+
// display features falling within the search radius
262+
if(!mResults)
263+
{
264+
mResults = new QgsIdentifyResults(actions, mCanvas->window());
265+
mResults->setAttribute(Qt::WA_DeleteOnClose);
266+
// Be informed when the dialog box is closed so that we can stop using it.
267+
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
268+
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
269+
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int)));
270+
// restore the identify window position and show it
271+
mResults->restorePosition();
272+
}
273+
else
274+
{
275+
mResults->raise();
276+
mResults->clear();
277+
mResults->setActions(actions);
278+
}
279+
280+
QApplication::setOverrideCursor(Qt::WaitCursor);
281+
282+
int lastFeatureId = 0;
283+
284+
QList<QgsFeature> featureList;
285+
layer->featuresInRectangle(r, featureList, true, true);
286+
QList<QgsFeature>::iterator f_it = featureList.begin();
287+
288+
for(; f_it != featureList.end(); ++f_it)
289+
{
290+
featureCount++;
291+
292+
QTreeWidgetItem* featureNode = mResults->addNode("foo");
293+
featureNode->setData(0, Qt::UserRole, QVariant(f_it->featureId())); // save feature id
294+
lastFeatureId = f_it->featureId();
295+
featureNode->setText(0, fieldIndex);
296+
const QgsAttributeMap& attr = f_it->attributeMap();
297+
298+
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
299+
{
300+
//QgsDebugMsg(it->fieldName() + " == " + fieldIndex);
301+
302+
if (fields[it.key()].name() == fieldIndex)
303+
{
304+
featureNode->setText(1, it->toString());
305+
}
306+
mResults->addAttribute(featureNode, fields[it.key()].name(), it->toString());
307+
}
308+
309+
// Calculate derived attributes and insert:
310+
// measure distance or area depending on geometry type
311+
if (layer->vectorType() == QGis::Line)
312+
{
313+
double dist = calc.measure(f_it->geometry());
314+
QString str = calc.textUnit(dist, 3, mCanvas->mapUnits(), false);
315+
mResults->addDerivedAttribute(featureNode, QObject::tr("Length"), str);
316+
}
317+
else if (layer->vectorType() == QGis::Polygon)
318+
{
319+
double area = calc.measure(f_it->geometry());
320+
QString str = calc.textUnit(area, 3, mCanvas->mapUnits(), true);
321+
mResults->addDerivedAttribute(featureNode, QObject::tr("Area"), str);
322+
}
323+
324+
// Add actions
325+
QgsAttributeAction::aIter iter = actions.begin();
326+
for (register int i = 0; iter != actions.end(); ++iter, ++i)
327+
{
328+
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
329+
}
330+
331+
}
332+
333+
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount));
334+
335+
//also test the not commited features //todo: eliminate copy past code
336+
337+
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
338+
if (featureCount == 1)
339+
{
340+
mResults->showAllAttributes();
341+
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
342+
highlightFeature(lastFeatureId);
343+
}
344+
else if (featureCount == 0)
345+
{
346+
mResults->setTitle(layer->name() + " - " + QObject::tr("No features found") );
347+
mResults->setMessage ( QObject::tr("No features found"), QObject::tr("No features were found in the active layer at the point you clicked") );
348+
}
349+
else
350+
{
351+
QString title = layer->name();
352+
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
353+
mResults->setTitle(title);
354+
}
355+
QApplication::restoreOverrideCursor();
356+
357+
mResults->show();
358+
}
359+
360+
#if 0 //MH: old state of the function
227361
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
228362
{
229363
if (!layer)
@@ -434,6 +568,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
434568
}
435569
}
436570
}
571+
#endif
437572

438573

439574
void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
@@ -478,10 +613,11 @@ void QgsMapToolIdentify::highlightFeature(int featureId)
478613
delete mRubberBand;
479614
mRubberBand = 0;
480615

481-
QgsVectorDataProvider* provider = layer->getDataProvider();
482616
QgsFeature feat;
483-
if (!provider->getFeatureAtId(featureId, feat))
484-
return;
617+
if(layer->getFeatureAtId(featureId, feat, true, false) != 0)
618+
{
619+
return;
620+
}
485621

486622
if(!feat.geometry())
487623
{
@@ -490,50 +626,6 @@ void QgsMapToolIdentify::highlightFeature(int featureId)
490626

491627
mRubberBand = new QgsRubberBand(mCanvas, feat.geometry()->vectorType() == QGis::Polygon);
492628

493-
#if 0
494-
QgsGeometry* g = feat.geometry();
495-
496-
// TODO: support multipart geometries
497-
if (g->isMultipart())
498-
return;
499-
500-
switch (g->vectorType())
501-
{
502-
case QGis::Point:
503-
{
504-
mRubberBand = new QgsRubberBand(mCanvas, true);
505-
QgsPoint pt = g->asPoint();
506-
double d = mCanvas->extent().width() * 0.005;
507-
mRubberBand->addPoint(QgsPoint(pt.x()-d,pt.y()-d));
508-
mRubberBand->addPoint(QgsPoint(pt.x()+d,pt.y()-d));
509-
mRubberBand->addPoint(QgsPoint(pt.x()+d,pt.y()+d));
510-
mRubberBand->addPoint(QgsPoint(pt.x()-d,pt.y()+d));
511-
break;
512-
}
513-
case QGis::Line:
514-
{
515-
mRubberBand = new QgsRubberBand(mCanvas);
516-
QgsPolyline line = g->asPolyline();
517-
for (int i = 0; i < line.count(); i++)
518-
mRubberBand->addPoint(line[i]);
519-
break;
520-
}
521-
case QGis::Polygon:
522-
{
523-
mRubberBand = new QgsRubberBand(mCanvas,true);
524-
QgsPolygon polygon = g->asPolygon();
525-
QgsPolyline line = polygon[0];
526-
for (int i = 0; i < line.count(); i++)
527-
mRubberBand->addPoint(line[i]);
528-
break;
529-
}
530-
531-
default:
532-
break;
533-
}
534-
#endif //0
535-
536-
537629
if (mRubberBand)
538630
{
539631
mRubberBand->setToGeometry(feat.geometry(), *layer);

‎src/app/qgsmaptoolmovefeature.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <QMessageBox>
2525
#include <QMouseEvent>
2626
#include <QSettings>
27-
27+
#include <limits>
2828
QgsMapToolMoveFeature::QgsMapToolMoveFeature(QgsMapCanvas* canvas): QgsMapToolEdit(canvas), mRubberBand(0)
2929
{
3030

@@ -68,28 +68,52 @@ void QgsMapToolMoveFeature::canvasPressEvent(QMouseEvent * e)
6868
return;
6969
}
7070

71-
//find first geometry under mouse cursor and store its id
71+
//find first geometry under mouse cursor and store iterator to it
7272
QgsPoint layerCoords = toLayerCoords((QgsMapLayer*)vlayer, e->pos());
7373
QSettings settings;
7474
int searchRadius = settings.value("/qgis/digitizing/search_radius_vertex_edit", 10).toInt();
7575
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius, \
7676
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
7777

78-
QgsGeometry* theGeom = 0;
79-
int featureId;
80-
81-
theGeom = vlayer->geometryInRectangle(selectRect, featureId);
78+
QList<QgsFeature> featureList;
79+
vlayer->featuresInRectangle(selectRect, featureList, true, false);
8280

83-
if(theGeom)
81+
if(featureList.size() > 0)
8482
{
83+
//find the closest feature
84+
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords);
85+
if(!pointGeometry)
86+
{
87+
return;
88+
}
89+
90+
QList<QgsFeature>::iterator closestFeatureIt;
91+
double minDistance = std::numeric_limits<double>::max();
92+
double currentDistance;
93+
94+
QList<QgsFeature>::iterator it = featureList.begin();
95+
for(; it != featureList.end(); ++it)
96+
{
97+
if(it->geometry())
98+
{
99+
currentDistance = pointGeometry->distance(*(it->geometry()));
100+
if(currentDistance < minDistance)
101+
{
102+
minDistance = currentDistance;
103+
closestFeatureIt = it;
104+
}
105+
}
106+
}
107+
85108
mStartPointMapCoords = toMapCoords(e->pos());
86-
mMovedFeature = featureId;
87-
109+
mMovedFeature = closestFeatureIt->featureId(); //todo: take the closest feature, not the first one...
88110
mRubberBand = createRubberBand();
89-
mRubberBand->setToGeometry(theGeom, *vlayer);
111+
mRubberBand->setToGeometry(closestFeatureIt->geometry(), *vlayer);
90112
mRubberBand->setColor(Qt::red);
91113
mRubberBand->setWidth(2);
92114
mRubberBand->show();
115+
116+
delete pointGeometry;
93117
}
94118
}
95119

‎src/app/qgsmaptoolmovevertex.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,25 @@ void QgsMapToolMoveVertex::canvasPressEvent(QMouseEvent * e)
8888
}
8989
else if(it->beforeVertexNr == -1)
9090
{
91-
rb->addPoint(it->snappedVertex, false);
92-
rb->addPoint(it->afterVertex, true);
93-
mRubberBandMovingPoints.push_back(0);
91+
rb->addPoint(it->afterVertex, false);
92+
rb->addPoint(it->snappedVertex, true);
93+
//consider that the first rubber band point is added twice
94+
mRubberBandMovingPoints.push_back(2);
9495
}
9596
else if(it->afterVertexNr == -1)
9697
{
97-
rb->addPoint(it->snappedVertex, false);
98-
rb->addPoint(it->beforeVertex, true);
99-
mRubberBandMovingPoints.push_back(0);
98+
rb->addPoint(it->beforeVertex, false);
99+
rb->addPoint(it->snappedVertex, true);
100+
//consider that the first rubber band point is added twice
101+
mRubberBandMovingPoints.push_back(2);
100102
}
101103
else
102104
{
103105
rb->addPoint(it->beforeVertex, false);
104106
rb->addPoint(it->snappedVertex, false);
105107
rb->addPoint(it->afterVertex, true);
106-
mRubberBandMovingPoints.push_back(1);
108+
//consider that the first rubber band point is added twice
109+
mRubberBandMovingPoints.push_back(2);
107110
}
108111
mRubberBands.push_back(rb);
109112
}

‎src/app/qgsmaptoolsplitfeatures.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "qgsmaptoolsplitfeatures.h"
1818
#include "qgsmapcanvas.h"
19+
#include "qgsproject.h"
1920
#include "qgsrubberband.h"
2021
#include "qgsvectorlayer.h"
2122
#include <QMessageBox>
@@ -87,6 +88,15 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent(QMouseEvent * e)
8788
//too complex intersection (most likely several polygon intersections)
8889
QMessageBox::warning(0, tr("Intersection problem"), tr("One or more geometries cannot be split because the intersection is too complex. Note that polygon splits can only be done if the split line intersects the polygon once. Also inner polygon rings cannot be split"));
8990
}
91+
else if(returnCode == 0)
92+
{
93+
//does not work, because the final split line is not identical to the one entered by the user!
94+
/*int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
95+
if(topologicalEditing)
96+
{
97+
addTopologicalPoints(mCaptureList);
98+
}*/
99+
}
90100

91101
mCaptureList.clear();
92102
mCanvas->refresh();

‎src/app/qgsprojectproperties.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ QgsProjectProperties::QgsProjectProperties(QgsMapCanvas* mapCanvas, QWidget *par
105105
mEnableTopologicalEditingCheckBox->setCheckState(Qt::Unchecked);
106106
}
107107

108+
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
109+
if(avoidPolygonIntersections != 0)
110+
{
111+
mAvoidIntersectionsCheckBox->setCheckState(Qt::Checked);
112+
}
113+
else
114+
{
115+
mAvoidIntersectionsCheckBox->setCheckState(Qt::Unchecked);
116+
}
117+
108118
bool ok;
109119
QStringList layerIdList = QgsProject::instance()->readListEntry("Digitizing", "/LayerSnappingList", &ok);
110120
QStringList enabledList = QgsProject::instance()->readListEntry("Digitizing", "/LayerSnappingEnabledList", &ok);
@@ -283,6 +293,8 @@ void QgsProjectProperties::apply()
283293
//write the digitizing settings
284294
int topologicalEditingEnabled = (mEnableTopologicalEditingCheckBox->checkState() == Qt::Checked) ? 1:0;
285295
QgsProject::instance()->writeEntry("Digitizing", "/TopologicalEditing", topologicalEditingEnabled);
296+
int avoidPolygonIntersectionsEnabled = (mAvoidIntersectionsCheckBox->checkState() == Qt::Checked) ? 1:0;
297+
QgsProject::instance()->writeEntry("Digitizing", "/AvoidPolygonIntersections", avoidPolygonIntersectionsEnabled);
286298

287299
QMap<QString, LayerEntry>::const_iterator layerEntryIt;
288300

‎src/core/qgsgeometry.cpp

Lines changed: 453 additions & 285 deletions
Large diffs are not rendered by default.

‎src/core/qgsgeometry.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ email : morb at ozemail dot com dot au
1717
#ifndef QGSGEOMETRY_H
1818
#define QGSGEOMETRY_H
1919

20+
#include <QMultiMap>
2021
#include <QString>
2122
#include <QVector>
2223

@@ -261,6 +262,11 @@ not disjoint with existing polygons of the feature*/
261262
else other error*/
262263
int splitGeometry(const QList<QgsPoint>& splitLine, QgsGeometry** newGeometry);
263264

265+
/**Changes this geometry such that it does not intersect the other geometry
266+
@param other geometry that should not be intersect
267+
@return 0 in case of success*/
268+
int difference(QgsGeometry* other);
269+
264270
/**Returns the bounding box of this feature*/
265271
QgsRect boundingBox();
266272

@@ -397,6 +403,11 @@ not disjoint with existing polygons of the feature*/
397403
/**Finds the vertices next to point where the line is split. If it is split at a vertex, beforeVertex
398404
and afterVertex are the same*/
399405
int findVerticesNextToSplit(const QgsPoint& splitPoint, int& beforeVertex, int& afterVertex);
406+
/**Test if a point is a geometry vertex
407+
@param p point to test
408+
@param vertexNr vertex number (if point is a vertex)
409+
@return true if p is vertex of this geometry*/
410+
bool vertexContainedInGeometry(const QgsPoint& p, int& vertexNr);
400411
/**Splits this geometry into two lines*/
401412
int splitThisLine(const QgsPoint& splitPoint, int beforeVertex, int afterVertex, QgsGeometry** newGeometry);
402413
/**Splits this geometry into two multilines*/

‎src/core/qgspoint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ double QgsPoint::sqrDist(double x, double y) const
5555
return (m_x-x)*(m_x-x)+(m_y-y)*(m_y-y);
5656
}
5757

58-
double QgsPoint::sqrDist(const QgsPoint& other)
58+
double QgsPoint::sqrDist(const QgsPoint& other) const
5959
{
6060
return sqrDist(other.x(), other.y());
6161
}

‎src/core/qgspoint.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class CORE_EXPORT QgsPoint
9999
double sqrDist(double x, double y) const;
100100

101101
/**Returns the squared distance between this and other point*/
102-
double sqrDist(const QgsPoint& other);
102+
double sqrDist(const QgsPoint& other) const;
103103

104104
//! equality operator
105105
bool operator==(const QgsPoint &other);

‎src/core/qgsvectorlayer.cpp

Lines changed: 222 additions & 297 deletions
Large diffs are not rendered by default.

‎src/core/qgsvectorlayer.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
194194
*/
195195
virtual QString subsetString();
196196

197-
/**Returns the first geometry found in the search rectangle. Includes searching through the changed geometries
198-
and added features. This function is mainly usefull for map tools that search for a geometry to manipulate
199-
@param searchRect selection rectangle.
200-
@param featureId id of the feature the geometry belongs to
201-
@return pointer to the geometry or 0 if no geometry found. The calling function takes ownership of the geometry*/
202-
QgsGeometry* geometryInRectangle(const QgsRect& searchRect, int& featureId);
197+
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features
198+
@return 0 in case of success*/
199+
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features, bool fetchGeometries = true, bool fetchAttributes = true);
203200

201+
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
202+
@return 0 in case of success*/
203+
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
204204

205205
/** Adds a feature
206206
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents.
@@ -254,6 +254,12 @@ existing rings, 5 no feature found where ring can be inserted*/
254254
2 if intersection too complex to be handled, else other error*/
255255
int splitFeatures(const QList<QgsPoint>& splitLine);
256256

257+
/**Changes the specified geometry such that it has no intersections with other \
258+
polygon (or multipolygon) geometries in this vector layer
259+
@param geom geometry to modify
260+
@return 0 in case of success*/
261+
int removePolygonIntersections(QgsGeometry* geom);
262+
257263
/** Set labels on */
258264
void setLabelOn( bool on );
259265

@@ -270,7 +276,7 @@ existing rings, 5 no feature found where ring can be inserted*/
270276
@param point The point which is set to the position of a vertex if there is one within the snapping tolerance.
271277
If there is no point within this tolerance, point is left unchanged.
272278
@param tolerance The snapping tolerance
273-
@return true if the position of point has been changed, and false otherwise */
279+
@return true if point has been snapped, false if no vertex within search tolerance*/
274280
bool snapPoint(QgsPoint& point, double tolerance);
275281

276282
/**Snaps to segment or vertex within given tolerance

‎src/gui/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ../core
4040
${SQLITE3_INCLUDE_DIR}
4141
${CMAKE_CURRENT_BINARY_DIR}
4242
${CMAKE_CURRENT_BINARY_DIR}/../ui
43+
${GEOS_INCLUDE_DIR}
4344
)
4445

4546
IF (WIN32)

‎src/gui/qgsmapcanvassnapper.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void QgsMapCanvasSnapper::setMapCanvas(QgsMapCanvas* canvas)
5858
}
5959
}
6060

61-
int QgsMapCanvasSnapper::snapToCurrentLayer(const QPoint& p, QList<QgsSnappingResult>& results, QgsSnapper::SNAP_TO snap_to)
61+
int QgsMapCanvasSnapper::snapToCurrentLayer(const QPoint& p, QList<QgsSnappingResult>& results, QgsSnapper::SNAP_TO snap_to, double snappingTol)
6262
{
6363
results.clear();
6464

@@ -96,8 +96,17 @@ int QgsMapCanvasSnapper::snapToCurrentLayer(const QPoint& p, QList<QgsSnappingRe
9696
snapToList.push_back(snap_to);
9797

9898
QSettings settings;
99-
//use search tolerance for vertex editing
100-
toleranceList.push_back(settings.value("/qgis/digitizing/search_radius_vertex_edit", 50).toDouble());
99+
100+
if(snappingTol < 0)
101+
{
102+
//use search tolerance for vertex editing
103+
toleranceList.push_back(settings.value("/qgis/digitizing/search_radius_vertex_edit", 50).toDouble());
104+
}
105+
else
106+
{
107+
toleranceList.push_back(snappingTol);
108+
}
109+
101110

102111
mSnapper->setLayersToSnap(layerList);
103112
mSnapper->setTolerances(toleranceList);

‎src/gui/qgsmapcanvassnapper.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ class GUI_EXPORT QgsMapCanvasSnapper
4747
editing from the qgis options.
4848
@param p start point of the snap (in pixel coordinates)
4949
@param results list to which the results are appended
50-
@param snap_to snap to vertex or to segment*/
51-
int snapToCurrentLayer(const QPoint& p, QList<QgsSnappingResult>& results, QgsSnapper::SNAP_TO snap_to);
50+
@param snap_to snap to vertex or to segment
51+
@param snappingTol snapping tolerance. -1 means that the search radius for vertex edits is taken*/
52+
int snapToCurrentLayer(const QPoint& p, QList<QgsSnappingResult>& results, QgsSnapper::SNAP_TO snap_to, double snappingTol = -1);
5253
/**Snaps to the background layers. This method is usefull to align the features of the
5354
edited layers to those of other layers (as described in the project properties).
5455
Uses snap mode QgsSnapper::ONE_RESULT. Therefore, only the

‎src/gui/qgsrubberband.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,12 @@ void QgsRubberBand::reset(bool isPolygon)
7878
*/
7979
void QgsRubberBand::addPoint(const QgsPoint & p, bool do_update /* = true */, int geometryIndex)
8080
{
81-
//QgsDebugMsg("Adding point: " + QString::number(p.x()) + QString::number(p.y()));
8281
if(mPoints.size() < (geometryIndex + 1))
8382
{
8483
return;
8584
}
8685

87-
//QgsDebugMsg("size of current list: " + QString::number(mPoints[geometryIndex].size()));
86+
//we need to set two points at the begin of the ruber band for operations that move the last point
8887
if(mPoints[geometryIndex].size() == 0)
8988
{
9089
mPoints[geometryIndex].push_back(p);
@@ -119,8 +118,6 @@ void QgsRubberBand::removeLastPoint(int geometryIndex)
119118
*/
120119
void QgsRubberBand::movePoint(const QgsPoint & p, int geometryIndex)
121120
{
122-
123-
//QgsDebugMsg("Moving last point");
124121
if(mPoints.size() < (geometryIndex + 1))
125122
{
126123
return;
@@ -130,6 +127,7 @@ void QgsRubberBand::movePoint(const QgsPoint & p, int geometryIndex)
130127
{
131128
return;
132129
}
130+
133131
mPoints[geometryIndex][mPoints.at(geometryIndex).size() - 1] = p;
134132

135133
updateRect();

‎src/gui/qgsrubberband.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class GUI_EXPORT QgsRubberBand: public QgsMapCanvasItem
4646
void removeLastPoint(int geometryIndex = 0);
4747

4848
void movePoint(const QgsPoint & p, int geometryIndex = 0);
49+
/**Moves the rubber band point specified by index. Note that if the rubber band is
50+
not used to track the last mouse position, the first point of the rubber band has two vertices*/
4951
void movePoint(int index, const QgsPoint& p, int geometryIndex = 0);
5052

5153
/**Sets this rubber band to the geometry of an existing feature.

‎src/ui/qgsprojectpropertiesbase.ui

Lines changed: 112 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<rect>
66
<x>0</x>
77
<y>0</y>
8-
<width>726</width>
9-
<height>579</height>
8+
<width>750</width>
9+
<height>615</height>
1010
</rect>
1111
</property>
1212
<property name="windowTitle" >
@@ -23,7 +23,7 @@
2323
</property>
2424
<layout class="QGridLayout" >
2525
<property name="margin" >
26-
<number>11</number>
26+
<number>9</number>
2727
</property>
2828
<property name="spacing" >
2929
<number>6</number>
@@ -39,7 +39,7 @@
3939
</attribute>
4040
<layout class="QGridLayout" >
4141
<property name="margin" >
42-
<number>11</number>
42+
<number>9</number>
4343
</property>
4444
<property name="spacing" >
4545
<number>6</number>
@@ -69,58 +69,6 @@
6969
</layout>
7070
</widget>
7171
</item>
72-
<item row="1" column="0" >
73-
<widget class="QGroupBox" name="btnGrpMapUnits" >
74-
<property name="title" >
75-
<string>Map Units</string>
76-
</property>
77-
<layout class="QHBoxLayout" >
78-
<property name="margin" >
79-
<number>11</number>
80-
</property>
81-
<property name="spacing" >
82-
<number>6</number>
83-
</property>
84-
<item>
85-
<widget class="QRadioButton" name="radMeters" >
86-
<property name="text" >
87-
<string>Meters</string>
88-
</property>
89-
<property name="checked" >
90-
<bool>true</bool>
91-
</property>
92-
</widget>
93-
</item>
94-
<item>
95-
<widget class="QRadioButton" name="radFeet" >
96-
<property name="text" >
97-
<string>Feet</string>
98-
</property>
99-
</widget>
100-
</item>
101-
<item>
102-
<widget class="QRadioButton" name="radDecimalDegrees" >
103-
<property name="text" >
104-
<string>Decimal degrees</string>
105-
</property>
106-
</widget>
107-
</item>
108-
<item>
109-
<spacer>
110-
<property name="orientation" >
111-
<enum>Qt::Horizontal</enum>
112-
</property>
113-
<property name="sizeHint" >
114-
<size>
115-
<width>40</width>
116-
<height>20</height>
117-
</size>
118-
</property>
119-
</spacer>
120-
</item>
121-
</layout>
122-
</widget>
123-
</item>
12472
<item row="2" column="0" >
12573
<widget class="QGroupBox" name="btnGrpPrecision" >
12674
<property name="title" >
@@ -203,58 +151,6 @@
203151
</layout>
204152
</widget>
205153
</item>
206-
<item row="3" column="0" >
207-
<widget class="QGroupBox" name="grpDigitizing" >
208-
<property name="title" >
209-
<string>Digitizing</string>
210-
</property>
211-
<layout class="QGridLayout" >
212-
<property name="margin" >
213-
<number>11</number>
214-
</property>
215-
<property name="spacing" >
216-
<number>6</number>
217-
</property>
218-
<item row="0" column="0" >
219-
<layout class="QHBoxLayout" >
220-
<property name="margin" >
221-
<number>11</number>
222-
</property>
223-
<property name="spacing" >
224-
<number>6</number>
225-
</property>
226-
<item>
227-
<widget class="QCheckBox" name="mEnableTopologicalEditingCheckBox" >
228-
<property name="text" >
229-
<string>Enable topological editing</string>
230-
</property>
231-
</widget>
232-
</item>
233-
<item>
234-
<spacer>
235-
<property name="orientation" >
236-
<enum>Qt::Horizontal</enum>
237-
</property>
238-
<property name="sizeHint" >
239-
<size>
240-
<width>91</width>
241-
<height>20</height>
242-
</size>
243-
</property>
244-
</spacer>
245-
</item>
246-
<item>
247-
<widget class="QPushButton" name="mSnappingOptionsPushButton" >
248-
<property name="text" >
249-
<string>Snapping options...</string>
250-
</property>
251-
</widget>
252-
</item>
253-
</layout>
254-
</item>
255-
</layout>
256-
</widget>
257-
</item>
258154
<item row="4" column="0" >
259155
<widget class="QGroupBox" name="groupBox" >
260156
<property name="title" >
@@ -345,18 +241,111 @@
345241
</layout>
346242
</widget>
347243
</item>
348-
<item row="5" column="0" >
349-
<spacer>
350-
<property name="orientation" >
351-
<enum>Qt::Vertical</enum>
244+
<item row="3" column="0" >
245+
<widget class="QGroupBox" name="grpDigitizing" >
246+
<property name="sizePolicy" >
247+
<sizepolicy>
248+
<hsizetype>5</hsizetype>
249+
<vsizetype>7</vsizetype>
250+
<horstretch>0</horstretch>
251+
<verstretch>0</verstretch>
252+
</sizepolicy>
352253
</property>
353-
<property name="sizeHint" >
354-
<size>
355-
<width>678</width>
356-
<height>31</height>
357-
</size>
254+
<property name="title" >
255+
<string>Digitizing</string>
358256
</property>
359-
</spacer>
257+
<widget class="QCheckBox" name="mEnableTopologicalEditingCheckBox" >
258+
<property name="geometry" >
259+
<rect>
260+
<x>11</x>
261+
<y>21</y>
262+
<width>371</width>
263+
<height>31</height>
264+
</rect>
265+
</property>
266+
<property name="text" >
267+
<string>Enable topological editing</string>
268+
</property>
269+
</widget>
270+
<widget class="QPushButton" name="mSnappingOptionsPushButton" >
271+
<property name="geometry" >
272+
<rect>
273+
<x>11</x>
274+
<y>95</y>
275+
<width>194</width>
276+
<height>36</height>
277+
</rect>
278+
</property>
279+
<property name="text" >
280+
<string>Snapping options...</string>
281+
</property>
282+
</widget>
283+
<widget class="QCheckBox" name="mAvoidIntersectionsCheckBox" >
284+
<property name="geometry" >
285+
<rect>
286+
<x>11</x>
287+
<y>58</y>
288+
<width>371</width>
289+
<height>31</height>
290+
</rect>
291+
</property>
292+
<property name="text" >
293+
<string>Avoid intersections of new polygons</string>
294+
</property>
295+
</widget>
296+
</widget>
297+
</item>
298+
<item row="1" column="0" >
299+
<widget class="QGroupBox" name="btnGrpMapUnits" >
300+
<property name="title" >
301+
<string>Map Units</string>
302+
</property>
303+
<layout class="QHBoxLayout" >
304+
<property name="margin" >
305+
<number>11</number>
306+
</property>
307+
<property name="spacing" >
308+
<number>6</number>
309+
</property>
310+
<item>
311+
<widget class="QRadioButton" name="radMeters" >
312+
<property name="text" >
313+
<string>Meters</string>
314+
</property>
315+
<property name="checked" >
316+
<bool>true</bool>
317+
</property>
318+
</widget>
319+
</item>
320+
<item>
321+
<widget class="QRadioButton" name="radFeet" >
322+
<property name="text" >
323+
<string>Feet</string>
324+
</property>
325+
</widget>
326+
</item>
327+
<item>
328+
<widget class="QRadioButton" name="radDecimalDegrees" >
329+
<property name="text" >
330+
<string>Decimal degrees</string>
331+
</property>
332+
</widget>
333+
</item>
334+
<item>
335+
<spacer>
336+
<property name="orientation" >
337+
<enum>Qt::Horizontal</enum>
338+
</property>
339+
<property name="sizeHint" >
340+
<size>
341+
<width>40</width>
342+
<height>20</height>
343+
</size>
344+
</property>
345+
</spacer>
346+
</item>
347+
</layout>
348+
</widget>
360349
</item>
361350
</layout>
362351
</widget>
@@ -399,17 +388,17 @@
399388
</widget>
400389
<layoutdefault spacing="6" margin="11" />
401390
<customwidgets>
402-
<customwidget>
403-
<class>QgsColorButton</class>
404-
<extends>QToolButton</extends>
405-
<header>qgscolorbutton.h</header>
406-
</customwidget>
407391
<customwidget>
408392
<class>QgsProjectionSelector</class>
409393
<extends>QWidget</extends>
410394
<header>qgsprojectionselector.h</header>
411395
<container>1</container>
412396
</customwidget>
397+
<customwidget>
398+
<class>QgsColorButton</class>
399+
<extends>QToolButton</extends>
400+
<header>qgscolorbutton.h</header>
401+
</customwidget>
413402
</customwidgets>
414403
<tabstops>
415404
<tabstop>tabWidget</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.