osg::ComputeBoundsVisitor用法(一)

博客介绍了osg::ComputeBoundsVisitor可用于获取模型或绘制几何体的最小包围盒,给出获取cow.osg模型最小包围盒中心点及x、y、z坐标最大、最小值的示例,还提醒输出信息时要加回车换行,避免日志信息只存于缓冲区。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

osg::ComputeBoundsVisitor用于获取模型或绘制几何体的最小包围盒。如下代码:


#include<osg/Geometry>
#include<osg/Geode>
#include<osgViewer/Viewer>
#include<osgViewer/ViewerEventHandlers>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include<osg/DrawPixels>
#include<osg/PositionAttitudeTransform>
#include<osg/computeBoundsVisitor>
#include<osg/MatrixTransform>
#include<osg/ShapeDrawable>
#include<osg/Shape>
#include<osg/PolygonMode>
int main(int argc, char *argv[])
{
	osg::ref_ptr<osgViewer::Viewer> spViewer = new osgViewer::Viewer();
	osg::ref_ptr<osg::Group> spGroup = new osg::Group();

	osg::ref_ptr<osg::Node> spNode = osgDB::readNodeFile("cow.osg");
	spGroup->addChild(spNode);
	spViewer->setSceneData(spGroup);
	osg::ComputeBoundsVisitor boundsVist;
	spNode->accept(boundsVist);

	osg::BoundingBox box = boundsVist.getBoundingBox();
	//OSG_NOTIFY(osg::ALWAYS) << "bound info:" << std::endl;;
	osg::notify(osg::ALWAYS) << "bouding box info" << std::endl;
	osg::notify(osg::ALWAYS) << "center x:" << box.center().x() << std::endl;
	osg::notify(osg::ALWAYS) << "center y:"<< box.center().y() << std::endl;;
	osg::notify(osg::ALWAYS) << "center z:" << box.center().z() << std::endl;;
	osg::notify(osg::ALWAYS) << "x max:" << box.xMax() << std::endl;
	osg::notify(osg::ALWAYS) << "x min:" << box.xMin() << std::endl;
	osg::notify(osg::ALWAYS) << "y max:" << box.yMax() << std::endl;
	osg::notify(osg::ALWAYS) << "y min:" << box.yMin() << std::endl;
	osg::notify(osg::ALWAYS) << "z max:" << box.zMax() << std::endl;
	osg::notify(osg::ALWAYS) << "z min:" << box.zMin() << std::endl;

	// 画个外框
	osg::ref_ptr<osg::Geode>spGeodeBox = new osg::Geode();
	spGeodeBox->addDrawable(new osg::ShapeDrawable(new osg::Box(box.center(), box.xMax() - box.xMin(), box.yMax() - box.yMin(), box.zMax() - box.zMin())));
	osg::ref_ptr<osg::StateSet> spGeodeStateSet = spGeodeBox->getOrCreateStateSet();
	
   // 采用线框模式,以便能看见里面的模型即cow.osg
    osg::ref_ptr<osg::PolygonMode> spGeodePolygon = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
	spGeodeStateSet->setAttribute(spGeodePolygon);
	spGroup->addChild(spGeodeBox);
	spViewer->setUpViewInWindow(10, 10, 800, 600);
	spViewer->realize();
	spViewer->run();
    return 0;
}

获取cow.osg模型最小包围盒的中心点及x、y、z坐标的最大、最小值,输入如下:

注意:上面的osg::notify(osg::ALWAYS)输出信息时,后面要加回车换行,否则日志信息只输入到缓冲区,而不会立即输出到控制台

模型显示效果如下:

