modified panel

This commit is contained in:
pimin 2025-11-02 11:36:10 +08:00
commit 630552b156
43 changed files with 1320 additions and 697 deletions

View File

@ -3,8 +3,10 @@
#include "common/RecourceHelper.h" #include "common/RecourceHelper.h"
#include "workspace/WorkSpaceManager.h" #include "workspace/WorkSpaceManager.h"
#include "entities/EntitiesManager.h" #include "entities/EntitiesManager.h"
#include "entities/EntityFactory.h"
#include "viewer/OsgViewer.h" #include "viewer/OsgViewer.h"
#include "scene/MeshManager.h" #include "scene/MeshManager.h"
#include "workspace/PresetModelConfigParser.h"
#include "network/NetDriver.h" #include "network/NetDriver.h"
#include "python/PythonModule.h" #include "python/PythonModule.h"
@ -30,9 +32,11 @@ QString Application::GetBinPath() {
void Application::Init() { void Application::Init() {
Singleton<MeshManager>::Create(this); Singleton<MeshManager>::Create(this);
Singleton<RecourceHelper>::Create(this); Singleton<RecourceHelper>::Create(this);
Singleton<EntityFactory>::Create(this);
Singleton<EntitiesManager>::Create(this); Singleton<EntitiesManager>::Create(this);
Singleton<WorkSpaceManager>::Create(this); Singleton<WorkSpaceManager>::Create(this);
Singleton<NetDriver>::Create(this); Singleton<NetDriver>::Create(this);
Singleton<PresetModelConfigParser>::Create(this);
//Singleton<PythonModule>::Create(this); //Singleton<PythonModule>::Create(this);
connect(&timer_, &QTimer::timeout, this, &Application::OnTimeout); connect(&timer_, &QTimer::timeout, this, &Application::OnTimeout);
@ -46,8 +50,10 @@ void Application::OnTimeout() {
void Application::Uninit() { void Application::Uninit() {
//Singleton<PythonModule>::Destory(); //Singleton<PythonModule>::Destory();
Singleton<NetDriver>::Destory(); Singleton<NetDriver>::Destory();
Singleton<PresetModelConfigParser>::Destory();
Singleton<WorkSpaceManager>::Destory(); Singleton<WorkSpaceManager>::Destory();
Singleton<EntitiesManager>::Destory(); Singleton<EntitiesManager>::Destory();
Singleton<EntityFactory>::Destory();
Singleton<RecourceHelper>::Destory(); Singleton<RecourceHelper>::Destory();
Singleton<MeshManager>::Destory(); Singleton<MeshManager>::Destory();
} }

View File

@ -7,6 +7,8 @@
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "entities/Entity.h" #include "entities/Entity.h"
#include "entities/ComponentFactory.h" #include "entities/ComponentFactory.h"
#include "entities/EntityFactory.h"
#include "entities/EntityRegistration.h"
#include "xml/tinyxml2.h" #include "xml/tinyxml2.h"
@ -14,6 +16,7 @@ template<> EntitiesManager* Singleton<EntitiesManager>::instance_ = nullptr;
EntitiesManager::EntitiesManager(QObject* parent) EntitiesManager::EntitiesManager(QObject* parent)
: QObject(parent) { : QObject(parent) {
Initialize();
} }
EntitiesManager::~EntitiesManager() { EntitiesManager::~EntitiesManager() {
@ -107,9 +110,6 @@ Entity* EntitiesManager::CreateMesh(const QString& mesh) {
conponent->SetAttribute("mesh", mesh.toStdString().c_str()); conponent->SetAttribute("mesh", mesh.toStdString().c_str());
conponent->AttachEntity(entity); conponent->AttachEntity(entity);
//conponent = ComponentFactory::Create("PathComponent", conponent);
//conponent->AttachEntity(entity);
return entity; return entity;
} }
@ -148,3 +148,78 @@ void EntitiesManager::RemoveEntity(Entity* entity) {
entities_.erase(entity->GetUUid()); entities_.erase(entity->GetUUid());
} }
void EntitiesManager::Initialize() {
if (!initialized_) {
EntityRegistration::RegisterAllEntities();
initialized_ = true;
LOG_INFO("EntitiesManager::Initialize - Entity factory initialized");
}
}
Entity* EntitiesManager::CreateEntity(const QString& type, WorkSpace* workspace) {
if (!initialized_) {
Initialize();
}
if (!workspace) {
workspace = WorkSpaceManager::Get().GetCurrent();
}
Entity* entity = EntityFactory::Get().CreateEntity(type, workspace);
if (entity) {
AddEntity(entity);
if (workspace) {
workspace->AddEntity(entity);
}
LOG_INFO("EntitiesManager::CreateEntity - Created entity of type: {}", type.toStdString());
} else {
LOG_ERROR("EntitiesManager::CreateEntity - Failed to create entity of type: {}", type.toStdString());
}
return entity;
}
Entity* EntitiesManager::CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace) {
if (!initialized_) {
Initialize();
}
if (!workspace) {
workspace = WorkSpaceManager::Get().GetCurrent();
}
Entity* entity = EntityFactory::Get().CreateEntityWithComponents(type, mesh, useLabel, workspace);
if (entity) {
AddEntity(entity);
if (workspace) {
workspace->AddEntity(entity);
}
LOG_INFO("EntitiesManager::CreateEntityWithComponents - Created entity with components of type: {}", type.toStdString());
} else {
LOG_ERROR("EntitiesManager::CreateEntityWithComponents - Failed to create entity of type: {}", type.toStdString());
}
return entity;
}
QStringList EntitiesManager::GetSupportedEntityTypes() const {
if (!initialized_) {
return QStringList();
}
return EntityFactory::Get().GetRegisteredTypes();
}
QString EntitiesManager::GetEntityDisplayName(const QString& type) const {
if (!initialized_) {
return type;
}
return EntityFactory::Get().GetDisplayName(type);
}
QString EntitiesManager::GetEntityDescription(const QString& type) const {
if (!initialized_) {
return QString();
}
return EntityFactory::Get().GetDescription(type);
}

View File

@ -9,6 +9,7 @@
#include "xml/tinyxml2.h" #include "xml/tinyxml2.h"
class Entity; class Entity;
class WorkSpace;
class EntitiesManager : public QObject, public Singleton<EntitiesManager> { class EntitiesManager : public QObject, public Singleton<EntitiesManager> {
Q_OBJECT Q_OBJECT
@ -18,12 +19,26 @@ public:
~EntitiesManager(); ~EntitiesManager();
void OnDestory(); void OnDestory();
// Initialize entity factory
void Initialize();
bool Contains(const QString& name) const; bool Contains(const QString& name) const;
bool Parse(const tinyxml2::XMLElement* element, class WorkSpace* workspce); bool Parse(const tinyxml2::XMLElement* element, class WorkSpace* workspce);
// Legacy methods (for backward compatibility)
Entity* Create(const QString& name); Entity* Create(const QString& name);
Entity* CreateMesh(const QString& mesh); Entity* CreateMesh(const QString& mesh);
// New factory methods
Entity* CreateEntity(const QString& type, WorkSpace* workspace = nullptr);
Entity* CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace = nullptr);
// Get supported entity types
QStringList GetSupportedEntityTypes() const;
QString GetEntityDisplayName(const QString& type) const;
QString GetEntityDescription(const QString& type) const;
bool DeleteEntity(Entity* entity); bool DeleteEntity(Entity* entity);
Entity* GetEntity(const QString& uuid); Entity* GetEntity(const QString& uuid);
@ -36,5 +51,5 @@ protected:
private: private:
std::unordered_map<QString, Entity*> entities_; std::unordered_map<QString, Entity*> entities_;
bool initialized_{false};
}; };

View File

@ -0,0 +1,129 @@
#include "entities/EntityFactory.h"
#include "entities/ComponentFactory.h"
#include "common/SpdLogger.h"
#include "workspace/WorkSpace.h"
#include <QStringList>
template<> EntityFactory* Singleton<EntityFactory>::instance_ = nullptr;
Entity* EntityFactory::CreateEntity(const QString& type, WorkSpace* workspace) {
auto it = creators_.find(type);
if (it == creators_.end()) {
LOG_WARN("EntityFactory::CreateEntity - Unknown entity type: {}", type.toStdString());
return nullptr;
}
Entity* entity = it->second->CreateEntity(workspace);
if (!entity) {
LOG_ERROR("EntityFactory::CreateEntity - Failed to create entity of type: {}", type.toStdString());
return nullptr;
}
LOG_INFO("EntityFactory::CreateEntity - Successfully created entity of type: {}", type.toStdString());
return entity;
}
Entity* EntityFactory::CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace) {
Entity* entity = CreateEntity(type, workspace);
if (!entity) {
return nullptr;
}
auto it = creators_.find(type);
if (it == creators_.end()) {
return entity;
}
// Get default mesh
QString defaultMesh = it->second->GetDefaultMesh();
if (!mesh.isEmpty()) {
defaultMesh = mesh;
}
if (!defaultMesh.isEmpty()) {
SceneComponent* meshComponent = ComponentFactory::Create("MeshComponent", nullptr);
if (meshComponent) {
meshComponent->SetAttribute("mesh", defaultMesh.toLocal8Bit());
meshComponent->AttachEntity(entity);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added MeshComponent with mesh: {}", defaultMesh.toStdString());
}
}
if (useLabel) {
SceneComponent* rootComponent = entity->GetRootComponent();
if (nullptr == rootComponent) {
SceneComponent* meshComponent = ComponentFactory::Create("LabelComponent", nullptr);
if (meshComponent) {
meshComponent->AttachEntity(entity);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added LabelComponent with mesh: {}", defaultMesh.toStdString());
}
}
else {
SceneComponent* LabelComponent = ComponentFactory::Create("LabelComponent", rootComponent);
if (LabelComponent) {
LabelComponent->AttachTo(rootComponent);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added LabelComponent with mesh: {}", defaultMesh.toStdString());
}
}
}
// Add required components
QStringList requiredComponents = it->second->GetRequiredComponents();
SceneComponent* rootComponent = entity->GetRootComponent();
for (int i = 0; i < requiredComponents.size(); ++i) {
QString componentType = requiredComponents.at(i);
SceneComponent* component = ComponentFactory::Create(componentType, rootComponent);
if (component && rootComponent) {
component->AttachTo(rootComponent);
LOG_INFO("EntityFactory::CreateEntityWithComponents - Added component: {}", componentType.toStdString());
} else {
LOG_WARN("EntityFactory::CreateEntityWithComponents - Failed to create component: {}", componentType.toStdString());
}
}
return entity;
}
QStringList EntityFactory::GetRegisteredTypes() const {
QStringList types;
for (auto it = creators_.begin(); it != creators_.end(); ++it) {
types.append(it->first);
}
return types;
}
QString EntityFactory::GetDisplayName(const QString& type) const {
auto it = creators_.find(type);
if (it != creators_.end()) {
return it->second->GetDisplayName();
}
return type; // 返回类型名作为默认显示名
}
QString EntityFactory::GetDescription(const QString& type) const {
auto it = creators_.find(type);
if (it != creators_.end()) {
return it->second->GetDescription();
}
return QString();
}
QString EntityFactory::GetDefaultMesh(const QString& type) const {
auto it = creators_.find(type);
if (it != creators_.end()) {
return it->second->GetDefaultMesh();
}
return QString();
}
QStringList EntityFactory::GetRequiredComponents(const QString& type) const {
auto it = creators_.find(type);
if (it != creators_.end()) {
return it->second->GetRequiredComponents();
}
return QStringList();
}
bool EntityFactory::IsTypeSupported(const QString& type) const {
return creators_.find(type) != creators_.end();
}

View File

@ -0,0 +1,86 @@
#pragma once
#include <functional>
#include <unordered_map>
#include <memory>
#include <QString>
#include "app/Singleton.h"
#include "entities/Entity.h"
class WorkSpace;
class IEntityCreator {
public:
virtual ~IEntityCreator() = default;
virtual Entity* CreateEntity(WorkSpace* workspace) = 0;
virtual QString GetEntityType() const = 0;
virtual QString GetDisplayName() const = 0;
virtual QString GetDescription() const = 0;
virtual QString GetDefaultMesh() const = 0;
virtual QStringList GetRequiredComponents() const = 0;
};
template<typename T>
class EntityCreator : public IEntityCreator {
public:
EntityCreator(const QString& type, const QString& displayName,
const QString& description, const QString& defaultMesh,
const QStringList& requiredComponents = QStringList())
: entityType_(type), displayName_(displayName), description_(description),
defaultMesh_(defaultMesh), requiredComponents_(requiredComponents) {}
Entity* CreateEntity(WorkSpace* workspace) override {
return new T(workspace);
}
QString GetEntityType() const override { return entityType_; }
QString GetDisplayName() const override { return displayName_; }
QString GetDescription() const override { return description_; }
QString GetDefaultMesh() const override { return defaultMesh_; }
QStringList GetRequiredComponents() const override { return requiredComponents_; }
private:
QString entityType_;
QString displayName_;
QString description_;
QString defaultMesh_;
QStringList requiredComponents_;
};
class EntityFactory : public Singleton<EntityFactory> {
public:
EntityFactory() = default;
explicit EntityFactory(class Application* app) : app_(app) {}
~EntityFactory() = default;
void OnDestory() { }
template<typename T>
void RegisterEntity(const QString& type, const QString& displayName,
const QString& description, const QString& defaultMesh,
const QStringList& requiredComponents = QStringList()) {
auto creator = std::make_unique<EntityCreator<T>>(type, displayName, description, defaultMesh, requiredComponents);
creators_[type] = std::move(creator);
}
Entity* CreateEntity(const QString& type, WorkSpace* workspace);
Entity* CreateEntityWithComponents(const QString& type, const QString& mesh, bool useLabel, WorkSpace* workspace);
QStringList GetRegisteredTypes() const;
QString GetDisplayName(const QString& type) const;
QString GetDescription(const QString& type) const;
QString GetDefaultMesh(const QString& type) const;
QStringList GetRequiredComponents(const QString& type) const;
bool IsTypeSupported(const QString& type) const;
private:
std::unordered_map<QString, std::unique_ptr<IEntityCreator>> creators_;
class Application* app_ = nullptr;
};
#define REGISTER_ENTITY(EntityClass, Type, DisplayName, Description, DefaultMesh, ...) \
EntityFactory::Get().RegisterEntity<EntityClass>(Type, DisplayName, Description, DefaultMesh, QStringList{__VA_ARGS__})

View File

@ -0,0 +1,88 @@
#include "entities/EntityRegistration.h"
#include "common/SpdLogger.h"
void EntityRegistration::RegisterAllEntities() {
EntityFactory& factory = EntityFactory::Get();
// Register missile entity
factory.RegisterEntity<MissileEntity>("Missile",
"Missile",
"Military missile entity with target tracking and flight capabilities",
"models/missile.osg",
QStringList() << "LabelComponent" << "TrajectoryComponent"
);
// Register satellite entity
factory.RegisterEntity<SatelliteEntity>("Satellite",
"Satellite",
"Artificial satellite entity with orbital motion and communication capabilities",
"models/satellite.osg",
QStringList() << "LabelComponent" << "ConeWaveComponent" << "OrbitComponent"
);
// Register ship entity
factory.RegisterEntity<ShipEntity>("Ship",
"Ship",
"Naval vessel entity with maritime navigation and combat capabilities",
"models/ship.osg",
QStringList() << "LabelComponent" << "NavigationComponent"
);
// Register radar entity
factory.RegisterEntity<RadarEntity>("Radar",
"Radar",
"Radar system entity with target detection and tracking capabilities",
"models/radar.osg",
QStringList() << "LabelComponent" << "RadarComponent" << "ScanComponent"
);
// Register vehicle entity
factory.RegisterEntity<VehicleEntity>("Vehicle",
"Vehicle",
"Generic vehicle entity configurable for different types of transportation",
"models/vehicle.osg",
QStringList() << "LabelComponent" << "MovementComponent"
);
// Register aircraft entity
factory.RegisterEntity<VehicleEntity>("Aircraft",
"Aircraft",
"Aviation entity with flight and aerial combat capabilities",
"models/aircraft.osg",
QStringList() << "LabelComponent" << "FlightComponent" << "NavigationComponent"
);
// Register tank entity
factory.RegisterEntity<VehicleEntity>("Tank",
"Tank",
"Armored vehicle entity with ground combat capabilities",
"models/tank.osg",
QStringList() << "LabelComponent" << "ArmorComponent" << "WeaponComponent"
);
// Register submarine entity
factory.RegisterEntity<ShipEntity>("Submarine",
"Submarine",
"Submarine entity with underwater combat capabilities",
"models/submarine.osg",
QStringList() << "LabelComponent" << "SonarComponent" << "TorpedoComponent"
);
// Register base entity
factory.RegisterEntity<Entity>("Base",
"Base",
"Military base entity serving as command and logistics center",
"models/base.osg",
QStringList() << "LabelComponent" << "CommandComponent" << "DefenseComponent"
);
// Register generic entity (for backward compatibility)
factory.RegisterEntity<Entity>("Entity",
"Entity",
"Basic entity type extensible through component system",
"models/default.osg",
QStringList() << "LabelComponent"
);
LOG_INFO("EntityRegistration::RegisterAllEntities - All entity types registered successfully");
}

View File

@ -0,0 +1,11 @@
#pragma once
#include "entities/EntityFactory.h"
#include "entities/SpecializedEntities.h"
// Entity registration class
class EntityRegistration {
public:
// Register all entity types
static void RegisterAllEntities();
};

View File

@ -0,0 +1,60 @@
#include "entities/SpecializedEntities.h"
#include <cmath>
#include "common/SpdLogger.h"
MissileEntity::MissileEntity(WorkSpace* workspace)
: Entity(workspace) {
SetName("Missile");
LOG_INFO("MissileEntity created");
}
MissileEntity::MissileEntity(const QString& name, QObject* parent)
: Entity(name, parent) {
LOG_INFO("MissileEntity created with name: {}", name.toStdString());
}
SatelliteEntity::SatelliteEntity(WorkSpace* workspace)
: Entity(workspace) {
SetName("Satellite");
LOG_INFO("SatelliteEntity created");
}
SatelliteEntity::SatelliteEntity(const QString& name, QObject* parent)
: Entity(name, parent) {
LOG_INFO("SatelliteEntity created with name: {}", name.toStdString());
}
ShipEntity::ShipEntity(WorkSpace* workspace)
: Entity(workspace) {
SetName("Ship");
LOG_INFO("ShipEntity created");
}
ShipEntity::ShipEntity(const QString& name, QObject* parent)
: Entity(name, parent) {
LOG_INFO("ShipEntity created with name: {}", name.toStdString());
}
RadarEntity::RadarEntity(WorkSpace* workspace)
: Entity(workspace) {
SetName("Radar");
LOG_INFO("RadarEntity created");
}
RadarEntity::RadarEntity(const QString& name, QObject* parent)
: Entity(name, parent) {
LOG_INFO("RadarEntity created with name: {}", name.toStdString());
}
VehicleEntity::VehicleEntity(WorkSpace* workspace)
: Entity(workspace) {
SetName("Vehicle");
LOG_INFO("VehicleEntity created");
}
VehicleEntity::VehicleEntity(const QString& name, QObject* parent)
: Entity(name, parent) {
LOG_INFO("VehicleEntity created with name: {}", name.toStdString());
}

View File

@ -0,0 +1,58 @@
#pragma once
#include "entities/Entity.h"
// 导弹实体
class MissileEntity : public Entity {
Q_OBJECT
public:
explicit MissileEntity(WorkSpace* workspace);
explicit MissileEntity(const QString& name, QObject* parent = nullptr);
~MissileEntity() override = default;
};
// 卫星实体
class SatelliteEntity : public Entity {
Q_OBJECT
public:
explicit SatelliteEntity(WorkSpace* workspace);
explicit SatelliteEntity(const QString& name, QObject* parent = nullptr);
~SatelliteEntity() override = default;
};
// 舰船实体
class ShipEntity : public Entity {
Q_OBJECT
public:
explicit ShipEntity(WorkSpace* workspace);
explicit ShipEntity(const QString& name, QObject* parent = nullptr);
~ShipEntity() override = default;
};
// 雷达实体
class RadarEntity : public Entity {
Q_OBJECT
public:
explicit RadarEntity(WorkSpace* workspace);
explicit RadarEntity(const QString& name, QObject* parent = nullptr);
~RadarEntity() override = default;
};
// 通用载具实体
class VehicleEntity : public Entity {
Q_OBJECT
public:
explicit VehicleEntity(WorkSpace* workspace);
explicit VehicleEntity(const QString& name, QObject* parent = nullptr);
~VehicleEntity() override = default;
};

View File

@ -103,6 +103,64 @@ osg::Viewport* OEScene::GetViewport() const {
return curentView_->getCamera()->getViewport(); return curentView_->getCamera()->getViewport();
} }
bool OEScene::ScreenToWorldCoordinate(int x, int y, osg::Vec3d* output) const {
if (nullptr == output) {
LOG_WARN("OEScene::ScreenToWorldCoordinate - worldPoint is null");
return false;
}
osg::Camera* camera = curentView_->getCamera();
if (!camera) {
LOG_WARN("OEScene::ScreenToWorldCoordinate - camera is null");
return false;
}
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y);
osgUtil::IntersectionVisitor iv(intersector.get());
camera->accept(iv);
if (intersector->containsIntersections()) {
osgUtil::LineSegmentIntersector::Intersections& intersections = intersector->getIntersections();
osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
osg::Vec3d worldPoint = intersection.getWorldIntersectPoint();
Vec3ToLocation(worldPoint, output);
LOG_INFO("OsgWidget::ScreenToWorldCoordinate - Screen({}, {}) -> World({:.6f}, {:.6f}, {:.2f})",
x, y, output->x(), output->y(), output->z());
return true;
}
LOG_WARN("OsgWidget::ScreenToWorldCoordinate - No intersection found for screen coordinates ({}, {})", x, y);
return false;
}
bool OEScene::Vec3ToLocation(const osg::Vec3& input, osg::Vec3d* output) const {
if (nullptr == output) {
LOG_WARN("OEScene::vec3ToLocation - output is null");
return false;
}
const osgEarth::SpatialReference* srs = OEScene::GetSrs();
if (!srs) {
LOG_WARN("OEScene::vec3ToLocation - spatial reference system is null");
return false;
}
osgEarth::GeoPoint geoPoint;
geoPoint.fromWorld(srs, input);
const osgEarth::SpatialReference* wgs84 = osgEarth::SpatialReference::get("wgs84");
if (wgs84) {
geoPoint = geoPoint.transform(wgs84);
}
output->set(geoPoint.x(), geoPoint.y(),geoPoint.z());
return true;
}
const osgEarth::SpatialReference* OEScene::GetSrs() { const osgEarth::SpatialReference* OEScene::GetSrs() {
dyt_check(nullptr != g_srs_); dyt_check(nullptr != g_srs_);
return g_srs_; return g_srs_;

View File

@ -35,6 +35,8 @@ public:
} }
osg::Viewport* GetViewport() const; osg::Viewport* GetViewport() const;
bool ScreenToWorldCoordinate(int x, int y, osg::Vec3d* output) const;
bool Vec3ToLocation(const osg::Vec3& input, osg::Vec3d* output) const;
static const osgEarth::SpatialReference* GetSrs(); static const osgEarth::SpatialReference* GetSrs();

