osgEarth中绘制聚集区

osgEarth3.2+qt5.14+osg3.6.5

#ifndef GATHERINGAREADRAWER_H
#define GATHERINGAREADRAWER_H

#include <osgEarth/Feature>
#include <osgEarth/Style>
#include <osgEarth/FeatureNode>
#include<osgEarth/MapNode>
#include<osg/Vec2>
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include<QDebug>
#include"DrawerMath.h"
class GatheringAreaDrawer:public osgGA::GUIEventHandler
{
public:
    GatheringAreaDrawer(osg::ref_ptr<osgEarth::MapNode> mapNode);
    ~GatheringAreaDrawer();
    void beginDraw(const osg::Vec3d& lla);
    void moveDraw(const osg::Vec3d& lla);
    void endDraw(const osg::Vec3d& lla);
    void resetDraw();

    //删除选中的聚集区
    void removeSelectGatheringArea(osg::ref_ptr<osg::Node> node);

    //删除最后创建的聚集区
    void removeGatheringArea();

    //删除所有聚集区
    void removeAllGatheringAreas();

    //设置是否绘制聚集区
    void setIsDrawGatheringArea(bool isDrawGatheringArea);

    /**
    * Method: calculateParts
    * 重写了父类的方法
    * 用于通过控制点计算聚集地符号的所有点
    */
    std::vector<osg::Vec2> calculateParts(const std::vector<osg::Vec2>& controlPoints);
    //事件处理
    bool handle(const osgGA::GUIEventAdapter &ea,osgGA::GUIActionAdapter &aa);
private:
    osg::ref_ptr<osgEarth::MapNode> _mapNode;
    osg::NodePath   nodePaths;
    osgEarth::Style _gatheringAreaStyle;
    bool _isDrawGatheringArea;
    osg::ref_ptr<osgEarth::FeatureNode>_gatheringAreaFeatureNode;
    osg::ref_ptr<osgEarth::Feature> _gatheringAreFeature;

    std::vector<osg::Vec2> _controlPoints; // 存储点击的点
    std::vector<osg::Vec2> _drawParts;     //存储绘制点
    std::vector<osg::ref_ptr<osgEarth::FeatureNode>> _gatheringAreaNodes; // 保存所有绘制直箭头
};

#endif // GATHERINGAREADRAWER_H

#include "GatheringAreaDrawer.h"


GatheringAreaDrawer::GatheringAreaDrawer(osg::ref_ptr<osgEarth::MapNode> mapNode)
    :_mapNode(mapNode),_isDrawGatheringArea(true)
{
    nodePaths.push_back(_mapNode);
    _gatheringAreaStyle.getOrCreate<osgEarth::PolygonSymbol>()->fill()->color()= osgEarth::Color(osgEarth::Color::Yellow, 0.25);

    osgEarth::LineSymbol* ls = _gatheringAreaStyle.getOrCreate<osgEarth::LineSymbol>();
    ls->stroke()->color() = osgEarth::Color::White;
    ls->stroke()->width() = 2.0f;
    ls->stroke()->widthUnits() = osgEarth::Units::PIXELS;

    _gatheringAreaStyle.getOrCreate<osgEarth::AltitudeSymbol>()->clamping()= osgEarth::AltitudeSymbol::CLAMP_ABSOLUTE;
    _gatheringAreaStyle.getOrCreate<osgEarth::AltitudeSymbol>()->technique()=osgEarth:: AltitudeSymbol::TECHNIQUE_GPU;
    _gatheringAreaStyle.getOrCreate<osgEarth::AltitudeSymbol>()->verticalOffset()= 0.1;
}

GatheringAreaDrawer::~GatheringAreaDrawer()
{

}

