示例#1
0
void QgsMapToolSelectUtils::setSelectFeatures( QgsMapCanvas* canvas,
        QgsGeometry* selectGeometry,
        bool doContains,
        bool doDifference,
        bool singleSelect )
{
    if ( selectGeometry->type() != QGis::Polygon )
    {
        return;
    }
    QgsVectorLayer* vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas );
    if ( vlayer == NULL )
    {
        return;
    }

    // toLayerCoordinates will throw an exception for any 'invalid' points in
    // the rubber band.
    // For example, if you project a world map onto a globe using EPSG 2163
    // and then click somewhere off the globe, an exception will be thrown.
    QgsGeometry selectGeomTrans( *selectGeometry );

    if ( canvas->mapRenderer()->hasCrsTransformEnabled() )
    {
        try
        {
            QgsCoordinateTransform ct( canvas->mapRenderer()->destinationCrs(), vlayer->crs() );
            selectGeomTrans.transform( ct );
        }
        catch ( QgsCsException &cse )
        {
            Q_UNUSED( cse );
            // catch exception for 'invalid' point and leave existing selection unchanged
            QgsLogger::warning( "Caught CRS exception " + QString( __FILE__ ) + ": " + QString::number( __LINE__ ) );
            QMessageBox::warning( canvas, QObject::tr( "CRS Exception" ),
                                  QObject::tr( "Selection extends beyond layer's coordinate system." ) );
            return;
        }
    }

    QApplication::setOverrideCursor( Qt::WaitCursor );

    QgsDebugMsg( "Selection layer: " + vlayer->name() );
    QgsDebugMsg( "Selection polygon: " + selectGeomTrans.exportToWkt() );
    QgsDebugMsg( "doContains: " + QString( doContains ? "T" : "F" ) );
    QgsDebugMsg( "doDifference: " + QString( doDifference ? "T" : "F" ) );

    vlayer->select( QgsAttributeList(), selectGeomTrans.boundingBox(), true, true );

    QgsFeatureIds newSelectedFeatures;
    QgsFeature f;
    QgsFeatureId closestFeatureId = 0;
    bool foundSingleFeature = false;
    double closestFeatureDist = std::numeric_limits<double>::max();
    while ( vlayer->nextFeature( f ) )
    {
        QgsGeometry* g = f.geometry();
        if ( doContains )
        {
            if ( !selectGeomTrans.contains( g ) )
                continue;
        }
        else
        {
            if ( !selectGeomTrans.intersects( g ) )
                continue;
        }
        if ( singleSelect )
        {
            foundSingleFeature = true;
            double distance = g->distance( selectGeomTrans );
            if ( distance <= closestFeatureDist )
            {
                closestFeatureDist = distance;
                closestFeatureId = f.id();
            }
        }
        else
        {
            newSelectedFeatures.insert( f.id() );
        }
    }
    if ( singleSelect && foundSingleFeature )
    {
        newSelectedFeatures.insert( closestFeatureId );
    }

    QgsDebugMsg( "Number of new selected features: " + QString::number( newSelectedFeatures.size() ) );

    QgsFeatureIds layerSelectedFeatures;
    if ( doDifference )
    {
        layerSelectedFeatures = vlayer->selectedFeaturesIds();
        QgsFeatureIds::const_iterator i = newSelectedFeatures.constEnd();
        while ( i != newSelectedFeatures.constBegin() )
        {
            --i;
            if ( layerSelectedFeatures.contains( *i ) )
            {
                layerSelectedFeatures.remove( *i );
            }
            else
            {
                layerSelectedFeatures.insert( *i );
            }
        }
    }
    else
    {
        layerSelectedFeatures = newSelectedFeatures;
    }
    vlayer->setSelectedFeatures( layerSelectedFeatures );

    QApplication::restoreOverrideCursor();
}
void QgsMergeAttributesDialog::mRemoveFeatureFromSelectionButton_clicked()
{
  if ( !mVectorLayer )
  {
    return;
  }

  //find out feature id of selected row
  QList<QTableWidgetItem *> selectionList = mTableWidget->selectedItems();
  if ( selectionList.isEmpty() )
  {
    return;
  }

  //assume all selected items to be in the same row
  QTableWidgetItem *selectedItem = selectionList[0];
  int selectedRow = selectedItem->row();
  QTableWidgetItem *selectedHeaderItem = mTableWidget->verticalHeaderItem( selectedRow );
  if ( !selectedHeaderItem )
  {
    return;
  }

  bool conversionSuccess;
  QgsFeatureId featureId = selectedHeaderItem->text().toLongLong( &conversionSuccess );
  if ( !conversionSuccess )
  {
    selectedRowChanged();
    return;
  }

  mTableWidget->removeRow( selectedRow );
  selectedRowChanged();

  //remove feature from the vector layer selection
  QgsFeatureIds selectedIds = mVectorLayer->selectedFeatureIds();
  selectedIds.remove( featureId );
  mVectorLayer->selectByIds( selectedIds );
  mMapCanvas->repaint();

  //remove feature option from the combo box (without altering the current merge values)
  for ( int i = 0; i < mTableWidget->columnCount(); ++i )
  {
    QComboBox *currentComboBox = qobject_cast<QComboBox *>( mTableWidget->cellWidget( 0, i ) );
    if ( !currentComboBox )
      continue;

    currentComboBox->blockSignals( true );
    currentComboBox->removeItem( currentComboBox->findData( QStringLiteral( "f%1" ).arg( FID_TO_STRING( featureId ) ) ) );
    currentComboBox->blockSignals( false );
  }

  //finally remove the feature from mFeatureList
  for ( QgsFeatureList::iterator f_it = mFeatureList.begin();
        f_it != mFeatureList.end();
        ++f_it )
  {
    if ( f_it->id() == featureId )
    {
      mFeatureList.erase( f_it );
      break;
    }
  }
}
void QgsLocationBasedAlgorithm::process( QgsFeatureSource *targetSource,
    QgsFeatureSource *intersectSource,
    const QList< int > &selectedPredicates,
    const std::function < void( const QgsFeature & ) > &handleFeatureFunction,
    bool onlyRequireTargetIds,
    QgsFeedback *feedback )
{
  // build a list of 'reversed' predicates, because in this function
  // we actually test the reverse of what the user wants (allowing us
  // to prepare geometries and optimise the algorithm)
  QList< Predicate > predicates;
  for ( int i : selectedPredicates )
  {
    predicates << reversePredicate( static_cast< Predicate >( i ) );
  }

  QgsFeatureIds disjointSet;
  if ( predicates.contains( Disjoint ) )
    disjointSet = targetSource->allFeatureIds();

  QgsFeatureIds foundSet;
  QgsFeatureRequest request = QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ).setDestinationCrs( targetSource->sourceCrs() );
  QgsFeatureIterator fIt = intersectSource->getFeatures( request );
  double step = intersectSource->featureCount() > 0 ? 100.0 / intersectSource->featureCount() : 1;
  int current = 0;
  QgsFeature f;
  std::unique_ptr< QgsGeometryEngine > engine;
  while ( fIt.nextFeature( f ) )
  {
    if ( feedback->isCanceled() )
      break;

    if ( !f.hasGeometry() )
      continue;

    engine.reset();

    QgsRectangle bbox = f.geometry().boundingBox();
    request = QgsFeatureRequest().setFilterRect( bbox );
    if ( onlyRequireTargetIds )
      request.setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( QgsAttributeList() );

    QgsFeatureIterator testFeatureIt = targetSource->getFeatures( request );
    QgsFeature testFeature;
    while ( testFeatureIt.nextFeature( testFeature ) )
    {
      if ( feedback->isCanceled() )
        break;

      if ( foundSet.contains( testFeature.id() ) )
      {
        // already added this one, no need for further tests
        continue;
      }
      if ( predicates.count() == 1 && predicates.at( 0 ) == Disjoint && !disjointSet.contains( testFeature.id() ) )
      {
        // calculating only the disjoint set, and we've already eliminated this feature so no need for further tests
        continue;
      }

      if ( !engine )
      {
        engine.reset( QgsGeometry::createGeometryEngine( f.geometry().geometry() ) );
        engine->prepareGeometry();
      }

      for ( Predicate predicate : qgis::as_const( predicates ) )
      {
        bool isMatch = false;
        switch ( predicate )
        {
          case Intersects:
            isMatch = engine->intersects( testFeature.geometry().geometry() );
            break;
          case Contains:
            isMatch = engine->contains( testFeature.geometry().geometry() );
            break;
          case Disjoint:
            if ( engine->intersects( testFeature.geometry().geometry() ) )
            {
              disjointSet.remove( testFeature.id() );
            }
            break;
          case IsEqual:
            isMatch = engine->isEqual( testFeature.geometry().geometry() );
            break;
          case Touches:
            isMatch = engine->touches( testFeature.geometry().geometry() );
            break;
          case Overlaps:
            isMatch = engine->overlaps( testFeature.geometry().geometry() );
            break;
          case Within:
            isMatch = engine->within( testFeature.geometry().geometry() );
            break;
          case Crosses:
            isMatch = engine->crosses( testFeature.geometry().geometry() );
            break;
        }
        if ( isMatch )
        {
          foundSet.insert( testFeature.id() );
          handleFeatureFunction( testFeature );
        }
      }

    }

    current += 1;
    feedback->setProgress( current * step );
  }

  if ( predicates.contains( Disjoint ) )
  {
    disjointSet = disjointSet.subtract( foundSet );
    QgsFeatureRequest disjointReq = QgsFeatureRequest().setFilterFids( disjointSet );
    if ( onlyRequireTargetIds )
      disjointReq.setSubsetOfAttributes( QgsAttributeList() ).setFlags( QgsFeatureRequest::NoGeometry );
    QgsFeatureIterator disjointIt = targetSource->getFeatures( disjointReq );
    QgsFeature f;
    while ( disjointIt.nextFeature( f ) )
    {
      handleFeatureFunction( f );
    }
  }
}