DYTSrouce/src/viewer/OsgWidget.cpp
2025-11-02 17:52:24 +08:00

320 lines
11 KiB
C++

#include "viewer/OsgWidget.h"
#include <QWindow>
#include <QGridLayout>
#include <QMessageBox>
#include <QScreen>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDebug>
#include <osgDB/ReadFile>
#include <osgEarthUtil/EarthManipulator>
#include <osgUtil/LineSegmentIntersector>
#include <osgEarth/SpatialReference>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#include "OsgView.h"
#include "OsgViewer.h"
#include "common/SpdLogger.h"
#include "scene/OEScene.h"
#include "ui/MainFrame.h"
#include "workspace/WorkSpaceManager.h"
#include "workspace/WorkSpace.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 ) {
view->addEventHandler(new osgViewer::StatsHandler());
view->addEventHandler(new osgViewer::WindowSizeHandler());
view->addEventHandler(new osgViewer::ThreadingHandler());
view->addEventHandler(new osgViewer::LODScaleHandler());
view->addEventHandler(new osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet()));
view->addEventHandler(new osgViewer::RecordCameraPathHandler());
view->addEventHandler(new osgViewer::ScreenCaptureHandler());
}
OsgWidget::OsgWidget(QWidget* parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
// setAttribute(Qt::WA_PaintOnScreen, true);
// setAttribute(Qt::WA_StaticContents, true);
// setAttribute(Qt::WA_NoSystemBackground, true);
//setAttribute(Qt::WA_OpaquePaintEvent, true);
// setAttribute(Qt::WA_DontCreateNativeAncestors, false);
setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
setMouseTracking(true);
setKeyEventSetsDone(0);
// 启用拖拽接收
setAcceptDrops(true);
connect( &timer_, SIGNAL(timeout()), this, SLOT(update()) );
timer_.start( 10 );
setMinimumSize(100, 100);
LOG_INFO("OsgWidget::OsgWidget");
}
OsgWidget::~OsgWidget() {
LOG_INFO("OsgWidget::~OsgWidget");
if (nullptr != workspace_) {
workspace_->Unlaod();
}
if (nullptr != viewUI_) {
viewUI_->RemoveUI(activeScene_->GetOrCreateSceneUI());
viewUI_ = nullptr;
}
}
void OsgWidget::Initialize() {
LOG_INFO("OsgWidget::Initialize");
QHBoxLayout* layout = new QHBoxLayout(this);
activeScene_ = new OEScene;
connect(&WorkSpaceManager::Get(), &WorkSpaceManager::WorkSpaceChanged, [this](WorkSpace* workspace) {
if (nullptr == workspace) {
LOG_WARN("workspace is nullptr");
return;
}
activeScene_->SetHomeViewpoint(workspace->GetHomeViewpoint(), 3.0);
}
);
QWidget* widget = addViewWidget( createGraphicsWindow(0,0,100,100));
layout->addWidget(widget);
viewUI_ = new OsgViewUI(view_, 100,100);
viewUI_->AddUI(activeScene_->GetOrCreateSceneUI());
//osgScutcheonManager::instance()->Init(view_.get(), activeScene_);
}
void OsgWidget::Uninitialize() {
LOG_INFO("OsgWidget::Uninitialize");
if (nullptr != viewUI_) {
viewUI_->RemoveUI(activeScene_->GetOrCreateSceneUI());
viewUI_ = nullptr;
}
if (nullptr != activeScene_) {
activeScene_->DetachView(view_);
activeScene_ = nullptr;
}
if (nullptr != view_) {
removeView(view_);
view_ = nullptr;
}
}
void OsgWidget::LoadDefaultScene() {
dyt_check(nullptr != activeScene_);
if (nullptr == WorkSpaceManager::Get().LoadDefaultWorkspace(activeScene_)) {
LOG_ERROR("load default workspace failed");
//QMessageBox::warning(this, tr("warning"), tr("default workspace failed"));
}
}
void OsgWidget::OnLoadDyt(const QString& path) {
LOG_INFO("load dyt path:{}", path.toStdString());
WorkSpace* workSpace = WorkSpaceManager::Get().LoadDyt(path);
if (nullptr == workSpace) {
QMessageBox::warning(&MainFrame::Get(), tr("warning"),
tr("open dyt file failed"), QMessageBox::Ok);
return;
}
const QString& name = workSpace->GetName();
const QString windowTitle = MainFrame::Get().windowTitle();
MainFrame::Get().setWindowTitle(windowTitle + "-" + name);
WorkSpaceManager::Get().SetCurrent(workSpace);
if (nullptr != workspace_ && workspace_ != workSpace) {
workspace_->Unlaod();
}
workspace_ = workSpace;
emit signalResetWorkSpace();
}
osgQt::GraphicsWindowQt* OsgWidget::createGraphicsWindow(int x, int y, int w, int h, const std::string& name,
bool windowDecoration) {
osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->windowName = name;
traits->windowDecoration = windowDecoration;
traits->x = x;
traits->y = y;
traits->width = w;
traits->height = h;
traits->doubleBuffer = true;
traits->alpha = ds->getMinimumNumAlphaBits();
traits->stencil = ds->getMinimumNumStencilBits();
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = 16/*ds->getNumMultiSamples()*/;
return new osgQt::GraphicsWindowQt(traits.get());
}
QWidget* OsgWidget::addViewWidget(osgQt::GraphicsWindowQt* gw) {
view_ = new osgViewer::View;
addView( view_ );
ConfigureView(view_);
osg::Camera* camera = view_->getCamera();
camera->setGraphicsContext( gw );
const osg::GraphicsContext::Traits* traits = gw->getTraits();
camera->setClearColor( osg::Vec4(0.2f, 0.2f, 0.6f, 1.0) );
camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );
activeScene_->AttachView(view_);
return gw->getGLWidget();
}
void OsgWidget::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
if (nullptr == view_) {
return;
}
qreal devicePixelRatio = screen()->devicePixelRatio();
const QSize& size = event->size();
viewUI_->Resize(size.width() * devicePixelRatio, size.height() * devicePixelRatio);
}
void OsgWidget::paintEvent(QPaintEvent*) {
frame();
}
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")) {
LOG_INFO("OsgWidget::dragEnterEvent - Accept preset model drag");
event->acceptProposedAction();
} else {
LOG_INFO("OsgWidget::dragEnterEvent - Ignore drag, not preset model format");
event->ignore();
}
}
void OsgWidget::dragMoveEvent(QDragMoveEvent* event) {
// 检查是否是预制模型拖拽
if (event->mimeData()->hasFormat("application/x-preset-model")) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void OsgWidget::dropEvent(QDropEvent* event) {
LOG_INFO("OsgWidget::dropEvent - Start processing drop event");
if (event->mimeData()->hasFormat("application/x-preset-model")) {
QByteArray data = event->mimeData()->data("application/x-preset-model");
QString modelInfo = QString::fromUtf8(data);
LOG_INFO("OsgWidget::dropEvent - Received model info:{}", modelInfo.toStdString());
QStringList parts = modelInfo.split("|");
if (parts.size() == 2) {
QString modelType = parts[0];
QString modelName = parts[1];
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);
event->acceptProposedAction();
LOG_INFO("OsgWidget::dropEvent - Drag processing completed, accepted");
} else {
LOG_ERROR("OsgWidget::dropEvent - Data format error, expected: type|name, actual:{}", modelInfo.toStdString());
event->ignore();
}
} else {
LOG_INFO("OsgWidget::dropEvent - Not preset model format, ignore drag");
event->ignore();
}
}
void OsgWidget::OnPresetModelDropped(const QString& modelType, const QString& modelName, const QPointF& position) {
LOG_INFO("OsgWidget::OnPresetModelDropped - Dropped model type:{} name:{} position:({}, {})", modelType.toStdString(), modelName.toStdString(), position.x(), position.y());
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;
}