void GatheringAreaDrawer::beginDraw(const osg::Vec3d &lla)
{
    _controlPoints.push_back(osg::Vec2(lla.x(), lla.y()));
    if (_controlPoints.empty() || _controlPoints.size() < 2)
        return;
    if (_controlPoints.size() == 2 && _controlPoints[0]==_controlPoints[1])
        return;

    _drawParts.clear();
    _drawParts = calculateParts(_controlPoints);

    if (!_gatheringAreaFeatureNode.valid()) {
         osgEarth::Feature* feature = new osgEarth::Feature(new osgEarth::Polygon, osgEarth::SpatialReference::get("wgs84"), _gatheringAreaStyle);
        _gatheringAreaFeatureNode = new osgEarth::FeatureNode(feature,_gatheringAreaStyle);
        _mapNode->addChild(_gatheringAreaFeatureNode);
    }
    _gatheringAreaFeatureNode->setName("GatheringArea");
    _gatheringAreaNodes.push_back(_gatheringAreaFeatureNode);
    osgEarth::Geometry* geom = _gatheringAreaFeatureNode->getFeature()->getGeometry();
    geom->clear();
    for (auto& n : _drawParts) {
        geom->push_back(osg::Vec3(n.x(), n.y(), 0));
    }
    _gatheringAreaFeatureNode->dirty();

    _controlPoints.clear();
    _gatheringAreaFeatureNode = nullptr;
}

void GatheringAreaDrawer::moveDraw(const osg::Vec3d &lla)
{
    if (_controlPoints.empty())
       return;

        if (!_gatheringAreaFeatureNode.valid()) {
            osgEarth::Feature* feature = new osgEarth::Feature(new osgEarth::Polygon, osgEarth::SpatialReference::get("wgs84"), _gatheringAreaStyle);
           _gatheringAreaFeatureNode = new osgEarth::FeatureNode(feature,_gatheringAreaStyle);
           _mapNode->addChild(_gatheringAreaFeatureNode);
        }

        if (_gatheringAreaFeatureNode.valid()) {
           std::vector<osg::Vec2> ctrlPts = _controlPoints;
           std::vector<osg::Vec2> drawPts;
           ctrlPts.push_back(osg::Vec2(lla.x(), lla.y()));

           drawPts = calculateParts(ctrlPts);

           osgEarth::Geometry* geom = _gatheringAreaFeatureNode->getFeature()->getGeometry();
           geom->clear();
           for (auto& n : drawPts) {
               geom->push_back(osg::Vec3(n.x(), n.y(), 0));
           }
           _gatheringAreaFeatureNode->dirty();
    }
}

void GatheringAreaDrawer::endDraw(const osg::Vec3d &lla)
{

}

void GatheringAreaDrawer::resetDraw()
{
    _controlPoints.clear();
    _gatheringAreaFeatureNode = nullptr;
}

void GatheringAreaDrawer::removeSelectGatheringArea(osg::ref_ptr<osg::Node> node)
{
    _mapNode->removeChild(node);
}

void GatheringAreaDrawer::removeGatheringArea()
{
    if (!_gatheringAreaNodes.empty()) {
        osg::ref_ptr<osgEarth::FeatureNode> lastNode = _gatheringAreaNodes.back();
        _mapNode->removeChild(lastNode); // 从地图中移除
        _gatheringAreaNodes.pop_back();     // 从列表中移除
    }
}

void GatheringAreaDrawer::removeAllGatheringAreas()
{
    for (auto& node : _gatheringAreaNodes) {
       _mapNode->removeChild(node); // 从地图中移除
    }
    _gatheringAreaNodes.clear(); // 清空列表
}

void GatheringAreaDrawer::setIsDrawGatheringArea(bool isDrawGatheringArea)
{
    _isDrawGatheringArea=isDrawGatheringArea;
}



