diff --git a/src/Mod/Fem/Gui/Resources/ui/MeshGmsh.ui b/src/Mod/Fem/Gui/Resources/ui/MeshGmsh.ui
index a8ae88a12b..be66475ca2 100644
--- a/src/Mod/Fem/Gui/Resources/ui/MeshGmsh.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/MeshGmsh.ui
@@ -49,38 +49,35 @@
-
-
-
-
- 0
- 0
-
-
-
-
- 80
- 20
-
-
-
- 0 mm
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 1.000000000000000
-
-
- 1000000000.000000000000000
+
+
+ true
mm
-
- 2
+
+
+ 100
+ 20
+
-
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+ 0.000000000000000
+
+
+ 1000000000000000000000.000000000000000
+
+
+ 1.000000000000000
+
+
0.000000000000000
@@ -93,38 +90,35 @@
-
-
-
-
- 0
- 0
-
-
-
-
- 80
- 20
-
-
-
- 0 mm
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 1.000000000000000
-
-
- 1000000000.000000000000000
+
+
+ true
mm
-
- 2
+
+
+ 100
+ 20
+
-
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+ 0.000000000000000
+
+
+ 1000000000000000000000.000000000000000
+
+
+ 1.000000000000000
+
+
0.000000000000000
@@ -219,9 +213,9 @@
- Gui::InputField
- QLineEdit
-
+ Gui::QuantitySpinBox
+ QWidget
+
diff --git a/src/Mod/Fem/femmesh/gmshtools.py b/src/Mod/Fem/femmesh/gmshtools.py
index bbe2bf50f9..0a9bd5419f 100644
--- a/src/Mod/Fem/femmesh/gmshtools.py
+++ b/src/Mod/Fem/femmesh/gmshtools.py
@@ -46,17 +46,25 @@ class GmshError(Exception):
class GmshTools:
+
+ name = "Gmsh"
+
def __init__(self, gmsh_mesh_obj, analysis=None):
# mesh obj
self.mesh_obj = gmsh_mesh_obj
+ self.process = None
# analysis
if analysis:
self.analysis = analysis
else:
self.analysis = None
+ self.load_properties()
+ self.error = False
+
+ def load_properties(self):
# part to mesh
self.part_obj = self.mesh_obj.Shape
@@ -186,7 +194,6 @@ class GmshTools:
self.temp_file_geo = ""
self.mesh_name = ""
self.gmsh_bin = ""
- self.error = False
def update_mesh_data(self):
self.start_logs()
@@ -199,6 +206,27 @@ class GmshTools:
self.write_part_file()
self.write_geo()
+ def compute(self):
+ self.load_properties()
+ self.update_mesh_data()
+ self.get_tmp_file_paths()
+ self.get_gmsh_command()
+ self.write_gmsh_input_files()
+
+ command_list = [self.gmsh_bin, "-", self.temp_file_geo]
+ self.process = subprocess.Popen(
+ command_list, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+
+ out, err = self.process.communicate()
+ if self.process.returncode != 0:
+ raise RuntimeError(err.decode("utf-8"))
+
+ return True
+
+ def update_properties(self):
+ self.mesh_obj.FemMesh = Fem.read(self.temp_file_mesh)
+
def create_mesh(self):
try:
self.update_mesh_data()
@@ -399,7 +427,7 @@ class GmshTools:
# if self.group_elements:
# Console.PrintMessage(" {}\n".format(self.group_elements))
- def get_gmsh_version(self):
+ def version(self):
self.get_gmsh_command()
if os.path.exists(self.gmsh_bin):
found_message = "file found: " + self.gmsh_bin
@@ -407,7 +435,7 @@ class GmshTools:
else:
found_message = "file not found: " + self.gmsh_bin
Console.PrintError(found_message + "\n")
- return (None, None, None), found_message
+ return found_message
command_list = [self.gmsh_bin, "--info"]
try:
@@ -420,26 +448,10 @@ class GmshTools:
)
except Exception as e:
Console.PrintMessage(str(e) + "\n")
- return (None, None, None), found_message + "\n\n" + "Error: " + str(e)
+ return found_message + "\n\n" + "Error: " + str(e)
gmsh_stdout, gmsh_stderr = p.communicate()
- Console.PrintMessage("Gmsh: StdOut:\n" + gmsh_stdout + "\n")
- if gmsh_stderr:
- Console.PrintError("Gmsh: StdErr:\n" + gmsh_stderr + "\n")
-
- from re import search
-
- # use raw string mode to get pep8 quiet
- # https://stackoverflow.com/q/61497292
- # https://github.com/MathSci/fecon236/issues/6
- match = search(r"^Version\s*:\s*(\d+)\.(\d+)\.(\d+)", gmsh_stdout)
- # return (major, minor, patch), fullmessage
- if match:
- mess = found_message + "\n\n" + gmsh_stdout
- return match.group(1, 2, 3), mess
- else:
- mess = found_message + "\n\n" + "Warning: Output not recognized\n\n" + gmsh_stdout
- return (None, None, None), mess
+ return gmsh_stdout
def get_region_data(self):
# mesh regions
diff --git a/src/Mod/Fem/femtaskpanels/task_mesh_gmsh.py b/src/Mod/Fem/femtaskpanels/task_mesh_gmsh.py
index 9c35ba266c..32afdba764 100644
--- a/src/Mod/Fem/femtaskpanels/task_mesh_gmsh.py
+++ b/src/Mod/Fem/femtaskpanels/task_mesh_gmsh.py
@@ -29,24 +29,17 @@ __url__ = "https://www.freecad.org"
# \ingroup FEM
# \brief task panel for mesh gmsh object
-import sys
-import time
-
from PySide import QtCore
-from PySide import QtGui
-from PySide.QtCore import Qt
-from PySide.QtGui import QApplication
import FreeCAD
import FreeCADGui
-import FemGui
-from femtools.femutils import is_of_type
-from femtools.femutils import getOutputWinColor
-from . import base_femtaskpanel
+from femmesh import gmshtools
+
+from . import base_femmeshtaskpanel
-class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
+class _TaskPanel(base_femmeshtaskpanel._BaseMeshTaskPanel):
"""
The TaskPanel for editing References property of
MeshGmsh objects and creation of new FEM mesh
@@ -58,16 +51,14 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.form = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/MeshGmsh.ui"
)
- self.Timer = QtCore.QTimer()
- self.Timer.start(100) # 100 milli seconds
- self.gmsh_runs = False
- self.console_message_gmsh = ""
+
+ self.tool = gmshtools.GmshTools(obj)
QtCore.QObject.connect(
- self.form.if_max, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.max_changed
+ self.form.qsb_max_size, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.max_changed
)
QtCore.QObject.connect(
- self.form.if_min, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.min_changed
+ self.form.qsb_min_size, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.min_changed
)
QtCore.QObject.connect(
self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension
@@ -75,40 +66,16 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
QtCore.QObject.connect(
self.form.cb_order, QtCore.SIGNAL("activated(int)"), self.choose_order
)
- QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
- QtCore.QObject.connect(
- self.form.pb_get_gmsh_version, QtCore.SIGNAL("clicked()"), self.get_gmsh_version
- )
-
self.form.cb_dimension.addItems(self.obj.getEnumerationsOfProperty("ElementDimension"))
self.form.cb_order.addItems(self.obj.getEnumerationsOfProperty("ElementOrder"))
+ QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
+ QtCore.QObject.connect(
+ self.form.pb_get_gmsh_version, QtCore.SIGNAL("clicked()"), self.get_version
+ )
self.get_mesh_params()
- self.get_active_analysis()
- self.update()
-
- def getStandardButtons(self):
- button_value = (
- QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel
- )
- return button_value
- # show a OK, a apply and a Cancel button
- # def reject() is called on Cancel button
- # def clicked(self, button) is needed, to access the apply button
-
- def accept(self):
- self.set_mesh_params()
- return super().accept()
-
- def reject(self):
- self.Timer.stop()
- return super().reject()
-
- def clicked(self, button):
- if button == QtGui.QDialogButtonBox.Apply:
- self.set_mesh_params()
- self.run_gmsh()
+ self.set_widgets()
def get_mesh_params(self):
self.clmax = self.obj.CharacteristicLengthMax
@@ -122,42 +89,21 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.obj.ElementDimension = self.dimension
self.obj.ElementOrder = self.order
- def update(self):
+ def set_widgets(self):
"fills the widgets"
- self.form.if_max.setText(self.clmax.UserString)
- self.form.if_min.setText(self.clmin.UserString)
+ self.form.qsb_max_size.setProperty("value", self.clmax)
+ FreeCADGui.ExpressionBinding(self.form.qsb_max_size).bind(
+ self.obj, "CharacteristicLengthMax"
+ )
+ self.form.qsb_min_size.setProperty("value", self.clmin)
+ FreeCADGui.ExpressionBinding(self.form.qsb_min_size).bind(
+ self.obj, "CharacteristicLengthMin"
+ )
index_dimension = self.form.cb_dimension.findText(self.dimension)
self.form.cb_dimension.setCurrentIndex(index_dimension)
index_order = self.form.cb_order.findText(self.order)
self.form.cb_order.setCurrentIndex(index_order)
- def console_log(self, message="", outputwin_color_type=None):
- self.console_message_gmsh = self.console_message_gmsh + (
- '{:4.1f}: '.format(
- getOutputWinColor("Logging"), time.time() - self.Start
- )
- )
- if outputwin_color_type:
- if outputwin_color_type == "#00AA00": # Success is not part of output window parameters
- self.console_message_gmsh += '{}
'.format(
- outputwin_color_type, message
- )
- else:
- self.console_message_gmsh += '{}
'.format(
- getOutputWinColor(outputwin_color_type), message
- )
- else:
- self.console_message_gmsh += message + "
"
- self.form.te_output.setText(self.console_message_gmsh)
- self.form.te_output.moveCursor(QtGui.QTextCursor.End)
-
- def update_timer_text(self):
- # FreeCAD.Console.PrintMessage("timer1\n")
- if self.gmsh_runs:
- FreeCAD.Console.PrintMessage("timer2\n")
- # FreeCAD.Console.PrintMessage("Time: {0:4.1f}: \n".format(time.time() - self.Start))
- self.form.l_time.setText(f"Time: {time.time() - self.Start:4.1f}: ")
-
def max_changed(self, base_quantity_value):
self.clmax = base_quantity_value
@@ -168,81 +114,10 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
if index < 0:
return
self.form.cb_dimension.setCurrentIndex(index)
- self.dimension = str(self.form.cb_dimension.itemText(index)) # form returns unicode
+ self.dimension = self.form.cb_dimension.itemText(index)
def choose_order(self, index):
if index < 0:
return
self.form.cb_order.setCurrentIndex(index)
- self.order = str(self.form.cb_order.itemText(index)) # form returns unicode
-
- def get_gmsh_version(self):
- from femmesh import gmshtools
-
- version, full_message = gmshtools.GmshTools(self.obj, self.analysis).get_gmsh_version()
- if version[0] and version[1] and version[2]:
- messagebox = QtGui.QMessageBox.information
- else:
- messagebox = QtGui.QMessageBox.warning
- messagebox(None, "Gmsh - Information", full_message)
-
- def run_gmsh(self):
- from femmesh import gmshtools
-
- gmsh_mesh = gmshtools.GmshTools(self.obj, self.analysis)
- QApplication.setOverrideCursor(Qt.WaitCursor)
- part = self.obj.Shape
- if (
- self.obj.MeshRegionList
- and part.Shape.ShapeType == "Compound"
- and (
- is_of_type(part, "FeatureBooleanFragments")
- or is_of_type(part, "FeatureSlice")
- or is_of_type(part, "FeatureXOR")
- )
- ):
- gmsh_mesh.outputCompoundWarning()
- self.Start = time.time()
- self.form.l_time.setText(f"Time: {time.time() - self.Start:4.1f}: ")
- self.console_message_gmsh = ""
- self.gmsh_runs = True
- self.console_log("We are going to start ...")
- self.get_active_analysis()
- self.console_log("Start Gmsh ...")
- error = ""
- try:
- error = gmsh_mesh.create_mesh()
- except Exception:
- error = sys.exc_info()[1]
- FreeCAD.Console.PrintError(f"Unexpected error when creating mesh: {error}\n")
- if error:
- FreeCAD.Console.PrintWarning("Gmsh had warnings:\n")
- FreeCAD.Console.PrintWarning(f"{error}\n")
- self.console_log("Gmsh had warnings ...", "Warning")
- self.console_log(error, "Error")
- else:
- FreeCAD.Console.PrintMessage("Clean run of Gmsh\n")
- self.console_log("Clean run of Gmsh", "#00AA00")
- self.console_log("Gmsh done!")
- self.form.l_time.setText(f"Time: {time.time() - self.Start:4.1f}: ")
- self.Timer.stop()
- self.update()
- QApplication.restoreOverrideCursor()
-
- def get_active_analysis(self):
- analysis = FemGui.getActiveAnalysis()
- if not analysis:
- FreeCAD.Console.PrintLog("No active analysis, means no group meshing.\n")
- self.analysis = None # no group meshing
- else:
- for m in analysis.Group:
- if m.Name == self.obj.Name:
- FreeCAD.Console.PrintLog(f"Active analysis found: {analysis.Name}\n")
- self.analysis = analysis # group meshing
- break
- else:
- FreeCAD.Console.PrintLog(
- "Mesh is not member of active analysis, means no group meshing.\n"
- )
- self.analysis = None # no group meshing
- return
+ self.order = self.form.cb_order.itemText(index)