为了满足shapefile 编辑,实现键鼠对地理要素的增删改。
读取shapefile,用Geometry Feature FeatureNode绘制在osgEarth上;
自定义osgGA::GUIEventHandler,handle函数中监测osgGA::GUIEventAdapter::PUSH
之前疑惑在拾取,看过许多例子,比如:osgEarth 拾取示例,最后还是老老实实用的射线拾取(osgUtil::LineSegmentIntersector)
大佬们多多指点,在此做个记录。
osgEarth Node 键鼠交互 增删改
①拾取选中的featureNode确定距离鼠标最近的顶点。
// 使用射线拾取,找到 FeatureNode
osg::ref_ptr<osgEarth::FeatureNode> FeatureEditorHandler::pickFeatureNode(osgViewer::View* view, float x, float y) {
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y);
osgUtil::IntersectionVisitor iv(intersector);
view->getCamera()->accept(iv);
if (intersector->containsIntersections()) {
// 获取所有交叉点
auto intersections = intersector->getIntersections();
double minDistance = std::numeric_limits<double>::max();
osg::ref_ptr<osgEarth::FeatureNode> nearestFeatureNode = nullptr;
for (const auto& intersection : intersections) {
osg::NodePath nodePath = intersection.nodePath;
for (osg::Node* node : nodePath) {
osg::Group* groupNode = dynamic_cast<osg::Group*>(node);
if (groupNode) {
for (unsigned int i = 0; i < groupNode->getNumChildren(); ++i) {
osgEarth::FeatureNode* childFeatureNode = dynamic_cast<osgEarth::FeatureNode*>(groupNode->getChild(i));
if (childFeatureNode) {
Feature* feature = childFeatureNode->getFeature();
Geometry* geometry = feature->getGeometry();
if (geometry) {
// 将交叉点转换为地理坐标
GeoPoint _GeoPoint;
_GeoPoint.fromWorld(_mapNode->getMapSRS(), intersection.getWorldIntersectPoint());
osg::Vec3d clickPoint(_GeoPoint.x(), _GeoPoint.y(), _GeoPoint.z());
// 遍历顶点并找到与点击点最近的顶点
for (unsigned int j = 0; j < geometry->size(); ++j) {
osg::Vec3d vertex = geometry->operator[](j);
double distance = (vertex - clickPoint).length();
if (distance < minDistance) {
minDistance = distance;
nearestFeatureNode = childFeatureNode;
_nearestVertexIndex = j; // 更新最近的顶点索引
}
}
}
}
}
}
}
}
return nearestFeatureNode; // 返回最近的 FeatureNode
}
return nullptr; // 未找到返回空
}
②修改顶点
// 更新几何体的顶点位置
void FeatureEditorHandler::updateFeatureGeometry( osgViewer::View* view, osgEarth::FeatureNode* featureNode, float x, float y) {
osg::Vec3d worldPos = screenToWorld(view, x, y); // 将屏幕坐标转换为世界坐标
if (featureNode) {
osgEarth::Geometry* geometry = featureNode->getFeature()->getGeometry();
if (geometry) {
int iCnt = geometry->size();
GeoPoint _GeoPoint;
_GeoPoint.fromWorld(_mapNode->getMapSRS(), worldPos);
// qDebugV5()<<"_nearestVertexIndex:"<<_nearestVertexIndex;
if(_nearestVertexIndex>=0 &&_nearestVertexIndex<iCnt){
// 修改几何体的第一个顶点(可以根据需求修改其他顶点)
geometry->at(_nearestVertexIndex) = osg::Vec3d(_GeoPoint.x(), _GeoPoint.y(), _GeoPoint.z());
// 更新FeatureNode
featureNode->dirty();
}
else{
//qDebugV5()<<"_nearestVertexIndex 不合理:";
}
}
}
}
③删除顶点
// 删除选中的 FeatureNode
void FeatureEditorHandler::deleteFeatureNode(osgEarth::FeatureNode* featureNode) {
_mapNode->removeChild(featureNode);
}