qgis二次开发矢量数据点选择的方法

来源:互联网 发布:linux smp调度 编辑:程序博客网 时间:2024/05/22 01:47

qgis网上的资料比较少,能找到的资料就那么几篇基本的加载图层之类的,最主要还是参考qgis本身的源码和其api文档。

在这里感谢qgis群同时也是地大群的大哥的指导。

qgis程序是C++和qt平台编译出来的可执行文件。

其中MapCanvas保存了一个指针指向当前的tool,tool里面有各种响应鼠标等事件。

MapCanvas中的响应系统鼠标事件,调用tool的事件

其中鼠标Middle单击事件,被定义为pan(tool)的事件
tool可以setAction,也可以设置按键。(效果应该等同于Action的trigger信号
绑定MapCanvas,设置mapcanvas的当前tool。

还可以设置cursor设置鼠标的形状(手型)

所以在知道qgis的tool功能的基础上找到源码中的selecttool,将selecttool移植到

自己的程序中。

注意:这移植的过程中,也出现了一些问题,以为可以调用qgisapp的库进行移植,

但是移植过程中出现了一系列的错误。所以最后还是只调用qgis的核心库

//QgsVectorLayer* vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( mCanvas );
//这一行的功能为选择当前的矢量图层,改成如下代码:
QgsVectorLayer* vlayer = NULL;
  if ( !canvas->currentLayer()
       || ( vlayer = qobject_cast<QgsVectorLayer *>( canvas->currentLayer() ) ) == NULL )
  {
    QMessageBoox::information(...);
  }




  if ( vlayer == NULL )
  {
    return;
  }


  QgsRubberBand *rubberBand = new QgsRubberBand( mCanvas, QGis::Polygon );
  QRect selectRect( 0, 0, 0, 0 );
  //QgsMapToolSelectUtils::expandSelectRectangle( selectRect, vlayer, e->pos() );
  //这行代码的意义在于将点的范围扩大。


  int boxSize = 0;
  if ( vlayer->geometryType() != QGis::Polygon )
  {
    //if point or line use an artificial bounding box of 10x10 pixels
    //to aid the user to click on a feature accurately
    boxSize = 5;
  }
  else
  {
    //otherwise just use the click point for polys
    boxSize = 1;
  }
  selectRect.setLeft( point.x() - boxSize );
  selectRect.setRight( point.x() + boxSize );
  selectRect.setTop( point.y() - boxSize );
  selectRect.setBottom( point.y() + boxSize );
  //
 // QgsMapToolSelectUtils::setRubberBand( mCanvas, selectRect, &rubberBand );
  const QgsMapToPixel* transform = canvas->getCoordinateTransform();
  QgsPoint ll = transform->toMapCoordinates( selectRect.left(), selectRect.bottom() );
  QgsPoint ur = transform->toMapCoordinates( selectRect.right(), selectRect.top() );


  if ( rubberBand )
  {
    rubberBand->reset( QGis::Polygon );
    rubberBand->addPoint( ll, false );
    rubberBand->addPoint( QgsPoint( ur.x(), ll.y() ), false );
    rubberBand->addPoint( ur, false );
    rubberBand->addPoint( QgsPoint( ll.x(), ur.y() ), true );
  }
  QgsGeometry* selectGeom = rubberBand.asGeometry();
  bool doDifference = e->modifiers() & Qt::ControlModifier ? true : false;
 // QgsMapToolSelectUtils::setSelectFeatures( mCanvas, selectGeom, false, doDifference, true );
 //这一行才是选择的功能


 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->mapSettings().hasCrsTransformEnabled() )
  {
    try
    {
      QgsCoordinateTransform ct( canvas->mapSettings().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" ) );


  QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectGeomTrans.boundingBox() ).setFlags( QgsFeatureRequest::ExactIntersect ).setSubsetOfAttributes( QgsAttributeList() ) );


  QgsFeatureIds newSelectedFeatures;
  QgsFeature f;
  QgsFeatureId closestFeatureId = 0;
  bool foundSingleFeature = false;
  double closestFeatureDist = std::numeric_limits<double>::max();
  while ( fit.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() ) );


  if ( doDifference )
  {
    QgsFeatureIds layerSelectedFeatures = vlayer->selectedFeaturesIds();


    QgsFeatureIds selectedFeatures;
    QgsFeatureIds deselectedFeatures;


    QgsFeatureIds::const_iterator i = newSelectedFeatures.constEnd();
    while ( i != newSelectedFeatures.constBegin() )
    {
      --i;
      if ( layerSelectedFeatures.contains( *i ) )
      {
        deselectedFeatures.insert( *i );
      }
      else
      {
        selectedFeatures.insert( *i );
      }
    }


    vlayer->modifySelection( selectedFeatures, deselectedFeatures );
  }
  else
  {
    vlayer->setSelectedFeatures( newSelectedFeatures );
  }


  QApplication::restoreOverrideCursor();
  delete selectGeom;
  rubberBand.reset( QGis::Polygon );



0 0
原创粉丝点击