diff --git a/Polyhedron/demo/Polyhedron/MainWindow.cpp b/Polyhedron/demo/Polyhedron/MainWindow.cpp index 6866f6ef032..04c8b559808 100644 --- a/Polyhedron/demo/Polyhedron/MainWindow.cpp +++ b/Polyhedron/demo/Polyhedron/MainWindow.cpp @@ -371,6 +371,7 @@ MainWindow::MainWindow(const QStringList &keywords, bool verbose, QWidget* paren // Setup the submenu of the View menu that can toggle the dockwidgets Q_FOREACH(QDockWidget* widget, findChildren()) { + widget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable); ui->menuDockWindows->addAction(widget->toggleViewAction()); } ui->menuDockWindows->removeAction(ui->dummyAction); @@ -1285,7 +1286,7 @@ QList MainWindow::loadItem(QFileInfo fileinfo, QCursor tmp_cursor(Qt::WaitCursor); CGAL::Three::Three::CursorScopeGuard guard(tmp_cursor); QList result = loader->load(fileinfo, ok, add_to_scene); - if(result.empty() || !ok) + if(!ok) { QApplication::restoreOverrideCursor(); QMessageBox::warning(this, tr("Error"), @@ -1579,6 +1580,8 @@ void MainWindow::showSceneContextMenu(const QPoint& p) { has_stats = true; } QMenu menu; + menu.addAction(actionAddToGroup); + menu.insertSeparator(0); Q_FOREACH(QString name, menu_actions.keys()) { if(name == QString("alpha slider") @@ -2579,6 +2582,10 @@ void MainWindow::makeNewGroup() { Scene_group_item * group = new Scene_group_item(); scene->addItem(group); + for(Scene::Item_id id : scene->selectionIndices()) + { + scene->changeGroup(scene->item(id), group); + } } void MainWindow::on_upButton_pressed() @@ -2956,6 +2963,7 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() std::vector colors; std::vector rendering_modes; QStringList not_saved; + Polyhedron_demo_io_plugin_interface* camera_plugin = nullptr; for(int i = 0; i < scene->numberOfEntries(); ++i) { Scene_item* item = scene->item(i); @@ -2963,6 +2971,8 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() QString ext; for(Polyhedron_demo_io_plugin_interface* iop : io_plugins) { + if(iop->name() == "camera_positions_plugin") + camera_plugin = iop; if(iop->isDefaultLoader(item)) { QString sf = iop->saveNameFilters().split(";;").first(); @@ -2992,6 +3002,23 @@ void MainWindow::on_actionSa_ve_Scene_as_Script_triggered() colors.push_back(item->color()); rendering_modes.push_back(item->renderingMode()); } + bool has_camera_positions = false; + if(camera_plugin) + { + QString fullpath = make_fullpath("camera_tmp.camera.txt"); + QList dummy; + if(camera_plugin->save(QFileInfo(fullpath), dummy)) + { + QByteArray item = file_to_string(fullpath.toStdString().c_str()); + os << "var camera_positions= [\'"; + os<setTotalPass(nb); }); + + action = subviewer->findChild("actionScaleScene"); + action->setCheckable(true); + action->setChecked(false); + connect(action, &QAction::triggered, + viewer, &Viewer::scaleScene); + action= subviewer->findChild("actionBackFrontShading"); connect(action, SIGNAL(toggled(bool)), viewer, SLOT(setBackFrontShading(bool))); @@ -3450,6 +3490,10 @@ SubViewer::SubViewer(QWidget *parent, MainWindow* mw, Viewer* mainviewer) actionBackFrontShading->setChecked(false); viewMenu->addAction(actionBackFrontShading); + QAction* actionScaleScene = new QAction("&Scale the Scene...",this); + actionScaleScene->setObjectName("actionScaleScene"); + viewMenu->addAction(actionScaleScene); + if(mainviewer) setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(QIcon(":/cgal/icons/resources/menu.png")); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.cpp b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.cpp index 707a5b7fff3..c015e8f495c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.cpp @@ -89,13 +89,9 @@ void Camera_positions_list::activatedRow(QModelIndex index) Three::activeViewer()->moveCameraToCoordinates(s); } -void Camera_positions_list::on_saveButton_pressed() -{ - QString filename = - QFileDialog::getSaveFileName(this, - tr("Save camera coordinates to file"), - QString(), - tr("(*.camera.txt)")); +bool Camera_positions_list::save(QString filename) { + if(m_model->rowCount() <1) + return false; QFile file(filename); file.open(QIODevice::WriteOnly); QTextStream out(&file); @@ -108,6 +104,17 @@ void Camera_positions_list::on_saveButton_pressed() << "\n"; } file.close(); + return true; +} + +void Camera_positions_list::on_saveButton_pressed() +{ + QString filename = + QFileDialog::getSaveFileName(this, + tr("Save camera coordinates to file"), + QString(), + tr("(*.camera.txt)")); + save(filename); } void Camera_positions_list::on_openButton_pressed() diff --git a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.h b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.h index 575fd68b603..f9d43a2a88d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_list.h @@ -15,6 +15,7 @@ public: public Q_SLOTS: void load(QString filename); + bool save(QString filename); protected Q_SLOTS: void on_plusButton_pressed(); void on_minusButton_pressed(); @@ -41,3 +42,4 @@ private: }; #endif + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_plugin.cpp index e252689a452..53104cf7256 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Camera_position/Camera_positions_plugin.cpp @@ -31,8 +31,11 @@ public: return QList(); } - bool canSave(const Scene_item*) override { return false; } - bool save(QFileInfo,QList& ) override {return false; } + bool canSave(const Scene_item*) override { return true; } + bool save(QFileInfo fileinfo,QList& ) override + { + return cpl->save(fileinfo.filePath()); + } private: Camera_positions_list* cpl; }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index d4392625bca..a7d9eac607b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -95,7 +95,7 @@ target_link_libraries(surface_intersection_plugin PUBLIC scene_surface_mesh_item qt5_wrap_ui( repairUI_FILES RemoveNeedlesDialog.ui) polyhedron_demo_plugin(repair_polyhedron_plugin Repair_polyhedron_plugin ${repairUI_FILES} KEYWORDS PMP) -target_link_libraries(repair_polyhedron_plugin PUBLIC scene_surface_mesh_item) +target_link_libraries(repair_polyhedron_plugin PUBLIC scene_points_with_normal_item scene_surface_mesh_item) qt5_wrap_ui( isotropicRemeshingUI_FILES Isotropic_remeshing_dialog.ui) polyhedron_demo_plugin(isotropic_remeshing_plugin Isotropic_remeshing_plugin ${isotropicRemeshingUI_FILES} KEYWORDS PMP) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 0e50beabcf1..f16ad282266 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -1,6 +1,7 @@ #include #include "Scene_surface_mesh_item.h" +#include "Scene_points_with_normal_item.h" #include #include #include @@ -47,6 +48,7 @@ public: actionRemoveSelfIntersections = new QAction(tr("Remove Self-Intersections"), mw); actionStitchCloseBorderHalfedges = new QAction(tr("Stitch Close Border Halfedges"), mw); actionDuplicateNMVertices = new QAction(tr("Duplicate Non-Manifold Vertices"), mw); + actionExtractNMVertices = new QAction(tr("Extract Non-Manifold Vertices"), mw); actionMergeDuplicatedVerticesOnBoundaryCycles = new QAction(tr("Merge Duplicated Vertices on Boundary Cycles"), mw); actionAutorefine = new QAction(tr("Autorefine Mesh"), mw); actionAutorefineAndRMSelfIntersections = new QAction(tr("Autorefine and Remove Self-Intersections"), mw); @@ -57,6 +59,7 @@ public: actionRemoveSelfIntersections->setObjectName("actionRemoveSelfIntersections"); actionStitchCloseBorderHalfedges->setObjectName("actionStitchCloseBorderHalfedges"); actionDuplicateNMVertices->setObjectName("actionDuplicateNMVertices"); + actionExtractNMVertices->setObjectName("actionExtractNMVertices"); actionMergeDuplicatedVerticesOnBoundaryCycles->setObjectName("actionMergeDuplicatedVerticesOnBoundaryCycles"); actionAutorefine->setObjectName("actionAutorefine"); actionAutorefineAndRMSelfIntersections->setObjectName("actionAutorefineAndRMSelfIntersections"); @@ -67,6 +70,7 @@ public: actionRemoveSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionRemoveIsolatedVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionDuplicateNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); + actionExtractNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionMergeDuplicatedVerticesOnBoundaryCycles->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); @@ -82,6 +86,7 @@ public: << actionRemoveSelfIntersections << actionStitchCloseBorderHalfedges << actionDuplicateNMVertices + << actionExtractNMVertices << actionMergeDuplicatedVerticesOnBoundaryCycles << actionAutorefine << actionAutorefineAndRMSelfIntersections @@ -104,6 +109,8 @@ public: template void on_actionDuplicateNMVertices_triggered(Scene_interface::Item_id index); template + void on_actionExtractNMVertices_triggered(Scene_interface::Item_id index); + template void on_actionMergeDuplicatedVerticesOnBoundaryCycles_triggered(Scene_interface::Item_id index); template void on_actionAutorefine_triggered(Scene_interface::Item_id index); @@ -116,6 +123,7 @@ public Q_SLOTS: void on_actionRemoveSelfIntersections_triggered(); void on_actionStitchCloseBorderHalfedges_triggered(); void on_actionDuplicateNMVertices_triggered(); + void on_actionExtractNMVertices_triggered(); void on_actionMergeDuplicatedVerticesOnBoundaryCycles_triggered(); void on_actionAutorefine_triggered(); void on_actionAutorefineAndRMSelfIntersections_triggered(); @@ -127,6 +135,7 @@ private: QAction* actionRemoveSelfIntersections; QAction* actionStitchCloseBorderHalfedges; QAction* actionDuplicateNMVertices; + QAction* actionExtractNMVertices; QAction* actionMergeDuplicatedVerticesOnBoundaryCycles; QAction* actionAutorefine; QAction* actionAutorefineAndRMSelfIntersections; @@ -347,6 +356,32 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionDuplicateNMVertices_trig } } +template +void Polyhedron_demo_repair_polyhedron_plugin::on_actionExtractNMVertices_triggered(Scene_interface::Item_id index) +{ + namespace PMP = CGAL::Polygon_mesh_processing; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + if (Item* poly_item = qobject_cast(scene->item(index))) + { + std::vector hds; + PMP::non_manifold_vertices(*poly_item->face_graph(), std::back_inserter(hds)); + if(hds.empty()) + { + CGAL::Three::Three::information(tr(" No NM vertex found.")); + return; + } + Scene_points_with_normal_item* pitem = new Scene_points_with_normal_item(); + pitem->setColor(Qt::red); + pitem->setName(QString("%1 nm vertices").arg(poly_item->name())); + for(const auto& h : hds) + { + pitem->point_set()->insert(poly_item->face_graph()->point(target(h, *poly_item->face_graph()))); + } + scene->addItem (pitem); + } +} + void Polyhedron_demo_repair_polyhedron_plugin::on_actionDuplicateNMVertices_triggered() { QApplication::setOverrideCursor(Qt::WaitCursor); @@ -355,6 +390,14 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionDuplicateNMVertices_trig QApplication::restoreOverrideCursor(); } +void Polyhedron_demo_repair_polyhedron_plugin::on_actionExtractNMVertices_triggered() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + on_actionExtractNMVertices_triggered(index); + QApplication::restoreOverrideCursor(); +} + template void Polyhedron_demo_repair_polyhedron_plugin::on_actionMergeDuplicatedVerticesOnBoundaryCycles_triggered(Scene_interface::Item_id index) { diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_plugin_helper.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_plugin_helper.cpp index 0418d405f72..51a425f57f0 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_plugin_helper.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_plugin_helper.cpp @@ -9,7 +9,7 @@ void CGAL::Three::Polyhedron_demo_plugin_helper::addDockWidget(QDockWidget* dock { mw->addDockWidget(::Qt::LeftDockWidgetArea, dock_widget); dock_widget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); - + dock_widget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable); QList dockWidgets = mw->findChildren(); int counter = 0; Q_FOREACH(QDockWidget* dock, dockWidgets) { diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index 8ea8f34d521..6ddc13cc074 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -90,6 +90,8 @@ Scene::addItem(CGAL::Three::Scene_item* item) item->drawEdges(CGAL::Three::Three::mainViewer()); item->drawPoints(CGAL::Three::Three::mainViewer()); CGAL::Three::Three::mainViewer()->setDepthPeelingFbo(fbo); + if(group) + m_groups.append(id); return id; } @@ -110,6 +112,7 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi QList group_children; if(group) { + m_groups.removeAll(index); Q_FOREACH(Item_id id, group->getChildren()) { CGAL::Three::Scene_item* child = group->getChild(id); @@ -152,6 +155,7 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi if(group) { addGroup(group); + m_groups.append(index); } itemChanged(index); Q_EMIT restoreCollapsedState(); @@ -173,6 +177,7 @@ Scene::erase(Scene::Item_id index) setSelectedItemsList(QList()<parentGroup() && item->parentGroup()->isChildLocked(item)) return -1; @@ -248,6 +253,7 @@ Scene::erase(QList indices) item->parentGroup()->removeChild(item); children.removeAll(removed_item); indexErased(removed_item); + m_groups.removeAll(removed_item); m_entries.removeAll(item); Q_EMIT itemAboutToBeDestroyed(item); @@ -1359,9 +1365,15 @@ QItemSelection Scene::createSelectionAll() //it is not possible to directly create a selection with items that have different parents, so //we do it iteratively. QItemSelection sel; - for(int i=0; i< m_entries.size(); ++i) - sel.select(index_map.keys(i).at(0), - index_map.keys(i).at(4)); + sel.select(this->createIndex(0, 0), + this->createIndex(m_entries.size(), LastColumn)); + for(const auto& gid : m_groups) + { + CGAL::Three::Scene_group_item* group = + qobject_cast(item(gid)); + sel.select(index_map.keys(group->getChildren().first()).at(0), + index_map.keys(group->getChildren().last()).at(4)); + } return sel; } @@ -1726,7 +1738,7 @@ void Scene::updatePrimitiveIds(CGAL::Three::Scene_item* it) } } } -bool Scene::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer) +bool Scene::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler) { CGAL::Three::Scene_item *i = item(mainSelectionIndex()); if(!i) @@ -1734,7 +1746,7 @@ bool Scene::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_inte Scene_print_item_interface* spit= qobject_cast(i); if(spit && i->visible()) { - bool res = spit->testDisplayId(x,y,z, viewer); + bool res = spit->testDisplayId(x,y,z, viewer, scaler); return res; } else diff --git a/Polyhedron/demo/Polyhedron/Scene.h b/Polyhedron/demo/Polyhedron/Scene.h index 6240a255abf..1159739e3e7 100644 --- a/Polyhedron/demo/Polyhedron/Scene.h +++ b/Polyhedron/demo/Polyhedron/Scene.h @@ -64,6 +64,7 @@ public: int numberOfEntries() const Q_DECL_OVERRIDE; // returns the list of items. const QList& entries() const { return m_entries; } + Q_INVOKABLE CGAL::Three::Scene_item* item(int) const Q_DECL_OVERRIDE; int item_id(CGAL::Three::Scene_item*) const Q_DECL_OVERRIDE; @@ -94,7 +95,7 @@ public: void printAllIds() Q_DECL_OVERRIDE; //!Re-computes the primitiveIds for `item` void updatePrimitiveIds(Scene_item *item) Q_DECL_OVERRIDE; - bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer) Q_DECL_OVERRIDE; + bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler) Q_DECL_OVERRIDE; Bbox bbox() const Q_DECL_OVERRIDE; void computeBbox(); double len_diagonal() const Q_DECL_OVERRIDE @@ -280,6 +281,7 @@ private: typedef QList Entries; //List containing all the scene_items. Entries m_entries; + QList m_groups; //used to optimize createSelectionAll() QList children; // Index of the currently selected item. int selected_item; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index 2473c474f3c..69de06f2d58 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -2254,9 +2254,9 @@ void Scene_polyhedron_selection_item::printAllIds() { d->item->polyhedron_item()->printAllIds(); } -bool Scene_polyhedron_selection_item::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer)const +bool Scene_polyhedron_selection_item::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler)const { - return d->item->polyhedron_item()->testDisplayId(x, y, z, viewer); + return d->item->polyhedron_item()->testDisplayId(x, y, z, viewer, scaler); return false; } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index dbfca601296..71cd28e6f85 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -218,7 +218,7 @@ public: bool printEdgeIds() const; bool printFaceIds() const; void printAllIds(); - bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*)const; + bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*, const QVector3D&)const; bool shouldDisplayIds(CGAL::Three::Scene_item *current_item) const; QString defaultSaveName() const { diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index ee404035f3f..3addac4c486 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -2130,7 +2130,7 @@ void Scene_surface_mesh_item::printAllIds() d->killIds(); } -bool Scene_surface_mesh_item::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer)const +bool Scene_surface_mesh_item::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler)const { const CGAL::qglviewer::Vec offset = static_cast(CGAL::QGLViewer::QGLViewerPool().first())->offset(); EPICK::Point_3 src(x - offset.x, @@ -2138,13 +2138,14 @@ bool Scene_surface_mesh_item::testDisplayId(double x, double y, double z, CGAL:: z - offset.z); CGAL::qglviewer::Camera* cam = viewer->camera(); - EPICK::Point_3 dest( cam->position().x - offset.x, - cam->position().y - offset.y, - cam->position().z - offset.z); + EPICK::Point_3 dest( cam->position().x/scaler.x() - offset.x, + cam->position().y/scaler.y() - offset.y, + cam->position().z/scaler.z() - offset.z); EPICK::Vector_3 v(src,dest); EPICK::Vector_3 dir(cam->viewDirection().x, cam->viewDirection().y, cam->viewDirection().z); + if(-CGAL::scalar_product(v, dir) < cam->zNear()) //if src is behind the near plane, don't display. return false; v = 0.01*v; diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h index d04f771899b..fba5cb89635 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.h @@ -149,7 +149,7 @@ public: bool printFaceIds()const Q_DECL_OVERRIDE; void printAllIds() Q_DECL_OVERRIDE; bool shouldDisplayIds(CGAL::Three::Scene_item *current_item) const Q_DECL_OVERRIDE; - bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface*)const Q_DECL_OVERRIDE; + bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface*, const QVector3D &scaler)const Q_DECL_OVERRIDE; float alpha() const Q_DECL_OVERRIDE; void setAlpha(int alpha) Q_DECL_OVERRIDE; QSlider* alphaSlider(); diff --git a/Polyhedron/demo/Polyhedron/TextRenderer.cpp b/Polyhedron/demo/Polyhedron/TextRenderer.cpp index 2e9ce45fefe..9a18b8d19ab 100644 --- a/Polyhedron/demo/Polyhedron/TextRenderer.cpp +++ b/Polyhedron/demo/Polyhedron/TextRenderer.cpp @@ -2,7 +2,7 @@ #include #include #include "Scene_polyhedron_selection_item.h" -void TextRenderer::draw(CGAL::Three::Viewer_interface *viewer) +void TextRenderer::draw(CGAL::Three::Viewer_interface *viewer, const QVector3D& scaler) { QPainter *painter = viewer->getPainter(); if (!painter->isActive()) @@ -23,10 +23,15 @@ void TextRenderer::draw(CGAL::Three::Viewer_interface *viewer) if(viewer->testDisplayId(src.x, src.y, src.z)) { if(item->is_3D()) - rect = QRect(int(camera->projectedCoordinatesOf(src).x-item->width()/2), - int(camera->projectedCoordinatesOf(src).y-item->height()/2), + { + src.x *= scaler.x(); + src.y *= scaler.y(); + src.z *= scaler.z(); + rect = QRect(int(camera->projectedCoordinatesOf(src).x -item->width()/2), + int(camera->projectedCoordinatesOf(src).y -item->height()/2), int(item->width()), int(item->height())); + } else rect = QRect(int(src.x-item->width()/2), int(src.y-item->height()/2), diff --git a/Polyhedron/demo/Polyhedron/Viewer.cpp b/Polyhedron/demo/Polyhedron/Viewer.cpp index 95ede4b08db..b215784e429 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.cpp +++ b/Polyhedron/demo/Polyhedron/Viewer.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #ifdef CGAL_USE_WEBSOCKETS #include @@ -25,6 +26,7 @@ #include #include "ui_LightingDialog.h" +#include "CGAL_double_edit.h" #if defined(_WIN32) #include @@ -46,8 +48,10 @@ public: bool clipping; bool projection_is_ortho; bool cam_sharing; + bool scene_scaling; GLfloat gl_point_size; QVector4D clipbox[6]; + QVector3D scaler; QPainter *painter; // L i g h t i n g @@ -117,6 +121,7 @@ public: { return shader_programs; } + #ifdef CGAL_USE_WEBSOCKETS QWebSocket m_webSocket; #endif @@ -292,6 +297,8 @@ void Viewer::doBindings() d->textRenderer = new TextRenderer(); d->is_2d_selection_mode = false; d->is_connected = false; + d->scene_scaling = false; + d->scaler = QVector3D(1,1,1); connect( d->textRenderer, SIGNAL(sendMessage(QString,int)), this, SLOT(printMessage(QString,int)) ); @@ -407,7 +414,7 @@ Viewer::~Viewer() .arg(d->back_color.redF()) .arg(d->back_color.greenF()) .arg(d->back_color.blueF())); - + makeCurrent(); d->vao.destroy(); if(d->_recentFunctions) delete d->_recentFunctions; @@ -831,9 +838,23 @@ void Viewer::postSelection(const QPoint& pixel) point = camera()->pointUnderPixel(pixel, found) - offset(); } if(found) { - Q_EMIT selectedPoint(point.x, - point.y, - point.z); + QVector3D transformed_point(point.x, + point.y, + point.z); + if(d->scene_scaling) + { + transformed_point = QVector3D( + point.x+offset().x, + point.y+offset().y, + point.z+offset().z); + transformed_point = transformed_point/d->scaler; + transformed_point[0] -=offset().x ; + transformed_point[1] -=offset().y ; + transformed_point[2] -=offset().z ; + } + Q_EMIT selectedPoint(transformed_point.x(), + transformed_point.y(), + transformed_point.z()); CGAL::qglviewer::Vec dir; CGAL::qglviewer::Vec orig; if(d->projection_is_ortho) @@ -931,6 +952,10 @@ void Viewer::attribBuffers(int program_name) const { this->camera()->getModelViewProjectionMatrix(d_mat); for (int i=0; i<16; ++i) mvp_mat.data()[i] = GLfloat(d_mat[i]); + if(d->scene_scaling){ + mvp_mat.scale(d->scaler); + mv_mat.scale(d->scaler); + } QOpenGLShaderProgram* program = getShaderProgram(program_name); program->bind(); @@ -1130,7 +1155,7 @@ void Viewer::drawVisualHints() { d->textRenderer->addText(message_text); } - d->textRenderer->draw(this); + d->textRenderer->draw(this, d->scaler); if (d->_displayMessage) d->textRenderer->removeText(message_text); @@ -1458,7 +1483,7 @@ void Viewer::wheelEvent(QWheelEvent* e) bool Viewer::testDisplayId(double x, double y, double z) { - return d->scene->testDisplayId(x,y,z,this); + return d->scene->testDisplayId(x,y,z,this, d->scaler); } QPainter* Viewer::getPainter(){return d->painter;} @@ -1552,26 +1577,26 @@ void Viewer_impl::showDistance(QPoint pixel) rendering_program_dist.setAttributeBuffer("vertex",GL_FLOAT,0,3); buffer.release(); vao.release(); - distance_is_displayed = true; - double dist = std::sqrt((BPoint.x-APoint.x)*(BPoint.x-APoint.x) + (BPoint.y-APoint.y)*(BPoint.y-APoint.y) + (BPoint.z-APoint.z)*(BPoint.z-APoint.z)); + double dist = std::sqrt((BPoint.x-APoint.x)/scaler.x()*(BPoint.x-APoint.x)/scaler.x() + (BPoint.y-APoint.y)/scaler.y()*(BPoint.y-APoint.y)/scaler.y() + (BPoint.z-APoint.z)/scaler.z()*(BPoint.z-APoint.z)/scaler.z()); QFont font; font.setBold(true); TextItem *ACoord = new TextItem(float(APoint.x), float(APoint.y), float(APoint.z), QString("A(%1,%2,%3)") - .arg(APoint.x-viewer->offset().x, 0, 'g', 10) - .arg(APoint.y-viewer->offset().y, 0, 'g', 10) - .arg(APoint.z-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true); + .arg(APoint.x/scaler.x()-viewer->offset().x, 0, 'g', 10) + .arg(APoint.y/scaler.y()-viewer->offset().y, 0, 'g', 10) + .arg(APoint.z/scaler.z()-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true); distance_text.append(ACoord); TextItem *BCoord = new TextItem(float(BPoint.x), float(BPoint.y), float(BPoint.z), QString("B(%1,%2,%3)") - .arg(BPoint.x-viewer->offset().x, 0, 'g', 10) - .arg(BPoint.y-viewer->offset().y, 0, 'g', 10) - .arg(BPoint.z-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true); + .arg(BPoint.x/scaler.x()-viewer->offset().x, 0, 'g', 10) + .arg(BPoint.y/scaler.y()-viewer->offset().y, 0, 'g', 10) + .arg(BPoint.z/scaler.z()-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true); + distance_text.append(BCoord); CGAL::qglviewer::Vec centerPoint = 0.5*(BPoint+APoint); TextItem *centerCoord = new TextItem(float(centerPoint.x), @@ -1583,12 +1608,12 @@ void Viewer_impl::showDistance(QPoint pixel) Q_FOREACH(TextItem* ti, distance_text) textRenderer->addText(ti); Q_EMIT(viewer->sendMessage(QString("First point : A(%1,%2,%3), second point : B(%4,%5,%6), distance between them : %7") - .arg(APoint.x-viewer->offset().x) - .arg(APoint.y-viewer->offset().y) - .arg(APoint.z-viewer->offset().z) - .arg(BPoint.x-viewer->offset().x) - .arg(BPoint.y-viewer->offset().y) - .arg(BPoint.z-viewer->offset().z) + .arg(APoint.x/scaler.x()-viewer->offset().x) + .arg(APoint.y/scaler.y()-viewer->offset().y) + .arg(APoint.z/scaler.z()-viewer->offset().z) + .arg(BPoint.x/scaler.x()-viewer->offset().x) + .arg(BPoint.y/scaler.y()-viewer->offset().y) + .arg(BPoint.z/scaler.z()-viewer->offset().z) .arg(dist, 0, 'g', 10))); } @@ -1958,6 +1983,56 @@ bool Viewer::isClipping() const { return d->clipping; } + +void Viewer::scaleScene() +{ + CGAL::Bbox_3 bbox = CGAL::Three::Three::scene()->bbox(); + if(!d->scene_scaling) + { + QMultipleInputDialog dialog ("Scale Scene", CGAL::Three::Three::mainWindow()); + DoubleEdit* x_val = dialog.add ("Scale along X"); + DoubleEdit* y_val = dialog.add ("Scale along Y"); + DoubleEdit* z_val = dialog.add ("Scale along Z"); + x_val->setMinimum(0); + y_val->setMinimum(0); + z_val->setMinimum(0); + if(bbox != CGAL::Bbox_3(0,0,0,0,0,0)) + { + QPushButton* norm_button = dialog.add (""); + norm_button->setText("Normalize"); + norm_button->setToolTip("Automatically fill values to display the scene in a unit cube."); + + connect(norm_button, &QPushButton::clicked, this, + [x_val, y_val, z_val, &bbox](){ + x_val->setValue(1.0/(bbox.xmax()-bbox.xmin())); + y_val->setValue(1.0/(bbox.ymax()-bbox.ymin())); + z_val->setValue(1.0/(bbox.zmax()-bbox.zmin())); + }); + } + if (dialog.exec() != QDialog::Accepted) + { + parent()->findChild("actionScaleScene")->setChecked(false); + return; + } + d->scaler.setX(x_val->text()==""?1.0:x_val->value()); + d->scaler.setY(y_val->text()==""?1.0:y_val->value()); + d->scaler.setZ(z_val->text()==""?1.0:z_val->value()); + + if(d->scaler.x() == 0.0 || d->scaler.y() == 0.0 || d->scaler.z()== 0.0) + { + parent()->findChild("actionScaleScene")->setChecked(false); + return; + } + } + else + d->scaler = QVector3D(1,1,1); + + CGAL::qglviewer::Vec vmin(((float)bbox.xmin()+offset().x)*d->scaler.x(), ((float)bbox.ymin()+offset().y)*d->scaler.y(), ((float)bbox.zmin()+offset().z)*d->scaler.z()), + vmax(((float)bbox.xmax()+offset().x)*d->scaler.x(), ((float)bbox.ymax()+offset().y)*d->scaler.y(), ((float)bbox.zmax()+offset().z)*d->scaler.z()); + camera()->setPivotPoint((vmin+vmax)*0.5); + camera()->fitBoundingBox(vmin, vmax); + d->scene_scaling = !d->scene_scaling; +} #ifdef CGAL_USE_WEBSOCKETS void Viewer::setShareCam(bool b, QString session) { diff --git a/Polyhedron/demo/Polyhedron/Viewer.h b/Polyhedron/demo/Polyhedron/Viewer.h index 0d5bd3541df..7fceedbb0e7 100644 --- a/Polyhedron/demo/Polyhedron/Viewer.h +++ b/Polyhedron/demo/Polyhedron/Viewer.h @@ -137,7 +137,7 @@ public Q_SLOTS: void onSocketConnected(); void onTextMessageSocketReceived(QString message); #endif - + void scaleScene(); protected: void paintEvent(QPaintEvent *)Q_DECL_OVERRIDE; void paintGL()Q_DECL_OVERRIDE; diff --git a/Three/include/CGAL/Three/Scene_draw_interface.h b/Three/include/CGAL/Three/Scene_draw_interface.h index 4ceaa728a23..d3ef745763f 100644 --- a/Three/include/CGAL/Three/Scene_draw_interface.h +++ b/Three/include/CGAL/Three/Scene_draw_interface.h @@ -61,7 +61,7 @@ public: * \param z the Z coordinate of theTextItem's position. * \param viewer the viewer used to display the Scene. * \return true if the TextItem is visible. */ - virtual bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer) = 0; + virtual bool testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler) = 0; ///\brief displays all the vertices ids if there are less than max_textItems. virtual void printVertexIds() = 0; diff --git a/Three/include/CGAL/Three/Scene_print_item_interface.h b/Three/include/CGAL/Three/Scene_print_item_interface.h index 3ad79996463..f6ff32c2374 100644 --- a/Three/include/CGAL/Three/Scene_print_item_interface.h +++ b/Three/include/CGAL/Three/Scene_print_item_interface.h @@ -48,7 +48,7 @@ public: //! //! \returns true if the Id should be displayed //! \returns false if the Id should not be displayed (if it is hidden for example) - virtual bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*)const = 0; + virtual bool testDisplayId(double, double, double, CGAL::Three::Viewer_interface*, const QVector3D& scaler)const = 0; //! \brief Tests if this item should display its ids. //! diff --git a/Three/include/CGAL/Three/TextRenderer.h b/Three/include/CGAL/Three/TextRenderer.h index 678a3cfc0b9..2d2f8e3a4c0 100644 --- a/Three/include/CGAL/Three/TextRenderer.h +++ b/Three/include/CGAL/Three/TextRenderer.h @@ -139,7 +139,7 @@ public: { } //!Draws all the `TextItem`s - void draw(CGAL::Three::Viewer_interface* viewer); + void draw(CGAL::Three::Viewer_interface* viewer, const QVector3D& scaler); //!\brief Adds a single TextItem to TextRenderer::local_textItems //! //! @see addText(float p_x, float p_y, float p_z, QString p_text, bool p_3D = true, QFont font = QFont(), QColor p_color = Qt::black)