View File

@ -2110,12 +2110,12 @@
<context> <context>
<name>OsgWidget</name> <name>OsgWidget</name>
<message> <message>
<location filename="../viewer/OsgWidget.cpp" line="122"/> <location filename="../viewer/OsgWidget.cpp" line="131"/>
<source>warning</source> <source>warning</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../viewer/OsgWidget.cpp" line="123"/> <location filename="../viewer/OsgWidget.cpp" line="132"/>
<source>open dyt file failed</source> <source>open dyt file failed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -2216,31 +2216,6 @@
<source>Preset Models</source> <source>Preset Models</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../ui/ModelBrowser/PresetModelPanel.ui" line="35"/>
<source>PresetModelToolBox</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/ModelBrowser/PresetModelPanel.ui" line="50"/>
<source>Ships</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/ModelBrowser/PresetModelPanel.ui" line="75"/>
<source>Satellites</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/ModelBrowser/PresetModelPanel.ui" line="100"/>
<source>Missiles</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/ModelBrowser/PresetModelPanel.ui" line="125"/>
<source>Jammers</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>PropertyBrowser</name> <name>PropertyBrowser</name>

View File

@ -42,6 +42,7 @@ void FileManagerMenu::InitConnect() {
connect(ui->menu_table_file, &QToolButton::clicked, this, &FileManagerMenu::AddTableFile); connect(ui->menu_table_file, &QToolButton::clicked, this, &FileManagerMenu::AddTableFile);
connect(ui->menu_light_file, &QToolButton::clicked, this, &FileManagerMenu::AddLightFile); connect(ui->menu_light_file, &QToolButton::clicked, this, &FileManagerMenu::AddLightFile);
connect(ui->menu_polar_file, &QToolButton::clicked, this, &FileManagerMenu::AddPolarFile); connect(ui->menu_polar_file, &QToolButton::clicked, this, &FileManagerMenu::AddPolarFile);
connect(ui->menu_image_file, &QToolButton::clicked, this, &FileManagerMenu::AddImageFile);
} }
void FileManagerMenu::NewWorkSpace() { void FileManagerMenu::NewWorkSpace() {
@ -277,7 +278,8 @@ void FileManagerMenu::AddLightFile() {
} }
} }
void FileManagerMenu::AddPolarFile() { void FileManagerMenu::AddPolarFile()
{
auto current = WorkSpaceManager::Get().GetCurrent(); auto current = WorkSpaceManager::Get().GetCurrent();
if (nullptr == current) { if (nullptr == current) {
QMessageBox::information(&MainFrame::Get(), QObject::tr("prompt"), QObject::tr("please create workspace first")); QMessageBox::information(&MainFrame::Get(), QObject::tr("prompt"), QObject::tr("please create workspace first"));
@ -291,3 +293,8 @@ void FileManagerMenu::AddPolarFile() {
SaveWorkSpace(); SaveWorkSpace();
} }
} }
void FileManagerMenu::AddImageFile()
{
}

View File

@ -26,6 +26,7 @@ protected:
void AddTableFile(); void AddTableFile();
void AddLightFile(); void AddLightFile();
void AddPolarFile(); void AddPolarFile();
void AddImageFile();
signals: signals:
void LoadDyt(const QString& path); void LoadDyt(const QString& path);

View File

@ -104,6 +104,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="menu_image_file">
<property name="toolTip">
<string>new image file</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -0,0 +1,146 @@
#include "ui/ModelBrowser/PresetModelListWidget.h"
#include <QListWidgetItem>
#include <QDrag>
#include <QMimeData>
#include <QPainter>
#include "common/RecourceHelper.h"
#include "common/SpdLogger.h"
PresetModelListWidget::PresetModelListWidget(QWidget* parent)
: QListWidget(parent)
{
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
// Configure list widget for icon-text vertical layout
setViewMode(QListView::IconMode);
setResizeMode(QListView::Adjust);
setMovement(QListView::Static);
setGridSize(QSize(100, 80)); // Width x Height for each item
setIconSize(QSize(48, 48)); // Icon size
setSpacing(5); // Spacing between items
}
void PresetModelListWidget::startDrag(Qt::DropActions supportedActions) {
QListWidgetItem* item = currentItem();
if (nullptr == item) {
return;
}
QString modelType = property("modelType").toString();
QString modelName = item->data(Qt::UserRole).toString();
if (modelName.isEmpty()) {
modelName = item->text(); // Fallback to item text
}
QMimeData* mimeData = new QMimeData;
QString dragData = QString("%1|%2").arg(modelType, modelName);
mimeData->setData("application/x-preset-model", dragData.toUtf8());
// Create drag object
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
// Create drag pixmap with icon on top and text below
const int iconSize = 32;
const int textHeight = 20;
const int totalWidth = 80;
const int totalHeight = iconSize + textHeight + 5; // 5px spacing between icon and text
QPixmap pixmap(totalWidth, totalHeight);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
// Draw semi-transparent background
painter.setBrush(QColor(255, 255, 255, 50)); // White with 70% opacity
painter.setPen(QPen(QColor(200, 200, 200, 200), 1)); // Light gray border
painter.drawRoundedRect(2, 2, totalWidth - 4, totalHeight - 4, 4, 4);
// Draw icon at the top center
QPixmap iconPixmap = item->icon().pixmap(iconSize, iconSize);
if (!iconPixmap.isNull()) {
int iconX = (totalWidth - iconSize) / 2;
painter.drawPixmap(iconX, 0, iconPixmap);
} else {
// Draw a default placeholder icon
int iconX = (totalWidth - iconSize) / 2;
painter.setPen(QPen(Qt::gray, 2));
painter.setBrush(Qt::lightGray);
painter.drawRect(iconX, 0, iconSize, iconSize);
painter.setPen(Qt::black);
painter.drawText(iconX, 0, iconSize, iconSize, Qt::AlignCenter, "?");
}
// Draw text below the icon
painter.setPen(Qt::black);
QFont font = painter.font();
font.setPointSize(8);
painter.setFont(font);
QRect textRect(0, iconSize + 5, totalWidth, textHeight);
painter.drawText(textRect, Qt::AlignCenter | Qt::TextWordWrap, item->text());
drag->setPixmap(pixmap);
// Set hot spot to the center of the icon (not the entire pixmap)
int hotSpotX = totalWidth / 2;
int hotSpotY = iconSize / 2; // Center of the icon part only
drag->setHotSpot(QPoint(hotSpotX, hotSpotY));
// Execute drag
drag->exec(Qt::CopyAction);
}
void PresetModelListWidget::setModelType(const QString& modelType) {
modelType_ = modelType;
setProperty("modelType", modelType_);
}
QString PresetModelListWidget::getModelType() const {
return modelType_;
}
void PresetModelListWidget::setModelList(const QVector<ModelInfo>& models) {
modelList_ = models;
clear();
for (const ModelInfo& modelInfo : models) {
if (!modelInfo.enabled) continue; // Skip disabled models
QListWidgetItem* item = new QListWidgetItem(modelInfo.displayName.isEmpty() ? modelInfo.name : modelInfo.displayName);
item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
// Use icon from ModelInfo if available
if (!modelInfo.icon.isEmpty()) {
QString presetsPath = QString("%1/%2").arg(RecourceHelper::Get().GetResourcesPath(), modelInfo.icon);
QIcon icon(presetsPath);
item->setIcon(icon);
} else {
// Create a default icon if no icon is specified
QPixmap pixmap(48, 48);
pixmap.fill(Qt::lightGray);
QPainter painter(&pixmap);
painter.setPen(Qt::black);
painter.drawRect(0, 0, 47, 47);
painter.drawText(pixmap.rect(), Qt::AlignCenter, "?");
item->setIcon(QIcon(pixmap));
}
item->setToolTip(modelInfo.description.isEmpty() ? modelInfo.name : modelInfo.description);
// Store model name as simple string
item->setData(Qt::UserRole, modelInfo.name);
addItem(item);
}
}
QVector<ModelInfo> PresetModelListWidget::getModelList() const {
return modelList_;
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <QListWidget>
#include <QString>
#include "workspace/ModelInfo.h"
class PresetModelListWidget : public QListWidget
{
Q_OBJECT
public:
explicit PresetModelListWidget(QWidget* parent = nullptr);
void setModelType(const QString& modelType);
QString getModelType() const;
void setModelList(const QVector<ModelInfo>& models);
QVector<ModelInfo> getModelList() const;
protected:
void startDrag(Qt::DropActions supportedActions);
private:
QString modelType_;
QVector<ModelInfo> modelList_;
};

View File

@ -8,14 +8,19 @@
#include <QPixmap> #include <QPixmap>
#include <QPainter> #include <QPainter>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QMetaType>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QIcon> #include <QIcon>
#include <QMouseEvent> #include <QMouseEvent>
#include <QFontMetrics>
#include <QWidget>
#include "common/RecourceHelper.h"
#include "common/SpdLogger.h" #include "common/SpdLogger.h"
#include "ui/DockTitleBar.h" #include "ui/DockTitleBar.h"
#include "ui/DockWidget.h" #include "ui/DockWidget.h"
#include "workspace/PresetModelConfigParser.h"
#include "ui_PresetModelPanel.h" #include "ui_PresetModelPanel.h"
@ -23,6 +28,7 @@
PresetModelPanel::PresetModelPanel(QWidget *parent) PresetModelPanel::PresetModelPanel(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::PresetModelPanel) , ui(new Ui::PresetModelPanel)
, dragSourceWidget_(nullptr)
{ {
ui->setupUi(this); ui->setupUi(this);
InitUI(); InitUI();
@ -30,6 +36,7 @@ PresetModelPanel::PresetModelPanel(QWidget *parent)
PresetModelPanel::~PresetModelPanel() PresetModelPanel::~PresetModelPanel()
{ {
ClearDynamicUI();
delete ui; delete ui;
} }
@ -50,175 +57,100 @@ void PresetModelPanel::AttachDock(DockWidget* dockWidget)
void PresetModelPanel::InitUI() void PresetModelPanel::InitUI()
{ {
// Try to load model data from configuration files // Try to load model data from configuration files
if (m_configParser.LoadAllConfigs("workspace/presets")) { QString presetsPath = QString("%1/presets").arg(RecourceHelper::Get().GetResourcesPath());
if (PresetModelConfigParser::Get().LoadAllConfigs(presetsPath)) {
// Successfully loaded from configuration files // Successfully loaded from configuration files
CreateDynamicUI();
LoadModelsFromConfig(); LoadModelsFromConfig();
} else { } else {
// Failed to load configuration files, use hardcoded defaults as fallback // Failed to load configuration files, use hardcoded defaults as fallback
LOG_WARN("Failed to load preset models from config files, using hardcoded defaults. Error: {}", LOG_WARN("Failed to load preset models from config files, using hardcoded defaults. Error: {}",
m_configParser.GetLastError().toStdString()); PresetModelConfigParser::Get().GetLastError().toStdString());
LoadDefaultModels();
} }
} }
void PresetModelPanel::LoadModelsFromConfig() void PresetModelPanel::CreateDynamicUI()
{ {
// Load ship models // Clear any existing dynamic UI
QStringList shipModels = m_configParser.GetModelNames("Ship"); ClearDynamicUI();
if (!shipModels.isEmpty()) {
PopulateModelList(ui->shipList, "Ship", shipModels); // Get all category names from configuration
QStringList categoryNames = PresetModelConfigParser::Get().GetCategoryNames();
if (categoryNames.isEmpty()) {
LOG_WARN("No categories found in configuration");
return;
} }
// Load satellite models // Create UI for each category
QStringList satelliteModels = m_configParser.GetModelNames("Satellite"); for (const QString& categoryName : categoryNames) {
if (!satelliteModels.isEmpty()) { ModelCategory category = PresetModelConfigParser::Get().GetCategory(categoryName);
PopulateModelList(ui->satelliteList, "Satellite", satelliteModels);
}
// Load missile models // Create page widget
QStringList missileModels = m_configParser.GetModelNames("Missile"); QWidget* page = new QWidget();
if (!missileModels.isEmpty()) { page->setObjectName(QString("%1Page").arg(categoryName.toLower()));
PopulateModelList(ui->missileList, "Missile", missileModels);
}
// Load jammer models // Create layout for the page
QStringList jammerModels = m_configParser.GetModelNames("Jammer"); QVBoxLayout* layout = new QVBoxLayout(page);
if (!jammerModels.isEmpty()) { layout->setSpacing(0);
PopulateModelList(ui->jammerList, "Jammer", jammerModels); layout->setContentsMargins(0, 0, 0, 0);
}
}
void PresetModelPanel::LoadDefaultModels() // Create list widget
{ PresetModelListWidget* listWidget = new PresetModelListWidget(page);
// Use hardcoded default models as fallback mechanism listWidget->setObjectName(QString("%1List").arg(categoryName.toLower()));
QStringList shipModels = {
"Destroyer",
"Aircraft Carrier",
"Frigate",
"Submarine"
};
PopulateModelList(ui->shipList, "Ship", shipModels);
QStringList satelliteModels = {
"Communication Satellite",
"Weather Satellite",
"GPS Satellite",
"Spy Satellite"
};
PopulateModelList(ui->satelliteList, "Satellite", satelliteModels);
QStringList missileModels = {
"Cruise Missile",
"Ballistic Missile",
"Anti-Ship Missile",
"Surface-to-Air Missile"
};
PopulateModelList(ui->missileList, "Missile", missileModels);
QStringList jammerModels = {
"Electronic Jammer",
"Communication Jammer",
"Radar Jammer",
"GPS Jammer"
};
PopulateModelList(ui->jammerList, "Jammer", jammerModels);
}
void PresetModelPanel::PopulateModelList(QListWidget* listWidget, const QString& modelType, const QStringList& models)
{
if (!listWidget) return;
// Set the model type as a property for later use
listWidget->setProperty("modelType", modelType);
for (const QString& model : models) {
QListWidgetItem* item = new QListWidgetItem(model);
item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
if (modelType == "Ship") {
item->setIcon(QIcon(":/icons/ship.png"));
} else if (modelType == "Satellite") {
item->setIcon(QIcon(":/icons/satellite.png"));
} else if (modelType == "Missile") {
item->setIcon(QIcon(":/icons/missile.png"));
} else if (modelType == "Jammer") {
item->setIcon(QIcon(":/icons/jammer.png"));
}
listWidget->addItem(item);
}
connect(listWidget, &QListWidget::itemDoubleClicked, this, &PresetModelPanel::OnModelItemDoubleClicked);
}
void PresetModelPanel::SetupDragAndDrop(QListWidget* listWidget)
{
listWidget->setDragDropMode(QAbstractItemView::DragOnly); listWidget->setDragDropMode(QAbstractItemView::DragOnly);
listWidget->setDefaultDropAction(Qt::CopyAction); listWidget->setDefaultDropAction(Qt::CopyAction);
// Add list widget to layout
layout->addWidget(listWidget);
// Add page to toolbox with display name
QString displayName = category.displayName.isEmpty() ? categoryName : category.displayName;
ui->PresetModelToolBox->addItem(page, displayName);
// Store references for later use
categoryWidgets_[categoryName] = listWidget;
categoryPages_[categoryName] = page;
LOG_INFO("Created dynamic UI for category: {}", categoryName.toStdString());
} }
void PresetModelPanel::OnModelItemDoubleClicked(QListWidgetItem* item) // Set first page as current if available
if (ui->PresetModelToolBox->count() > 0) {
ui->PresetModelToolBox->setCurrentIndex(0);
}
}
void PresetModelPanel::LoadModelsFromConfig() {
// Load models for each dynamically created category
QStringList categoryNames = PresetModelConfigParser::Get().GetCategoryNames();
for (const QString& categoryName : categoryNames) {
ModelCategory category = PresetModelConfigParser::Get().GetCategory(categoryName);
if (!category.models.isEmpty() && categoryWidgets_.contains(categoryName)) {
PresetModelListWidget* listWidget = categoryWidgets_[categoryName];
listWidget->setModelType(categoryName);
listWidget->setModelList(category.models);
LOG_INFO("Loaded {} models for category: {}",
category.models.size(), categoryName.toStdString());
}
}
}
void PresetModelPanel::ClearDynamicUI()
{ {
if (!item) return; // Clear all dynamic UI elements
categoryWidgets_.clear();
categoryPages_.clear();
QListWidget* listWidget = item->listWidget(); // Remove all pages from toolbox
if (!listWidget) return; while (ui->PresetModelToolBox->count() > 0) {
QWidget* widget = ui->PresetModelToolBox->widget(0);
QString modelType = listWidget->property("modelType").toString(); ui->PresetModelToolBox->removeItem(0);
QString modelName = item->text(); if (widget) {
widget->deleteLater();
emit ModelDropped(modelType, modelName);
} }
// DraggableListWidget implementation
DraggableListWidget::DraggableListWidget(const QString& modelType, QWidget* parent)
: QListWidget(parent), modelType_(modelType)
{
setProperty("modelType", modelType);
} }
void DraggableListWidget::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton) {
dragStartPosition_ = event->pos();
}
QListWidget::mousePressEvent(event);
}
void DraggableListWidget::mouseMoveEvent(QMouseEvent* event) {
if (!(event->buttons() & Qt::LeftButton)) {
return;
}
if ((event->pos() - dragStartPosition_).manhattanLength() < QApplication::startDragDistance()) {
return;
}
QListWidgetItem* item = itemAt(dragStartPosition_);
if (!item) {
return;
}
QDrag* drag = new QDrag(this);
QMimeData* mimeData = new QMimeData;
QString modelType = this->property("modelType").toString();
QString modelName = item->text();
QString dragData = QString("%1|%2").arg(modelType, modelName);
mimeData->setData("application/x-preset-model", dragData.toUtf8());
drag->setMimeData(mimeData);
QPixmap pixmap(item->icon().pixmap(32, 32));
if (pixmap.isNull()) {
pixmap = QPixmap(100, 30);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setPen(Qt::black);
painter.drawText(pixmap.rect(), Qt::AlignCenter, modelName);
}
drag->setPixmap(pixmap);
Qt::DropAction dropAction = drag->exec(Qt::CopyAction);
Q_UNUSED(dropAction);
} }

View File

@ -10,22 +10,25 @@
#include <QMimeData> #include <QMimeData>
#include <QDrag> #include <QDrag>
#include <QMouseEvent> #include <QMouseEvent>
#include "PresetModelConfigParser.h" #include <QEvent>
#include <QStyledItemDelegate>
#include <QPainter>
#include <QApplication>
#include <QMap>
#include "workspace/ModelInfo.h"
#include "ui/ModelBrowser/PresetModelListWidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class PresetModelPanel; } namespace Ui { class PresetModelPanel; }
QT_END_NAMESPACE
class DockWidget; class DockWidget;
/** /**
* @brief Preset model panel class * @brief Preset model panel class
* *
* Provides preset 3D models for users to drag into the 3D scene, including: * Provides preset 3D models for users to drag into the 3D scene.
* - Ships: Destroyer, Aircraft Carrier * Dynamically creates UI based on configuration files, supporting any number of categories.
* - Satellites: Geostationary Satellites
* - Missiles: Hypersonic Missiles
* - Jammers: Passive Jammers, Active Jammers
*/ */
class PresetModelPanel : public QWidget { class PresetModelPanel : public QWidget {
Q_OBJECT Q_OBJECT
@ -40,22 +43,6 @@ public:
*/ */
void AttachDock(DockWidget* dockWidget); void AttachDock(DockWidget* dockWidget);
Q_SIGNALS:
/**
* @brief Signal emitted when model is dragged to scene
* @param modelType Model type
* @param modelName Model name
* @param position Scene position (optional)
*/
void ModelDropped(const QString& modelType, const QString& modelName, const QPointF& position = QPointF());
private slots:
/**
* @brief Handle model item double click event
* @param item Clicked item
*/
void OnModelItemDoubleClicked(QListWidgetItem* item);
private: private:
/** /**
* @brief Initialize user interface * @brief Initialize user interface
@ -63,18 +50,9 @@ private:
void InitUI(); void InitUI();
/** /**
* @brief Populate model list with items * @brief Create dynamic UI based on configuration
* @param listWidget List widget to populate
* @param modelType Model type
* @param models Model name list
*/ */
void PopulateModelList(QListWidget* listWidget, const QString& modelType, const QStringList& models); void CreateDynamicUI();
/**
* @brief Setup drag and drop functionality
* @param listWidget List widget to setup drag and drop
*/
void SetupDragAndDrop(QListWidget* listWidget);
/** /**
* @brief Load models from configuration file * @brief Load models from configuration file
@ -82,32 +60,18 @@ private:
void LoadModelsFromConfig(); void LoadModelsFromConfig();
/** /**
* @brief Load default models when config is unavailable * @brief Clear all dynamic UI elements
*/ */
void LoadDefaultModels(); void ClearDynamicUI();
private: private:
Ui::PresetModelPanel *ui; Ui::PresetModelPanel *ui;
PresetModelConfigParser m_configParser;
};
/** // Dynamic UI management
* @brief Custom list widget with drag and drop support QMap<QString, PresetModelListWidget*> categoryWidgets_;
*/ QMap<QString, QWidget*> categoryPages_;
class DraggableListWidget : public QListWidget {
Q_OBJECT
public: // Drag and drop support
explicit DraggableListWidget(const QString& modelType, QWidget* parent = nullptr);
Q_SIGNALS:
void ItemDragged(const QString& modelType, const QString& modelName);
protected:
void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
private:
QString modelType_;
QPoint dragStartPosition_; QPoint dragStartPosition_;
QListWidget* dragSourceWidget_;
}; };

View File

@ -14,129 +14,26 @@
<string>Preset Models</string> <string>Preset Models</string>
</property> </property>
<layout class="QVBoxLayout" name="mainLayout"> <layout class="QVBoxLayout" name="mainLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<property name="spacing"> <property name="spacing">
<number>5</number> <number>5</number>
</property> </property>
<item> <property name="leftMargin">
<widget class="QToolBox" name="toolBox">
<property name="objectName">
<string>PresetModelToolBox</string>
</property>
<property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="shipPage"> <property name="topMargin">
<property name="geometry"> <number>0</number>
<rect> </property>
<x>0</x> <property name="rightMargin">
<y>0</y> <number>0</number>
<width>290</width> </property>
<height>540</height> <property name="bottomMargin">
</rect> <number>0</number>
</property> </property>
<attribute name="label">
<string>Ships</string>
</attribute>
<layout class="QVBoxLayout" name="shipLayout">
<item> <item>
<widget class="QListWidget" name="shipList"> <widget class="QToolBox" name="PresetModelToolBox">
<property name="dragDropMode"> <property name="currentIndex">
<enum>QAbstractItemView::DragOnly</enum> <number>-1</number>
</property> </property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="satellitePage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>290</width>
<height>540</height>
</rect>
</property>
<attribute name="label">
<string>Satellites</string>
</attribute>
<layout class="QVBoxLayout" name="satelliteLayout">
<item>
<widget class="QListWidget" name="satelliteList">
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="missilePage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>290</width>
<height>540</height>
</rect>
</property>
<attribute name="label">
<string>Missiles</string>
</attribute>
<layout class="QVBoxLayout" name="missileLayout">
<item>
<widget class="QListWidget" name="missileList">
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="jammerPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>290</width>
<height>540</height>
</rect>
</property>
<attribute name="label">
<string>Jammers</string>
</attribute>
<layout class="QVBoxLayout" name="jammerLayout">
<item>
<widget class="QListWidget" name="jammerList">
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -434,6 +434,12 @@ void CurvePanel::updateParseWaveFile(const QString& strFile, int nT, FileEntryCu
return; return;
} }
curveChart->removeAllSeries();
m_seriesIDMap.clear();
m_dataWava.clear();
m_dataReport.clear();
QFile file(strFile); QFile file(strFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {
@ -546,6 +552,12 @@ void CurvePanel::updateParseReportFile(const QString & strFile, int nT, FileEntr
return; return;
} }
curveChart->removeAllSeries();
m_seriesIDMap.clear();
m_dataWava.clear();
m_dataReport.clear();
QFile file(strFile); QFile file(strFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {

View File

@ -45,7 +45,9 @@ void LightPanel::RefreshPanel()
void LightPanel::InitUI() void LightPanel::InitUI()
{ {
QGridLayout* pMainLyt = new QGridLayout(this);
pMainLyt->setContentsMargins(5, 0, 5, 0);
setLayout(pMainLyt);
} }
QString LightPanel::GetTypeDisplayName() const QString LightPanel::GetTypeDisplayName() const
@ -111,10 +113,19 @@ void LightPanel::updateParseFile(const QString & strFile, int nT, FileEntryLight
return; return;
} }
m_dataLamp.clear();
clearLightPanel();
QGridLayout* layout = qobject_cast<QGridLayout*>(this->layout());
if (!layout)
{
return;
}
QFile file(strFile); QFile file(strFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {
QGridLayout* pMainLyt = new QGridLayout(this);
for (int nI = 0; nI < listCurve.size(); nI++) for (int nI = 0; nI < listCurve.size(); nI++)
{ {
FileEntryLight::LightRowProperty prop = listCurve.at(nI); FileEntryLight::LightRowProperty prop = listCurve.at(nI);
@ -134,14 +145,12 @@ void LightPanel::updateParseFile(const QString & strFile, int nT, FileEntryLight
pLyt->addWidget(pLampLab); pLyt->addWidget(pLampLab);
pLyt->addWidget(pTextLab); pLyt->addWidget(pTextLab);
pMainLyt->addLayout(pLyt, nI, i); layout->addLayout(pLyt, nI, i);
QString strKey = QString::number(nI) + "-" + QString::number(i); QString strKey = QString::number(nI) + "-" + QString::number(i);
m_mapLamp.insert(strKey, pLampLab); m_mapLamp.insert(strKey, pLampLab);
} }
} }
pMainLyt->setContentsMargins(5, 0, 5, 0);
setLayout(pMainLyt);
while (!file.atEnd()) while (!file.atEnd())
{ {
@ -174,6 +183,8 @@ void LightPanel::updateParseFile(const QString & strFile, int nT, FileEntryLight
void LightPanel::updateLampColor(const QString & strOpenColor, const QString & strCloseColor) void LightPanel::updateLampColor(const QString & strOpenColor, const QString & strCloseColor)
{ {
m_lampColor.clear();
{ {
QString strStyle = "QLabel{background-color: rgb(" + strCloseColor + ");border-radius: 10px;}; "; QString strStyle = "QLabel{background-color: rgb(" + strCloseColor + ");border-radius: 10px;}; ";
m_lampColor.insert(0, strStyle); m_lampColor.insert(0, strStyle);
@ -183,3 +194,32 @@ void LightPanel::updateLampColor(const QString & strOpenColor, const QString & s
m_lampColor.insert(1, strStyle); m_lampColor.insert(1, strStyle);
} }
} }
void LightPanel::clearLightPanel()
{
if (auto* layout = qobject_cast<QGridLayout*>(this->layout()))
{
while (layout->count() > 0)
{
QLayoutItem* item = layout->takeAt(0);
if (item)
{
auto* childLayout = item->layout();
while (childLayout->count() > 0)
{
QLayoutItem* itemChild = childLayout->takeAt(0);
if (itemChild)
{
if (auto* w = itemChild->widget())
{
w->deleteLater();
}
delete itemChild;
}
}
delete item;
}
}
}
m_mapLamp.clear();
}

View File

@ -64,6 +64,8 @@ private:
void updateParseFile(const QString& strFile, int nT, FileEntryLight::LightRowProperties listCurve); void updateParseFile(const QString& strFile, int nT, FileEntryLight::LightRowProperties listCurve);
void updateLampColor(const QString& strOpenColor, const QString& strCloseColor); void updateLampColor(const QString& strOpenColor, const QString& strCloseColor);
void clearLightPanel();
private: private:
QMap<int, QString> m_lampColor; QMap<int, QString> m_lampColor;
QMap<QString, SignalLabel*> m_mapLamp; QMap<QString, SignalLabel*> m_mapLamp;

View File

@ -234,6 +234,9 @@ void SurfacePanel::updateParseFile(const QString & strFile, int nT, FileEntrySur
return; return;
} }
m_data.clear();
m_pSeries->dataProxy()->resetArray(nullptr);
QFile file(strFile); QFile file(strFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {

View File

@ -122,6 +122,10 @@ void TablePanel::updateParseFile(const QString & strFile, int nT, FileEntryTable
return; return;
} }
m_tableSetting.clear();
m_dataTable.clear();
clearTable();
QFile file(strFile); QFile file(strFile);
if (file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {

View File

@ -54,8 +54,8 @@ void AddCurveFileDlg::setupConnections() {
connect(ui->curveNameEdit, &QLineEdit::textChanged, this, &AddCurveFileDlg::onCurveNameChanged); connect(ui->curveNameEdit, &QLineEdit::textChanged, this, &AddCurveFileDlg::onCurveNameChanged);
connect(ui->dataStartSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged); connect(ui->dataStartSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged);
connect(ui->dataStopSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged); connect(ui->dataStopSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged);
connect(ui->xValueSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged); connect(ui->xValueSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged);
connect(ui->yValueSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged); connect(ui->yValueSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &AddCurveFileDlg::onCurveDataChanged);
// Dialog buttons // Dialog buttons
connect(ui->addBtn, &QPushButton::clicked, this, &AddCurveFileDlg::onSure); connect(ui->addBtn, &QPushButton::clicked, this, &AddCurveFileDlg::onSure);
@ -87,9 +87,11 @@ void AddCurveFileDlg::updateFileInfo(const QString& filePath) {
ui->filePathEdit->setText(filePath); ui->filePathEdit->setText(filePath);
} }
void AddCurveFileDlg::onAddCurveClicked() { void AddCurveFileDlg::onAddCurveClicked()
{
// Save current curve properties if any curve is selected // Save current curve properties if any curve is selected
if (currentCurveIndex_ >= 0) { if (currentCurveIndex_ >= 0)
{
saveCurveProperties(); saveCurveProperties();
} }
@ -99,10 +101,13 @@ void AddCurveFileDlg::onAddCurveClicked() {
newCurve.color = generateCurveColor(); newCurve.color = generateCurveColor();
// Set default values based on chart type // Set default values based on chart type
if (chartProperties_.chartType == ChartType::Wave) { if (chartProperties_.chartType == ChartType::Wave)
{
newCurve.data.wave.start = 1; newCurve.data.wave.start = 1;
newCurve.data.wave.stop = 241; newCurve.data.wave.stop = 241;
} else { }
else
{
newCurve.data.report.x = 0.0; newCurve.data.report.x = 0.0;
newCurve.data.report.y = 0.0; newCurve.data.report.y = 0.0;
} }
@ -121,7 +126,7 @@ void AddCurveFileDlg::onAddCurveClicked() {
.arg(newCurve.color.green()) .arg(newCurve.color.green())
.arg(newCurve.color.blue()); .arg(newCurve.color.blue());
} else { } else {
displayText = QString("%1 (%.2f,%.2f) (%4,%5,%6)") displayText = QString("%1 [%2,%3] (%4,%5,%6)")
.arg(newCurve.name) .arg(newCurve.name)
.arg(newCurve.data.report.x) .arg(newCurve.data.report.x)
.arg(newCurve.data.report.y) .arg(newCurve.data.report.y)
@ -134,6 +139,8 @@ void AddCurveFileDlg::onAddCurveClicked() {
ui->curveListWidget->addItem(item); ui->curveListWidget->addItem(item);
++currentCurveIndex_; ++currentCurveIndex_;
ui->curveNameEdit->setText(newCurve.name);
// Select the new curve // Select the new curve
ui->curveListWidget->setCurrentRow(curves_.size() - 1); ui->curveListWidget->setCurrentRow(curves_.size() - 1);
} }
@ -169,21 +176,36 @@ void AddCurveFileDlg::onRemoveCurveClicked() {
} }
void AddCurveFileDlg::onCurveListWidgetItemClicked(QListWidgetItem* item) { void AddCurveFileDlg::onCurveListWidgetItemClicked(QListWidgetItem* item) {
if (!item) { if (!item)
{
return; return;
} }
int clickedIndex = ui->curveListWidget->row(item); int clickedIndex = ui->curveListWidget->row(item);
if (clickedIndex == currentCurveIndex_) { if (clickedIndex == currentCurveIndex_)
{
ui->curveNameEdit->setText(curves_[currentCurveIndex_].name); ui->curveNameEdit->setText(curves_[currentCurveIndex_].name);
if (chartProperties_.chartType == ChartType::Wave) { if (chartProperties_.chartType == ChartType::Wave)
{
ui->dataStartSpinBox->blockSignals(true);
ui->dataStartSpinBox->setValue(curves_[currentCurveIndex_].data.wave.start); ui->dataStartSpinBox->setValue(curves_[currentCurveIndex_].data.wave.start);
ui->dataStartSpinBox->blockSignals(false);
ui->dataStopSpinBox->blockSignals(true);
ui->dataStopSpinBox->setValue(curves_[currentCurveIndex_].data.wave.stop); ui->dataStopSpinBox->setValue(curves_[currentCurveIndex_].data.wave.stop);
} else { ui->dataStopSpinBox->blockSignals(false);
}
else
{
ui->xValueSpinBox->blockSignals(true);
ui->xValueSpinBox->setValue(curves_[currentCurveIndex_].data.report.x); ui->xValueSpinBox->setValue(curves_[currentCurveIndex_].data.report.x);
ui->xValueSpinBox->blockSignals(false);
ui->yValueSpinBox->blockSignals(true);
ui->yValueSpinBox->setValue(curves_[currentCurveIndex_].data.report.y); ui->yValueSpinBox->setValue(curves_[currentCurveIndex_].data.report.y);
ui->yValueSpinBox->blockSignals(false);
} }
updateColorPreview(curves_[currentCurveIndex_].color); updateColorPreview(curves_[currentCurveIndex_].color);
@ -234,7 +256,7 @@ void AddCurveFileDlg::onCurveNameChanged() {
.arg(curves_[currentCurveIndex_].color.green()) .arg(curves_[currentCurveIndex_].color.green())
.arg(curves_[currentCurveIndex_].color.blue()); .arg(curves_[currentCurveIndex_].color.blue());
} else { } else {
displayText = QString("%1 (%.2f,%.2f) (%4,%5,%6)") displayText = QString("%1 [%2,%3] (%4,%5,%6)")
.arg(newName) .arg(newName)
.arg(curves_[currentCurveIndex_].data.report.x) .arg(curves_[currentCurveIndex_].data.report.x)
.arg(curves_[currentCurveIndex_].data.report.y) .arg(curves_[currentCurveIndex_].data.report.y)
@ -343,18 +365,32 @@ void AddCurveFileDlg::addCurveToList(const FileEntryCurve::CurveProperty& curve)
} }
void AddCurveFileDlg::updateCurveProperties() { void AddCurveFileDlg::updateCurveProperties() {
if (currentCurveIndex_ >= 0 && currentCurveIndex_ < curves_.size()) { if (currentCurveIndex_ >= 0 && currentCurveIndex_ < curves_.size())
{
const FileEntryCurve::CurveProperty& curve = curves_[currentCurveIndex_]; const FileEntryCurve::CurveProperty& curve = curves_[currentCurveIndex_];
ui->curveNameEdit->setText(curve.name); ui->curveNameEdit->setText(curve.name);
// Update properties based on chart type // Update properties based on chart type
if (chartProperties_.chartType == ChartType::Wave) { if (chartProperties_.chartType == ChartType::Wave)
{
ui->dataStartSpinBox->blockSignals(true);
ui->dataStartSpinBox->setValue(curve.data.wave.start); ui->dataStartSpinBox->setValue(curve.data.wave.start);
ui->dataStartSpinBox->blockSignals(false);
ui->dataStopSpinBox->blockSignals(true);
ui->dataStopSpinBox->setValue(curve.data.wave.stop); ui->dataStopSpinBox->setValue(curve.data.wave.stop);
} else { ui->dataStopSpinBox->blockSignals(false);
}
else
{
ui->xValueSpinBox->blockSignals(true);
ui->xValueSpinBox->setValue(curve.data.report.x); ui->xValueSpinBox->setValue(curve.data.report.x);
ui->xValueSpinBox->blockSignals(false);
ui->yValueSpinBox->blockSignals(true);
ui->yValueSpinBox->setValue(curve.data.report.y); ui->yValueSpinBox->setValue(curve.data.report.y);
ui->yValueSpinBox->blockSignals(false);
} }
selectedColor_ = curve.color; selectedColor_ = curve.color;
@ -561,12 +597,12 @@ bool AddCurveFileDlg::validateSpecificParams() {
double yMin = ui->yMinSpinBox->value(); double yMin = ui->yMinSpinBox->value();
double yMax = ui->yMaxSpinBox->value(); double yMax = ui->yMaxSpinBox->value();
if (xMin >= xMax) { if (xMin > xMax) {
QMessageBox::warning(this, tr("Validation Error"), tr("X axis minimum value must be less than maximum value.")); QMessageBox::warning(this, tr("Validation Error"), tr("X axis minimum value must be less than maximum value."));
return false; return false;
} }
if (yMin >= yMax) { if (yMin > yMax) {
QMessageBox::warning(this, tr("Validation Error"), tr("Y axis minimum value must be less than maximum value.")); QMessageBox::warning(this, tr("Validation Error"), tr("Y axis minimum value must be less than maximum value."));
return false; return false;
} }
@ -580,11 +616,11 @@ bool AddCurveFileDlg::validateSpecificParams() {
} }
// X axis tick count validation // X axis tick count validation
int xTickCount = ui->xCountSpinBox->value(); //int xTickCount = ui->xCountSpinBox->value();
if (xTickCount < 2) { //if (xTickCount < 2) {
QMessageBox::warning(this, tr("Validation Error"), tr("X axis tick count must be at least 2.")); // QMessageBox::warning(this, tr("Validation Error"), tr("X axis tick count must be at least 2."));
return false; // return false;
} //}
return true; return true;
} }

View File

@ -2,12 +2,15 @@
<ui version="4.0"> <ui version="4.0">
<class>AddCurveFileDlg</class> <class>AddCurveFileDlg</class>
<widget class="QWidget" name="AddCurveFileDlg"> <widget class="QWidget" name="AddCurveFileDlg">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>600</width> <width>600</width>
<height>789</height> <height>842</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -287,7 +290,7 @@
</size> </size>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>2</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>50</number>
@ -377,7 +380,7 @@
</size> </size>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>2</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>50</number>
@ -543,7 +546,7 @@
<property name="title"> <property name="title">
<string>Selected Curve Properties</string> <string>Selected Curve Properties</string>
</property> </property>
<layout class="QGridLayout" name="curvePropertiesGridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="curveNameLabel"> <widget class="QLabel" name="curveNameLabel">
<property name="minimumSize"> <property name="minimumSize">
@ -609,7 +612,7 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>50</width> <width>50</width>
<height>25</height> <height>0</height>
</size> </size>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
@ -701,8 +704,11 @@
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="xValueLabel"> <widget class="QLabel" name="xValueLabel">
<property name="visible"> <property name="minimumSize">
<bool>false</bool> <size>
<width>0</width>
<height>25</height>
</size>
</property> </property>
<property name="text"> <property name="text">
<string>X Value:</string> <string>X Value:</string>
@ -710,25 +716,31 @@
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QDoubleSpinBox" name="xValueSpinBox"> <widget class="QSpinBox" name="xValueSpinBox">
<property name="visible"> <property name="minimumSize">
<bool>false</bool> <size>
<width>0</width>
<height>25</height>
</size>
</property> </property>
<property name="minimum"> <property name="minimum">
<double>-999999.000000000000000</double> <number>1</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>999999.000000000000000</double> <number>999999</number>
</property> </property>
<property name="value"> <property name="value">
<double>0.000000000000000</double> <number>1</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="yValueLabel"> <widget class="QLabel" name="yValueLabel">
<property name="visible"> <property name="minimumSize">
<bool>false</bool> <size>
<width>0</width>
<height>25</height>
</size>
</property> </property>
<property name="text"> <property name="text">
<string>Y Value:</string> <string>Y Value:</string>
@ -736,18 +748,21 @@
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QDoubleSpinBox" name="yValueSpinBox"> <widget class="QSpinBox" name="yValueSpinBox">
<property name="visible"> <property name="minimumSize">
<bool>false</bool> <size>
<width>0</width>
<height>25</height>
</size>
</property> </property>
<property name="minimum"> <property name="minimum">
<double>-999999.000000000000000</double> <number>1</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>999999.000000000000000</double> <number>999999</number>
</property> </property>
<property name="value"> <property name="value">
<double>0.000000000000000</double> <number>2</number>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -230,17 +230,24 @@ void AddLightFileDlg::addLightToList(const FileEntryLight::LightRowProperty& lig
ui->lightListWidget->addItem(item); ui->lightListWidget->addItem(item);
} }
void AddLightFileDlg::updateLightProperties() { void AddLightFileDlg::updateLightProperties()
if (currentLightIndex_ >= 0 && currentLightIndex_ < lights_.size()) { {
if (currentLightIndex_ >= 0 && currentLightIndex_ < lights_.size())
{
const FileEntryLight::LightRowProperty& light = lights_[currentLightIndex_]; const FileEntryLight::LightRowProperty& light = lights_[currentLightIndex_];
ui->lightNameEdit->blockSignals(true);
ui->lightNameEdit->setText(light.name.join(", ")); ui->lightNameEdit->setText(light.name.join(", "));
ui->lightNameEdit->blockSignals(false);
// Update data edit // Update data edit
QStringList dataStrings; QStringList dataStrings;
for (int dataValue : light.data) { for (int dataValue : light.data) {
dataStrings.append(QString::number(dataValue)); dataStrings.append(QString::number(dataValue));
} }
ui->lightDataEdit->blockSignals(true);
ui->lightDataEdit->setText(dataStrings.join(", ")); ui->lightDataEdit->setText(dataStrings.join(", "));
ui->lightDataEdit->blockSignals(false);
// Update row index display // Update row index display
ui->rowIndexValue->setText(QString::number(currentLightIndex_)); ui->rowIndexValue->setText(QString::number(currentLightIndex_));
@ -290,15 +297,22 @@ QString AddLightFileDlg::generateLightName() {
return QString("Light_%1").arg(lights_.size() + 1); return QString("Light_%1").arg(lights_.size() + 1);
} }
void AddLightFileDlg::updateDataDisplay() { void AddLightFileDlg::updateDataDisplay()
if (currentLightIndex_ >= 0 && currentLightIndex_ < lights_.size()) { {
if (currentLightIndex_ >= 0 && currentLightIndex_ < lights_.size())
{
const FileEntryLight::LightRowProperty& light = lights_[currentLightIndex_]; const FileEntryLight::LightRowProperty& light = lights_[currentLightIndex_];
QStringList dataStrings; QStringList dataStrings;
for (int dataValue : light.data) { for (int dataValue : light.data)
{
dataStrings.append(QString::number(dataValue)); dataStrings.append(QString::number(dataValue));
} }
ui->lightDataEdit->blockSignals(true);
ui->lightDataEdit->setText(dataStrings.join(", ")); ui->lightDataEdit->setText(dataStrings.join(", "));
} else { ui->lightDataEdit->blockSignals(false);
}
else
{
ui->lightDataEdit->clear(); ui->lightDataEdit->clear();
} }
} }
@ -376,6 +390,7 @@ void AddLightFileDlg::onSure() {
if (lightEntry) { if (lightEntry) {
lightEntry->SetName(sName); lightEntry->SetName(sName);
colorProperties_.timeParam = ui->SpinBox_time->value();
// Set color properties // Set color properties
lightEntry->SetColorProperties(colorProperties_); lightEntry->SetColorProperties(colorProperties_);

View File

@ -123,7 +123,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>Chart Names:</string> <string>Chart Name:</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -135,11 +135,37 @@
<height>25</height> <height>25</height>
</size> </size>
</property> </property>
<property name="text">
<string>Chart 1</string>
</property>
<property name="placeholderText"> <property name="placeholderText">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="timeParamLabel">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="SpinBox_time">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -539,7 +539,7 @@ void AddPolarFileDlg::onSure()
QString errorMsg; QString errorMsg;
switch (result) { switch (result) {
case WorkSpace::FileEntryResult::LimitExceeded: case WorkSpace::FileEntryResult::LimitExceeded:
errorMsg = tr("Curve file count has reached the limit (9 files)"); errorMsg = tr("Polar file count has reached the limit (9 files)");
break; break;
case WorkSpace::FileEntryResult::Duplicate: case WorkSpace::FileEntryResult::Duplicate:
errorMsg = tr("File already exists"); errorMsg = tr("File already exists");
@ -560,6 +560,10 @@ void AddPolarFileDlg::onSure()
accept(); accept();
} }
else
{
QMessageBox::critical(this, tr("Error"), tr("Failed to create Polar file entry."));
}
} }
void AddPolarFileDlg::onCurveDataChanged() void AddPolarFileDlg::onCurveDataChanged()

View File

@ -291,13 +291,29 @@ void AddSurfaceFileDlg::updateSurfaceProperties()
if (currentSurfaceIndex_ >= 0 && currentSurfaceIndex_ < surfaces_.size()) { if (currentSurfaceIndex_ >= 0 && currentSurfaceIndex_ < surfaces_.size()) {
const auto& surface = surfaces_[currentSurfaceIndex_]; const auto& surface = surfaces_[currentSurfaceIndex_];
ui->surfaceNameLineEdit->blockSignals(true);
ui->surfaceNameLineEdit->setText(surface.name); ui->surfaceNameLineEdit->setText(surface.name);
ui->surfaceStartSpinBox->setValue(surface.start); ui->surfaceNameLineEdit->blockSignals(false);
ui->surfaceStopSpinBox->setValue(surface.stop);
ui->surfaceStartSpinBox->blockSignals(true);
ui->surfaceStartSpinBox->setValue(surface.start);
ui->surfaceStartSpinBox->blockSignals(false);
ui->surfaceStopSpinBox->blockSignals(true);
ui->surfaceStopSpinBox->setValue(surface.stop);
ui->surfaceStopSpinBox->blockSignals(false);
ui->comboBox_x->blockSignals(true);
ui->comboBox_x->setCurrentText(surface.x); ui->comboBox_x->setCurrentText(surface.x);
ui->comboBox_x->blockSignals(false);
ui->comboBox_y->blockSignals(true);
ui->comboBox_y->setCurrentText(surface.y); ui->comboBox_y->setCurrentText(surface.y);
ui->comboBox_y->blockSignals(false);
ui->comboBox_z->blockSignals(true);
ui->comboBox_z->setCurrentText(surface.z); ui->comboBox_z->setCurrentText(surface.z);
ui->comboBox_z->blockSignals(false);
selectedColor_ = surface.color; selectedColor_ = surface.color;
updateColorPreview(ui->surfaceColorButton, selectedColor_); updateColorPreview(ui->surfaceColorButton, selectedColor_);

View File

@ -11,6 +11,8 @@
#include <QDebug> #include <QDebug>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <osgEarthUtil/EarthManipulator> #include <osgEarthUtil/EarthManipulator>
#include <osgUtil/LineSegmentIntersector>
#include <osgEarth/SpatialReference>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator> #include <osgGA/StateSetManipulator>
@ -23,6 +25,13 @@
#include "workspace/WorkSpaceManager.h" #include "workspace/WorkSpaceManager.h"
#include "workspace/WorkSpace.h" #include "workspace/WorkSpace.h"
#include "scutcheon/osgScutcheon.h" #include "scutcheon/osgScutcheon.h"
#include "workspace/PresetModelConfigParser.h"
#include "entities/EntitiesManager.h"
#include "entities/EntityFactory.h"
#include "entities/ComponentFactory.h"
#include "entities/Entity.h"
#include "entities/Component.h"
static void ConfigureView( osgViewer::View* view ) { static void ConfigureView( osgViewer::View* view ) {
view->addEventHandler(new osgViewer::StatsHandler()); view->addEventHandler(new osgViewer::StatsHandler());
@ -191,10 +200,14 @@ void OsgWidget::paintEvent(QPaintEvent*) {
} }
void OsgWidget::dragEnterEvent(QDragEnterEvent* event) { void OsgWidget::dragEnterEvent(QDragEnterEvent* event) {
// 检查是否是预制模型拖拽 LOG_INFO("OsgWidget::dragEnterEvent - Available formats:{}", event->mimeData()->formats().join(",").toStdString());
// Check if it's a preset model drag
if (event->mimeData()->hasFormat("application/x-preset-model")) { if (event->mimeData()->hasFormat("application/x-preset-model")) {
LOG_INFO("OsgWidget::dragEnterEvent - Accept preset model drag");
event->acceptProposedAction(); event->acceptProposedAction();
} else { } else {
LOG_INFO("OsgWidget::dragEnterEvent - Ignore drag, not preset model format");
event->ignore(); event->ignore();
} }
} }
@ -209,40 +222,98 @@ void OsgWidget::dragMoveEvent(QDragMoveEvent* event) {
} }
void OsgWidget::dropEvent(QDropEvent* event) { void OsgWidget::dropEvent(QDropEvent* event) {
// 检查是否是预制模型拖拽 LOG_INFO("OsgWidget::dropEvent - Start processing drop event");
if (event->mimeData()->hasFormat("application/x-preset-model")) { if (event->mimeData()->hasFormat("application/x-preset-model")) {
QByteArray data = event->mimeData()->data("application/x-preset-model"); QByteArray data = event->mimeData()->data("application/x-preset-model");
QString modelInfo = QString::fromUtf8(data); QString modelInfo = QString::fromUtf8(data);
// 解析模型信息 (格式: "modelType|modelName") LOG_INFO("OsgWidget::dropEvent - Received model info:{}", modelInfo.toStdString());
QStringList parts = modelInfo.split("|"); QStringList parts = modelInfo.split("|");
if (parts.size() == 2) { if (parts.size() == 2) {
QString modelType = parts[0]; QString modelType = parts[0];
QString modelName = parts[1]; QString modelName = parts[1];
// 获取拖拽位置
QPointF position = event->posF(); QPointF position = event->posF();
// 处理预制模型拖拽 LOG_INFO("OsgWidget::dropEvent - Parse success, type:{} name:{} position:({},{})", modelType.toStdString(), modelName.toStdString(), position.x(), position.y());
OnPresetModelDropped(modelType, modelName, position); OnPresetModelDropped(modelType, modelName, position);
event->acceptProposedAction(); event->acceptProposedAction();
LOG_INFO("OsgWidget::dropEvent - Drag processing completed, accepted");
} else { } else {
LOG_ERROR("OsgWidget::dropEvent - Data format error, expected: type|name, actual:{}", modelInfo.toStdString());
event->ignore(); event->ignore();
} }
} else { } else {
LOG_INFO("OsgWidget::dropEvent - Not preset model format, ignore drag");
event->ignore(); event->ignore();
} }
} }
void OsgWidget::OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position) { void OsgWidget::OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position) {
// TODO: 实现预制模型拖拽处理逻辑 LOG_INFO("OsgWidget::OnPresetModelDropped - Dropped model type:{} name:{} position:({}, {})", modelType.toStdString(), modelName.toStdString(), position.x(), position.y());
// 1. 将屏幕坐标转换为世界坐标
// 2. 创建对应的Entity和MeshComponent
// 3. 添加到场景中
qDebug() << "预制模型拖拽:" << modelType << modelName << "位置:" << position; WorkSpace* currentWorkSpace = WorkSpaceManager::Get().GetCurrent();
if (nullptr == currentWorkSpace) {
// 这里暂时只是输出调试信息,后续需要集成实体系统 LOG_WARN("OsgWidget::OnPresetModelDropped - Current workspace is nullptr");
return;
}
// 将屏幕坐标转换为世界坐标
double longitude, latitude, height;
if (!ScreenToWorldCoordinate(static_cast<int>(position.x()), static_cast<int>(position.y()), longitude, latitude, height)) {
LOG_WARN("OsgWidget::OnPresetModelDropped - Failed to convert screen coordinates to world coordinates");
// 使用默认位置
longitude = 0.0;
latitude = 0.0;
height = 0.0;
}
bool success = false;
ModelInfo modelInfo = PresetModelConfigParser::Get().GetModelInfo(modelType, modelName, &success);
if (!success) {
LOG_ERROR("OsgWidget::OnPresetModelDropped - Failed to get model info of type:{} name:{}", modelType.toStdString(), modelName.toStdString());
return;
}
Entity* entity = EntitiesManager::Get().CreateEntityWithComponents(modelType, modelInfo.meshFile, modelInfo.useLabel, currentWorkSpace);
if (nullptr == entity) {
LOG_ERROR("OsgWidget::OnPresetModelDropped - Failed to create entity of type: {}", modelType.toStdString());
return;
}
int count = currentWorkSpace->GetEntities().size();
entity->SetName(QString("%1_%2").arg(modelName).arg(count));
SceneComponent* rootComponent = entity->GetRootComponent();
if (rootComponent) {
osg::Vec3 worldPos(longitude, latitude, height);
rootComponent->SetLocation(worldPos);
LOG_INFO("OsgWidget::OnPresetModelDropped - Set entity position to ({:.6f}, {:.6f}, {:.2f})", longitude, latitude, height);
}
LOG_INFO("OsgWidget::OnPresetModelDropped - Successfully created {} entity: {} at position ({:.6f}, {:.6f}, {:.2f})",
modelType.toStdString(), entity->GetName().toStdString(), longitude, latitude, height);
}
bool OsgWidget::ScreenToWorldCoordinate(int x, int y, double& longitude, double& latitude, double& height) {
if (!activeScene_.valid()) {
LOG_WARN("OsgWidget::ScreenToWorldCoordinate - active scene is null");
return false;
}
osg::Vec3d output;
if (!activeScene_->ScreenToWorldCoordinate(x, y, &output)) {
LOG_WARN("OsgWidget::ScreenToWorldCoordinate - Failed to convert screen coordinates to world coordinates");
return false;
}
longitude = output.x();
latitude = output.y();
height = output.z();
return true;
} }

View File

@ -43,6 +43,8 @@ public slots:
*/ */
void OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position = QPointF()); void OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position = QPointF());
bool ScreenToWorldCoordinate(int x, int y, double& longitude, double& latitude, double& altitude);
private: private:
QTimer timer_; QTimer timer_;

View File

@ -510,6 +510,8 @@ bool FileEntryLight::SaveFiles(tinyxml2::XMLElement* scene, tinyxml2::XMLDocumen
chartElement->SetAttribute("openColor", QColorToString(colorProperties_.openColor).toUtf8().constData()); chartElement->SetAttribute("openColor", QColorToString(colorProperties_.openColor).toUtf8().constData());
chartElement->SetAttribute("closeColor", QColorToString(colorProperties_.closeColor).toUtf8().constData()); chartElement->SetAttribute("closeColor", QColorToString(colorProperties_.closeColor).toUtf8().constData());
chartElement->SetAttribute("t", colorProperties_.timeParam);
// 为每个LightRowProperty创建<light>元素 // 为每个LightRowProperty创建<light>元素
for (const auto& lightRow : lightProperties_) { for (const auto& lightRow : lightProperties_) {
tinyxml2::XMLElement* lightElement = doc->NewElement("curve"); tinyxml2::XMLElement* lightElement = doc->NewElement("curve");
@ -559,6 +561,8 @@ bool FileEntryLight::ParseFiles(const tinyxml2::XMLElement* chartElement) {
colorProperties_.closeColor = StringToQColor(QString::fromUtf8(closeColorAttr)); colorProperties_.closeColor = StringToQColor(QString::fromUtf8(closeColorAttr));
} }
colorProperties_.timeParam = chartElement->DoubleAttribute("t", 0.0);
// 解析所有<light>元素 // 解析所有<light>元素
lightProperties_.clear(); lightProperties_.clear();
for (const tinyxml2::XMLElement* lightElement = chartElement->FirstChildElement("curve"); for (const tinyxml2::XMLElement* lightElement = chartElement->FirstChildElement("curve");

49
src/workspace/ModelInfo.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <QString>
#include <QVector>
/**
* @brief Model information structure
*
* Contains all information for a single preset model, including name, display name,
* description, mesh file path, icon path, enabled status, and entity registration info.
*/
struct ModelInfo {
QString name; ///< Model name (unique identifier)
QString displayName; ///< Display name (for UI display)
QString description; ///< Model description
QString meshFile; ///< 3D mesh file path
QString icon; ///< Icon file path
bool useLabel;
bool enabled; ///< Whether this model is enabled
/**
* @brief Default constructor
* Model is enabled by default
*/
ModelInfo() : useLabel(true), enabled(true) {}
/**
* @brief Constructor with parameters
*/
ModelInfo(const QString& name, const QString& displayName, const QString& description,
const QString& meshFile, const QString& icon, bool enabled = true,
const QString& entityType = "", const QString& entityClass = "",
const QStringList& requiredComponents = QStringList())
: name(name), displayName(displayName), description(description),
meshFile(meshFile), icon(icon), useLabel(true), enabled(enabled) {}
};
/**
* @brief Model category structure
*
* Contains information for a model category, such as ships, satellites, missiles, jammers, etc.
* Each category contains multiple specific models.
*/
struct ModelCategory {
QString name; ///< Category name (unique identifier)
QString displayName; ///< Display name (for UI display)
QString icon; ///< Category icon path
QVector<ModelInfo> models; ///< All models in this category
};

View File

@ -1,19 +1,21 @@
#include "PresetModelConfigParser.h" #include "workspace/PresetModelConfigParser.h"
#include "../../xml/tinyxml2.h"
#include "../../common/SpdLogger.h"
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
PresetModelConfigParser::PresetModelConfigParser() #include "xml/tinyxml2.h"
{ #include "common/SpdLogger.h"
template<> PresetModelConfigParser* Singleton<PresetModelConfigParser>::instance_ = nullptr;
PresetModelConfigParser::PresetModelConfigParser(QObject* parent)
: QObject(parent) {
} }
PresetModelConfigParser::~PresetModelConfigParser() PresetModelConfigParser::~PresetModelConfigParser() {
{
} }
bool PresetModelConfigParser::LoadAllConfigs(const QString& configDir) bool PresetModelConfigParser::LoadAllConfigs(const QString& configDir) {
{
Clear(); Clear();
QDir dir(configDir); QDir dir(configDir);
@ -102,8 +104,15 @@ bool PresetModelConfigParser::ParseXmlFile(const QString& filePath)
const char* modelDisplayName = modelElement->Attribute("displayName"); const char* modelDisplayName = modelElement->Attribute("displayName");
const char* description = modelElement->Attribute("description"); const char* description = modelElement->Attribute("description");
const char* meshFile = modelElement->Attribute("meshFile"); const char* meshFile = modelElement->Attribute("meshFile");
const char* modelIcon = modelElement->Attribute("icon");
const char* label = modelElement->Attribute("label");
const char* enabled = modelElement->Attribute("enabled"); const char* enabled = modelElement->Attribute("enabled");
// Entity registration attributes
const char* entityType = modelElement->Attribute("entityType");
const char* entityClass = modelElement->Attribute("entityClass");
const char* requiredComponents = modelElement->Attribute("requiredComponents");
if (!modelName) { if (!modelName) {
LOG_WARN("Model element missing name attribute in file: {}", filePath.toStdString()); LOG_WARN("Model element missing name attribute in file: {}", filePath.toStdString());
modelElement = modelElement->NextSiblingElement("model"); modelElement = modelElement->NextSiblingElement("model");
@ -114,6 +123,8 @@ bool PresetModelConfigParser::ParseXmlFile(const QString& filePath)
model.displayName = modelDisplayName ? QString::fromUtf8(modelDisplayName) : model.name; model.displayName = modelDisplayName ? QString::fromUtf8(modelDisplayName) : model.name;
model.description = description ? QString::fromUtf8(description) : ""; model.description = description ? QString::fromUtf8(description) : "";
model.meshFile = meshFile ? QString::fromUtf8(meshFile) : ""; model.meshFile = meshFile ? QString::fromUtf8(meshFile) : "";
model.icon = modelIcon ? QString::fromUtf8(modelIcon) : "";
model.useLabel = label ? (strcmp(label, "true") == 0) : true;
model.enabled = enabled ? (strcmp(enabled, "true") == 0) : true; model.enabled = enabled ? (strcmp(enabled, "true") == 0) : true;
category.models.append(model); category.models.append(model);
@ -156,16 +167,18 @@ ModelCategory PresetModelConfigParser::GetCategory(const QString& categoryName)
return ModelCategory(); return ModelCategory();
} }
ModelInfo PresetModelConfigParser::GetModelInfo(const QString& categoryName, const QString& modelName) const ModelInfo PresetModelConfigParser::GetModelInfo(const QString& categoryName, const QString& modelName, bool* success) const {
{
if (m_categories.contains(categoryName)) { if (m_categories.contains(categoryName)) {
const ModelCategory& category = m_categories[categoryName]; const ModelCategory& category = m_categories[categoryName];
for (const ModelInfo& model : category.models) { for (const ModelInfo& model : category.models) {
if (model.name == modelName) { if (model.name == modelName) {
if (success) *success = true;
return model; return model;
} }
} }
} }
if (success) *success = false;
return ModelInfo(); return ModelInfo();
} }

View File

@ -1,33 +1,22 @@
#pragma once #pragma once
#include <QObject>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QMap> #include <QMap>
#include <QVector>
struct ModelInfo { #include "app/Singleton.h"
QString name;
QString displayName;
QString description;
QString meshFile;
bool enabled;
ModelInfo() : enabled(true) {} #include "ModelInfo.h"
};
struct ModelCategory { class PresetModelConfigParser : public QObject, public Singleton<PresetModelConfigParser> {
QString name; Q_OBJECT
QString displayName;
QString icon;
QVector<ModelInfo> models;
};
class PresetModelConfigParser
{
public: public:
PresetModelConfigParser(); explicit PresetModelConfigParser(QObject* parent = nullptr);
~PresetModelConfigParser(); ~PresetModelConfigParser();
void OnDestory() { }
// Load all preset model configurations // Load all preset model configurations
bool LoadAllConfigs(const QString& configDir = "workspace/presets"); bool LoadAllConfigs(const QString& configDir = "workspace/presets");
@ -44,7 +33,7 @@ public:
ModelCategory GetCategory(const QString& categoryName) const; ModelCategory GetCategory(const QString& categoryName) const;
// Get model information // Get model information
ModelInfo GetModelInfo(const QString& categoryName, const QString& modelName) const; ModelInfo GetModelInfo(const QString& categoryName, const QString& modelName, bool* success) const;
// Check if configuration data exists // Check if configuration data exists
bool HasData() const; bool HasData() const;

View File

@ -1,129 +0,0 @@
#include <QApplication>
#include <QDebug>
#include <iostream>
#include "workspace/WorkSpaceXMLParse.h"
#include "common/ChartData.h"
void printChartData(const std::shared_ptr<BaseChartData>& chartData) {
if (!chartData) {
std::cout << " Chart data is null" << std::endl;
return;
}
std::cout << " Chart Name: " << chartData->name.toStdString() << std::endl;
std::cout << " Chart Path: " << chartData->path.toStdString() << std::endl;
// Handle different chart types
if (auto curveChart = std::dynamic_pointer_cast<CurveChartData>(chartData)) {
std::cout << " Chart Type: Curve" << std::endl;
std::cout << " X Title: " << curveChart->xTitle.toStdString() << std::endl;
std::cout << " Y Title: " << curveChart->yTitle.toStdString() << std::endl;
std::cout << " X Range: [" << curveChart->xMin << " - " << curveChart->xMax << "]" << std::endl;
std::cout << " Y Range: [" << curveChart->yMin << " - " << curveChart->yMax << "]" << std::endl;
std::cout << " X Count: " << curveChart->xCount << std::endl;
std::cout << " Time: " << curveChart->t << std::endl;
std::cout << " Curves (" << curveChart->curves.size() << "):" << std::endl;
for (const auto& curve : curveChart->curves) {
std::cout << " - Name: " << curve.name.toStdString()
<< ", Range: [" << curve.start << " - " << curve.stop << "]"
<< ", Color: " << curve.color.toStdString() << std::endl;
}
} else if (auto surfaceChart = std::dynamic_pointer_cast<SurfaceChartData>(chartData)) {
std::cout << " Chart Type: Surface" << std::endl;
std::cout << " X Title: " << surfaceChart->xTitle.toStdString() << std::endl;
std::cout << " Y Title: " << surfaceChart->yTitle.toStdString() << std::endl;
std::cout << " Z Title: " << surfaceChart->zTitle.toStdString() << std::endl;
std::cout << " X Range: [" << surfaceChart->xMin << " - " << surfaceChart->xMax << "]" << std::endl;
std::cout << " Y Range: [" << surfaceChart->yMin << " - " << surfaceChart->yMax << "]" << std::endl;
std::cout << " Z Range: [" << surfaceChart->zMin << " - " << surfaceChart->zMax << "]" << std::endl;
std::cout << " X Count: " << surfaceChart->xCount << std::endl;
std::cout << " Y Count: " << surfaceChart->yCount << std::endl;
std::cout << " Z Count: " << surfaceChart->zCount << std::endl;
std::cout << " Time: " << surfaceChart->t << std::endl;
std::cout << " Surface Curves (" << surfaceChart->curves.size() << "):" << std::endl;
for (const auto& curve : surfaceChart->curves) {
std::cout << " - Name: " << curve.name.toStdString()
<< ", Range: [" << curve.start << " - " << curve.stop << "]"
<< ", Color: " << curve.color.toStdString()
<< ", Position: (" << curve.x << "," << curve.y << "," << curve.z << ")" << std::endl;
}
} else if (auto tableChart = std::dynamic_pointer_cast<TableChartData>(chartData)) {
std::cout << " Chart Type: Table" << std::endl;
std::cout << " Head: " << tableChart->head.toStdString() << std::endl;
std::cout << " Time: " << tableChart->t << std::endl;
std::cout << " Table Data (" << tableChart->curves.size() << "):" << std::endl;
for (const auto& curve : tableChart->curves) {
std::cout << " - Name: " << curve.name.toStdString()
<< ", Color: " << curve.color.toStdString()
<< ", Data: " << curve.data.toStdString() << std::endl;
}
} else if (auto lightChart = std::dynamic_pointer_cast<LightChartData>(chartData)) {
std::cout << " Chart Type: Light" << std::endl;
std::cout << " Open Color: " << lightChart->openColor.toStdString() << std::endl;
std::cout << " Close Color: " << lightChart->closeColor.toStdString() << std::endl;
std::cout << " Time: " << lightChart->t << std::endl;
std::cout << " Light Data (" << lightChart->curves.size() << "):" << std::endl;
for (const auto& curve : lightChart->curves) {
std::cout << " - Name: " << curve.name.toStdString()
<< ", Data: " << curve.data.toStdString() << std::endl;
}
} else {
std::cout << " Chart Type: Unknown" << std::endl;
}
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
std::cout << "Testing XML Chart Parsing with New Inheritance Structure..." << std::endl;
// Test XML file path
QString xmlFilePath = "test_workspace.xml";
// Create parser instance
WorkSpaceXMLParse parser;
// Parse the XML file
FileTypeData fileData;
bool success = parser.ParseFiles(xmlFilePath, fileData);
if (!success) {
std::cout << "Failed to parse XML file: " << xmlFilePath.toStdString() << std::endl;
return -1;
}
std::cout << "Successfully parsed XML file!" << std::endl;
std::cout << "=== File Type Data ===" << std::endl;
std::cout << "Files count: " << fileData.files.size() << std::endl;
std::cout << "Charts count: " << fileData.charts.size() << std::endl;
// Print file information
std::cout << "\n=== Files ===" << std::endl;
for (int i = 0; i < fileData.files.size(); ++i) {
const auto& file = fileData.files[i];
std::cout << "File " << i << ":" << std::endl;
std::cout << " Name: " << file.name.toStdString() << std::endl;
std::cout << " Path: " << file.path.toStdString() << std::endl;
std::cout << " Type: " << static_cast<int>(file.type) << std::endl;
}
// Print chart information
std::cout << "\n=== Charts ===" << std::endl;
for (int i = 0; i < fileData.charts.size(); ++i) {
std::cout << "Chart " << i << ":" << std::endl;
printChartData(fileData.charts[i]);
std::cout << std::endl;
}
std::cout << "Test completed successfully!" << std::endl;
return 0;
}

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<scene name="test_chart" describe="测试图表解析" uuid="{test-uuid}" viewpoint="120.000000, 25.000000, 100.000000, 0.000000, -90.000000, 8200000.000000" commondPath="">
<charts>
<Wave file="D:/Project/DYTSrouce/bin/Release/workspace/test/Wave.txt"/>
<Report Report="D:/Project/DYTSrouce/bin/Release/workspace/test/Report.txt"/>
<RD RD="D:/Project/DYTSrouce/bin/Release/workspace/test/RD.txt"/>
<SimMatlab SimMatlab=""/>
</charts>
<timestep path="Timestep.txt"/>
<lamp path="D:/Project/DYTSrouce/bin/Release/workspace/test/Lamp.txt"/>
<commond path="command.xml"/>
<files>
<type name="curve" count="2">
<chart name="测试曲线1" path="Wave.txt" xTitle="时间" yTitle="幅度" xMin="0" xMax="250" xCount="6" yMin="-800" yMax="800" t="0">
<curve name="曲线1" color="255,0,0" start="1" stop="241"/>
<curve name="曲线2" color="0,255,0" start="50" stop="200"/>
</chart>
<chart name="测试曲线2" path="Wave2.txt" xTitle="频率" yTitle="功率" xMin="0" xMax="100" xCount="5" yMin="0" yMax="1000" t="0">
<curve name="功率曲线" color="0,0,255" start="1" stop="100"/>
</chart>
</type>
<type name="surface" count="1">
<Chart Name="RD图" path="RD.txt" xTitle="y" yTitle="z" zTitle="x" xMin="0" xMax="14000" xCount="7" yMin="0" yMax="0" yCount="0" zMin="0" zMax="70" zCount="7" t="0">
<curve Name="RD曲面" Color="61,38,168" Start="0" Stop="0" x="y" y="z" z="x"/>
</Chart>
</type>
<type name="table" count="1">
<chart Name="测试表格" path="Report.txt" head="编号,信噪比,方位瞄准线,俯仰注视角,方位,俯仰,属性,多普勒,航线,速度,经度,纬度,距离,速率,径向尺寸,目标RCS" t="0">
<curve Name="目标1" color="" data="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"/>
</chart>
</type>
<type name="light" count="1">
<chart name="信号灯" path="Lamp.txt" openColor="0,255,0" closeColor="255,0,0" t="0">
<curve name="目标1,目标2,目标3" data="1,2,3"/>
</chart>
</type>
</files>
<entities>
<Entity uuid="{test-entity-uuid}" name="test_entity">
<MeshComponent mesh="test/test.ive" location="0.000000,0.000000,0.000000" rotation="0.000000,0.000000,0.000000" scale="1.000000,1.000000,1.000000" uuid="{test-mesh-uuid}">
<LabelComponent text="test_entity" fontSize="26" visible="true" color="1.00,0.00,0.00,1.00" location="0.000000,0.000000,0.000000" rotation="0.000000,0.000000,0.000000" scale="1.000000,1.000000,1.000000" uuid="{test-label-uuid}"/>
</MeshComponent>
</Entity>
</entities>
</scene>

View File

@ -3,21 +3,11 @@
<model name="Electronic Jammer" displayName="Electronic Jammer" <model name="Electronic Jammer" displayName="Electronic Jammer"
description="Comprehensive electronic warfare jamming equipment" description="Comprehensive electronic warfare jamming equipment"
meshFile="models/electronic_jammer.ive" meshFile="models/electronic_jammer.ive"
enabled="true" /> icon="icons/electronic_jammer_icon.png"
<model name="Communication Jammer" displayName="Communication Jammer"
description="Specialized communication signal jamming equipment"
meshFile="models/comm_jammer.ive"
enabled="true" />
<model name="Radar Jammer" displayName="Radar Jammer"
description="Radar signal jamming and deception equipment"
meshFile="models/radar_jammer.ive"
enabled="true" />
<model name="GPS Jammer" displayName="GPS Jammer"
description="Satellite navigation signal jamming equipment"
meshFile="models/gps_jammer.ive"
enabled="true" /> enabled="true" />
<model name="Signal Jammer" displayName="Signal Jammer" <model name="Signal Jammer" displayName="Signal Jammer"
description="Multi-frequency signal jamming equipment" description="Multi-frequency signal jamming equipment"
meshFile="models/signal_jammer.ive" meshFile="models/signal_jammer.ive"
icon="icons/signal_jammer_icon.png"
enabled="true"/> enabled="true"/>
</modelCategory> </modelCategory>

View File

@ -1,23 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<modelCategory name="Missile" displayName="Missiles" icon="missile_icon.png"> <modelCategory name="Missile" displayName="Missiles" icon="missile_icon.png">
<model name="Cruise Missile" displayName="Cruise Missile"
description="Long-range precision strike cruise missile"
meshFile="models/cruise_missile.ive"
enabled="true" />
<model name="Ballistic Missile" displayName="Ballistic Missile" <model name="Ballistic Missile" displayName="Ballistic Missile"
description="Long-range ballistic missile system" description="Long-range ballistic missile system"
meshFile="models/ballistic_missile.ive" meshFile="models/ballistic_missile.ive"
enabled="true" /> icon="icons/ballistic_missile_icon.png"
<model name="Anti-Ship Missile" displayName="Anti-Ship Missile"
description="Specialized anti-ship attack missile"
meshFile="models/antiship_missile.ive"
enabled="true" />
<model name="Surface-to-Air Missile" displayName="Surface-to-Air Missile"
description="Surface-to-air defense missile system"
meshFile="models/sam_missile.ive"
enabled="true" />
<model name="Anti-Tank Missile" displayName="Anti-Tank Missile"
description="Anti-armor precision guided missile"
meshFile="models/antitank_missile.ive"
enabled="true" /> enabled="true" />
</modelCategory> </modelCategory>

View File

@ -1,23 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<modelCategory name="Satellite" displayName="Satellites" icon="satellite_icon.png"> <modelCategory name="Satellite" displayName="Satellites" icon="satellite_icon.png">
<model name="Communication Satellite" displayName="Communication Satellite" <model name="Communication Satellite" displayName="Communication Satellite"
description="Satellite platform providing global communication services" description="High-capacity communication relay satellite"
meshFile="models/comm_satellite.ive" meshFile="models/comm_satellite.ive"
enabled="true" /> icon="icons/comm_satellite_icon.png"
<model name="Weather Satellite" displayName="Weather Satellite"
description="Observation satellite monitoring weather and climate changes"
meshFile="models/weather_satellite.ive"
enabled="true" />
<model name="GPS Satellite" displayName="GPS Satellite"
description="Global Positioning System satellite"
meshFile="models/gps_satellite.ive"
enabled="true" />
<model name="Spy Satellite" displayName="Spy Satellite"
description="Military reconnaissance and surveillance satellite"
meshFile="models/spy_satellite.ive"
enabled="true" />
<model name="Scientific Satellite" displayName="Scientific Satellite"
description="Dedicated satellite for scientific research"
meshFile="models/science_satellite.ive"
enabled="true" /> enabled="true" />
</modelCategory> </modelCategory>

View File

@ -3,21 +3,11 @@
<model name="Destroyer" displayName="Destroyer" <model name="Destroyer" displayName="Destroyer"
description="High-speed combat vessel with powerful anti-submarine and air defense capabilities" description="High-speed combat vessel with powerful anti-submarine and air defense capabilities"
meshFile="models/destroyer.ive" meshFile="models/destroyer.ive"
icon="icons/destroyer_icon.png"
enabled="true"/> enabled="true"/>
<model name="Aircraft Carrier" displayName="Aircraft Carrier" <model name="Aircraft Carrier" displayName="Aircraft Carrier"
description="Large aircraft carrier, mobile airfield and command center at sea" description="Large aircraft carrier, mobile airfield and command center at sea"
meshFile="models/carrier.ive" meshFile="models/carrier.ive"
enabled="true" /> icon="icons/carrier_icon.png"
<model name="Frigate" displayName="Frigate"
description="Medium-sized escort vessel, multi-purpose combat platform"
meshFile="models/frigate.ive"
enabled="true" />
<model name="Submarine" displayName="Submarine"
description="Underwater combat platform with strong stealth capabilities"
meshFile="models/submarine.ive"
enabled="true" />
<model name="Cruiser" displayName="Cruiser"
description="Heavy combat vessel with powerful firepower"
meshFile="models/cruiser.ive"
enabled="true"/> enabled="true"/>
</modelCategory> </modelCategory>