int QgsVectorLayerEditUtils::addRing( const QList<QgsPoint>& ring ) { if ( !L->hasGeometryType() ) return 5; int addRingReturnCode = 5; //default: return code for 'ring not inserted' double xMin, yMin, xMax, yMax; QgsRectangle bBox; if ( boundingBoxFromPointList( ring, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 3; //ring not valid } QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) { addRingReturnCode = f.geometry()->addRing( ring ); if ( addRingReturnCode == 0 ) { L->editBuffer()->changeGeometry( f.id(), f.geometry() ); //setModified( true, true ); break; } } return addRingReturnCode; }
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureIterator features; const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection { features = L->selectedFeaturesIterator(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( L->crs().geographicFlag() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } QgsFeature feat; while ( features.nextFeature( feat ) ) { if ( !feat.constGeometry() ) { continue; } QList<QgsGeometry*> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry* newGeometry = 0; splitFunctionReturn = feat.geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( feat.id(), feat.geometry() ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { newGeometry = newGeometries.at( i ); QgsFeature newFeature; newFeature.setGeometry( newGeometry ); //use default value where possible for primary key (e.g. autoincrement), //and use the value from the original (split) feature if not primary key QgsAttributes newAttributes = feat.attributes(); Q_FOREACH ( int pkIdx, L->dataProvider()->pkAttributeIndexes() ) { const QVariant defaultValue = L->dataProvider()->defaultValue( pkIdx ); if ( !defaultValue.isNull() ) { newAttributes[ pkIdx ] = defaultValue; } else //try with NULL { newAttributes[ pkIdx ] = QVariant(); } } newFeature.setAttributes( newAttributes ); newFeatures.append( newFeature ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureList featureList; const QgsFeatureIds selectedIds = L->selectedFeaturesIds(); if ( selectedIds.size() > 0 ) //consider only the selected features if there is a selection { featureList = L->selectedFeatures(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { return 2; } } QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; while ( fit.nextFeature( f ) ) featureList << QgsFeature( f ); } QgsFeatureList::iterator select_it = featureList.begin(); for ( ; select_it != featureList.end(); ++select_it ) { if ( !select_it->geometry() ) { continue; } QList<QgsGeometry*> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry* newGeometry = 0; splitFunctionReturn = select_it->geometry()->splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( select_it->id(), select_it->geometry() ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { newGeometry = newGeometries.at( i ); QgsFeature newFeature; newFeature.setGeometry( newGeometry ); //use default value where possible (primary key issue), otherwise the value from the original (split) feature QgsAttributes newAttributes = select_it->attributes(); QVariant defaultValue; for ( int j = 0; j < newAttributes.count(); ++j ) { defaultValue = L->dataProvider()->defaultValue( j ); if ( !defaultValue.isNull() ) { newAttributes[ j ] = defaultValue; } } newFeature.setAttributes( newAttributes ); newFeatures.append( newFeature ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error { returnCode = splitFunctionReturn; } } if ( numberOfSplittedFeatures == 0 && selectedIds.size() > 0 ) { //There is a selection but no feature has been split. //Maybe user forgot that only the selected features are split returnCode = 4; } //now add the new features to this vectorlayer L->editBuffer()->addFeatures( newFeatures ); return returnCode; }
int QgsVectorLayerEditUtils::splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedParts = 0; QgsFeatureIterator fit; if ( L->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection { fit = L->selectedFeaturesIterator(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( L->crs().isGeographic() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } int addPartRet = 0; QgsFeature feat; while ( fit.nextFeature( feat ) ) { QList<QgsGeometry> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry featureGeom = feat.geometry(); splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //add new parts if ( !newGeometries.isEmpty() ) featureGeom.convertToMultiType(); for ( int i = 0; i < newGeometries.size(); ++i ) { addPartRet = featureGeom.addPart( newGeometries.at( i ) ); if ( addPartRet ) break; } // For test only: Exception already thrown here... // feat.geometry()->asWkb(); if ( !addPartRet ) { L->editBuffer()->changeGeometry( feat.id(), featureGeom ); } else { // Test addPartRet switch ( addPartRet ) { case 1: QgsDebugMsg( "Not a multipolygon" ); break; case 2: QgsDebugMsg( "Not a valid geometry" ); break; case 3: QgsDebugMsg( "New polygon ring" ); break; } } L->editBuffer()->changeGeometry( feat.id(), featureGeom ); if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedParts; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error { returnCode = splitFunctionReturn; } } if ( numberOfSplittedParts == 0 && L->selectedFeatureCount() > 0 && returnCode == 0 ) { //There is a selection but no feature has been split. //Maybe user forgot that only the selected features are split returnCode = 4; } return returnCode; }
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing ) { if ( !L->hasGeometryType() ) return 4; QgsFeatureList newFeatures; //store all the newly created features double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line int returnCode = 0; int splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplittedFeatures = 0; QgsFeatureIterator features; const QgsFeatureIds selectedIds = L->selectedFeatureIds(); if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection { features = L->selectedFeaturesIterator(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) == 0 ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return 1; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( L->crs().isGeographic() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } QgsFeature feat; while ( features.nextFeature( feat ) ) { if ( !feat.hasGeometry() ) { continue; } QList<QgsGeometry> newGeometries; QList<QgsPoint> topologyTestPoints; QgsGeometry featureGeom = feat.geometry(); splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //change this geometry L->editBuffer()->changeGeometry( feat.id(), featureGeom ); //insert new features for ( int i = 0; i < newGeometries.size(); ++i ) { QgsFeature f = QgsVectorLayerUtils::createFeature( L, newGeometries.at( i ), feat.attributes().toMap() ); L->editBuffer()->addFeature( f ); } if ( topologicalEditing ) { QList<QgsPoint>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplittedFeatures; } else if ( splitFunctionReturn > 1 ) //1 means no split but also no error { returnCode = splitFunctionReturn; } } if ( numberOfSplittedFeatures == 0 && !selectedIds.isEmpty() ) { //There is a selection but no feature has been split. //Maybe user forgot that only the selected features are split returnCode = 4; } return returnCode; }
QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing ) { if ( !mLayer->isSpatial() ) return QgsGeometry::InvalidBaseGeometry; double xMin, yMin, xMax, yMax; QgsRectangle bBox; //bounding box of the split line QgsGeometry::OperationResult returnCode = QgsGeometry::OperationResult::Success; QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry int numberOfSplitParts = 0; QgsFeatureIterator fit; if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection { fit = mLayer->getSelectedFeatures(); } else //else consider all the feature that intersect the bounding box of the split line { if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) ) { bBox.setXMinimum( xMin ); bBox.setYMinimum( yMin ); bBox.setXMaximum( xMax ); bBox.setYMaximum( yMax ); } else { return QgsGeometry::OperationResult::InvalidInputGeometryType; } if ( bBox.isEmpty() ) { //if the bbox is a line, try to make a square out of it if ( bBox.width() == 0.0 && bBox.height() > 0 ) { bBox.setXMinimum( bBox.xMinimum() - bBox.height() / 2 ); bBox.setXMaximum( bBox.xMaximum() + bBox.height() / 2 ); } else if ( bBox.height() == 0.0 && bBox.width() > 0 ) { bBox.setYMinimum( bBox.yMinimum() - bBox.width() / 2 ); bBox.setYMaximum( bBox.yMaximum() + bBox.width() / 2 ); } else { //If we have a single point, we still create a non-null box double bufferDistance = 0.000001; if ( mLayer->crs().isGeographic() ) bufferDistance = 0.00000001; bBox.setXMinimum( bBox.xMinimum() - bufferDistance ); bBox.setXMaximum( bBox.xMaximum() + bufferDistance ); bBox.setYMinimum( bBox.yMinimum() - bufferDistance ); bBox.setYMaximum( bBox.yMaximum() + bufferDistance ); } } fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) ); } QgsGeometry::OperationResult addPartRet = QgsGeometry::OperationResult::Success; QgsFeature feat; while ( fit.nextFeature( feat ) ) { QVector<QgsGeometry> newGeometries; QVector<QgsPointXY> topologyTestPoints; QgsGeometry featureGeom = feat.geometry(); splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints ); if ( splitFunctionReturn == 0 ) { //add new parts if ( !newGeometries.isEmpty() ) featureGeom.convertToMultiType(); for ( int i = 0; i < newGeometries.size(); ++i ) { addPartRet = featureGeom.addPart( newGeometries.at( i ) ); if ( addPartRet ) break; } // For test only: Exception already thrown here... // feat.geometry()->asWkb(); if ( !addPartRet ) { mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom ); } if ( topologicalEditing ) { QVector<QgsPointXY>::const_iterator topol_it = topologyTestPoints.constBegin(); for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it ) { addTopologicalPoints( *topol_it ); } } ++numberOfSplitParts; } else if ( splitFunctionReturn != QgsGeometry::OperationResult::Success && splitFunctionReturn != QgsGeometry::OperationResult::NothingHappened ) { returnCode = splitFunctionReturn; } } if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == QgsGeometry::Success ) { //There is a selection but no feature has been split. //Maybe user forgot that only the selected features are split returnCode = QgsGeometry::OperationResult::NothingHappened; } return returnCode; }