@@ -74,74 +74,116 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
7474 stopCapturing ();
7575 return ;
7676 }
77- QgsPointXY firstPoint = points ().at ( 0 );
78- QgsRectangle bbox ( firstPoint.x (), firstPoint.y (), firstPoint.x (), firstPoint.y () );
79- for ( int i = 1 ; i < size (); ++i )
77+
78+ reshape ( vlayer );
79+
80+ stopCapturing ();
81+ }
82+ }
83+
84+ bool QgsMapToolReshape::isBindingLine ( QgsVectorLayer *vlayer, const QgsRectangle &bbox ) const
85+ {
86+ if ( vlayer->geometryType () != QgsWkbTypes::LineGeometry )
87+ return false ;
88+
89+ bool begin = false ;
90+ bool end = false ;
91+ const QgsPointXY beginPoint = points ().first ();
92+ const QgsPointXY endPoint = points ().last ();
93+
94+ QgsFeatureIterator fit = vlayer->getFeatures ( QgsFeatureRequest ().setFilterRect ( bbox ).setSubsetOfAttributes ( QgsAttributeList () ) );
95+ QgsFeature f;
96+
97+ // check that extremities of the new line are contained by features
98+ while ( fit.nextFeature ( f ) )
99+ {
100+ const QgsGeometry geom = f.geometry ();
101+ if ( !geom.isNull () )
80102 {
81- bbox.combineExtentWith ( points ().at ( i ).x (), points ().at ( i ).y () );
103+ const QgsPolylineXY line = geom.asPolyline ();
104+
105+ if ( line.contains ( beginPoint ) )
106+ begin = true ;
107+ else if ( line.contains ( endPoint ) )
108+ end = true ;
82109 }
110+ }
83111
84- QgsLineString reshapeLineString ( points () );
85- if ( QgsWkbTypes::hasZ ( vlayer->wkbType () ) )
86- reshapeLineString.addZValue ( defaultZValue () );
112+ return end && begin;
113+ }
114+
115+ void QgsMapToolReshape::reshape ( QgsVectorLayer *vlayer )
116+ {
117+ QgsPointXY firstPoint = points ().at ( 0 );
118+ QgsRectangle bbox ( firstPoint.x (), firstPoint.y (), firstPoint.x (), firstPoint.y () );
119+ for ( int i = 1 ; i < size (); ++i )
120+ {
121+ bbox.combineExtentWith ( points ().at ( i ).x (), points ().at ( i ).y () );
122+ }
87123
88- // query all the features that intersect bounding box of capture line
89- QgsFeatureIterator fit = vlayer->getFeatures ( QgsFeatureRequest ().setFilterRect ( bbox ).setSubsetOfAttributes ( QgsAttributeList () ) );
90- QgsFeature f;
91- int reshapeReturn;
92- bool reshapeDone = false ;
124+ QgsLineString reshapeLineString ( points () );
125+ if ( QgsWkbTypes::hasZ ( vlayer->wkbType () ) )
126+ reshapeLineString.addZValue ( defaultZValue () );
93127
94- vlayer->beginEditCommand ( tr ( " Reshape" ) );
95- while ( fit.nextFeature ( f ) )
128+ // query all the features that intersect bounding box of capture line
129+ QgsFeatureIterator fit = vlayer->getFeatures ( QgsFeatureRequest ().setFilterRect ( bbox ).setSubsetOfAttributes ( QgsAttributeList () ) );
130+ QgsFeature f;
131+ int reshapeReturn;
132+ bool reshapeDone = false ;
133+ bool isBinding = isBindingLine ( vlayer, bbox );
134+
135+ vlayer->beginEditCommand ( tr ( " Reshape" ) );
136+ while ( fit.nextFeature ( f ) )
137+ {
138+ // query geometry
139+ // call geometry->reshape(mCaptureList)
140+ // register changed geometry in vector layer
141+ QgsGeometry geom = f.geometry ();
142+ if ( !geom.isNull () )
96143 {
97- // query geometry
98- // call geometry->reshape(mCaptureList)
99- // register changed geometry in vector layer
100- QgsGeometry geom = f.geometry ();
101- if ( !geom.isNull () )
144+ // in case of a binding line, we just want to update the line from
145+ // the starting point and not both side
146+ if ( isBinding && !geom.asPolyline ().contains ( points ().first () ) )
147+ continue ;
148+
149+ reshapeReturn = geom.reshapeGeometry ( reshapeLineString );
150+ if ( reshapeReturn == 0 )
102151 {
103- reshapeReturn = geom. reshapeGeometry ( reshapeLineString );
104- if ( reshapeReturn == 0 )
152+ // avoid intersections on polygon layers
153+ if ( vlayer-> geometryType () == QgsWkbTypes::PolygonGeometry )
105154 {
106- // avoid intersections on polygon layers
107- if ( vlayer->geometryType () == QgsWkbTypes::PolygonGeometry )
155+ // ignore all current layer features as they should be reshaped too
156+ QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures;
157+ ignoreFeatures.insert ( vlayer, vlayer->allFeatureIds () );
158+
159+ if ( geom.avoidIntersections ( QgsProject::instance ()->avoidIntersectionsLayers (), ignoreFeatures ) != 0 )
108160 {
109- // ignore all current layer features as they should be reshaped too
110- QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures;
111- ignoreFeatures.insert ( vlayer, vlayer->allFeatureIds () );
112-
113- if ( geom.avoidIntersections ( QgsProject::instance ()->avoidIntersectionsLayers (), ignoreFeatures ) != 0 )
114- {
115- emit messageEmitted ( tr ( " An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
116- vlayer->destroyEditCommand ();
117- stopCapturing ();
118- return ;
119- }
120-
121- if ( geom.isEmpty () ) // intersection removal might have removed the whole geometry
122- {
123- emit messageEmitted ( tr ( " The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
124- vlayer->destroyEditCommand ();
125- stopCapturing ();
126- return ;
127- }
161+ emit messageEmitted ( tr ( " An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
162+ vlayer->destroyEditCommand ();
163+ stopCapturing ();
164+ return ;
128165 }
129166
130- vlayer->changeGeometry ( f.id (), geom );
131- reshapeDone = true ;
167+ if ( geom.isEmpty () ) // intersection removal might have removed the whole geometry
168+ {
169+ emit messageEmitted ( tr ( " The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
170+ vlayer->destroyEditCommand ();
171+ return ;
172+ }
132173 }
133- }
134- }
135174
136- if ( reshapeDone )
137- {
138- vlayer->endEditCommand ();
139- }
140- else
141- {
142- vlayer->destroyEditCommand ();
175+ vlayer->changeGeometry ( f.id (), geom );
176+ reshapeDone = true ;
177+ }
143178 }
179+ }
144180
145- stopCapturing ();
181+ if ( reshapeDone )
182+ {
183+ vlayer->endEditCommand ();
184+ }
185+ else
186+ {
187+ vlayer->destroyEditCommand ();
146188 }
147189}
0 commit comments