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();
}```
相关推荐
岑梓铭几秒前
《考研408数据结构》第七章(B树 和 B+树)复习笔记
数据结构·笔记·b树·考研·408
Go Work5 小时前
docker 占满根分区时先分清谁在吃盘
经验分享·笔记
3095566665 小时前
股票接口返回 404 与空数组的排查笔记:证书状态与级别参数
java·笔记·python·ios·iphone·股票数据api·股票数据接口
蒸蒸yyyyzwd6 小时前
从邓明学习的后端笔记
笔记·学习
岑梓铭6 小时前
《考研408数据结构》第八章(排序)复习笔记
数据结构·笔记
Rabitebla18 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
坤坤子吖1 天前
Linux网络编程:TCP 粘包与半包问题,如何正确处理 TCP 流式数据?
linux·服务器·网络·笔记·网络协议·学习
YLCHUP1 天前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
旖旎夜光1 天前
【C++ 基础入门】C++11 新特性(中):右值引用、移动语义与完美转发
开发语言·c++·笔记·学习
星恒随风2 天前
MySQL 从零入门(五):MySQL 内置函数详解——日期、字符串、数学函数与实战案例
linux·数据库·笔记·sql·mysql