Skip to content

Commit

Permalink
[bugfix] Do no add binding line in both side in reshape map tool
Browse files Browse the repository at this point in the history
  • Loading branch information
pblottiere committed Dec 6, 2017
1 parent aa68a9f commit 096f689
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 56 deletions.
150 changes: 96 additions & 54 deletions src/app/qgsmaptoolreshape.cpp
Expand Up @@ -74,74 +74,116 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
stopCapturing();
return;
}
QgsPointXY firstPoint = points().at( 0 );
QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
for ( int i = 1; i < size(); ++i )

reshape( vlayer );

stopCapturing();
}
}

bool QgsMapToolReshape::isBindingLine( QgsVectorLayer *vlayer, const QgsRectangle &bbox ) const
{
if ( vlayer->geometryType() != QgsWkbTypes::LineGeometry )
return false;

bool begin = false;
bool end = false;
const QgsPointXY beginPoint = points().first();
const QgsPointXY endPoint = points().last();

QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeature f;

// check that extremities of the new line are contained by features
while ( fit.nextFeature( f ) )
{
const QgsGeometry geom = f.geometry();
if ( !geom.isNull() )
{
bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
const QgsPolylineXY line = geom.asPolyline();

if ( line.contains( beginPoint ) )
begin = true;
else if ( line.contains( endPoint ) )
end = true;
}
}

QgsLineString reshapeLineString( points() );
if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
reshapeLineString.addZValue( defaultZValue() );
return end && begin;
}

void QgsMapToolReshape::reshape( QgsVectorLayer *vlayer )
{
QgsPointXY firstPoint = points().at( 0 );
QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
for ( int i = 1; i < size(); ++i )
{
bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
}

//query all the features that intersect bounding box of capture line
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeature f;
int reshapeReturn;
bool reshapeDone = false;
QgsLineString reshapeLineString( points() );
if ( QgsWkbTypes::hasZ( vlayer->wkbType() ) )
reshapeLineString.addZValue( defaultZValue() );

vlayer->beginEditCommand( tr( "Reshape" ) );
while ( fit.nextFeature( f ) )
//query all the features that intersect bounding box of capture line
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
QgsFeature f;
int reshapeReturn;
bool reshapeDone = false;
bool isBinding = isBindingLine( vlayer, bbox );

vlayer->beginEditCommand( tr( "Reshape" ) );
while ( fit.nextFeature( f ) )
{
//query geometry
//call geometry->reshape(mCaptureList)
//register changed geometry in vector layer
QgsGeometry geom = f.geometry();
if ( !geom.isNull() )
{
//query geometry
//call geometry->reshape(mCaptureList)
//register changed geometry in vector layer
QgsGeometry geom = f.geometry();
if ( !geom.isNull() )
// in case of a binding line, we just want to update the line from
// the starting point and not both side
if ( isBinding && !geom.asPolyline().contains( points().first() ) )
continue;

reshapeReturn = geom.reshapeGeometry( reshapeLineString );
if ( reshapeReturn == 0 )
{
reshapeReturn = geom.reshapeGeometry( reshapeLineString );
if ( reshapeReturn == 0 )
//avoid intersections on polygon layers
if ( vlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
{
//avoid intersections on polygon layers
if ( vlayer->geometryType() == QgsWkbTypes::PolygonGeometry )
//ignore all current layer features as they should be reshaped too
QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures;
ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );

if ( geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers(), ignoreFeatures ) != 0 )
{
//ignore all current layer features as they should be reshaped too
QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures;
ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );

if ( geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers(), ignoreFeatures ) != 0 )
{
emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
vlayer->destroyEditCommand();
stopCapturing();
return;
}

if ( geom.isEmpty() ) //intersection removal might have removed the whole geometry
{
emit messageEmitted( tr( "The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
vlayer->destroyEditCommand();
stopCapturing();
return;
}
emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
vlayer->destroyEditCommand();
stopCapturing();
return;
}

vlayer->changeGeometry( f.id(), geom );
reshapeDone = true;
if ( geom.isEmpty() ) //intersection removal might have removed the whole geometry
{
emit messageEmitted( tr( "The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
vlayer->destroyEditCommand();
return;
}
}
}
}

if ( reshapeDone )
{
vlayer->endEditCommand();
}
else
{
vlayer->destroyEditCommand();
vlayer->changeGeometry( f.id(), geom );
reshapeDone = true;
}
}
}

stopCapturing();
if ( reshapeDone )
{
vlayer->endEditCommand();
}
else
{
vlayer->destroyEditCommand();
}
}
7 changes: 7 additions & 0 deletions src/app/qgsmaptoolreshape.h
Expand Up @@ -27,6 +27,13 @@ class APP_EXPORT QgsMapToolReshape: public QgsMapToolCapture
public:
QgsMapToolReshape( QgsMapCanvas *canvas );
void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override;

private:
void reshape( QgsVectorLayer *vlayer );

bool isBindingLine( QgsVectorLayer *vlayer, const QgsRectangle &bbox ) const;

friend class TestQgsMapToolReshape;
};

#endif
2 changes: 1 addition & 1 deletion src/gui/qgsmaptoolcapture.cpp
Expand Up @@ -763,7 +763,7 @@ int QgsMapToolCapture::size()
return mCaptureCurve.numPoints();
}

QVector<QgsPointXY> QgsMapToolCapture::points()
QVector<QgsPointXY> QgsMapToolCapture::points() const
{
QgsPointSequence pts;
QVector<QgsPointXY> points;
Expand Down
4 changes: 3 additions & 1 deletion src/gui/qgsmaptoolcapture.h
Expand Up @@ -192,7 +192,7 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
* List of digitized points
* \returns List of points
*/
QVector<QgsPointXY> points();
QVector<QgsPointXY> points() const;

/**
* Set the points on which to work
Expand Down Expand Up @@ -259,6 +259,8 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
*/
QgsPointXY mTracingStartPoint;

friend class TestQgsMapToolReshape;

#ifdef Q_OS_WIN
int mSkipNextContextMenuEvent;
#endif
Expand Down

0 comments on commit 096f689

Please sign in to comment.