GIS开发笔记(5)结合osg及osgEarth实现虚线环形区域绘制

一、实现效果:输入中点坐标点、内圆半径、外圆半径,绘制坐标点所在高度的水平面的两个圆形形成环形区域。

二、实现原理:

创建中心点所在平面的圆形几何体,将其分别挂接到同一个节点上,再将该节点挂接到用户绘制组节点,用户绘制组节点挂接到地球节点。

三、参考代码:

cpp 复制代码
void GlobeWidget::drawAnnularRegion(osg::Vec3d point, double innerRadius, double outerRadius)
{
    osgViewer::Viewer* viewer = m_osgWidget->getOsgViewer();
    if (!viewer) return;

    // 使用 osgEarth 转换经纬度到地球坐标
    osgEarth::GeoPoint geoPoint(osgEarth::SpatialReference::get("wgs84"),
                                point.x(), point.y(), point.z(), osgEarth::ALTMODE_ABSOLUTE);
    osg::Vec3d cartesianCenter;
    geoPoint.toWorld(cartesianCenter);  // 转换为地球坐标系

    // 计算地表法线(从地心指向圆心)
    osg::Vec3d surfaceNormal = cartesianCenter;
    surfaceNormal.normalize();

    // 找到一个与地表法线垂直的向量
    osg::Vec3d rightVector;
    if (std::abs(surfaceNormal.x()) < 0.9) {
        rightVector = osg::Vec3d(1.0, 0.0, 0.0);
    } else {
        rightVector = osg::Vec3d(0.0, 1.0, 0.0);
    }
    rightVector = rightVector - surfaceNormal * (rightVector * surfaceNormal);
    rightVector.normalize();

    // 计算另一个垂直向量
    osg::Vec3d forwardVector = surfaceNormal ^ rightVector;
    forwardVector.normalize();

    // 创建环形区域的几何体
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;

    // 创建顶点数组
    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;

    const int numSegments = 36;
    // 存储外圆顶点数量
    int outerVertexCount = 0;
    for (int i = 0; i <= numSegments; ++i) {
        double angle = 2.0 * osg::PI * static_cast<double>(i) / static_cast<double>(numSegments);

        // 计算外圆上的点
        osg::Vec3d outerOffset = rightVector * cos(angle) * outerRadius + forwardVector * sin(angle) * outerRadius;
        osg::Vec3d outerPoint = cartesianCenter + outerOffset;
        vertices->push_back(outerPoint);
        outerVertexCount++;
    }

    for (int i = numSegments; i >= 0; --i) {
        double angle = 2.0 * osg::PI * static_cast<double>(i) / static_cast<double>(numSegments);

        // 计算内圆上的点
        osg::Vec3d innerOffset = rightVector * cos(angle) * innerRadius + forwardVector * sin(angle) * innerRadius;
        osg::Vec3d innerPoint = cartesianCenter + innerOffset;
        vertices->push_back(innerPoint);
    }

    geometry->setVertexArray(vertices.get());

    // 设置颜色(透明填充,仅显示边框)
    osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
    colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 0.0f));
    geometry->setColorArray(colors.get());
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

    // 设置外圆图元为线带
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, outerVertexCount));
    // 设置内圆图元为线带
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, outerVertexCount, vertices->size() - outerVertexCount));

    // 设置虚线样式
    osg::ref_ptr<osg::LineStipple> lineStipple = new osg::LineStipple;
    lineStipple->setFactor(1);
    lineStipple->setPattern(0xAAAA);

    osg::ref_ptr<osg::StateSet> stateSet = geometry->getOrCreateStateSet();
    stateSet->setAttributeAndModes(lineStipple.get(), osg::StateAttribute::ON);
    stateSet->setMode(GL_LINE_STIPPLE, osg::StateAttribute::ON);

    geode->addDrawable(geometry.get());

    // 将 Geode 添加到根节点
    m_userDrawGroup->addChild(geode.get());

    // 强制刷新场景
    viewer->requestRedraw();
}```
相关推荐
杨先生哦几秒前
【2026热端攻防系列 11/12】前端AI风控攻防实战:验证码缺陷、人机验证绕过、智能爬虫对抗与企业智能风控加固方案
前端·人工智能·笔记·爬虫·安全
摇滚侠15 分钟前
《SpringBoot 3:入门与应用实战》第 15 章 生产级特性 使用监控体系 阅读笔记
spring boot·笔记·后端
我叫唧唧波31 分钟前
【Java】Java 基础系统学习笔记
java·笔记·学习
晓梦林9 小时前
BUUCTF findKey-学习笔记
笔记·学习
x173880627312 小时前
XXE外部实体注入
xml·笔记
库玛西16 小时前
C++ 运行时多态 :核心总结与原理图解
c语言·c++·笔记
魔力女仆17 小时前
语言开发笔记3
笔记
x173880627317 小时前
文件包含漏洞介绍
笔记
一只小菜鸡..20 小时前
南京大学 操作系统 (JYY) 学习笔记:CPU 的局限、GPU 与 AI 时代的算力革命
人工智能·笔记·学习
所愿ღ21 小时前
SSM框架-Spring3
java·开发语言·笔记·spring