@@ -93,7 +93,7 @@ void QgsMapToolOffsetCurve::canvasReleaseEvent( QgsMapMouseEvent *e )
93
93
// setup new settings (temporary)
94
94
QgsSettings settings;
95
95
config.setEnabled ( true );
96
- config.setMode ( QgsSnappingConfig::AllLayers );
96
+ config.setMode ( QgsSnappingConfig::ActiveLayer );
97
97
config.setType ( QgsSnappingConfig::Segment );
98
98
config.setTolerance ( settings.value ( QStringLiteral ( " qgis/digitizing/search_radius_vertex_edit" ), 10 ).toDouble () );
99
99
config.setUnits ( static_cast <QgsTolerance::UnitType>( settings.value ( QStringLiteral ( " qgis/digitizing/search_radius_vertex_edit_unit" ), QgsTolerance::Pixels ).toInt () ) );
@@ -111,11 +111,11 @@ void QgsMapToolOffsetCurve::canvasReleaseEvent( QgsMapMouseEvent *e )
111
111
if ( match.layer ()->getFeatures ( QgsFeatureRequest ( match.featureId () ) ).nextFeature ( fet ) )
112
112
{
113
113
mCtrlWasHeldOnFeatureSelection = ( e->modifiers () & Qt::ControlModifier ); // no geometry modification if ctrl is pressed
114
- mOriginalGeometry = createOriginGeometry ( match.layer (), match, fet );
114
+ prepareGeometry ( match.layer (), match, fet );
115
115
mRubberBand = createRubberBand ();
116
116
if ( mRubberBand )
117
117
{
118
- mRubberBand ->setToGeometry ( mOriginalGeometry , layer );
118
+ mRubberBand ->setToGeometry ( mManipulatedGeometry , layer );
119
119
}
120
120
mModifiedFeature = fet.id ();
121
121
createDistanceWidget ();
@@ -155,7 +155,56 @@ void QgsMapToolOffsetCurve::applyOffset( bool forceCopy )
155
155
156
156
if ( mMultiPartGeometry )
157
157
{
158
- mModifiedGeometry .convertToMultiType ();
158
+ QgsGeometry geometry;
159
+ int partIndex = 0 ;
160
+ QgsWkbTypes::Type geomType = mOriginalGeometry .wkbType ();
161
+ if ( QgsWkbTypes::geometryType ( geomType ) == QgsWkbTypes::LineGeometry )
162
+ {
163
+ QgsMultiPolylineXY newMultiLine;
164
+ QgsMultiPolylineXY multiLine = mOriginalGeometry .asMultiPolyline ();
165
+ QgsMultiPolylineXY::const_iterator it = multiLine.constBegin ();
166
+ for ( ; it != multiLine.constEnd (); ++it )
167
+ {
168
+ if ( partIndex == mModifiedPart )
169
+ {
170
+ newMultiLine.append ( mModifiedGeometry .asPolyline () );
171
+ }
172
+ else
173
+ {
174
+ newMultiLine.append ( *it );
175
+ }
176
+ partIndex++;
177
+ }
178
+ geometry = QgsGeometry::fromMultiPolylineXY ( newMultiLine );
179
+ }
180
+ else
181
+ {
182
+ QgsMultiPolygonXY newMultiPoly;
183
+ QgsMultiPolygonXY multiPoly = mOriginalGeometry .asMultiPolygon ();
184
+ QgsMultiPolygonXY::const_iterator multiPolyIt = multiPoly.constBegin ();
185
+ for ( ; multiPolyIt != multiPoly.constEnd (); ++multiPolyIt )
186
+ {
187
+ if ( partIndex == mModifiedPart )
188
+ {
189
+ if ( mModifiedGeometry .isMultipart () )
190
+ {
191
+ newMultiPoly += mModifiedGeometry .asMultiPolygon ();
192
+ }
193
+ else
194
+ {
195
+ newMultiPoly.append ( mModifiedGeometry .asPolygon () );
196
+ }
197
+ }
198
+ else
199
+ {
200
+ newMultiPoly.append ( *multiPolyIt );
201
+ }
202
+ partIndex++;
203
+ }
204
+ geometry = QgsGeometry::fromMultiPolygonXY ( newMultiPoly );
205
+ }
206
+ geometry.convertToMultiType ();
207
+ mModifiedGeometry = geometry;
159
208
}
160
209
161
210
layer->beginEditCommand ( tr ( " Offset curve" ) );
@@ -248,73 +297,79 @@ void QgsMapToolOffsetCurve::canvasMoveEvent( QgsMapMouseEvent *e )
248
297
{
249
298
return ;
250
299
}
251
-
300
+ offset = leftOf < 0 ? offset : -offset;
252
301
253
302
254
303
if ( mDistanceWidget )
255
304
{
256
305
// this will also set the rubber band
257
- mDistanceWidget ->setValue ( leftOf < 0 ? offset : - offset );
306
+ mDistanceWidget ->setValue ( offset );
258
307
mDistanceWidget ->setFocus ( Qt::TabFocusReason );
259
308
}
260
309
else
261
310
{
262
311
// create offset geometry using geos
263
- setOffsetForRubberBand ( leftOf < 0 ? offset : - offset );
312
+ setOffsetForRubberBand ( offset );
264
313
}
265
314
}
266
315
267
- QgsGeometry QgsMapToolOffsetCurve::createOriginGeometry ( QgsVectorLayer *vl, const QgsPointLocator::Match &match, QgsFeature &snappedFeature )
316
+ void QgsMapToolOffsetCurve::prepareGeometry ( QgsVectorLayer *vl, const QgsPointLocator::Match &match, QgsFeature &snappedFeature )
268
317
{
269
318
if ( !vl )
270
319
{
271
- return QgsGeometry () ;
320
+ return ;
272
321
}
273
322
323
+ mOriginalGeometry = QgsGeometry ();
324
+ mManipulatedGeometry = QgsGeometry ();
274
325
mMultiPartGeometry = false ;
275
- // assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment)
276
- int partVertexNr = match.vertexIndex ();
326
+ mModifiedPart = 0 ;
277
327
278
- if ( vl == currentVectorLayer () && !mCtrlWasHeldOnFeatureSelection )
328
+ // assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment)
329
+ QgsGeometry geom = snappedFeature.geometry ();
330
+ if ( geom.isNull () )
279
331
{
280
- // don't consider selected geometries, only the snap result
281
- return convertToSingleLine ( snappedFeature.geometry (), partVertexNr, mMultiPartGeometry );
332
+ return ;
282
333
}
283
- else // snapped to a background layer
334
+ mOriginalGeometry = geom;
335
+
336
+ QgsWkbTypes::Type geomType = geom.wkbType ();
337
+ if ( QgsWkbTypes::geometryType ( geomType ) == QgsWkbTypes::LineGeometry )
284
338
{
285
- // if source layer is polygon / multipolygon, create a linestring from the snapped ring
286
- if ( vl->geometryType () == QgsWkbTypes::PolygonGeometry )
339
+ if ( !geom.isMultipart () )
287
340
{
288
- // make linestring from polygon ring and return this geometry
289
- return linestringFromPolygon ( snappedFeature.geometry (), partVertexNr );
341
+ mManipulatedGeometry = geom;
290
342
}
343
+ else
344
+ {
345
+ mMultiPartGeometry = true ;
346
+
347
+ int vertex = match.vertexIndex ();
348
+ QgsVertexId vertexId;
349
+ geom.vertexIdFromVertexNr ( vertex, vertexId );
350
+ mModifiedPart = vertexId.part ;
291
351
292
- // for background layers, try to merge selected entries together if snapped feature is contained in selection
293
- const QgsFeatureIds &selection = vl->selectedFeatureIds ();
294
- if ( selection.empty () || !selection.contains ( match.featureId () ) )
352
+ QgsMultiPolylineXY multiLine = geom.asMultiPolyline ();
353
+ mManipulatedGeometry = QgsGeometry::fromPolylineXY ( multiLine.at ( mModifiedPart ) );
354
+ }
355
+ }
356
+ else if ( QgsWkbTypes::geometryType ( geomType ) == QgsWkbTypes::PolygonGeometry )
357
+ {
358
+ if ( !geom.isMultipart () )
295
359
{
296
- return convertToSingleLine ( snappedFeature. geometry (), partVertexNr, mMultiPartGeometry ) ;
360
+ mManipulatedGeometry = geom ;
297
361
}
298
362
else
299
363
{
300
- // merge together if several features
301
- QgsFeatureList selectedFeatures = vl->selectedFeatures ();
302
- QgsFeatureList::iterator selIt = selectedFeatures.begin ();
303
- QgsGeometry geom = selIt->geometry ();
304
- ++selIt;
305
- for ( ; selIt != selectedFeatures.end (); ++selIt )
306
- {
307
- geom = geom.combine ( selIt->geometry () );
308
- }
364
+ mMultiPartGeometry = true ;
309
365
310
- // if multitype, return only the snapped to geometry
311
- if ( geom.isMultipart () )
312
- {
313
- return convertToSingleLine ( snappedFeature.geometry (),
314
- match.vertexIndex (), mMultiPartGeometry );
315
- }
366
+ int vertex = match.vertexIndex ();
367
+ QgsVertexId vertexId;
368
+ geom.vertexIdFromVertexNr ( vertex, vertexId );
369
+ mModifiedPart = vertexId.part ;
316
370
317
- return geom;
371
+ QgsMultiPolygonXY multiPoly = geom.asMultiPolygon ();
372
+ mManipulatedGeometry = QgsGeometry::fromPolygonXY ( multiPoly.at ( mModifiedPart ) );
318
373
}
319
374
}
320
375
}
@@ -356,6 +411,7 @@ void QgsMapToolOffsetCurve::deleteDistanceWidget()
356
411
void QgsMapToolOffsetCurve::deleteRubberBandAndGeometry ()
357
412
{
358
413
mOriginalGeometry .set ( nullptr );
414
+ mManipulatedGeometry .set ( nullptr );
359
415
delete mRubberBand ;
360
416
mRubberBand = nullptr ;
361
417
}
@@ -378,7 +434,16 @@ void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset )
378
434
int quadSegments = s.value ( QStringLiteral ( " /qgis/digitizing/offset_quad_seg" ), 8 ).toInt ();
379
435
double miterLimit = s.value ( QStringLiteral ( " /qgis/digitizing/offset_miter_limit" ), 5.0 ).toDouble ();
380
436
381
- QgsGeometry offsetGeom = mOriginalGeometry .offsetCurve ( offset, quadSegments, joinStyle, miterLimit );
437
+ QgsGeometry offsetGeom;
438
+ if ( QgsWkbTypes::geometryType ( mOriginalGeometry .wkbType () ) == QgsWkbTypes::LineGeometry )
439
+ {
440
+ offsetGeom = mManipulatedGeometry .offsetCurve ( offset, quadSegments, joinStyle, miterLimit );
441
+ }
442
+ else
443
+ {
444
+ offsetGeom = mManipulatedGeometry .buffer ( offset, quadSegments, QgsGeometry::CapRound, joinStyle, miterLimit );
445
+ }
446
+
382
447
if ( !offsetGeom )
383
448
{
384
449
deleteRubberBandAndGeometry ();
@@ -396,80 +461,3 @@ void QgsMapToolOffsetCurve::setOffsetForRubberBand( double offset )
396
461
mRubberBand ->setToGeometry ( mModifiedGeometry , sourceLayer );
397
462
}
398
463
}
399
-
400
- QgsGeometry QgsMapToolOffsetCurve::linestringFromPolygon ( const QgsGeometry &featureGeom, int vertex )
401
- {
402
- if ( featureGeom.isNull () )
403
- {
404
- return QgsGeometry ();
405
- }
406
-
407
- QgsWkbTypes::Type geomType = featureGeom.wkbType ();
408
- int currentVertex = 0 ;
409
- QgsMultiPolygonXY multiPoly;
410
-
411
- if ( geomType == QgsWkbTypes::Polygon || geomType == QgsWkbTypes::Polygon25D )
412
- {
413
- QgsPolygonXY polygon = featureGeom.asPolygon ();
414
- multiPoly.append ( polygon );
415
- }
416
- else if ( geomType == QgsWkbTypes::MultiPolygon || geomType == QgsWkbTypes::MultiPolygon25D )
417
- {
418
- // iterate all polygons / rings
419
- multiPoly = featureGeom.asMultiPolygon ();
420
- }
421
- else
422
- {
423
- return QgsGeometry ();
424
- }
425
-
426
- QgsMultiPolygonXY::const_iterator multiPolyIt = multiPoly.constBegin ();
427
- for ( ; multiPolyIt != multiPoly.constEnd (); ++multiPolyIt )
428
- {
429
- QgsPolygonXY::const_iterator polyIt = multiPolyIt->constBegin ();
430
- for ( ; polyIt != multiPolyIt->constEnd (); ++polyIt )
431
- {
432
- currentVertex += polyIt->size ();
433
- if ( vertex < currentVertex )
434
- {
435
- // found, return ring
436
- return QgsGeometry::fromPolylineXY ( *polyIt );
437
- }
438
- }
439
- }
440
-
441
- return QgsGeometry ();
442
- }
443
-
444
-
445
- QgsGeometry QgsMapToolOffsetCurve::convertToSingleLine ( const QgsGeometry &geom, int vertex, bool &isMulti )
446
- {
447
- if ( geom.isNull () )
448
- {
449
- return QgsGeometry ();
450
- }
451
-
452
- isMulti = false ;
453
- QgsWkbTypes::Type geomType = geom.wkbType ();
454
- if ( geomType == QgsWkbTypes::LineString || geomType == QgsWkbTypes::LineString25D )
455
- {
456
- return geom;
457
- }
458
- else if ( geomType == QgsWkbTypes::MultiLineString || geomType == QgsWkbTypes::MultiLineString25D )
459
- {
460
- // search vertex
461
- isMulti = true ;
462
- int currentVertex = 0 ;
463
- QgsMultiPolylineXY multiLine = geom.asMultiPolyline ();
464
- QgsMultiPolylineXY::const_iterator it = multiLine.constBegin ();
465
- for ( ; it != multiLine.constEnd (); ++it )
466
- {
467
- currentVertex += it->size ();
468
- if ( vertex < currentVertex )
469
- {
470
- return QgsGeometry::fromPolylineXY ( *it );
471
- }
472
- }
473
- }
474
- return QgsGeometry ();
475
- }
0 commit comments