osgEarth中绘制线

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;
}

参考代码链接
办流量卡,可以看看29元 235G

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值