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