first commit
This commit is contained in:
commit
ac8b22f196
54
.gitignore
vendored
Normal file
54
.gitignore
vendored
Normal file
@ -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*
|
||||
|
151
MousePicker.cpp
Normal file
151
MousePicker.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#include "MousePicker.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include <osg/Point>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
MousePicker::MousePicker(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
// 防止老点绘制影响新点的求交运算
|
||||
currentDrawNode->setNodeMask(0xffffffff & (~0x00000004));
|
||||
}
|
||||
|
||||
void MousePicker::setRoot(osg::ref_ptr<osg::Group> 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<osgViewer::Viewer*>( &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<osg::Vec4Array> 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<osg::Geometry> MousePicker::createPointGeode(const osg::Vec3 &pos)
|
||||
{
|
||||
osg::Geometry *geom = new osg::Geometry();
|
||||
|
||||
osg::ref_ptr<osg::Vec3Array> vertex = new osg::Vec3Array();
|
||||
vertex->push_back(pos);
|
||||
geom->setVertexArray(vertex.get());
|
||||
|
||||
osg::ref_ptr<osg::Vec4Array> 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;
|
||||
}
|
43
MousePicker.h
Normal file
43
MousePicker.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef MOUSEPICKER_H
|
||||
#define MOUSEPICKER_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QObject>
|
||||
#include <osg/Geode>
|
||||
#include <osgGA/GUIEventHandler>
|
||||
|
||||
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<osg::Group> root = nullptr);
|
||||
void activate(PickingMode _mode, osg::Node* model);
|
||||
bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa );
|
||||
void disactivate();
|
||||
static osg::ref_ptr<osg::Geometry> createPointGeode(const osg::Vec3 &pos);
|
||||
|
||||
signals:
|
||||
void editionDone(PickingMode, osg::ref_ptr<osg::Vec3Array>);
|
||||
|
||||
private:
|
||||
bool isActivated = false;
|
||||
bool isDrawing = false;
|
||||
PickingMode mode;
|
||||
|
||||
osg::Vec3 pushPnt;
|
||||
osg::ref_ptr<osg::Node> model;
|
||||
osg::ref_ptr<osg::Group> drawNodeList = new osg::Group;
|
||||
osg::ref_ptr<osg::Geode> currentDrawNode = new osg::Geode;
|
||||
osg::ref_ptr<osg::Geometry> lineGeometry;
|
||||
osg::ref_ptr<osg::Vec3Array> vertexArray;
|
||||
};
|
||||
|
||||
|
||||
#endif // MOUSEPICKER_H
|
18
main.cpp
Normal file
18
main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
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();
|
||||
}
|
262
mainwindow.cpp
Normal file
262
mainwindow.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtCore>
|
||||
#include <QtXml>
|
||||
#include <math.h>
|
||||
#include <osgQOpenGL/osgQOpenGLWidget>
|
||||
|
||||
#include <osg/Point>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgGA/TrackballManipulator>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
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<QUrl> urls = event->mimeData()->urls();
|
||||
if(urls.isEmpty()){
|
||||
return;
|
||||
}
|
||||
QList<QUrl>::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<float>( osgWidget->width()) / static_cast<float>( osgWidget->height() );
|
||||
osgWidget->getOsgViewer()->getCamera()->setProjectionMatrixAsPerspective( 30.f, aspectRatio, 1.f, 1000.f );
|
||||
|
||||
osg::ref_ptr<osg::Light> 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<Item, QList<Item>> 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<Item> 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<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int index){
|
||||
modelChosen->clear();
|
||||
QList<Item> 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<osg::Vec3Array> 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;
|
||||
}
|
60
mainwindow.h
Normal file
60
mainwindow.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "myNodeVisitor.h"
|
||||
#include "MousePicker.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <osgQOpenGL/osgQOpenGLWidget>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
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
|
||||
|
61
mainwindow.ui
Normal file
61
mainwindow.ui
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1331</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1331</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>文件</string>
|
||||
</property>
|
||||
<addaction name="actionOpenModel"/>
|
||||
<addaction name="actionUpdateModel"/>
|
||||
<addaction name="actionZoomToExtent"/>
|
||||
<addaction name="actionEditModel"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionOpenModel">
|
||||
<property name="text">
|
||||
<string>打开模型</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUpdateModel">
|
||||
<property name="text">
|
||||
<string>更新模型</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionZoomToExtent">
|
||||
<property name="text">
|
||||
<string>重置视角</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditModel">
|
||||
<property name="text">
|
||||
<string>模型编辑</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
147
myNodeVisitor.cpp
Normal file
147
myNodeVisitor.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include "myNodeVisitor.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/ProxyNode>
|
||||
#include <osg/PagedLOD>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
myNodeVisitor::myNodeVisitor()
|
||||
{
|
||||
opt->setOptionString("WriteImageHint=IncludeFile");
|
||||
}
|
||||
|
||||
void myNodeVisitor::apply(osg::Geode &node)
|
||||
{
|
||||
// 遍历Geode里面的所有Geometry,即形状(点、线、面)
|
||||
for(uint i = 0; i<node.getNumDrawables(); i++){
|
||||
osg::Geometry* pGeo = node.getDrawable(i)->asGeometry();
|
||||
if(pGeo){
|
||||
osg::Vec3Array* vertex = dynamic_cast<osg::Vec3Array*>(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; i<node.getNumChildren(); i++){
|
||||
childAffected = false;
|
||||
node.getChild(i)->accept(*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<osg::Node> 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<osg::Vec3Array> 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;
|
||||
}
|
35
myNodeVisitor.h
Normal file
35
myNodeVisitor.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef MYNODEVISITOR_H
|
||||
#define MYNODEVISITOR_H
|
||||
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osgUtil/Optimizer>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <QtCore>
|
||||
|
||||
// 深度优先的访问器
|
||||
class myNodeVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
myNodeVisitor();
|
||||
|
||||
void setPoints(osg::ref_ptr<osg::Vec3Array> _vertexArray) {vertexArray = _vertexArray;}
|
||||
void setBoundaryList(QList<osg::ref_ptr<osg::Vec3Array>> _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<osg::Vec3Array> vertexArray;
|
||||
QList<osg::ref_ptr<osg::Vec3Array>> boundaryList;
|
||||
};
|
||||
#endif // MYNODEVISITOR_H
|
45
simulationMaster.pro
Normal file
45
simulationMaster.pro
Normal file
@ -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
|
3
simulationMaster_zh_CN.ts
Normal file
3
simulationMaster_zh_CN.ts
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="simulationMaster_zh_CN"></TS>
|
Loading…
x
Reference in New Issue
Block a user