#ifndef MODELMANGER_H #define MODELMANGER_H #include <QObject> #include <map> #include <vector> #include <osg/Node> #include <osg/Vec3d> #include <osgEarth/MapNode> #include <osg/observer_ptr> #include <osgEarthAnnotation/FeatureNode> namespace osg { class Group; class MatrixTransform; class Geode; } namespace osgEarth { class GeoPoint; class GeoTransform; } class ModelManger : public QObject { Q_OBJECT public: explicit ModelManger(QObject *parent = nullptr); /// 标记点数据结构 struct AnchorPoint { QString name; // 标记点名称 QString type; // 标记点类型 double x; // X坐标(模型局部坐标系) double y; // Y坐标 double z; // Z坐标 osgEarth::GeoPoint geoPoint; // 地理坐标(经纬度+高程) osg::ref_ptr<osg::Node> markerNode; // 标记点场景节点 }; bool loadModelTower(double lon, double lat, double alt, const QString& filePath, const QString& modelName, double angX, double angY, double angZ); bool loadModelFitForTower(const QString& filePath, const QString& towerName, const QString& pointName, double angX, double angY, double angZ); bool removeModel(const QString& modelName); Q_INVOKABLE void yflTest(QString modelName,double lon, double lat, double alt,double ang,const QString& modelPath); void setModelColor(const QString& modelName, const osg::Vec4& color); void setFitModelColor(const QString& towerName, const QString& pointName, const osg::Vec4& color); // 获取模型标记点信息 Q_INVOKABLE QVariantList getModelAnchorPoints(const QString& modelName) const; Q_INVOKABLE QVariantList getFitAnchorPoints(const QString& towerName, const QString& fitName) const; /// 两点连线 bool drawLine(const QString& lineName, const QString& startModel, const QString& startPoint, const QString& startType, const QString& endModel, const QString& endPoint, const QString& endType, const osg::Vec4& color, float width); bool removeLine(const QString& lineName); private: void applyColorToNode(osg::Node* node, const osg::Vec4& color); std::vector<ModelManger::AnchorPoint> getAnchorPointsFromJson(const QString &jsonPath, bool isTower); /// 塔模型信息结构 struct TowerModelInfo { osg::ref_ptr<osgEarth::GeoTransform> geoTransform; // 地理变换节点 osg::ref_ptr<osg::Group> modelGroup; // 主容器组 osg::ref_ptr<osg::MatrixTransform> modelXform; // 模型旋转节点 std::vector<AnchorPoint> anchorPoints; // 标记点列表 std::map<QString, osg::ref_ptr<osg::MatrixTransform>> fitModels; // 附属模型映射表 // std::map<QString, osg::ref_ptr<osg::MatrixTransform>> anchorTransforms; //存储每个标记点的变换矩阵 // 使用 observer_ptr 断开循环引用 std::map<QString, osg::observer_ptr<osg::MatrixTransform>> anchorTransforms; }; /// 附属模型信息结构 struct FitModelInfo { osg::ref_ptr<osg::MatrixTransform> transform; // 变换节点 std::vector<AnchorPoint> anchorPoints; // 标记点列表 QString parentTowerName; // 所属塔模型名称 QString pointName; // 安装点名称 }; // 计算所有标记点的地理坐标 void calculateAllAnchorPoints(); // 计算单个节点的地理坐标 osgEarth::GeoPoint calculateNodeGeoPoint(osg::Node* node) const; // 私有工具方法 osg::Node* createMarker(const QString& name, const osg::Vec3d& position); osg::Node* createBoundingBox(osg::Node* node); osg::Node* createCoordinateAxes(const osg::Vec3d& position); osg::observer_ptr<osgEarth::MapNode> m_mapNode; // 地图节点 std::map<QString, TowerModelInfo> m_towerModels; // 塔模型存储映射表 std::map<QString, FitModelInfo> m_fitModelsInfo; // 存储附属模型信息 // 添加QMutex保护 mutable QMutex m_dataMutex; /// 线段数据结构 struct LineSegment { osg::ref_ptr<osgEarth::Annotation::FeatureNode> featureNode; // 使用FeatureNode }; std::map<QString, LineSegment> m_lineSegments; // 存储所有线段 // 查找标记点坐标 bool findAnchorPoint(const QString& modelName, const QString& pointName, const QString& pointType, osgEarth::GeoPoint& outPoint) const; }; #endif // MODELMANGER_H #include "ModelManger.h" #include "utils/HkrCommon.h" #include <osgDB/ReadFile> #include <osgText/Text> #include <osgEarth/GeoTransform> #include <osg/ComputeBoundsVisitor> #include <osg/ShapeDrawable> #include <osg/MatrixTransform> #include <osg/AutoTransform> #include <osg/PositionAttitudeTransform> #include <osg/Geode> #include <osg/Geometry> #include <codecvt> #include <QDebug> #include <osg/StateSet> #include <osg/BlendFunc> #include <osg/LineWidth> #include <osgTools/OSGObject.h> #include <osgUtil/CullVisitor> #include <QVariantMap> #include <osgEarthFeatures/Feature> // 坐标单位转换宏(毫米→米) #define MM_TO_M(mm) ((mm) / 1000.0) ModelManger::ModelManger(QObject *parent) : QObject{parent} { m_mapNode = OSGObject::getInstance()->getMapNode(); } bool ModelManger::loadModelTower(double lon, double lat, double alt, const QString& filePath, const QString& modelName, double angX, double angY, double angZ) { // 检查模型名称是否已存在,存在就删除 if (m_towerModels.find(modelName) != m_towerModels.end()) { removeModel(modelName); } // 加载OBJ模型 osg::ref_ptr<osg::Node> towerModel = osgDB::readNodeFile(filePath.toStdString()); if (!towerModel) { qDebug() << "模型加载失败:" << filePath; return false; } // 输出模型原始包围盒信息 osg::ComputeBoundsVisitor cbv; towerModel->accept(cbv); osg::BoundingBox bb = cbv.getBoundingBox(); qDebug() << "模型原始包围盒(毫米):min(" << bb.xMin() << ", " << bb.yMin() << ", " << bb.zMin() << ") max(" << bb.xMax() << ", " << bb.yMax() << ", " << bb.zMax() << ")"; // 创建地理变换节点 osg::ref_ptr<osgEarth::GeoTransform> geoXform = new osgEarth::GeoTransform(); geoXform->setPosition(osgEarth::GeoPoint( m_mapNode->getMapSRS(), lon, lat, alt, osgEarth::ALTMODE_ABSOLUTE )); // 创建主容器组 osg::ref_ptr<osg::Group> modelGroup = new osg::Group(); // 添加固定旋转:绕X轴-90度(Y-up to Z-up) osg::Matrix fixRotation; fixRotation.makeRotate(osg::DegreesToRadians(-90.0), osg::X_AXIS); osg::Matrix rotationMatrix; rotationMatrix.makeRotate( osg::DegreesToRadians(angX), osg::X_AXIS, osg::DegreesToRadians(angY), osg::Y_AXIS, osg::DegreesToRadians(angZ), osg::Z_AXIS ); // 组合旋转:先应用初始修正,再应用用户旋转 osg::Matrix totalRotation = fixRotation * rotationMatrix; osg::ref_ptr<osg::MatrixTransform> modelXform = new osg::MatrixTransform(); modelXform->setMatrix(totalRotation); // 使用组合后的旋转矩阵 modelXform->addChild(towerModel); // 创建包围盒并添加到模型 osg::ref_ptr<osg::Node> bbox = createBoundingBox(towerModel); modelXform->addChild(bbox); modelGroup->addChild(modelXform); // 保存模型信息 TowerModelInfo info; // 创建标记点(添加到主容器组) QString jsonPath = filePath; jsonPath.replace(".obj", ".json"); // 获取对应的JSON文件路径 std::vector<AnchorPoint> towerPoints = getAnchorPointsFromJson(jsonPath, true); // 创建标记点节点 for (auto& pt : towerPoints) { osg::Vec3d position(MM_TO_M(pt.x), MM_TO_M(pt.y), MM_TO_M(pt.z)); qDebug() << "创建标记点" << pt.name << "坐标(米):" << position.x() << ", " << position.y() << ", " << position.z(); // 创建标记点节点 pt.markerNode = createMarker(pt.name, position); // 添加坐标轴 osg::ref_ptr<osg::Node> axes = createCoordinateAxes(position); // 创建变换节点 osg::Matrix posM; posM.makeRotate(osg::DegreesToRadians(angZ), osg::Z_AXIS); osg::ref_ptr<osg::MatrixTransform> posform = new osg::MatrixTransform(); posform->setMatrix(posM); posform->addChild(axes); posform->addChild(pt.markerNode); modelGroup->addChild(posform); // 记录标记点变换节点 info.anchorTransforms[pt.name] = posform; // 添加到标记点列表 info.anchorPoints.push_back(pt); } // 在原点添加坐标轴 modelGroup->addChild(createCoordinateAxes(osg::Vec3d(0,0,0))); // 将主容器组添加到地理变换节点 geoXform->addChild(modelGroup); // 保存模型信息 info.geoTransform = geoXform; info.modelGroup = modelGroup; info.modelXform = modelXform; info.anchorPoints = towerPoints; m_towerModels[modelName] = info; // 添加到场景 m_mapNode->addChild(geoXform); qDebug() << "塔模型加载完成:" << modelName; // 延迟计算地理坐标 calculateAllAnchorPoints(); return true; } bool ModelManger::loadModelFitForTower(const QString& filePath, const QString& towerName, const QString& pointName, double angX, double angY, double angZ) { // 查找塔模型 auto towerIt = m_towerModels.find(towerName); if (towerIt == m_towerModels.end()) { qDebug() << "未找到塔模型:" << towerName; return false; } TowerModelInfo& towerInfo = towerIt->second; // 查找标记点 auto pointIt = std::find_if(towerInfo.anchorPoints.begin(), towerInfo.anchorPoints.end(), [&](const AnchorPoint& pt) { return pt.name == pointName; }); if (pointIt == towerInfo.anchorPoints.end()) { qDebug() << "未找到标记点:" << pointName << "在塔模型" << towerName; return false; } osg::Vec3d towerPointPos(MM_TO_M(pointIt->x), MM_TO_M(pointIt->y), MM_TO_M(pointIt->z)); // 获取标记点变换节点 auto anchorTransformIt = towerInfo.anchorTransforms.find(pointName); if (anchorTransformIt == towerInfo.anchorTransforms.end()) { qDebug() << "未找到标记点变换节点:" << pointName << "在塔模型" << towerName; return false; } osg::ref_ptr<osg::MatrixTransform> anchorTransform = anchorTransformIt->second; // 加载fit模型 osg::ref_ptr<osg::Node> fitModel = osgDB::readNodeFile(filePath.toStdString()); if (!fitModel) { qDebug() << "fit模型加载失败:" << filePath; return false; } // 获取fit模型的JT点 QString fitJsonPath = filePath; fitJsonPath.replace(".obj", ".json"); std::vector<AnchorPoint> fitPoints = getAnchorPointsFromJson(fitJsonPath, false); osg::Vec3d jtPos(0, 0, 0); for (const auto& pt : fitPoints) { if (pt.type == "JT") { jtPos.set(MM_TO_M(pt.x), MM_TO_M(pt.y), MM_TO_M(pt.z)); break; } } // 创建fit模型的变换节点 osg::ref_ptr<osg::MatrixTransform> fitXform = new osg::MatrixTransform(); // 设置相对于标记点的变换 // 将JT点移动到原点 // osg::Matrix matrix = osg::Matrix::translate(-jtPos); // 应用fit模型自身旋转 osg::Matrix rotation; rotation.makeRotate( osg::DegreesToRadians(angX), osg::X_AXIS, osg::DegreesToRadians(angY), osg::Y_AXIS, osg::DegreesToRadians(angZ), osg::Z_AXIS ); // matrix = matrix * rotation; // matrix.setTrans(towerPointPos); // 移动到塔模型标记点 osg::Matrix matrix = osg::Matrix::translate(-jtPos) * rotation * osg::Matrix::translate(towerPointPos); fitXform->setMatrix(matrix); fitXform->addChild(fitModel); // 添加包围盒和坐标轴 fitXform->addChild(createBoundingBox(fitModel)); fitXform->addChild(createCoordinateAxes(osg::Vec3d(0, 0, 0))); // 创建FitModelInfo FitModelInfo fitInfo; fitInfo.transform = fitXform; fitInfo.parentTowerName = towerName; fitInfo.pointName = pointName; // 创建标记点节点 for (auto& pt : fitPoints) { osg::Vec3d position(MM_TO_M(pt.x), MM_TO_M(pt.y), MM_TO_M(pt.z)); qDebug() << "创建fit标记点" << pt.type << pt.name << "坐标(米):" << position.x() << ", " << position.y() << ", " << position.z(); // 创建标记点节点 pt.markerNode = createMarker(pt.type, position); // 添加坐标轴 osg::ref_ptr<osg::Node> axes = createCoordinateAxes(position); osg::Matrix posM; posM.makeRotate(osg::DegreesToRadians(-angX), osg::X_AXIS); osg::ref_ptr<osg::MatrixTransform> posform = new osg::MatrixTransform(); posform->setMatrix(posM); posform->addChild(axes); posform->addChild(pt.markerNode); fitXform->addChild(posform); // 添加到标记点列表 fitInfo.anchorPoints.push_back(pt); } // 存储fit模型信息 QString fitKey = towerName + "::" + pointName; m_fitModelsInfo[fitKey] = fitInfo; // 移除旧的fit模型(如果存在) auto fitIt = towerInfo.fitModels.find(pointName); if (fitIt != towerInfo.fitModels.end()) { anchorTransform->removeChild(fitIt->second); towerInfo.fitModels.erase(fitIt); } // 将fit模型节点附加到标记点变换节点 anchorTransform->addChild(fitXform); // 保存到塔模型信息中,以便后续删除 towerInfo.fitModels[pointName] = fitXform; // 调试输出 qDebug() << "fit模型加载到" << towerName << "的" << pointName << "位置, JT点: (" << jtPos.x() << "," << jtPos.y() << "," << jtPos.z() << ")" << "旋转角度: (" << angX << ", " << angY << ", " << angZ << ")"; // 计算JT点最终位置(相对于世界坐标系) osg::Matrix worldMatrix = fitXform->getWorldMatrices()[0]; osg::Vec3d jtFinal = jtPos * worldMatrix; qDebug() << "JT点最终位置: (" << jtFinal.x() << ", " << jtFinal.y() << ", " << jtFinal.z() << ")"; // 延迟计算地理坐标 calculateAllAnchorPoints(); return true; } bool ModelManger::removeModel(const QString& modelName) { auto it = m_towerModels.find(modelName); if (it == m_towerModels.end()) { qDebug() << "未找到要删除的模型:" << modelName; return false; } // 删除关联的fit模型信息 for (auto fitIt = m_fitModelsInfo.begin(); fitIt != m_fitModelsInfo.end(); ) { if (fitIt->second.parentTowerName == modelName) { fitIt = m_fitModelsInfo.erase(fitIt); } else { ++fitIt; } } // 从场景中移除整个塔模型 m_mapNode->removeChild(it->second.geoTransform); // 从管理列表中移除 m_towerModels.erase(it); qDebug() << "模型已删除:" << modelName; return true; } std::wstring string_to_wstring(const std::string& str) { std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; return converter.from_bytes(str); } // 创建坐标轴(辅助调试) osg::Node* ModelManger::createCoordinateAxes(const osg::Vec3d& position) { osg::ref_ptr<osg::Geode> geode = new osg::Geode(); // 创建几何体 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry(); // 顶点 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(); vertices->push_back(position); // 原点 vertices->push_back(position + osg::Vec3d(1.0, 0.0, 0.0)); // X轴 vertices->push_back(position); // 原点 vertices->push_back(position + osg::Vec3d(0.0, 1.0, 0.0)); // Y轴 vertices->push_back(position); // 原点 vertices->push_back(position + osg::Vec3d(0.0, 0.0, 1.0)); // Z轴 geometry->setVertexArray(vertices); // 颜色 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(); colors->push_back(osg::Vec4(1.0, 0.0, 0.0, 1.0)); // 红色 - X轴 colors->push_back(osg::Vec4(1.0, 0.0, 0.0, 1.0)); colors->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0)); // 绿色 - Y轴 colors->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0)); colors->push_back(osg::Vec4(0.0, 0.0, 1.0, 1.0)); // 蓝色 - Z轴 colors->push_back(osg::Vec4(0.0, 0.0, 1.0, 1.0)); geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); // 图元 geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 6)); // 线宽 osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(3.0f); geometry->getOrCreateStateSet()->setAttributeAndModes(lineWidth); geode->addDrawable(geometry); return geode.release(); } bool ModelManger::findAnchorPoint(const QString &modelName, const QString &pointName, const QString &pointType, osgEarth::GeoPoint &outPoint) const { // // 1. 在塔模型中查找 // auto towerIt = m_towerModels.find(modelName); // if (towerIt != m_towerModels.end()) { // const TowerModelInfo& towerInfo = towerIt->second; // for (const auto& pt : towerInfo.anchorPoints) { // // 匹配名称或类型 // if ((!pointName.isEmpty() && pt.name == pointName) || // (!pointType.isEmpty() && pt.type == pointType)) { // if (pt.geoPoint.isValid()) { // outPoint = pt.geoPoint; // return true; // } // } // } // } // 2. 在附属模型中查找 for (const auto& fitPair : m_fitModelsInfo) { if(fitPair.first == modelName + "::" + pointName){ const FitModelInfo& fitInfo = fitPair.second; // 检查是否属于指定模型 if (fitInfo.parentTowerName == modelName && fitInfo.pointName == pointName) { for (const auto& pt : fitInfo.anchorPoints) { // 匹配名称或类型 if (!pointType.isEmpty() && pt.type == pointType) { if (pt.geoPoint.isValid()) { outPoint = pt.geoPoint; return true; } } } } } // const FitModelInfo& fitInfo = fitPair.second; // // 检查是否属于指定模型 // if (fitInfo.parentTowerName == modelName) { // for (const auto& pt : fitInfo.anchorPoints) { // // 匹配名称或类型 // if ((!pointName.isEmpty() && pt.name == pointName) || // (!pointType.isEmpty() && pt.type == pointType)) { // if (pt.geoPoint.isValid()) { // outPoint = pt.geoPoint; // return true; // } // } // } // } } // // 3. 在附属模型键值中查找 // QString fullKey = modelName + "::" + pointName; // auto fitIt = m_fitModelsInfo.find(fullKey); // if (fitIt != m_fitModelsInfo.end()) { // const FitModelInfo& fitInfo = fitIt->second; // for (const auto& pt : fitInfo.anchorPoints) { // // 匹配类型 // if (!pointType.isEmpty() && pt.type == pointType) { // if (pt.geoPoint.isValid()) { // outPoint = pt.geoPoint; // return true; // } // } // } // } qDebug() << "未找到标记点: model=" << modelName << ", point=" << pointName << ", type=" << pointType; return false; } // 创建标记点(红色小球+文字标签) osg::Node* ModelManger::createMarker(const QString& name, const osg::Vec3d& position) { osg::ref_ptr<osg::Group> group = new osg::Group(); // 创建小球 osg::Geode* sphereGeode = new osg::Geode(); osg::Sphere* sphere = new osg::Sphere(osg::Vec3d(0,0,0), 0.20); osg::ShapeDrawable* sphereDrawable = new osg::ShapeDrawable(sphere); sphereDrawable->setColor(osg::Vec4(1.0, 0.0, 0.0, 0.8));// 红色 sphereGeode->addDrawable(sphereDrawable); // 设置状态 osg::StateSet* ss = sphereGeode->getOrCreateStateSet(); ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF); ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); // 创建标签 osg::Geode* textGeode = new osg::Geode; osgText::Text* text = new osgText::Text; text->setFont(GISDATA"Fonts/simhei.ttf"); text->setColor(osg::Vec4(1,1,0,1)); // 黄色文本 text->setCharacterSize(0.2); // 文本尺寸 text->setPosition(osg::Vec3(-0.3,0,0.2)); // 文本位置 text->setAxisAlignment(osgText::Text::SCREEN); text->setText(string_to_wstring(name.toStdString()).c_str()); // text->setBackdropType(osgText::Text::OUTLINE); // text->setBackdropColor(osg::Vec4(0,0,0,1)); textGeode->addDrawable(text); // 创建定位节点(将标记移动到指定位置) osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform(); pat->setPosition(position); // 设置模型局部坐标位置 pat->addChild(sphereGeode); pat->addChild(textGeode); // 直接返回定位变换PAT节点 return pat.release(); // group->addChild(pat); // return group.release(); } // 创建模型包围盒(绿色线框) osg::Node* ModelManger::createBoundingBox(osg::Node* node) { // 计算模型边界 osg::ComputeBoundsVisitor cbv; node->accept(cbv); osg::BoundingBox bb = cbv.getBoundingBox(); // 创建几何体 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); // 添加8个顶点 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(); vertices->push_back(osg::Vec3(bb.xMin(), bb.yMin(), bb.zMin())); vertices->push_back(osg::Vec3(bb.xMax(), bb.yMin(), bb.zMin())); vertices->push_back(osg::Vec3(bb.xMax(), bb.yMax(), bb.zMin())); vertices->push_back(osg::Vec3(bb.xMin(), bb.yMax(), bb.zMin())); vertices->push_back(osg::Vec3(bb.xMin(), bb.yMin(), bb.zMax())); vertices->push_back(osg::Vec3(bb.xMax(), bb.yMin(), bb.zMax())); vertices->push_back(osg::Vec3(bb.xMax(), bb.yMax(), bb.zMax())); vertices->push_back(osg::Vec3(bb.xMin(), bb.yMax(), bb.zMax())); geom->setVertexArray(vertices); // 添加边索引(12条边) osg::ref_ptr<osg::DrawElementsUInt> lines = new osg::DrawElementsUInt(osg::PrimitiveSet::LINES); const int indices[] = { 0,1, 1,2, 2,3, 3,0, // 底面 4,5, 5,6, 6,7, 7,4, // 顶面 0,4, 1,5, 2,6, 3,7 // 侧面 }; for (int i = 0; i < 24; ++i) lines->push_back(indices[i]); geom->addPrimitiveSet(lines); // 设置颜色(绿色) osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(); colors->push_back(osg::Vec4(0,1,0,1)); geom->setColorArray(colors, osg::Array::BIND_OVERALL); // 设置线宽 osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth(2.0f); geom->getOrCreateStateSet()->setAttributeAndModes(lineWidth); // 创建几何节点 osg::ref_ptr<osg::Geode> geode = new osg::Geode(); geode->addDrawable(geom); return geode.release(); } std::vector<ModelManger::AnchorPoint> ModelManger::getAnchorPointsFromJson(const QString &jsonPath, bool isTower) { std::vector<AnchorPoint> points; QFile jsonFile(jsonPath); if (!jsonFile.open(QIODevice::ReadOnly)) { qWarning() << "无法打开JSON文件:" << jsonPath; return points; } QJsonDocument doc = QJsonDocument::fromJson(jsonFile.readAll()); if (doc.isNull()) { qWarning() << "无效的JSON格式:" << jsonPath; return points; } QJsonObject root = doc.object(); if (isTower) { // 解析塔模型的标记点 (来自"Tower.Head.HeadList[0].Property.Hanging_Points") QJsonObject tower = root.value("Tower").toObject(); QJsonObject head = tower.value("Head").toObject(); QJsonArray headList = head.value("HeadList").toArray(); if (!headList.isEmpty()) { QJsonObject firstHead = headList[0].toObject(); QJsonObject property = firstHead.value("Property").toObject(); QJsonArray hangingPoints = property.value("Hanging_Points").toArray(); for (const QJsonValue& ptVal : hangingPoints) { QJsonObject ptObj = ptVal.toObject(); AnchorPoint pt; pt.name = ptObj["name"].toString(); pt.type = ""; // 塔模型没有类型字段 pt.x = ptObj["x"].toDouble(); pt.y = ptObj["y"].toDouble(); pt.z = ptObj["z"].toDouble(); points.push_back(pt); } } } else { // 解析fit模型的标记点 (来自"Locations") QJsonArray locations = root.value("Locations").toArray(); for (const QJsonValue& locVal : locations) { QJsonObject locObj = locVal.toObject(); AnchorPoint pt; pt.name = locObj["name"].toString(); pt.type = locObj["Type"].toString(); // 保存类型 pt.x = locObj["x"].toString().toDouble(); // 注意:x,y,z是字符串类型 pt.y = locObj["y"].toString().toDouble(); pt.z = locObj["z"].toString().toDouble(); points.push_back(pt); } } // 添加原点作为参考点 AnchorPoint origin; origin.name = "原点"; origin.type = "origin"; origin.x = 0; origin.y = 0; origin.z = 0; points.push_back(origin); return points; } // 实现颜色设置方法 void ModelManger::applyColorToNode(osg::Node* node, const osg::Vec4& color) { if (!node) return; // 创建或获取状态集 osg::StateSet* stateSet = node->getOrCreateStateSet(); // 创建材质 osg::ref_ptr<osg::Material> material = new osg::Material; material->setAmbient(osg::Material::FRONT_AND_BACK, color); material->setDiffuse(osg::Material::FRONT_AND_BACK, color); material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0.1, 0.1, 0.1, 1.0)); material->setShininess(osg::Material::FRONT_AND_BACK, 20.0); // 设置材质 stateSet->setAttributeAndModes(material, osg::StateAttribute::ON); // 处理透明效果 if (color.a() < 1.0f) { stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); } else { stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF); } } void ModelManger::setModelColor(const QString& modelName, const osg::Vec4& color) { auto it = m_towerModels.find(modelName); if (it == m_towerModels.end()) { qDebug() << "未找到塔模型:" << modelName; return; } TowerModelInfo& info = it->second; applyColorToNode(info.modelXform, color); } void ModelManger::setFitModelColor(const QString& towerName, const QString& pointName, const osg::Vec4& color) { auto towerIt = m_towerModels.find(towerName); if (towerIt == m_towerModels.end()) { qDebug() << "未找到塔模型:" << towerName; return; } TowerModelInfo& info = towerIt->second; auto fitIt = info.fitModels.find(pointName); if (fitIt == info.fitModels.end()) { qDebug() << "未找到附属模型:" << pointName << "在塔模型" << towerName; return; } applyColorToNode(fitIt->second, color); } void ModelManger::yflTest(QString modelName, double lon, double lat, double alt, double ang, const QString &modelPath) { qDebug() << "开始测试:"; qDebug() << " 模型名称:" << modelName; qDebug() << " 位置:" << lon << "," << lat << "," << alt; qDebug() << " 旋转角度:" << ang << "度"; qDebug() << " 模型路径:" << modelPath; // 只加载塔模型,不加载fit模型 bool result = loadModelTower( lon, lat, alt, // 经纬度和高程 GISDATA"bimmodel/tower/21178.obj", // 模型路径 modelName, // 模型名称 0, 0, ang // 旋转角度 ); if (result) { qDebug() << "塔模型加载成功"; } else { qDebug() << "塔模型加载失败"; } // 设置塔模型为红色 // setModelColor(modelName, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //在塔模型的"导1"位置加载fit模型 loadModelFitForTower( GISDATA"bimmodel/fit/166817290949493765.obj", // fit模型路径 modelName, // 目标塔名称 "跳1-1", // 目标标记点 -90, 0, 90 // 旋转角度 ); loadModelFitForTower( GISDATA"bimmodel/fit/166817290949493765.obj", modelName, "跳1-2", -90, 0, 90 ); loadModelFitForTower( GISDATA"bimmodel/fit/166817290949493765.obj", modelName, "跳1-3", -90, 0, 90 ); loadModelFitForTower( GISDATA"bimmodel/fit/166817290986193925.obj", modelName, "前导1", -90, 0, 90 ); loadModelFitForTower( GISDATA"bimmodel/fit/166817290986193925.obj", modelName, "后导1", -90, 0, -90 ); // 设置模型为半透明蓝色 setFitModelColor(modelName, "前导1", osg::Vec4(0.0f, 0.0f, 1.0f, 0.7f)); setFitModelColor(modelName, "跳1-2", osg::Vec4(0.0f, 0.0f, 1.0f, 0.7f)); setFitModelColor(modelName, "后导1", osg::Vec4(0.0f, 0.0f, 1.0f, 0.7f)); // 获取塔模型标记点 QVariantList points = getModelAnchorPoints(modelName); for (int i = 0; i < points.size (); i++) { qDebug()<<"塔模型标记点:"<<points[i]; } // 获取fit模型标记点 QVariantList pointfits = getFitAnchorPoints(modelName, "前导1"); for (int j = 0; j < pointfits.size (); j++) { qDebug()<<"Fit模型标记点:"<<pointfits[j]; } //连线测试 xx塔的xx挂点上串子的xx点 line to xx塔的xx挂点上串子的xx点 // 添加连线 drawLine("line1", modelName, "前导1", "TX", modelName, "跳1-1", "DAX", osg::Vec4(1, 0, 0, 1), // 红色 3.0f); drawLine("line2", modelName, "跳1-1", "DAX", modelName, "跳1-2", "DAX", osg::Vec4(0, 1, 0, 1), // 绿色 2.0f); drawLine("line3", modelName, "跳1-2", "DAX", modelName, "跳1-3", "DAX", osg::Vec4(0, 0, 1, 1), // 蓝色 2.5f); drawLine("line4", modelName, "跳1-3", "DAX", modelName, "后导1", "TX", osg::Vec4(1, 1, 0, 1), // 黄色 3.0f); } // 计算所有标记点的地理坐标 void ModelManger::calculateAllAnchorPoints() { // 计算塔模型标记点 for (auto& towerPair : m_towerModels) { TowerModelInfo& towerInfo = towerPair.second; for (auto& anchorPoint : towerInfo.anchorPoints) { if (anchorPoint.markerNode) { anchorPoint.geoPoint = calculateNodeGeoPoint(anchorPoint.markerNode); if (anchorPoint.geoPoint.isValid()) { qDebug() << "塔模型标记点" << anchorPoint.name << "位置: " <<QString::number( anchorPoint.geoPoint.x(),'f',8) << ", " <<QString::number( anchorPoint.geoPoint.y(),'f',8) << ", " <<QString::number( anchorPoint.geoPoint.z(),'f',8); } } } } // 计算附属模型标记点 for (auto& fitPair : m_fitModelsInfo) { FitModelInfo& fitInfo = fitPair.second; for (auto& anchorPoint : fitInfo.anchorPoints) { if (anchorPoint.markerNode) { anchorPoint.geoPoint = calculateNodeGeoPoint(anchorPoint.markerNode); if (anchorPoint.geoPoint.isValid()) { qDebug() << "附属模型标记点" << anchorPoint.name << "位置: " <<QString::number( anchorPoint.geoPoint.x(),'f',8) << ", " <<QString::number( anchorPoint.geoPoint.y(),'f',8) << ", " <<QString::number( anchorPoint.geoPoint.z(),'f',8); } } } } } // // 计算节点的地理坐标 // osgEarth::GeoPoint ModelManger::calculateNodeGeoPoint(osg::Node* node) const { // if (!node || !m_mapNode) return osgEarth::GeoPoint::INVALID; // // 获取节点的父路径列表 // osg::NodePathList nodePaths = node->getParentalNodePaths(); // if (nodePaths.empty()) return osgEarth::GeoPoint::INVALID; // // 使用第条父路径(通常只有个) // const osg::NodePath& nodePath = nodePaths.front(); // osg::Matrix worldMatrix = osg::computeLocalToWorld(nodePath); // // // 计算原点在世界坐标系中的位置 // // osg::Vec3d worldPosition = osg::Vec3d(0, 0, 0) * worldMatrix; // // 获取节点的实际位置 // osg::Vec3d worldPosition = node->getBound().center() * worldMatrix; // // 转换为地理坐标 // osgEarth::GeoPoint geoPoint; // geoPoint.fromWorld(m_mapNode->getMapSRS(), worldPosition); // return geoPoint; // } osgEarth::GeoPoint ModelManger::calculateNodeGeoPoint(osg::Node* node) const { // if (!node || !m_mapNode) return osgEarth::GeoPoint::INVALID; // osg::NodePathList nodePaths = node->getParentalNodePaths(); // if (nodePaths.empty()) return osgEarth::GeoPoint::INVALID; // const osg::NodePath& nodePath = nodePaths.front(); // osg::Matrix worldMatrix = osg::computeLocalToWorld(nodePath); // // 关键修复:获取节点实际位置 // osg::Vec3d localPos = node->getBound().center(); // osg::Vec3d worldPosition = localPos * worldMatrix; // osgEarth::GeoPoint geoPoint; // geoPoint.fromWorld(m_mapNode->getMapSRS(), worldPosition); // return geoPoint; if (!node || !m_mapNode) return osgEarth::GeoPoint::INVALID; // 获取节点的世界变换矩阵 osg::NodePathList nodePaths = node->getParentalNodePaths(); if (nodePaths.empty()) return osgEarth::GeoPoint::INVALID; osg::Matrix worldMatrix = osg::computeLocalToWorld(nodePaths.front()); // 关键修改:获取标记点的实际位置(PAT节点设置的位置) osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>(node); if (pat) { // 获取PAT节点设置的位置(模型局部坐标系) osg::Vec3d markerPos = pat->getPosition(); // 转换为世界坐标系 osg::Vec3d worldPosition = markerPos * worldMatrix; osgEarth::GeoPoint geoPoint; geoPoint.fromWorld(m_mapNode->getMapSRS(), worldPosition); return geoPoint; } return osgEarth::GeoPoint::INVALID; } // 获取塔模型标记点信息 QVariantList ModelManger::getModelAnchorPoints(const QString& modelName) const { QMutexLocker locker(&m_dataMutex); QVariantList points; auto it = m_towerModels.find(modelName); if (it == m_towerModels.end()) return points; for (const auto& pt : it->second.anchorPoints) { QVariantMap pointInfo; pointInfo["name"] = pt.name; pointInfo["type"] = pt.type; if (pt.geoPoint.isValid()) { pointInfo["lon"] = pt.geoPoint.x(); pointInfo["lat"] = pt.geoPoint.y(); pointInfo["alt"] = pt.geoPoint.z(); } else { pointInfo["lon"] = 0; pointInfo["lat"] = 0; pointInfo["alt"] = 0; } points.append(pointInfo); } return points; } // 获取附属模型标记点信息 QVariantList ModelManger::getFitAnchorPoints( const QString& towerName, const QString& fitName) const { QVariantList points; // 构建唯标识符 QString fullId = towerName + "::" + fitName; auto it = m_fitModelsInfo.find(fullId); if (it == m_fitModelsInfo.end()) return points; for (const auto& pt : it->second.anchorPoints) { QVariantMap pointInfo; pointInfo["name"] = pt.name; pointInfo["type"] = pt.type; if (pt.geoPoint.isValid()) { pointInfo["lon"] = pt.geoPoint.x(); pointInfo["lat"] = pt.geoPoint.y(); pointInfo["alt"] = pt.geoPoint.z(); } else { pointInfo["lon"] = 0; pointInfo["lat"] = 0; pointInfo["alt"] = 0; } points.append(pointInfo); } return points; } //line // 绘制两点之间的线段 bool ModelManger::drawLine(const QString& lineName, const QString& startModel, const QString& startPoint, const QString& startType, const QString& endModel, const QString& endPoint, const QString& endType, const osg::Vec4& color, float width) { // 删除已存在的同名线段 removeLine(lineName); // 获取起点和终点的地理坐标 osgEarth::GeoPoint startGeo, endGeo; if (!findAnchorPoint(startModel, startPoint, startType, startGeo) || !findAnchorPoint(endModel, endPoint, endType, endGeo)) { return false; } qDebug() << "绘制线段: " << lineName << "\n 起点: (" << startGeo.x() << ", " << startGeo.y() << ", " << startGeo.z() << ")" << "\n 终点: (" << endGeo.x() << ", " << endGeo.y() << ", " << endGeo.z() << ")"; // 创建线特征 osgEarth::LineString* line = new osgEarth::LineString(); line->push_back(startGeo.x (),startGeo.y (),startGeo.z ()); line->push_back(endGeo.x (),endGeo.y (),endGeo.z ()); // 创建样式 osgEarth::Style style; style.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = color; style.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = width; style.getOrCreate<osgEarth::LineSymbol>()->stroke()->widthUnits() = osgEarth::Units::PIXELS; // 设置高度模式为绝对高度 style.getOrCreate<osgEarth::AltitudeSymbol>()->clamping() = osgEarth::AltitudeSymbol::CLAMP_ABSOLUTE; style.getOrCreate<osgEarth::AltitudeSymbol>()->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE; // 创建特征 osgEarth::Features::Feature* feature = new osgEarth::Features::Feature(line, m_mapNode->getMapSRS(), style); feature->geoInterp() = osgEarth::GEOINTERP_GREAT_CIRCLE; // 使用大圆航线 // 创建特征节点 osgEarth::Annotation::FeatureNode* featureNode = new osgEarth::Annotation::FeatureNode(feature); featureNode->setMapNode(m_mapNode.get ()); // 添加到场景 m_mapNode->addChild(featureNode); // 存储线段信息 LineSegment segment; segment.featureNode = featureNode; m_lineSegments[lineName] = segment; return true; } // 删除线段 bool ModelManger::removeLine(const QString& lineName) { auto it = m_lineSegments.find(lineName); if (it != m_lineSegments.end()) { m_mapNode->removeChild(it->second.featureNode); m_lineSegments.erase(it); qDebug() << "已删除线段: " << lineName; return true; } return false; } 上述代码运行ModelManger::yflTest后连线不准确,没有在对应的点位置,检查代码找出问题,并修改(输出完整.h .cpp)
最新发布
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值