@@ -72,33 +72,17 @@ void QgsMapToolOffsetCurve::canvasReleaseEvent( QgsMapMouseEvent *e )
72
72
deleteRubberBandAndGeometry ();
73
73
mGeometryModified = false ;
74
74
75
- QgsSnappingUtils *snapping = mCanvas ->snappingUtils ();
76
-
77
- // store previous settings
78
- QgsSnappingConfig oldConfig = snapping->config ();
79
- QgsSnappingConfig config = snapping->config ();
80
- // setup new settings (temporary)
81
- QgsSettings settings;
82
- config.setEnabled ( true );
83
- config.setMode ( QgsSnappingConfig::ActiveLayer );
84
- config.setType ( QgsSnappingConfig::Segment );
85
- config.setTolerance ( settings.value ( QStringLiteral ( " qgis/digitizing/search_radius_vertex_edit" ), 10 ).toDouble () );
86
- config.setUnits ( static_cast <QgsTolerance::UnitType>( settings.value ( QStringLiteral ( " qgis/digitizing/search_radius_vertex_edit_unit" ), QgsTolerance::Pixels ).toInt () ) );
87
- snapping->setConfig ( config );
88
-
89
- QgsPointLocator::Match match = snapping->snapToMap ( e->pos () );
90
-
91
- // restore old settings
92
- snapping->setConfig ( oldConfig );
93
-
94
- if ( match.hasEdge () && match.layer () )
75
+ QgsPointLocator::Match match = mCanvas ->snappingUtils ()->snapToCurrentLayer ( e->pos (),
76
+ QgsPointLocator::Types ( QgsPointLocator::Edge | QgsPointLocator::Area ) );
77
+
78
+ if ( ( match.hasEdge () || match.hasArea () ) && match.layer () )
95
79
{
96
80
mLayer = match.layer ();
97
81
QgsFeature fet;
98
82
if ( match.layer ()->getFeatures ( QgsFeatureRequest ( match.featureId () ) ).nextFeature ( fet ) )
99
83
{
100
84
mCtrlHeldOnFirstClick = ( e->modifiers () & Qt::ControlModifier ); // no geometry modification if ctrl is pressed
101
- prepareGeometry ( match. layer (), match , fet );
85
+ prepareGeometry ( match, fet );
102
86
mRubberBand = createRubberBand ();
103
87
if ( mRubberBand )
104
88
{
@@ -143,7 +127,7 @@ void QgsMapToolOffsetCurve::applyOffset( const double &offset, const Qt::Keyboar
143
127
return ;
144
128
}
145
129
146
- if ( mMultiPartGeometry )
130
+ if ( mModifiedPart >= 0 )
147
131
{
148
132
QgsGeometry geometry;
149
133
int partIndex = 0 ;
@@ -170,19 +154,75 @@ void QgsMapToolOffsetCurve::applyOffset( const double &offset, const Qt::Keyboar
170
154
else
171
155
{
172
156
QgsMultiPolygonXY newMultiPoly;
173
- QgsMultiPolygonXY multiPoly = mOriginalGeometry .asMultiPolygon ();
157
+ const QgsMultiPolygonXY multiPoly = mOriginalGeometry .asMultiPolygon ();
174
158
QgsMultiPolygonXY::const_iterator multiPolyIt = multiPoly.constBegin ();
175
159
for ( ; multiPolyIt != multiPoly.constEnd (); ++multiPolyIt )
176
160
{
177
161
if ( partIndex == mModifiedPart )
178
162
{
179
163
if ( mModifiedGeometry .isMultipart () )
180
164
{
181
- newMultiPoly += mModifiedGeometry .asMultiPolygon ();
165
+ // not a ring
166
+ if ( mModifiedRing <= 0 )
167
+ {
168
+ // part became mulitpolygon, that means discard original rings from the part
169
+ newMultiPoly += mModifiedGeometry .asMultiPolygon ();
170
+ }
171
+ else
172
+ {
173
+ // ring became multipolygon, oh boy!
174
+ QgsPolygonXY newPoly;
175
+ int ringIndex = 0 ;
176
+ QgsPolygonXY::const_iterator polyIt = multiPolyIt->constBegin ();
177
+ for ( ; polyIt != multiPolyIt->constEnd (); ++polyIt )
178
+ {
179
+ if ( ringIndex == mModifiedRing )
180
+ {
181
+ const QgsMultiPolygonXY ringParts = mModifiedGeometry .asMultiPolygon ();
182
+ QgsPolygonXY newRings;
183
+ QgsMultiPolygonXY::const_iterator ringIt = ringParts.constBegin ();
184
+ for ( ; ringIt != ringParts.constEnd (); ++ringIt )
185
+ {
186
+ // the different parts of the new rings cannot have rings themselves
187
+ newRings.append ( ringIt->at ( 0 ) );
188
+ }
189
+ newPoly += newRings;
190
+ }
191
+ else
192
+ {
193
+ newPoly.append ( *polyIt );
194
+ }
195
+ ringIndex++;
196
+ }
197
+ newMultiPoly.append ( newPoly );
198
+ }
182
199
}
183
200
else
184
201
{
185
- newMultiPoly.append ( mModifiedGeometry .asPolygon () );
202
+ // original part had no ring
203
+ if ( mModifiedRing == -1 )
204
+ {
205
+ newMultiPoly.append ( mModifiedGeometry .asPolygon () );
206
+ }
207
+ else
208
+ {
209
+ QgsPolygonXY newPoly;
210
+ int ringIndex = 0 ;
211
+ QgsPolygonXY::const_iterator polyIt = multiPolyIt->constBegin ();
212
+ for ( ; polyIt != multiPolyIt->constEnd (); ++polyIt )
213
+ {
214
+ if ( ringIndex == mModifiedRing )
215
+ {
216
+ newPoly.append ( mModifiedGeometry .asPolygon ().at ( 0 ) );
217
+ }
218
+ else
219
+ {
220
+ newPoly.append ( *polyIt );
221
+ }
222
+ ringIndex++;
223
+ }
224
+ newMultiPoly.append ( newPoly );
225
+ }
186
226
}
187
227
}
188
228
else
@@ -196,6 +236,72 @@ void QgsMapToolOffsetCurve::applyOffset( const double &offset, const Qt::Keyboar
196
236
geometry.convertToMultiType ();
197
237
mModifiedGeometry = geometry;
198
238
}
239
+ else if ( mModifiedRing >= 0 )
240
+ {
241
+ // original geometry had some rings
242
+ if ( mModifiedGeometry .isMultipart () )
243
+ {
244
+ // not a ring
245
+ if ( mModifiedRing == 0 )
246
+ {
247
+ // polygon became mulitpolygon, that means discard original rings from the part
248
+ // keep the modified geometry as is
249
+ }
250
+ else
251
+ {
252
+ QgsPolygonXY newPoly;
253
+ const QgsPolygonXY poly = mOriginalGeometry .asPolygon ();
254
+
255
+ // ring became multipolygon, oh boy!
256
+ int ringIndex = 0 ;
257
+ QgsPolygonXY::const_iterator polyIt = poly.constBegin ();
258
+ for ( ; polyIt != poly.constEnd (); ++polyIt )
259
+ {
260
+ if ( ringIndex == mModifiedRing )
261
+ {
262
+ QgsMultiPolygonXY ringParts = mModifiedGeometry .asMultiPolygon ();
263
+ QgsPolygonXY newRings;
264
+ QgsMultiPolygonXY::const_iterator ringIt = ringParts.constBegin ();
265
+ for ( ; ringIt != ringParts.constEnd (); ++ringIt )
266
+ {
267
+ // the different parts of the new rings cannot have rings themselves
268
+ newRings.append ( ringIt->at ( 0 ) );
269
+ }
270
+ newPoly += newRings;
271
+ }
272
+ else
273
+ {
274
+ newPoly.append ( *polyIt );
275
+ }
276
+ ringIndex++;
277
+ }
278
+ mModifiedGeometry = QgsGeometry::fromPolygonXY ( newPoly );
279
+ }
280
+ }
281
+ else
282
+ {
283
+ // simple case where modified geom is a polygon (not multi)
284
+ QgsPolygonXY newPoly;
285
+ const QgsPolygonXY poly = mOriginalGeometry .asPolygon ();
286
+
287
+ int ringIndex = 0 ;
288
+ QgsPolygonXY::const_iterator polyIt = poly.constBegin ();
289
+ for ( ; polyIt != poly.constEnd (); ++polyIt )
290
+ {
291
+ if ( ringIndex == mModifiedRing )
292
+ {
293
+ newPoly.append ( mModifiedGeometry .asPolygon ().at ( 0 ) );
294
+ }
295
+ else
296
+ {
297
+ newPoly.append ( *polyIt );
298
+ }
299
+ ringIndex++;
300
+ }
301
+ mModifiedGeometry = QgsGeometry::fromPolygonXY ( newPoly );
302
+ }
303
+
304
+ }
199
305
200
306
mLayer ->beginEditCommand ( tr ( " Offset curve" ) );
201
307
@@ -288,17 +394,18 @@ void QgsMapToolOffsetCurve::canvasMoveEvent( QgsMapMouseEvent *e )
288
394
updateGeometryAndRubberBand ( offset );
289
395
}
290
396
291
- void QgsMapToolOffsetCurve::prepareGeometry ( QgsVectorLayer *vl, const QgsPointLocator::Match &match, QgsFeature &snappedFeature )
397
+ void QgsMapToolOffsetCurve::prepareGeometry ( const QgsPointLocator::Match &match, QgsFeature &snappedFeature )
292
398
{
399
+ QgsVectorLayer *vl = match.layer ();
293
400
if ( !vl )
294
401
{
295
402
return ;
296
403
}
297
404
298
405
mOriginalGeometry = QgsGeometry ();
299
406
mManipulatedGeometry = QgsGeometry ();
300
- mMultiPartGeometry = false ;
301
- mModifiedPart = 0 ;
407
+ mModifiedPart = - 1 ;
408
+ mModifiedRing = - 1 ;
302
409
303
410
// assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment)
304
411
QgsGeometry geom = snappedFeature.geometry ();
@@ -311,14 +418,16 @@ void QgsMapToolOffsetCurve::prepareGeometry( QgsVectorLayer *vl, const QgsPointL
311
418
QgsWkbTypes::Type geomType = geom.wkbType ();
312
419
if ( QgsWkbTypes::geometryType ( geomType ) == QgsWkbTypes::LineGeometry )
313
420
{
421
+ if ( !match.hasEdge () )
422
+ {
423
+ return ;
424
+ }
314
425
if ( !geom.isMultipart () )
315
426
{
316
427
mManipulatedGeometry = geom;
317
428
}
318
429
else
319
430
{
320
- mMultiPartGeometry = true ;
321
-
322
431
int vertex = match.vertexIndex ();
323
432
QgsVertexId vertexId;
324
433
geom.vertexIdFromVertexNr ( vertex, vertexId );
@@ -330,21 +439,67 @@ void QgsMapToolOffsetCurve::prepareGeometry( QgsVectorLayer *vl, const QgsPointL
330
439
}
331
440
else if ( QgsWkbTypes::geometryType ( geomType ) == QgsWkbTypes::PolygonGeometry )
332
441
{
333
- if ( !geom. isMultipart () )
442
+ if ( !match. hasEdge () && match. hasArea () )
334
443
{
335
- mManipulatedGeometry = geom;
444
+ if ( !geom.isMultipart () )
445
+ {
446
+ mManipulatedGeometry = geom;
447
+ }
448
+ else
449
+ {
450
+ // get the correct part
451
+ QgsMultiPolygonXY mpolygon = geom.asMultiPolygon ();
452
+ for ( int part = 0 ; part < mpolygon.count (); part++ ) // go through the polygons
453
+ {
454
+ const QgsPolygonXY &polygon = mpolygon[part];
455
+ QgsGeometry partGeo = QgsGeometry::fromPolygonXY ( polygon );
456
+ const QgsPointXY layerCoords = match.point ();
457
+ if ( partGeo.contains ( &layerCoords ) )
458
+ {
459
+ mModifiedPart = part;
460
+ mManipulatedGeometry = partGeo;
461
+ }
462
+ }
463
+ }
336
464
}
337
- else
465
+ else if ( match. hasEdge () )
338
466
{
339
- mMultiPartGeometry = true ;
340
-
341
467
int vertex = match.vertexIndex ();
342
468
QgsVertexId vertexId;
343
469
geom.vertexIdFromVertexNr ( vertex, vertexId );
344
- mModifiedPart = vertexId.part ;
470
+ QgsDebugMsg ( QString ( " %1 " ). arg ( vertexId.ring ) ) ;
345
471
346
- QgsMultiPolygonXY multiPoly = geom.asMultiPolygon ();
347
- mManipulatedGeometry = QgsGeometry::fromPolygonXY ( multiPoly.at ( mModifiedPart ) );
472
+ if ( !geom.isMultipart () )
473
+ {
474
+ QgsPolygonXY poly = geom.asPolygon ();
475
+ // if has rings
476
+ if ( poly.count () > 0 )
477
+ {
478
+ mModifiedRing = vertexId.ring ;
479
+ mManipulatedGeometry = QgsGeometry::fromPolygonXY ( QgsPolygonXY () << poly.at ( mModifiedRing ) );
480
+ }
481
+ else
482
+ {
483
+ mManipulatedGeometry = QgsGeometry::fromPolygonXY ( poly );
484
+ }
485
+
486
+ }
487
+ else
488
+ {
489
+ mModifiedPart = vertexId.part ;
490
+ // get part, get ring
491
+ QgsMultiPolygonXY multiPoly = geom.asMultiPolygon ();
492
+ // if has rings
493
+ if ( multiPoly.at ( mModifiedPart ).count () > 0 )
494
+ {
495
+ mModifiedRing = vertexId.ring ;
496
+ mManipulatedGeometry = QgsGeometry::fromPolygonXY ( QgsPolygonXY () << multiPoly.at ( mModifiedPart ).at ( mModifiedRing ) );
497
+ }
498
+ else
499
+ {
500
+ mManipulatedGeometry = QgsGeometry::fromPolygonXY ( multiPoly.at ( mModifiedPart ) );
501
+ }
502
+ }
348
503
}
349
504
}
350
505
}
@@ -421,6 +576,7 @@ void QgsMapToolOffsetCurve::updateGeometryAndRubberBand( double offset )
421
576
deleteUserInputWidget ();
422
577
mLayer = nullptr ;
423
578
mGeometryModified = false ;
579
+ emit messageDiscarded ();
424
580
emit messageEmitted ( tr ( " Creating offset geometry failed: %1" ).arg ( offsetGeom.lastError () ), Qgis::Critical );
425
581
}
426
582
else
0 commit comments