bool GatheringAreaDrawer::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 (!_isDrawGatheringArea)
       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=25;//固定高度防止闪烁,渲染优先级不冲突
                       // 调用 beginDraw 添加点击点
                       beginDraw(osg::Vec3d(lon, lat, height));
                   }
                   break;
               }

               case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
               {
                   resetDraw();
                   osg::ref_ptr<osg::Node> GatheringAreaNode = 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::string nodeName = i->getName();
                               if (nodeName == "GatheringArea")
                               {
                                   GatheringAreaNode = i;  // 记录 Polygon
                               }
                           }
                       }
                   }
                   // 先删除 Polygon
                   if (GatheringAreaNode)
                   {
                       removeSelectGatheringArea(GatheringAreaNode);
                   }
                   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=25;//固定高度防止闪烁,渲染优先级不冲突
                 moveDraw(osg::Vec3d(lon, lat, height));
             }
         }
         break;
       case osgGA::GUIEventAdapter::KEYDOWN:
       {
           switch(ea.getKey())
             {
             case osgGA::GUIEventAdapter::KEY_Delete:
                 qDebug() << "Delete key pressed";
                 removeGatheringArea(); // 按下 Delete 键删除刚刚创建的矩形
                 break;
             case osgGA::GUIEventAdapter::KEY_BackSpace:
                   qDebug() << "BackSpace key pressed";
                   removeAllGatheringAreas(); // 按下 BackSpace 键删除所有矩形
                 break;
             default:
                 break;
           }
       }
       break;

       default:
         break;
       }
    return false;
}
std::vector<osg::Vec2> GatheringAreaDrawer::calculateParts(const std::vector<osg::Vec2> &controlPoints)
{
    //取第一个点作为第一控制点
       osg::Vec2 originP = controlPoints[0];
       //取最后一个作为第二控制点
       osg::Vec2 lastP = controlPoints[controlPoints.size()-1];
       std::vector<osg::Vec2> points;
       // 向量originP_lastP
       osg::Vec2 vectorOL(lastP.x()-originP.x(), lastP.y()-originP.y());
       // 向量originP_lastP的模
       float dOL = sqrtf(vectorOL.x() * vectorOL.x()+vectorOL.y() * vectorOL.y());

       //计算第一个插值控制点
       //向量originP_P1以originP为起点,与向量originP_lastP的夹角设为30,模为√3/12*dOL,
       std::vector<osg::Vec2> v_O_P1_lr = DrawMath::calculateVector(vectorOL, osg::PI/3.0, sqrtf(3.0)/12.0*dOL);
       //取左边的向量作为向量originP_P1
       osg::Vec2 originP_P1 = v_O_P1_lr[0];
       osg::Vec2 p1(originP_P1.x()+originP.x(), originP_P1.y()+originP.y());

       //计算第二个插值控制点,取第一控制点和第二控制点的中点为第二个插值控制点
       osg::Vec2 p2((originP.x()+lastP.x())/2.0, (originP.y()+lastP.y())/2.0);

       //计算第三个插值控制点
       //向量originP_P3以lastP为起点,与向量originP_lastP的夹角设为150°,模为√3/12*dOL,
       std::vector<osg::Vec2> v_L_P3_lr = DrawMath::calculateVector(vectorOL, osg::PI*2.0/3.0, sqrtf(3.0)/12.0*dOL);
       //取左边的向量作为向量originP_P1
       osg::Vec2 lastP_P3 = v_L_P3_lr[0];
       osg::Vec2 p3(lastP_P3.x()+lastP.x(), lastP_P3.y()+lastP.y());

       //计算第四个插值控制点
       //向量originP_P4以向量originP_lastP中点为起点,与向量originP_lastP的夹角设为90°,模为1/2*dOL,
       std::vector<osg::Vec2> v_O_P5_lr = DrawMath::calculateVector(vectorOL, osg::PI_2, 1.0/2.0*dOL);
       //取左边的向量作为向量originP_P1
       osg::Vec2 v_O_P5 = v_O_P5_lr[1];
       osg::Vec2 p5(v_O_P5.x()+p2.x(), v_O_P5.y()+p2.y());

       osg::Vec2 P0 = originP;
       osg::Vec2 P4 = lastP;
       points.push_back(P0);
       points.push_back(p1);
       points.push_back(p2);
       points.push_back(p3);
       points.push_back(P4);
       points.push_back(p5);

       std::vector<osg::Vec2> cardinalPoints = DrawMath::createCloseCardinal(points);
       return DrawMath::createBezier3(cardinalPoints, 100);
}

DrawMath.h
DrawMath.cpp
29 235G

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值