void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e ) { Q_UNUSED( e ); QgsVectorLayer* vlayer = currentVectorLayer(); if ( !vlayer ) { deleteRubberBandAndGeometry(); return; } if ( !mGeometryModified ) { deleteRubberBandAndGeometry(); vlayer->destroyEditCommand(); return; } if ( mMultiPartGeometry ) { mModifiedGeometry.convertToMultiType(); } vlayer->beginEditCommand( tr( "Offset curve" ) ); bool editOk; if ( mSourceLayerId == vlayer->id() && !mForceCopy ) { editOk = vlayer->changeGeometry( mModifiedFeature, &mModifiedGeometry ); } else { QgsFeature f; f.setGeometry( mModifiedGeometry ); //add empty values for all fields (allows inserting attribute values via the feature form in the same session) QgsAttributes attrs( vlayer->pendingFields().count() ); const QgsFields& fields = vlayer->pendingFields(); for ( int idx = 0; idx < fields.count(); ++idx ) { attrs[idx] = QVariant(); } f.setAttributes( attrs ); editOk = vlayer->addFeature( f ); } if ( editOk ) { vlayer->endEditCommand(); } else { vlayer->destroyEditCommand(); } deleteRubberBandAndGeometry(); deleteDistanceItem(); delete mSnapVertexMarker; mSnapVertexMarker = 0; mForceCopy = false; mCanvas->refresh(); }
QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const { QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() ); QString pkField = mJoinInfo.targetFieldName(); QgsFeature joinFeature; QgsFeature targetFeature; QgsFeatureIterator it = getFeatures(); layer->startEditing(); while ( it.nextFeature( joinFeature ) ) { QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) ); QgsFeatureRequest request; request.setFilterExpression( filter ); mLayer->getFeatures( request ).nextFeature( targetFeature ); if ( targetFeature.isValid() ) { QgsFeature newFeature( joinFeature ); newFeature.setGeometry( targetFeature.geometry() ); layer->addFeature( newFeature ); } } layer->commitChanges(); return layer; }
static QgsVectorLayer* make_layer( const QStringList& wkts ) { QgsVectorLayer* vl = new QgsVectorLayer( "LineString", "x", "memory" ); Q_ASSERT( vl->isValid() ); vl->startEditing(); Q_FOREACH ( const QString& wkt, wkts ) { QgsFeature f( make_feature( wkt ) ); vl->addFeature( f, false ); }
void RgShortestPathWidget::exportPath() { RgExportDlg dlg( this ); if ( !dlg.exec() ) return; QgsVectorLayer *vl = dlg.mapLayer(); if ( vl == NULL ) return; QgsPoint p1, p2; QgsGraph *path = getPath( p1, p2 ); if ( path == NULL ) return; QgsCoordinateTransform ct( mPlugin->iface()->mapCanvas()->mapRenderer()->destinationCrs(), vl->crs() ); int startVertexIdx = path->findVertex( p1 ); int stopVertexIdx = path->findVertex( p2 ); QgsPolyline p; while ( startVertexIdx != stopVertexIdx ) { QgsGraphArcIdList l = path->vertex( stopVertexIdx ).inArc(); if ( l.empty() ) break; const QgsGraphArc& e = path->arc( l.front() ); p.push_front( ct.transform( path->vertex( e.inVertex() ).point() ) ); stopVertexIdx = e.outVertex(); } p.push_front( ct.transform( p1 ) ); vl->startEditing(); QgsFeature f; f.setGeometry( QgsGeometry::fromPolyline( p ) ); vl->addFeature( f ); vl->updateExtents(); mPlugin->iface()->mapCanvas()->update(); delete path; }
void QgsMapToolFillRing::cadCanvasReleaseEvent( QgsMapMouseEvent * e ) { //check if we operate on a vector layer QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->mapPoint() ); 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" ), QgsMessageBar::WARNING ); return; } startCapturing(); } else if ( e->button() == Qt::RightButton ) { if ( !isCapturing() ) return; deleteTempRubberBand(); closePolygon(); vlayer->beginEditCommand( tr( "Ring added and filled" ) ); QList< QgsPoint > pointList = points(); QgsFeatureId modifiedFid; int addRingReturnCode = vlayer->addRing( pointList, &modifiedFid ); if ( addRingReturnCode != 0 ) { QString errorMessage; //todo: open message box to communicate errors if ( addRingReturnCode == 1 ) { errorMessage = tr( "a problem with geometry type occured" ); } else if ( addRingReturnCode == 2 ) { errorMessage = tr( "the inserted Ring is not closed" ); } else if ( addRingReturnCode == 3 ) { errorMessage = tr( "the inserted Ring is not a valid geometry" ); } else if ( addRingReturnCode == 4 ) { errorMessage = tr( "the inserted Ring crosses existing rings" ); } else if ( addRingReturnCode == 5 ) { errorMessage = tr( "the inserted Ring is not contained in a feature" ); } else { errorMessage = tr( "an unknown error occured" ); } emit messageEmitted( tr( "could not add ring since %1." ).arg( errorMessage ), QgsMessageBar::CRITICAL ); vlayer->destroyEditCommand(); } else { // find parent feature and get it attributes double xMin, xMax, yMin, yMax; QgsRectangle bBox; xMin = std::numeric_limits<double>::max(); xMax = -std::numeric_limits<double>::max(); yMin = std::numeric_limits<double>::max(); yMax = -std::numeric_limits<double>::max(); Q_FOREACH ( const QgsPoint& point, pointList ) { xMin = qMin( xMin, point.x() ); xMax = qMax( xMax, point.x() ); yMin = qMin( yMin, point.y() ); yMax = qMax( yMax, point.y() ); } bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterFid( modifiedFid ) ); QgsFeature f; bool res = false; if ( fit.nextFeature( f ) ) { //create QgsFeature with wkb representation QgsFeature* ft = new QgsFeature( vlayer->fields(), 0 ); ft->setGeometry( QgsGeometry::fromPolygon( QgsPolygon() << pointList.toVector() ) ); ft->setAttributes( f.attributes() ); if ( QApplication::keyboardModifiers() == Qt::ControlModifier ) { res = vlayer->addFeature( *ft ); } else { QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true ); dialog->setIsAddDialog( true ); res = dialog->exec(); // will also add the feature } if ( res ) { vlayer->endEditCommand(); } else { delete ft; vlayer->destroyEditCommand(); } res = false; } } stopCapturing(); }
void QgsMapToolFillRing::canvasReleaseEvent( QMouseEvent * e ) { //check if we operate on a vector layer QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->pos() ); if ( error == 1 ) { //current layer is not a vector layer return; } else if ( error == 2 ) { //problem with coordinate transformation QMessageBox::information( 0, tr( "Coordinate transform error" ), tr( "Cannot transform the point to the layers coordinate system" ) ); return; } startCapturing(); } else if ( e->button() == Qt::RightButton ) { deleteTempRubberBand(); closePolygon(); vlayer->beginEditCommand( tr( "Ring added and filled" ) ); int addRingReturnCode = vlayer->addRing( points() ); if ( addRingReturnCode != 0 ) { QString errorMessage; //todo: open message box to communicate errors if ( addRingReturnCode == 1 ) { errorMessage = tr( "A problem with geometry type occured" ); } else if ( addRingReturnCode == 2 ) { errorMessage = tr( "The inserted Ring is not closed" ); } else if ( addRingReturnCode == 3 ) { errorMessage = tr( "The inserted Ring is not a valid geometry" ); } else if ( addRingReturnCode == 4 ) { errorMessage = tr( "The inserted Ring crosses existing rings" ); } else if ( addRingReturnCode == 5 ) { errorMessage = tr( "The inserted Ring is not contained in a feature" ); } else { errorMessage = tr( "An unknown error occured" ); } QMessageBox::critical( 0, tr( "Error, could not add ring" ), errorMessage ); vlayer->destroyEditCommand(); } else { // find parent feature and get it attributes double xMin, xMax, yMin, yMax; QgsRectangle bBox; xMin = std::numeric_limits<double>::max(); xMax = -std::numeric_limits<double>::max(); yMin = std::numeric_limits<double>::max(); yMax = -std::numeric_limits<double>::max(); for ( QList<QgsPoint>::const_iterator it = points().constBegin(); it != points().constEnd(); ++it ) { if ( it->x() < xMin ) { xMin = it->x(); } if ( it->x() > xMax ) { xMax = it->x(); } if ( it->y() < yMin ) { yMin = it->y(); } if ( it->y() > yMax ) { yMax = it->y(); } } bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; bool res = false; while ( fit.nextFeature( f ) ) { //create QgsFeature with wkb representation QgsFeature* ft = new QgsFeature( vlayer->pendingFields(), 0 ); QgsGeometry *g; g = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() ); ft->setGeometry( g ); ft->setAttributes( f.attributes() ); if ( QgsApplication::keyboardModifiers() == Qt::ControlModifier ) { res = vlayer->addFeature( *ft ); } else { QgsAttributeDialog *dialog = new QgsAttributeDialog( vlayer, ft, false, NULL, true ); dialog->setIsAddDialog( true ); res = dialog->exec(); // will also add the feature } if ( res ) { vlayer->endEditCommand(); } else { delete ft; vlayer->destroyEditCommand(); } res = false; } } stopCapturing(); } }
void QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlite3* db, const QString& offlineDbPath ) { if ( layer == NULL ) { return; } QString tableName = layer->name(); // create table QString sql = QString( "CREATE TABLE '%1' (" ).arg( tableName ); QString delim = ""; const QgsFields& fields = layer->dataProvider()->fields(); for ( int idx = 0; idx < fields.count(); ++idx ) { QString dataType = ""; QVariant::Type type = fields[idx].type(); if ( type == QVariant::Int ) { dataType = "INTEGER"; } else if ( type == QVariant::Double ) { dataType = "REAL"; } else if ( type == QVariant::String ) { dataType = "TEXT"; } else { showWarning( tr( "Unknown data type %1" ).arg( type ) ); } sql += delim + QString( "'%1' %2" ).arg( fields[idx].name() ).arg( dataType ); delim = ","; } sql += ")"; // add geometry column QString geomType = ""; switch ( layer->wkbType() ) { case QGis::WKBPoint: geomType = "POINT"; break; case QGis::WKBMultiPoint: geomType = "MULTIPOINT"; break; case QGis::WKBLineString: geomType = "LINESTRING"; break; case QGis::WKBMultiLineString: geomType = "MULTILINESTRING"; break; case QGis::WKBPolygon: geomType = "POLYGON"; break; case QGis::WKBMultiPolygon: geomType = "MULTIPOLYGON"; break; default: showWarning( tr( "QGIS wkbType %1 not supported" ).arg( layer->wkbType() ) ); break; }; QString sqlAddGeom = QString( "SELECT AddGeometryColumn('%1', 'Geometry', %2, '%3', 2)" ) .arg( tableName ) .arg( layer->crs().authid().startsWith( "EPSG:", Qt::CaseInsensitive ) ? layer->crs().authid().mid( 5 ).toLong() : 0 ) .arg( geomType ); // create spatial index QString sqlCreateIndex = QString( "SELECT CreateSpatialIndex('%1', 'Geometry')" ).arg( tableName ); int rc = sqlExec( db, sql ); if ( rc == SQLITE_OK ) { rc = sqlExec( db, sqlAddGeom ); if ( rc == SQLITE_OK ) { rc = sqlExec( db, sqlCreateIndex ); } } if ( rc == SQLITE_OK ) { // add new layer QgsVectorLayer* newLayer = new QgsVectorLayer( QString( "dbname='%1' table='%2'(Geometry) sql=" ) .arg( offlineDbPath ).arg( tableName ), tableName + " (offline)", "spatialite" ); if ( newLayer->isValid() ) { // mark as offline layer newLayer->setCustomProperty( CUSTOM_PROPERTY_IS_OFFLINE_EDITABLE, true ); // store original layer source newLayer->setCustomProperty( CUSTOM_PROPERTY_REMOTE_SOURCE, layer->source() ); newLayer->setCustomProperty( CUSTOM_PROPERTY_REMOTE_PROVIDER, layer->providerType() ); // copy style bool hasLabels = layer->hasLabelsEnabled(); if ( !hasLabels ) { // NOTE: copy symbology before adding the layer so it is displayed correctly copySymbology( layer, newLayer ); } // register this layer with the central layers registry QgsMapLayerRegistry::instance()->addMapLayers( QList<QgsMapLayer *>() << newLayer ); if ( hasLabels ) { // NOTE: copy symbology of layers with labels enabled after adding to project, as it will crash otherwise (WORKAROUND) copySymbology( layer, newLayer ); } // TODO: layer order // copy features newLayer->startEditing(); QgsFeature f; // NOTE: force feature recount for PostGIS layer, else only visible features are counted, before iterating over all features (WORKAROUND) layer->setSubsetString( "" ); QgsFeatureIterator fit = layer->getFeatures(); emit progressModeSet( QgsOfflineEditing::CopyFeatures, layer->featureCount() ); int featureCount = 1; QList<QgsFeatureId> remoteFeatureIds; while ( fit.nextFeature( f ) ) { remoteFeatureIds << f.id(); // NOTE: Spatialite provider ignores position of geometry column // fill gap in QgsAttributeMap if geometry column is not last (WORKAROUND) int column = 0; QgsAttributes attrs = f.attributes(); QgsAttributes newAttrs( attrs.count() ); for ( int it = 0; it < attrs.count(); ++it ) { newAttrs[column++] = attrs[it]; } f.setAttributes( newAttrs ); newLayer->addFeature( f, false ); emit progressUpdated( featureCount++ ); } if ( newLayer->commitChanges() ) { emit progressModeSet( QgsOfflineEditing::ProcessFeatures, layer->featureCount() ); featureCount = 1; // update feature id lookup int layerId = getOrCreateLayerId( db, newLayer->id() ); QList<QgsFeatureId> offlineFeatureIds; QgsFeatureIterator fit = newLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( QgsAttributeList() ) ); while ( fit.nextFeature( f ) ) { offlineFeatureIds << f.id(); } // NOTE: insert fids in this loop, as the db is locked during newLayer->nextFeature() sqlExec( db, "BEGIN" ); int remoteCount = remoteFeatureIds.size(); for ( int i = 0; i < remoteCount; i++ ) { addFidLookup( db, layerId, offlineFeatureIds.at( i ), remoteFeatureIds.at( remoteCount - ( i + 1 ) ) ); emit progressUpdated( featureCount++ ); } sqlExec( db, "COMMIT" ); } else { showWarning( newLayer->commitErrors().join( "\n" ) ); } // remove remote layer QgsMapLayerRegistry::instance()->removeMapLayers( QStringList() << layer->id() ); } } }
void QgsMapToolOffsetCurve::applyOffset() { QgsVectorLayer* layer = currentVectorLayer(); if ( !layer ) { deleteRubberBandAndGeometry(); notifyNotVectorLayer(); return; } // no modification if ( !mGeometryModified ) { deleteRubberBandAndGeometry(); layer->destroyEditCommand(); deleteDistanceWidget(); return; } if ( mMultiPartGeometry ) { mModifiedGeometry.convertToMultiType(); } layer->beginEditCommand( tr( "Offset curve" ) ); bool editOk; if ( mSourceLayerId == layer->id() && !mForceCopy ) { editOk = layer->changeGeometry( mModifiedFeature, &mModifiedGeometry ); } else { QgsFeature f; f.setGeometry( mModifiedGeometry ); //add empty values for all fields (allows inserting attribute values via the feature form in the same session) QgsAttributes attrs( layer->fields().count() ); const QgsFields& fields = layer->fields(); for ( int idx = 0; idx < fields.count(); ++idx ) { attrs[idx] = QVariant(); } f.setAttributes( attrs ); editOk = layer->addFeature( f ); } if ( editOk ) { layer->endEditCommand(); } else { layer->destroyEditCommand(); } deleteRubberBandAndGeometry(); deleteDistanceWidget(); delete mSnapVertexMarker; mSnapVertexMarker = nullptr; mForceCopy = false; mCanvas->refresh(); }