Merge pull request #16515 from marioalexis84/fem-meshing_no_blocking
Fem: Enable cancel meshing for Gmsh - fixes #5914
This commit is contained in:
@@ -571,6 +571,7 @@ SET(FemGuiObjects_SRCS
|
||||
SET(FemGuiTaskPanels_SRCS
|
||||
femtaskpanels/__init__.py
|
||||
femtaskpanels/base_femtaskpanel.py
|
||||
femtaskpanels/base_femmeshtaskpanel.py
|
||||
femtaskpanels/task_constraint_bodyheatsource.py
|
||||
femtaskpanels/task_constraint_centrif.py
|
||||
femtaskpanels/task_constraint_currentdensity.py
|
||||
|
||||
@@ -49,38 +49,35 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::InputField" name="if_max">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0 mm</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000.000000000000000</double>
|
||||
<widget class="Gui::QuantitySpinBox" name="qsb_max_size">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="decimals" stdset="0">
|
||||
<number>2</number>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000000000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -93,38 +90,35 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::InputField" name="if_min">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0 mm</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000.000000000000000</double>
|
||||
<widget class="Gui::QuantitySpinBox" name="qsb_min_size">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">mm</string>
|
||||
</property>
|
||||
<property name="decimals" stdset="0">
|
||||
<number>2</number>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="keyboardTracking">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000000000000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -219,9 +213,9 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::InputField</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>Gui/InputField.h</header>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
||||
@@ -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
|
||||
|
||||
188
src/Mod/Fem/femtaskpanels/base_femmeshtaskpanel.py
Normal file
188
src/Mod/Fem/femtaskpanels/base_femmeshtaskpanel.py
Normal file
@@ -0,0 +1,188 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2024 Mario Passaglia <mpassaglia[at]cbc.uba.ar> *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD 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 *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD FEM mesh base task panel for mesh object object"
|
||||
__author__ = "Mario Passaglia"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package base_femmeshtaskpanel
|
||||
# \ingroup FEM
|
||||
# \brief base task panel for mesh object
|
||||
|
||||
import time
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from PySide import QtCore
|
||||
from PySide import QtGui
|
||||
|
||||
import FreeCAD
|
||||
|
||||
from femtools.femutils import getOutputWinColor
|
||||
|
||||
from . import base_femtaskpanel
|
||||
|
||||
|
||||
class _Process(threading.Thread):
|
||||
"""
|
||||
Class for thread and subprocess manipulation
|
||||
'tool' argument must be an object with a 'compute' method
|
||||
and a 'process' attribute of type Popen object
|
||||
"""
|
||||
|
||||
def __init__(self, tool):
|
||||
self.tool = tool
|
||||
self._timer = QtCore.QTimer()
|
||||
self.success = False
|
||||
self.update = False
|
||||
self.error = ""
|
||||
super().__init__(target=self.tool.compute)
|
||||
QtCore.QObject.connect(self._timer, QtCore.SIGNAL("timeout()"), self._check)
|
||||
|
||||
def init(self):
|
||||
self._timer.start(100)
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.success = self._target(*self._args, **self._kwargs)
|
||||
except Exception as e:
|
||||
self.error = str(e)
|
||||
|
||||
def finish(self):
|
||||
if self.tool.process:
|
||||
self.tool.process.terminate()
|
||||
self.join()
|
||||
|
||||
def _check(self):
|
||||
if not self.is_alive():
|
||||
self._timer.stop()
|
||||
self.join()
|
||||
if self.success:
|
||||
try:
|
||||
self.tool.update_properties()
|
||||
self.update = True
|
||||
except Exception as e:
|
||||
self.error = str(e)
|
||||
self.success = False
|
||||
|
||||
|
||||
class _BaseMeshTaskPanel(base_femtaskpanel._BaseTaskPanel, ABC):
|
||||
"""
|
||||
Abstract base class for FemMesh object TaskPanel
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
|
||||
self.tool = None
|
||||
self.form = None
|
||||
self.timer = QtCore.QTimer()
|
||||
self.process = None
|
||||
self.console_message = ""
|
||||
|
||||
@abstractmethod
|
||||
def set_mesh_params(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_mesh_params(self):
|
||||
pass
|
||||
|
||||
def getStandardButtons(self):
|
||||
button_value = (
|
||||
QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel
|
||||
)
|
||||
return button_value
|
||||
|
||||
def accept(self):
|
||||
if self.process and self.process.is_alive():
|
||||
FreeCAD.Console.PrintWarning("Process still running\n")
|
||||
return None
|
||||
|
||||
self.timer.stop()
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
self.set_mesh_params()
|
||||
return super().accept()
|
||||
|
||||
def reject(self):
|
||||
self.timer.stop()
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
if self.process and self.process.is_alive():
|
||||
self.console_log("Process aborted", "#ff6700")
|
||||
self.process.finish()
|
||||
else:
|
||||
return super().reject()
|
||||
|
||||
def clicked(self, button):
|
||||
if button == QtGui.QDialogButtonBox.Apply:
|
||||
if self.process and self.process.is_alive():
|
||||
FreeCAD.Console.PrintWarning("Process already running\n")
|
||||
return None
|
||||
|
||||
self.set_mesh_params()
|
||||
self.run_mesher()
|
||||
|
||||
def console_log(self, message="", outputwin_color_type=None):
|
||||
self.console_message = self.console_message + (
|
||||
'<font color="{}"><b>{:4.1f}:</b></font> '.format(
|
||||
getOutputWinColor("Logging"), time.time() - self.time_start
|
||||
)
|
||||
)
|
||||
if outputwin_color_type:
|
||||
self.console_message += '<font color="{}">{}</font><br>'.format(
|
||||
outputwin_color_type, message
|
||||
)
|
||||
else:
|
||||
self.console_message += message + "<br>"
|
||||
self.form.te_output.setText(self.console_message)
|
||||
self.form.te_output.moveCursor(QtGui.QTextCursor.End)
|
||||
|
||||
def update_timer_text(self):
|
||||
if self.process and self.process.is_alive():
|
||||
self.form.l_time.setText(f"Time: {time.time() - self.time_start:4.1f}: ")
|
||||
else:
|
||||
if self.process:
|
||||
if self.process.success:
|
||||
if not self.process.update:
|
||||
return None
|
||||
self.console_log("Success!", "#00AA00")
|
||||
else:
|
||||
self.console_log(self.process.error, "#AA0000")
|
||||
self.timer.stop()
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
|
||||
def run_mesher(self):
|
||||
self.process = _Process(self.tool)
|
||||
self.timer.start(100)
|
||||
self.time_start = time.time()
|
||||
self.form.l_time.setText(f"Time: {time.time() - self.time_start:4.1f}: ")
|
||||
self.console_message = ""
|
||||
self.console_log("Start process...")
|
||||
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
|
||||
|
||||
self.process.init()
|
||||
|
||||
def get_version(self):
|
||||
full_message = self.tool.version()
|
||||
QtGui.QMessageBox.information(None, "{} - Information".format(self.tool.name), full_message)
|
||||
@@ -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 + (
|
||||
'<font color="{}"><b>{:4.1f}:</b></font> '.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 += '<font color="{}">{}</font><br>'.format(
|
||||
outputwin_color_type, message
|
||||
)
|
||||
else:
|
||||
self.console_message_gmsh += '<font color="{}">{}</font><br>'.format(
|
||||
getOutputWinColor(outputwin_color_type), message
|
||||
)
|
||||
else:
|
||||
self.console_message_gmsh += message + "<br>"
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user