bool operator==( const QgsGeometry &g1, const QgsGeometry &g2 ) { if ( g1.isNull() && g2.isNull() ) return true; else return g1.isGeosEqual( g2 ); }
QgsFeatureList QgsConvexHullAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback ) { QgsFeature f = feature; if ( f.hasGeometry() ) { QgsGeometry outputGeometry; if ( QgsWkbTypes::flatType( f.geometry().wkbType() ) == QgsWkbTypes::Point ) { feedback->reportError( QObject::tr( "Cannot calculate convex hull for a single Point feature (try 'Minimum bounding geometry' algorithm instead)." ) ); f.clearGeometry(); } else { outputGeometry = f.geometry().convexHull(); if ( outputGeometry.isNull() ) feedback->reportError( outputGeometry.lastError() ); f.setGeometry( outputGeometry ); } if ( !outputGeometry.isNull() ) { QgsAttributes attrs = f.attributes(); attrs << outputGeometry.constGet()->area() << outputGeometry.constGet()->perimeter(); f.setAttributes( attrs ); } else { QgsAttributes attrs = f.attributes(); attrs << QVariant() << QVariant(); f.setAttributes( attrs ); } } return QgsFeatureList() << f; }
void QgsZonalStatistics::statisticsFromPreciseIntersection( const QgsGeometry &poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle &rasterBBox, FeatureStats &stats ) { stats.reset(); double currentY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2; QgsGeometry pixelRectGeometry; double hCellSizeX = cellSizeX / 2.0; double hCellSizeY = cellSizeY / 2.0; double pixelArea = cellSizeX * cellSizeY; double weight = 0; QgsRectangle featureBBox = poly.boundingBox().intersect( &rasterBBox ); QgsRectangle intersectBBox = rasterBBox.intersect( &featureBBox ); QgsRasterBlock *block = mRasterProvider->block( mRasterBand, intersectBBox, nCellsX, nCellsY ); for ( int i = 0; i < nCellsY; ++i ) { double currentX = rasterBBox.xMinimum() + cellSizeX / 2.0 + pixelOffsetX * cellSizeX; for ( int j = 0; j < nCellsX; ++j ) { if ( !validPixel( block->value( i, j ) ) ) { continue; } pixelRectGeometry = QgsGeometry::fromRect( QgsRectangle( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) ); if ( !pixelRectGeometry.isNull() ) { //intersection QgsGeometry intersectGeometry = pixelRectGeometry.intersection( poly ); if ( !intersectGeometry.isNull() ) { double intersectionArea = intersectGeometry.area(); if ( intersectionArea >= 0.0 ) { weight = intersectionArea / pixelArea; stats.addValue( block->value( i, j ), weight ); } } pixelRectGeometry = QgsGeometry(); } currentX += cellSizeX; } currentY -= cellSizeY; } delete block; }
bool QgsOverlayUtils::sanitizeIntersectionResult( QgsGeometry &geom, QgsWkbTypes::GeometryType geometryType ) { if ( geom.isNull() ) { // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: intersection failed." ), geom.lastError() ) ); } // Intersection of geometries may give use also geometries we do not want in our results. // For example, two square polygons touching at the corner have a point as the intersection, but no area. // In other cases we may get a mixture of geometries in the output - we want to keep only the expected types. if ( QgsWkbTypes::flatType( geom.wkbType() ) == QgsWkbTypes::GeometryCollection ) { // try to filter out irrelevant parts with different geometry type than what we want geom.convertGeometryCollectionToSubclass( geometryType ); if ( geom.isEmpty() ) return false; } if ( QgsWkbTypes::geometryType( geom.wkbType() ) != geometryType ) { // we can't make use of this resulting geometry return false; } // some data providers are picky about the geometries we pass to them: we can't add single-part geometries // when we promised multi-part geometries, so ensure we have the right type geom.convertToMultiType(); return true; }
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() ) { const QgsPolylineXY line = geom.asPolyline(); if ( line.contains( beginPoint ) ) begin = true; else if ( line.contains( endPoint ) ) end = true; } } return end && begin; }
ErrorList topolTest::checkMultipart( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); Q_UNUSED( layer1 ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; QList<FeatureLayer>::Iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( ++i ); if ( testCanceled() ) break; QgsGeometry g = it->feature.geometry(); if ( g.isNull() ) { QgsMessageLog::logMessage( tr( "Missing geometry in multipart check." ), tr( "Topology plugin" ) ); continue; } if ( !_canExportToGeos( g ) ) continue; if ( g.isMultipart() ) { QgsRectangle r = g.boundingBox(); QList<FeatureLayer> fls; fls << *it << *it; TopolErroMultiPart *err = new TopolErroMultiPart( r, g, fls ); errorList << err; } } return errorList; }
QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom ) { if ( lineGeom.isNull() ) { return QgsGeometry(); } QgsMultiPolyline resultGeom; //need to go with WKB and z coordinate until QgsGeometry supports M values QByteArray wkb( lineGeom.exportToWkb() ); QgsConstWkbPtr wkbPtr( wkb ); wkbPtr.readHeader(); QgsWkbTypes::Type wkbType = lineGeom.wkbType(); if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D ) { return QgsGeometry(); } if ( wkbType == QgsWkbTypes::LineString25D ) { locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); } else if ( wkbType == QgsWkbTypes::MultiLineString25D ) { int nLines; wkbPtr >> nLines; for ( int i = 0; i < nLines; ++i ) { wkbPtr.readHeader(); wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure ); } }
QgsFeatureList QgsSnapToGridAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { QgsFeature f = feature; if ( f.hasGeometry() ) { double intervalX = mIntervalX; if ( mDynamicIntervalX ) intervalX = mIntervalXProperty.valueAsDouble( context.expressionContext(), intervalX ); double intervalY = mIntervalY; if ( mDynamicIntervalY ) intervalY = mIntervalYProperty.valueAsDouble( context.expressionContext(), intervalY ); double intervalZ = mIntervalZ; if ( mDynamicIntervalZ ) intervalZ = mIntervalZProperty.valueAsDouble( context.expressionContext(), intervalZ ); double intervalM = mIntervalM; if ( mDynamicIntervalM ) intervalM = mIntervalMProperty.valueAsDouble( context.expressionContext(), intervalM ); QgsGeometry outputGeometry = f.geometry().snappedToGrid( intervalX, intervalY, intervalZ, intervalM ); if ( outputGeometry.isNull() ) { feedback->reportError( QObject::tr( "Error snapping geometry %1" ).arg( feature.id() ) ); } f.setGeometry( outputGeometry ); } return QgsFeatureList() << f; }
double QgsDistanceArea::measureLength( const QgsGeometry& geometry ) const { if ( geometry.isNull() ) return 0.0; const QgsAbstractGeometry* geomV2 = geometry.geometry(); return measure( geomV2, Length ); }
void QgsGeometryAnalyzer::addEventLayerFeature( QgsFeature &feature, const QgsGeometry &geom, const QgsGeometry &lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures, int offsetField, double offsetScale, bool forceSingleType ) { if ( geom.isNull() ) { return; } QList<QgsGeometry> geomList; if ( forceSingleType ) { geomList = geom.asGeometryCollection(); } else { geomList.push_back( geom ); } QList<QgsGeometry>::iterator geomIt = geomList.begin(); for ( ; geomIt != geomList.end(); ++geomIt ) { //consider offset QgsGeometry newGeom = *geomIt; if ( offsetField >= 0 ) { double offsetVal = feature.attribute( offsetField ).toDouble(); offsetVal *= offsetScale; newGeom = createOffsetGeometry( *geomIt, lineGeom, offsetVal ); if ( newGeom.isNull() ) { continue; } } feature.setGeometry( newGeom ); if ( fileWriter ) { fileWriter->addFeature( feature ); } else { memoryFeatures << feature; } } }
void QgsMapToolLabel::createRubberBands() { delete mLabelRubberBand; delete mFeatureRubberBand; //label rubber band QgsRectangle rect = mCurrentLabel.pos.labelRect; mLabelRubberBand = new QgsRubberBand( mCanvas, QgsWkbTypes::LineGeometry ); mLabelRubberBand->addPoint( QgsPointXY( rect.xMinimum(), rect.yMinimum() ) ); mLabelRubberBand->addPoint( QgsPointXY( rect.xMinimum(), rect.yMaximum() ) ); mLabelRubberBand->addPoint( QgsPointXY( rect.xMaximum(), rect.yMaximum() ) ); mLabelRubberBand->addPoint( QgsPointXY( rect.xMaximum(), rect.yMinimum() ) ); mLabelRubberBand->addPoint( QgsPointXY( rect.xMinimum(), rect.yMinimum() ) ); mLabelRubberBand->setColor( QColor( 0, 255, 0, 65 ) ); mLabelRubberBand->setWidth( 3 ); mLabelRubberBand->show(); //feature rubber band QgsVectorLayer *vlayer = mCurrentLabel.layer; if ( vlayer ) { QgsFeature f; if ( currentFeature( f, true ) ) { QgsGeometry geom = f.geometry(); if ( !geom.isNull() ) { QgsSettings settings; int r = settings.value( QStringLiteral( "qgis/digitizing/line_color_red" ), 255 ).toInt(); int g = settings.value( QStringLiteral( "qgis/digitizing/line_color_green" ), 0 ).toInt(); int b = settings.value( QStringLiteral( "qgis/digitizing/line_color_blue" ), 0 ).toInt(); int a = settings.value( QStringLiteral( "qgis/digitizing/line_color_alpha" ), 200 ).toInt(); mFeatureRubberBand = new QgsRubberBand( mCanvas, geom.type() ); mFeatureRubberBand->setColor( QColor( r, g, b, a ) ); mFeatureRubberBand->setToGeometry( geom, vlayer ); mFeatureRubberBand->show(); } } //fixpoint rubber band QgsPointXY fixPoint; if ( currentLabelRotationPoint( fixPoint, false, false ) ) { if ( mCanvas ) { const QgsMapSettings &s = mCanvas->mapSettings(); fixPoint = s.mapToLayerCoordinates( vlayer, fixPoint ); } QgsGeometry pointGeom = QgsGeometry::fromPointXY( fixPoint ); mFixPointRubberBand = new QgsRubberBand( mCanvas, QgsWkbTypes::LineGeometry ); mFixPointRubberBand->setColor( QColor( 0, 0, 255, 65 ) ); mFixPointRubberBand->setToGeometry( pointGeom, vlayer ); mFixPointRubberBand->show(); } } }
double QgsDistanceArea::measurePerimeter( const QgsGeometry& geometry ) const { if ( geometry.isNull() ) return 0.0; const QgsAbstractGeometry* geomV2 = geometry.geometry(); if ( !geomV2 || geomV2->dimension() < 2 ) { return 0.0; } if ( !mEllipsoidalMode || mEllipsoid == GEO_NONE ) { return geomV2->perimeter(); } //create list with (single) surfaces QList< const QgsSurface* > surfaces; const QgsSurface* surf = dynamic_cast<const QgsSurface*>( geomV2 ); if ( surf ) { surfaces.append( surf ); } const QgsMultiSurface* multiSurf = dynamic_cast<const QgsMultiSurface*>( geomV2 ); if ( multiSurf ) { surfaces.reserve(( surf ? 1 : 0 ) + multiSurf->numGeometries() ); for ( int i = 0; i < multiSurf->numGeometries(); ++i ) { surfaces.append( static_cast<const QgsSurface*>( multiSurf->geometryN( i ) ) ); } } double length = 0; QList<const QgsSurface*>::const_iterator surfaceIt = surfaces.constBegin(); for ( ; surfaceIt != surfaces.constEnd(); ++surfaceIt ) { if ( !*surfaceIt ) { continue; } QgsPolygonV2* poly = ( *surfaceIt )->surfaceToPolygon(); const QgsCurve* outerRing = poly->exteriorRing(); if ( outerRing ) { length += measure( outerRing ); } int nInnerRings = poly->numInteriorRings(); for ( int i = 0; i < nInnerRings; ++i ) { length += measure( poly->interiorRing( i ) ); } delete poly; } return length; }
void QgsMapToolCapture::validateGeometry() { QgsSettings settings; if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 0 ) return; if ( mValidator ) { mValidator->deleteLater(); mValidator = nullptr; } mGeomErrors.clear(); while ( !mGeomErrorMarkers.isEmpty() ) { delete mGeomErrorMarkers.takeFirst(); } QgsGeometry geom; switch ( mCaptureMode ) { case CaptureNone: case CapturePoint: return; case CaptureLine: if ( size() < 2 ) return; geom = QgsGeometry( mCaptureCurve.curveToLine() ); break; case CapturePolygon: if ( size() < 3 ) return; QgsLineString *exteriorRing = mCaptureCurve.curveToLine(); exteriorRing->close(); QgsPolygon *polygon = new QgsPolygon(); polygon->setExteriorRing( exteriorRing ); geom = QgsGeometry( polygon ); break; } if ( geom.isNull() ) return; QgsGeometry::ValidationMethod method = QgsGeometry::ValidatorQgisInternal; if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 2 ) method = QgsGeometry::ValidatorGeos; mValidator = new QgsGeometryValidator( geom, nullptr, method ); connect( mValidator, &QgsGeometryValidator::errorFound, this, &QgsMapToolCapture::addError ); mValidator->start(); QgsDebugMsgLevel( QStringLiteral( "Validation started" ), 4 ); }
bool QgsSpatialQuery::hasValidGeometry( QgsFeature &feature ) { if ( !feature.isValid() ) return false; QgsGeometry geom = feature.geometry(); if ( geom.isNull() || geom.isEmpty() ) return false; return true; } // bool QgsSpatialQuery::hasValidGeometry(QgsFeature &feature)
void QgsExpressionSelectionDialog::mButtonZoomToFeatures_clicked() { if ( mExpressionBuilder->expressionText().isEmpty() || !mMapCanvas ) return; QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( mExpressionBuilder->expressionText() ) .setExpressionContext( context ) .setNoAttributes(); QgsFeatureIterator features = mLayer->getFeatures( request ); QgsRectangle bbox; bbox.setMinimal(); QgsFeature feat; int featureCount = 0; while ( features.nextFeature( feat ) ) { QgsGeometry geom = feat.geometry(); if ( geom.isNull() || geom.constGet()->isEmpty() ) continue; QgsRectangle r = mMapCanvas->mapSettings().layerExtentToOutputExtent( mLayer, geom.boundingBox() ); bbox.combineExtentWith( r ); featureCount++; } features.close(); QgsSettings settings; int timeout = settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt(); if ( featureCount > 0 ) { mMapCanvas->zoomToFeatureExtent( bbox ); if ( mMessageBar ) { mMessageBar->pushMessage( QString(), tr( "Zoomed to %n matching feature(s)", "number of matching features", featureCount ), Qgis::Info, timeout ); } } else if ( mMessageBar ) { mMessageBar->pushMessage( QString(), tr( "No matching features found" ), Qgis::Info, timeout ); } saveRecent(); }
QgsGeometry QgsMapToolDeleteRing::ringUnderPoint( const QgsPoint &p, QgsFeatureId &fid, int &partNum, int &ringNum ) { //There is no clean way to find if we are inside the ring of a feature, //so we iterate over all the features visible in the canvas //If several rings are found at this position, the smallest one is chosen, //in order to be able to delete a ring inside another ring QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( toLayerCoordinates( vlayer, mCanvas->extent() ) ) ); QgsFeature f; QgsGeometry g; QgsGeometry ringGeom; QgsMultiPolygon pol; QgsPolygon tempPol; QgsGeometry tempGeom; double area = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { g = f.geometry(); if ( g.isNull() ) continue; if ( g.wkbType() == QgsWkbTypes::Polygon || g.wkbType() == QgsWkbTypes::Polygon25D ) { pol = QgsMultiPolygon() << g.asPolygon(); } else { pol = g.asMultiPolygon(); } for ( int i = 0; i < pol.size() ; ++i ) { //for each part if ( pol[i].size() > 1 ) { for ( int j = 1; j < pol[i].size(); ++j ) { tempPol = QgsPolygon() << pol[i][j]; tempGeom = QgsGeometry::fromPolygon( tempPol ); if ( tempGeom.area() < area && tempGeom.contains( &p ) ) { fid = f.id(); partNum = i; ringNum = j; area = tempGeom.area(); ringGeom = tempGeom; } } } } } return ringGeom; }
void QgsSelectByFormDialog::zoomToFeatures( const QString &filter ) { QgsFeatureIds ids; QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) ); QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter ) .setExpressionContext( context ) .setSubsetOfAttributes( QgsAttributeList() ); QgsFeatureIterator features = mLayer->getFeatures( request ); QgsRectangle bbox; bbox.setMinimal(); QgsFeature feat; int featureCount = 0; while ( features.nextFeature( feat ) ) { QgsGeometry geom = feat.geometry(); if ( geom.isNull() || geom.geometry()->isEmpty() ) continue; QgsRectangle r = mMapCanvas->mapSettings().layerExtentToOutputExtent( mLayer, geom.boundingBox() ); bbox.combineExtentWith( r ); featureCount++; } features.close(); QgsSettings settings; int timeout = settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt(); if ( featureCount > 0 ) { mMapCanvas->zoomToFeatureExtent( bbox ); if ( mMessageBar ) { mMessageBar->pushMessage( QString(), tr( "Zoomed to %n matching feature(s)", "number of matching features", featureCount ), QgsMessageBar::INFO, timeout ); } } else if ( mMessageBar ) { mMessageBar->pushMessage( QString(), tr( "No matching features found" ), QgsMessageBar::INFO, timeout ); } }
void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const { double offsetX = 0; double offsetY = 0; markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale ); offset = QPointF( offsetX, offsetY ); //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle) bool ok = true; angle = mAngle + mLineAngle; bool usingDataDefinedRotation = false; if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle ) ) { context.setOriginalValueVariable( angle ); angle = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyAngle, context.renderContext().expressionContext(), 0 ) + mLineAngle; usingDataDefinedRotation = ok; } hasDataDefinedRotation = context.renderHints() & QgsSymbol::DynamicRotation || usingDataDefinedRotation; if ( hasDataDefinedRotation ) { // For non-point markers, "dataDefinedRotation" means following the // shape (shape-data defined). For them, "field-data defined" does // not work at all. TODO: if "field-data defined" ever gets implemented // we'll need a way to distinguish here between the two, possibly // using another flag in renderHints() const QgsFeature *f = context.feature(); if ( f ) { const QgsGeometry g = f->geometry(); if ( !g.isNull() && g.type() == QgsWkbTypes::PointGeometry ) { const QgsMapToPixel &m2p = context.renderContext().mapToPixel(); angle += m2p.mapRotation(); } } } if ( angle ) offset = _rotatedOffset( offset, angle ); }
ErrorList topolTest::checkValid( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( tolerance ); Q_UNUSED( layer1 ); Q_UNUSED( layer2 ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; QgsFeature f; QList<FeatureLayer>::Iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( ++i ); if ( testCanceled() ) break; QgsGeometry g = it->feature.geometry(); if ( g.isNull() ) { QgsMessageLog::logMessage( tr( "Invalid geometry in validity test." ), tr( "Topology plugin" ) ); continue; } GEOSGeometry *gGeos = g.exportToGeos(); if ( !gGeos ) continue; if ( !GEOSisValid_r( QgsGeometry::getGEOSHandler(), gGeos ) ) { QgsRectangle r = g.boundingBox(); QList<FeatureLayer> fls; fls << *it << *it; TopolErrorValid *err = new TopolErrorValid( r, g, fls ); errorList << err; } GEOSGeom_destroy_r( QgsGeometry::getGEOSHandler(), gGeos ); } return errorList; }
//! Makes sure that what came out from difference of two geometries is good to be used in the output static bool sanitizeDifferenceResult( QgsGeometry &geom ) { if ( geom.isNull() ) { // TODO: not sure if this ever happens - if it does, that means GEOS failed badly - would be good to have a test for such situation throw QgsProcessingException( QStringLiteral( "%1\n\n%2" ).arg( QObject::tr( "GEOS geoprocessing error: difference failed." ), geom.lastError() ) ); } // if geomB covers the whole source geometry, we get an empty geometry collection if ( geom.isEmpty() ) return false; // some data providers are picky about the geometries we pass to them: we can't add single-part geometries // when we promised multi-part geometries, so ensure we have the right type geom.convertToMultiType(); return true; }
QgsGeometry QgsGeometryAnalyzer::dissolveFeature( const QgsFeature &f, const QgsGeometry &dissolveInto ) { if ( !f.hasGeometry() ) { return dissolveInto; } QgsGeometry featureGeometry = f.geometry(); if ( dissolveInto.isNull() ) { return featureGeometry; } else { return dissolveInto.combine( featureGeometry ); } }
bool TopolError::fixUnion( const FeatureLayer &fl1, const FeatureLayer &fl2 ) { bool ok; QgsFeature f1, f2; ok = fl1.layer->getFeatures( QgsFeatureRequest().setFilterFid( fl1.feature.id() ) ).nextFeature( f1 ); ok = ok && fl2.layer->getFeatures( ( QgsFeatureRequest().setFilterFid( fl2.feature.id() ) ) ).nextFeature( f2 ); if ( !ok ) return false; QgsGeometry g = f1.geometry().combine( f2.geometry() ); if ( g.isNull() ) return false; if ( fl2.layer->deleteFeature( f2.id() ) ) return fl1.layer->changeGeometry( f1.id(), g ); return false; }
bool TopolError::fixMove( const FeatureLayer &fl1, const FeatureLayer &fl2 ) { bool ok; QgsFeature f1, f2; ok = fl1.layer->getFeatures( QgsFeatureRequest().setFilterFid( fl1.feature.id() ) ).nextFeature( f1 ); ok = ok && fl2.layer->getFeatures( ( QgsFeatureRequest().setFilterFid( fl2.feature.id() ) ) ).nextFeature( f2 ); if ( !ok ) return false; // 0 means success QgsGeometry g = f1.geometry(); QgsGeometry difference = g.makeDifference( f2.geometry() ); if ( !difference.isNull() ) { return fl1.layer->changeGeometry( f1.id(), difference ); } return false; }
QgsVectorLayer::EditResult QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId featureId, int vertex ) { if ( !mLayer->isSpatial() ) return QgsVectorLayer::InvalidLayer; QgsFeature f; if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() ) return QgsVectorLayer::FetchFeatureFailed; // geometry not found QgsGeometry geometry = f.geometry(); if ( !geometry.deleteVertex( vertex ) ) return QgsVectorLayer::EditFailed; if ( geometry.constGet() && geometry.constGet()->nCoordinates() == 0 ) { //last vertex deleted, set geometry to null geometry.set( nullptr ); } mLayer->editBuffer()->changeGeometry( featureId, geometry ); return !geometry.isNull() ? QgsVectorLayer::Success : QgsVectorLayer::EmptyGeometry; }
//! Returns a simplified version the specified geometry (Removing duplicated points) when is applied the specified map2pixel context QgsGeometry QgsMapToPixelSimplifier::simplify( const QgsGeometry& geometry ) const { if ( geometry.isNull() ) { return QgsGeometry(); } if ( mSimplifyFlags == QgsMapToPixelSimplifier::NoFlags ) { return geometry; } // Check whether the geometry can be simplified using the map2pixel context const QgsWkbTypes::Type singleType = QgsWkbTypes::singleType( geometry.wkbType() ); const QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( singleType ); if ( flatType == QgsWkbTypes::Point ) { return geometry; } const bool isaLinearRing = flatType == QgsWkbTypes::Polygon; const int numPoints = geometry.geometry()->nCoordinates(); if ( numPoints <= ( isaLinearRing ? 6 : 3 ) ) { // No simplify simple geometries return geometry; } const QgsRectangle envelope = geometry.boundingBox(); if ( qMax( envelope.width(), envelope.height() ) / numPoints > mTolerance * 2.0 ) { //points are in average too far apart to lead to any significant simplification return geometry; } return simplifyGeometry( mSimplifyFlags, mSimplifyAlgorithm, geometry.wkbType(), *geometry.geometry(), envelope, mTolerance, false ); }
bool QgsGeometryAnalyzer::eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString &outputLayer, const QString &outputFormat, int locationField1, int locationField2, int offsetField, double offsetScale, bool forceSingleGeometry, QgsVectorDataProvider *memoryProvider, QProgressDialog *p ) { if ( !lineLayer || !eventLayer || !lineLayer->isValid() || !eventLayer->isValid() ) { return false; } //create line field / id map for line layer QMultiHash< QString, QgsFeature > lineLayerIdMap; //1:n possible (e.g. several linear reference geometries for one feature in the event layer) QgsFeatureIterator fit = lineLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() << lineField ) ); QgsFeature fet; while ( fit.nextFeature( fet ) ) { lineLayerIdMap.insert( fet.attribute( lineField ).toString(), fet ); } //create output datasource or attributes in memory provider QgsVectorFileWriter *fileWriter = nullptr; QgsFeatureList memoryProviderFeatures; if ( !memoryProvider ) { QgsWkbTypes::Type memoryProviderType = QgsWkbTypes::MultiLineString; if ( locationField2 == -1 ) { memoryProviderType = forceSingleGeometry ? QgsWkbTypes::Point : QgsWkbTypes::MultiPoint; } else { memoryProviderType = forceSingleGeometry ? QgsWkbTypes::LineString : QgsWkbTypes::MultiLineString; } fileWriter = new QgsVectorFileWriter( outputLayer, eventLayer->dataProvider()->encoding(), eventLayer->fields(), memoryProviderType, lineLayer->crs(), outputFormat ); } else { memoryProvider->addAttributes( eventLayer->fields().toList() ); } //iterate over eventLayer and write new features to output file or layer fit = eventLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ); QgsGeometry lrsGeom; double measure1, measure2 = 0.0; int nEventFeatures = eventLayer->featureCount(); int featureCounter = 0; int nOutputFeatures = 0; //number of output features for the current event feature if ( p ) { p->setWindowModality( Qt::WindowModal ); p->setMinimum( 0 ); p->setMaximum( nEventFeatures ); p->show(); } while ( fit.nextFeature( fet ) ) { nOutputFeatures = 0; //update progress dialog if ( p ) { if ( p->wasCanceled() ) { break; } p->setValue( featureCounter ); ++featureCounter; } measure1 = fet.attribute( locationField1 ).toDouble(); if ( locationField2 != -1 ) { measure2 = fet.attribute( locationField2 ).toDouble(); if ( qgsDoubleNear( ( measure2 - measure1 ), 0.0 ) ) { continue; } } QList<QgsFeature> featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() ); QList<QgsFeature>::iterator featureIdIt = featureIdList.begin(); for ( ; featureIdIt != featureIdList.end(); ++featureIdIt ) { if ( locationField2 == -1 ) { lrsGeom = locateAlongMeasure( measure1, featureIdIt->geometry() ); } else { lrsGeom = locateBetweenMeasures( measure1, measure2, featureIdIt->geometry() ); } if ( !lrsGeom.isNull() ) { ++nOutputFeatures; addEventLayerFeature( fet, lrsGeom, featureIdIt->geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry ); } } if ( nOutputFeatures < 1 ) { unlocatedFeatureIds.insert( fet.id() ); } } if ( p ) { p->setValue( nEventFeatures ); } if ( memoryProvider ) { memoryProvider->addFeatures( memoryProviderFeatures ); } delete fileWriter; return true; }
bool QgsGeometryAnalyzer::buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance, bool onlySelectedFeatures, bool dissolve, int bufferDistanceField, QProgressDialog *p ) { if ( !layer ) { return false; } QgsVectorDataProvider *dp = layer->dataProvider(); if ( !dp ) { return false; } QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; if ( dissolve ) { outputType = QgsWkbTypes::MultiPolygon; } QgsCoordinateReferenceSystem crs = layer->crs(); QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs ); QgsFeature currentFeature; QgsGeometry dissolveGeometry; //dissolve geometry (if dissolve enabled) //take only selection if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeatureIds(); if ( p ) { p->setMaximum( selection.size() ); } int processedFeatures = 0; QgsFeatureIds::const_iterator it = selection.constBegin(); for ( ; it != selection.constEnd(); ++it ) { if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { break; } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) { continue; } bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField ); ++processedFeatures; } if ( p ) { p->setValue( selection.size() ); } } //take all features else { QgsFeatureIterator fit = layer->getFeatures(); int featureCount = layer->featureCount(); if ( p ) { p->setMaximum( featureCount ); } int processedFeatures = 0; while ( fit.nextFeature( currentFeature ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { break; } bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField ); ++processedFeatures; } if ( p ) { p->setValue( featureCount ); } } if ( dissolve ) { QgsFeature dissolveFeature; if ( dissolveGeometry.isNull() ) { QgsDebugMsg( "no dissolved geometry - should not happen" ); return false; } dissolveFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( dissolveFeature ); } return true; }
bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures, int uniqueIdField, QProgressDialog *p ) { if ( !layer ) { return false; } QgsVectorDataProvider *dp = layer->dataProvider(); if ( !dp ) { return false; } bool useField = false; if ( uniqueIdField == -1 ) { uniqueIdField = 0; } else { useField = true; } QgsFields fields; fields.append( QgsField( QStringLiteral( "UID" ), QVariant::String ) ); fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) ); fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) ); QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon; QgsCoordinateReferenceSystem crs = layer->crs(); QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs ); QgsFeature currentFeature; QgsGeometry dissolveGeometry; //dissolve geometry QMultiMap<QString, QgsFeatureId> map; if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeatureIds(); QgsFeatureIds::const_iterator it = selection.constBegin(); for ( ; it != selection.constEnd(); ++it ) { #if 0 if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { // break; // it may be better to do something else here? return false; } #endif if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) ) { continue; } map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } else { QgsFeatureIterator fit = layer->getFeatures(); while ( fit.nextFeature( currentFeature ) ) { #if 0 if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { // break; // it may be better to do something else here? return false; } #endif map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() ); } } QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin(); while ( jt != map.constEnd() ) { QString currentKey = jt.key(); int processedFeatures = 0; //take only selection if ( onlySelectedFeatures ) { //use QgsVectorLayer::featureAtId const QgsFeatureIds selection = layer->selectedFeatureIds(); if ( p ) { p->setMaximum( selection.size() ); } processedFeatures = 0; while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p && p->wasCanceled() ) { break; } if ( selection.contains( jt.value() ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } convexFeature( currentFeature, processedFeatures, dissolveGeometry ); ++processedFeatures; } ++jt; } QList<double> values; if ( dissolveGeometry.isNull() ) { QgsDebugMsg( "no dissolved geometry - should not happen" ); return false; } dissolveGeometry = dissolveGeometry.convexHull(); values = simpleMeasure( dissolveGeometry ); QgsAttributes attributes( 3 ); attributes[0] = QVariant( currentKey ); attributes[1] = values.at( 0 ); attributes[2] = values.at( 1 ); QgsFeature dissolveFeature; dissolveFeature.setAttributes( attributes ); dissolveFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( dissolveFeature ); } //take all features else { int featureCount = layer->featureCount(); if ( p ) { p->setMaximum( featureCount ); } processedFeatures = 0; while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) ) { if ( p ) { p->setValue( processedFeatures ); } if ( p && p->wasCanceled() ) { break; } if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) ) { continue; } convexFeature( currentFeature, processedFeatures, dissolveGeometry ); ++processedFeatures; ++jt; } QList<double> values; if ( dissolveGeometry.isNull() ) { QgsDebugMsg( "no dissolved geometry - should not happen" ); return false; } dissolveGeometry = dissolveGeometry.convexHull(); // values = simpleMeasure( tmpGeometry ); values = simpleMeasure( dissolveGeometry ); QgsAttributes attributes; attributes[0] = QVariant( currentKey ); attributes[1] = QVariant( values[ 0 ] ); attributes[2] = QVariant( values[ 1 ] ); QgsFeature dissolveFeature; dissolveFeature.setAttributes( attributes ); dissolveFeature.setGeometry( dissolveGeometry ); vWriter.addFeature( dissolveFeature ); } } return true; }
QgsGeometry QgsGeometryAnalyzer::createOffsetGeometry( const QgsGeometry &geom, const QgsGeometry &lineGeom, double offset ) { if ( !geom || lineGeom.isNull() ) { return QgsGeometry(); } QList<QgsGeometry> inputGeomList; if ( geom.isMultipart() ) { inputGeomList = geom.asGeometryCollection(); } else { inputGeomList.push_back( geom ); } QList<GEOSGeometry *> outputGeomList; QList<QgsGeometry>::const_iterator inputGeomIt = inputGeomList.constBegin(); GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler(); for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt ) { if ( geom.type() == QgsWkbTypes::LineGeometry ) { GEOSGeometry *inputGeomItGeos = inputGeomIt->exportToGeos(); GEOSGeometry *offsetGeom = GEOSOffsetCurve_r( geosctxt, inputGeomItGeos, -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*mitreLimit*/ ); GEOSGeom_destroy_r( geosctxt, inputGeomItGeos ); if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) ) { return QgsGeometry(); } if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 ) { GEOSGeom_destroy_r( geosctxt, offsetGeom ); return QgsGeometry(); } outputGeomList.push_back( offsetGeom ); } else if ( geom.type() == QgsWkbTypes::PointGeometry ) { QgsPointXY p = ( *inputGeomIt ).asPoint(); p = createPointOffset( p.x(), p.y(), offset, lineGeom ); GEOSCoordSequence *ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 ); GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() ); GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() ); GEOSGeometry *geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq ); outputGeomList.push_back( geosPt ); } } QgsGeometry outGeometry; if ( !geom.isMultipart() ) { GEOSGeometry *outputGeom = outputGeomList.at( 0 ); if ( outputGeom ) { outGeometry.fromGeos( outputGeom ); } } else { GEOSGeometry **geomArray = new GEOSGeometry*[outputGeomList.size()]; for ( int i = 0; i < outputGeomList.size(); ++i ) { geomArray[i] = outputGeomList.at( i ); } GEOSGeometry *collection = nullptr; if ( geom.type() == QgsWkbTypes::PointGeometry ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() ); } else if ( geom.type() == QgsWkbTypes::LineGeometry ) { collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() ); } outGeometry.fromGeos( collection ); delete[] geomArray; } return outGeometry; }
void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e ) { if ( !mCanvas ) { return; } QgsVectorLayer *vlayer = currentVectorLayer(); if ( !vlayer ) { deleteRotationWidget(); deleteRubberband(); notifyNotVectorLayer(); return; } if ( e->button() == Qt::RightButton ) { cancel(); return; } // place anchor point on CTRL + click if ( e->modifiers() & Qt::ControlModifier ) { if ( !mAnchorPoint ) { return; } mAnchorPoint->setCenter( toMapCoordinates( e->pos() ) ); mStartPointMapCoords = toMapCoordinates( e->pos() ); mStPoint = e->pos(); return; } deleteRotationWidget(); // Initialize rotation if not yet active if ( !mRotationActive ) { mRotation = 0; mRotationOffset = 0; deleteRubberband(); mInitialPos = e->pos(); if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->pos() ); 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() ) { 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() ) { emit messageEmitted( tr( "Could not find a nearby feature in the current layer." ) ); return; } QgsRectangle bound = cf.geometry().boundingBox(); mStartPointMapCoords = toMapCoordinates( vlayer, bound.center() ); if ( !mAnchorPoint ) { mAnchorPoint = qgis::make_unique<QgsVertexMarker>( mCanvas ); } mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS ); mAnchorPoint->setCenter( mStartPointMapCoords ); mStPoint = toCanvasCoordinates( mStartPointMapCoords ); mRotatedFeatures.clear(); mRotatedFeatures << cf.id(); //todo: take the closest feature, not the first one... mRubberBand = createRubberBand( vlayer->geometryType() ); mRubberBand->setToGeometry( cf.geometry(), vlayer ); } else { mRotatedFeatures = vlayer->selectedFeatureIds(); mRubberBand = createRubberBand( vlayer->geometryType() ); QgsFeature feat; QgsFeatureIterator it = vlayer->getSelectedFeatures(); while ( it.nextFeature( feat ) ) { mRubberBand->addGeometry( feat.geometry(), vlayer ); } } mRubberBand->show(); double XDistance = mInitialPos.x() - mAnchorPoint->x(); double YDistance = mInitialPos.y() - mAnchorPoint->y(); mRotationOffset = std::atan2( YDistance, XDistance ) * ( 180 / M_PI ); createRotationWidget(); if ( e->modifiers() & Qt::ShiftModifier ) { if ( mRotationWidget ) { mRotationWidget->setMagnet( 45 ); } } mRotationActive = true; return; } applyRotation( mRotation ); }