Beispiel #1
0
std::unique_ptr<QgsAbstractGeometry> QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry &geom,
    const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
    const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
{
  std::unique_ptr<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( &geom ) );
  if ( !geomEngine )
  {
    return nullptr;
  }
  QgsWkbTypes::Type geomTypeBeforeModification = geom.wkbType();


  //check if g has polygon type
  if ( QgsWkbTypes::geometryType( geomTypeBeforeModification ) != QgsWkbTypes::PolygonGeometry )
  {
    return nullptr;
  }

  if ( avoidIntersectionsLayers.isEmpty() )
    return nullptr; //no intersections stored in project does not mean error

  QList< QgsGeometry > nearGeometries;

  //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
  for ( QgsVectorLayer *currentLayer : avoidIntersectionsLayers )
  {
    QgsFeatureIds ignoreIds;
    QHash<QgsVectorLayer *, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.constFind( currentLayer );
    if ( ignoreIt != ignoreFeatures.constEnd() )
      ignoreIds = ignoreIt.value();

    QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
                            .setFlags( QgsFeatureRequest::ExactIntersect )
                            .setSubsetOfAttributes( QgsAttributeList() ) );
    QgsFeature f;
    while ( fi.nextFeature( f ) )
    {
      if ( ignoreIds.contains( f.id() ) )
        continue;

      if ( !f.hasGeometry() )
        continue;

      nearGeometries << f.geometry();
    }
  }

  if ( nearGeometries.isEmpty() )
  {
    return nullptr;
  }

  std::unique_ptr< QgsAbstractGeometry > combinedGeometries( geomEngine->combine( nearGeometries ) );
  if ( !combinedGeometries )
  {
    return nullptr;
  }

  std::unique_ptr< QgsAbstractGeometry > diffGeom( geomEngine->difference( combinedGeometries.get() ) );

  return diffGeom;
}
Beispiel #2
0
void QgsGeometryGapCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
{
  if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );

  QVector<QgsAbstractGeometry *> geomList;

  QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
  QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, 0, true );
  for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
  {
    geomList.append( layerFeature.geometry()->clone() );
  }

  if ( geomList.isEmpty() )
  {
    return;
  }

  std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( nullptr, mContext->tolerance );

  // Create union of geometry
  QString errMsg;
  QgsAbstractGeometry *unionGeom = geomEngine->combine( geomList, &errMsg );
  qDeleteAll( geomList );
  if ( !unionGeom )
  {
    messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
    return;
  }

  // Get envelope of union
  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( unionGeom, mContext->tolerance );
  QgsAbstractGeometry *envelope = geomEngine->envelope( &errMsg );
  if ( !envelope )
  {
    messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
    delete unionGeom;
    return;
  }

  // Buffer envelope
  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope, mContext->tolerance );
  QgsAbstractGeometry *bufEnvelope = geomEngine->buffer( 2, 0, GEOSBUF_CAP_SQUARE, GEOSBUF_JOIN_MITRE, 4. );  //#spellok  //#spellok
  delete envelope;
  envelope = bufEnvelope;

  // Compute difference between envelope and union to obtain gap polygons
  geomEngine = QgsGeometryCheckerUtils::createGeomEngine( envelope, mContext->tolerance );
  QgsAbstractGeometry *diffGeom = geomEngine->difference( unionGeom, &errMsg );
  if ( !diffGeom )
  {
    messages.append( tr( "Gap check: %1" ).arg( errMsg ) );
    delete unionGeom;
    delete diffGeom;
    return;
  }

  // For each gap polygon which does not lie on the boundary, get neighboring polygons and add error
  for ( int iPart = 0, nParts = diffGeom->partCount(); iPart < nParts; ++iPart )
  {
    QgsAbstractGeometry *gapGeom = QgsGeometryCheckerUtils::getGeomPart( diffGeom, iPart )->clone();
    // Skip the gap between features and boundingbox
    if ( gapGeom->boundingBox() == envelope->boundingBox() )
    {
      continue;
    }

    // Skip gaps above threshold
    if ( gapGeom->area() > mThresholdMapUnits || gapGeom->area() < mContext->reducedTolerance )
    {
      continue;
    }

    QgsRectangle gapAreaBBox = gapGeom->boundingBox();

    // Get neighboring polygons
    QMap<QString, QgsFeatureIds> neighboringIds;
    QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds.keys(), gapAreaBBox, mCompatibleGeometryTypes );
    for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
    {
      if ( QgsGeometryCheckerUtils::sharedEdgeLength( gapGeom, layerFeature.geometry(), mContext->reducedTolerance ) > 0 )
      {
        neighboringIds[layerFeature.layer().id()].insert( layerFeature.feature().id() );
        gapAreaBBox.combineExtentWith( layerFeature.geometry()->boundingBox() );
      }
    }

    if ( neighboringIds.isEmpty() )
    {
      delete gapGeom;
      continue;
    }

    // Add error
    errors.append( new QgsGeometryGapCheckError( this, "", gapGeom, neighboringIds, gapGeom->area(), gapAreaBBox ) );

  }
  delete unionGeom;
  delete envelope;
  delete diffGeom;
}