From d7077f06a70cec9a8e819ab8c615af8a42160697 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 10 Dec 2018 00:23:31 +0100 Subject: [PATCH] mesh segmentation algorithm for surfaces --- src/Mod/Mesh/App/Core/MeshKernel.cpp | 9 + src/Mod/Mesh/App/Core/MeshKernel.h | 4 + src/Mod/Mesh/App/Core/Segmentation.cpp | 57 ++- src/Mod/Mesh/App/Core/Segmentation.h | 11 +- src/Mod/Mesh/App/Mesh.cpp | 6 +- src/Mod/Mesh/Gui/CMakeLists.txt | 6 +- src/Mod/Mesh/Gui/Command.cpp | 36 ++ src/Mod/Mesh/Gui/SegmentationBestFit.cpp | 464 +++++++++++++++++++++++ src/Mod/Mesh/Gui/SegmentationBestFit.h | 125 ++++++ src/Mod/Mesh/Gui/SegmentationBestFit.ui | 180 +++++++++ src/Mod/Mesh/Gui/Workbench.cpp | 1 + 11 files changed, 871 insertions(+), 28 deletions(-) create mode 100644 src/Mod/Mesh/Gui/SegmentationBestFit.cpp create mode 100644 src/Mod/Mesh/Gui/SegmentationBestFit.h create mode 100644 src/Mod/Mesh/Gui/SegmentationBestFit.ui diff --git a/src/Mod/Mesh/App/Core/MeshKernel.cpp b/src/Mod/Mesh/App/Core/MeshKernel.cpp index e4303ea7e8..9c2e363876 100644 --- a/src/Mod/Mesh/App/Core/MeshKernel.cpp +++ b/src/Mod/Mesh/App/Core/MeshKernel.cpp @@ -773,6 +773,15 @@ std::vector MeshKernel::HasFacets (const MeshPointIterator &rclIt return aulBelongs; } +MeshPointArray MeshKernel::GetPoints(const std::vector& indices) const +{ + MeshPointArray ary; + ary.reserve(indices.size()); + for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) + ary.push_back(this->_aclPointArray[*it]); + return ary; +} + MeshFacetArray MeshKernel::GetFacets(const std::vector& indices) const { MeshFacetArray ary; diff --git a/src/Mod/Mesh/App/Core/MeshKernel.h b/src/Mod/Mesh/App/Core/MeshKernel.h index 9259ee876d..ba271fc19a 100644 --- a/src/Mod/Mesh/App/Core/MeshKernel.h +++ b/src/Mod/Mesh/App/Core/MeshKernel.h @@ -140,6 +140,10 @@ public: /** Returns the array of all data points. */ const MeshPointArray& GetPoints (void) const { return _aclPointArray; } + /** Returns an array of points to the given indices. The indices + * must not be out of range. + */ + MeshPointArray GetPoints(const std::vector&) const; /** Returns a modifier for the point array */ MeshPointModifier ModifyPoints() diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index 785f13f624..aae8f83334 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -111,6 +111,13 @@ PlaneSurfaceFit::PlaneSurfaceFit() { } +PlaneSurfaceFit::PlaneSurfaceFit(const Base::Vector3f& b, const Base::Vector3f& n) + : basepoint(b) + , normal(n) + , fitter(nullptr) +{ +} + PlaneSurfaceFit::~PlaneSurfaceFit() { delete fitter; @@ -118,13 +125,15 @@ PlaneSurfaceFit::~PlaneSurfaceFit() void PlaneSurfaceFit::Initialize(const MeshCore::MeshGeomFacet& tria) { - fitter->Clear(); + if (fitter) { + fitter->Clear(); - basepoint = tria.GetGravityPoint(); - normal = tria.GetNormal(); - fitter->AddPoint(tria._aclPoints[0]); - fitter->AddPoint(tria._aclPoints[1]); - fitter->AddPoint(tria._aclPoints[2]); + basepoint = tria.GetGravityPoint(); + normal = tria.GetNormal(); + fitter->AddPoint(tria._aclPoints[0]); + fitter->AddPoint(tria._aclPoints[1]); + fitter->AddPoint(tria._aclPoints[2]); + } } bool PlaneSurfaceFit::TestTriangle(const MeshGeomFacet&) const @@ -134,22 +143,32 @@ bool PlaneSurfaceFit::TestTriangle(const MeshGeomFacet&) const void PlaneSurfaceFit::AddTriangle(const MeshCore::MeshGeomFacet& tria) { - fitter->AddPoint(tria.GetGravityPoint()); + if (fitter) + fitter->AddPoint(tria.GetGravityPoint()); } bool PlaneSurfaceFit::Done() const { - return fitter->Done(); + if (!fitter) + return true; + else + return fitter->Done(); } float PlaneSurfaceFit::Fit() { - return fitter->Fit(); + if (!fitter) + return 0; + else + return fitter->Fit(); } float PlaneSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const { - return fitter->GetDistanceToPlane(pnt); + if (!fitter) + return pnt.DistanceToPlane(basepoint, normal); + else + return fitter->GetDistanceToPlane(pnt); } // -------------------------------------------------------- @@ -291,27 +310,27 @@ float SphereSurfaceFit::GetDistanceToSurface(const Base::Vector3f& pnt) const // -------------------------------------------------------- -MeshDistanceGenericSurfaceSegment::MeshDistanceGenericSurfaceSegment(AbstractSurfaceFit* fit, - const MeshKernel& mesh, - unsigned long minFacets, - float tol) +MeshDistanceGenericSurfaceFitSegment::MeshDistanceGenericSurfaceFitSegment(AbstractSurfaceFit* fit, + const MeshKernel& mesh, + unsigned long minFacets, + float tol) : MeshDistanceSurfaceSegment(mesh, minFacets, tol) , fitter(fit) { } -MeshDistanceGenericSurfaceSegment::~MeshDistanceGenericSurfaceSegment() +MeshDistanceGenericSurfaceFitSegment::~MeshDistanceGenericSurfaceFitSegment() { delete fitter; } -void MeshDistanceGenericSurfaceSegment::Initialize(unsigned long index) +void MeshDistanceGenericSurfaceFitSegment::Initialize(unsigned long index) { MeshGeomFacet triangle = kernel.GetFacet(index); fitter->Initialize(triangle); } -bool MeshDistanceGenericSurfaceSegment::TestInitialFacet(unsigned long index) const +bool MeshDistanceGenericSurfaceFitSegment::TestInitialFacet(unsigned long index) const { MeshGeomFacet triangle = kernel.GetFacet(index); for (int i=0; i<3; i++) { @@ -321,7 +340,7 @@ bool MeshDistanceGenericSurfaceSegment::TestInitialFacet(unsigned long index) co return fitter->TestTriangle(triangle); } -bool MeshDistanceGenericSurfaceSegment::TestFacet (const MeshFacet& face) const +bool MeshDistanceGenericSurfaceFitSegment::TestFacet (const MeshFacet& face) const { if (!fitter->Done()) fitter->Fit(); @@ -334,7 +353,7 @@ bool MeshDistanceGenericSurfaceSegment::TestFacet (const MeshFacet& face) const return fitter->TestTriangle(triangle); } -void MeshDistanceGenericSurfaceSegment::AddFacet(const MeshFacet& face) +void MeshDistanceGenericSurfaceFitSegment::AddFacet(const MeshFacet& face) { MeshGeomFacet triangle = kernel.GetFacet(face); fitter->AddTriangle(triangle); diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index 1f124ea35e..d203efea63 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -101,6 +101,7 @@ class MeshExport PlaneSurfaceFit : public AbstractSurfaceFit { public: PlaneSurfaceFit(); + PlaneSurfaceFit(const Base::Vector3f& b, const Base::Vector3f& n); ~PlaneSurfaceFit(); void Initialize(const MeshGeomFacet&); bool TestTriangle(const MeshGeomFacet&) const; @@ -153,14 +154,14 @@ private: float radius; }; -class MeshExport MeshDistanceGenericSurfaceSegment : public MeshDistanceSurfaceSegment +class MeshExport MeshDistanceGenericSurfaceFitSegment : public MeshDistanceSurfaceSegment { public: - MeshDistanceGenericSurfaceSegment(AbstractSurfaceFit*, const MeshKernel& mesh, - unsigned long minFacets, float tol); - virtual ~MeshDistanceGenericSurfaceSegment(); + MeshDistanceGenericSurfaceFitSegment(AbstractSurfaceFit*, const MeshKernel& mesh, + unsigned long minFacets, float tol); + virtual ~MeshDistanceGenericSurfaceFitSegment(); bool TestFacet (const MeshFacet& rclFacet) const; - const char* GetType() const { return "Generic"; } + const char* GetType() const { return "GenericSurfaceFit"; } void Initialize(unsigned long); bool TestInitialFacet(unsigned long) const; void AddFacet(const MeshFacet& rclFacet); diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 71c5062933..7e90d4cbd1 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1711,15 +1711,15 @@ std::vector MeshObject::getSegmentsOfType(MeshObject::GeometryType type switch (type) { case PLANE: //surf.reset(new MeshCore::MeshDistancePlanarSegment(this->_kernel, minFacets, dev)); - surf.reset(new MeshCore::MeshDistanceGenericSurfaceSegment(new MeshCore::PlaneSurfaceFit, + surf.reset(new MeshCore::MeshDistanceGenericSurfaceFitSegment(new MeshCore::PlaneSurfaceFit, this->_kernel, minFacets, dev)); break; case CYLINDER: - surf.reset(new MeshCore::MeshDistanceGenericSurfaceSegment(new MeshCore::CylinderSurfaceFit, + surf.reset(new MeshCore::MeshDistanceGenericSurfaceFitSegment(new MeshCore::CylinderSurfaceFit, this->_kernel, minFacets, dev)); break; case SPHERE: - surf.reset(new MeshCore::MeshDistanceGenericSurfaceSegment(new MeshCore::SphereSurfaceFit, + surf.reset(new MeshCore::MeshDistanceGenericSurfaceFitSegment(new MeshCore::SphereSurfaceFit, this->_kernel, minFacets, dev)); break; default: diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index 51f428bfcd..7786f60ba1 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -26,11 +26,11 @@ set(Mesh_MOC_HDRS DlgRegularSolidImp.h DlgSettingsMeshView.h DlgSettingsImportExportImp.h - DlgSmoothing.h MeshEditor.h PropertyEditorMesh.h RemoveComponents.h + SegmentationBestFit.h Selection.h ) fc_wrap_cpp(Mesh_MOC_SRCS ${Mesh_MOC_HDRS}) @@ -45,6 +45,7 @@ set(Dialogs_UIC_SRCS DlgSmoothing.ui RemoveComponents.ui Segmentation.ui + SegmentationBestFit.ui Selection.ui ) @@ -74,6 +75,9 @@ SET(Dialogs_SRCS Segmentation.ui Segmentation.cpp Segmentation.h + SegmentationBestFit.ui + SegmentationBestFit.cpp + SegmentationBestFit.h Selection.ui Selection.cpp Selection.h diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 80e13ab637..090eb9784b 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -75,6 +75,7 @@ #include "ViewProviderCurvature.h" #include "MeshEditor.h" #include "Segmentation.h" +#include "SegmentationBestFit.h" using namespace Mesh; @@ -1622,6 +1623,40 @@ bool CmdMeshSegmentation::isActive(void) (Mesh::Feature::getClassTypeId()) == 1; } +//-------------------------------------------------------------------------------------- + +DEF_STD_CMD_A(CmdMeshSegmentationBestFit) + +CmdMeshSegmentationBestFit::CmdMeshSegmentationBestFit() + : Command("Mesh_SegmentationBestFit") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Create mesh segments from best-fit surfaces..."); + sToolTipText = QT_TR_NOOP("Create mesh segments from best-fit surfaces"); + sWhatsThis = "Mesh_SegmentationBestFit"; + sStatusTip = QT_TR_NOOP("Create mesh segments from best-fit surfaces"); +} + +void CmdMeshSegmentationBestFit::activated(int) +{ + std::vector objs = Gui::Selection().getObjectsOfType + (Mesh::Feature::getClassTypeId()); + Mesh::Feature* mesh = static_cast(objs.front()); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + dlg = new MeshGui::TaskSegmentationBestFit(mesh); + } + Gui::Control().showDialog(dlg); +} + +bool CmdMeshSegmentationBestFit::isActive(void) +{ + if (Gui::Control().activeDialog()) + return false; + return Gui::Selection().countObjectsOfType + (Mesh::Feature::getClassTypeId()) == 1; +} //-------------------------------------------------------------------------------------- @@ -1749,6 +1784,7 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshFromGeometry()); rcCmdMgr.addCommand(new CmdMeshFromPartShape()); rcCmdMgr.addCommand(new CmdMeshSegmentation()); + rcCmdMgr.addCommand(new CmdMeshSegmentationBestFit); rcCmdMgr.addCommand(new CmdMeshMerge()); rcCmdMgr.addCommand(new CmdMeshScale()); } diff --git a/src/Mod/Mesh/Gui/SegmentationBestFit.cpp b/src/Mod/Mesh/Gui/SegmentationBestFit.cpp new file mode 100644 index 0000000000..4566fee0ac --- /dev/null +++ b/src/Mod/Mesh/Gui/SegmentationBestFit.cpp @@ -0,0 +1,464 @@ +/*************************************************************************** + * Copyright (c) 2018 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 +# include +# include +# include +# include +# include +#endif + +#include "SegmentationBestFit.h" +#include "ui_SegmentationBestFit.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace MeshGui; + +namespace MeshGui { +class PlaneFitParameter : public FitParameter +{ +public: + PlaneFitParameter() {} + virtual ~PlaneFitParameter() {} + virtual std::vector getParameter(FitParameter::Points pts) const { + MeshCore::PlaneFit fit; + fit.AddPoints(pts); + fit.Fit(); + Base::Vector3f base = fit.GetBase(); + Base::Vector3f axis = fit.GetNormal(); + std::vector values; + values.push_back(base.x); + values.push_back(base.y); + values.push_back(base.z); + values.push_back(axis.x); + values.push_back(axis.y); + values.push_back(axis.z); + return values; + } +}; + +class CylinderFitParameter : public FitParameter +{ +public: + CylinderFitParameter() {} + virtual ~CylinderFitParameter() {} + virtual std::vector getParameter(FitParameter::Points pts) const { + std::vector values; + return values; + } +}; + +class SphereFitParameter : public FitParameter +{ +public: + SphereFitParameter() {} + virtual ~SphereFitParameter() {} + virtual std::vector getParameter(FitParameter::Points pts) const { + std::vector values; + return values; + } +}; +} + +ParametersDialog::ParametersDialog(std::vector& val, FitParameter* fitPar, + ParameterList par, Mesh::Feature* mesh, + QWidget* parent) + : QDialog(parent) + , values(val) + , fitParameter(fitPar) + , parameter(par) + , myMesh(mesh) +{ + this->setWindowTitle(tr("Surface fit")); + + QGridLayout *gridLayout; + gridLayout = new QGridLayout(this); + + QGroupBox *groupBox; + groupBox = new QGroupBox(this); + groupBox->setTitle(tr("Parameters")); + gridLayout->addWidget(groupBox, 0, 0, 1, 1); + + QGroupBox *selectBox; + selectBox = new QGroupBox(this); + selectBox->setTitle(tr("Selection")); + gridLayout->addWidget(selectBox, 1, 0, 1, 1); + + QVBoxLayout *selectLayout; + selectLayout = new QVBoxLayout(selectBox); + + QPushButton *regionButton; + regionButton = new QPushButton(this); + regionButton->setText(tr("Region")); + regionButton->setObjectName(QString::fromLatin1("region")); + selectLayout->addWidget(regionButton); + + QPushButton *singleButton; + singleButton = new QPushButton(this); + singleButton->setText(tr("Triangle")); + singleButton->setObjectName(QString::fromLatin1("single")); + selectLayout->addWidget(singleButton); + + QPushButton *clearButton; + clearButton = new QPushButton(this); + clearButton->setText(tr("Clear")); + clearButton->setObjectName(QString::fromLatin1("clear")); + selectLayout->addWidget(clearButton); + + QPushButton *computeButton; + computeButton = new QPushButton(this); + computeButton->setText(tr("Compute")); + computeButton->setObjectName(QString::fromLatin1("compute")); + gridLayout->addWidget(computeButton, 2, 0, 1, 1); + + QDialogButtonBox *buttonBox; + buttonBox = new QDialogButtonBox(this); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + gridLayout->addWidget(buttonBox, 3, 0, 1, 1); + + int index = 0; + QGridLayout *layout; + layout = new QGridLayout(groupBox); + for (auto it : parameter) { + QLabel* label = new QLabel(groupBox); + label->setText(it.first); + layout->addWidget(label, index, 0, 1, 1); + + QDoubleSpinBox* doubleSpinBox = new QDoubleSpinBox(groupBox); + doubleSpinBox->setObjectName(it.first); + doubleSpinBox->setRange(-INT_MAX, INT_MAX); + doubleSpinBox->setValue(it.second); + layout->addWidget(doubleSpinBox, index, 1, 1, 1); + spinBoxes.push_back(doubleSpinBox); + ++index; + } + + QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + QMetaObject::connectSlotsByName(this); + + Gui::SelectionObject obj(mesh); + std::vector sel; + sel.push_back(obj); + meshSel.setObjects(sel); + meshSel.setCheckOnlyPointToUserTriangles(true); + meshSel.setCheckOnlyVisibleTriangles(true); +} + +ParametersDialog::~ParametersDialog() +{ + meshSel.clearSelection(); + delete fitParameter; +} + +void ParametersDialog::on_region_clicked() +{ + meshSel.startSelection(); +} + +void ParametersDialog::on_single_clicked() +{ + meshSel.selectTriangle(); +} + +void ParametersDialog::on_clear_clicked() +{ + meshSel.clearSelection(); +} + +void ParametersDialog::on_compute_clicked() +{ + const Mesh::MeshObject& kernel = myMesh->Mesh.getValue(); + if (kernel.hasSelectedFacets()) { + std::vector facets, points; + kernel.getFacetsFromSelection(facets); + points = kernel.getPointsFromFacets(facets); + MeshCore::MeshPointArray coords = kernel.getKernel().GetPoints(points); + + // Copy points into right format + FitParameter::Points fitpts; + fitpts.insert(fitpts.end(), coords.begin(), coords.end()); + coords.clear(); + + values = fitParameter->getParameter(fitpts); + if (values.size() == spinBoxes.size()) { + for (std::size_t i=0; isetValue(values[i]); + } + } + meshSel.stopSelection(); + meshSel.clearSelection(); + } + else { + QMessageBox::warning(this, tr("No selection"), tr("Before fitting the surface select an area.")); + } +} + +void ParametersDialog::accept() +{ + std::vector v; + for (auto it : spinBoxes) + v.push_back(it->value()); + values = v; + QDialog::accept(); +} + +void ParametersDialog::reject() +{ + values.clear(); + QDialog::reject(); +} + +// ---------------------------------------------------------------------------- + +/* TRANSLATOR MeshGui::SegmentationBestFit */ + +SegmentationBestFit::SegmentationBestFit(Mesh::Feature* mesh, QWidget* parent, Qt::WindowFlags fl) + : QWidget(parent, fl), myMesh(mesh) +{ + ui = new Ui_SegmentationBestFit; + ui->setupUi(this); + ui->numPln->setRange(1, INT_MAX); + ui->numPln->setValue(100); + ui->numCyl->setRange(1, INT_MAX); + ui->numCyl->setValue(100); + ui->numSph->setRange(1, INT_MAX); + ui->numSph->setValue(100); + + Gui::SelectionObject obj(myMesh); + std::vector sel; + sel.push_back(obj); + meshSel.setObjects(sel); +} + +SegmentationBestFit::~SegmentationBestFit() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void SegmentationBestFit::on_planeParameters_clicked() +{ + ParameterList list; + std::vector p = planeParameter; + p.resize(6); + QString base = tr("Base"); + QString axis = tr("Normal"); + QString x = QString::fromLatin1(" x"); + QString y = QString::fromLatin1(" y"); + QString z = QString::fromLatin1(" z"); + list.push_back(std::make_pair(base + x, p[0])); + list.push_back(std::make_pair(base + y, p[1])); + list.push_back(std::make_pair(base + z, p[2])); + list.push_back(std::make_pair(axis + x, p[3])); + list.push_back(std::make_pair(axis + y, p[4])); + list.push_back(std::make_pair(axis + z, p[5])); + + static QPointer dialog = 0; + if (!dialog) + dialog = new ParametersDialog(planeParameter, + new PlaneFitParameter, + list, myMesh, this); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); +} + +void SegmentationBestFit::on_cylinderParameters_clicked() +{ + ParameterList list; + std::vector p = cylinderParameter; + p.resize(7); + QString base = tr("Base"); + QString axis = tr("Axis"); + QString radius = tr("Radius"); + QString x = QString::fromLatin1(" x"); + QString y = QString::fromLatin1(" y"); + QString z = QString::fromLatin1(" z"); + list.push_back(std::make_pair(base + x, p[0])); + list.push_back(std::make_pair(base + y, p[1])); + list.push_back(std::make_pair(base + z, p[2])); + list.push_back(std::make_pair(axis + x, p[3])); + list.push_back(std::make_pair(axis + y, p[4])); + list.push_back(std::make_pair(axis + z, p[5])); + list.push_back(std::make_pair(radius, p[6])); + + static QPointer dialog = 0; + if (!dialog) + dialog = new ParametersDialog(cylinderParameter, + new CylinderFitParameter, + list, myMesh, this); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); +} + +void SegmentationBestFit::on_sphereParameters_clicked() +{ + ParameterList list; + std::vector p = sphereParameter; + p.resize(4); + QString base = tr("Center"); + QString radius = tr("Radius"); + QString x = QString::fromLatin1(" x"); + QString y = QString::fromLatin1(" y"); + QString z = QString::fromLatin1(" z"); + list.push_back(std::make_pair(base + x, p[0])); + list.push_back(std::make_pair(base + y, p[1])); + list.push_back(std::make_pair(base + z, p[2])); + list.push_back(std::make_pair(radius, p[3])); + + static QPointer dialog = 0; + if (!dialog) + dialog = new ParametersDialog(sphereParameter, + new SphereFitParameter, + list, myMesh, this); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); +} + +void SegmentationBestFit::accept() +{ + const Mesh::MeshObject* mesh = myMesh->Mesh.getValuePtr(); + const MeshCore::MeshKernel& kernel = mesh->getKernel(); + + MeshCore::MeshSegmentAlgorithm finder(kernel); + + std::vector segm; + if (ui->groupBoxCyl->isChecked()) { + MeshCore::AbstractSurfaceFit* fitter; + if (cylinderParameter.size() == 7) { + std::vector& p = cylinderParameter; + fitter = new MeshCore::CylinderSurfaceFit( + Base::Vector3f(p[0],p[1],p[2]), + Base::Vector3f(p[3],p[4],p[5]), + p[6]); + } + else { + fitter = new MeshCore::CylinderSurfaceFit; + } + segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + (fitter, kernel, ui->numCyl->value(), ui->tolCyl->value())); + } + if (ui->groupBoxSph->isChecked()) { + MeshCore::AbstractSurfaceFit* fitter; + if (sphereParameter.size() == 4) { + std::vector& p = sphereParameter; + fitter = new MeshCore::SphereSurfaceFit( + Base::Vector3f(p[0],p[1],p[2]), + p[3]); + } + else { + fitter = new MeshCore::SphereSurfaceFit; + } + segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + (fitter, kernel, ui->numSph->value(), ui->tolSph->value())); + } + if (ui->groupBoxPln->isChecked()) { + MeshCore::AbstractSurfaceFit* fitter; + if (planeParameter.size() == 6) { + std::vector& p = planeParameter; + fitter = new MeshCore::PlaneSurfaceFit( + Base::Vector3f(p[0],p[1],p[2]), + Base::Vector3f(p[3],p[4],p[5])); + } + else { + fitter = new MeshCore::PlaneSurfaceFit; + } + segm.push_back(new MeshCore::MeshDistanceGenericSurfaceFitSegment + (fitter, kernel, ui->numPln->value(), ui->tolPln->value())); + } + finder.FindSegments(segm); + + App::Document* document = App::GetApplication().getActiveDocument(); + document->openTransaction("Segmentation"); + + std::string internalname = "Segments_"; + internalname += myMesh->getNameInDocument(); + App::DocumentObjectGroup* group = static_cast(document->addObject + ("App::DocumentObjectGroup", internalname.c_str())); + std::string labelname = "Segments "; + labelname += myMesh->Label.getValue(); + group->Label.setValue(labelname); + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + const std::vector& data = (*it)->GetSegments(); + for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { + Mesh::MeshObject* 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(); + delete segment; + + std::stringstream label; + label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; + feaSegm->Label.setValue(label.str()); + } + delete (*it); + } + document->commitTransaction(); +} + +void SegmentationBestFit::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + QWidget::changeEvent(e); +} + +// --------------------------------------- + +/* TRANSLATOR MeshGui::TaskSegmentationBestFit */ + +TaskSegmentationBestFit::TaskSegmentationBestFit(Mesh::Feature* mesh) +{ + widget = new SegmentationBestFit(mesh); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSegmentationBestFit::~TaskSegmentationBestFit() +{ + // automatically deleted in the sub-class +} + +bool TaskSegmentationBestFit::accept() +{ + widget->accept(); + return true; +} + +#include "moc_SegmentationBestFit.cpp" diff --git a/src/Mod/Mesh/Gui/SegmentationBestFit.h b/src/Mod/Mesh/Gui/SegmentationBestFit.h new file mode 100644 index 0000000000..2bff2026b2 --- /dev/null +++ b/src/Mod/Mesh/Gui/SegmentationBestFit.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (c) 2018 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 MESHGUI_SEGMENTATIONBESTFIT_H +#define MESHGUI_SEGMENTATIONBESTFIT_H + +#include +#include +#include +#include +#include "MeshSelection.h" + +class QDoubleSpinBox; + +// forward declarations +namespace Mesh { class Feature; } + +namespace MeshGui { +class Ui_SegmentationBestFit; + +class FitParameter +{ +public: + typedef std::vector Points; + virtual ~FitParameter() {} + virtual std::vector getParameter(Points) const = 0; +}; + +typedef std::list > ParameterList; +class ParametersDialog : public QDialog +{ + Q_OBJECT + +public: + ParametersDialog(std::vector&, FitParameter*, + ParameterList, Mesh::Feature* mesh, + QWidget* parent=0); + ~ParametersDialog(); + void accept(); + void reject(); + +private Q_SLOTS: + void on_region_clicked(); + void on_single_clicked(); + void on_clear_clicked(); + void on_compute_clicked(); + +private: + std::vector& values; + FitParameter* fitParameter; + ParameterList parameter; + Mesh::Feature* myMesh; + MeshSelection meshSel; + std::vector spinBoxes; +}; + +class MeshGuiExport SegmentationBestFit : public QWidget +{ + Q_OBJECT + +public: + SegmentationBestFit(Mesh::Feature* mesh, QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~SegmentationBestFit(); + void accept(); + +protected: + void changeEvent(QEvent *e); + +private Q_SLOTS: + void on_planeParameters_clicked(); + void on_cylinderParameters_clicked(); + void on_sphereParameters_clicked(); + +private: + std::vector planeParameter; + std::vector cylinderParameter; + std::vector sphereParameter; + Ui_SegmentationBestFit* ui; + Mesh::Feature* myMesh; + MeshSelection meshSel; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskSegmentationBestFit : public Gui::TaskView::TaskDialog +{ +public: + TaskSegmentationBestFit(Mesh::Feature* mesh); + ~TaskSegmentationBestFit(); + +public: + bool accept(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + SegmentationBestFit* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} + +#endif // MESHGUI_SEGMENTATIONBESTFIT_H diff --git a/src/Mod/Mesh/Gui/SegmentationBestFit.ui b/src/Mod/Mesh/Gui/SegmentationBestFit.ui new file mode 100644 index 0000000000..9c09115dfe --- /dev/null +++ b/src/Mod/Mesh/Gui/SegmentationBestFit.ui @@ -0,0 +1,180 @@ + + + MeshGui::SegmentationBestFit + + + + 0 + 0 + 289 + 354 + + + + Mesh segmentation + + + + + + Sphere + + + true + + + + + + Tolerance + + + + + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + Parameters... + + + + + + + + + + Plane + + + true + + + + + + Tolerance + + + + + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + Parameters... + + + + + + + + + + Cylinder + + + true + + + + + + Tolerance + + + + + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + Parameters... + + + + + + + + + + + diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 95f3458f8b..152ba5e1ec 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -213,6 +213,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_Segmentation" + << "Mesh_SegmentationBestFit" << "Separator" << "Mesh_Smoothing" << "Mesh_Scale"