FEM: Addition of "half cycle" animation (#24129)

* Animation of Results - addition of half cycle

* Delete src/Mod/Fem/Gui/Resources/ui/ResultShow.ui

* Delete src/Mod/Fem/femtaskpanels/task_result_mechanical.py

* Delete src/Mod/Fem/femviewprovider/view_result_mechanical.py

* Add files via upload

* Add files via upload

* Add files via upload

* Update view_result_mechanical.py

* Update task_result_mechanical.py

* Update task_result_mechanical.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Delete user_guide_animate.txt

* Delete results.png

---------

Co-authored-by: mac-the-bike <mac-the-bike@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
mac-the-bike
2026-01-07 08:22:07 +00:00
committed by GitHub
parent 8bfbeac40f
commit f548697603
3 changed files with 90 additions and 25 deletions

View File

@@ -60,7 +60,7 @@
<item row="1" column="1">
<widget class="QRadioButton" name="rb_vm_stress">
<property name="text">
<string>von Mises Stress</string>
<string>von Mises stress</string>
</property>
</widget>
</item>
@@ -495,9 +495,9 @@
<widget class="QPushButton" name="startButton">
<property name="geometry">
<rect>
<x>10</x>
<x>230</x>
<y>130</y>
<width>435</width>
<width>200</width>
<height>25</height>
</rect>
</property>
@@ -508,6 +508,35 @@
<string>Start Animation</string>
</property>
</widget>
<widget class="QRadioButton" name="rb_full_cycle">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>91</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string> Full cycle</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="rb_half_cycle">
<property name="geometry">
<rect>
<x>120</x>
<y>130</y>
<width>101</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Half cycle</string>
</property>
</widget>
</widget>
</item>
<item>

View File

@@ -2,6 +2,7 @@
# * Copyright (c) 2015 Qingfeng Xia <qingfeng.xia()eng.ox.ac.uk> *
# * Copyright (c) 2016 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2024 PMcB *
# * Copyright (c) 2025 PMcB *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -266,6 +267,11 @@ class _TaskPanel:
self.result_widget.steps.setValue(FreeCAD.FEM_dialog["animate"][0])
self.result_widget.loops.setValue(FreeCAD.FEM_dialog["animate"][1])
self.result_widget.framerate.setValue(FreeCAD.FEM_dialog["animate"][2])
if FreeCAD.FEM_dialog["animate"][3]:
self.result_widget.rb_full_cycle.setChecked(True)
else:
self.result_widget.rb_half_cycle.setChecked(True)
self.result_widget.sb_displacement_factor.setValue(FreeCAD.FEM_dialog["animate"][4])
except Exception:
self.restore_initial_result_dialog()
@@ -284,7 +290,7 @@ class _TaskPanel:
"show_disp": True, # False,
"disp_factor": 5.0,
"disp_factor_max": 100.0,
"animate": [-1, -1, -1, -1], # steps, loops, rate, indicator (not used)
"animate": [-1, -1, -1, -1, -1, -1, -1], # steps, loops, rate, cycle type
}
self.result_widget.sb_displacement_factor_max.setValue(100.0) # init non standard values
@@ -315,7 +321,7 @@ class _TaskPanel:
"Uabs",
self.result_obj.DisplacementLengths,
"mm",
translate("FEM", "Displacement Magnitude"),
translate("FEM", "Displacement magnitude"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -351,7 +357,7 @@ class _TaskPanel:
"Sabs",
self.result_obj.vonMises,
"MPa",
translate("FEM", "von Mises Stress"),
translate("FEM", "von Mises stress"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -363,7 +369,7 @@ class _TaskPanel:
"MaxShear",
self.result_obj.MaxShear,
"MPa",
translate("FEM", "Max Shear Stress"),
translate("FEM", "Maximum shear stress (Tresca)"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -375,7 +381,7 @@ class _TaskPanel:
"MaxPrin",
self.result_obj.PrincipalMax,
"MPa",
translate("FEM", "Max Principal Stress"),
translate("FEM", "Maximum principal stress"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -399,7 +405,7 @@ class _TaskPanel:
"MFlow",
self.result_obj.MassFlowRate,
"kg/s",
translate("FEM", "Mass Flow Rate"),
translate("FEM", "Mass flow rate"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -411,7 +417,7 @@ class _TaskPanel:
"NPress",
self.result_obj.NetworkPressure,
"MPa",
translate("FEM", "Network Pressure"),
translate("FEM", "Network pressure"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -423,7 +429,7 @@ class _TaskPanel:
"MinPrin",
self.result_obj.PrincipalMin,
"MPa",
translate("FEM", "Min Principal Stress"),
translate("FEM", "Minimum principal stress"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -435,7 +441,7 @@ class _TaskPanel:
"Peeq",
self.result_obj.Peeq,
"",
translate("FEM", "Equivalent Plastic Strain"),
translate("FEM", "Equivalent plastic strain"),
)
else:
self.result_widget.rb_none.setChecked(True)
@@ -787,8 +793,14 @@ class _TaskPanel:
FreeCAD.FEM_dialog["animate"][0] = self.result_widget.steps.value()
FreeCAD.FEM_dialog["animate"][1] = self.result_widget.loops.value()
FreeCAD.FEM_dialog["animate"][2] = self.result_widget.framerate.value()
FreeCAD.FEM_dialog["animate"][3] = self.result_widget.rb_full_cycle.isChecked()
try:
FreeCAD.FEM_dialog["animate"][4] = self.result_widget.sb_displacement_factor.value()
except:
FreeCAD.FEM_dialog["animate"][4] = 1
# animation start
def animate_displacement(self):
if "result_obj" in FreeCAD.FEM_dialog:
if FreeCAD.FEM_dialog["result_obj"] != self.result_obj:
@@ -806,22 +818,44 @@ class _TaskPanel:
steps_per_cycle = int(self.result_widget.steps.value())
number_cycles = int(self.result_widget.loops.value())
inc = math.pi / steps_per_cycle * 2.0
sinc = inc = math.pi / steps_per_cycle * 2.0
self.set_label(self.result_obj.Label, self.results_name)
done = False
for lo in range(0, number_cycles):
for st in range(0, steps_per_cycle):
# for lo in range(0, number_cycles):
loops = max(1, number_cycles) * steps_per_cycle + 1
st = 0
for loop in range(0, loops):
if self.result_widget.rb_half_cycle.isChecked():
if number_cycles > 0: # 0 -> 1 -> 0, repeated
inc = sinc / 2
else:
inc = sinc / 4
# full cycle
if self.result_widget.rb_full_cycle.isChecked():
self.mesh_obj.ViewObject.applyDisplacement(
math.sin(st * inc) * self.hsb_displacement_factor
)
FreeCADGui.updateGui()
if not self.startAnimate:
done = True
break
time.sleep(1.0 / frame_rate) # modify the time here
if done:
elif self.result_widget.rb_half_cycle.isChecked():
# half cycle
if number_cycles > 0: # 0 -> 1 -> 0, repeated
self.mesh_obj.ViewObject.applyDisplacement(
abs(math.sin(st * inc)) * self.hsb_displacement_factor
)
elif number_cycles <= 0: # 0 -> 1, once
self.mesh_obj.ViewObject.applyDisplacement(
abs(math.sin(st * inc)) * self.hsb_displacement_factor
)
else:
print("No cycle type selected")
FreeCADGui.updateGui()
if not self.startAnimate:
done = True
break
time.sleep(1.0 / frame_rate) # modify the time here
st += 1
# if done:
# break
try:
self.result_widget.startButton.setText("Start Animation")
except:

View File

@@ -2,6 +2,7 @@
# * Copyright (c) 2015 Qingfeng Xia <qingfeng.xia()eng.ox.ac.uk> *
# * Copyright (c) 2016 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2024 PMcB *
# * Copyright (c) 2025 PMcB *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -44,6 +45,8 @@ class VPResultMechanical(view_base_femconstraint.VPBaseFemConstraint):
"""
def setEdit(self, vobj, mode=0):
# is mesh visible
self.visibility = self.Object.Mesh.ViewObject.Visibility
return view_base_femconstraint.VPBaseFemConstraint.setEdit(
self,
vobj,
@@ -51,12 +54,11 @@ class VPResultMechanical(view_base_femconstraint.VPBaseFemConstraint):
task_result_mechanical._TaskPanel,
)
# overwrite unsetEdit, hide result mesh object on task panel exit
def unsetEdit(self, vobj, mode=0):
FreeCADGui.Control.closeDialog()
# hide the mesh after result viewing is finished, but do not reset the coloring
# change this to not hide - PMcB
# self.Object.Mesh.ViewObject.hide()
# hide the mesh if it was not visible
if not self.visibility:
self.Object.Mesh.ViewObject.hide()
return True
def claimChildren(self):