From c794679dac06dbf1b51797bed575249f50737f92 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 6 Sep 2019 15:47:02 +0200 Subject: [PATCH 01/16] Save the scene directly into the js, without using external files. --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 197 ++++++++++++------ Polyhedron/demo/Polyhedron/MainWindow.h | 2 + .../Polyhedron/Plugins/IO/VTK_io_plugin.cpp | 3 +- .../Plugins/Mesh_3/C3t3_io_plugin.cpp | 2 +- 4 files changed, 140 insertions(+), 64 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 9fb344a24b3..09a20d966d4 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -158,9 +158,9 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren CGAL::Three::Three::s_mainviewer = viewer; viewer->setObjectName("mainViewer"); viewer_window->showMaximized(); - viewer_window->setWindowFlags( + viewer_window->setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -353,7 +353,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // Load plugins, and re-enable actions that need it. operationSearchBar.setPlaceholderText("Filter..."); - searchAction->setDefaultWidget(&operationSearchBar); + searchAction->setDefaultWidget(&operationSearchBar); connect(&operationSearchBar, &QLineEdit::textChanged, this, [=](){filterOperations(true);}); loadPlugins(); @@ -689,7 +689,7 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted) else{ //qdebug << "error: " << qPrintable(loader.errorString()); pluginsStatus_map[name] = loader.errorString(); - + } PathNames_map[name].push_back(fileinfo.absoluteDir().absolutePath()); return true; @@ -933,7 +933,7 @@ void MainWindow::viewerShow(float xmin, } void MainWindow::viewerShow(Viewer_interface* vi, float x, float y, float z) { - + CGAL::qglviewer::ManipulatedCameraFrame backup_frame(*vi->camera()->frame()); vi->camera()->fitSphere(CGAL::qglviewer::Vec(x, y, z), vi->camera()->sceneRadius()/100); @@ -1000,16 +1000,16 @@ void MainWindow::computeViewerBBox(CGAL::qglviewer::Vec& min, CGAL::qglviewer::V const double xmax = bbox.xmax(); const double ymax = bbox.ymax(); const double zmax = bbox.zmax(); - - - + + + min = CGAL::qglviewer::Vec(xmin, ymin, zmin); max= CGAL::qglviewer::Vec(xmax, ymax, zmax); - + CGAL::qglviewer::Vec bbox_center((xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2); - + CGAL::qglviewer::Vec offset(0,0,0); - + double l_dist = (std::max)((std::abs)(bbox_center.x - viewer->offset().x), (std::max)((std::abs)(bbox_center.y - viewer->offset().y), (std::abs)(bbox_center.z - viewer->offset().z))); @@ -1231,7 +1231,7 @@ void MainWindow::open(QString filename) settings.setValue("OFF open directory", fileinfo.absoluteDir().absolutePath()); loadItem(fileinfo, findLoader(load_pair.first), ok); - + if(!ok) return; this->addToRecentFiles(fileinfo.absoluteFilePath()); @@ -1418,7 +1418,7 @@ void MainWindow::selectionChanged() { if(vi == NULL) continue; - + if(item != NULL && item->manipulatable()) { vi->setManipulatedFrame(item->manipulatedFrame()); } else { @@ -1552,7 +1552,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { menu_actions["line width"] = action->menu()->actions().last(); } } - + } Q_FOREACH(Scene::Item_id index, scene->selectionIndices()) { @@ -1585,7 +1585,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1620,7 +1620,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1655,7 +1655,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1698,7 +1698,7 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { )->value()); slider->setOrientation(Qt::Horizontal); sliderAction->setDefaultWidget(slider); - + connect(slider, &QSlider::valueChanged, [this, slider]() { Q_FOREACH(Scene::Item_id id, scene->selectionIndices()) @@ -1927,7 +1927,7 @@ void MainWindow::on_actionLoad_triggered() filters << filter; } } - + QString directory = settings.value("OFF open directory", QDir::current().dirName()).toString(); @@ -1955,7 +1955,7 @@ void MainWindow::on_actionLoad_triggered() static_cast(nb_files), std::back_inserter(colors_)); std::size_t nb_item = -1; - + Q_FOREACH(const QString& filename, dialog.selectedFiles()) { CGAL::Three::Scene_item* item = NULL; @@ -2197,7 +2197,7 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); - + float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2208,22 +2208,22 @@ void MainWindow::on_actionPreferences_triggered() } prefdiag.linesHorizontalSlider->setMinimum(lineWidth[0]); prefdiag.linesHorizontalSlider->setMaximum(lineWidth[1]); - + prefdiag.offset_updateCheckBox->setChecked( settings.value("offset_update", false).toBool()); connect(prefdiag.offset_updateCheckBox, SIGNAL(toggled(bool)), scene, SLOT(enableVisibilityRecentering(bool))); - + prefdiag.antialiasingCheckBox->setChecked(settings.value("antialiasing", false).toBool()); connect(prefdiag.antialiasingCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setAntiAliasing(bool))); - + prefdiag.quick_cameraCheckBox->setChecked( settings.value("quick_camera_mode", true).toBool()); connect(prefdiag.quick_cameraCheckBox, SIGNAL(toggled(bool)), viewer, SLOT(setFastDrawing(bool))); prefdiag.max_itemsSpinBox->setValue(viewer->textRenderer()->getMax_textItems()); - + connect(prefdiag.max_itemsSpinBox,static_cast(&QSpinBox::valueChanged), this, [this](int i){ setMaxTextItemsDisplayed(i); @@ -2254,27 +2254,27 @@ void MainWindow::on_actionPreferences_triggered() }); connect(prefdiag.background_colorPushButton, &QPushButton::clicked, this, &MainWindow::setBackgroundColor); - + connect(prefdiag.default_save_asPushButton, &QPushButton::clicked, this, &MainWindow::setDefaultSaveDir); - + connect(prefdiag.lightingPushButton, &QPushButton::clicked, this, &MainWindow::setLighting_triggered); - + prefdiag.surface_meshComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultSMRM)); connect(prefdiag.surface_meshComboBox, &QComboBox::currentTextChanged, this, [this](const QString& text){ this->s_defaultSMRM = CGAL::Three::Three::modeFromName(text); }); - + prefdiag.point_setComboBox->setCurrentText(CGAL::Three::Three::modeName( CGAL::Three::Three::s_defaultPSRM)); connect(prefdiag.point_setComboBox, &QComboBox::currentTextChanged, this, [this](const QString& text){ this->s_defaultPSRM = CGAL::Three::Three::modeFromName(text); }); - + std::vector items; QBrush successBrush(Qt::green), errorBrush(Qt::red), @@ -2348,7 +2348,7 @@ void MainWindow::on_actionPreferences_triggered() if (item->checkState(0)==Qt::Unchecked) plugin_blacklist.insert(item->text(1)); } - + //write settings settings.setValue("antialiasing", prefdiag.antialiasingCheckBox->isChecked()); @@ -2368,7 +2368,7 @@ void MainWindow::on_actionPreferences_triggered() settings.setValue("points_size", this->default_point_size); settings.setValue("normals_length", this->default_normal_length); settings.setValue("lines_width", this->default_lines_width); - + } else { @@ -2388,7 +2388,7 @@ void MainWindow::setBackgroundColor() v->update(); } } - + } void MainWindow::setLighting_triggered() @@ -2550,7 +2550,7 @@ QString MainWindow::get_item_stats() Q_FOREACH(int id, scene->selectionIndices()) { Scene_item* item = scene->item(id); - QString classname = item->property("classname").toString(); + QString classname = item->property("classname").toString(); if(classname.isEmpty()) classname = item->metaObject()->className(); if(!classnames.contains(classname)) @@ -2777,53 +2777,122 @@ void MainWindow::propagate_action() } } +/* + The two following functions allow to create files from string and strings from files. + This is used as a workaround of the absence of stream management in our IO system. + The whole to/from Base64 is used to avoid problems with binary formats. Everything is written + as a base64 binary string, and converted back to what it was. +*/ +QByteArray file_to_string(const char* filename) +{ + std::ifstream f(filename, std::ifstream::binary); + // get size of file + f.seekg (0,f.end); + long size = f.tellg(); + f.seekg (0); + std::ostringstream ss; + // allocate memory for file content + char* buffer = new char[size]; + + // read content of infile + f.read(buffer,size); + + // write to outfile + ss.write(buffer,size); + // release dynamically-allocated memory + delete[] buffer; + //ss.write( << f.rdbuf(); // reading data + f.close(); + std::string st = ss.str(); + QByteArray ba(st.c_str(), st.size()); + return ba; +} + +void MainWindow::write_string_to_file(const QString& str, const QString &filename) +{ + std::ofstream f(filename.toStdString().c_str(), std::ofstream::binary); + QByteArray ba(str.toStdString().c_str()); + QByteArray bb = QByteArray::fromBase64(ba); + f.write(bb.constData(),bb.toStdString().size()); + f.close(); +} + void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() { + if(scene->numberOfEntries() == 0) + return; QString filename = QFileDialog::getSaveFileName(this, "Save the Scene as a Script File", last_saved_dir, "Qt Script files (*.js)"); - std::ofstream os(filename.toUtf8()); + CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); + std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) return; - std::vector names; - std::vector loaders; + std::vector > names; + std::vector > loaders; std::vector colors; std::vector rendering_modes; QStringList not_saved; for(int i = 0; i < scene->numberOfEntries(); ++i) { Scene_item* item = scene->item(i); - QString loader = item->property("loader_name").toString(); - QString source = item->property("source filename").toString(); + QString loader;// = item->property("loader_name").toString(); + QString ext; + for(Polyhedron_demo_io_plugin_interface* iop : io_plugins) + { + if(iop->canSave(item)) + { + QString sf = iop->saveNameFilters().split(";;").first(); + //OFF Files (*.off) + QRegularExpression re("\\(\\*\\.(.*)\\)"); + QRegularExpressionMatch rem = re.match(sf); + if(!rem.hasMatch()) + continue; + ext = rem.captured(1); + QListto_save; + to_save.append(item); + QString savename(tr("%1.%2").arg(item->name()).arg(ext)); + iop->save(QFileInfo(savename), to_save); + names.push_back(std::make_pair(savename, item->name())); + loader=iop->name(); + break; + } + } if(loader.isEmpty()) { - not_saved.push_back(item->name()); + QMessageBox::warning(this, "", tr("No plugin found for %1. Not saved.").arg(item->name())); continue; } - names.push_back(source); - loaders.push_back(loader); + loaders.push_back(std::make_pair(loader, ext)); colors.push_back(item->color()); rendering_modes.push_back(item->renderingMode()); } + if(loaders.empty()) + return; //path os << "var camera = \""<dumpCameraCoordinates().toStdString()<<"\";\n"; os << "var items = ["; for(std::size_t i = 0; i< names.size() -1; ++i) { - os << "\'" << names[i].toStdString() << "\', "; + QByteArray item = file_to_string(names[i].first.toStdString().c_str()); + os<<"[\'"; + os<show(); } visibleDockWidgets.clear(); - + } } @@ -2906,7 +2979,7 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) viewer, SLOT(update())); connect(scene, SIGNAL(updated()), viewer, SLOT(update())); - + QAction* action = subviewer->findChild("actionRecenter"); connect(action, SIGNAL(triggered()), viewer, SLOT(update())); @@ -2965,17 +3038,17 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) this, SLOT(selectSceneItem(int))); connect(viewer, SIGNAL(selectedPoint(double, double, double)), this, SLOT(showSelectedPoint(double, double, double))); - + connect(viewer, SIGNAL(selectionRay(double, double, double, double, double, double)), scene, SIGNAL(selectionRay(double, double, double, double, double, double))); - + connect(viewer, &Viewer::sendMessage, this, [](QString s){ information(s); }); - + } void MainWindow::on_actionAdd_Viewer_triggered() @@ -2994,7 +3067,7 @@ void MainWindow::on_actionAdd_Viewer_triggered() scene->removeViewer(viewer2); viewerDestroyed(viewer2); }); - + setupViewer(viewer2, subviewer); viewer2->camera()->interpolateToFitScene(); subviewer->show(); @@ -3174,7 +3247,7 @@ void SubViewer::color() void SubViewer::closeEvent(QCloseEvent *closeEvent) { - + if(is_main) { QMessageBox::information(mw, "", "This is the main viewer. It cannot be closed."); @@ -3195,9 +3268,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->addAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint //| Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3213,9 +3286,9 @@ void SubViewer::changeEvent(QEvent *event) { menu->removeAction(action); } - setWindowFlags( + setWindowFlags( Qt::SubWindow - | Qt::CustomizeWindowHint + | Qt::CustomizeWindowHint | Qt::WindowMaximizeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint @@ -3237,7 +3310,7 @@ void MainWindow::invalidate_bbox(bool do_recenter) void MainWindow::on_action_Save_triggered() { - if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") + if(QMessageBox::question(this, "Save", "Are you sure you want to override these files ?") == QMessageBox::No) return; QList to_save; diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index e4bd6d5b3b1..417a8cd7043 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -138,6 +138,8 @@ public Q_SLOTS: This slot is for use by scripts.*/ bool open(QString filename, QString loader_name); + void write_string_to_file(const QString &str, const QString& filename); + /*! Reloads an item. Expects to be called by a QAction with the index of the item to be reloaded as data attached to the action. The index must identify a valid `Scene_item`.*/ diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp index b21c1a21d5d..33c8a8c24dd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/VTK_io_plugin.cpp @@ -299,10 +299,11 @@ public: QString nameFilters() const { - return "VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp);; VTK XML UnstructuredGrid (*.vtu)"; } + return "VTK XML UnstructuredGrid (*.vtu);;VTK PolyData files (*.vtk);; VTK XML PolyData (*.vtp)"; } QString name() const { return "vtk_plugin"; } bool canSave(const CGAL::Three::Scene_item* item) { + return (qobject_cast(item) || qobject_cast(item)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 4a7c004be2b..157e1a393e6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -20,7 +20,7 @@ class Polyhedron_demo_c3t3_binary_io_plugin : public: QString name() const { return "C3t3_io_plugin"; } QString nameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } - QString saveNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } + QString saveNameFilters() const { return "ascii (*.mesh);;binary files (*.cgal);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } QString loadNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh)"; } bool canLoad(QFileInfo) const; QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); From 1ebc5e3d009532599603fe15f05e2091165ae145 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 9 Sep 2019 16:53:12 +0200 Subject: [PATCH 02/16] Use temp files in /tmp instead of the build-dir --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 45 +++++++++++++++++++---- Polyhedron/demo/Polyhedron/MainWindow.h | 2 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 09a20d966d4..b9040e7c635 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef QT_SCRIPT_LIB # include # ifdef QT_SCRIPTTOOLS_LIB @@ -2777,6 +2778,23 @@ void MainWindow::propagate_action() } } +QString make_fullpath(const QString& filename, bool duplicate = false) +{ + QString fullpath = QString("%1/%2").arg(QDir::tempPath()).arg(filename); + QString tmp_fullpath = fullpath; + if(duplicate) + { + int i=0; + while(QFileInfo(tmp_fullpath).exists()) + { + QString basename = QFileInfo(tmp_fullpath).baseName(); + QString dir = QFileInfo(tmp_fullpath).dir().path(); + QString suffix= QFileInfo(fullpath).completeSuffix(); + tmp_fullpath=QString("%1/%2%3.%4").arg(dir).arg(basename).arg(++i).arg(suffix); + } + } + return tmp_fullpath; +} /* The two following functions allow to create files from string and strings from files. This is used as a workaround of the absence of stream management in our IO system. @@ -2808,13 +2826,15 @@ QByteArray file_to_string(const char* filename) return ba; } -void MainWindow::write_string_to_file(const QString& str, const QString &filename) +QString MainWindow::write_string_to_file(const QString& str, const QString &filename) { - std::ofstream f(filename.toStdString().c_str(), std::ofstream::binary); + QString fullpath = make_fullpath(filename); + std::ofstream f(fullpath.toStdString().c_str(), std::ofstream::binary); QByteArray ba(str.toStdString().c_str()); QByteArray bb = QByteArray::fromBase64(ba); f.write(bb.constData(),bb.toStdString().size()); f.close(); + return fullpath; } void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() @@ -2854,7 +2874,9 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() QListto_save; to_save.append(item); QString savename(tr("%1.%2").arg(item->name()).arg(ext)); - iop->save(QFileInfo(savename), to_save); + QString fullpath = make_fullpath(savename, true); + savename = QFileInfo(fullpath).fileName(); + iop->save(QFileInfo(fullpath), to_save); names.push_back(std::make_pair(savename, item->name())); loader=iop->name(); break; @@ -2876,15 +2898,24 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() os << "var items = ["; for(std::size_t i = 0; i< names.size() -1; ++i) { - QByteArray item = file_to_string(names[i].first.toStdString().c_str()); + QString fullpath = make_fullpath(names[i].first); + + QByteArray item = file_to_string(fullpath.toStdString().c_str()); os<<"[\'"; os< Date: Tue, 10 Sep 2019 11:35:19 +0200 Subject: [PATCH 03/16] Add defaultLoaders where needed, and use only default loaders to save items in .js --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 11 ++++++----- .../demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp | 6 ++++++ .../Plugins/IO/Implicit_function_io_plugin.cpp | 5 +++++ .../demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp | 5 +++++ .../Polyhedron/Plugins/IO/Polylines_io_plugin.cpp | 5 +++++ .../demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp | 7 ++++++- .../Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp | 5 +++++ .../demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp | 6 ++++++ 8 files changed, 44 insertions(+), 6 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index b9040e7c635..3cae43a185f 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -2830,8 +2830,9 @@ QString MainWindow::write_string_to_file(const QString& str, const QString &file { QString fullpath = make_fullpath(filename); std::ofstream f(fullpath.toStdString().c_str(), std::ofstream::binary); - QByteArray ba(str.toStdString().c_str()); - QByteArray bb = QByteArray::fromBase64(ba); + QByteArray compressed_item(str.toStdString().c_str()); + QByteArray item = qUncompress(QByteArray::fromBase64(compressed_item)); + QByteArray bb = item; f.write(bb.constData(),bb.toStdString().size()); f.close(); return fullpath; @@ -2862,7 +2863,7 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() QString ext; for(Polyhedron_demo_io_plugin_interface* iop : io_plugins) { - if(iop->canSave(item)) + if(iop->isDefaultLoader(item)) { QString sf = iop->saveNameFilters().split(";;").first(); //OFF Files (*.off) @@ -2902,7 +2903,7 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() QByteArray item = file_to_string(fullpath.toStdString().c_str()); os<<"[\'"; - os<(item)) + return true; + return false; + } + using Polyhedron_demo_io_plugin_interface::init; void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* m) override; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp index 24ddcc7a818..9ba512c8bc1 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp @@ -68,6 +68,11 @@ public: { return QList(); } + bool isDefaultLoader(const Scene_item* item) const{ + if(qobject_cast(item)) + return true; + return false; + } public Q_SLOTS: void load_function() const; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp index 4aab33b4e0a..aac88470ca4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp @@ -22,6 +22,11 @@ public: bool canSave(const CGAL::Three::Scene_item*); bool save(QFileInfo fileinfo,QList& items); + bool isDefaultLoader(const Scene_item* item) const{ + if(qobject_cast(item)) + return true; + return false; + } }; QString Polyhedron_demo_io_nef_plugin::nameFilters() const { diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp index d86309749f8..ce163fc9717 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp @@ -75,6 +75,11 @@ public: return QList()<(item)) + return true; + return false; + } protected Q_SLOTS: //!Splits the selected Scene_polylines_item in multiple items all containing a single polyline. void split(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 157e1a393e6..67f57c56c48 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -20,13 +20,18 @@ class Polyhedron_demo_c3t3_binary_io_plugin : public: QString name() const { return "C3t3_io_plugin"; } QString nameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } - QString saveNameFilters() const { return "ascii (*.mesh);;binary files (*.cgal);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } + QString saveNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } QString loadNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh)"; } bool canLoad(QFileInfo) const; QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); bool canSave(const CGAL::Three::Scene_item*); bool save(QFileInfo fileinfo,QList& ); + bool isDefaultLoader(const Scene_item* item) const{ + if(qobject_cast(item)) + return true; + return false; + } private: bool try_load_other_binary_format(std::istream& in, C3t3& c3t3); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 0bf1193c35b..e4c577937a9 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -295,6 +295,11 @@ public: items.pop_front(); return ok; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } QString name() const override{ return "segmented images"; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index b4864357dd3..be80490894e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -127,6 +127,12 @@ public: return res; } + bool isDefaultLoader(const Scene_item* item) const override{ + if(qobject_cast(item)) + return true; + return false; + } + bool applicable(QAction* action) const override { if(action == actionSelfIntersection) return qobject_cast(scene->item(scene->mainSelectionIndex())); From b1a8ec6d7652f375a3ab51dd13d4f232f5cbcd5a Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 11 Sep 2019 15:01:33 +0200 Subject: [PATCH 04/16] Add a way to upload a scene through ssh. --- Installation/cmake/modules/FindLibSSH.cmake | 39 +++ Polyhedron/demo/Polyhedron/CMakeLists.txt | 12 +- Polyhedron/demo/Polyhedron/MainWindow.cpp | 254 +++++++++++++++++- Polyhedron/demo/Polyhedron/MainWindow.h | 1 + Polyhedron/demo/Polyhedron/MainWindow.ui | 7 +- Polyhedron/demo/Polyhedron/Preferences.ui | 16 +- Polyhedron/demo/Polyhedron/SSH_dialog.ui | 130 +++++++++ Polyhedron/demo/Polyhedron/Use_ssh.cpp | 244 +++++++++++++++++ .../demo/Polyhedron/include/CGAL/Use_ssh.h | 25 ++ 9 files changed, 710 insertions(+), 18 deletions(-) create mode 100644 Installation/cmake/modules/FindLibSSH.cmake create mode 100644 Polyhedron/demo/Polyhedron/SSH_dialog.ui create mode 100644 Polyhedron/demo/Polyhedron/Use_ssh.cpp create mode 100644 Polyhedron/demo/Polyhedron/include/CGAL/Use_ssh.h diff --git a/Installation/cmake/modules/FindLibSSH.cmake b/Installation/cmake/modules/FindLibSSH.cmake new file mode 100644 index 00000000000..e2c49ee2fce --- /dev/null +++ b/Installation/cmake/modules/FindLibSSH.cmake @@ -0,0 +1,39 @@ +# - Try to find the LibSSH libraries +# This module defines: +# LIBSSH_FOUND - system has LibSSH lib +# LIBSSH_INCLUDE_DIR - the LibSSH include directory +# LIBSSH_LIBRARIES_DIR - directory where the LibSSH libraries are located +# LIBSSH_LIBRARIES - Link these to use LibSSH + + +include(FindPackageHandleStandardArgs) +include(${CMAKE_CURRENT_LIST_DIR}/CGAL_GeneratorSpecificSettings.cmake) + +if(LIBSSH_INCLUDE_DIR) + set(LIBSSH_in_cache TRUE) +else() + set(LIBSSH_in_cache FALSE) +endif() +if(NOT LIBSSH_LIBRARIES) + set(LIBSSH_in_cache FALSE) +endif() + +# Is it already configured? +if( NOT LIBSSH_in_cache ) + + find_path(LIBSSH_INCLUDE_DIR + NAMES "libssh/libssh.h" + ) + + find_library(LIBSSH_LIBRARIES NAMES ssh libssh + HINTS "/usr/lib" + "usr/lib/x86_64-linux-gnu" + PATH_SUFFIXES lib + DOC "Path to the LIBSSH library" + ) +endif() + +SET(LIBSSH_FOUND TRUE) +if( NOT LIBSSH_LIBRARIES OR NOT LIBSSH_INCLUDE_DIR) + SET(LIBSSH_FOUND FALSE) +endif() diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index fc4afa3bb09..72853cfd237 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -95,6 +95,11 @@ if( POLYHEDRON_DEMO_ACTIVATE_CONCURRENCY ) endif() endif() +#find libssh for scene sharing +find_package(LibSSH) +if( NOT LIBSSH_FOUND ) + message("NOTICE : The SSH features will be disabled.") +endif() # Activate concurrency ? (turned OFF by default) option(CGAL_ACTIVATE_CONCURRENT_MESH_3 @@ -131,7 +136,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) qt5_wrap_ui( statisticsUI_FILES Statistics_on_item_dialog.ui) qt5_wrap_ui( FileLoaderDialogUI_files FileLoaderDialog.ui ) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) - qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui) + qt5_wrap_ui( PreferencesUI_FILES Preferences.ui Details.ui SSH_dialog.ui) qt5_wrap_ui( Show_point_dialogUI_FILES Show_point_dialog.ui ) qt5_wrap_ui( ViewerUI_FILES LightingDialog.ui) qt5_generate_moc( "File_loader_dialog.h" "${CMAKE_CURRENT_BINARY_DIR}/File_loader_dialog_moc.cpp" ) @@ -322,11 +327,16 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) MainWindow.cpp Polyhedron_demo.cpp File_loader_dialog_moc.cpp + Use_ssh.cpp ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ${FileLoaderDialogUI_files} ${MainWindowUI_files} ${PreferencesUI_FILES} ${statisticsUI_FILES} ${SubViewerUI_files}) target_link_libraries(polyhedron_demo PUBLIC demo_framework point_dialog Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Script) + if(LIBSSH_FOUND) + add_definitions(-DCGAL_USE_SSH) + target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) + endif() #libssh add_executable ( Polyhedron_3 Polyhedron_3.cpp ) target_link_libraries( Polyhedron_3 PRIVATE polyhedron_demo ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 3cae43a185f..5c4a45dd6da 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -59,6 +59,7 @@ #include "ui_Preferences.h" #include "ui_Details.h" #include "ui_Statistics_on_item_dialog.h" +#include "ui_SSH_dialog.h" #include "Show_point_dialog.h" #include "File_loader_dialog.h" #include "Viewer.h" @@ -70,6 +71,11 @@ # include # include #include "Color_map.h" + +#ifdef CGAL_USE_SSH +# include "CGAL/Use_ssh.h" +#endif + using namespace CGAL::Three; QScriptValue myScene_itemToScriptValue(QScriptEngine *engine, @@ -151,6 +157,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB #if !defined(QT_SCRIPT_LIB) ui->menuBar->removeAction(ui->actionLoadScript); + ui->menuBar->removeAction(ui->on_actionLoad_a_Scene_from_a_Script_File); #endif // Save some pointers from ui, for latter use. sceneView = ui->sceneView; @@ -1891,14 +1898,7 @@ void MainWindow::throw_exception() { void MainWindow::on_actionLoadScript_triggered() { #if defined(QT_SCRIPT_LIB) - QString filename = QFileDialog::getOpenFileName( - this, - tr("Select a script to run..."), - ".", - "QTScripts (*.js);;All Files (*)"); - if(filename.isEmpty()) - return; - loadScript(QFileInfo(filename)); + #endif } @@ -2198,7 +2198,10 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); +#ifdef CGAL_USE_SSH + prefdiag.sshButton->setEnabled(true); +#endif float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2337,6 +2340,52 @@ void MainWindow::on_actionPreferences_triggered() }); dialog.exec(); }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this, prefdiag](){ + QDialog dialog(this); + Ui::SSHDialog sshdiag; + sshdiag.setupUi(&dialog); + sshdiag.userEdit->setText(settings.value("ssh_user", QString()).toString()); + sshdiag.serverEdit->setText(settings.value("ssh_server", QString()).toString()); + sshdiag.publicEdit->setText(settings.value("ssh_public_key", QString()).toString()); + sshdiag.privkEdit->setText(settings.value("ssh_priv_key", QString()).toString()); + connect(sshdiag.pubButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Public Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.publicEdit->setText(diag.selectedFiles().front()); + }); + connect(sshdiag.privButton, &QPushButton::clicked, + this, [this, sshdiag](){ + QFileDialog diag(this, + "Private Key", + "", + "All Files (*)"); + diag.setFilter(QDir::Hidden|QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot); + if(!diag.exec()) + return; + sshdiag.privkEdit->setText(diag.selectedFiles().front()); + }); + connect(prefdiag.sshButton, &QPushButton::clicked, + this, [this, prefdiag](){}); + dialog.exec(); + if ( dialog.result() ) + { + settings.setValue("ssh_user", + sshdiag.userEdit->text()); + settings.setValue("ssh_server", + sshdiag.serverEdit->text()); + settings.setValue("ssh_public_key", + sshdiag.publicEdit->text()); + settings.setValue("ssh_priv_key", + sshdiag.privkEdit->text()); + } + }); dialog.exec(); if ( dialog.result() ) @@ -2842,11 +2891,41 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() { if(scene->numberOfEntries() == 0) return; - QString filename = - QFileDialog::getSaveFileName(this, - "Save the Scene as a Script File", - last_saved_dir, - "Qt Script files (*.js)"); + bool do_upload = false; +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Upload ?"), tr("Do you wish to upload the scene" + " using the SSH preferences ?")); + bool ok; + do_upload = (doyou == QMessageBox::Yes); + if(do_upload) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + QString filename; + + if(do_upload){ + filename = QString("%1/save_scene.js").arg(QDir::tempPath()); + }else{ + filename = QFileDialog::getSaveFileName(this, + "Save the Scene as a Script File", + last_saved_dir, + "Qt Script files (*.js)"); + } CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) @@ -2961,6 +3040,58 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() "Items Not Saved", QString("The following items could not be saved: %1").arg( not_saved.join(", "))); +#ifdef CGAL_USE_SSH + using namespace CGAL::ssh_internal; + if(do_upload) + { + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + if(user.isEmpty()){ + return; + } + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the destination path for your file.")); + if(path.isEmpty()) + return; + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + res = push_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be uploaded. Check your console for more information."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + } +#endif } void MainWindow::setTransparencyPasses(int val) { @@ -3358,3 +3489,100 @@ void MainWindow::on_action_Save_triggered() } } } + +void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() +{ + bool do_download = false; + QString filename; + +#ifdef CGAL_USE_SSH + QString user = settings.value("ssh_user", QString()).toString(); + QString pass; + if(!user.isEmpty()) + { + QMessageBox::StandardButton doyou = + QMessageBox::question(this, tr("Download ?"), tr("Do you wish to download the scene" + " using the SSH preferences ?")); + bool ok; + do_download= (doyou == QMessageBox::Yes); + if(do_download) + { + pass = QInputDialog::getText(this, "SSH Password", + "Enter ssh key password:", + QLineEdit::Password, + tr(""), + &ok); + if(!ok) + return; + pass = pass.trimmed(); + } + } +#endif + + if(do_download) + { + using namespace CGAL::ssh_internal; + QString server = settings.value("ssh_server", QString()).toString(); + QString pk = settings.value("ssh_public_key", QString()).toString(); + QString privK = settings.value("ssh_priv_key", QString()).toString(); + user = user.trimmed(); + server = server.trimmed(); + pk = pk.trimmed(); + privK=privK.trimmed(); + QString path; + path = QInputDialog::getText(this, + "", + tr("Enter the remote path for your file.")); + if(path.isEmpty()) + return; + try{ + ssh_session session; + bool res = establish_ssh_session(session, + user.toStdString().c_str(), + server.toStdString().c_str(), + pk.toStdString().c_str(), + privK.toStdString().c_str(), + pass.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The SSH session could not be started."); + return; + } + filename = QString("%1/load_scene.js").arg(QDir::tempPath()); + path = tr("%1/%2").arg(QDir::tempPath()).arg(path); + res = pull_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); + if(!res) + { + QMessageBox::warning(this, + "Error", + "The file could not be fetched. Check your console for more info."); + close_connection(session); + return; + } + close_connection(session); + } catch( ssh::SshException e ) + { + std::cout << "Error during connection : "; + std::cout << e.getError() << std::endl; + } + } + else + { + filename = QFileDialog::getOpenFileName( + this, + tr("Select a Whole Scene file..."), + ".", + "Whole Scene files (*.js)"); + if(filename.isEmpty()) + return; + } + + + + + loadScript(QFileInfo(filename)); + + +} diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index a0758610429..98ed3417ba7 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -449,6 +449,7 @@ public: #endif public Q_SLOTS: void on_actionSa_ve_Scene_as_Script_triggered(); + void on_actionLoad_a_Scene_from_a_Script_File_triggered(); void toggleFullScreen(); void setDefaultSaveDir(); void invalidate_bbox(bool do_recenter); diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index a011dedab64..0ba2d19b535 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -58,6 +58,7 @@ + @@ -463,10 +464,14 @@ &Save + + + Load a Scene &from a Script File... + + - diff --git a/Polyhedron/demo/Polyhedron/Preferences.ui b/Polyhedron/demo/Polyhedron/Preferences.ui index 34613871e8d..3eef949ea8e 100644 --- a/Polyhedron/demo/Polyhedron/Preferences.ui +++ b/Polyhedron/demo/Polyhedron/Preferences.ui @@ -7,7 +7,7 @@ 0 0 631 - 526 + 628 @@ -59,8 +59,8 @@ 0 0 - 278 - 499 + 275 + 534 @@ -285,6 +285,16 @@ + + + + false + + + SSH Settings + + + diff --git a/Polyhedron/demo/Polyhedron/SSH_dialog.ui b/Polyhedron/demo/Polyhedron/SSH_dialog.ui new file mode 100644 index 00000000000..ce100341261 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/SSH_dialog.ui @@ -0,0 +1,130 @@ + + + SSHDialog + + + + 0 + 0 + 466 + 399 + + + + SSH Settings + + + + + + + + User + + + + + + + + + + + + Server + + + + + + + + + + + + Public Key + + + + + + + + + Browse... + + + + + + + + + + Private Key + + + + + + + + + Browse... + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SSHDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SSHDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp new file mode 100644 index 00000000000..663e10ac7ea --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -0,0 +1,244 @@ +#ifdef CGAL_USE_SSH +#include "CGAL/Use_ssh.h" +#include +#include +#include +#include + +#include + +bool test_result(int res) +{ + switch(res){ + + case SSH_AUTH_ERROR: + { + std::cerr<<"Auth failed with error: "< buffer(size); + if (!file.read(buffer.data(), size)) + { + std::cerr<<"error while reading file."< buffer; + + ssh_scp scp = ssh_scp_new( + session, SSH_SCP_READ | SSH_SCP_RECURSIVE, from_path); + if (scp == NULL) + { + std::cerr<<"Error allocating scp session: %s\n" + << ssh_get_error(session)< +namespace CGAL{ +namespace ssh_internal{ +//should be used inside a try/catch(ssh::SshException e) + +//give an unitialized session. +bool establish_ssh_session(ssh_session& session, + const char *user, + const char *server, + const char *pub_key_path, + const char *priv_key_path, + const char *priv_key_password); +void close_connection(ssh_session& session); + +bool push_file(ssh_session& session, + const char* dest_path, + const char* filepath); +bool pull_file(ssh_session &session, + const char *from_path, + const char *to_path); + +}} +#endif From b9e9dcc09b71e6006ff5038c3e044ff751cceac5 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 12 Sep 2019 16:09:35 +0200 Subject: [PATCH 05/16] Add Camera sharing through WebSockets --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 10 +- Polyhedron/demo/Polyhedron/MainWindow.cpp | 40 ++++++-- Polyhedron/demo/Polyhedron/Preferences.ui | 4 +- Polyhedron/demo/Polyhedron/SSH_dialog.ui | 113 +++++++++++++--------- Polyhedron/demo/Polyhedron/Viewer.cpp | 56 ++++++++++- Polyhedron/demo/Polyhedron/Viewer.h | 5 + 6 files changed, 170 insertions(+), 58 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 72853cfd237..a6ea6a615d1 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -64,7 +64,7 @@ include(${CGAL_USE_FILE}) find_package(Qt5 QUIET COMPONENTS OpenGL Script - OPTIONAL_COMPONENTS ScriptTools) + OPTIONAL_COMPONENTS ScriptTools WebSockets) if(Qt5_FOUND) @@ -199,6 +199,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) target_link_libraries(demo_framework PUBLIC Qt5::OpenGL Qt5::Widgets Qt5::Gui Qt5::Script ) + if(TARGET Qt5::WebSockets) + target_link_libraries(demo_framework PUBLIC Qt5::WebSockets) + message(STATUS "Qt5WebSockets was found. Using WebSockets is therefore possible.") + endif() + cgal_add_compilation_test(demo_framework) # Let's define `three_EXPORT` during the compilation of `demo_framework`, # in addition of `demo_framework_EXPORT` (defined automatically by @@ -337,6 +342,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) add_definitions(-DCGAL_USE_SSH) target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) endif() #libssh + if(TARGET Qt5::WebSockets) + target_link_libraries(polyhedron_demo PUBLIC Qt5::WebSockets) + endif() add_executable ( Polyhedron_3 Polyhedron_3.cpp ) target_link_libraries( Polyhedron_3 PRIVATE polyhedron_demo ) add_to_cached_list( CGAL_EXECUTABLE_TARGETS Polyhedron_3 ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 5c4a45dd6da..ee4e8ad65a8 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -2198,10 +2198,6 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::PreferencesDialog prefdiag; prefdiag.setupUi(&dialog); -#ifdef CGAL_USE_SSH - - prefdiag.sshButton->setEnabled(true); -#endif float lineWidth[2]; if(!viewer->isOpenGL_4_3()) viewer->glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth); @@ -2345,6 +2341,12 @@ void MainWindow::on_actionPreferences_triggered() QDialog dialog(this); Ui::SSHDialog sshdiag; sshdiag.setupUi(&dialog); + +#ifdef CGAL_USE_SSH + sshdiag.userBox->setEnabled(true); + sshdiag.serverBox->setEnabled(true); + sshdiag.pkBox->setEnabled(true); + sshdiag.privkBox->setEnabled(true); sshdiag.userEdit->setText(settings.value("ssh_user", QString()).toString()); sshdiag.serverEdit->setText(settings.value("ssh_server", QString()).toString()); sshdiag.publicEdit->setText(settings.value("ssh_public_key", QString()).toString()); @@ -2371,11 +2373,18 @@ void MainWindow::on_actionPreferences_triggered() return; sshdiag.privkEdit->setText(diag.selectedFiles().front()); }); - connect(prefdiag.sshButton, &QPushButton::clicked, - this, [this, prefdiag](){}); +#else + sshdiag.userBox->setEnabled(false); + sshdiag.serverBox->setEnabled(false); + sshdiag.pkBox->setEnabled(false); + sshdiag.privkBox->setEnabled(false); +#endif + sshdiag.wsEdit->setText(settings.value("ws_server_url", QString()).toString()); + dialog.exec(); if ( dialog.result() ) { +#ifdef CGAL_USE_SSH settings.setValue("ssh_user", sshdiag.userEdit->text()); settings.setValue("ssh_server", @@ -2384,8 +2393,13 @@ void MainWindow::on_actionPreferences_triggered() sshdiag.publicEdit->text()); settings.setValue("ssh_priv_key", sshdiag.privkEdit->text()); +#endif + settings.setValue("ws_server_url", + sshdiag.wsEdit->text()); + setProperty("ws_url", sshdiag.wsEdit->text()); } }); + dialog.exec(); if ( dialog.result() ) @@ -2871,7 +2885,7 @@ QByteArray file_to_string(const char* filename) //ss.write( << f.rdbuf(); // reading data f.close(); std::string st = ss.str(); - QByteArray ba(st.c_str(), st.size()); + QByteArray ba(st.c_str(), static_cast(st.size())); return ba; } @@ -3212,6 +3226,11 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) information(s); }); + + action= subviewer->findChild("actionShareCamera"); + connect(action, SIGNAL(toggled(bool)), + viewer, SLOT(setShareCam(bool))); + } void MainWindow::on_actionAdd_Viewer_triggered() @@ -3363,6 +3382,11 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) QAction* actionTotalPass = new QAction("Set Transparency Pass &Number...",this); actionTotalPass->setObjectName("actionTotalPass"); viewMenu->addAction(actionTotalPass); + QAction* actionShareCamera= new QAction("Join WS Server",this); + actionShareCamera->setObjectName("actionShareCamera"); + actionShareCamera->setCheckable(true); + actionShareCamera->setChecked(false); + viewMenu->addAction(actionShareCamera); if(mainviewer) setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(QIcon(":/cgal/icons/resources/menu.png")); @@ -3521,6 +3545,7 @@ void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() if(do_download) { + #ifdef CGAL_USE_SSH using namespace CGAL::ssh_internal; QString server = settings.value("ssh_server", QString()).toString(); QString pk = settings.value("ssh_public_key", QString()).toString(); @@ -3567,6 +3592,7 @@ void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() std::cout << "Error during connection : "; std::cout << e.getError() << std::endl; } + #endif } else { diff --git a/Polyhedron/demo/Polyhedron/Preferences.ui b/Polyhedron/demo/Polyhedron/Preferences.ui index 3eef949ea8e..27c3f5f7063 100644 --- a/Polyhedron/demo/Polyhedron/Preferences.ui +++ b/Polyhedron/demo/Polyhedron/Preferences.ui @@ -288,10 +288,10 @@ - false + true - SSH Settings + Network Settings diff --git a/Polyhedron/demo/Polyhedron/SSH_dialog.ui b/Polyhedron/demo/Polyhedron/SSH_dialog.ui index ce100341261..0f18f927cb8 100644 --- a/Polyhedron/demo/Polyhedron/SSH_dialog.ui +++ b/Polyhedron/demo/Polyhedron/SSH_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 466 - 399 + 415 + 441 @@ -17,63 +17,84 @@ - + - User + SSH Preferences - + - - - - - - - - - Server - - - - - - - - - - - - Public Key - - - - - - - - - Browse... + + + User + + + + + + + + + + + Server + + + + + + + + + + + + Public Key + + + + + + + + + Browse... + + + + + + + + + + Private Key + + + + + + + + + Browse... + + + + - + - Private Key + Camera Synchronization Server - + - - - - - - Browse... - - + diff --git a/Polyhedron/demo/Polyhedron/Viewer.cpp b/Polyhedron/demo/Polyhedron/Viewer.cpp index cc5cb24d158..57e7bb6650e 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.cpp +++ b/Polyhedron/demo/Polyhedron/Viewer.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -40,6 +41,7 @@ public: bool inDrawWithNames; bool clipping; bool projection_is_ortho; + bool cam_sharing; GLfloat gl_point_size; QVector4D clipbox[6]; QPainter *painter; @@ -107,6 +109,9 @@ public: { return shader_programs; } + + QWebSocket m_webSocket; + QUrl m_url; }; class LightingDialog : @@ -254,6 +259,7 @@ void Viewer::doBindings() d->spec_power = viewer_settings.value("spec_power", 51.8).toFloat(); d->scene = 0; d->projection_is_ortho = false; + d->cam_sharing = false; d->twosides = false; this->setProperty("draw_two_sides", false); d->macro_mode = false; @@ -589,7 +595,7 @@ void Viewer::mousePressEvent(QMouseEvent* event) d->showDistance(event->pos()); event->accept(); } - else { + else{ makeCurrent(); CGAL::QGLViewer::mousePressEvent(event); } @@ -1836,5 +1842,51 @@ bool Viewer::isClipping() const return d->clipping; } -#include "Viewer.moc" +void Viewer::setShareCam(bool b) +{ + static bool init = false; + if(b) + { + d->cam_sharing = b; + QString ws_url + = CGAL::Three::Three::mainWindow()->property("ws_url").toString(); + if(ws_url.isEmpty()) + { + QMessageBox::warning(this, "Error", "No Server configured. Please go to Edit->Preferences->Network Settings and fill the \"Camera Synchronization Server\" Field."); + } + else{ + if(!init) + { + connect(&d->m_webSocket, &QWebSocket::connected, this, &Viewer::onSocketConnected); + connect(&d->m_webSocket, &QWebSocket::disconnected, this, &Viewer::socketClosed); + init = true; + } + d->m_webSocket.open(QUrl(ws_url)); + } + } + else + { + d->m_webSocket.close(); + } +} +void Viewer::onSocketConnected() +{ + connect(&d->m_webSocket, &QWebSocket::textMessageReceived, + this, &Viewer::onTextMessageSocketReceived); + connect(camera()->frame(), &CGAL::qglviewer::ManipulatedCameraFrame::manipulated, + this, [this](){ + if(d->cam_sharing){ + QString cam_state = dumpCameraCoordinates(); + //send to server + d->m_webSocket.sendTextMessage(cam_state); + } + }); +} + +void Viewer::onTextMessageSocketReceived(QString message) +{ + moveCameraToCoordinates(message, 0.05f); +} + +#include "Viewer.moc" diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index 6d33097f672..0316bd8d6bc 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -95,6 +95,7 @@ public: Q_SIGNALS: void sendMessage(QString); void doneInitGL(CGAL::Three::Viewer_interface*); + void socketClosed(); public Q_SLOTS: //! Sets the antialiasing to true or false. void setAntiAliasing(bool b) Q_DECL_OVERRIDE; @@ -130,6 +131,10 @@ public Q_SLOTS: void messageLogged(QOpenGLDebugMessage); + void setShareCam(bool); + void onSocketConnected(); + void onTextMessageSocketReceived(QString message); + protected: void paintEvent(QPaintEvent *)Q_DECL_OVERRIDE; void paintGL()Q_DECL_OVERRIDE; From af5773cf4e78ed31dc40ae4e9b811a1ac6473a8b Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 16 Sep 2019 11:08:08 +0200 Subject: [PATCH 06/16] Integration of WS Server to the demo. Sessions handled and Remove the point_sets and polylines management from the 3mf plugin --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 146 ++++++++++++-- Polyhedron/demo/Polyhedron/MainWindow.h | 28 +++ Polyhedron/demo/Polyhedron/MainWindow.ui | 12 ++ .../Polyhedron/Plugins/IO/3mf_io_plugin.cpp | 55 ----- Polyhedron/demo/Polyhedron/Use_ssh.cpp | 21 +- Polyhedron/demo/Polyhedron/Viewer.cpp | 39 +++- Polyhedron/demo/Polyhedron/Viewer.h | 2 +- Stream_support/include/CGAL/IO/read_3mf.h | 188 ------------------ 8 files changed, 217 insertions(+), 274 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index ee4e8ad65a8..fd4e1c2d00c 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -1,3 +1,6 @@ +#ifdef CGAL_USE_SSH +# include "CGAL/Use_ssh.h" +#endif #include #include "config.h" @@ -72,9 +75,11 @@ # include #include "Color_map.h" -#ifdef CGAL_USE_SSH -# include "CGAL/Use_ssh.h" -#endif + +#include +#include +#include +#include using namespace CGAL::Three; QScriptValue @@ -1824,6 +1829,7 @@ void MainWindow::readSettings() this->default_point_size = settings.value("points_size").toInt(); this->default_normal_length = settings.value("normals_length").toInt(); this->default_lines_width = settings.value("lines_width").toInt(); + setProperty("ws_url", settings.value("ws_server_url").toString()); } void MainWindow::writeSettings() @@ -2940,10 +2946,10 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() last_saved_dir, "Qt Script files (*.js)"); } - CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); std::ofstream os(filename.toUtf8(), std::ofstream::binary); if(!os) return; + CGAL::Three::Three::CursorScopeGuard cs(Qt::WaitCursor); std::vector > names; std::vector > loaders; std::vector colors; @@ -3033,14 +3039,13 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() os << rendering_modes[i] << ", "; } os << rendering_modes.back()<<"];\n"; - os <<"var initial_scene_size = scene.numberOfEntries;\n"; os << "items.forEach(function(item, index, array){\n"; os<<" var path=items[index][1];\n"; os<<" path+='.';\n"; os<<" path+=loaders[index][1];\n"; os<<" var fullpath = main_window.write_string_to_file(item[0], path);\n"; os<<" main_window.open(fullpath,loaders[index][0]);\n"; - os << " var it = scene.item(initial_scene_size+index);\n"; + os << " var it = scene.item(scene.numberOfEntries-1);\n"; os << " var r = colors[index][0];\n"; os << " var g = colors[index][1];\n"; os << " var b = colors[index][2];\n"; @@ -3099,6 +3104,8 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() return; } close_connection(session); + QFile tmp_file(filename); + tmp_file.remove(); } catch( ssh::SshException e ) { std::cout << "Error during connection : "; @@ -3227,9 +3234,30 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) }); - action= subviewer->findChild("actionShareCamera"); - connect(action, SIGNAL(toggled(bool)), - viewer, SLOT(setShareCam(bool))); + action= subviewer->viewer->findChild("actionShareCamera"); + connect(action, &QAction::toggled, + this, [this, viewer](bool b) + { + if(!viewer){ + return; + } + QString session; + if(b){ + bool ok; + session = QInputDialog::getText( + this,"Session", + "Please enter the session name.\n" + "Only the machines that enter the same session name will be connected.\n" + "Several sessions can run simultaneously on a same server. ", + QLineEdit::Normal, QString(), &ok); + if(session.isEmpty() || !ok) + { + viewer->setShareCam(false, session); + return; + } + } + viewer->setShareCam(b, session); + }); } @@ -3382,7 +3410,7 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) QAction* actionTotalPass = new QAction("Set Transparency Pass &Number...",this); actionTotalPass->setObjectName("actionTotalPass"); viewMenu->addAction(actionTotalPass); - QAction* actionShareCamera= new QAction("Join WS Server",this); + QAction* actionShareCamera= new QAction("Join &WS Server",viewer); actionShareCamera->setObjectName("actionShareCamera"); actionShareCamera->setCheckable(true); actionShareCamera->setChecked(false); @@ -3576,7 +3604,7 @@ void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() return; } filename = QString("%1/load_scene.js").arg(QDir::tempPath()); - path = tr("%1/%2").arg(QDir::tempPath()).arg(path); + path = tr("/tmp/%2").arg(path); res = pull_file(session,path.toStdString().c_str(), filename.toStdString().c_str()); if(!res) { @@ -3604,11 +3632,95 @@ void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() if(filename.isEmpty()) return; } - - - - loadScript(QFileInfo(filename)); - - + if(do_download){ + QFile tmp_file(filename); + tmp_file.remove(); + } +} + +void MainWindow::on_action_Start_a_Session_triggered() +{ + QAction * action= findChild("action_Start_a_Session"); + static EchoServer *server =nullptr; + if(action->isChecked()){ + server = new EchoServer(1234); + QObject::connect(server, &EchoServer::closed, server,&EchoServer::deleteLater); + } + else + { + server->deleteLater(); + } +} + + +EchoServer::EchoServer(quint16 port) : + QObject(CGAL::Three::Three::mainWindow()), + m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), + QWebSocketServer::NonSecureMode, this)) +{ + if (m_pWebSocketServer->listen(QHostAddress::Any, port)) { + connect(m_pWebSocketServer, &QWebSocketServer::newConnection, + this, &EchoServer::onNewConnection); + connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &EchoServer::closed); + } + QHostAddress local_host("0.0.0.0"); + + //to avoid printing 127.0.0.1. Not realy sure it won't ever print the external ipv4 though. + const QHostAddress &localhost = QHostAddress(QHostAddress::LocalHost); + for (const QHostAddress &address: QNetworkInterface::allAddresses()) { + if (address.protocol() == QAbstractSocket::IPv4Protocol && address != localhost) + { + local_host= address; + break; + } + } + QMessageBox mb(QMessageBox::NoIcon, "WS Server", + tr("WebSockets Server started.\nEnter the following address in\nyour Network Preferences to be able to join it :\n" + "ws://%1:%2").arg(local_host.toString()).arg(port), QMessageBox::Ok, CGAL::Three::Three::mainWindow()); + mb.setTextInteractionFlags(Qt::TextSelectableByMouse); + mb.exec(); +} + +EchoServer::~EchoServer() +{ + m_pWebSocketServer->close(); + qDeleteAll(m_clients.begin(), m_clients.end()); +} + +void EchoServer::onNewConnection() +{ + QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + + connect(pSocket, &QWebSocket::textMessageReceived, this, &EchoServer::processTextMessage); + connect(pSocket, &QWebSocket::binaryMessageReceived, this, &EchoServer::processBinaryMessage); + connect(pSocket, &QWebSocket::disconnected, this, &EchoServer::socketDisconnected); + + m_clients << pSocket; +} + +void EchoServer::processTextMessage(QString message) +{ + QWebSocket *pClient = qobject_cast(sender()); + for(auto *client : m_clients) { + if(client != pClient) + client->sendTextMessage(message); + } +} + +void EchoServer::processBinaryMessage(QByteArray message) +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + pClient->sendBinaryMessage(message); + } +} + +void EchoServer::socketDisconnected() +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + m_clients.removeAll(pClient); + pClient->deleteLater(); + } } diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index 98ed3417ba7..14c9269adf1 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -354,6 +354,8 @@ protected Q_SLOTS: void save(QString filename, QList& to_save); //!Calls the function saveSnapShot of the viewer. void on_actionSaveSnapshot_triggered(); + //!Starts a new WS server if none is already exist. Else, does nothing. + void on_action_Start_a_Session_triggered(); //!Opens a Dialog to choose a color and make it the background color. void setBackgroundColor(); //!Opens a Dialog to change the lighting settings @@ -497,4 +499,30 @@ protected: private: bool is_main; }; + +QT_FORWARD_DECLARE_CLASS(QWebSocketServer) +QT_FORWARD_DECLARE_CLASS(QWebSocket) + +class EchoServer : public QObject +{ + Q_OBJECT +public: + explicit EchoServer(quint16 port); + ~EchoServer(); + + +Q_SIGNALS: + void closed(); + +private Q_SLOTS: + void onNewConnection(); + void processTextMessage(QString message); + void processBinaryMessage(QByteArray message); + void socketDisconnected(); + +private: + QWebSocketServer *m_pWebSocketServer; + QList m_clients; +}; + #endif // ifndef MAINWINDOW_H diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index 0ba2d19b535..e8fee1ec699 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -97,6 +97,7 @@ + @@ -469,6 +470,17 @@ Load a Scene &from a Script File... + + + true + + + &Start a Session + + + Start a WebSocket Server to share your camera with others on your network. + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp index d2e34e4e00e..90f036e8cea 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/3mf_io_plugin.cpp @@ -78,61 +78,6 @@ class Io_3mf_plugin: std::vector names; QList result; std::vector > all_colors; - int nb_polylines = - CGAL::read_polylines_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_polylines < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<polylines; - polylines.push_back(all_points[i]); - pol_item->setName(names[i].data()); - pol_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pol_item->setColor(QColor(c.red(), c.green(), c.blue())); - pol_item->setProperty("already_colord", true); - result << pol_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pol_item); - } - all_points.clear(); - all_colors.clear(); - names.clear(); - int nb_point_sets = - CGAL::read_point_clouds_from_3mf(fileinfo.filePath().toUtf8().toStdString(), - all_points, all_colors, names); - if(nb_point_sets < 0 ) - { - ok = false; - std::cerr << "Error in reading of meshes."<point_set()->insert(all_points[i][j]); - } - pts_item->setName(names[i].data()); - pts_item->invalidateOpenGLBuffers(); - CGAL::Color c = all_colors[i].front(); - pts_item->setColor(QColor(c.red(), c.green(), c.blue())); - pts_item->setProperty("already_colord", true); - result << pts_item; - if(add_to_scene) - CGAL::Three::Three::scene()->addItem(pts_item); - } - all_points.clear(); - names.clear(); - all_colors.clear(); int nb_meshes = CGAL::read_triangle_soups_from_3mf(fileinfo.filePath().toUtf8().toStdString(), all_points, all_polygons, all_colors, names); diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp index 663e10ac7ea..d529acbcb4c 100644 --- a/Polyhedron/demo/Polyhedron/Use_ssh.cpp +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -4,8 +4,8 @@ #include #include #include - -#include +#include +#include bool test_result(int res) { @@ -112,7 +112,7 @@ bool push_file(ssh_session &session, { std::cerr<<"Error allocating scp session: %s\n" << ssh_get_error(session)< timespan(size); + std::this_thread::sleep_for(timespan); if (res != SSH_OK) { std::cerr<< "Can't write to remote file: %s\n" @@ -176,8 +180,8 @@ bool pull_file(ssh_session &session, const char* to_path) { int rc; - long unsigned int size; - long unsigned int processed = 0; + std::size_t size; + std::size_t processed = 0; std::vector buffer; ssh_scp scp = ssh_scp_new( @@ -186,7 +190,7 @@ bool pull_file(ssh_session &session, { std::cerr<<"Error allocating scp session: %s\n" << ssh_get_error(session)< #include #include +#include #include #include @@ -111,6 +112,8 @@ public: } QWebSocket m_webSocket; + bool is_connected; + QString session; QUrl m_url; }; @@ -269,6 +272,7 @@ void Viewer::doBindings() d->shader_programs.resize(NB_OF_PROGRAMS); d->textRenderer = new TextRenderer(); d->is_2d_selection_mode = false; + d->is_connected = false; connect( d->textRenderer, SIGNAL(sendMessage(QString,int)), this, SLOT(printMessage(QString,int)) ); @@ -1842,12 +1846,13 @@ bool Viewer::isClipping() const return d->clipping; } -void Viewer::setShareCam(bool b) +void Viewer::setShareCam(bool b, QString session) { static bool init = false; if(b) { d->cam_sharing = b; + d->session = session; QString ws_url = CGAL::Three::Three::mainWindow()->property("ws_url").toString(); if(ws_url.isEmpty()) @@ -1858,14 +1863,30 @@ void Viewer::setShareCam(bool b) if(!init) { connect(&d->m_webSocket, &QWebSocket::connected, this, &Viewer::onSocketConnected); - connect(&d->m_webSocket, &QWebSocket::disconnected, this, &Viewer::socketClosed); + connect(&d->m_webSocket, &QWebSocket::disconnected, this,[this]() + { + d->is_connected = false; + Viewer::socketClosed(); + }); init = true; } d->m_webSocket.open(QUrl(ws_url)); + QApplication::setOverrideCursor(Qt::WaitCursor); + QTimer::singleShot(1000, this, [this](){ + QApplication::restoreOverrideCursor(); + if(!d->is_connected){ + QMessageBox::warning(CGAL::Three::Three::mainWindow(), + "Connection failure", + "The requested server was not found."); + setShareCam(false, ""); + } + }); } } else { + QAction* action = findChild("actionShareCamera"); + action->setChecked(false); d->m_webSocket.close(); } } @@ -1877,16 +1898,26 @@ void Viewer::onSocketConnected() connect(camera()->frame(), &CGAL::qglviewer::ManipulatedCameraFrame::manipulated, this, [this](){ if(d->cam_sharing){ - QString cam_state = dumpCameraCoordinates(); + QString cam_state = QString("[%1] %2").arg(d->session).arg(dumpCameraCoordinates()); //send to server d->m_webSocket.sendTextMessage(cam_state); } }); + d->is_connected = true; } void Viewer::onTextMessageSocketReceived(QString message) { - moveCameraToCoordinates(message, 0.05f); + QString session; + QString position; + QRegularExpression re("\\[(.*)\\] (.*)"); + QRegularExpressionMatch match = re.match(message); + session = match.captured(1); + position = match.captured(2); + if(session != d->session){ + return; + } + moveCameraToCoordinates(position, 0.05f); } #include "Viewer.moc" diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index 0316bd8d6bc..c7a437da293 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -131,7 +131,7 @@ public Q_SLOTS: void messageLogged(QOpenGLDebugMessage); - void setShareCam(bool); + void setShareCam(bool, QString); void onSocketConnected(); void onTextMessageSocketReceived(QString message); diff --git a/Stream_support/include/CGAL/IO/read_3mf.h b/Stream_support/include/CGAL/IO/read_3mf.h index cbd1dbd6c40..d2d2486b13f 100644 --- a/Stream_support/include/CGAL/IO/read_3mf.h +++ b/Stream_support/include/CGAL/IO/read_3mf.h @@ -74,12 +74,6 @@ bool extract_soups (NMR::PLib3MFModelMeshObject *pMeshObject, pBuffer.resize(nNeededChars + 1); hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pc") != std::string::npos - || temp.find("_cgal_pl")!= std::string::npos) //ignore point clouds and polylines - { - return false; - } name = std::string(&pBuffer[0]); } else @@ -129,151 +123,6 @@ bool extract_soups (NMR::PLib3MFModelMeshObject *pMeshObject, return true; } -template -bool extract_polylines (NMR::PLib3MFModelMeshObject *pMeshObject, - const NMR::MODELTRANSFORM& , - PointRange& points, - PolygonRange&, - ColorRange& colors, - std::string& name) { - typedef typename PointRange::value_type Point_3; - - HRESULT hResult; - DWORD nNeededChars; - std::vector pBuffer; - // Retrieve Mesh Name Length - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); - if (hResult != LIB3MF_OK) - { - points.resize(0); - std::cerr<<"Error during name extraction."; - return false; - } - - // Retrieve Mesh Name - if (nNeededChars > 0) { - pBuffer.resize(nNeededChars + 1); - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); - pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pl")== std::string::npos) //ignore not polylines - { - points.resize(0); - return false; - } - name = std::string(&pBuffer[0]); - } - else - { - points.resize(0); - return false; - } - - NMR::PLib3MFPropertyHandler * pPropertyHandler; - hResult = NMR::lib3mf_meshobject_createpropertyhandler(pMeshObject, &pPropertyHandler); - if (hResult != LIB3MF_OK) { - DWORD nErrorMessage; - LPCSTR pszErrorMessage; - std::cerr << "could not create property handler: " << std::hex << hResult << std::endl; - NMR::lib3mf_getlasterror(pMeshObject, &nErrorMessage, &pszErrorMessage); - std::cerr << "error #" << std::hex << nErrorMessage << ": " << pszErrorMessage << std::endl; - NMR::lib3mf_release(pMeshObject); - return false; - } - - points.resize(points.size()-3);//ignore dummy_vertices - for(DWORD vid = 0; vid < points.size(); ++vid) - { - NMR::MODELMESHVERTEX pVertex; - NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); - points[vid] = - Point_3(pVertex.m_fPosition[0], - pVertex.m_fPosition[1], - pVertex.m_fPosition[2]); - } - - NMR::MODELMESH_TRIANGLECOLOR_SRGB pColor; - NMR::lib3mf_propertyhandler_getcolor(pPropertyHandler, 0, &pColor);//get color of the dummy triangle - NMR::MODELMESHCOLOR_SRGB mColor = pColor.m_Colors[0]; - colors[0]=CGAL::Color(mColor.m_Red, mColor.m_Green, - mColor.m_Blue, mColor.m_Alpha); - return true; -} - -template -bool extract_point_clouds (NMR::PLib3MFModelMeshObject *pMeshObject, - const NMR::MODELTRANSFORM&, - PointRange& points, - PolygonRange&, - ColorRange& colors, - std::string& name) { - typedef typename PointRange::value_type Point_3; - - HRESULT hResult; - DWORD nNeededChars; - std::vector pBuffer; - // Retrieve Mesh Name Length - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); - if (hResult != LIB3MF_OK) - { - std::cerr<<"Error during name extraction."; - points.resize(0); - return false; - } - - // Retrieve Mesh Name - if (nNeededChars > 0) { - pBuffer.resize(nNeededChars + 1); - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); - pBuffer[nNeededChars] = 0; - std::string temp(&pBuffer[0]); - if(temp.find("_cgal_pc")== std::string::npos) //ignore not point_cloud - { - points.resize(0); - return false; - } - name = std::string(&pBuffer[0]); - } - else{ - points.resize(0); - return false; - } - - NMR::PLib3MFPropertyHandler * pPropertyHandler; - hResult = NMR::lib3mf_meshobject_createpropertyhandler(pMeshObject, &pPropertyHandler); - if (hResult != LIB3MF_OK) { - DWORD nErrorMessage; - LPCSTR pszErrorMessage; - std::cerr << "could not create property handler: " << std::hex << hResult << std::endl; - NMR::lib3mf_getlasterror(pMeshObject, &nErrorMessage, &pszErrorMessage); - std::cerr << "error #" << std::hex << nErrorMessage << ": " << pszErrorMessage << std::endl; - NMR::lib3mf_release(pMeshObject); - return -1; - } - - points.resize(points.size()-3);//ignore dummy_vertices - for(DWORD vid = 0; vid < points.size(); ++vid) - { - NMR::MODELMESHVERTEX pVertex; - NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); - points[vid] = - Point_3(pVertex.m_fPosition[0], - pVertex.m_fPosition[1], - pVertex.m_fPosition[2]); - } - - NMR::MODELMESH_TRIANGLECOLOR_SRGB pColor; - NMR::lib3mf_propertyhandler_getcolor(pPropertyHandler, 0, &pColor);//get color of the dummy triangle - NMR::MODELMESHCOLOR_SRGB mColor = pColor.m_Colors[0]; - colors[0]=CGAL::Color(mColor.m_Red, mColor.m_Green, - mColor.m_Blue, mColor.m_Alpha); - return true; -} - template @@ -614,43 +463,6 @@ int read_triangle_soups_from_3mf(const std::string& file_name, PointRanges& all_ all_colors, names, extract_soups); } - -template -int read_polylines_from_3mf(const std::string& file_name, - PointRanges& all_points, - ColorRanges& all_colors, - std::vector& names - ) -{ - typedef typename PointRanges::value_type PointRange; - typedef std::vector Polygon; - typedef std::vector PolygonRange; - typedef std::vector ColorRange; - std::vector all_polygons; - return read_from_3mf, - std::vector, PointRange, PolygonRange, ColorRange> - (file_name, all_points, all_polygons, all_colors, names, - extract_polylines); -} - - -template -int read_point_clouds_from_3mf(const std::string& file_name, - PointRanges& all_points, - ColorRanges& all_colors, - std::vector& names - ) -{ - typedef typename PointRanges::value_type PointRange; - typedef std::vector Polygon; - typedef std::vector PolygonRange; - typedef std::vector ColorRange; - std::vector all_polygons; - return read_from_3mf, - std::vector, PointRange, PolygonRange, ColorRange> - (file_name, all_points, all_polygons, all_colors, names, - extract_point_clouds); -} }//end CGAL #endif // CGAL_IO_READ_3MF_H From 6701a7322cc972dc478735815f26e280e6b59478 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 3 Oct 2019 09:41:11 +0200 Subject: [PATCH 07/16] Protect websocket code --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 1 + Polyhedron/demo/Polyhedron/MainWindow.cpp | 11 ++++++++--- Polyhedron/demo/Polyhedron/MainWindow.h | 7 +++++-- Polyhedron/demo/Polyhedron/Viewer.cpp | 9 ++++++--- Polyhedron/demo/Polyhedron/Viewer.h | 3 ++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index a6ea6a615d1..fb0d7f391fc 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -343,6 +343,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND) target_link_libraries(polyhedron_demo PUBLIC ${LIBSSH_LIBRARIES}) endif() #libssh if(TARGET Qt5::WebSockets) + add_definitions(-DCGAL_USE_WEBSOCKETS) target_link_libraries(polyhedron_demo PUBLIC Qt5::WebSockets) endif() add_executable ( Polyhedron_3 Polyhedron_3.cpp ) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index fd4e1c2d00c..d0870d1af6d 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -76,10 +76,11 @@ #include "Color_map.h" +#ifdef CGAL_USE_WEBSOCKETS #include #include -#include #include +#endif using namespace CGAL::Three; QScriptValue @@ -3233,7 +3234,7 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) information(s); }); - +#ifdef CGAL_USE_WEBSOCKETS action= subviewer->viewer->findChild("actionShareCamera"); connect(action, &QAction::toggled, this, [this, viewer](bool b) @@ -3258,6 +3259,7 @@ void MainWindow::setupViewer(Viewer* viewer, SubViewer* subviewer) } viewer->setShareCam(b, session); }); +#endif } @@ -3410,11 +3412,13 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) QAction* actionTotalPass = new QAction("Set Transparency Pass &Number...",this); actionTotalPass->setObjectName("actionTotalPass"); viewMenu->addAction(actionTotalPass); +#ifdef CGAL_USE_WEBSOCKETS QAction* actionShareCamera= new QAction("Join &WS Server",viewer); actionShareCamera->setObjectName("actionShareCamera"); actionShareCamera->setCheckable(true); actionShareCamera->setChecked(false); viewMenu->addAction(actionShareCamera); +#endif if(mainviewer) setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(QIcon(":/cgal/icons/resources/menu.png")); @@ -3639,6 +3643,7 @@ void MainWindow::on_actionLoad_a_Scene_from_a_Script_File_triggered() } } +#ifdef CGAL_USE_WEBSOCKETS void MainWindow::on_action_Start_a_Session_triggered() { QAction * action= findChild("action_Start_a_Session"); @@ -3653,7 +3658,6 @@ void MainWindow::on_action_Start_a_Session_triggered() } } - EchoServer::EchoServer(quint16 port) : QObject(CGAL::Three::Three::mainWindow()), m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), @@ -3724,3 +3728,4 @@ void EchoServer::socketDisconnected() pClient->deleteLater(); } } +#endif diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index 14c9269adf1..b10e9fc7273 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -1,5 +1,6 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#undef CGAL_USE_WEBSOCKETS #include "config.h" #include "MainWindow_config.h" @@ -354,8 +355,10 @@ protected Q_SLOTS: void save(QString filename, QList& to_save); //!Calls the function saveSnapShot of the viewer. void on_actionSaveSnapshot_triggered(); +#ifdef CGAL_USE_WEBSOCKETS //!Starts a new WS server if none is already exist. Else, does nothing. void on_action_Start_a_Session_triggered(); +#endif //!Opens a Dialog to choose a color and make it the background color. void setBackgroundColor(); //!Opens a Dialog to change the lighting settings @@ -499,7 +502,7 @@ protected: private: bool is_main; }; - +#ifdef CGAL_USE_WEBSOCKETS QT_FORWARD_DECLARE_CLASS(QWebSocketServer) QT_FORWARD_DECLARE_CLASS(QWebSocket) @@ -524,5 +527,5 @@ private: QWebSocketServer *m_pWebSocketServer; QList m_clients; }; - +#endif #endif // ifndef MAINWINDOW_H diff --git a/Polyhedron/demo/Polyhedron/Viewer.cpp b/Polyhedron/demo/Polyhedron/Viewer.cpp index 4a1a32180f8..08c6a4ffe2a 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.cpp +++ b/Polyhedron/demo/Polyhedron/Viewer.cpp @@ -17,7 +17,9 @@ #include #include #include +#ifdef CGAL_USE_WEBSOCKETS #include +#endif #include @@ -110,8 +112,9 @@ public: { return shader_programs; } - +#ifdef CGAL_USE_WEBSOCKETS QWebSocket m_webSocket; +#endif bool is_connected; QString session; QUrl m_url; @@ -1845,7 +1848,7 @@ bool Viewer::isClipping() const { return d->clipping; } - +#ifdef CGAL_USE_WEBSOCKETS void Viewer::setShareCam(bool b, QString session) { static bool init = false; @@ -1919,5 +1922,5 @@ void Viewer::onTextMessageSocketReceived(QString message) } moveCameraToCoordinates(position, 0.05f); } - +#endif #include "Viewer.moc" diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index c7a437da293..66a9e59194e 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -130,10 +130,11 @@ public Q_SLOTS: void setLighting(); void messageLogged(QOpenGLDebugMessage); - +#ifdef CGAL_USE_WEBSOCKETS void setShareCam(bool, QString); void onSocketConnected(); void onTextMessageSocketReceived(QString message); +#endif protected: void paintEvent(QPaintEvent *)Q_DECL_OVERRIDE; From 73ffe67feba205cd61d39887764f09b39e6de867 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 7 Jan 2020 09:29:16 +0100 Subject: [PATCH 08/16] Add missing header --- Polyhedron/demo/Polyhedron/Viewer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Polyhedron/demo/Polyhedron/Viewer.cpp b/Polyhedron/demo/Polyhedron/Viewer.cpp index a1779cefa28..ec6f374323c 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.cpp +++ b/Polyhedron/demo/Polyhedron/Viewer.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CGAL_USE_WEBSOCKETS #include #endif From 94bbd715abac3732c9ca2dd48ec557a66ee4de8d Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 9 Jan 2020 14:57:22 +0100 Subject: [PATCH 09/16] Remove test of unexisting functions --- .../test/Stream_support/test_3mf_to_sm.cpp | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp index 654cae33bb0..4f4e94feb7e 100644 --- a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp +++ b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp @@ -51,33 +51,6 @@ int main(int argc, char** argv) ofs << mesh; ofs.close(); } - int nb_polylines = - CGAL::read_polylines_from_3mf(file_name, all_points, all_colors, names); - - if(nb_polylines == 0) - std::cout<<"No polyline found."< Date: Mon, 13 Jan 2020 16:51:40 +0100 Subject: [PATCH 10/16] Fix warnigns --- Polyhedron/demo/Polyhedron/MainWindow.cpp | 2 +- Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 69f02cb1245..065a6309622 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -2349,7 +2349,7 @@ void MainWindow::on_actionPreferences_triggered() dialog.exec(); }); connect(prefdiag.sshButton, &QPushButton::clicked, - this, [this, prefdiag](){ + this, [this](){ QDialog dialog(this); Ui::SSHDialog sshdiag; sshdiag.setupUi(&dialog); diff --git a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp index 69faea6ee9d..d8484185f47 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp @@ -860,7 +860,7 @@ public: return ok; } - bool isDefaultLoader(const Scene_item* item) const{ + bool isDefaultLoader(const Scene_item* item) const Q_DECL_OVERRIDE{ if(qobject_cast(item)) return true; return false; From dd2bd99b4280954401363c87e9dbb732c82445d1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 14 Jan 2020 09:44:10 +0100 Subject: [PATCH 11/16] add missing `override` keywords --- .../Plugins/IO/Implicit_function_io_plugin.cpp | 5 ----- .../demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp | 2 +- .../demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp | 4 ++-- .../demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp | 14 +++++++------- .../Plugins/IO/Polylines_io_plugin.cpp | 3 ++- .../demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp | 16 ++++++++-------- .../Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp | 2 +- 7 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp index 21e2ab6d5ca..b79a873c233 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Implicit_function_io_plugin.cpp @@ -59,11 +59,6 @@ public: { return QList(); } - bool isDefaultLoader(const Scene_item* item) const{ - if(qobject_cast(item)) - return true; - return false; - } public Q_SLOTS: void load_function() const; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp index aac88470ca4..4586a6e5a67 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp @@ -22,7 +22,7 @@ public: bool canSave(const CGAL::Three::Scene_item*); bool save(QFileInfo fileinfo,QList& items); - bool isDefaultLoader(const Scene_item* item) const{ + bool isDefaultLoader(const Scene_item* item) const override{ if(qobject_cast(item)) return true; return false; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index 580023022f7..76d1f9394ef 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp @@ -26,14 +26,14 @@ class Polyhedron_demo_off_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "off_io_plugin.json") public: - bool isDefaultLoader(const Scene_item *item) const + bool isDefaultLoader(const Scene_item *item) const override { if(qobject_cast(item) || qobject_cast(item)) return true; return false; } - bool isDefaultLoader(const QString& name) const + bool isDefaultLoader(const QString& name) const override { if(name == QString("off")) return true; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp index 6ce2fdeb793..75c2e1d9845 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/PLY_io_plugin.cpp @@ -23,19 +23,19 @@ class Polyhedron_demo_ply_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "ply_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "ply_plugin"; } - QString nameFilters() const { return "PLY files (*.ply)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "ply_plugin"; } + QString nameFilters() const override{ return "PLY files (*.ply)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true)override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList&); + bool canSave(const CGAL::Three::Scene_item*)override; + bool save(QFileInfo fileinfo,QList&)override; }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp index ce163fc9717..d9fe0b44e0d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp @@ -75,7 +75,8 @@ public: return QList()<(item)) return true; return false; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp index 71c47452676..55a3a7e1b14 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/lcc_io_plugin.cpp @@ -17,24 +17,24 @@ class LCC_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "lcc_io_plugin.json") public: - bool isDefaultLoader(const CGAL::Three::Scene_item *item) const + bool isDefaultLoader(const CGAL::Three::Scene_item *item) const override { if(qobject_cast(item)) return true; return false; } - QString name() const { return "lcc_plugin"; } - QString nameFilters() const { return + QString name() const override{ return "lcc_plugin"; } + QString nameFilters() const override{ return "OFF files (*.off);;" "3-map files (*.3map)"; } - QString saveNameFilters() const { + QString saveNameFilters() const override{ return "3-map files (*.3map)"; } - bool canLoad(QFileInfo) const { return true; } - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true){ + bool canLoad(QFileInfo) const override{ return true; } + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override{ // Open file std::ifstream ifs(fileinfo.filePath().toUtf8()); if(!ifs) { @@ -67,8 +67,8 @@ public: } - bool canSave(const CGAL::Three::Scene_item*){return false;} - bool save(QFileInfo, QList& ){ + bool canSave(const CGAL::Three::Scene_item*)override{return false;} + bool save(QFileInfo, QList& )override{ return false; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 67f57c56c48..3164c5df22d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -27,7 +27,7 @@ public: bool canSave(const CGAL::Three::Scene_item*); bool save(QFileInfo fileinfo,QList& ); - bool isDefaultLoader(const Scene_item* item) const{ + bool isDefaultLoader(const Scene_item* item) const override{ if(qobject_cast(item)) return true; return false; From 2078b804db3dc3d8cfe6ac7747e8a539be19c413 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Wed, 15 Jan 2020 12:42:27 +0100 Subject: [PATCH 12/16] more override --- .../demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp | 12 ++++++------ .../demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp | 12 ++++++------ .../Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp index 4586a6e5a67..22b2ed695d4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Nef_io_plugin.cpp @@ -15,13 +15,13 @@ class Polyhedron_demo_io_nef_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "nef_io_plugin.json") public: - QString nameFilters() const; - QString name() const { return "io_nef_plugin"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString nameFilters() const override; + QString name() const override { return "io_nef_plugin"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& items); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& items) override; bool isDefaultLoader(const Scene_item* item) const override{ if(qobject_cast(item)) return true; diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index 76d1f9394ef..e5605c82ebb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp @@ -39,15 +39,15 @@ public: return true; return false; } - QString name() const { return "off_plugin"; } - QString nameFilters() const { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } - bool canLoad(QFileInfo fileinfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override{ return "off_plugin"; } + QString nameFilters() const override { return "OFF files (*.off);;Wavefront OBJ (*.obj)"; } + bool canLoad(QFileInfo fileinfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; CGAL::Three::Scene_item* load_off(QFileInfo fileinfo); CGAL::Three::Scene_item* load_obj(QFileInfo fileinfo); - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; }; bool Polyhedron_demo_off_plugin::canLoad(QFileInfo) const { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp index 3164c5df22d..21a0d5c6207 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -18,15 +18,15 @@ class Polyhedron_demo_c3t3_binary_io_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90" FILE "c3t3_io_plugin.json") public: - QString name() const { return "C3t3_io_plugin"; } - QString nameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } - QString saveNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } - QString loadNameFilters() const { return "binary files (*.cgal);;ascii (*.mesh)"; } - bool canLoad(QFileInfo) const; - QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true); + QString name() const override { return "C3t3_io_plugin"; } + QString nameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma)"; } + QString saveNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh);;maya (*.ma);;avizo (*.am);;OFF files (*.off)"; } + QString loadNameFilters() const override { return "binary files (*.cgal);;ascii (*.mesh)"; } + bool canLoad(QFileInfo) const override; + QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; - bool canSave(const CGAL::Three::Scene_item*); - bool save(QFileInfo fileinfo,QList& ); + bool canSave(const CGAL::Three::Scene_item*) override; + bool save(QFileInfo fileinfo,QList& ) override; bool isDefaultLoader(const Scene_item* item) const override{ if(qobject_cast(item)) return true; From 634b0cf7e91dd44a80fc63e3e454efd32dfc57fb Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 20 Feb 2020 13:30:15 +0100 Subject: [PATCH 13/16] fix known_hosts and ask for permission. Clean-up. --- Polyhedron/demo/Polyhedron/MainWindow.h | 1 - Polyhedron/demo/Polyhedron/MainWindow.ui | 3 +- Polyhedron/demo/Polyhedron/Use_ssh.cpp | 60 ++++++++++++++++-------- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/MainWindow.h b/Polyhedron/demo/Polyhedron/MainWindow.h index b10e9fc7273..b7650b52b34 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.h +++ b/Polyhedron/demo/Polyhedron/MainWindow.h @@ -1,6 +1,5 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#undef CGAL_USE_WEBSOCKETS #include "config.h" #include "MainWindow_config.h" diff --git a/Polyhedron/demo/Polyhedron/MainWindow.ui b/Polyhedron/demo/Polyhedron/MainWindow.ui index e8fee1ec699..6273a37bd16 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.ui +++ b/Polyhedron/demo/Polyhedron/MainWindow.ui @@ -478,12 +478,13 @@ &Start a Session - Start a WebSocket Server to share your camera with others on your network. + Start a WebSocket Server to Share your Camera with Others on your Network. + diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp index d529acbcb4c..8af5e1ee7f8 100644 --- a/Polyhedron/demo/Polyhedron/Use_ssh.cpp +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -1,4 +1,7 @@ #ifdef CGAL_USE_SSH + +#include + #include "CGAL/Use_ssh.h" #include #include @@ -7,6 +10,8 @@ #include #include +#include + bool test_result(int res) { switch(res){ @@ -50,30 +55,47 @@ bool establish_ssh_session(ssh_session &session, //Can use SSH_LOG_PROTOCOL here for verbose output int verbosity = SSH_LOG_NOLOG; - - session = ssh_new(); - ssh_options_set( session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity ); - ssh_options_set( session, SSH_OPTIONS_PORT, &port ); - ssh_options_set( session, SSH_OPTIONS_USER, user ); - ssh_options_set( session, SSH_OPTIONS_HOST, server); - - ssh_connect(session); - - if( ssh_is_server_known(session) != SSH_SERVER_KNOWN_OK ) + int res; + //retry 4 times max each time the connection asks to be retried. + for(int k = 0; k < 4; ++k) { - if( ssh_write_knownhost(session) != SSH_OK ) + session = ssh_new(); + ssh_options_set( session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity ); + ssh_options_set( session, SSH_OPTIONS_PORT, &port ); + ssh_options_set( session, SSH_OPTIONS_USER, user ); + ssh_options_set( session, SSH_OPTIONS_HOST, server); + + ssh_connect(session); + + if( ssh_is_server_known(session) != SSH_SERVER_KNOWN_OK ) { - std::cerr << "writeKnownHost failed" << std::endl; - return false; + if(QMessageBox::warning(CGAL::Three::Three::mainWindow(), QString("Unknown Server"), + QString ("The server you are trying to join is not known.\n" + "Do you wish to add it to the known servers list and continue?"), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + { + return false; + } + + if( ssh_write_knownhost(session) != SSH_OK ) + { + std::cerr << "writeKnownHost failed" << std::endl; + return false; + } + else + { + ssh_connect(session); + } } + ssh_key pubkey = ssh_key_new(); + ssh_pki_import_pubkey_file(pub_key_path, &pubkey); + res = ssh_userauth_try_publickey(session, NULL, pubkey); + if(res == SSH_AUTH_AGAIN) + ssh_disconnect(session); else - { - ssh_connect(session); - } + break; } - ssh_key pubkey = ssh_key_new(); - ssh_pki_import_pubkey_file(pub_key_path, &pubkey); - int res = ssh_userauth_try_publickey(session, NULL, pubkey); + if(!test_result(res)) { ssh_disconnect(session); From 56af5c2d7d8288f1c26d36d5cb48a9ad01e4291c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 20 Feb 2020 13:32:50 +0100 Subject: [PATCH 14/16] Put Use_ssh.cpp under LGPL3+ --- Polyhedron/demo/Polyhedron/Use_ssh.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp index 8af5e1ee7f8..50ef9d2b68f 100644 --- a/Polyhedron/demo/Polyhedron/Use_ssh.cpp +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -1,3 +1,14 @@ +// Copyright (c) 2020 GeometryFactory (France). All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Maxime Gimeno + #ifdef CGAL_USE_SSH #include From 1d69e9048e5a566ac7b5d9c720f7c9510a8a683c Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 27 Feb 2020 15:56:56 +0100 Subject: [PATCH 15/16] conditionnally use some functions (fix deprecation warning) --- Polyhedron/demo/Polyhedron/Use_ssh.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp index 50ef9d2b68f..c1e8e0e9d28 100644 --- a/Polyhedron/demo/Polyhedron/Use_ssh.cpp +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -77,8 +77,11 @@ bool establish_ssh_session(ssh_session &session, ssh_options_set( session, SSH_OPTIONS_HOST, server); ssh_connect(session); - +#if LIBSSH_VERSION_MAJOR <1 && LIBSSH_VERSION_MINOR < 8 if( ssh_is_server_known(session) != SSH_SERVER_KNOWN_OK ) +#else + if( ssh_session_is_known_server(session) != SSH_SERVER_KNOWN_OK ) +#endif { if(QMessageBox::warning(CGAL::Three::Three::mainWindow(), QString("Unknown Server"), QString ("The server you are trying to join is not known.\n" @@ -87,8 +90,11 @@ bool establish_ssh_session(ssh_session &session, { return false; } - +#if LIBSSH_VERSION_MAJOR <1 && LIBSSH_VERSION_MINOR < 8 if( ssh_write_knownhost(session) != SSH_OK ) +#else + if( ssh_session_update_known_hosts(session) != SSH_OK ) +#endif { std::cerr << "writeKnownHost failed" << std::endl; return false; From 3e61bcbe51f4319527aad36785794962004ff85f Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 3 Mar 2020 15:26:30 +0100 Subject: [PATCH 16/16] Fix enum --- Polyhedron/demo/Polyhedron/Use_ssh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Use_ssh.cpp b/Polyhedron/demo/Polyhedron/Use_ssh.cpp index c1e8e0e9d28..a1b342eda69 100644 --- a/Polyhedron/demo/Polyhedron/Use_ssh.cpp +++ b/Polyhedron/demo/Polyhedron/Use_ssh.cpp @@ -80,7 +80,7 @@ bool establish_ssh_session(ssh_session &session, #if LIBSSH_VERSION_MAJOR <1 && LIBSSH_VERSION_MINOR < 8 if( ssh_is_server_known(session) != SSH_SERVER_KNOWN_OK ) #else - if( ssh_session_is_known_server(session) != SSH_SERVER_KNOWN_OK ) + if( ssh_session_is_known_server(session) != SSH_KNOWN_HOSTS_OK ) #endif { if(QMessageBox::warning(CGAL::Three::Three::mainWindow(), QString("Unknown Server"),