一、实现效果:输入中点坐标点、内圆半径、外圆半径,绘制坐标点所在高度的水平面的两个圆形形成环形区域。
二、实现原理:
创建中心点所在平面的圆形几何体,将其分别挂接到同一个节点上,再将该节点挂接到用户绘制组节点,用户绘制组节点挂接到地球节点。
三、参考代码:
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();
}```