From 2de707e60418c546964a4baadafabe87eb5acc46 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 5 Mar 2020 13:07:18 +0100 Subject: [PATCH] ReverseEngineering: manual mesh segmentation --- src/Mod/ReverseEngineering/Gui/CMakeLists.txt | 6 +- src/Mod/ReverseEngineering/Gui/Command.cpp | 84 ++++++++ src/Mod/ReverseEngineering/Gui/PreCompiled.h | 8 +- .../Gui/SegmentationManual.cpp | 203 ++++++++++++++++++ .../Gui/SegmentationManual.h | 97 +++++++++ .../Gui/SegmentationManual.ui | 160 ++++++++++++++ src/Mod/ReverseEngineering/Gui/Workbench.cpp | 2 + 7 files changed, 556 insertions(+), 4 deletions(-) create mode 100644 src/Mod/ReverseEngineering/Gui/SegmentationManual.cpp create mode 100644 src/Mod/ReverseEngineering/Gui/SegmentationManual.h create mode 100644 src/Mod/ReverseEngineering/Gui/SegmentationManual.ui diff --git a/src/Mod/ReverseEngineering/Gui/CMakeLists.txt b/src/Mod/ReverseEngineering/Gui/CMakeLists.txt index fca294202e..8f77f8c9cd 100644 --- a/src/Mod/ReverseEngineering/Gui/CMakeLists.txt +++ b/src/Mod/ReverseEngineering/Gui/CMakeLists.txt @@ -19,7 +19,7 @@ link_directories(${OCC_LIBRARY_DIR}) set(ReenGui_LIBS ReverseEngineering - FreeCADGui + MeshGui ) if(BUILD_QT5) @@ -32,6 +32,7 @@ set(ReenGui_MOC_HDRS FitBSplineSurface.h Poisson.h Segmentation.h + SegmentationManual.h ) fc_wrap_cpp(ReenGui_MOC_SRCS ${ReenGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${ReenGui_MOC_SRCS}) @@ -40,6 +41,7 @@ set(Dialogs_UIC_SRCS FitBSplineSurface.ui Poisson.ui Segmentation.ui + SegmentationManual.ui ) if(BUILD_QT5) @@ -57,6 +59,8 @@ SET(Dialogs_SRCS Poisson.h Segmentation.cpp Segmentation.h + SegmentationManual.cpp + SegmentationManual.h ) SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS}) diff --git a/src/Mod/ReverseEngineering/Gui/Command.cpp b/src/Mod/ReverseEngineering/Gui/Command.cpp index 43b4c6ccfb..06bb71ed87 100644 --- a/src/Mod/ReverseEngineering/Gui/Command.cpp +++ b/src/Mod/ReverseEngineering/Gui/Command.cpp @@ -36,12 +36,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -55,6 +57,7 @@ #include "FitBSplineSurface.h" #include "Poisson.h" #include "Segmentation.h" +#include "SegmentationManual.h" using namespace std; @@ -324,6 +327,85 @@ bool CmdSegmentation::isActive(void) (Mesh::Feature::getClassTypeId()) == 1; } +DEF_STD_CMD_A(CmdSegmentationManual) + +CmdSegmentationManual::CmdSegmentationManual() + : Command("Reen_SegmentationManual") +{ + sAppModule = "Reen"; + sGroup = QT_TR_NOOP("Reverse Engineering"); + sMenuText = QT_TR_NOOP("Manual segmentation..."); + sToolTipText = QT_TR_NOOP("Create mesh segments manually"); + sWhatsThis = "Reen_SegmentationManual"; + sStatusTip = sToolTipText; +} + +void CmdSegmentationManual::activated(int) +{ + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + dlg = new ReverseEngineeringGui::TaskSegmentationManual(); + } + Gui::Control().showDialog(dlg); +} + +bool CmdSegmentationManual::isActive(void) +{ + if (Gui::Control().activeDialog()) + return false; + return hasActiveDocument(); +} + +DEF_STD_CMD_A(CmdSegmentationFromComponents) + +CmdSegmentationFromComponents::CmdSegmentationFromComponents() + : Command("Reen_SegmentationFromComponents") +{ + sAppModule = "Reen"; + sGroup = QT_TR_NOOP("Reverse Engineering"); + sMenuText = QT_TR_NOOP("From components"); + sToolTipText = QT_TR_NOOP("Create mesh segments from components"); + sWhatsThis = "Reen_SegmentationFromComponents"; + sStatusTip = sToolTipText; +} + +void CmdSegmentationFromComponents::activated(int) +{ + std::vector sel = getSelection().getObjectsOfType(); + App::Document* doc = App::GetApplication().getActiveDocument(); + doc->openTransaction("Segmentation"); + + for (auto it : sel) { + std::string internalname = "Segments_"; + internalname += it->getNameInDocument(); + App::DocumentObjectGroup* group = static_cast(doc->addObject + ("App::DocumentObjectGroup", internalname.c_str())); + std::string labelname = "Segments "; + labelname += it->Label.getValue(); + group->Label.setValue(labelname); + + const Mesh::MeshObject& mesh = it->Mesh.getValue(); + std::vector > comps = mesh.getComponents(); + for (auto jt : comps) { + std::unique_ptr segment(mesh.meshFromSegment(jt)); + Mesh::Feature* feaSegm = static_cast(group->addObject("Mesh::Feature", "Segment")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + } + } + + doc->commitTransaction(); + doc->recompute(); +} + +bool CmdSegmentationFromComponents::isActive(void) +{ + if (getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0) + return true; + return false; +} + DEF_STD_CMD_A(CmdMeshBoundary) CmdMeshBoundary::CmdMeshBoundary() @@ -484,6 +566,8 @@ void CreateReverseEngineeringCommands(void) rcCmdMgr.addCommand(new CmdApproxCylinder()); rcCmdMgr.addCommand(new CmdApproxSphere()); rcCmdMgr.addCommand(new CmdSegmentation()); + rcCmdMgr.addCommand(new CmdSegmentationManual()); + rcCmdMgr.addCommand(new CmdSegmentationFromComponents()); rcCmdMgr.addCommand(new CmdMeshBoundary()); rcCmdMgr.addCommand(new CmdPoissonReconstruction()); rcCmdMgr.addCommand(new CmdViewTriangulation()); diff --git a/src/Mod/ReverseEngineering/Gui/PreCompiled.h b/src/Mod/ReverseEngineering/Gui/PreCompiled.h index 80954fa056..313b942286 100644 --- a/src/Mod/ReverseEngineering/Gui/PreCompiled.h +++ b/src/Mod/ReverseEngineering/Gui/PreCompiled.h @@ -30,15 +30,17 @@ #ifdef FC_OS_WIN32 # define ReenExport __declspec(dllimport) # define ReenGuiExport __declspec(dllexport) -# define PartExport __declspec(dllimport) +# define PartExport __declspec(dllimport) # define MeshExport __declspec(dllimport) -# define PointsExport __declspec(dllimport) -# define AppExport __declspec(dllimport) +# define MeshGuiExport __declspec(dllimport) +# define PointsExport __declspec(dllimport) +# define AppExport __declspec(dllimport) #else // for Linux # define ReenExport # define ReenGuiExport # define PartExport # define MeshExport +# define MeshGuiExport # define PointsExport # define AppExport #endif diff --git a/src/Mod/ReverseEngineering/Gui/SegmentationManual.cpp b/src/Mod/ReverseEngineering/Gui/SegmentationManual.cpp new file mode 100644 index 0000000000..6b9f93db44 --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/SegmentationManual.cpp @@ -0,0 +1,203 @@ +/*************************************************************************** + * Copyright (c) 2020 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +#endif + +#include "SegmentationManual.h" +#include "ui_SegmentationManual.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ReverseEngineeringGui; + + +SegmentationManual::SegmentationManual(QWidget* parent, Qt::WindowFlags fl) + : QWidget(parent, fl) + , ui(new Ui_SegmentationManual) +{ + ui->setupUi(this); + ui->spSelectComp->setRange(1, INT_MAX); + ui->spSelectComp->setValue(10); + + Gui::Selection().clearSelection(); + meshSel.setCheckOnlyVisibleTriangles(ui->visibleTriangles->isChecked()); + meshSel.setCheckOnlyPointToUserTriangles(ui->screenTriangles->isChecked()); + meshSel.setEnabledViewerSelection(false); +} + +SegmentationManual::~SegmentationManual() +{ +} + +void SegmentationManual::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + QWidget::changeEvent(e); +} + +void SegmentationManual::on_selectRegion_clicked() +{ + meshSel.startSelection(); +} + +void SegmentationManual::on_selectAll_clicked() +{ + // select the complete meshes + meshSel.fullSelection(); +} + +void SegmentationManual::on_deselectAll_clicked() +{ + // deselect all meshes + meshSel.clearSelection(); +} + +void SegmentationManual::on_selectComponents_clicked() +{ + // select components up to a certain size + int size = ui->spSelectComp->value(); + meshSel.selectComponent(size); +} + +void SegmentationManual::on_visibleTriangles_toggled(bool on) +{ + meshSel.setCheckOnlyVisibleTriangles(on); +} + +void SegmentationManual::on_screenTriangles_toggled(bool on) +{ + meshSel.setCheckOnlyPointToUserTriangles(on); +} + +void SegmentationManual::on_cbSelectComp_toggled(bool on) +{ + meshSel.setAddComponentOnClick(on); +} + +void SegmentationManual::createSegment() +{ + Gui::Document* gdoc = Gui::Application::Instance->activeDocument(); + if (!gdoc) + return; + // delete all selected faces + App::Document* adoc = gdoc->getDocument(); + gdoc->openCommand("Segmentation"); + + std::vector meshes = adoc->getObjectsOfType(); + bool selected = false; + for (auto it : meshes) { + const Mesh::MeshObject& mesh = it->Mesh.getValue(); + const MeshCore::MeshKernel& kernel = mesh.getKernel(); + + MeshCore::MeshAlgorithm algo(kernel); + unsigned long ct = algo.CountFacetFlag(MeshCore::MeshFacet::SELECTED); + if (ct > 0) { + selected = true; + + std::vector facets; + algo.GetFacetsFlag(facets, MeshCore::MeshFacet::SELECTED); + + std::unique_ptr segment(mesh.meshFromSegment(facets)); + Mesh::Feature* feaSegm = static_cast(adoc->addObject("Mesh::Feature", "Segment")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + } + } + + if (!selected) + gdoc->abortCommand(); + else + gdoc->commitCommand(); + meshSel.clearSelection(); +} + +void SegmentationManual::on_selectTriangle_clicked() +{ + meshSel.selectTriangle(); + meshSel.setAddComponentOnClick(ui->cbSelectComp->isChecked()); +} + +void SegmentationManual::reject() +{ + // deselect all meshes + meshSel.clearSelection(); + meshSel.setEnabledViewerSelection(true); +} + +// ------------------------------------------------- + +/* TRANSLATOR ReverseEngineeringGui::TaskSegmentationManual */ + +TaskSegmentationManual::TaskSegmentationManual() +{ + widget = new SegmentationManual(); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSegmentationManual::~TaskSegmentationManual() +{ + // automatically deleted in the sub-class +} + +void TaskSegmentationManual::modifyStandardButtons(QDialogButtonBox* box) +{ + QPushButton* btn = box->button(QDialogButtonBox::Ok); + btn->setText(tr("Create")); +} + +bool TaskSegmentationManual::accept() +{ + return false; +} + +void TaskSegmentationManual::clicked(int id) +{ + if (id == QDialogButtonBox::Ok) { + widget->createSegment(); + } + else if (id == QDialogButtonBox::Close) { + widget->reject(); + } +} + +#include "moc_SegmentationManual.cpp" diff --git a/src/Mod/ReverseEngineering/Gui/SegmentationManual.h b/src/Mod/ReverseEngineering/Gui/SegmentationManual.h new file mode 100644 index 0000000000..b1acda693d --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/SegmentationManual.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (c) 2020 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef REVERSEENGINEERINGGUI_SEGMENTATIONMANUAL_H +#define REVERSEENGINEERINGGUI_SEGMENTATIONMANUAL_H + +#include +#include +#include +#include +#include + +namespace ReverseEngineeringGui { +class Ui_SegmentationManual; + +/** + * Dialog to create segments from components, regions, the complete or single faces + * of a mesh. + * @author Werner Mayer + */ +class SegmentationManual : public QWidget +{ + Q_OBJECT + +public: + SegmentationManual(QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~SegmentationManual(); + void reject(); + void createSegment(); + +public Q_SLOTS: + void on_selectRegion_clicked(); + void on_selectAll_clicked(); + void on_selectComponents_clicked(); + void on_selectTriangle_clicked(); + void on_deselectAll_clicked(); + void on_visibleTriangles_toggled(bool); + void on_screenTriangles_toggled(bool); + void on_cbSelectComp_toggled(bool); + +protected: + void changeEvent(QEvent *e); + +private: + std::unique_ptr ui; + MeshGui::MeshSelection meshSel; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskSegmentationManual : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskSegmentationManual(); + ~TaskSegmentationManual(); + +public: + bool accept(); + void clicked(int); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Close; } + virtual bool isAllowedAlterDocument(void) const + { return true; } + virtual void modifyStandardButtons(QDialogButtonBox*); + +private: + SegmentationManual* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} + +#endif // REVERSEENGINEERINGGUI_SEGMENTATIONMANUAL_H diff --git a/src/Mod/ReverseEngineering/Gui/SegmentationManual.ui b/src/Mod/ReverseEngineering/Gui/SegmentationManual.ui new file mode 100644 index 0000000000..0300c15936 --- /dev/null +++ b/src/Mod/ReverseEngineering/Gui/SegmentationManual.ui @@ -0,0 +1,160 @@ + + + ReverseEngineeringGui::SegmentationManual + + + + 0 + 0 + 346 + 314 + + + + Manual segmentation + + + + + + Select + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + + + Components + + + + + + + Region + + + + + + + Select whole component + + + + + + + Pick triangle + + + + + + + Qt::Horizontal + + + + 161 + 20 + + + + + + + + < faces than + + + + + + + All + + + + + + + + + + Qt::Horizontal + + + + 161 + 20 + + + + + + + + Clear + + + + + + + + + + Region options + + + + + + Respect only visible triangles + + + false + + + + + + + Respect only triangles with normals facing screen + + + true + + + + + + + + + + selectRegion + selectAll + selectComponents + spSelectComp + selectTriangle + cbSelectComp + + + + diff --git a/src/Mod/ReverseEngineering/Gui/Workbench.cpp b/src/Mod/ReverseEngineering/Gui/Workbench.cpp index e2398d426f..0d1b18682d 100644 --- a/src/Mod/ReverseEngineering/Gui/Workbench.cpp +++ b/src/Mod/ReverseEngineering/Gui/Workbench.cpp @@ -69,6 +69,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_CurvatureInfo" << "Separator" << "Reen_Segmentation" + << "Reen_SegmentationManual" + << "Reen_SegmentationFromComponents" << "Reen_MeshBoundary"; *reen << segm;