From ac8b22f196644a57723e95b1ac891e165939d637 Mon Sep 17 00:00:00 2001 From: Zd <1628411814@qq.com> Date: Thu, 23 Dec 2021 17:46:55 +0800 Subject: [PATCH] first commit --- .gitignore | 54 ++++++++ MousePicker.cpp | 151 ++++++++++++++++++++++ MousePicker.h | 43 +++++++ main.cpp | 18 +++ mainwindow.cpp | 262 ++++++++++++++++++++++++++++++++++++++ mainwindow.h | 60 +++++++++ mainwindow.ui | 61 +++++++++ myNodeVisitor.cpp | 147 +++++++++++++++++++++ myNodeVisitor.h | 35 +++++ simulationMaster.pro | 45 +++++++ simulationMaster_zh_CN.ts | 3 + 11 files changed, 879 insertions(+) create mode 100644 .gitignore create mode 100644 MousePicker.cpp create mode 100644 MousePicker.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 myNodeVisitor.cpp create mode 100644 myNodeVisitor.h create mode 100644 simulationMaster.pro create mode 100644 simulationMaster_zh_CN.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5405aaa --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# ---> Qt +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.so.* +*.dll +*.dylib + +# Qt-es +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qmlc +*.jsc +Makefile* +*build-* +*.qm +*.prl + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator CMake +CMakeLists.txt.user* + +# QtCreator 4.8< compilation database +compile_commands.json + +# QtCreator local machine specific files for imported projects +*creator.user* + diff --git a/MousePicker.cpp b/MousePicker.cpp new file mode 100644 index 0000000..d7c4656 --- /dev/null +++ b/MousePicker.cpp @@ -0,0 +1,151 @@ +#include "MousePicker.h" + +#include + +#include +#include +#include + +MousePicker::MousePicker(QObject *parent) + : QObject(parent) +{ + // 防止老点绘制影响新点的求交运算 + currentDrawNode->setNodeMask(0xffffffff & (~0x00000004)); +} + +void MousePicker::setRoot(osg::ref_ptr root) +{ +// root->addChild(currentDrawNode); + root->addChild(drawNodeList); +} + +void MousePicker::activate(PickingMode _mode, osg::Node* node) +{ + disactivate(); + mode = _mode; + isActivated = true; + model = node; +} + +bool MousePicker::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) +{ + if(!isActivated){ + return false; + } + osgViewer::Viewer* pViewer = dynamic_cast( &aa ); + osgUtil::LineSegmentIntersector::Intersections intersections; + pViewer->computeIntersections(ea, intersections, 0x00000004); + if(intersections.empty()){ + return false; + } + osg::Vec3 mouseWorldCoord = intersections.begin()->getWorldIntersectPoint(); + switch( ea.getEventType() ){ + case osgGA::GUIEventAdapter::PUSH:{ + if(ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON){ + if(!isDrawing){ + // 初始化lineGeometry + lineGeometry = new osg::Geometry; + lineGeometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); + currentDrawNode->addDrawable(lineGeometry); + // 初始化vertexArray + vertexArray = new osg::Vec3Array; + vertexArray->push_back(mouseWorldCoord); + osg::ref_ptr color = new osg::Vec4Array(); + color->push_back(osg::Vec4(0.0f, 0.8f, 0.8f, 0.5f) ); + lineGeometry->setColorArray(color, osg::Array::BIND_OVERALL); + isDrawing = true; + } + vertexArray->push_back(mouseWorldCoord); + vertexArray->dirty(); + pushPnt = mouseWorldCoord; + } + if(ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON){ + // 当点击右键时, 退出编辑 + disactivate(); + } + return false; + } + case osgGA::GUIEventAdapter::RELEASE:{ + if(ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON){ + // 点击事件完成时 + if(pushPnt != mouseWorldCoord){ + // 当用户真正希望的是拖动视角时,弹出点击事件的录入操作,假装无事发生 + vertexArray->pop_back(); + return false; + } + // 绘制相应点 +// currentDrawNode->addDrawable(createPointGeode(mouseWorldCoord)); + + osg::MatrixTransform* mt = new osg::MatrixTransform; + mt->setMatrix( + osg::Matrix::translate(mouseWorldCoord)); + mt->addChild(model); + drawNodeList->addChild(mt); + if(mode == LinePicker){ + // 如果是线要素则绘制该线段并显示长度 + lineGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertexArray->size())); + } + if(mode == AreaPicker){ + // 如果是面要素则绘制该面并显示面积 + lineGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, vertexArray->size())); + } + } + return false; + } + case osgGA::GUIEventAdapter::MOVE:{ + if(isDrawing){ + // 绘制过程中,按不同的图形类型进行图形绘制的预览 + vertexArray->pop_back(); + vertexArray->push_back(mouseWorldCoord); + vertexArray->dirty(); + if(mode == PointPicker){ + return false; + } + // 根据MOVE的坐标实时更新lineGeometry + lineGeometry->setVertexArray(vertexArray); + lineGeometry->dirtyDisplayList(); + } + return false; + } + case osgGA::GUIEventAdapter::DOUBLECLICK:{ + if(isDrawing){ + // 当双击时,完成当前geode的编辑 + isDrawing = false; + } + // 双击时应避免视角操作,故返回true + return true; + } + } + return false; +} + +void MousePicker::disactivate() +{ + isDrawing = false; + isActivated = false; + emit editionDone(mode, vertexArray); + + currentDrawNode->removeChildren(0, currentDrawNode->getNumChildren()); + lineGeometry = nullptr; + vertexArray = nullptr; +} + +osg::ref_ptr MousePicker::createPointGeode(const osg::Vec3 &pos) +{ + osg::Geometry *geom = new osg::Geometry(); + + osg::ref_ptr vertex = new osg::Vec3Array(); + vertex->push_back(pos); + geom->setVertexArray(vertex.get()); + + osg::ref_ptr color = new osg::Vec4Array(); + color->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) ); + geom->setColorArray(color, osg::Array::BIND_OVERALL); + + geom->getOrCreateStateSet()->setAttribute(new osg::Point(6.0f), osg::StateAttribute::ON); + geom->getOrCreateStateSet()->setMode(GL_POINT_SMOOTH, osg::StateAttribute::ON); + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 1)); + geom->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); + + return geom; +} diff --git a/MousePicker.h b/MousePicker.h new file mode 100644 index 0000000..a177b66 --- /dev/null +++ b/MousePicker.h @@ -0,0 +1,43 @@ +#ifndef MOUSEPICKER_H +#define MOUSEPICKER_H + +#include +#include +#include +#include + +enum PickingMode{ + PointPicker = 0, + LinePicker = 1, + AreaPicker = 2, +}; + +class MousePicker : public QObject, public osgGA::GUIEventHandler +{ + Q_OBJECT +public: + explicit MousePicker(QObject *parent = nullptr); + void setRoot(osg::ref_ptr root = nullptr); + void activate(PickingMode _mode, osg::Node* model); + bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + void disactivate(); + static osg::ref_ptr createPointGeode(const osg::Vec3 &pos); + +signals: + void editionDone(PickingMode, osg::ref_ptr); + +private: + bool isActivated = false; + bool isDrawing = false; + PickingMode mode; + + osg::Vec3 pushPnt; + osg::ref_ptr model; + osg::ref_ptr drawNodeList = new osg::Group; + osg::ref_ptr currentDrawNode = new osg::Geode; + osg::ref_ptr lineGeometry; + osg::ref_ptr vertexArray; +}; + + +#endif // MOUSEPICKER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..59fd086 --- /dev/null +++ b/main.cpp @@ -0,0 +1,18 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication::setStyle("fusion"); + + auto font = QFont("Microsoft YaHei UI"); + font.setPointSize(12); + QApplication::setFont(font); + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..e053c78 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,262 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + setAcceptDrops(true); + + QHBoxLayout * hlayout = new QHBoxLayout(ui->centralwidget); + hlayout->addWidget(osgWidget); + hlayout->setSizeConstraint(QLayout::SetNoConstraint); + osgWidget->setMouseTracking(true); + + connect(osgWidget, &osgQOpenGLWidget::initialized, this, &MainWindow::initOsg); + connect(ui->actionOpenModel, &QAction::triggered, [this](){ + QString modelFile = QFileDialog::getOpenFileName(this, tr("3D Model File Selection"), "", "*.s3c; *.osg; *.osgb"); + if(modelFile != ""){ + addModel(modelFile); + } + }); + connect(ui->actionUpdateModel, &QAction::triggered, this, &MainWindow::updateModel); + connect(ui->actionZoomToExtent, &QAction::triggered, [this]{ + osgWidget->getOsgViewer()->setCameraManipulator(new osgGA::TrackballManipulator()); + }); +} + +MainWindow::~MainWindow() +{ + delete ui; +} +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + event->acceptProposedAction(); +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + if(urls.isEmpty()){ + return; + } + QList::iterator it; + for(it = urls.begin(); it != urls.end(); it++){ + QFileInfo fileInfo(it->toLocalFile()); + if(fileInfo.isFile()){ + addModel(fileInfo.filePath()); + } + } +} + +void MainWindow::initOsg() +{ + osgWidget->getOsgViewer()->setSceneData(root); + osgWidget->getOsgViewer()->getCamera()->setSmallFeatureCullingPixelSize(-1.0f); + osgWidget->getOsgViewer()->getCamera()->setClearColor(osg::Vec4(0.5,0.5,0.5,0.5)); + osgWidget->getOsgViewer()->getCamera()->setNearFarRatio(0.0001); + + float aspectRatio = static_cast( osgWidget->width()) / static_cast( osgWidget->height() ); + osgWidget->getOsgViewer()->getCamera()->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f ); + + osg::ref_ptr light = new osg::Light(); + light->setLightNum(0); + light->setDirection(osg::Vec3(0.0f, 0.0f, -1.0f)); + light->setPosition(osg::Vec4(0.0f, 0.0f, 1000, 0.0f)); + light->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + light->setDiffuse(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + +// //设置恒衰减指数 +// light->setConstantAttenuation(1.0f); +// //设置线形衰减指数 +// light->setLinearAttenuation(0.0f); +// //设置二次方衰减指数 +// light->setQuadraticAttenuation(0.0f); + + osgWidget->getOsgViewer()->setLight(light); + + mp = new MousePicker(this); + osgWidget->getOsgViewer()->addEventHandler(mp); + addModel("C:/Users/16284/Desktop/qt/Tile_+000_+005/Tile_+000_+005/Tile_+000_+005.osgb"); +} + +void MainWindow::addModel(QString modelFile) +{ + if(modelFile == filename){ + return; + } + + filename = modelFile; + QString ext = filename.split('.').back().toLower(); + + osg::Group* layer = new osg::Group; + if(ext == "osg" || ext == "osgb" || ext == "obj" || ext == "ive"){ + clearModel(); + osg::Node* node = osgDB::readNodeFile(Utf8ToGbk(filename.toStdString())); + node->setName(filename.toStdString()); + layer->addChild(node); + } + else if(ext == "s3c"){ + QDir folder(filename); + folder.cdUp(); + QDir dataPath(folder.absolutePath() + "/Data"); + clearModel(); + QStringList tileFolderList = dataPath.entryList(); + for(QString tileFolder: tileFolderList){ + QString tileFile = dataPath.absolutePath() + '/' + tileFolder + '/' + tileFolder + ".osgb"; + if(QDir().exists(tileFile)){ + osg::Node* node = osgDB::readNodeFile(Utf8ToGbk(tileFile.toStdString())); + node->setName(tileFolder.toStdString() + ".osgb"); + layer->addChild(node); + } + } + } + else{ + QMessageBox::warning(this, "simulationMaster", "Unsupported File Format! "); + return; + } + root->addChild(layer); + mp->setRoot(root); + osgGA::TrackballManipulator* tm = new osgGA::TrackballManipulator(); + tm->setAllowThrow(false); + tm->setAnimationTime(1000); + osgWidget->getOsgViewer()->setCameraManipulator(tm); +} + +void MainWindow::updateModel() +{ + // 选择模型更新基于的三维符号库 +// QString libFileName = QFileDialog::getOpenFileName(this, "Plz choose the 3dl file", "", "*.3dl"); + QString libFileName = QString::fromLocal8Bit("C:/Users/16284/Desktop/qt/LibMASTER/基础三维符号库.3dl"); + if(libFileName == ""){ + return; + } + QDir dir = QDir(libFileName); + dir.cdUp(); + + // 将三维符号库读取到内存中 + QMap> map; + QDomDocument doc; + QFile file(libFileName); + file.open(QIODevice::ReadOnly); + doc.setContent(&file); + file.close(); + + QDomNode FLevNode = doc.documentElement().firstChild().toElement().firstChild(); //用来访问第一级符号 + QDomNode SLevNode = FLevNode.toElement().firstChild(); //用来访问第二级符号 + + while(!FLevNode.isNull()){ + if (FLevNode.toElement().tagName() == QStringLiteral("catagory")){ + Item FirstItem; //存一级符号 + QList SecondList; //某一级符号下,所有二级符号组成的列表 + FirstItem.name = FLevNode.toElement().attribute("name").trimmed(); + FirstItem.code = FLevNode.toElement().attribute("code").trimmed(); + SLevNode = FLevNode.toElement().firstChild(); + while(!SLevNode.isNull()){ + if (SLevNode.toElement().tagName() == QStringLiteral("feature")){ + Item SecondItem; //存二级符号 + SecondItem.name = SLevNode.toElement().attribute("name").trimmed(); + SecondItem.code = SLevNode.toElement().attribute("code").trimmed(); + SecondItem.address = SLevNode.toElement().attribute("address").trimmed(); + SecondList << SecondItem; + } + SLevNode = SLevNode.nextSibling(); + } + map.insert(FirstItem, SecondList); + } + FLevNode = FLevNode.nextSibling(); //访问下一个兄弟节点 + } + + // 选择需要渲染的符号 + QDialog dialog(this); + QFormLayout form(&dialog); + form.addRow(new QLabel(QStringLiteral("选择渲染使用的符号"))); + // 获取符号类别名称 + QComboBox *cataChosen = new QComboBox(&dialog); + form.addRow(QStringLiteral("类别名称: "), cataChosen); + // 获取符号类别编码 + QComboBox *modelChosen = new QComboBox(&dialog); + connect(cataChosen, static_cast(&QComboBox::currentIndexChanged), [=](int index){ + modelChosen->clear(); + QList itemList = map.values().at(index); + for(int i = 0; i < itemList.count(); i++){ + modelChosen->addItem(itemList.at(i).name); + } + }); + for(int i = 0; i < map.count(); i++){ + cataChosen->addItem(map.keys().at(i).name); + } + form.addRow(QStringLiteral("符号名称: "), modelChosen); + + // Add Cancel and OK button + QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, &dialog); + form.addRow(&buttonBox); + QObject::connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); + QObject::connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + dialog.adjustSize(); +// dialog.setFixedWidth(250); +// dialog.setFixedHeight(120); + + // Process when OK button is clicked + int result = dialog.exec(); + while(result == QDialog::Accepted){ + if(cataChosen->currentIndex()==-1 || modelChosen->currentIndex()==-1){ + QMessageBox::warning(this, "simulationMaster", "Plz choose the catagory and model"); + result = dialog.exec(); + continue; + } + Item item = map.values().at(cataChosen->currentIndex()).at(modelChosen->currentIndex()); + // 根据item.address读取模型 + osg::Node* model = osgDB::readNodeFile(Utf8ToGbk((dir.absolutePath() + '/' + item.address).toStdString())); + + mp->activate(PickingMode::PointPicker, model); +// connect(mp, &MousePicker::editionDone, [=](PickingMode mode, osg::ref_ptr vertexArray) +// { +// if(vertexArray == nullptr){ +// return; +// } +// if(mode == PickingMode::PointPicker){ +// nv.setPoints(vertexArray); +// root->getChild(0)->accept(nv); +// } +// }); + break; + } +} + +void MainWindow::clearModel() +{ + root->removeChildren(0, root->getNumChildren()); +} + +std::string Utf8ToGbk(std::string str){ + const char* src_str = str.data(); + int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0); + wchar_t* wszGBK = new wchar_t[len + 1]; + memset(wszGBK, 0, len * 2 + 2); + MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len); + len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); + char* szGBK = new char[len + 1]; + memset(szGBK, 0, len + 1); + WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); + std::string strTemp(szGBK); + if (wszGBK) delete[] wszGBK; + if (szGBK) delete[] szGBK; + return strTemp; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..735a5a4 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,60 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "myNodeVisitor.h" +#include "MousePicker.h" + +#include + +#include +#include + +struct Item +{ + QString name; //符号名称 + QString code; //符号代码 + QString address; //符号所在的相对路径 + + bool operator < ( const Item& item) const + { + return this->name < item.name; + } +}; + + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + void initOsg(); + void addModel(QString filename); + void updateModel(); + void clearModel(); + +protected: + void dragEnterEvent(QDragEnterEvent* event = NULL); + void dropEvent(QDropEvent* event); + +private: + Ui::MainWindow *ui; + osgQOpenGLWidget* osgWidget = new osgQOpenGLWidget; + osg::Group* root = new osg::Group; + osg::Geode* drawNode = new osg::Geode; + myNodeVisitor nv; + QString filename; + + MousePicker* mp; +}; + +std::string Utf8ToGbk(std::string str); +#endif // MAINWINDOW_H + diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..7edf2c0 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,61 @@ + + + MainWindow + + + + 0 + 0 + 1331 + 600 + + + + MainWindow + + + + + + 0 + 0 + 1331 + 30 + + + + + 鏂囦欢 + + + + + + + + + + + + 鎵撳紑妯″瀷 + + + + + 鏇存柊妯″瀷 + + + + + 閲嶇疆瑙嗚 + + + + + 妯″瀷缂栬緫 + + + + + + diff --git a/myNodeVisitor.cpp b/myNodeVisitor.cpp new file mode 100644 index 0000000..bedea39 --- /dev/null +++ b/myNodeVisitor.cpp @@ -0,0 +1,147 @@ +#include "myNodeVisitor.h" +#include "mainwindow.h" + +#include +#include +#include +#include +#include + +myNodeVisitor::myNodeVisitor() +{ + opt->setOptionString("WriteImageHint=IncludeFile"); +} + +void myNodeVisitor::apply(osg::Geode &node) +{ + // 遍历Geode里面的所有Geometry,即形状(点、线、面) + for(uint i = 0; iasGeometry(); + if(pGeo){ + osg::Vec3Array* vertex = dynamic_cast(pGeo->getVertexArray()); + if (!vertex){ + continue; + } + for (int i = 0; i < vertex->size(); i++){ + // 对于满足条件的点 + int index = pointsNearVertex((*vertex)[i]); + if (index != -1) + { + (*vertex)[i].z() = vertexArray->at(index).z(); + affected = true; + } + } + } + } + + if (affected && !node.getName().empty()){ + // 和PagedLOD的处理方式一致 + newFileName = QString::fromStdString(node.getName()).split('.').first() + "~.osgb"; + node.accept(*tv); + node.setName(newFileName.toStdString()); + // 写文件 + osgDB::writeNodeFile(node, (workingDir + '/' + newFileName).toStdString(), opt); + childAffected = true; + } +} + +void myNodeVisitor::apply(osg::Group &node) +{ + bool groupAffected = false; + for(uint i = 0; iaccept(*this); + if(childAffected){ + groupAffected = true; + } + } + + if(groupAffected && !node.getName().empty()){ + // 和PagedLOD的处理方式一致 + newFileName = QString::fromStdString(node.getName()).split('.').first() + "~.osgb"; + node.accept(*tv); + node.setName(newFileName.toStdString()); + // 写文件 + osgDB::writeNodeFile(node, (workingDir + '/' + newFileName).toStdString(), opt); + childAffected = true; + } +} + +void myNodeVisitor::apply(osg::PagedLOD &node) +{ + affected = false; + childAffected = false; + for(uint i = 0; i < node.getNumChildren(); i++){ + // 这个遍历过程可能会修改文件 + node.getChild(i)->accept(*this); + } + +// // 使用affected作为初步判断,以尽可能地减少计算量, 非affected文件都不会被修改 +// if(!affected && ! childAffected){ +// return; +// } + + // 如果真的被修改了文件,那么, + workingDir = QString::fromStdString(node.getDatabasePath()); + // for(uint i = 0; i < node.getNumFileNames(); i++){ + for(uint i = 1; i < node.getNumFileNames(); i++){ + // 遍历这个LOD文件中的所有子文件,即金字塔中更精细的那一层,他们也要改 + childAffected = false; + // 读文件以继续遍历 + osg::ref_ptr fileNode = osgDB::readNodeFile(workingDir.toStdString() + '/' + node.getFileName(i)); + if(!fileNode.valid()){ + continue; + } + // 将fileNode和文件名链接在一起,这样当节点被修改时,可以及时更新对应的文件 + fileNode->setName(node.getFileName(i)); + // 两个遍历器都要遍历 + fileNode->accept(*tv); + fileNode->accept(*this); + if(childAffected){ + //更改文件名链接 + node.setFileName(i, newFileName.toStdString()); + // 此时也应该相应地修改pLOD对应的文件 + } + } + + if(!node.getName().empty()){ + newFileName = QString::fromStdString(node.getName()).split('.').first() + "~.osgb"; + node.accept(*tv); + node.setName(newFileName.toStdString()); + // 写文件 + osgDB::writeNodeFile(node, (workingDir + '/' + newFileName).toStdString(), opt); + } + + // 作为别人的儿子,文件被修改了 + childAffected = true; +} + +bool myNodeVisitor::pointInPolygon(osg::Vec3 &point) +{ + for(osg::ref_ptr boundary: boundaryList){ + int i, j, nvert = boundary->size(); + bool c = false; + + // 射线法 + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((boundary->at(i).y() >= point.y()) != (boundary->at(j).y() >= point.y())) && + (point.x() <= (boundary->at(j).x() - boundary->at(i).x()) * (point.y() - boundary->at(i).y()) / (boundary->at(j).y() - boundary->at(i).y()) + boundary->at(i).x()) + ) + c = !c; + } + if(c && point.z() > boundary->at(0).z()){ + return true; + } + } + return false; +} + +int myNodeVisitor::pointsNearVertex(osg::Vec3 &point) +{ + for(int i = 0; i < vertexArray->size(); i++){ + if(pow(point.x() - vertexArray->at(i).x(), 2) + pow(point.y() - vertexArray->at(i).y(), 2) < 4 && point.z() > vertexArray->at(i).z()){ + return i; + } + } + return -1; +} diff --git a/myNodeVisitor.h b/myNodeVisitor.h new file mode 100644 index 0000000..be72746 --- /dev/null +++ b/myNodeVisitor.h @@ -0,0 +1,35 @@ +#ifndef MYNODEVISITOR_H +#define MYNODEVISITOR_H + +#include +#include +#include +#include + +// 深度优先的访问器 +class myNodeVisitor : public osg::NodeVisitor +{ +public: + myNodeVisitor(); + + void setPoints(osg::ref_ptr _vertexArray) {vertexArray = _vertexArray;} + void setBoundaryList(QList> _boundaryList){ boundaryList = _boundaryList; } + virtual void apply(osg::Geode &node) override; + virtual void apply(osg::Group &node) override; + virtual void apply(osg::PagedLOD &node) override; + bool pointInPolygon(osg::Vec3& point); + int pointsNearVertex(osg::Vec3& point); + +private: + osgUtil::Optimizer::TextureVisitor* tv = new osgUtil::Optimizer::TextureVisitor(true, false, false, false, false, false); + osgDB::ReaderWriter::Options* opt = new osgDB::ReaderWriter::Options; + QString workingDir; + QString newFileName; + // 记录点位是否被修改,从而缩减计算量 + bool affected = false; + bool childAffected = false; + + osg::ref_ptr vertexArray; + QList> boundaryList; +}; +#endif // MYNODEVISITOR_H diff --git a/simulationMaster.pro b/simulationMaster.pro new file mode 100644 index 0000000..e0aad2e --- /dev/null +++ b/simulationMaster.pro @@ -0,0 +1,45 @@ +QT += core gui opengl xml + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + + +TARGET = simulationMaster +TEMPLATE = app + + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +INCLUDEPATH += C:/Users/16284/Desktop/qt/OSG-install/include +LIBS += -LC:/Users/16284/Desktop/qt/OSG-install/lib -losg -losgDB -losgQOpenGL -losgViewer -losgGA -lOpenThreads -losgUtil + + +SOURCES += \ + main.cpp \ + mainwindow.cpp\ + MousePicker.cpp \ + myNodeVisitor.cpp + +HEADERS += \ + mainwindow.h\ + myNodeVisitor.h \ + MousePicker.h + +FORMS += \ + mainwindow.ui + +TRANSLATIONS += \ + simulationMaster_zh_CN.ts + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/simulationMaster_zh_CN.ts b/simulationMaster_zh_CN.ts new file mode 100644 index 0000000..77c9e05 --- /dev/null +++ b/simulationMaster_zh_CN.ts @@ -0,0 +1,3 @@ + + +