MeshPart: add gmsh as another option to create mesh from shape

This commit is contained in:
wmayer
2020-02-28 21:15:17 +01:00
parent 549b424e1f
commit 1cb4625bfd
4 changed files with 210 additions and 69 deletions

View File

@@ -32,6 +32,7 @@
#include "RemeshGmsh.h"
#include "ui_RemeshGmsh.h"
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <Base/Tools.h>
#include <App/Application.h>
@@ -115,39 +116,6 @@ void GmshWidget::changeEvent(QEvent *e)
QWidget::changeEvent(e);
}
#if 0 // this is for meshing a CAD shape see gmshtools.py write_geo
// geo file for meshing with Gmsh meshing software created by FreeCAD
// open brep geometry
Merge "/tmp/fcfem_f1enjjfa/Part__Feature_Geometry.brep";
// Characteristic Length
// no boundary layer settings for this mesh
// min, max Characteristic Length
Mesh.CharacteristicLengthMax = 1e+22;
Mesh.CharacteristicLengthMin = 0.0;
// optimize the mesh
Mesh.Optimize = 1;
Mesh.OptimizeNetgen = 0;
Mesh.HighOrderOptimize = 0; // for more HighOrderOptimize parameter check http://gmsh.info/doc/texinfo/gmsh.html
// mesh order
Mesh.ElementOrder = 2;
Mesh.SecondOrderLinear = 1; // Second order nodes are created by linear interpolation instead by curvilinear
// mesh algorithm, only a few algorithms are usable with 3D boundary layer generation
// 2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad)
Mesh.Algorithm = 2;
// 3D mesh algorithm (1=Delaunay, 2=New Delaunay, 4=Frontal, 5=Frontal Delaunay, 6=Frontal Hex, 7=MMG3D, 9=R-tree)
Mesh.Algorithm3D = 1;
// meshing
Geometry.Tolerance = 1e-06; // set geometrical tolerance (also used for merging nodes)
Mesh 2;
Coherence Mesh; // Remove duplicate vertices
#endif
bool GmshWidget::writeProject(QString& inpFile, QString& outFile)
{
Q_UNUSED(inpFile)
@@ -183,6 +151,11 @@ double GmshWidget::getMinSize() const
void GmshWidget::accept()
{
if (d->gmsh.state() == QProcess::Running) {
Base::Console().Warning("Cannot start gmsh because it's already running\n");
return;
}
QString inpFile;
QString outFile;
if (writeProject(inpFile, outFile)) {
@@ -311,38 +284,6 @@ RemeshGmsh::~RemeshGmsh()
{
}
#if 0 // this is for meshing a CAD shape see gmshtools.py write_geo
// geo file for meshing with Gmsh meshing software created by FreeCAD
// open brep geometry
Merge "/tmp/fcfem_f1enjjfa/Part__Feature_Geometry.brep";
// Characteristic Length
// no boundary layer settings for this mesh
// min, max Characteristic Length
Mesh.CharacteristicLengthMax = 1e+22;
Mesh.CharacteristicLengthMin = 0.0;
// optimize the mesh
Mesh.Optimize = 1;
Mesh.OptimizeNetgen = 0;
Mesh.HighOrderOptimize = 0; // for more HighOrderOptimize parameter check http://gmsh.info/doc/texinfo/gmsh.html
// mesh order
Mesh.ElementOrder = 2;
Mesh.SecondOrderLinear = 1; // Second order nodes are created by linear interpolation instead by curvilinear
// mesh algorithm, only a few algorithms are usable with 3D boundary layer generation
// 2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad)
Mesh.Algorithm = 2;
// 3D mesh algorithm (1=Delaunay, 2=New Delaunay, 4=Frontal, 5=Frontal Delaunay, 6=Frontal Hex, 7=MMG3D, 9=R-tree)
Mesh.Algorithm3D = 1;
// meshing
Geometry.Tolerance = 1e-06; // set geometrical tolerance (also used for merging nodes)
Mesh 2;
Coherence Mesh; // Remove duplicate vertices
#endif
bool RemeshGmsh::writeProject(QString& inpFile, QString& outFile)
{
if (!d->mesh.expired()) {

View File

@@ -36,11 +36,14 @@
#include <App/Document.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Gui/Document.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Selection.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>
#include <Mod/Mesh/App/Mesh.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Mesh/Gui/ViewProvider.h>
#include <Mod/Part/Gui/ViewProvider.h>
@@ -53,6 +56,10 @@ Tessellation::Tessellation(QWidget* parent)
: QWidget(parent), ui(new Ui_Tessellation)
{
ui->setupUi(this);
gmsh = new Mesh2ShapeGmsh(this);
connect(gmsh, SIGNAL(processed()), this, SLOT(gmshProcessed()));
ui->stackedWidget->addTab(gmsh, tr("gmsh"));
ParameterGrp::handle handle = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Mesh/Meshing/Standard");
@@ -85,7 +92,8 @@ Tessellation::Tessellation(QWidget* parent)
Gui::Command::doCommand(Gui::Command::Doc, "import MeshPart");
}
catch (...) {
ui->stackedWidget->setDisabled(true);
ui->stackedWidget->setTabEnabled(Mefisto, false);
ui->stackedWidget->setTabEnabled(Netgen, false);
}
}
@@ -154,6 +162,13 @@ void Tessellation::on_checkQuadDominated_toggled(bool on)
ui->checkSecondOrder->setChecked(false);
}
void Tessellation::gmshProcessed()
{
bool doClose = !ui->checkBoxDontQuit->isChecked();
if (doClose)
Gui::Control().reject();
}
void Tessellation::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
@@ -233,12 +248,24 @@ bool Tessellation::accept()
return false;
}
bool doClose = !ui->checkBoxDontQuit->isChecked();
int method = ui->stackedWidget->currentIndex();
// For gmsh the workflow is very different because it uses an executable
// and therefore things are asynchronous
if (method == Gmsh) {
std::list<App::SubObjectT> obj;
for (const auto &info : shapeObjects) {
obj.emplace_back(info.obj, info.subname.c_str());
}
gmsh->process(activeDoc, obj);
return false;
}
try {
QString objname, label, subname;
Gui::WaitCursor wc;
int method = ui->stackedWidget->currentIndex();
// Save parameters
if (method == Standard) {
ParameterGrp::handle handle = App::GetApplication().GetParameterGroupByPath
@@ -380,6 +407,137 @@ bool Tessellation::accept()
Base::Console().Error(e.what());
}
return doClose;
}
// ---------------------------------------
class Mesh2ShapeGmsh::Private {
public:
std::string label;
std::list<App::SubObjectT> shapes;
App::DocumentT doc;
std::string cadFile;
std::string stlFile;
std::string geoFile;
};
Mesh2ShapeGmsh::Mesh2ShapeGmsh(QWidget* parent, Qt::WindowFlags fl)
: GmshWidget(parent, fl)
, d(new Private())
{
d->cadFile = App::Application::getTempFileName() + "mesh.brep";
d->stlFile = App::Application::getTempFileName() + "mesh.stl";
d->geoFile = App::Application::getTempFileName() + "mesh.geo";
}
Mesh2ShapeGmsh::~Mesh2ShapeGmsh()
{
}
void Mesh2ShapeGmsh::process(App::Document* doc, const std::list<App::SubObjectT>& objs)
{
d->doc = doc;
d->shapes = objs;
doc->openTransaction("Meshing");
accept();
}
bool Mesh2ShapeGmsh::writeProject(QString& inpFile, QString& outFile)
{
if (!d->shapes.empty()) {
App::SubObjectT sub = d->shapes.front();
d->shapes.pop_front();
App::DocumentObject* part = sub.getObject();
if (part) {
Part::TopoShape shape = Part::Feature::getTopoShape(part, sub.getSubName().c_str());
shape.exportBrep(d->cadFile.c_str());
d->label = part->Label.getStrValue() + " (Meshed)";
// Parameters
int algorithm = meshingAlgorithm();
double maxSize = getMaxSize();
if (maxSize == 0.0)
maxSize = 1.0e22;
double minSize = getMinSize();
// gmsh geo file
Base::FileInfo geo(d->geoFile);
Base::ofstream geoOut(geo, std::ios::out);
geoOut << "// geo file for meshing with Gmsh meshing software created by FreeCAD\n"
<< "// open brep geometry\n"
<< "Merge \"" << d->cadFile << "\";\n\n"
<< "// Characteristic Length\n"
<< "// no boundary layer settings for this mesh\n"
<< "// min, max Characteristic Length\n"
<< "Mesh.CharacteristicLengthMax = " << maxSize << ";\n"
<< "Mesh.CharacteristicLengthMin = " << minSize << ";\n\n"
<< "// optimize the mesh\n"
<< "Mesh.Optimize = 1;\n"
<< "Mesh.OptimizeNetgen = 0;\n"
<< "// for more HighOrderOptimize parameter check http://gmsh.info/doc/texinfo/gmsh.html\n"
<< "Mesh.HighOrderOptimize = 0;\n\n"
<< "// mesh order\n"
<< "Mesh.ElementOrder = 2;\n"
<< "// Second order nodes are created by linear interpolation instead by curvilinear\n"
<< "Mesh.SecondOrderLinear = 1;\n\n"
<< "// mesh algorithm, only a few algorithms are usable with 3D boundary layer generation\n"
<< "// 2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=BAMG, 8=DelQuad)\n"
<< "Mesh.Algorithm = " << algorithm << ";\n"
<< "// 3D mesh algorithm (1=Delaunay, 2=New Delaunay, 4=Frontal, 5=Frontal Delaunay, 6=Frontal Hex, 7=MMG3D, 9=R-tree)\n"
<< "Mesh.Algorithm3D = 1;\n\n"
<< "// meshing\n"
<< "// set geometrical tolerance (also used for merging nodes)\n"
<< "Geometry.Tolerance = 1e-06;\n"
<< "Mesh 2;\n"
<< "Coherence Mesh; // Remove duplicate vertices\n";
geoOut.close();
inpFile = QString::fromUtf8(d->geoFile.c_str());
outFile = QString::fromUtf8(d->stlFile.c_str());
return true;
}
}
else {
App::Document* doc = d->doc.getDocument();
if (doc)
doc->commitTransaction();
Q_EMIT processed();
}
return false;
}
bool Mesh2ShapeGmsh::loadOutput()
{
App::Document* doc = d->doc.getDocument();
if (!doc)
return false;
// Now read-in the mesh
Base::FileInfo stl(d->stlFile);
Base::FileInfo geo(d->geoFile);
Mesh::MeshObject kernel;
MeshCore::MeshInput input(kernel.getKernel());
Base::ifstream stlIn(stl, std::ios::in | std::ios::binary);
input.LoadBinarySTL(stlIn);
stlIn.close();
kernel.harmonizeNormals();
Mesh::Feature* fea = static_cast<Mesh::Feature*>(doc->addObject("Mesh::Feature", "Mesh"));
fea->Label.setValue(d->label);
fea->Mesh.setValue(kernel.getKernel());
stl.deleteFile();
geo.deleteFile();
// process next object
accept();
return true;
}

View File

@@ -28,10 +28,42 @@
#include <Gui/TaskView/TaskView.h>
#include <Gui/Selection.h>
#include <App/DocumentObserver.h>
#include <Mod/Mesh/Gui/RemeshGmsh.h>
#include <memory>
#include <QPointer>
namespace App {
class Document;
class SubObjectT;
}
namespace MeshPartGui {
/**
* Non-modal dialog to mesh a shape.
* @author Werner Mayer
*/
class MeshGuiExport Mesh2ShapeGmsh : public MeshGui::GmshWidget
{
Q_OBJECT
public:
Mesh2ShapeGmsh(QWidget* parent = 0, Qt::WindowFlags fl = 0);
~Mesh2ShapeGmsh();
void process(App::Document* doc, const std::list<App::SubObjectT>&);
Q_SIGNALS:
void processed();
protected:
virtual bool writeProject(QString& inpFile, QString& outFile);
virtual bool loadOutput();
private:
class Private;
std::unique_ptr<Private> d;
};
class Ui_Tessellation;
class Tessellation : public QWidget
{
@@ -40,7 +72,8 @@ class Tessellation : public QWidget
enum {
Standard,
Mefisto,
Netgen
Netgen,
Gmsh
};
public:
@@ -57,9 +90,11 @@ private Q_SLOTS:
void on_comboFineness_currentIndexChanged(int);
void on_checkSecondOrder_toggled(bool);
void on_checkQuadDominated_toggled(bool);
void gmshProcessed();
private:
QString document;
QPointer<Mesh2ShapeGmsh> gmsh;
std::unique_ptr<Ui_Tessellation> ui;
};

View File

@@ -416,6 +416,13 @@ A value in the range of 0.2-10.</string>
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBoxDontQuit">
<property name="text">
<string>Leave panel open</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>