osgEarth 键鼠 增删改 feature Node

news2024/10/23 11:45:25

为了满足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);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2213025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

已解决:“发生生成错误,是否继续并运行上次的成功的生成?”无法启动程序,系统找不到指定的文件

版本&#xff1a;Visual Studio 2022用于C开发 目录 问题描述 问题原因 解决办法 问题描述 代码没有问题&#xff0c;运行后出现如下界面&#xff1a; 点击“是”后&#xff0c;又出现如下问题&#xff1a; 问题原因 源程序文件下出现两个main函数。 像我的文件目录下的另…

Allegro PCB中过孔的整体替换

Cadence Allegro PCB中过孔的整体替换 在PCB设计过程中&#xff0c;之前是使用的小的过孔&#xff0c;后面需要替换成大的过孔&#xff0c;一个一个去替换过孔非常麻烦的&#xff0c;这里&#xff0c;讲解一下如何去整体的替换过孔&#xff0c;具体的操作方法如下所示&#xf…

微软推出最新 Azure 虚拟机 ND H200 v5 系列

声明&#xff1a;本文翻译自微软全球官方博客&#xff0c;ND H200 v5 系列虚拟机目前只在 Microsoft Azure 海外版上发布。 随着人工智能领域的高速发展&#xff0c;企业对于可扩展和高性能基础设施的需求呈指数级增长。客户需要 Azure AI 基础设施来开发智能驱动的创新解决方案…

HUAWEI_HCIA_实验指南_Lib2.1_交换机基础配置

1、原理概述 交换机之间通过以太网电接口对接时需要协商一些接口参数&#xff0c;比如速率、双工模式等。交换机的全双工是指交换机在发送数据的同时也能够接收数据&#xff0c;两者同时进行。就如平时打电话一样&#xff0c;说话的同时也能够听到对方的声音。而半双工指在同一…

Linux高性能服务器编程

文章目录 Linux高性能服务器编程一、TCP/IP协议族1.TCP/IP体系结构图2.ARP协议2.1 ARP协议工作原理2.2 以太网ARP请求/应答报文格式2.3 ARP高速缓存的查看与修改 3. DNS协议3.1 DNS 查询和应答报文 二、IP协议详解1.路由表更新 三、TCP1.特点2.字节流3.TCP头部结构4.三次握手与…

双卡双待功能

双卡功能&#xff0c;指的是设备上安装和使用了两张SIM卡的功能&#xff0c;这两张SIM卡可以来自同一运营商&#xff0c;也可以来自不同的运营商。设备可以选择使用其中一张SIM卡&#xff0c;或者两张同时使用。当然&#xff0c;能否两张SIM卡同时使用&#xff0c;还取决于设备…

Python 语言学习——做题记录 2.3

这次主要练习集合这一数据类型。 P1. 洛谷B3633集合运算2 import sys n1input() a1sys.stdin.readline() a2a1.split() A{int(i) for i in a2} #print(A) n2input() b1sys.stdin.readline() b2b1.split() B{int(i) for i in b2} #print(B)print(len(A)) CA&B DA|B Uset(ra…

全球化智能组网基于多技术混合组网,适用于各行业的全球办公组网

在全球化的今天&#xff0c;企业的业务网络不仅需要覆盖更广泛的地理区域&#xff0c;同时也要能够灵活应对各种复杂的业务场景。为此&#xff0c;中国联通国际公司推出了全球化智能组网服务&#xff0c;该服务以中国联通云联网为核心&#xff0c;结合SD-WAN、多云连接&#xf…

echarts图例右侧竖向排列修改图例文字颜色

实操链接戳这里哈 left代表图例在水平放置的位置&#xff0c;有left、center、right top代表图例在垂直方向的位置&#xff0c;有top、middle、bottom width是最主要的&#xff0c;当设置的宽度比较小时&#xff0c;才会迫使图例换行&#xff0c;从而形成竖直排列的现像。 lege…

SpringBoot2核心功能-数据访问

