Browse Source

Implement project management (Closes #14).

Johannes Kreutz 2 years ago
parent
commit
578eb99a87

+ 1 - 1
trackpoint-app/include/EditWidget.hpp

@@ -25,13 +25,13 @@ public:
   int getSelectedPoint();
   void updateTrackpointCount();
   void resetActionPointSettings();
+  void resetAllSettings();
 
 protected:
   virtual void showEvent(QShowEvent* event);
 
 private slots:
   void selectTool(Tool tool);
-  void resetAllSettings();
   void tabChanged(int index);
   void updateNormalModifier();
   void resetNormalModifier();

+ 8 - 3
trackpoint-app/include/MainWindow.hpp

@@ -1,11 +1,13 @@
 #pragma once
 
+// Include modules
 #include "OSGWidget.hpp"
 #include "NoMeshWidget.hpp"
 #include "EditWidget.hpp"
 #include "ProjectStore.hpp"
 #include "enums.hpp"
 
+// Include dependencies
 #include <QMainWindow>
 
 QT_BEGIN_NAMESPACE
@@ -25,10 +27,13 @@ public:
   EditWidget* getEditWiget();
 
 private:
+  void newFile();
   void load();
-  void save();
-  void saveAs();
-  void loadStaticMeshes();
+  bool save();
+  bool saveAs();
+  void close();
+  void cleanup();
+  bool saveChangesPopup();
   Ui::MainWindow* ui;
   OSGWidget* osgWidget;
   NoMeshWidget* noMeshWidget;

+ 1 - 1
trackpoint-app/include/NoMeshWidget.hpp

@@ -12,9 +12,9 @@ class NoMeshWidget: public QWidget {
 public:
   NoMeshWidget(QWidget* parent = nullptr);
   ~NoMeshWidget();
+  void loadMeshFile();
 
 private slots:
-  void loadMeshFile();
   void loadProjectFile();
 
 private:

+ 1 - 0
trackpoint-app/include/OSGWidget.hpp

@@ -37,6 +37,7 @@ public:
   PickHandler* getPicker();
   TrackPointRenderer* getPointRenderer();
   void loadSteamvrThread();
+  void clear();
   osg::ref_ptr<osg::Geometry> _steamvrThreadMesh;
 
 protected:

+ 1 - 0
trackpoint-app/include/OptiTrackPoint.hpp

@@ -14,6 +14,7 @@ public:
   void updateOptiTrackSettings(OptiTrackSettings settings);
 
 private:
+  void updateShift();
   double _length;
   double _radius;
 };

+ 9 - 0
trackpoint-app/include/ProjectStore.hpp

@@ -31,6 +31,14 @@ public:
   bool saveProject(std::string projectFile);
   // Export the project
   bool exportProject(std::string path, ExportSettings settings);
+  // Is currently a project opened
+  bool isProjectOpen();
+  // Close the current project
+  void closeProject();
+  // Is current project modified
+  bool isModified();
+  // Set project modification status
+  void projectModified();
   // UNIVERSAL
   // Get trackpoint
   TrackPoint* getTrackPointById(int id, ActiveTrackingSystem activeTrackingSystem);
@@ -84,6 +92,7 @@ private:
   ActionPointSettings _actionPointSettings = ActionPointSettings {ACTIONPOINT_DEFAULT_IDENFIFIER};
   osg::Vec3 _normalModifier = osg::Vec3(0.0f, 0.0f, 0.0f);
   void load3mfLib();
+  void reset();
   void render3MFMesh();
   void updateMetaData();
   void loadMetaData();

+ 1 - 0
trackpoint-app/include/SteamVRTrackPoint.hpp

@@ -13,5 +13,6 @@ public:
   void updateSteamVRTrackSettings(SteamVRTrackSettings settings);
 
 private:
+  void updateShift();
   double _length;
 };

+ 0 - 2
trackpoint-app/include/TrackPoint.hpp

@@ -19,8 +19,6 @@ protected:
   osg::ref_ptr<osg::MatrixTransform> _rotationGroup;
   osg::ref_ptr<osg::MatrixTransform> _originFixGroup;
   osg::Vec3 _trackOrigin;
-
-private:
   osg::Vec3 _origin;
   osg::Vec3 _normal;
   osg::Vec3 _normalModifier;

+ 1 - 0
trackpoint-app/include/TrackPointRenderer.hpp

