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();
}```
相关推荐
曾庆睿16 分钟前
计算机图形学入门笔记_GAMES101_Lecture01-02
笔记·计算机图形学
coolwest18 分钟前
某游戏辅助完整破解复盘报告(仅用于本人学习记录)
笔记
Go Work30 分钟前
npm 卡在 Step 7 七分钟,翻上去四行才看到 E404
经验分享·笔记
Hello World . .40 分钟前
【嵌入式学习笔记 Day 1】
linux·数据结构·笔记
小向是个Der40 分钟前
P02_你的变量住在哪里_教学文档
经验分享·笔记·stm32·单片机
叼烟扛炮41 分钟前
Linux 学习笔记(三十一):线程概念、底层分页机制与初体验
linux·运维·服务器·笔记·学习·1024程序员节
星恒随风42 分钟前
Linux Socket UDP编程(一):手写UDP回显服务器与客户端,从socket、bind、recvfrom到网络字典服务器完整实战
linux·服务器·网络·笔记
凉、介1 小时前
深入理解 ARMv7-M | 异常/中断处理
笔记·学习·嵌入式·arm
蒸蒸yyyyzwd1 小时前
工具、力扣、中间件学习笔记
笔记·八股
深圳老胡1 小时前
液面探测功能的硬件方案对比:原理、优缺点与选型建议
笔记·单片机