├── README.md ├── graphicsview.cpp ├── graphicsview.h ├── image ├── label_hover_01.png ├── label_hover_02.png ├── label_hover_03.png ├── label_item.png ├── label_normal_01.png ├── label_normal_02.png ├── label_normal_03.png ├── label_press_01.png ├── label_press_02.png ├── label_press_03.png ├── label_title.png ├── placemark32.png ├── placemark64.png ├── point.png ├── point_32.png └── readme.txt ├── model.cpp ├── model.h ├── osgScutcheon.cpp ├── osgScutcheon.h ├── qCommonFunction.cpp └── qCommonFunction.h /README.md: -------------------------------------------------------------------------------- 1 | # osgScutcheon 2 | osg/osgEarth 标牌管理器 3 | 4 | 因为原来整个Model类比较大,我只把里面关于标牌的重要信息提取出来。有问题欢迎大家在下面链接的博客中给我留言评论。 5 | image里的资源素材还是使用杨石兴老师FreeEarth里的,大家根据需要可以自行修改。 6 | 7 | 使用: 8 | 9 | 1、在Model类中,将osgScutcheon标牌节点绑定到osg::MatrixTransform模型节点上, 10 | 11 | 2、然后自定义标牌的一级和二级菜单的显示内容, 12 | 13 | 3、最后添加一个osg::NodeCallback来更新标牌节点一级和二级菜单上的数据。 14 | 15 | 效果: 16 | 17 | 参考博客: 18 | https://blog.csdn.net/hph982775799/article/details/105655733 19 | 20 | 21 | ![image](https://user-images.githubusercontent.com/6800925/114290485-acddb800-9ab2-11eb-8b3d-1d7ceb0da5bc.png) 22 | 23 | -------------------------------------------------------------------------------- /graphicsview.cpp: -------------------------------------------------------------------------------- 1 | #include "graphicsview.h" 2 | 3 | GraphicsView* GraphicsView::m_pInstance = NULL; 4 | 5 | GraphicsView::GraphicsView(const QString& strFile, QWidget *parent) 6 | { 7 | //... 8 | //... 9 | 10 | m_pWindowManager = nullptr; 11 | 12 | init(); 13 | //... 14 | //... 15 | //加载.earth配置文件 16 | setEarthFile(strFile); 17 | } 18 | 19 | GraphicsView::~GraphicsView() 20 | { 21 | release(); 22 | } 23 | 24 | GraphicsView *GraphicsView::instance() 25 | { 26 | if ( NULL == m_pInstance ) 27 | { 28 | m_pInstance = new GraphicsView(QStringLiteral("../publish/data/gisdata/earthfile/earth_map/planets/earth_map.earth")); 29 | } 30 | 31 | return m_pInstance; 32 | } 33 | 34 | void GraphicsView::destroy() 35 | { 36 | if ( NULL != m_pInstance ) 37 | { 38 | delete m_pInstance; 39 | m_pInstance = NULL; 40 | } 41 | } 42 | 43 | 44 | void GraphicsView::init() 45 | { 46 | //初始化m_pViewer 47 | 48 | //... 49 | //... 50 | 51 | //初始化m_pRoot 52 | m_pRoot = new osg::Group; 53 | m_pRoot->setName("root"); 54 | 55 | 56 | //GL_DEPTH_TEST开启深度检测,也就是说,后绘制的物体覆盖先绘制的物体 57 | //m_pRoot->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); 58 | //m_pRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); 59 | 60 | } 61 | 62 | 63 | void GraphicsView::initSky() 64 | { 65 | //一般方法初始化天空 66 | m_pSkyNode = osgEarth::Util::SkyNode::create(m_pMapNode); 67 | m_pSkyNode->setName("SkyNode"); 68 | // 设置时间;默认当前时间 69 | osgEarth::DateTime dateTime(2018, 4, 26, 2);//dateTime(2018, 3, 8, 5) 70 | qDebug() << dateTime.year() << ":" << dateTime.month() << ":" << dateTime.day() << ":" << dateTime.hours(); 71 | osgEarth::Util::Ephemeris* ephemeris = new osgEarth::Util::Ephemeris; 72 | m_pSkyNode->setEphemeris(ephemeris); 73 | m_pSkyNode->setAtmosphereVisible(true); 74 | m_pSkyNode->setStarsVisible(true); 75 | m_pSkyNode->setMoonVisible(true); 76 | m_pSkyNode->setSunVisible(true); 77 | m_pSkyNode->setDateTime(dateTime); 78 | m_pSkyNode->attach(m_pViewer, 0); 79 | m_pSkyNode->setLighting(true); 80 | m_pSkyNode->addChild(m_pMapNode); 81 | m_pRoot->addChild(m_pSkyNode); 82 | 83 | //使用silverlining初始化天空 84 | //initSilverlining(); 85 | 86 | //使用triton初始化海洋模块 87 | //initTriton(); 88 | 89 | 90 | } 91 | 92 | void GraphicsView::initWindowManager() 93 | { 94 | if(m_pWindowManager == nullptr) 95 | { 96 | 97 | m_pWindowManager = new osgWidget::WindowManager(m_pViewer, 50.f, 50.f, 1, /*0xF0000000*/ 98 | osgWidget::WindowManager::WM_USE_RENDERBINS); 99 | osg::Camera* camera = m_pWindowManager->createParentOrthoCamera(); 100 | m_pRoot->addChild(camera); 101 | m_pViewer->addEventHandler(new osgWidget::MouseHandler(m_pWindowManager));//响应鼠标事件 102 | m_pViewer->addEventHandler(new osgWidget::KeyboardHandler(m_pWindowManager));//响应键盘事件 103 | m_pViewer->addEventHandler(new osgWidget::ResizeHandler(m_pWindowManager,camera));//防止WindowManager随着窗口改变而改变 104 | m_pViewer->addEventHandler(new osgWidget::CameraSwitchHandler(m_pWindowManager,camera)); 105 | 106 | } 107 | 108 | } 109 | 110 | //加载.earth配置文件 111 | void GraphicsView::setEarthFile(const QString& str) 112 | { 113 | 114 | if (!str.isEmpty()) 115 | { 116 | // 初始化地球数据; 117 | osg::ref_ptr node = osgDB::readNodeFile(str.toLocal8Bit().data()); 118 | if (node) 119 | { 120 | m_pMapNode = osgEarth::MapNode::findMapNode(node); 121 | m_pMapNode->setName("MapNode"); 122 | m_pMapSRS = m_pMapNode->getMapSRS(); 123 | 124 | m_pViewer = new osgViewer::Viewer; 125 | m_pEarthManipulator = new osgEarth::Util::EarthManipulator; 126 | //m_pEarthWalkManipulator = new EarthWalkManipulator(); 127 | m_pEarthManipulator->getSettings()->setMinMaxPitch(-360.0, 360.0); 128 | m_pEarthManipulator->getSettings()->setArcViewpointTransitions(true); 129 | m_pEarthManipulator->getSettings()->bindMouseDoubleClick(osgEarth::Util::EarthManipulator::ACTION_GOTO, 130 | osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ); 131 | m_pEarthManipulator->setNode(m_pMapNode); 132 | m_pViewer->setCameraManipulator(m_pEarthManipulator); 133 | 134 | m_pViewer->addEventHandler(new osgViewer::StatsHandler); 135 | m_pViewer->addEventHandler(new osgViewer::WindowSizeHandler()); 136 | m_pViewer->addEventHandler(new osgViewer::ThreadingHandler()); 137 | m_pViewer->addEventHandler(new osgViewer::LODScaleHandler());//运行用户即时调整场景细节层次(LOD)缩放比例。按*键场景中所有模型距离视点更近才显示,按/键模型再更大范围内被渲染显示 138 | m_pViewer->addEventHandler(new osgViewer::RecordCameraPathHandler);//记录相机运行路径,先按小z开始记录 再次按下z停止记录,最后按Z开始回放 139 | m_pViewer->addEventHandler(new osgGA::StateSetManipulator(m_pViewer->getCamera()->getOrCreateStateSet()));//按l键整个地球变亮,再按l又变回原来亮度 140 | //设置裁剪,避免屏幕下方出现黑边 141 | m_pViewer->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(m_pMapNode)); 142 | m_pViewer->getCamera()->setNearFarRatio(0.0000003); 143 | m_pViewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); 144 | m_pViewer->setUpViewerAsEmbeddedInWindow(0, 0, width(), height()); 145 | //优化场景数据 146 | osgUtil::Optimizer optimizer; 147 | optimizer.optimize(m_pRoot.get()); 148 | m_pViewer->setSceneData(m_pRoot.get()); 149 | m_pGraphicsWindow = dynamic_cast(m_pViewer->getCamera()->getGraphicsContext()); 150 | m_pViewer->getCamera()->setSmallFeatureCullingPixelSize(-1.0f); 151 | //视点跟随 152 | m_pEarthManipulator->setViewpoint(osgEarth::Util::Viewpoint("China", 112.971, 31.85, 444.02, -15.0, -60.0, 9000000), 5.0); 153 | 154 | //初始化天空 155 | initSky(); 156 | //初始化标牌WindowManager 157 | initWindowManager(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /graphicsview.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHICSVIEW_H 2 | #define GRAPHICSVIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | 12 | class GraphicsView 13 | { 14 | Q_OBJECT 15 | 16 | protected: 17 | GraphicsView(const QString& strFile, QWidget* parent = 0); 18 | ~GraphicsView(); 19 | 20 | public: 21 | static GraphicsView *instance(); 22 | 23 | //... 24 | //... 25 | private: 26 | void init(); 27 | void initSky(); 28 | void initWindowManager(); 29 | 30 | 31 | private: 32 | osg::ref_ptr m_pRoot; 33 | osg::ref_ptr m_pViewer; 34 | //.... 35 | //.... 36 | //.... 37 | //标牌windowManger 38 | osg::ref_ptr m_pWindowManager; 39 | 40 | 41 | private: 42 | static GraphicsView* m_pInstance; 43 | 44 | }; 45 | 46 | //GraphicsView g_pMap3D; 47 | 48 | #endif // GRAPHICSVIEW_H 49 | -------------------------------------------------------------------------------- /image/label_hover_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_hover_01.png -------------------------------------------------------------------------------- /image/label_hover_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_hover_02.png -------------------------------------------------------------------------------- /image/label_hover_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_hover_03.png -------------------------------------------------------------------------------- /image/label_item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_item.png -------------------------------------------------------------------------------- /image/label_normal_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_normal_01.png -------------------------------------------------------------------------------- /image/label_normal_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_normal_02.png -------------------------------------------------------------------------------- /image/label_normal_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_normal_03.png -------------------------------------------------------------------------------- /image/label_press_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_press_01.png -------------------------------------------------------------------------------- /image/label_press_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_press_02.png -------------------------------------------------------------------------------- /image/label_press_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_press_03.png -------------------------------------------------------------------------------- /image/label_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/label_title.png -------------------------------------------------------------------------------- /image/placemark32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/placemark32.png -------------------------------------------------------------------------------- /image/placemark64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/placemark64.png -------------------------------------------------------------------------------- /image/point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/point.png -------------------------------------------------------------------------------- /image/point_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huhui/osgScutcheon/99fe4de63326ed57f80411289763eb4449778122/image/point_32.png -------------------------------------------------------------------------------- /image/readme.txt: -------------------------------------------------------------------------------- 1 | 使用到的图片资源 2 | -------------------------------------------------------------------------------- /model.cpp: -------------------------------------------------------------------------------- 1 | #include "model.h" 2 | 3 | NCSEModel::Model::Model(QObject *parent) : QObject(parent), 4 | m_pMap3D(GraphicsView::instance()) 5 | { 6 | m_pRootModel = new osg::Group; 7 | m_pRootModel->setName("RootModel"); 8 | m_pMap3D->getRoot()->addChild(m_pRootModel); 9 | 10 | this->m_pModelNode = nullptr; 11 | 12 | this->m_pModelScutcheonCallback = nullptr; 13 | this->m_pScutcheon = nullptr; 14 | this->m_pScutcheonManager = nullptr; 15 | 16 | } 17 | 18 | 19 | NCSEModel::Model::~Model() 20 | { 21 | 22 | } 23 | 24 | 25 | void NCSEModel::Model::addModelNode(QString modelPath, QString modelName) 26 | { 27 | 28 | //模型初始指向必须为正北方向,不是正北方向的必须通过旋转Z轴(航向角)调整为正北 29 | m_pNode = osgDB::readNodeFile(modelPath.toLocal8Bit().data()); 30 | if (!m_pNode) 31 | { 32 | qDebug() << "Error:addModel failure! Please check model path:" << modelPath; 33 | return; 34 | } 35 | //开启法线跟随缩放,避免模型缩放后变黑 36 | m_pNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON); 37 | m_pNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED); 38 | 39 | m_pModelNode = new osg::MatrixTransform; 40 | m_pModelNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON); 41 | m_pModelNode->addChild(m_pNode); 42 | m_pModelNode->setName(modelName.toStdString()); 43 | m_pRootModel->addChild(m_pModelNode.get()); 44 | 45 | //创建标牌 46 | createScutcheon(); 47 | 48 | } 49 | 50 | void NCSEModel::Model::createScutcheon() 51 | { 52 | if(!m_pModelNode) 53 | return; 54 | if(m_pScutcheon == nullptr) 55 | { 56 | qDebug() << "m_pScutcheon"; 57 | //标牌管理器,全局唯一,一个标牌管理器包含多个标牌 58 | m_pScutcheonManager = osgScutcheonManager::instance(); 59 | //标牌,每个标牌包含多个一级菜单 60 | QString scutTitleText = QString::fromStdString(m_pModelNode->getName()); 61 | m_pScutcheon = new osgScutcheon(scutTitleText, m_pModelNode); 62 | m_pScutcheonManager->addLabel(m_pScutcheon.get()); 63 | 64 | //一级标牌菜单,每个一级菜单包含多个二级菜单 65 | osg::ref_ptr labelItemMenu1 = new osgScutcheonMenu(QStringLiteral("基础信息"), m_pScutcheon); 66 | QString labelText = QStringLiteral("类型:") + QString::fromStdString(m_pModelTypeNode->getName()); 67 | QString speed = QStringLiteral("速度:1550km/h"); 68 | QString dis = QStringLiteral("射程:5000km"); 69 | labelItemMenu1->addChildMenu(labelText);//二级标牌菜单 70 | labelItemMenu1->addChildMenu(speed);//二级标牌菜单 71 | labelItemMenu1->addChildMenu(dis);//二级标牌菜单 72 | 73 | 74 | QString lon = QStringLiteral("经度:") + QString::number(0.000000, 'f', 6); 75 | QString lan = QStringLiteral("纬度:") + QString::number(0.000000, 'f', 6); 76 | QString alt = QStringLiteral("高度:") + QString::number(0.000000, 'f', 6); 77 | QString heading = QStringLiteral("航向:") + QString::number(0.000000, 'f', 6); 78 | QString pitch = QStringLiteral("俯仰:") + QString::number(0.000000, 'f', 6); 79 | QString roll = QStringLiteral("滚转:") + QString::number(0.000000, 'f', 6); 80 | osg::ref_ptr labelItemMenu2 = new osgScutcheonMenu(QStringLiteral("位置信息"), m_pScutcheon); 81 | labelItemMenu2->addChildMenu(lon); 82 | labelItemMenu2->addChildMenu(lan); 83 | labelItemMenu2->addChildMenu(alt); 84 | labelItemMenu2->addChildMenu(heading); 85 | labelItemMenu2->addChildMenu(pitch); 86 | labelItemMenu2->addChildMenu(roll); 87 | 88 | m_pScutcheon->addLabelItem(*labelItemMenu1);//表示第0个标牌菜单 89 | m_pScutcheon->addLabelItem(*labelItemMenu2);//表示第1个标牌菜单 90 | } 91 | 92 | //添加标牌更新回调事件 93 | addModelScutcheonCallback(); 94 | 95 | } 96 | 97 | void NCSEModel::Model::hideScutcheon() 98 | { 99 | if(!m_pScutcheon) 100 | return; 101 | m_pScutcheon->setVisibility(false); 102 | } 103 | 104 | void NCSEModel::Model::showScutcheon() 105 | { 106 | if(!m_pScutcheon) 107 | return; 108 | m_pScutcheon->setVisibility(true); 109 | } 110 | 111 | void NCSEModel::Model::addModelScutcheonCallback() 112 | { 113 | 114 | if(!m_pScutcheon) 115 | return; 116 | if(!m_pModelScutcheonCallback) 117 | { 118 | qDebug() << "m_pModelScutcheonCallback"; 119 | m_pModelScutcheonCallback = new NCSEModel::ModelScutcheonCallback(1);//1表示第1个标牌菜单需要更新文字 120 | m_pScutcheon->setUpdateCallback(m_pModelScutcheonCallback); 121 | } 122 | } 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /model.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief 所有模型的基类 3 | * @author hph 4 | * @date 2018/05/08 5 | */ 6 | #ifndef MODEL_H 7 | #define MODEL_H 8 | #include 9 | #include 10 | #include 11 | #include "Model/osgScutcheon.h" 12 | #include 13 | 14 | namespace NCSEModel { 15 | 16 | 17 | class ModelScutcheonCallback; 18 | class Model : public QObject, public osg::Referenced 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit Model(QObject *parent = nullptr); 23 | ~Model(); 24 | 25 | 26 | /** 27 | * @brief addModel 添加模型 28 | * @param modelPath 模型文件所在路径 29 | * @param modelName 模型名称 30 | */ 31 | void addModelNode(QString modelPath, QString modelName); 32 | 33 | 34 | /** 35 | *创建标牌 36 | * @brief createScutcheon 37 | */ 38 | void createScutcheon(); 39 | 40 | /** 41 | *隐藏标牌 42 | * @brief hideScutcheon 43 | */ 44 | void hideScutcheon(); 45 | /** 46 | *显示标牌 47 | * @brief showScutcheon 48 | */ 49 | void showScutcheon(); 50 | /** 51 | *添加模型标牌的回调事件更新标牌 52 | * @brief addModelScaleCallback 53 | */ 54 | void addModelScutcheonCallback(); 55 | 56 | 57 | 58 | private: 59 | 60 | //一个完整的模型Model包含一个模型根节点; 61 | //模型根节点:包含一个模型类型节点; 62 | //模型类型节点:包含模型节点、模型轨迹线节点等; 63 | //模型节点:如果模型不需要缩放旋转等操作,则模型节点下包含原始模型节点; 64 | //—————————如果需要缩放等操作,则按照按照先Scale/Rotate/Translate顺序,模型节点下包含平移节点, 65 | //—————————平移节点下包含旋转节点,旋转节点下包含缩放节点,缩放节点下才包含原始模型节点; 66 | //标牌节点:标牌节点与对应的模型节点绑定,表示是具体某个模型节点的标牌。一个标牌节点包含多个一级标牌菜单,每个一级菜单又可以包含多个二级菜单 67 | //标牌管理器节点:标牌管理器节点统一管理所有标牌,标牌管理器全局唯一 68 | GraphicsView* m_pMap3D; 69 | ModelConfig m_modelConfig; 70 | int m_modelID; 71 | osg::ref_ptr m_pNode;//原始模型节点 72 | osg::ref_ptr m_pRootModel;//模型根节点 73 | 74 | osg::ref_ptr m_pModelNode;//模型节点 75 | 76 | osg::ref_ptr m_pScutcheonManager;//标牌管理器,一个标牌管理器包含多个标牌 77 | osg::ref_ptr m_pScutcheon;//模型标牌节点 78 | 79 | }; 80 | 81 | /** 82 | *添加模型标牌的回调事件更新标牌 83 | */ 84 | class ModelScutcheonCallback : public osg::NodeCallback 85 | { 86 | public: 87 | ModelScutcheonCallback(int menuIndex): 88 | m_menuIndex(menuIndex) 89 | { 90 | m_pNewScutcheonMenu = nullptr; 91 | m_pScutcheon = nullptr; 92 | } 93 | virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) 94 | { 95 | m_pScutcheon = dynamic_cast(node); 96 | if(m_pScutcheon->getVisibility()) 97 | { 98 | m_pScutcheon->setVisibility(true); 99 | m_pNewScutcheonMenu = m_pScutcheon->getLabelItemManager().at(m_menuIndex);//找到更新的一级标牌菜单 100 | updateScutcheonText(); 101 | } 102 | else 103 | { 104 | m_pScutcheon->setVisibility(false); 105 | } 106 | 107 | traverse(node, nv); 108 | } 109 | 110 | void updateScutcheonText() 111 | { 112 | if(!m_pScutcheon || !m_pNewScutcheonMenu) 113 | return; 114 | m_pModelNode = m_pScutcheon->getTargetObject(); 115 | osg::Vec3d currentPos = getModelPosition(m_pModelNode); 116 | 117 | osg::Vec3d scale = osg::Vec3d(); 118 | osg::Quat so; 119 | osg::Vec3d translate = osg::Vec3d(); 120 | //经过缩放后的模型最好使用decompose矩阵分解,不然getRotate所得旋转量可能不正确 121 | osg::Quat rotation; 122 | m_pModelNode->getMatrix().decompose(translate, rotation, scale, so); 123 | // osg::Quat rotation = m_pModelNode->getMatrix().getRotate(); 124 | //新方法 125 | Quaternion q(rotation.x(), rotation.y(), rotation.z(), rotation.w()); 126 | q.normalize(); 127 | double res[3]; 128 | q.quaternion2Euler(q, res, Quaternion::zyx); 129 | double pitchAngle = res[0]; 130 | double headingAngle = res[1]; 131 | double rollAngle = res[2]; 132 | //老方法 133 | // double headingAngle = 0.0; 134 | // double pitchAngle = 0.0; 135 | // double rollAngle = 0.0; 136 | // QuatToHPR(rotation, headingAngle, pitchAngle, rollAngle); 137 | 138 | QString lon = QStringLiteral("经度:") + QString::number(currentPos.x(), 'f', 6); 139 | QString lan = QStringLiteral("纬度:") + QString::number(currentPos.y(), 'f', 6); 140 | QString alt = QStringLiteral("高度:") + QString::number(currentPos.z(), 'f', 6); 141 | QString heading = QStringLiteral("航向:") + QString::number(osg::RadiansToDegrees(headingAngle), 'f', 6); 142 | QString pitch = QStringLiteral("俯仰:") + QString::number(osg::RadiansToDegrees(pitchAngle), 'f', 6); 143 | QString roll = QStringLiteral("滚转:") + QString::number(osg::RadiansToDegrees(rollAngle), 'f', 6); 144 | 145 | int menuItemIndex = 0; 146 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, lon);//更新二级菜单 147 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, lan); 148 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, alt); 149 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, heading); 150 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, pitch); 151 | m_pNewScutcheonMenu->updateChildMenuText(menuItemIndex++, roll); 152 | 153 | } 154 | 155 | osg::Vec3d getModelPosition(osg::ref_ptr m_pModelNode) 156 | { 157 | osg::Vec3d posXYZ = osg::Vec3d(); 158 | osg::Vec3d currentPosition = osg::Vec3d(); 159 | if (m_pModelNode) 160 | { 161 | osg::Matrix mat = m_pModelNode->getMatrix(); 162 | posXYZ = posXYZ * mat; 163 | // posXYZ = m_pModelNode->getMatrix().getTrans(); 164 | } 165 | 166 | GraphicsView::instance()->getSRS()->getGeodeticSRS()->getEllipsoid()->convertXYZToLatLongHeight(posXYZ.x(), posXYZ.y(), posXYZ.z(), 167 | currentPosition.y(), currentPosition.x(), 168 | currentPosition.z()); 169 | 170 | currentPosition.x() = osg::RadiansToDegrees(currentPosition.x()); 171 | currentPosition.y() = osg::RadiansToDegrees(currentPosition.y()); 172 | return currentPosition; 173 | } 174 | //ZXY 175 | void QuatToHPR(osg::Quat q, double& heading, double& pitch, double& roll) 176 | { 177 | double test = q.y() * q.z() + q.x() * q.w(); 178 | 179 | if (test > 0.4999) 180 | { // singularity at north pole 181 | heading = 2.0 * atan2(q.y(), q.w()); 182 | pitch = osg::PI_2; 183 | roll = 0.0; 184 | return; 185 | } 186 | if (test < -0.4999) 187 | { // singularity at south pole 188 | heading = 2.0 * atan2(q.y(), q.w()); 189 | pitch = -osg::PI_2; 190 | roll = 0.0; 191 | return; 192 | } 193 | double sqx = q.x() * q.x(); 194 | double sqy = q.y() * q.y(); 195 | double sqz = q.z() * q.z(); 196 | heading = atan2(2.0 * q.z() * q.w() - 2.0 * q.y() * q.x(), 1.0 - 2.0 * sqz - 2.0 * sqx); 197 | pitch = asin(2.0 * test); 198 | roll = atan2(2.0 * q.y() * q.w() - 2.0 * q.z() * q.x(), 1.0 - 2.0 * sqy - 2.0 * sqx); 199 | } 200 | 201 | public: 202 | int m_menuIndex;//标牌一级菜单标识,判断是哪个菜单需要更新 203 | osg::ref_ptr m_pScutcheon;//需要增加信息的标牌 204 | osg::ref_ptr m_pNewScutcheonMenu;//要更新的标牌菜单 205 | osg::ref_ptr m_pModelNode;//标牌绑定的模型节点 206 | }; 207 | 208 | 209 | 210 | } 211 | #endif // MODEL_H 212 | -------------------------------------------------------------------------------- /osgScutcheon.cpp: -------------------------------------------------------------------------------- 1 | #include "osgScutcheon.h" 2 | 3 | 4 | osgScutcheon::osgScutcheon() 5 | { 6 | 7 | } 8 | 9 | osgScutcheon::osgScutcheon(const QString& titleText, osg::ref_ptr targetObj): 10 | osgWidget::Box("osgScutcheon", osgWidget::Box::VERTICAL), 11 | mTargetObj(targetObj), 12 | mIndex(0), 13 | mIsVisible(true), 14 | mIsItemVisible(true), 15 | mIsMouseDrag(false), 16 | mIsMousePush(false) 17 | { 18 | 19 | getBackground()->setColor(1.0, 1.0, 1.0, 0.5); 20 | setEventMask(osgWidget::EVENT_ALL); 21 | attachMoveCallback(); 22 | 23 | mTitleText = titleText; 24 | addLabelTitle(titleText); 25 | 26 | } 27 | 28 | osgScutcheon::~osgScutcheon() 29 | { 30 | 31 | } 32 | 33 | void osgScutcheon::addLabelTitle(const QString &titleText) 34 | { 35 | 36 | osg::ref_ptr labelTitle = new osgWidget::Label("labelTitle"); 37 | labelTitle->setFont(FONT_TEXT); 38 | labelTitle->setFontSize(14); 39 | labelTitle->setFontColor(1.0f, 1.0f, 0.0f, 1.0f); 40 | labelTitle->setColor(1.0f, 1.0f, 1.0f, 0.3f); 41 | labelTitle->addSize(128.0f, 32.0f); 42 | //labelTitle->setEventMask(osgWidget::EVENT_MOUSE_DRAG);//设置完无法拖动 43 | //labelTitle->addCallback(new osgWidget::Callback(&osgScutcheon::callbackMousePush, this, osgWidget::EVENT_MOUSE_DRAG)); 44 | 45 | //labelTitle->setShadow(0.08f); 46 | labelTitle->setCanFill(true); 47 | labelTitle->setImage(TITLE_IMAGE); 48 | labelTitle->setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT); 49 | labelTitle->setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT); 50 | labelTitle->setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT); 51 | labelTitle->setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT); 52 | CommonFunction com; 53 | osgText::String labelString = com.qstringToOsgTextString(titleText); 54 | labelTitle->setLabel(labelString); 55 | addWidget(labelTitle);//谁先add谁在标牌最下面 56 | } 57 | 58 | 59 | void osgScutcheon::addLabelItem(const QString &labelText) 60 | { 61 | ++mIndex; 62 | osgScutcheonMenu* labelItem = new osgScutcheonMenu(labelText, this); 63 | labelItem->setIndex(mIndex); 64 | mLabelItemManager.push_back(labelItem); 65 | addWidget(labelItem);//谁先add谁在标牌最下面 66 | } 67 | 68 | void osgScutcheon::addLabelItem(osgScutcheonMenu &labelItem) 69 | { 70 | ++mIndex; 71 | labelItem.setIndex(mIndex); 72 | mLabelItemManager.push_back(&labelItem); 73 | if(mIsItemVisible) 74 | { 75 | addWidget(&labelItem);//谁先add谁在标牌最下面 76 | } 77 | 78 | } 79 | 80 | void osgScutcheon::moveLabelItem() 81 | { 82 | int x = this->getX(); 83 | int y = this->getY(); 84 | 85 | for(int i = 0; i < mLabelItemManager.size(); ++i) 86 | { 87 | osgScutcheonMenu *labelItem = mLabelItemManager.at(i); 88 | labelItem->moveTo(x, y); 89 | } 90 | } 91 | 92 | bool osgScutcheon::callbackMouseDrag(osgWidget::Event &ev) 93 | { 94 | 95 | return true; 96 | } 97 | 98 | bool osgScutcheon::mouseDrag(double, double, const osgWidget::WindowManager *) 99 | { 100 | qDebug() << "osgScutcheon mouseDrag called" ; 101 | mIsMouseDrag = true; 102 | return true; 103 | } 104 | 105 | bool osgScutcheon::mousePush(double, double, const osgWidget::WindowManager *) 106 | { 107 | mIsMousePush = true; 108 | qDebug() << "osgScutcheon mousePush called" << mIsMousePush << ":" << mTitleText; 109 | return true; 110 | } 111 | 112 | bool osgScutcheon::mouseRelease(double, double, const osgWidget::WindowManager *) 113 | { 114 | qDebug() << "osgScutcheon mouseRelease called" << mIsMouseDrag << ":" << mTitleText; 115 | 116 | if(!mIsMouseDrag) 117 | { 118 | if(mIsMousePush && mIsItemVisible) 119 | { 120 | std::vector >::const_iterator it; 121 | for(it = mLabelItemManager.begin(); it != mLabelItemManager.end(); ++it) 122 | { 123 | (*it)->getChildMenu()->hide(); 124 | this->removeWidget((*it)); 125 | qDebug() << "item removed!" << (*it)->getIndex(); 126 | } 127 | } 128 | else 129 | { 130 | if(this->getNumChildren() <= mLabelItemManager.size()) 131 | { 132 | std::vector >::const_iterator it; 133 | for(it = mLabelItemManager.begin(); it != mLabelItemManager.end(); ++it) 134 | { 135 | this->addWidget((*it)); 136 | qDebug() << "item added!" << (*it)->getIndex(); 137 | } 138 | } 139 | } 140 | mIsItemVisible = !mIsItemVisible; 141 | } 142 | mIsMousePush = false; 143 | mIsMouseDrag = false; 144 | 145 | return true; 146 | } 147 | 148 | std::vector > osgScutcheon::getLabelItemManager() const 149 | { 150 | return mLabelItemManager; 151 | } 152 | 153 | 154 | void osgScutcheon::onMouseEvent(const osgGA::GUIEventAdapter &ea, osgViewer::Viewer *viewer) 155 | { 156 | int etype = ea.getEventType(); 157 | if(etype == ea.FRAME) 158 | { 159 | if (mTargetObj) 160 | { 161 | osg::Vec3 position = mTargetObj->getMatrix().getTrans() + osg::Vec3d(0, 0, 0); 162 | osgViewer::Renderer* renderer = dynamic_cast(viewer->getCamera()->getRenderer()); 163 | osg::Vec3 renderPos; 164 | renderer->getSceneView(0)->projectObjectIntoWindow(position, renderPos); 165 | 166 | float x = this->getX();//renderpos.x 167 | float y = this->getY(); 168 | float w = this->getWidth();//rendersize.x 169 | float h = this->getHeight(); 170 | 171 | float offset = 0.0; 172 | osg::Vec3 stPt(x + 0.5 * w, y + 0.5 * h, 0); 173 | if (stPt.y()- renderPos.y()>0.5*h) 174 | { 175 | stPt[1] = stPt.y()-0.5*h+offset; 176 | } 177 | else if (stPt.y()- renderPos.y()<-0.5*h) 178 | { 179 | stPt[1] = stPt.y()+0.5*h+offset; 180 | } 181 | if (stPt.x()- renderPos.x()>0.5*w) 182 | { 183 | stPt[0] = stPt.x()-0.5*w-offset; 184 | } 185 | else if (stPt.x()- renderPos.x()<-0.5*w) 186 | { 187 | stPt[0] = stPt.x()+0.5*w-offset; 188 | } 189 | setPos(renderPos + osg::Vec3d(50, 50, 50));//设置标牌初始位置距离目标的偏移为50 190 | createLine(stPt, renderPos); 191 | 192 | } 193 | } 194 | if ((etype == ea.PUSH) && ea.getButtonMask() == ea.LEFT_MOUSE_BUTTON) 195 | { 196 | if (mIsMousePush) 197 | { 198 | //qDebug() << "mousePush called" ; 199 | m_LBDownPt.set(ea.getX(), ea.getY(), 0); 200 | m_LastPt = m_LBDownPt; 201 | } 202 | } 203 | if ((etype == ea.DRAG)) 204 | { 205 | //qDebug() << "mouseDrag called" ; 206 | if (mIsMouseDrag) 207 | { 208 | osg::Vec3 pt(ea.getX() - m_LastPt[0], ea.getY() - m_LastPt[1], 0); 209 | setOffset(m_offset + pt); 210 | m_LastPt.set(ea.getX(), ea.getY(), 0); 211 | ea.setHandled(true); 212 | } 213 | } 214 | if ((etype == ea.RELEASE)) 215 | { 216 | //qDebug() << "mouseDrag release" ; 217 | } 218 | } 219 | 220 | void osgScutcheon::setPos(osg::Vec3 pos) 221 | { 222 | m_pos = pos; 223 | pos = m_pos + m_offset; 224 | this->setOrigin(pos.x(), pos.y()); 225 | this->update(); 226 | moveLabelItem(); 227 | } 228 | 229 | void osgScutcheon::setOffset(osg::Vec3 offset) 230 | { 231 | m_offset = offset; 232 | offset = m_pos+m_offset; 233 | this->setOrigin(offset.x(), offset.y()); 234 | this->update(); 235 | moveLabelItem(); 236 | } 237 | 238 | osg::ref_ptr osgScutcheon::getTargetObject() 239 | { 240 | return mTargetObj; 241 | } 242 | int osgScutcheon::getItemCount() 243 | { 244 | return mLabelItemManager.size(); 245 | } 246 | 247 | void osgScutcheon::setVisibility(bool b) 248 | { 249 | mIsVisible = b; 250 | if(mIsVisible) 251 | { 252 | this->show(); 253 | m_line->setNodeMask(1); 254 | } 255 | else 256 | { 257 | this->hide(); 258 | m_line->setNodeMask(0); 259 | for(int i= 0; i < mLabelItemManager.size(); i++) 260 | { 261 | mLabelItemManager.at(i)->getChildMenu()->hide(); 262 | } 263 | } 264 | 265 | } 266 | 267 | void osgScutcheon::createLine(const osg::Vec3 &startPt, const osg::Vec3 &endPt) 268 | { 269 | if (NULL == m_line) 270 | { //创建标牌和模型之间的连接线 271 | m_line = new osg::Geometry; 272 | osg::Vec3Array* vertices = new osg::Vec3Array; 273 | vertices->push_back(startPt); 274 | vertices->push_back(endPt); 275 | m_line->setVertexArray(vertices); 276 | 277 | osg::Vec3Array* normals = new osg::Vec3Array; 278 | normals->push_back(osg::Vec3(0.0f,0.0f,1.0f)); 279 | m_line->setNormalArray(normals); 280 | m_line->setNormalBinding(osg::Geometry::BIND_OVERALL); 281 | 282 | osg::Vec4Array* colors = new osg::Vec4Array; 283 | 284 | colors->push_back(osg::Vec4(1.0, 1.0, 0.0, 1.0)); 285 | m_line->setColorArray(colors); 286 | m_line->setColorBinding(osg::Geometry::BIND_OVERALL); 287 | 288 | m_line->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,2)); 289 | m_line->getOrCreateStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); 290 | m_line->getOrCreateStateSet()->setAttributeAndModes(new osg::LineWidth(1.0f),osg::StateAttribute::ON); 291 | m_line->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); 292 | osg::Geode* geode = new osg::Geode(); 293 | geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF); 294 | geode->addDrawable(m_line); 295 | //this->addChild(geode); 296 | this->getWindowManager()->addChild(geode); 297 | } 298 | else 299 | { //动态更新线长 300 | osg::Vec3Array* vertices = dynamic_cast(m_line->getVertexArray()); 301 | (*vertices)[0].set( startPt.x(), startPt.y(), 0.0 ); 302 | (*vertices)[1].set( endPt.x(), endPt.y(), 0.0 ); 303 | vertices->dirty(); 304 | m_line->setVertexArray(vertices); 305 | m_line->dirtyDisplayList(); 306 | } 307 | } 308 | 309 | 310 | 311 | /////////////////////////////////////////////////////////////// 312 | /// \brief osgScutcheonManager::osgScutcheonManager 313 | /// 标牌管理器 314 | /// /////////////////////////////////////////////////////////// 315 | osgScutcheonManager* osgScutcheonManager::m_pInstance = NULL; 316 | osgScutcheonManager::osgScutcheonManager(osgViewer::Viewer* pViewer, osg::Group* pScreneRoot) 317 | { 318 | m_bVisible = true; 319 | 320 | 321 | //0xF0000000表示标牌显示 0x00000000表示标牌隐藏 WM_PICK_DEBUG显示调试信息 322 | mWindowManager = new osgWidget::WindowManager(pViewer, 50.0f, 50.0f, 1, /*0xF0000000*/ 323 | osgWidget::WindowManager::WM_PICK_DEBUG); 324 | osg::Camera* camera = mWindowManager->createParentOrthoCamera(); 325 | pScreneRoot->addChild(camera); 326 | 327 | pViewer->addEventHandler(new osgWidget::MouseHandler(mWindowManager)); 328 | pViewer->addEventHandler(new osgWidget::KeyboardHandler(mWindowManager)); 329 | pViewer->addEventHandler(new osgWidget::ResizeHandler(mWindowManager, camera)); 330 | pViewer->addEventHandler(new osgWidget::CameraSwitchHandler(mWindowManager, camera)); 331 | 332 | } 333 | 334 | osgScutcheonManager::~osgScutcheonManager() 335 | { 336 | m_bGUIStoped = true; 337 | clear(); 338 | } 339 | 340 | osgScutcheonManager *osgScutcheonManager::instance() 341 | { 342 | if ( NULL == m_pInstance ) 343 | { 344 | //osgViewer::Viewer* getOSGViewer(){ return m_pViewer; } 345 | //osg::Group* getRoot(){ return m_pRoot.get(); } 346 | m_pInstance = new osgScutcheonManager(GraphicsView::instance()->getOSGViewer(), 347 | GraphicsView::instance()->getRoot()); 348 | GraphicsView::instance()->getOSGViewer()->addEventHandler(m_pInstance); 349 | } 350 | return m_pInstance; 351 | } 352 | 353 | void osgScutcheonManager::destroy() 354 | { 355 | if ( NULL != m_pInstance ) 356 | { 357 | delete m_pInstance; 358 | m_pInstance = NULL; 359 | } 360 | } 361 | 362 | bool osgScutcheonManager::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) 363 | { 364 | if (m_bStopGUI) 365 | { 366 | m_bGUIStoped = true; 367 | } 368 | else 369 | { 370 | osgViewer::Viewer *viewer = dynamic_cast(&aa); 371 | int nCount = m_LabelList.size(); 372 | for (int i=0; i< nCount; i++) 373 | { 374 | m_LabelList[i]->onMouseEvent(ea, viewer); 375 | } 376 | } 377 | return false; 378 | } 379 | 380 | int osgScutcheonManager::addLabel(osgScutcheon *label) 381 | { 382 | m_bVisible = true; 383 | if (label == NULL) { return 0;} 384 | lock(true); 385 | // while (!m_bStopGUI) QThread::sleep(100); 386 | int nCount = m_LabelList.size(); 387 | for (int i = 0; i < nCount; i++) 388 | { 389 | if (m_LabelList[i] == label) 390 | { 391 | lock(false); 392 | return 0; 393 | } 394 | } 395 | mWindowManager->addChild(label); 396 | mWindowManager->resizeAllWindows(); 397 | m_LabelList.push_back(label); 398 | 399 | lock(false); 400 | return m_LabelList.size(); 401 | } 402 | 403 | int osgScutcheonManager::delLabel(osgScutcheon *&label) 404 | { 405 | lock(true); 406 | while (!m_bStopGUI) QThread::sleep(100); 407 | for (std::vector::iterator vit = m_LabelList.begin(); vit != m_LabelList.end(); vit++) 408 | { 409 | if ((*vit) == label) 410 | { 411 | m_LabelList.erase(vit); 412 | //label->setVisibility(false);//TODO 清除界面上已经显示的标牌 413 | delete label; 414 | label = NULL; 415 | lock(false); 416 | return m_LabelList.size(); 417 | } 418 | } 419 | lock(false); 420 | return 0; 421 | } 422 | 423 | int osgScutcheonManager::delLabel(osg::MatrixTransform *tethernode) 424 | { 425 | return 0; 426 | } 427 | 428 | void osgScutcheonManager::clear() 429 | { 430 | lock(true); 431 | //while (!m_bGUIStoped) Sleep(200); 432 | while (m_LabelList.size()>0) 433 | { 434 | osgScutcheon* back = m_LabelList.back(); 435 | delLabel(back); 436 | } 437 | lock(false); 438 | } 439 | 440 | void osgScutcheonManager::lock(bool b) 441 | { 442 | if (b) 443 | { 444 | m_bStopGUI = true; 445 | m_bGUIStoped = false; 446 | } 447 | else 448 | { 449 | m_bStopGUI = false; 450 | m_bGUIStoped = true; 451 | } 452 | } 453 | 454 | osg::ref_ptr osgScutcheonManager::getWindowManager() const 455 | { 456 | return mWindowManager; 457 | } 458 | 459 | 460 | -------------------------------------------------------------------------------- /osgScutcheon.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief 标牌 3 | * @author hph 4 | * @date 2018/07/07 5 | */ 6 | #ifndef OSGSCUTCHEON_H 7 | #define OSGSCUTCHEON_H 8 | 9 | //#include "Windows.h" 10 | //#include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "qCommonFunction.h" 18 | #include 19 | #include 20 | #include "3DEngine/graphicsview.h" 21 | 22 | #define FONT_TEXT "fonts/simhei.ttf" 23 | #define TITLE_IMAGE "../publish/data/texture/mark/label_title.png" 24 | #define ITEM_IAMGE "../publish/data/texture/mark/label_normal_01.png" 25 | //标牌二级菜单 26 | class ImageLabel; 27 | //标牌一级菜单 28 | class osgScutcheonMenu; 29 | 30 | /**标牌 31 | * @brief The osgScutcheon class 32 | */ 33 | class osgScutcheon : public osgWidget::Box 34 | { 35 | 36 | public: 37 | osgScutcheon(); 38 | /// 39 | /// \brief osgScutcheon构造函数 40 | /// \param titleText 标牌的标题文字 41 | /// \param targetObj 标牌绑定的节点 42 | /// 43 | osgScutcheon(const QString& titleText, osg::ref_ptr targetObj); 44 | ~osgScutcheon(); 45 | 46 | public: 47 | 48 | void addLabelTitle(const QString &titleText); 49 | void addLabelItem(const QString &labelText); 50 | void addLabelItem(osgScutcheonMenu &labelItem); 51 | 52 | void hideOtherLabelItem(); 53 | void moveLabelItem(); 54 | 55 | void createLine(const osg::Vec3& startPt = osg::Vec3(0,0,0), const osg::Vec3& endPt = osg::Vec3(0,0,0) ); 56 | 57 | void onMouseEvent(const osgGA::GUIEventAdapter& ea, osgViewer::Viewer *viewer); 58 | 59 | osg::Geometry* getLine() const { return m_line; } 60 | 61 | int getItemCount(); 62 | 63 | void setVisibility(bool b); 64 | bool getVisibility() {return mIsVisible;} 65 | 66 | void setPos(osg::Vec3 pos); 67 | void setOffset(osg::Vec3 offset); 68 | 69 | //用于模型更新标牌回调函数中使用 70 | osg::ref_ptr getTargetObject(); 71 | std::vector > getLabelItemManager() const; 72 | 73 | private: 74 | bool callbackMouseDrag(osgWidget::Event& ev); 75 | 76 | protected: 77 | bool mouseDrag(double, double, const osgWidget::WindowManager*); 78 | bool mousePush(double, double, const osgWidget::WindowManager*); 79 | bool mouseRelease(double, double, const osgWidget::WindowManager*); 80 | 81 | public: 82 | QString mTitleText; 83 | std::vector > mLabelItemManager; 84 | 85 | int mIndex; 86 | 87 | osg::ref_ptr mTargetObj; 88 | osg::ref_ptr m_line; 89 | 90 | bool mIsVisible; 91 | bool mIsItemVisible; 92 | bool mIsMousePush; 93 | bool mIsMouseDrag; 94 | 95 | 96 | osg::Vec3 m_pos; 97 | osg::Vec3 m_offset; 98 | 99 | osg::Vec3 m_LastPt; 100 | osg::Vec3 m_LBDownPt; 101 | 102 | }; 103 | 104 | /** 105 | 标牌管理器,全局唯一,一个标牌管理器包含多个标牌 106 | * @brief The osgScutcheonManager class 107 | */ 108 | class osgScutcheonManager : public osgGA::GUIEventHandler 109 | { 110 | protected: 111 | osgScutcheonManager(osgViewer::Viewer* pViewer, osg::Group* pScreneRoot); 112 | ~osgScutcheonManager(); 113 | 114 | public: 115 | static osgScutcheonManager *instance(); 116 | static void destroy(); 117 | bool handle(const osgGA::GUIEventAdapter&,osgGA::GUIActionAdapter&); 118 | int addLabel(osgScutcheon* label); 119 | int delLabel(osgScutcheon*& label); 120 | int delLabel(osg::MatrixTransform* tethernode); 121 | void clear(); 122 | void lock(bool b); 123 | 124 | void setVisibility(bool b); 125 | void setVisibilityByID(unsigned int ID,bool b); 126 | bool getVisibilityByID(unsigned int ID); 127 | bool getVisibility() const { return m_bVisible; } 128 | 129 | void setLabelTxtColor(const osg::Vec4f& color); 130 | void setLabelBgColor(const osg::Vec4f& color); 131 | const osg::Vec4f& getLabelTxtColor() const { return m_clrTxt; } 132 | const osg::Vec4f& getLabelBgColor() const { return m_clrBg; } 133 | 134 | osg::ref_ptr getWindowManager() const; 135 | public: 136 | static osgScutcheonManager *m_pInstance; 137 | osg::ref_ptr mWindowManager; 138 | //osgWidget::WindowManager* mWindowManager; 139 | std::vector m_LabelList; 140 | bool m_bStopGUI; 141 | bool m_bGUIStoped; 142 | bool m_bVisible; 143 | osg::Vec4f m_clrTxt; 144 | osg::Vec4f m_clrBg; 145 | 146 | }; 147 | 148 | 149 | 150 | //标牌一级菜单 151 | class osgScutcheonMenu: public osgWidget::Label 152 | { 153 | 154 | public: 155 | osgScutcheonMenu(const QString &label, osg::ref_ptr parentMenu): 156 | osgWidget::Label("menu1"), 157 | mChildMenu(NULL), 158 | mParentMenu(parentMenu), 159 | mHasChildMenu(false), 160 | mIndex(0), 161 | mMenuItemCount(0) 162 | { 163 | initLabel(label);//初始化一级菜单 164 | } 165 | 166 | //添加二级菜单 167 | void addChildMenu(QString &menuText) 168 | { 169 | ImageLabel *childMenuContent = new ImageLabel(menuText); 170 | if(mChildMenu == NULL) 171 | { 172 | mChildMenu = new osgWidget::Box("childMenu", osgWidget::Box::VERTICAL,true); 173 | mChildMenu->addWidget(childMenuContent); 174 | mMenuItemManager.push_back(childMenuContent); 175 | mChildMenu->getBackground()->setColor(1.0f, 1.0f, 1.0f, 0.6f); 176 | mChildMenu->resize(); 177 | mChildMenu->hide(); 178 | mHasChildMenu = true; 179 | //此句不能加,不然多一个视口显示mChildMenu,因为mParent是显示的 180 | //mParentMenu->addChild(mChildMenu); 181 | mParentMenu->getWindowManager()->addChild(mChildMenu.get()); 182 | 183 | } 184 | else 185 | { 186 | mChildMenu->addWidget(childMenuContent); 187 | mMenuItemManager.push_back(childMenuContent); 188 | } 189 | 190 | ++mMenuItemCount; 191 | } 192 | 193 | //更新二级菜单文字 194 | void updateChildMenuText(int index, QString labelText) 195 | { 196 | if(index >= 0 && index < getMenuItemCount()) 197 | { 198 | mMenuItemManager.at(index)->setLabelText(labelText); 199 | } 200 | } 201 | 202 | //初始化一级菜单 203 | void initLabel(const QString &labelText) 204 | { 205 | setFont(FONT_TEXT); 206 | setFontSize(15); 207 | setFontColor(0.0f, 0.0f, 1.0f, 1.0f); 208 | addSize(128.0f, 32.0f); 209 | setColor(1.0f, 1.0f, 0.0f, 0.6f); 210 | //setShadow(0.08f); 211 | setCanFill(true); 212 | setEventMask(osgWidget::EVENT_ALL); 213 | setImage(ITEM_IAMGE); 214 | setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT); 215 | setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT); 216 | setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT); 217 | setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT); 218 | //设置文本放在最后,不然标牌大小会改变 219 | CommonFunction com; 220 | osgText::String labelString = com.qstringToOsgTextString(labelText); 221 | setLabel(labelString); 222 | } 223 | 224 | 225 | 226 | void setIndex(int index) 227 | { 228 | mIndex = index; 229 | } 230 | 231 | void moveTo(int parentX, int parentY) 232 | { 233 | if(mChildMenu) 234 | { 235 | mChildMenu->setOrigin(parentX + 128.0, parentY + 32.0 * mIndex); 236 | mChildMenu->update(); 237 | } 238 | } 239 | 240 | bool isHasChildMenu() 241 | { 242 | return mHasChildMenu; 243 | } 244 | 245 | osg::ref_ptr getChildMenu() 246 | { 247 | return mChildMenu; 248 | } 249 | 250 | int getIndex() 251 | { 252 | return mIndex; 253 | } 254 | 255 | int getMenuItemCount() 256 | { 257 | return mMenuItemManager.size(); 258 | } 259 | 260 | //隐藏当前标牌其余二级子菜单 261 | void hideOtherChildMenu() 262 | { 263 | for(int i = 0; i < mParentMenu->getLabelItemManager().size(); i++) 264 | { 265 | osg::ref_ptr childItem = mParentMenu->getLabelItemManager().at(i); 266 | if(childItem->getChildMenu() != mChildMenu) 267 | { 268 | childItem->getChildMenu()->hide(); 269 | } 270 | qDebug() << "hideOtherChildMenu"; 271 | } 272 | } 273 | //隐藏所有标牌其余二级子菜单 274 | void hideAllChildMenu(osgWidget::WindowManager*wm) 275 | { 276 | osgWidget::Window *tmp = 0; 277 | unsigned int count = wm->getNumChildren(); 278 | for(unsigned int i = 0; i < count; ++i) 279 | { 280 | tmp = dynamic_cast(wm->getChild(i)); 281 | if(tmp) 282 | { 283 | QString name = QString::fromStdString(tmp->getName()); 284 | if(tmp != mChildMenu.get() && name == "childMenu") 285 | { 286 | if(tmp->isVisible()) 287 | { 288 | tmp->hide(); 289 | } 290 | } 291 | } 292 | } 293 | } 294 | 295 | void managed(osgWidget::WindowManager* wm) 296 | { 297 | osgWidget::Label::managed(wm); 298 | if(mChildMenu) 299 | { 300 | mChildMenu->hide(); 301 | } 302 | } 303 | 304 | void positioned() 305 | { 306 | osgWidget::Label::positioned(); 307 | if(mChildMenu) 308 | { 309 | //qDebug() << "mChildMenu not NULL!!" << mIndex; 310 | mChildMenu->setOrigin(mParentMenu->getX() + 128.0, mParentMenu->getY() + 32.0 * mIndex ); 311 | } 312 | } 313 | 314 | bool mousePush(double, double, const osgWidget::WindowManager*wm) 315 | { 316 | hideOtherChildMenu(); 317 | //hideAllChildMenu(mParentMenu->getWindowManager()); 318 | 319 | if(!mChildMenu->isVisible()) 320 | { 321 | mChildMenu->show(); 322 | qDebug() << "hideOtherChildMenu show"; 323 | } 324 | else 325 | { 326 | mChildMenu->hide(); 327 | qDebug() << "hideOtherChildMenu hide"; 328 | } 329 | return true; 330 | } 331 | 332 | bool mouseEnter(double, double, const osgWidget::WindowManager*) 333 | { 334 | setColor(1.0f, 1.0f, 1.0f, 0.3f); 335 | return true; 336 | } 337 | 338 | bool mouseLeave(double, double, const osgWidget::WindowManager*) 339 | { 340 | setColor(1.0f, 1.0f, 1.0f, 0.6f); 341 | return true; 342 | } 343 | 344 | public: 345 | QVector > mMenuItemManager; 346 | 347 | private: 348 | osg::ref_ptr mChildMenu; 349 | osg::ref_ptr mParentMenu; 350 | 351 | int mIndex; 352 | int mMenuItemCount; 353 | bool mHasChildMenu; 354 | 355 | }; 356 | 357 | //标牌二级菜单 358 | class ImageLabel: public osgWidget::Label 359 | { 360 | 361 | public: 362 | ImageLabel(QString &labelText): osgWidget::Label("menu1") 363 | { 364 | setFont(FONT_TEXT); 365 | setFontSize(13); 366 | setFontColor(0.0f, 0.2f, 1.0f, 1.0f); 367 | addSize(128.0f, 32.0f); 368 | setColor(1.0f, 1.0f, 1.0f, 0.6f); 369 | //setPadding(1.0f); 370 | //setShadow(0.08f); 371 | setCanFill(true); 372 | setEventMask(osgWidget::EVENT_ALL); 373 | setImage(ITEM_IAMGE); 374 | 375 | setLabelText(labelText); 376 | 377 | } 378 | 379 | void setLabelText(QString labelText) 380 | { 381 | setAlignHorizontal(osgWidget::Widget::HA_LEFT); 382 | setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT); 383 | setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT); 384 | setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT); 385 | setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT); 386 | 387 | CommonFunction com; 388 | osgText::String labelString = com.qstringToOsgTextString(labelText); 389 | setLabel(labelString); 390 | } 391 | 392 | bool mousePush(double, double, const osgWidget::WindowManager*) 393 | { 394 | return true; 395 | } 396 | 397 | 398 | bool mouseDrag(double, double, const osgWidget::WindowManager*) 399 | { 400 | //osg::notify(osg::NOTICE) << _name << " > mouseDrag called" << std::endl; 401 | return false; 402 | } 403 | 404 | bool mouseEnter(double, double, const osgWidget::WindowManager*) 405 | { 406 | //setColor(1.0f, 1.0f, 1.0f, 1.0f); 407 | setFontColor(0.0f, 0.0f, 1.0f, 1.0f); 408 | return true; 409 | } 410 | 411 | bool mouseLeave(double, double, const osgWidget::WindowManager*) 412 | { 413 | //setColor(1.0f, 1.0f, 1.0f, 0.8f); 414 | setFontColor(0.0f, 0.2f, 1.0f, 1.0f); 415 | return true; 416 | } 417 | 418 | bool mouseOver(double, double, const osgWidget::WindowManager*) 419 | { 420 | return true; 421 | } 422 | }; 423 | 424 | #endif // OSGSCUTCHEON_H 425 | -------------------------------------------------------------------------------- /qCommonFunction.cpp: -------------------------------------------------------------------------------- 1 | #include "qCommonFunction.h" 2 | 3 | CommonFunction::CommonFunction() 4 | { 5 | 6 | } 7 | 8 | CommonFunction::~CommonFunction() 9 | { 10 | 11 | } 12 | 13 | //wstring转string 14 | std::string CommonFunction:: unicodeToUTF8(const std::wstring &src) 15 | { 16 | std::string result; 17 | int n = WideCharToMultiByte(CP_UTF8,0,src.c_str(),-1,0,0,0,0); 18 | result.resize(n); 19 | ::WideCharToMultiByte(CP_UTF8,0,src.c_str(),-1,(char*)result.c_str(),result.length(),0,0); 20 | return result; 21 | } 22 | //string转wstring 23 | std::wstring CommonFunction:: gb2312ToUnicode(const std::string &src) 24 | { 25 | std::wstring result; 26 | int n = MultiByteToWideChar(CP_ACP,0,src.c_str(),-1,NULL,0); 27 | result.resize(n); 28 | ::MultiByteToWideChar(CP_ACP,0,src.c_str(),-1,(LPWSTR)result.c_str(),result.length()); 29 | return result; 30 | } 31 | //先string转wstring 32 | //再wstring转string 33 | std::string CommonFunction::gb2312ToUTF8(const std::string &src) 34 | { 35 | std::string result; 36 | result = unicodeToUTF8(gb2312ToUnicode(src)); 37 | return result; 38 | } 39 | 40 | std::string CommonFunction::qstringToOsgTextToStdString(QString &srcString) 41 | { 42 | osgText::String dstString; 43 | osg::ref_ptr text = new osgText::Text; 44 | osg::ref_ptr font = osgText::readFontFile("fonts/simhei.ttf"); 45 | text->setFont(font); 46 | const std::string tmpStr = srcString.toStdString(); 47 | text->setText(tmpStr, osgText::String::ENCODING_UTF8); 48 | dstString = text->getText(); 49 | return dstString.createUTF8EncodedString(); 50 | } 51 | 52 | QString CommonFunction::asciiToUTF8(std::string &src) 53 | { 54 | //ANSI转unicode 55 | setlocale(LC_ALL, "chs"); 56 | wchar_t wcsStr[100]; 57 | swprintf(wcsStr, L"%S",src.c_str()); 58 | //unicode转utf-8 59 | QString placeName = QString::fromWCharArray(wcsStr); 60 | return placeName; 61 | //return ""; 62 | } 63 | 64 | osgText::String CommonFunction::qstringToOsgTextString(const QString &srcString) 65 | { 66 | osgText::String dstString; 67 | osg::ref_ptr text = new osgText::Text; 68 | osg::ref_ptr font = osgText::readFontFile("fonts/simhei.ttf"); 69 | text->setFont(font); 70 | const std::string tmpStr = srcString.toStdString(); 71 | text->setText(tmpStr, osgText::String::ENCODING_UTF8); 72 | dstString = text->getText(); 73 | return dstString;//.createUTF8EncodedString() 74 | } 75 | 76 | -------------------------------------------------------------------------------- /qCommonFunction.h: -------------------------------------------------------------------------------- 1 | #ifndef QCOMMONFUNCTION_H 2 | #define QCOMMONFUNCTION_H 3 | 4 | #include "Windows.h" 5 | #include "WinNls.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class CommonFunction 13 | { 14 | public: 15 | CommonFunction(); 16 | ~CommonFunction(); 17 | std::string unicodeToUTF8(const std::wstring &src); 18 | std::wstring gb2312ToUnicode(const std::string &src); 19 | std::string gb2312ToUTF8(const std::string &src); 20 | std::string qstringToOsgTextToStdString(QString &srcString); 21 | osgText::String qstringToOsgTextString(const QString &srcString); 22 | QString asciiToUTF8(std::string &src); 23 | }; 24 | 25 | #endif // QCOMMONFUNCTION_H 26 | --------------------------------------------------------------------------------