// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include "SegmentationManual.h" #include "ui_SegmentationManual.h" using namespace ReverseEngineeringGui; SegmentationManual::SegmentationManual(QWidget* parent, Qt::WindowFlags fl) : QWidget(parent, fl) , ui(new Ui_SegmentationManual) { ui->setupUi(this); setupConnections(); ui->spSelectComp->setRange(1, std::numeric_limits::max()); ui->spSelectComp->setValue(10); Gui::Selection().clearSelection(); meshSel.setCheckOnlyVisibleTriangles(ui->visibleTriangles->isChecked()); meshSel.setCheckOnlyPointToUserTriangles(ui->screenTriangles->isChecked()); meshSel.setEnabledViewerSelection(false); } SegmentationManual::~SegmentationManual() = default; void SegmentationManual::setupConnections() { connect(ui->selectRegion, &QPushButton::clicked, this, &SegmentationManual::onSelectRegionClicked); connect(ui->selectAll, &QPushButton::clicked, this, &SegmentationManual::onSelectAllClicked); connect( ui->selectComponents, &QPushButton::clicked, this, &SegmentationManual::onSelectComponentsClicked ); connect(ui->selectTriangle, &QPushButton::clicked, this, &SegmentationManual::onSelectTriangleClicked); connect(ui->deselectAll, &QPushButton::clicked, this, &SegmentationManual::onDeselectAllClicked); connect(ui->visibleTriangles, &QCheckBox::toggled, this, &SegmentationManual::onVisibleTrianglesToggled); connect(ui->screenTriangles, &QCheckBox::toggled, this, &SegmentationManual::onScreenTrianglesToggled); connect(ui->cbSelectComp, &QCheckBox::toggled, this, &SegmentationManual::onSelectCompToggled); connect(ui->planeDetect, &QPushButton::clicked, this, &SegmentationManual::onPlaneDetectClicked); connect(ui->cylinderDetect, &QPushButton::clicked, this, &SegmentationManual::onCylinderDetectClicked); connect(ui->sphereDetect, &QPushButton::clicked, this, &SegmentationManual::onSphereDetectClicked); } void SegmentationManual::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } QWidget::changeEvent(e); } void SegmentationManual::onSelectRegionClicked() { meshSel.startSelection(); } void SegmentationManual::onSelectAllClicked() { // select the complete meshes meshSel.fullSelection(); } void SegmentationManual::onDeselectAllClicked() { // deselect all meshes meshSel.clearSelection(); } void SegmentationManual::onSelectComponentsClicked() { // select components up to a certain size int size = ui->spSelectComp->value(); meshSel.selectComponent(size); } void SegmentationManual::onVisibleTrianglesToggled(bool on) { meshSel.setCheckOnlyVisibleTriangles(on); } void SegmentationManual::onScreenTrianglesToggled(bool on) { meshSel.setCheckOnlyPointToUserTriangles(on); } void SegmentationManual::onSelectCompToggled(bool on) { meshSel.setAddComponentOnClick(on); } class SegmentationManual::Private { public: static void findGeometry( int minFaces, double tolerance, std::function&, const std::vector& )> fitFunc ) { Gui::Document* gdoc = Gui::Application::Instance->activeDocument(); if (!gdoc) { return; } App::Document* adoc = gdoc->getDocument(); std::vector meshes = adoc->getObjectsOfType(); for (auto it : meshes) { MeshGui::ViewProviderMesh* vpm = static_cast( gdoc->getViewProvider(it) ); const Mesh::MeshObject& mesh = it->Mesh.getValue(); if (mesh.hasSelectedFacets()) { const MeshCore::MeshKernel& kernel = mesh.getKernel(); std::vector facets; std::vector vertexes; mesh.getFacetsFromSelection(facets); vertexes = mesh.getPointsFromFacets(facets); MeshCore::MeshPointArray coords = kernel.GetPoints(vertexes); std::vector points, normals; normals = kernel.GetFacetNormals(facets); points.insert(points.end(), coords.begin(), coords.end()); coords.clear(); MeshCore::AbstractSurfaceFit* surfFit = fitFunc(points, normals); if (surfFit) { MeshCore::MeshSegmentAlgorithm finder(kernel); std::vector segm; segm.emplace_back( std::make_shared( surfFit, kernel, minFaces, tolerance ) ); finder.FindSegments(segm); for (const auto& segmIt : segm) { const std::vector& data = segmIt->GetSegments(); for (const auto& dataIt : data) { vpm->addSelection(dataIt); } } } } } } }; void SegmentationManual::onPlaneDetectClicked() { auto func = [=](const std::vector& points, const std::vector& normal) -> MeshCore::AbstractSurfaceFit* { Q_UNUSED(normal) MeshCore::PlaneFit fit; fit.AddPoints(points); if (fit.Fit() < std::numeric_limits::max()) { Base::Vector3f base = fit.GetBase(); Base::Vector3f axis = fit.GetNormal(); return new MeshCore::PlaneSurfaceFit(base, axis); } return nullptr; }; Private::findGeometry(ui->numPln->value(), ui->tolPln->value(), func); } void SegmentationManual::onCylinderDetectClicked() { auto func = [=](const std::vector& points, const std::vector& normal) -> MeshCore::AbstractSurfaceFit* { Q_UNUSED(normal) MeshCore::CylinderFit fit; fit.AddPoints(points); if (!normal.empty()) { Base::Vector3f base = fit.GetGravity(); Base::Vector3f axis = fit.GetInitialAxisFromNormals(normal); fit.SetInitialValues(base, axis); } if (fit.Fit() < std::numeric_limits::max()) { Base::Vector3f base = fit.GetBase(); Base::Vector3f axis = fit.GetAxis(); float radius = fit.GetRadius(); return new MeshCore::CylinderSurfaceFit(base, axis, radius); } return nullptr; }; Private::findGeometry(ui->numCyl->value(), ui->tolCyl->value(), func); } void SegmentationManual::onSphereDetectClicked() { auto func = [=](const std::vector& points, const std::vector& normal) -> MeshCore::AbstractSurfaceFit* { Q_UNUSED(normal) MeshCore::SphereFit fit; fit.AddPoints(points); if (fit.Fit() < std::numeric_limits::max()) { Base::Vector3f base = fit.GetCenter(); float radius = fit.GetRadius(); return new MeshCore::SphereSurfaceFit(base, radius); } return nullptr; }; Private::findGeometry(ui->numSph->value(), ui->tolSph->value(), func); } void SegmentationManual::createSegment() { Gui::Document* gdoc = Gui::Application::Instance->activeDocument(); if (!gdoc) { return; } // delete all selected faces App::Document* adoc = gdoc->getDocument(); gdoc->openCommand(QT_TRANSLATE_NOOP("Command", "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)); auto* feaSegm = adoc->addObject("Segment"); Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); feaMesh->swap(*segment); feaMesh->clearFacetSelection(); feaSegm->Mesh.finishEditing(); if (ui->checkBoxHideSegm->isChecked()) { feaSegm->Visibility.setValue(false); } if (ui->checkBoxCutSegm->isChecked()) { Mesh::MeshObject* editmesh = it->Mesh.startEditing(); editmesh->deleteFacets(facets); it->Mesh.finishEditing(); } } } if (!selected) { gdoc->abortCommand(); } else { gdoc->commitCommand(); } meshSel.clearSelection(); } void SegmentationManual::onSelectTriangleClicked() { 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(); addTaskBox(widget, false); } 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"