@@ -14,6 +14,7 @@ public:
   ~TrackPointRenderer();
   void render(ActiveTrackingSystem activeTrackingSystem);
   std::vector<PointShape*> getShapes();
+  void clear();
 
 private:
   OSGWidget* _osgWidget;

+ 11 - 2
trackpoint-app/src/EditWidget.cpp

@@ -157,6 +157,7 @@ void EditWidget::showEvent(QShowEvent* event) {
 }
 
 void EditWidget::resetAllSettings() {
+  selectedPoint = -1;
   resetNormalModifier();
   resetOptiTrackSettings();
   resetSteamVRTrackSettings();
@@ -170,7 +171,6 @@ void EditWidget::selectTool(Tool tool) {
       ui->selectionToolButton->setChecked(false);
       MainWindow::getInstance()->getOsgWidget()->getPicker()->setSelection(true);
       invalidatePositions();
-      selectedPoint = -1;
       resetAllSettings();
       break;
     }
@@ -201,6 +201,7 @@ void EditWidget::updateNormalModifier() {
     ActiveTrackingSystem activeTrackingSystem = getSelectedTrackingSystem();
     MainWindow::getInstance()->getStore()->getTrackPointById(selectedPoint, activeTrackingSystem)->updateNormalModifier(modifier);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(activeTrackingSystem);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -216,6 +217,7 @@ void EditWidget::resetNormalModifier() {
     ActiveTrackingSystem activeTrackingSystem = getSelectedTrackingSystem();
     MainWindow::getInstance()->getStore()->getTrackPointById(selectedPoint, activeTrackingSystem)->updateNormalModifier(modifier);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(activeTrackingSystem);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -233,6 +235,7 @@ void EditWidget::updateOptiTrackSettings() {
   } else {
     MainWindow::getInstance()->getStore()->getOptiTrackPoints()[selectedPoint]->updateOptiTrackSettings(settings);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(OptiTrack);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -246,6 +249,7 @@ void EditWidget::resetOptiTrackSettings() {
   } else {
     MainWindow::getInstance()->getStore()->getOptiTrackPoints()[selectedPoint]->updateOptiTrackSettings(settings);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(OptiTrack);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -262,6 +266,7 @@ void EditWidget::updateSteamVRTrackSettings() {
   } else {
     MainWindow::getInstance()->getStore()->getSteamVRTrackPoints()[selectedPoint]->updateSteamVRTrackSettings(settings);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(SteamVRTrack);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -274,6 +279,7 @@ void EditWidget::resetSteamVRTrackSettings() {
   } else {
     MainWindow::getInstance()->getStore()->getSteamVRTrackPoints()[selectedPoint]->updateSteamVRTrackSettings(settings);
     MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(SteamVRTrack);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -293,6 +299,7 @@ void EditWidget::updateActionPointSettings(QString qinput) {
       MainWindow::getInstance()->getStore()->updateActionPointSettings(settings);
     } else {
       MainWindow::getInstance()->getStore()->getActionPoints()[selectedPoint]->updateActionPointSettings(settings);
+      MainWindow::getInstance()->getStore()->projectModified();
     }
   }
 }
@@ -316,6 +323,7 @@ void EditWidget::resetActionPointSettings() {
     MainWindow::getInstance()->getStore()->updateActionPointSettings(settings);
   } else {
     MainWindow::getInstance()->getStore()->getActionPoints()[selectedPoint]->updateActionPointSettings(settings);
+    MainWindow::getInstance()->getStore()->projectModified();
   }
 }
 
@@ -345,12 +353,13 @@ void EditWidget::deleteCurrentTrackPoint() {
       break;
     }
     case ActionPoints: {
+      resetActionPointSettings();
       break;
     }
   }
   resetNormalModifier();
   invalidatePositions();
-  MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(OptiTrack);
+  MainWindow::getInstance()->getOsgWidget()->getPointRenderer()->render(activeTrackingSystem);
 }
 
 void EditWidget::exportProject() {

+ 57 - 7
trackpoint-app/src/MainWindow.cpp

@@ -2,8 +2,13 @@
 #include "MainWindow.hpp"
 #include "../gui/ui_MainWindow.h"
 
+// Include modules
+#include "TrackPointRenderer.hpp"
+#include "PickHandler.hpp"
+
 // Include dependencies
 #include <QFileDialog>
+#include <QMessageBox>
 
 MainWindow* globalPointer;
 
@@ -30,7 +35,7 @@ MainWindow::MainWindow(QWidget* parent): QMainWindow(parent), ui(new Ui::MainWin
   newAct = new QAction(tr("&New project"), this);
   newAct->setShortcuts(QKeySequence::New);
   newAct->setStatusTip(tr("Create a new file"));
-  //connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
+  connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
 
   loadAct = new QAction(tr("&Load project"), this);
   loadAct->setShortcuts(QKeySequence::Open);
@@ -49,7 +54,7 @@ MainWindow::MainWindow(QWidget* parent): QMainWindow(parent), ui(new Ui::MainWin
   closeAct = new QAction(tr("&Close project"), this);
   closeAct->setShortcuts(QKeySequence::Close);
   closeAct->setStatusTip(tr("Closing the current project"));
-  //connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
+  connect(closeAct, &QAction::triggered, this, &MainWindow::close);
 
   fileMenu = menuBar()->addMenu(tr("&File"));
   fileMenu->addAction(newAct);
@@ -94,26 +99,71 @@ void MainWindow::renderView(GuiView view) {
   }
 }
 
+void MainWindow::newFile() {
+  if (MainWindow::getInstance()->getStore()->isProjectOpen()) {
+    if (MainWindow::getInstance()->getStore()->isModified()) {
+      if (!saveChangesPopup()) return;
+    }
+    MainWindow::getInstance()->getStore()->closeProject();
+  }
+  renderView(NoMesh);
+  cleanup();
+  noMeshWidget->loadMeshFile();
+}
+
 void MainWindow::load() {
   QString fileName = QFileDialog::getOpenFileName(this, tr("Open a TrackpointApp Project"), "", tr("TrackpointApp Projects (*.trackproj)"));
   std::string projectFile = fileName.toUtf8().constData();
   MainWindow::getInstance()->getStore()->loadProject(projectFile);
 }
 
-void MainWindow::save() {
+bool MainWindow::save() {
   if (!projectStore->saveProject()) {
-    saveAs();
+    return saveAs();
   }
+  return true;
 }
 
-void MainWindow::saveAs() {
+bool MainWindow::saveAs() {
   QString fileName = QFileDialog::getSaveFileName(this, tr("Save your TrackpointApp Project"), "", tr("TrackpointApp Projects (*.trackproj)"));
   std::string fileString = fileName.toUtf8().constData();
   if (!projectStore->saveProject(fileString)) {
     // TODO: Show error popup
+    return false;
   }
+  return true;
 }
 
-void MainWindow::loadStaticMeshes() {
-  
+void MainWindow::close() {
+  if (MainWindow::getInstance()->getStore()->isModified()) {
+    if (!saveChangesPopup()) return;
+  }
+  MainWindow::getInstance()->getStore()->closeProject();
+  renderView(NoMesh);
+  cleanup();
+}
+
+void MainWindow::cleanup() {
+  editWidget->resetAllSettings();
+  osgWidget->clear();
+  osgWidget->getPointRenderer()->clear();
+}
+
+bool MainWindow::saveChangesPopup() {
+  QMessageBox msgBox;
+  msgBox.setText("The current project has been modified.");
+  msgBox.setInformativeText("Do you want to save your changes?");
+  msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+  msgBox.setDefaultButton(QMessageBox::Save);
+  int ret = msgBox.exec();
+  switch(ret) {
+    case QMessageBox::Save:
+      return save();
+    case QMessageBox::Discard:
+      return true;
+    case QMessageBox::Cancel:
+      return false;
+    default:
+      return false;
+  }
 }

+ 5 - 2
trackpoint-app/src/OSGWidget.cpp

@@ -136,8 +136,6 @@ OSGWidget::OSGWidget(QWidget* parent): QOpenGLWidget(parent),
 
   _root->addChild(_coordinateAxes);
 
-  _mesh = new osg::Geode;
-
   // Add axes preview
   osg::ref_ptr<osg::Camera> hudCamera = new osg::Camera;
   int width = 1024;
@@ -193,6 +191,7 @@ OSGWidget::~OSGWidget() {
 void OSGWidget::renderBaseMesh(const osg::ref_ptr<osg::Vec3Array> vertices, const osg::ref_ptr<osg::Vec3Array> normals) {
   _root->removeChild(_mesh);
 
+  _mesh = new osg::Geode;
   osg::ref_ptr<osg::Geometry> meshGeometry = new osg::Geometry;
   meshGeometry->setVertexArray(vertices.get());
   meshGeometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX);
@@ -245,6 +244,10 @@ void OSGWidget::loadSteamvrThread() {
   }
 }
 
+void OSGWidget::clear() {
+  _root->removeChild(_mesh);
+}
+
 void OSGWidget::paintEvent(QPaintEvent*) {
   this->makeCurrent();
 

+ 7 - 3
trackpoint-app/src/OptiTrackPoint.cpp

@@ -4,9 +4,7 @@
 OptiTrackPoint::OptiTrackPoint(const osg::Vec3 point, const osg::Vec3 normal, const osg::Vec3 normalModifier, const double length, const double radius): TrackPoint(point, normal, normalModifier) {
   _length = length;
   _radius = radius;
-
-  osg::Vec3 shift = normal.operator*(length);
-  _trackOrigin = shift.operator+(point);
+  updateShift();
 }
 
 double OptiTrackPoint::getLength() {
@@ -24,4 +22,10 @@ OptiTrackSettings OptiTrackPoint::getOptiTrackSettings() {
 void OptiTrackPoint::updateOptiTrackSettings(OptiTrackSettings settings) {
   _length = settings.length;
   _radius = settings.radius;
+  updateShift();
+}
+
+void OptiTrackPoint::updateShift() {
+  osg::Vec3 shift = _normal.operator*(_length);
+  _trackOrigin = shift.operator+(_origin);
 }

+ 46 - 2
trackpoint-app/src/ProjectStore.cpp

@@ -26,8 +26,12 @@ ProjectStore::~ProjectStore() {
 }
 
 void ProjectStore::loadMesh(std::string meshFile) {
+  if (meshFile == "") {
+    return;
+  }
   if (StringBasics::endsWithCaseInsensitive(meshFile, ".STL")) {
     _projectLoaded = true;
+    _projectModified = false;
     // Read STL file
     std::vector<Lib3MF::sPosition> verticesBuffer;
     std::vector<Lib3MF::sTriangle> triangleBuffer;
@@ -38,6 +42,7 @@ void ProjectStore::loadMesh(std::string meshFile) {
     MainWindow::getInstance()->renderView(Edit);
   } else if (StringBasics::endsWithCaseInsensitive(meshFile, ".3MF")) {
     _projectLoaded = true;
+    _projectModified = false;
     // Read 3MF file
     Lib3MF::PReader reader = _project->QueryReader("3mf");
     reader->ReadFromFile(meshFile);
@@ -50,11 +55,15 @@ void ProjectStore::loadMesh(std::string meshFile) {
 }
 
 bool ProjectStore::loadProject(std::string projectFile) {
+  if (projectFile == "") {
+    return false;
+  }
   if (!_projectLoaded) {
     Lib3MF::PReader reader = _project->QueryReader("3mf");
     reader->ReadFromFile(projectFile);
     _projectLoaded = true;
     _projectModified = false;
+    _projectFile = projectFile;
     loadMetaData();
     return true;
   }
@@ -69,10 +78,14 @@ bool ProjectStore::saveProject() {
 }
 
 bool ProjectStore::saveProject(std::string path) {
+  if (path == "") {
+    return false;
+  }
   updateMetaData();
   Lib3MF::PWriter writer = _project->QueryWriter("3mf");
   writer->WriteToFile(path);
   _projectFile = path;
+  _projectModified = false;
   return true;
 }
 
@@ -177,6 +190,23 @@ bool ProjectStore::exportProject(std::string path, ExportSettings settings) {
   return true;
 }
 
+bool ProjectStore::isProjectOpen() {
+  return _projectLoaded;
+}
+
+void ProjectStore::closeProject() {
+  _projectLoaded = false;
+  reset();
+}
+
+bool ProjectStore::isModified() {
+  return _projectModified;
+}
+
+void ProjectStore::projectModified() {
+  _projectModified = true;
+}
+
 TrackPoint* ProjectStore::getTrackPointById(int id, ActiveTrackingSystem activeTrackingSystem) {
   switch(activeTrackingSystem) {
     case OptiTrack: {
@@ -215,6 +245,7 @@ void ProjectStore::addTrackPoint(osg::Vec3 point, osg::Vec3 normal, ActiveTracki
       break;
     }
   }
+  projectModified();
   MainWindow::getInstance()->getEditWiget()->updateTrackpointCount();
 }
 
@@ -253,6 +284,7 @@ void ProjectStore::removeTrackPoint(int id, ActiveTrackingSystem activeTrackingS
       break;
     }
   }
+  projectModified();
   MainWindow::getInstance()->getEditWiget()->updateTrackpointCount();
 }
 
@@ -317,6 +349,17 @@ void ProjectStore::load3mfLib() {
   _project = _wrapper->CreateModel();
 }
 
+void ProjectStore::reset() {
+  _project = _wrapper->CreateModel();
+  _optiTrackPoints.clear();
+  _steamVrTrackPoints.clear();
+  _actionPoints.clear();
+  _optiTrackSettings = OptiTrackSettings {OPTITRACK_DEFAULT_LENGTH, OPTITRACK_DEFAULT_RADIUS};
+  _steamVrTrackSettings = SteamVRTrackSettings {STEAMVR_DEFAULT_LENGTH};
+  _actionPointSettings = ActionPointSettings {ACTIONPOINT_DEFAULT_IDENFIFIER};
+  _normalModifier = osg::Vec3(0.0f, 0.0f, 0.0f);
+}
+
 void ProjectStore::render3MFMesh() {
   // Get meshes
   Lib3MF::PMeshObjectIterator meshIterator = _project->GetMeshObjects();
@@ -388,7 +431,8 @@ void ProjectStore::updateMetaData() {
     actionPointData.push_back({
       {"point", osgVecToStdVec(actionPoint->getTranslation())},
       {"normal", osgVecToStdVec(actionPoint->getNormal())},
-      {"normalModifier", osgVecToStdVec(actionPoint->getNormalModifier())}
+      {"normalModifier", osgVecToStdVec(actionPoint->getNormalModifier())},
+      {"identifier", actionPoint->getIdentifier()}
     });
   }
   try {
@@ -446,7 +490,7 @@ void ProjectStore::loadMetaData() {
       osg::Vec3f point = osg::Vec3f(pointData["point"][0], pointData["point"][1], pointData["point"][2]);
       osg::Vec3f normal = osg::Vec3f(pointData["normal"][0], pointData["normal"][1], pointData["normal"][2]);
       osg::Vec3f normalModifier = osg::Vec3f(pointData["normalModifier"][0], pointData["normalModifier"][1], pointData["normalModifier"][2]);
-      ActionPoint* actionPoint = new ActionPoint(point, normal, normalModifier);
+      ActionPoint* actionPoint = new ActionPoint(point, normal, normalModifier, pointData["identifier"]);
       _actionPoints.push_back(actionPoint);
     }
   } catch (Lib3MF::ELib3MFException &e) {

+ 7 - 3
trackpoint-app/src/SteamVRTrackPoint.cpp

@@ -3,9 +3,7 @@
 
 SteamVRTrackPoint::SteamVRTrackPoint(const osg::Vec3 point, const osg::Vec3 normal, const osg::Vec3 normalModifier, const double length): TrackPoint(point, normal, normalModifier) {
   _length = length;
-
-  osg::Vec3 shift = normal.operator*(length);
-  _trackOrigin = shift.operator+(point);
+  updateShift();
 }
 
 double SteamVRTrackPoint::getLength() {
@@ -18,4 +16,10 @@ SteamVRTrackSettings SteamVRTrackPoint::getSteamVRTrackSettings() {
 
 void SteamVRTrackPoint::updateSteamVRTrackSettings(SteamVRTrackSettings settings) {
   _length = settings.length;
+  updateShift();
+}
+
+void SteamVRTrackPoint::updateShift() {
+  osg::Vec3 shift = _normal.operator*(_length);
+  _trackOrigin = shift.operator+(_origin);
 }

+ 8 - 4
trackpoint-app/src/TrackPointRenderer.cpp

@@ -17,10 +17,7 @@ TrackPointRenderer::~TrackPointRenderer() {
 }
 
 void TrackPointRenderer::render(ActiveTrackingSystem activeTrackingSystem) {
-  for (PointShape* shape: _shapes) {
-    delete shape;
-  }
-  _shapes.clear();
+  clear();
   switch(activeTrackingSystem) {
     case OptiTrack: {
       std::vector<OptiTrackPoint*> points = MainWindow::getInstance()->getStore()->getOptiTrackPoints();
@@ -83,3 +80,10 @@ void TrackPointRenderer::render(ActiveTrackingSystem activeTrackingSystem) {
 std::vector<PointShape*> TrackPointRenderer::getShapes() {
   return _shapes;
 }
+
+void TrackPointRenderer::clear() {
+  for (PointShape* shape: _shapes) {
+    delete shape;
+  }
+  _shapes.clear();
+}