osgEarth 键鼠 增删改 feature Node
为了满足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());// 更新FeatureNodefeatureNode->dirty();}else{//qDebugV5()<<"_nearestVertexIndex 不合理:";}}}
}
③删除顶点
// 删除选中的 FeatureNode
void FeatureEditorHandler::deleteFeatureNode(osgEarth::FeatureNode* featureNode) {_mapNode->removeChild(featureNode);}