#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)
最新发布