目录 一、数据源的自动配置-HikariDataSource1、导入JDBC场景2、分析自动配置3、修改配置项4、测试 二、使用Druid数据源2.1、druid官方github地址2.2、自定义方式2.2.1、创建数据源2.2.2、StatViewServlet2.2.3、StatFilter 2.3、使用官方starter方式2.3.1、引入druid-starter…

DS线性表之队列的讲解和实现(5)

文章目录 前言一、队列的概念及结构二、队列的实现队列节点和队列初始化销毁判断是否为空入队列出队列获取队头队尾数据获取队列元素个数 三、实际使用效果总结 前言 队列实现源代码   队列是我们遇到的第二个实用数据结构&#xff0c;栈和队列地位等同 一、队列的概念及结构…

SAP学习笔记 - 豆知识13 - Msg 番号 NR751 - Object RF_BELEG R100、番号範囲間隔 49 不存在 FBN1

其实这种就是自动採番的番号没弄。 比如跨年了&#xff0c;那该新年度的番号范围没弄啊&#xff0c;就会出这种错误。 把番号范围给加一下就可以了。 1&#xff0c;现象 比如点 VL02N 出荷传票变更 画面&#xff0c;点 出库确认 就会出如下错误&#xff1a; Object RF_BEL…

双十一有哪些必买的好物清单?分享2024年双十一好用的好物排行榜

随着数字化生活的日益普及&#xff0c;每年的双十一已不仅仅是简单的购物狂欢&#xff0c;在这个充满期待的日子&#xff0c;无数家庭和个人都希望能以最实惠的价格&#xff0c;淘到那些能给日常生活带来便利与乐趣的好物。今天我们将聚焦于那些兼具实用性和创新性的产品&#…

使用飞桨AI Studio平台训练数据,并进行图像识别分析得牡丹花测试

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

zookeeper客户端

启动单机版的zookeeper 配置Maven环境 (1) IDEA自带maven (2) 更新Maven库镜像地址&#xff1a; ① 拷贝D:\Program Files\JetBrains\IntelliJ IDEA 2018.3.5\plugins\maven\lib\maven3\conf\settings.xml [IntelliJ的安装目录]到 C:/用户/username/.m2 (如果.m2文件不存在&…

JDK17下,使用SHA1算法报Certificates do not conform to algorithm constraints错误

JDK17从17.0.5开始&#xff0c;默认不再允许使用SHA1算法&#xff0c;如果引用的jar包或代码里使用了SHA1算法&#xff0c;会报以下错误。 Caused by: javax.net.ssl.SSLHandshakeException: Certificates do not conform to algorithm constraintsat java.base/sun.security.…

SQL第16课——更新和删除数据

介绍如何利用update和delete语句进一步操作表数据。 16.1 更新数据 使用update语句。两种使用方式&#xff1a; 1. 更新表中的特定行&#xff1b; 2. 更新表中的所有行。 &#xff01;&#xff01;&#xff01;&#xff08;使用update时不要省略where子句&#xff0c;因为…

vue+ant 弹窗可以拖动

通过自定义指令实现拖拽功能 在main.js里加入drag自定义指令 我自己测试时发现modal不管如何设置宽度&#xff0c;居中等&#xff0c;他的初始的left都为0&#xff0c;如果不设置好&#xff0c;容易出现点击后刚开始移动弹窗会偏移一段距离。 Vue.directive(drag, {bind(el)…

一些硬件知识【20241014】

BUCK电路中SW节点过冲怎么解决&#xff0c;什么原因产生&#xff1a; BUCK电路中电感感值过大会怎样&#xff1a; 所以buck电路中电感感值大小不是越大越好&#xff1a; 在以太网通信中&#xff0c;接口和码元是两个重要概念&#xff0c;它们涉及物理层和数据传输方式的不同方面…

黑马程序员-redis项目实践笔记1

目录 一、 基于Session实现登录 发送验证码 验证用户输入验证码 校验登录状态 Redis代替Session登录 发送验证码修改 验证用户输入验证码 登录拦截器的优化 二、 商铺查询缓存 缓存更新策略 数据库和缓存不一致解决方案 缓存更新策略的最佳实践方案 实现商铺缓…