void QgsMapToolAddPart::canvasReleaseEvent( QgsMapMouseEvent *e ) { if ( checkSelection() ) { QgsMapToolAdvancedDigitizing::canvasReleaseEvent( e ); } else { cadDockWidget()->clear(); } }
void QgsMapToolDigitizeFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayer ); if ( !vlayer ) //if no given layer take the current from canvas vlayer = currentVectorLayer(); if ( !vlayer ) { notifyNotVectorLayer(); return; } QgsWkbTypes::Type layerWKBType = vlayer->wkbType(); QgsVectorDataProvider *provider = vlayer->dataProvider(); if ( !( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) ) { emit messageEmitted( tr( "The data provider for this layer does not support the addition of features." ), Qgis::Warning ); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } // POINT CAPTURING if ( mode() == CapturePoint ) { if ( e->button() != Qt::LeftButton ) return; //check we only use this tool for point/multipoint layers if ( vlayer->geometryType() != QgsWkbTypes::PointGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture point' tool on this vector layer" ), Qgis::Warning ); return; } QgsPointXY savePoint; //point in layer coordinates try { QgsPoint fetchPoint; int res; res = fetchLayerPoint( e->mapPointMatch(), fetchPoint ); if ( res == 0 ) { savePoint = QgsPointXY( fetchPoint.x(), fetchPoint.y() ); } else { savePoint = toLayerCoordinates( vlayer, e->mapPoint() ); } QgsDebugMsg( "savePoint = " + savePoint.toString() ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::Warning ); return; } //only do the rest for provider with feature addition support //note that for the grass provider, this will return false since //grass provider has its own mechanism of feature addition if ( provider->capabilities() & QgsVectorDataProvider::AddFeatures ) { QgsFeature f( vlayer->fields(), 0 ); QgsGeometry g; if ( layerWKBType == QgsWkbTypes::Point ) { g = QgsGeometry::fromPointXY( savePoint ); } else if ( !QgsWkbTypes::isMultiType( layerWKBType ) && QgsWkbTypes::hasZ( layerWKBType ) ) { g = QgsGeometry( new QgsPoint( QgsWkbTypes::PointZ, savePoint.x(), savePoint.y(), defaultZValue() ) ); } else if ( QgsWkbTypes::isMultiType( layerWKBType ) && !QgsWkbTypes::hasZ( layerWKBType ) ) { g = QgsGeometry::fromMultiPointXY( QgsMultiPointXY() << savePoint ); } else if ( QgsWkbTypes::isMultiType( layerWKBType ) && QgsWkbTypes::hasZ( layerWKBType ) ) { QgsMultiPoint *mp = new QgsMultiPoint(); mp->addGeometry( new QgsPoint( QgsWkbTypes::PointZ, savePoint.x(), savePoint.y(), defaultZValue() ) ); g = QgsGeometry( mp ); } else { // if layer supports more types (mCheckGeometryType is false) g = QgsGeometry::fromPointXY( savePoint ); } if ( QgsWkbTypes::hasM( layerWKBType ) ) { g.get()->addMValue(); } f.setGeometry( g ); f.setValid( true ); digitized( f ); // we are done with digitizing for now so instruct advanced digitizing dock to reset its CAD points cadDockWidget()->clearPoints(); } } // LINE AND POLYGON CAPTURING else if ( mode() == CaptureLine || mode() == CapturePolygon ) { //check we only use the line tool for line/multiline layers if ( mode() == CaptureLine && vlayer->geometryType() != QgsWkbTypes::LineGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture line' tool on this vector layer" ), Qgis::Warning ); return; } //check we only use the polygon tool for polygon/multipolygon layers if ( mode() == CapturePolygon && vlayer->geometryType() != QgsWkbTypes::PolygonGeometry && mCheckGeometryType ) { emit messageEmitted( tr( "Wrong editing tool, cannot apply the 'capture polygon' tool on this vector layer" ), Qgis::Warning ); return; } //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->mapPoint(), e->mapPointMatch() ); if ( error == 1 ) { //current layer is not a vector layer return; } else if ( error == 2 ) { //problem with coordinate transformation emit messageEmitted( tr( "Cannot transform the point to the layers coordinate system" ), Qgis::Warning ); return; } startCapturing(); } else if ( e->button() == Qt::RightButton ) { // End of string deleteTempRubberBand(); //lines: bail out if there are not at least two vertices if ( mode() == CaptureLine && size() < 2 ) { stopCapturing(); return; } //polygons: bail out if there are not at least two vertices if ( mode() == CapturePolygon && size() < 3 ) { stopCapturing(); return; } if ( mode() == CapturePolygon ) { closePolygon(); } //create QgsFeature with wkb representation std::unique_ptr< QgsFeature > f( new QgsFeature( vlayer->fields(), 0 ) ); //does compoundcurve contain circular strings? //does provider support circular strings? bool hasCurvedSegments = captureCurve()->hasCurvedSegments(); bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries; QList<QgsPointLocator::Match> snappingMatchesList; QgsCurve *curveToAdd = nullptr; if ( hasCurvedSegments && providerSupportsCurvedSegments ) { curveToAdd = captureCurve()->clone(); } else { curveToAdd = captureCurve()->curveToLine(); snappingMatchesList = snappingMatches(); } if ( mode() == CaptureLine ) { QgsGeometry g( curveToAdd ); f->setGeometry( g ); } else { QgsCurvePolygon *poly = nullptr; if ( hasCurvedSegments && providerSupportsCurvedSegments ) { poly = new QgsCurvePolygon(); } else { poly = new QgsPolygon(); } poly->setExteriorRing( curveToAdd ); QgsGeometry g( poly ); f->setGeometry( g ); QgsGeometry featGeom = f->geometry(); int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); f->setGeometry( featGeom ); if ( avoidIntersectionsReturn == 1 ) { //not a polygon type. Impossible to get there } if ( f->geometry().isEmpty() ) //avoid intersection might have removed the whole geometry { emit messageEmitted( tr( "The feature cannot be added because it's geometry collapsed due to intersection avoidance" ), Qgis::Critical ); stopCapturing(); return; } } f->setValid( true ); digitized( *f ); stopCapturing(); } } }
void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e ) { QgsVectorLayer *vlayer = currentVectorLayer(); if ( !vlayer || !vlayer->isEditable() ) { delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); cadDockWidget()->clear(); notifyNotEditableLayer(); return; } if ( !mRubberBand ) { //find first geometry under mouse cursor and store iterator to it QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->mapPoint() ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); if ( vlayer->selectedFeatureCount() == 0 ) { QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setNoAttributes() ); //find the closest feature QgsGeometry pointGeometry = QgsGeometry::fromPointXY( layerCoords ); if ( pointGeometry.isNull() ) { cadDockWidget()->clear(); return; } double minDistance = std::numeric_limits<double>::max(); QgsFeature cf; QgsFeature f; while ( fit.nextFeature( f ) ) { if ( f.hasGeometry() ) { double currentDistance = pointGeometry.distance( f.geometry() ); if ( currentDistance < minDistance ) { minDistance = currentDistance; cf = f; } } } if ( minDistance == std::numeric_limits<double>::max() ) { cadDockWidget()->clear(); return; } mMovedFeatures.clear(); mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one... mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand->setToGeometry( cf.geometry(), vlayer ); } else { mMovedFeatures = vlayer->selectedFeatureIds(); mRubberBand = createRubberBand( vlayer->geometryType() ); QgsFeature feat; QgsFeatureIterator it = vlayer->getSelectedFeatures( QgsFeatureRequest().setNoAttributes() ); bool allFeaturesInView = true; QgsRectangle viewRect = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, mCanvas->extent() ); while ( it.nextFeature( feat ) ) { mRubberBand->addGeometry( feat.geometry(), vlayer ); if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) ) allFeaturesInView = false; } if ( !allFeaturesInView ) { // for extra safety to make sure we are not modifying geometries by accident int res = QMessageBox::warning( mCanvas, tr( "Move features" ), tr( "Some of the selected features are outside of the current map view. Would you still like to continue?" ), QMessageBox::Yes | QMessageBox::No ); if ( res != QMessageBox::Yes ) { mMovedFeatures.clear(); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); return; } } } mStartPointMapCoords = e->mapPoint(); mRubberBand->show(); } else { // copy and move mode if ( e->button() != Qt::LeftButton ) { cadDockWidget()->clear(); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); return; } QgsPointXY startPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, mStartPointMapCoords ); QgsPointXY stopPointLayerCoords = toLayerCoordinates( ( QgsMapLayer * )vlayer, e->mapPoint() ); double dx = stopPointLayerCoords.x() - startPointLayerCoords.x(); double dy = stopPointLayerCoords.y() - startPointLayerCoords.y(); vlayer->beginEditCommand( mMode == Move ? tr( "Feature moved" ) : tr( "Feature copied and moved" ) ); switch ( mMode ) { case Move: Q_FOREACH ( QgsFeatureId id, mMovedFeatures ) { vlayer->translateFeature( id, dx, dy ); } delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); cadDockWidget()->clear(); break; case CopyMove: QgsFeatureRequest request; request.setFilterFids( mMovedFeatures ); QString *errorMsg = new QString(); if ( !QgisApp::instance()->vectorLayerTools()->copyMoveFeatures( vlayer, request, dx, dy, errorMsg ) ) { emit messageEmitted( *errorMsg, Qgis::Critical ); delete mRubberBand; mRubberBand = nullptr; mSnapIndicator->setMatch( QgsPointLocator::Match() ); } break; } vlayer->endEditCommand(); vlayer->triggerRepaint(); }