QgsGeometry QgsInternalGeometryEngine::densifyByDistance( double distance ) const { if ( !mGeometry ) { return QgsGeometry(); } if ( QgsWkbTypes::geometryType( mGeometry->wkbType() ) == QgsWkbTypes::PointGeometry ) { return QgsGeometry( mGeometry->clone() ); // point geometry, nothing to do } if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) ) { int numGeom = gc->numGeometries(); QVector< QgsAbstractGeometry * > geometryList; geometryList.reserve( numGeom ); for ( int i = 0; i < numGeom; ++i ) { geometryList << densifyGeometry( gc->geometryN( i ), -1, distance ); } QgsGeometry first = QgsGeometry( geometryList.takeAt( 0 ) ); for ( QgsAbstractGeometry *g : qgis::as_const( geometryList ) ) { first.addPart( g ); } return first; } else { return QgsGeometry( densifyGeometry( mGeometry, -1, distance ) ); } }
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( QgsCurve *ring, QgsFeatureId featureId ) { if ( !mLayer->isSpatial() ) return QgsGeometry::AddPartSelectedGeometryNotFound; QgsGeometry geometry; bool firstPart = false; QgsFeature f; if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) ) return QgsGeometry::AddPartSelectedGeometryNotFound; if ( !f.hasGeometry() ) { //no existing geometry, so adding first part to null geometry firstPart = true; } else { geometry = f.geometry(); } QgsGeometry::OperationResult errorCode = geometry.addPart( ring, mLayer->geometryType() ); if ( errorCode == QgsGeometry::Success ) { if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() ) && mLayer->dataProvider()->doesStrictFeatureTypeCheck() ) { //convert back to single part if required by layer geometry.convertToSingleType(); } mLayer->editBuffer()->changeGeometry( featureId, geometry ); } return errorCode; }
QgsGeometry QgsInternalGeometryEngine::orthogonalize( double tolerance, int maxIterations, double angleThreshold ) const { if ( !mGeometry || ( QgsWkbTypes::geometryType( mGeometry->wkbType() ) != QgsWkbTypes::LineGeometry && QgsWkbTypes::geometryType( mGeometry->wkbType() ) != QgsWkbTypes::PolygonGeometry ) ) { return QgsGeometry(); } double lowerThreshold = std::cos( ( 90 - angleThreshold ) * M_PI / 180.00 ); double upperThreshold = std::cos( angleThreshold * M_PI / 180.0 ); if ( const QgsGeometryCollection *gc = qgsgeometry_cast< const QgsGeometryCollection *>( mGeometry ) ) { int numGeom = gc->numGeometries(); QVector< QgsAbstractGeometry * > geometryList; geometryList.reserve( numGeom ); for ( int i = 0; i < numGeom; ++i ) { geometryList << orthogonalizeGeom( gc->geometryN( i ), maxIterations, tolerance, lowerThreshold, upperThreshold ); } QgsGeometry first = QgsGeometry( geometryList.takeAt( 0 ) ); for ( QgsAbstractGeometry *g : qgis::as_const( geometryList ) ) { first.addPart( g ); } return first; } else { return QgsGeometry( orthogonalizeGeom( mGeometry, maxIterations, tolerance, lowerThreshold, upperThreshold ) ); } }
void QgsProjectionSelectionTreeWidget::updateBoundsPreview() { QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem(); if ( !lvi || lvi->text( QgisCrsIdColumn ).isEmpty() ) return; QgsCoordinateReferenceSystem currentCrs = crs(); if ( !currentCrs.isValid() ) return; QgsRectangle rect = currentCrs.bounds(); if ( !qgsDoubleNear( rect.area(), 0.0 ) ) { QgsGeometry geom; if ( rect.xMinimum() > rect.xMaximum() ) { QgsRectangle rect1 = QgsRectangle( -180, rect.yMinimum(), rect.xMaximum(), rect.yMaximum() ); QgsRectangle rect2 = QgsRectangle( rect.xMinimum(), rect.yMinimum(), 180, rect.yMaximum() ); geom = QgsGeometry::fromRect( rect1 ); geom.addPart( QgsGeometry::fromRect( rect2 ) ); } else { geom = QgsGeometry::fromRect( rect ); } mPreviewBand->setToGeometry( geom, nullptr ); mPreviewBand->setColor( QColor( 255, 0, 0, 65 ) ); QgsRectangle extent = geom.boundingBox(); extent.scale( 1.1 ); mAreaCanvas->setExtent( extent ); mAreaCanvas->refresh(); mPreviewBand->show(); QString extentString = tr( "Extent: %1, %2, %3, %4" ) .arg( rect.xMinimum(), 0, 'f', 2 ) .arg( rect.yMinimum(), 0, 'f', 2 ) .arg( rect.xMaximum(), 0, 'f', 2 ) .arg( rect.yMaximum(), 0, 'f', 2 ); QString proj4String = tr( "Proj4: %1" ).arg( selectedProj4String() ); teProjection->setText( extentString + "\n" + proj4String ); } else { mPreviewBand->hide(); mAreaCanvas->zoomToFullExtent(); QString extentString = tr( "Extent: Extent not known" ); QString proj4String = tr( "Proj4: %1" ).arg( selectedProj4String() ); teProjection->setText( extentString + "\n" + proj4String ); } }
int QgsVectorLayerEditUtils::addPart( QgsCurveV2* ring, QgsFeatureId featureId ) { if ( !L->hasGeometryType() ) return 6; QgsGeometry geometry; bool firstPart = false; if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache { // it's not in cache: let's fetch it from layer QgsFeature f; if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) ) return 6; //not found if ( !f.constGeometry() || f.constGeometry()->isEmpty() ) { //no existing geometry, so adding first part to null geometry firstPart = true; } else { geometry = *f.geometry(); } } int errorCode = geometry.addPart( ring, L->geometryType() ); if ( errorCode == 0 ) { if ( firstPart && QgsWKBTypes::isSingleType( QGis::fromOldWkbType( L->wkbType() ) ) && L->dataProvider()->doesStrictFeatureTypeCheck() ) { //convert back to single part if required by layer geometry.convertToSingleType(); } L->editBuffer()->changeGeometry( featureId, &geometry ); } return errorCode; }
int QgsVectorLayerEditUtils::addPart( const QList<QgsPoint> &points, QgsFeatureId featureId ) { if ( !L->hasGeometryType() ) return 6; QgsGeometry geometry; if ( !cache()->geometry( featureId, geometry ) ) // maybe it's in cache { // it's not in cache: let's fetch it from layer QgsFeature f; if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.geometry() ) return 6; //geometry not found geometry = *f.geometry(); } int errorCode = geometry.addPart( points, L->geometryType() ); if ( errorCode == 0 ) { L->editBuffer()->changeGeometry( featureId, &geometry ); } return errorCode; }
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; }
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; }