From 7407fe9ff37472c213355d545abedf97f1b7059d Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 21 Sep 2019 01:23:28 +0200 Subject: [PATCH] cross-section of meshes --- src/Mod/Mesh/Gui/Command.cpp | 26 ++ src/Mod/Mesh/Gui/Workbench.cpp | 3 +- src/Mod/MeshPart/Gui/CMakeLists.txt | 5 + src/Mod/MeshPart/Gui/Command.cpp | 41 ++ src/Mod/MeshPart/Gui/CrossSections.cpp | 611 +++++++++++++++++++++++++ src/Mod/MeshPart/Gui/CrossSections.h | 102 +++++ src/Mod/MeshPart/Gui/CrossSections.ui | 192 ++++++++ 7 files changed, 979 insertions(+), 1 deletion(-) create mode 100644 src/Mod/MeshPart/Gui/CrossSections.cpp create mode 100644 src/Mod/MeshPart/Gui/CrossSections.h create mode 100644 src/Mod/MeshPart/Gui/CrossSections.ui diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index b0bf5016f618..0167be084de2 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -1051,6 +1051,31 @@ bool CmdMeshSectionByPlane::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdMeshCrossSections) + +CmdMeshCrossSections::CmdMeshCrossSections() + : Command("Mesh_CrossSections") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Cross-sections..."); + sToolTipText = QT_TR_NOOP("Cross-sections"); + sStatusTip = QT_TR_NOOP("Cross-sections"); +} + +void CmdMeshCrossSections::activated(int) +{ + doCommand(Doc,"import MeshPartGui, FreeCADGui\nFreeCADGui.runCommand('MeshPart_CrossSections')\n"); +} + +bool CmdMeshCrossSections::isActive(void) +{ + return (Gui::Selection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0 && + !Gui::Control().activeDialog()); +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdMeshPolySplit) CmdMeshPolySplit::CmdMeshPolySplit() @@ -1769,6 +1794,7 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshPolyTrim()); rcCmdMgr.addCommand(new CmdMeshTrimByPlane()); rcCmdMgr.addCommand(new CmdMeshSectionByPlane()); + rcCmdMgr.addCommand(new CmdMeshCrossSections()); rcCmdMgr.addCommand(new CmdMeshEvaluation()); rcCmdMgr.addCommand(new CmdMeshEvaluateFacet()); rcCmdMgr.addCommand(new CmdMeshEvaluateSolid()); diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 152ba5e1eca6..b0fc01a795bd 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -195,7 +195,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_PolyTrim" //<< "Mesh_PolySegm" << "Mesh_TrimByPlane" - << "Mesh_SectionByPlane"; + << "Mesh_SectionByPlane" + << "Mesh_CrossSections"; mesh->setCommand("&Meshes"); *mesh << "Mesh_Import" diff --git a/src/Mod/MeshPart/Gui/CMakeLists.txt b/src/Mod/MeshPart/Gui/CMakeLists.txt index b757744ddb28..92ccfdf9ebfc 100644 --- a/src/Mod/MeshPart/Gui/CMakeLists.txt +++ b/src/Mod/MeshPart/Gui/CMakeLists.txt @@ -35,6 +35,7 @@ set(MeshPartGui_LIBS ) set(MeshPartGui_MOC_HDRS + CrossSections.h CurveOnMesh.h TaskCurveOnMesh.h Tessellation.h @@ -43,6 +44,7 @@ fc_wrap_cpp(MeshPartGui_MOC_SRCS ${MeshPartGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${MeshPartGui_MOC_SRCS}) set(MeshPartGui_UIC_SRCS + CrossSections.ui TaskCurveOnMesh.ui Tessellation.ui ) @@ -60,6 +62,9 @@ SET(MeshPartGui_SRCS ${MeshPartGui_UIC_HDRS} AppMeshPartGui.cpp Command.cpp + CrossSections.ui + CrossSections.cpp + CrossSections.h CurveOnMesh.cpp CurveOnMesh.h Resources/MeshPart.qrc diff --git a/src/Mod/MeshPart/Gui/Command.cpp b/src/Mod/MeshPart/Gui/Command.cpp index 3435b67599a5..f59b51597939 100644 --- a/src/Mod/MeshPart/Gui/Command.cpp +++ b/src/Mod/MeshPart/Gui/Command.cpp @@ -42,6 +42,7 @@ #include #include #include "Tessellation.h" +#include "CrossSections.h" #include "TaskCurveOnMesh.h" using namespace std; @@ -263,6 +264,45 @@ bool CmdMeshPartSection::isActive(void) return true; } +//=========================================================================== +// MeshPart_CrossSections +//=========================================================================== +DEF_STD_CMD_A(CmdMeshPartCrossSections) + +CmdMeshPartCrossSections::CmdMeshPartCrossSections() + :Command("MeshPart_CrossSections") +{ + sAppModule = "MeshPart"; + sGroup = QT_TR_NOOP("MeshPart"); + sMenuText = QT_TR_NOOP("Cross-sections..."); + sToolTipText = QT_TR_NOOP("Cross-sections"); + sWhatsThis = "MeshPart_CrossSections"; + sStatusTip = sToolTipText; + //sPixmap = "MeshPart_CrossSections"; +} + +void CmdMeshPartCrossSections::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + std::vector obj = Gui::Selection().getObjectsOfType + (Mesh::Feature::getClassTypeId()); + Base::BoundBox3d bbox; + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { + bbox.Add(static_cast(*it)->Mesh.getBoundingBox()); + } + dlg = new MeshPartGui::TaskCrossSections(bbox); + } + Gui::Control().showDialog(dlg); +} + +bool CmdMeshPartCrossSections::isActive(void) +{ + return (Gui::Selection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0 && + !Gui::Control().activeDialog()); +} + DEF_STD_CMD_A(CmdMeshPartCurveOnMesh) CmdMeshPartCurveOnMesh::CmdMeshPartCurveOnMesh() @@ -307,5 +347,6 @@ void CreateMeshPartCommands(void) rcCmdMgr.addCommand(new CmdMeshPartMesher()); rcCmdMgr.addCommand(new CmdMeshPartTrimByPlane()); rcCmdMgr.addCommand(new CmdMeshPartSection()); + rcCmdMgr.addCommand(new CmdMeshPartCrossSections()); rcCmdMgr.addCommand(new CmdMeshPartCurveOnMesh()); } diff --git a/src/Mod/MeshPart/Gui/CrossSections.cpp b/src/Mod/MeshPart/Gui/CrossSections.cpp new file mode 100644 index 000000000000..9399cac1463d --- /dev/null +++ b/src/Mod/MeshPart/Gui/CrossSections.cpp @@ -0,0 +1,611 @@ +/*************************************************************************** + * Copyright (c) 2019 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ui_CrossSections.h" +#include "CrossSections.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace MeshPartGui; + +namespace MeshPartGui { +class ViewProviderCrossSections : public Gui::ViewProvider +{ +public: + ViewProviderCrossSections() + { + coords = new SoCoordinate3(); + coords->ref(); + planes = new SoLineSet(); + planes->ref(); + SoBaseColor* color = new SoBaseColor(); + color->rgb.setValue(1.0f, 0.447059f, 0.337255f); + SoDrawStyle* style = new SoDrawStyle(); + style->lineWidth.setValue(2.0f); + this->pcRoot->addChild(color); + this->pcRoot->addChild(style); + this->pcRoot->addChild(coords); + this->pcRoot->addChild(planes); + } + ~ViewProviderCrossSections() + { + coords->unref(); + planes->unref(); + } + void updateData(const App::Property*) + { + } + const char* getDefaultDisplayMode() const + { + return ""; + } + std::vector getDisplayModes(void) const + { + return std::vector(); + } + void setCoords(const std::vector& v) + { + coords->point.setNum(v.size()); + SbVec3f* p = coords->point.startEditing(); + for (unsigned int i=0; ipoint.finishEditing(); + unsigned int count = v.size()/5; + planes->numVertices.setNum(count); + int32_t* l = planes->numVertices.startEditing(); + for (unsigned int i=0; inumVertices.finishEditing(); + } + +private: + SoCoordinate3* coords; + SoLineSet* planes; +}; + +class MeshCrossSection { +public: + MeshCrossSection(const MeshCore::MeshKernel& mesh, + const MeshCore::MeshFacetGrid& grid, + double x, double y, double z, + bool connectEdges, double eps) + : mesh(mesh) + , grid(grid) + , x(x) + , y(y) + , z(z) + , connectEdges(connectEdges) + , epsilon(eps) + { + } + std::list section(double d) + { + Mesh::MeshObject::TPolylines polylines; + MeshCore::MeshAlgorithm algo(mesh); + Base::Vector3f p(x*d, y*d, z*d); + Base::Vector3f n(x, y, z); + algo.CutWithPlane(p, n, grid, polylines, epsilon, connectEdges); + + std::list wires; + for (auto it = polylines.begin(); it != polylines.end(); ++it) { + BRepBuilderAPI_MakePolygon mkPoly; + for (auto jt = it->begin(); jt != it->end(); ++jt) { + mkPoly.Add(Base::convertTo(*jt)); + } + + if (mkPoly.IsDone()) + wires.push_back(mkPoly.Wire()); + } + + return wires; + } + +private: + const MeshCore::MeshKernel& mesh; + const MeshCore::MeshFacetGrid& grid; + double x,y,z; + bool connectEdges; + double epsilon; +}; +} + +CrossSections::CrossSections(const Base::BoundBox3d& bb, QWidget* parent, Qt::WindowFlags fl) + : QDialog(parent, fl), bbox(bb) +{ + ui = new Ui_CrossSections(); + ui->setupUi(this); + ui->position->setRange(-DBL_MAX, DBL_MAX); + ui->position->setUnit(Base::Unit::Length); + ui->distance->setRange(0, DBL_MAX); + ui->distance->setUnit(Base::Unit::Length); + ui->spinEpsilon->setMinimum(0.0001); + vp = new ViewProviderCrossSections(); + + Base::Vector3d c = bbox.GetCenter(); + calcPlane(CrossSections::XY, c.z); + ui->position->setValue(c.z); + + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + view = qobject_cast(doc->getActiveView()); + if (view) { + view->getViewer()->addViewProvider(vp); + } +} + +/* + * Destroys the object and frees any allocated resources + */ +CrossSections::~CrossSections() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; + if (view) { + view->getViewer()->removeViewProvider(vp); + } + delete vp; +} + +CrossSections::Plane CrossSections::plane() const +{ + if (ui->xyPlane->isChecked()) + return CrossSections::XY; + else if (ui->xzPlane->isChecked()) + return CrossSections::XZ; + else + return CrossSections::YZ; +} + +void CrossSections::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + else { + QDialog::changeEvent(e); + } +} + +void CrossSections::keyPressEvent(QKeyEvent* ke) +{ + // The cross-sections dialog is embedded into a task panel + // which is a parent widget and will handle the event + ke->ignore(); +} + +void CrossSections::accept() +{ + apply(); + QDialog::accept(); +} + +void CrossSections::apply() +{ + std::vector obj = Gui::Selection(). + getObjectsOfType(Mesh::Feature::getClassTypeId()); + + std::vector d; + if (ui->sectionsBox->isChecked()) + d = getPlanes(); + else + d.push_back(ui->position->value().getValue()); + double a=0,b=0,c=0; + switch (plane()) { + case CrossSections::XY: + c = 1.0; + break; + case CrossSections::XZ: + b = 1.0; + break; + case CrossSections::YZ: + a = 1.0; + break; + } + + bool connectEdges = ui->checkBoxConnect->isChecked(); + double eps = ui->spinEpsilon->value(); + +#if 1 // multi-threaded sections + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { + const Mesh::MeshObject& mesh = static_cast(*it)->Mesh.getValue(); + + MeshCore::MeshKernel kernel(mesh.getKernel()); + kernel.Transform(mesh.getTransform()); + + MeshCore::MeshFacetGrid grid(kernel); + + MeshCrossSection cs(kernel, grid, a, b, c, connectEdges, eps); + QFuture< std::list > future = QtConcurrent::mapped + (d, boost::bind(&MeshCrossSection::section, &cs, _1)); + future.waitForFinished(); + + TopoDS_Compound comp; + BRep_Builder builder; + builder.MakeCompound(comp); + + for (auto ft = future.begin(); ft != future.end(); ++ft) { + const std::list& w = *ft; + for (std::list::const_iterator wt = w.begin(); wt != w.end(); ++wt) { + if (!wt->IsNull()) + builder.Add(comp, *wt); + } + } + + App::Document* doc = (*it)->getDocument(); + std::string s = (*it)->getNameInDocument(); + s += "_cs"; + Part::Feature* section = static_cast + (doc->addObject("Part::Feature",s.c_str())); + section->Shape.setValue(comp); + section->purgeTouched(); + } +#else + try { + Gui::Command::runCommand(Gui::Command::App, "import Mesh, Part\n"); + Gui::Command::runCommand(Gui::Command::App, "from FreeCAD import Base\n"); + + std::stringstream str; + str << "["; + for (std::vector::iterator jt = d.begin(); jt != d.end(); ++jt) { + double d = *jt; + str << "(" + << "App.Vector(" << a*d << ", " << b*d << ", " << c*d << "), " + << "App.Vector(" << a << ", " << b << ", " << c << ")" + << "), "; + } + str << "]"; + + QString planes = QString::fromStdString(str.str()); + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { + App::Document* doc = (*it)->getDocument(); + std::string s = (*it)->getNameInDocument(); + s += "_cs"; + Gui::Command::runCommand(Gui::Command::App, QString::fromLatin1( + "points=FreeCAD.getDocument(\"%1\").%2.Mesh.crossSections(%3, %4, %5)\n" + "wires=[]\n" + "for i in points:\n" + " wires.extend([Part.makePolygon(j) for j in i])\n") + .arg(QLatin1String(doc->getName())) + .arg(QLatin1String((*it)->getNameInDocument())) + .arg(planes) + .arg(eps) + .arg(connectEdges ? QLatin1String("True") : QLatin1String("False")) + .toLatin1()); + + Gui::Command::runCommand(Gui::Command::App, QString::fromLatin1( + "comp=Part.Compound(wires)\n" + "slice=FreeCAD.getDocument(\"%1\").addObject(\"Part::Feature\",\"%2\")\n" + "slice.Shape=comp\n" + "slice.purgeTouched()\n" + "del slice,comp,wires,points") + .arg(QLatin1String(doc->getName())) + .arg(QLatin1String(s.c_str())).toLatin1()); + } + } + catch (const Base::Exception& e) { + QMessageBox::critical(this, tr("Failure"), QString::fromLatin1(e.what())); + } +#endif +} + +void CrossSections::on_xyPlane_clicked() +{ + Base::Vector3d c = bbox.GetCenter(); + ui->position->setValue(c.z); + if (!ui->sectionsBox->isChecked()) { + calcPlane(CrossSections::XY, c.z); + } + else { + double dist = bbox.LengthZ() / ui->countSections->value(); + if (!ui->checkBothSides->isChecked()) + dist *= 0.5f; + ui->distance->setValue(dist); + calcPlanes(CrossSections::XY); + } +} + +void CrossSections::on_xzPlane_clicked() +{ + Base::Vector3d c = bbox.GetCenter(); + ui->position->setValue(c.y); + if (!ui->sectionsBox->isChecked()) { + calcPlane(CrossSections::XZ, c.y); + } + else { + double dist = bbox.LengthY() / ui->countSections->value(); + if (!ui->checkBothSides->isChecked()) + dist *= 0.5f; + ui->distance->setValue(dist); + calcPlanes(CrossSections::XZ); + } +} + +void CrossSections::on_yzPlane_clicked() +{ + Base::Vector3d c = bbox.GetCenter(); + ui->position->setValue(c.x); + if (!ui->sectionsBox->isChecked()) { + calcPlane(CrossSections::YZ, c.x); + } + else { + double dist = bbox.LengthX() / ui->countSections->value(); + if (!ui->checkBothSides->isChecked()) + dist *= 0.5f; + ui->distance->setValue(dist); + calcPlanes(CrossSections::YZ); + } +} + +void CrossSections::on_position_valueChanged(double v) +{ + if (!ui->sectionsBox->isChecked()) { + calcPlane(plane(), v); + } + else { + calcPlanes(plane()); + } +} + +void CrossSections::on_sectionsBox_toggled(bool b) +{ + if (b) { + on_countSections_valueChanged(ui->countSections->value()); + } + else { + CrossSections::Plane type = plane(); + Base::Vector3d c = bbox.GetCenter(); + double value = 0; + switch (type) { + case CrossSections::XY: + value = c.z; + break; + case CrossSections::XZ: + value = c.y; + break; + case CrossSections::YZ: + value = c.x; + break; + } + + ui->position->setValue(value); + calcPlane(type, value); + } +} + +void CrossSections::on_checkBothSides_toggled(bool b) +{ + double d = ui->distance->value().getValue(); + d = b ? 2.0 * d : 0.5 * d; + ui->distance->setValue(d); + calcPlanes(plane()); +} + +void CrossSections::on_countSections_valueChanged(int v) +{ + CrossSections::Plane type = plane(); + double dist = 0; + switch (type) { + case CrossSections::XY: + dist = bbox.LengthZ() / v; + break; + case CrossSections::XZ: + dist = bbox.LengthY() / v; + break; + case CrossSections::YZ: + dist = bbox.LengthX() / v; + break; + } + if (!ui->checkBothSides->isChecked()) + dist *= 0.5f; + ui->distance->setValue(dist); + calcPlanes(type); +} + +void CrossSections::on_distance_valueChanged(double) +{ + calcPlanes(plane()); +} + +void CrossSections::calcPlane(Plane type, double pos) +{ + double bound[4]; + switch (type) { + case XY: + bound[0] = bbox.MinX; + bound[1] = bbox.MaxX; + bound[2] = bbox.MinY; + bound[3] = bbox.MaxY; + break; + case XZ: + bound[0] = bbox.MinX; + bound[1] = bbox.MaxX; + bound[2] = bbox.MinZ; + bound[3] = bbox.MaxZ; + break; + case YZ: + bound[0] = bbox.MinY; + bound[1] = bbox.MaxY; + bound[2] = bbox.MinZ; + bound[3] = bbox.MaxZ; + break; + } + + std::vector d; + d.push_back(pos); + makePlanes(type, d, bound); +} + +void CrossSections::calcPlanes(Plane type) +{ + double bound[4]; + switch (type) { + case XY: + bound[0] = bbox.MinX; + bound[1] = bbox.MaxX; + bound[2] = bbox.MinY; + bound[3] = bbox.MaxY; + break; + case XZ: + bound[0] = bbox.MinX; + bound[1] = bbox.MaxX; + bound[2] = bbox.MinZ; + bound[3] = bbox.MaxZ; + break; + case YZ: + bound[0] = bbox.MinY; + bound[1] = bbox.MaxY; + bound[2] = bbox.MinZ; + bound[3] = bbox.MaxZ; + break; + } + + std::vector d = getPlanes(); + makePlanes(type, d, bound); +} + +std::vector CrossSections::getPlanes() const +{ + int count = ui->countSections->value(); + double pos = ui->position->value().getValue(); + double stp = ui->distance->value().getValue(); + bool both = ui->checkBothSides->isChecked(); + + std::vector d; + if (both) { + double start = pos-0.5f*(count-1)*stp; + for (int i=0; i& d, double bound[4]) +{ + std::vector points; + for (std::vector::const_iterator it = d.begin(); it != d.end(); ++it) { + Base::Vector3f v[4]; + switch (type) { + case XY: + v[0].Set(bound[0],bound[2],*it); + v[1].Set(bound[1],bound[2],*it); + v[2].Set(bound[1],bound[3],*it); + v[3].Set(bound[0],bound[3],*it); + break; + case XZ: + v[0].Set(bound[0],*it,bound[2]); + v[1].Set(bound[1],*it,bound[2]); + v[2].Set(bound[1],*it,bound[3]); + v[3].Set(bound[0],*it,bound[3]); + break; + case YZ: + v[0].Set(*it,bound[0],bound[2]); + v[1].Set(*it,bound[1],bound[2]); + v[2].Set(*it,bound[1],bound[3]); + v[3].Set(*it,bound[0],bound[3]); + break; + } + + points.push_back(v[0]); + points.push_back(v[1]); + points.push_back(v[2]); + points.push_back(v[3]); + points.push_back(v[0]); + } + vp->setCoords(points); +} + +// --------------------------------------- + +TaskCrossSections::TaskCrossSections(const Base::BoundBox3d& bb) +{ + widget = new CrossSections(bb); + taskbox = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("Part_CrossSections"), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskCrossSections::~TaskCrossSections() +{ + // automatically deleted in the sub-class +} + +bool TaskCrossSections::accept() +{ + widget->accept(); + return (widget->result() == QDialog::Accepted); +} + +void TaskCrossSections::clicked(int id) +{ + if (id == QDialogButtonBox::Apply) { + widget->apply(); + } +} + +#include "moc_CrossSections.cpp" diff --git a/src/Mod/MeshPart/Gui/CrossSections.h b/src/Mod/MeshPart/Gui/CrossSections.h new file mode 100644 index 000000000000..8cf044f42430 --- /dev/null +++ b/src/Mod/MeshPart/Gui/CrossSections.h @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2019 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 MESHPARTGUI_CROSSSECTIONS_H +#define MESHPARTGUI_CROSSSECTIONS_H + +#include +#include +#include +#include +#include + +namespace Gui { +class View3DInventor; +} + +namespace MeshPartGui { + +class ViewProviderCrossSections; +class Ui_CrossSections; +class CrossSections : public QDialog +{ + Q_OBJECT + + enum Plane { XY, XZ, YZ }; + +public: + CrossSections(const Base::BoundBox3d& bb, QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~CrossSections(); + void accept(); + void apply(); + +protected: + void changeEvent(QEvent *e); + void keyPressEvent(QKeyEvent*); + +private Q_SLOTS: + void on_xyPlane_clicked(); + void on_xzPlane_clicked(); + void on_yzPlane_clicked(); + void on_position_valueChanged(double); + void on_distance_valueChanged(double); + void on_countSections_valueChanged(int); + void on_checkBothSides_toggled(bool); + void on_sectionsBox_toggled(bool); + +private: + std::vector getPlanes() const; + void calcPlane(Plane, double); + void calcPlanes(Plane/*, double, bool, int*/); + void makePlanes(Plane, const std::vector&, double[4]); + Plane plane() const; + +private: + Ui_CrossSections* ui; + Base::BoundBox3d bbox; + ViewProviderCrossSections* vp; + QPointer view; +}; + +class TaskCrossSections : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskCrossSections(const Base::BoundBox3d& bb); + ~TaskCrossSections(); + +public: + bool accept(); + void clicked(int id); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel; } + +private: + CrossSections* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} // namespace MeshPartGui + +#endif // MESHPARTGUI_CROSSSECTIONS_H diff --git a/src/Mod/MeshPart/Gui/CrossSections.ui b/src/Mod/MeshPart/Gui/CrossSections.ui new file mode 100644 index 000000000000..b26ac273a6c6 --- /dev/null +++ b/src/Mod/MeshPart/Gui/CrossSections.ui @@ -0,0 +1,192 @@ + + + MeshPartGui::CrossSections + + + + 0 + 0 + 309 + 269 + + + + Cross sections + + + + + + Guiding plane + + + + + + XY + + + true + + + + + + + XZ + + + + + + + YZ + + + + + + + + + Position: + + + + + + + mm + + + + + + + + + + + + Sections + + + true + + + false + + + + + + On both sides + + + + + + + + + Count + + + + + + + 1 + + + 2000000 + + + + + + + Distance: + + + + + + + mm + + + + + + + + + + + + Options + + + + + + Connect edges if distance less than + + + + + + + false + + + 4 + + + 0.020000000000000 + + + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + xyPlane + xzPlane + yzPlane + position + sectionsBox + checkBothSides + countSections + distance + + + + + checkBoxConnect + toggled(bool) + spinEpsilon + setEnabled(bool) + + + 75 + 230 + + + 254 + 231 + + + + +