osgEarth3.2+qt5.14+osg3.6.5
#ifndef LINEDRAWER_H
#define LINEDRAWER_H
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <osgEarth/MapNode>
#include <osgEarth/Geometry>
#include <osgEarth/GeoMath>
#include <osgEarth/Style>
#include<osgEarth/Geometry>
#include<osgEarth/Feature>
#include<osgEarth/FeatureNode>
#include <vector>
class LineDrawer:public osgGA::GUIEventHandler
{
public:
LineDrawer( osg::ref_ptr<osgEarth::MapNode> mapNode);
~LineDrawer();
//绘制线
void beginDraw(const osg::Vec3d& lla);
//动态线段
void moveDraw(const osg::Vec3d& lla);
//结束绘制
void endDraw(const osg::Vec3d& lla);
//结束结束一次绘制
void resetDraw();
//设置绘制状态
void setIsDrawLine(bool isDrawLine);
//删除选中的多边形
void removeSelectLine(osg::ref_ptr<osg::Node> node);
//删除最后创建的多边形
void removeLine();
//删除所以多边形
void removeAllLines();
//事件处理
bool handle(const osgGA::GUIEventAdapter &ea,osgGA::GUIActionAdapter &aa);
private:
osg::ref_ptr<osgEarth::MapNode> _mapNode;
bool _isDrawLine; //开启绘制圆
bool isDeletLine; //开启删除圆
osg::NodePath nodePaths;
osgEarth::Style _lineStyle; //线段样式
osg::ref_ptr<osgEarth::FeatureNode> _lineFeatureNode;
osgEarth::Style _stippleLineStyle;
osg::ref_ptr<osgEarth::FeatureNode> _stippleFeatureNode;
std::vector<osg::Vec3d> _clickedPoints; // 存储点击的点
std::vector<osg::ref_ptr<osgEarth::FeatureNode>> _lineNodes; // 保存所有绘制的矩形
};
#endif // LINEDRAWER_H
#include "LineDrawer.h"
#include<QDebug>
LineDrawer::LineDrawer( osg::ref_ptr<osgEarth::MapNode> mapNode)
:_mapNode(mapNode)
,_lineFeatureNode(nullptr)
,_stippleFeatureNode(nullptr)
,_isDrawLine(false)
{
nodePaths.push_back(_mapNode);
_clickedPoints.clear();
_lineStyle.getOrCreate<osgEarth::RenderSymbol>()->depthOffset()->enabled() = false;
_lineStyle.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = osgEarth::Color::Red;
_lineStyle.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = 2.0f;
_lineStyle.getOrCreate<osgEarth::LineSymbol>()->stroke()->smooth() = true;
_lineStyle.getOrCreate<osgEarth::LineSymbol>()->useGLLines() = true;
_lineStyle.getOrCreate<osgEarth::AltitudeSymbol>()->clamping() = osgEarth::AltitudeSymbol::CLAMP_ABSOLUTE;
_lineStyle.getOrCreate<osgEarth::AltitudeSymbol>()->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_GPU;
// ---------------------- 配置虚线(stipple)样式 ----------------------
// 创建或获取 LineSymbol,用于绘制动态虚线提示(例如鼠标移动时预览边界)
// 设置虚线颜色为红色、宽度为2、细分(tessellation)为20
osgEarth::LineSymbol* stippleLS = _stippleLineStyle.getOrCreate<osgEarth::LineSymbol>();
stippleLS->stroke()->color() = osgEarth::Color::Red;
stippleLS->stroke()->width() = 2.0;
stippleLS->tessellation() = 20.0;
stippleLS->stroke()->stipple() = 255; // 定义虚线样式
// 配置虚线使用的高程符号,确保虚线也能贴地显示并有适当的垂直偏移
osgEarth::AltitudeSymbol* stippleAlt = _stippleLineStyle.getOrCreate<osgEarth::AltitudeSymbol>();
stippleAlt->clamping() = osgEarth::AltitudeSymbol::CLAMP_ABSOLUTE;
stippleAlt->technique() =osgEarth:: AltitudeSymbol::TECHNIQUE_GPU;
stippleAlt->verticalOffset() = 0.1;
}
LineDrawer::~LineDrawer()
{
}
void LineDrawer::beginDraw(const osg::Vec3d &lla)
{
_clickedPoints.push_back(lla);
if (_clickedPoints.size() <= 1) {
return;
}
if (_lineFeatureNode == nullptr) {
osgEarth::Feature* _lineFeature = new osgEarth::Feature(new osgEarth::LineString,osgEarth::SpatialReference::get("wgs84"));
_lineFeatureNode = new osgEarth::FeatureNode(_lineFeature,_lineStyle);
_mapNode->addChild(_lineFeatureNode);
}
_lineFeatureNode->setName("Line");
osgEarth::Geometry* geom = _lineFeatureNode->getFeature()->getGeometry();
geom->clear();
for (auto& n : _clickedPoints) {
geom->push_back(n);
}
if (_stippleFeatureNode .valid()) {
_stippleFeatureNode->getFeature()->getGeometry()->clear();
}
_lineFeatureNode->dirty();
}
void LineDrawer::moveDraw(const osg::Vec3d &lla)
{
if (_clickedPoints.size() <= 0) {
return;
}
if (_stippleFeatureNode==nullptr) {
osgEarth::Feature* _stippleFeature = new osgEarth::Feature(new osgEarth::LineString,osgEarth::SpatialReference::get("wgs84"));
_stippleFeatureNode = new osgEarth::FeatureNode( _stippleFeature,_stippleLineStyle);
_mapNode->addChild(_stippleFeatureNode.get());
}
osgEarth::Geometry* geom = _stippleFeatureNode->getFeature()->getGeometry();
geom->clear();
geom->push_back(_clickedPoints[_clickedPoints.size() - 1]);
geom->push_back(lla);
_stippleFeatureNode->dirty();
}
void LineDrawer::endDraw(const osg::Vec3d &lla)
{
}
void LineDrawer::resetDraw()
{
_clickedPoints.clear();
if (_stippleFeatureNode.valid()) {
_mapNode->removeChild(_stippleFeatureNode.get());
_stippleFeatureNode = nullptr;
}
// 仅在存在有效线段时保存
if (_lineFeatureNode.valid() && _lineFeatureNode->getFeature()->getGeometry()->size() >= 2) {
_lineNodes.push_back(_lineFeatureNode);
}
_lineFeatureNode = nullptr;
}
void LineDrawer::setIsDrawLine(bool isDrawLine)
{
_isDrawLine=isDrawLine;
}
void LineDrawer::removeSelectLine(osg::ref_ptr<osg::Node> node)
{
_mapNode->removeChild(node); // 从地图中移除
}
void LineDrawer::removeLine()
{
if (!_lineNodes.empty()) {
osg::ref_ptr<osgEarth::FeatureNode> lastNode = _lineNodes.back();
_mapNode->removeChild(lastNode); // 从地图中移除
_lineNodes.pop_back(); // 从列表中移除
}
}
void LineDrawer::removeAllLines()
{
for (auto& node : _lineNodes) {
_mapNode->removeChild(node); // 从地图中移除
}
_lineNodes.clear(); // 清空列表
}
bool LineDrawer::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
{
if (!_mapNode)
return false;
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
if (!viewer)
return false;
if (!_isDrawLine)
return false;
// 使用 switch 结构更清晰地区分事件类型
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::PUSH:
{
switch (ea.getButton())
{
case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
{
osgUtil::LineSegmentIntersector::Intersections intersections;
if (viewer->computeIntersections(ea.getX(), ea.getY(), nodePaths, intersections))
{
const osgUtil::LineSegmentIntersector::Intersection& intersection = *intersections.begin();
osg::Vec3d worldPoint = intersection.getWorldIntersectPoint();
// 坐标转换:世界坐标 -> 地理坐标(WGS84)
const osgEarth::SpatialReference* mapSRS = _mapNode->getMapSRS();
const osgEarth::SpatialReference* geoSRS = osgEarth::SpatialReference::get("wgs84");
if (!geoSRS)
{
std::cerr << "[Error] geoSRS is null!" << std::endl;
return false;
}
osgEarth::GeoPoint geoPoint;
geoPoint.fromWorld(mapSRS, worldPoint);
osgEarth::GeoPoint wgs84Point;
geoPoint.transform(geoSRS, wgs84Point);
double lon = wgs84Point.x();
double lat = wgs84Point.y();
double height = wgs84Point.z();
height=46;//固定高度防止闪烁,渲染优先级不冲突
// 调用 beginDraw 添加点击点
beginDraw(osg::Vec3d(lon, lat, height));
}
break;
}
case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
{
osg::ref_ptr<osg::Node> lineNode = NULL;
osgUtil::LineSegmentIntersector::Intersections intersections;
if (viewer->computeIntersections(ea.getX(), ea.getY(), nodePaths, intersections)) {
for (const auto &intersection : intersections) {
for (auto i : intersection.nodePath) {
std::cout<<i->getName()<<endl;
if (i->getName().find("Line") != std::string::npos) {
lineNode = i;
break;
}
}
if (lineNode)
break;
}
}
// 先删除 Polygon
if (lineNode)
{
removeSelectLine(lineNode);
}
resetDraw();
break;
}
default:
break;
}
break;
}
case osgGA::GUIEventAdapter::MOVE:
{
osgUtil::LineSegmentIntersector::Intersections intersections;
if (viewer->computeIntersections(ea.getX(), ea.getY(), nodePaths, intersections))
{
const osgUtil::LineSegmentIntersector::Intersection& intersection = *intersections.begin();
osg::Vec3d worldPoint = intersection.getWorldIntersectPoint();
const osgEarth::SpatialReference* mapSRS = _mapNode->getMapSRS();
const osgEarth::SpatialReference* geoSRS = osgEarth::SpatialReference::get("wgs84");
osgEarth::GeoPoint geoPoint;
geoPoint.fromWorld(mapSRS, worldPoint);
osgEarth::GeoPoint wgs84Point;
geoPoint.transform(geoSRS, wgs84Point);
double lon = wgs84Point.x();
double lat = wgs84Point.y();
double height = wgs84Point.z();
// 调试输出,确认MOVE事件
// 鼠标移动时更新绘制状态(动态提示线)
height=46;//固定高度防止闪烁,渲染优先级不冲突
moveDraw(osg::Vec3d(lon, lat, height));
}
}
break;
case osgGA::GUIEventAdapter::KEYDOWN:
{
switch(ea.getKey())
{
case osgGA::GUIEventAdapter::KEY_Delete:
qDebug() << "Delete key pressed";
removeLine(); // 按下 Delete 键删除刚刚创建的矩形
return true;
case osgGA::GUIEventAdapter::KEY_BackSpace:
qDebug() << "BackSpace key pressed";
removeAllLines(); // 按下 BackSpace 键删除所有矩形
return true;
default:
break;
}
}
break;
default:
break;
}
return false;
}