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();
}```
相关推荐
阿絮~11 分钟前
Apache RocketMQ进阶之路阅读笔记和疑问
笔记·apache·rocketmq
天水幼麟5 小时前
动手学深度学习-学习笔记(总)
笔记·深度学习·学习
天水幼麟7 小时前
动手学深度学习-学习笔记【二】(基础知识)
笔记·深度学习·学习
绿皮的猪猪侠8 小时前
算法笔记上机训练实战指南刷题
笔记·算法·pta·上机·浙大
沧海一笑-dj8 小时前
【51单片机】51单片机学习笔记-课程简介
笔记·学习·51单片机·江科大·江科大学习笔记·江科大单片机·江科大51单片机
老虎06278 小时前
JavaWeb(苍穹外卖)--学习笔记04(前端:HTML,CSS,JavaScript)
前端·javascript·css·笔记·学习·html
大苏打seven9 小时前
Docker学习笔记:Docker网络
笔记·学习·docker
kikikidult13 小时前
(2025.07)解决——ubuntu20.04系统开机黑屏,左上角光标闪烁
笔记·ubuntu
近津薪荼13 小时前
初学者关于数据在内存中的储存的笔记
笔记
碎叶城李白15 小时前
若依学习笔记1-validated
java·笔记·学习·validated