FEM: Animation of Results (#18496)
This commit is contained in:
@@ -32,6 +32,7 @@ SET(FemBaseModules_SRCS
|
||||
InitGui.py
|
||||
ObjectsFem.py
|
||||
TestFemApp.py
|
||||
CreateLabels.py
|
||||
)
|
||||
|
||||
SET(FemCommands_SRCS
|
||||
|
||||
185
src/Mod/Fem/CreateLabels.py
Normal file
185
src/Mod/Fem/CreateLabels.py
Normal file
@@ -0,0 +1,185 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2024 Peter McB
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program 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 program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD result mechanical task panel"
|
||||
__author__ = "PMcB"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package view_result_mechanical
|
||||
# \ingroup FEM
|
||||
# \brief Create and Place Labels on the screen with an optional image.
|
||||
|
||||
import FreeCADGui
|
||||
from pivy import coin
|
||||
|
||||
"""
|
||||
Place Label on the screen with an optional image.
|
||||
positions on screen:
|
||||
(-.9, .9, 0) top left
|
||||
(.9, .9, 0) upper right
|
||||
(-.9, -.9, 0) lower left
|
||||
(.9, -.9, 0) lower right
|
||||
"""
|
||||
|
||||
|
||||
class createLabel:
|
||||
def __init__(self, trans, text, image="") -> None:
|
||||
self.textSep = coin.SoSeparator()
|
||||
self.cam = coin.SoOrthographicCamera()
|
||||
self.cam.aspectRatio = 1
|
||||
self.cam.viewportMapping = coin.SoCamera.LEAVE_ALONE
|
||||
|
||||
self.trans = coin.SoTranslation()
|
||||
self.trans.translation = trans
|
||||
self.translation = trans
|
||||
self.color = coin.SoBaseColor()
|
||||
self.color.rgb = (0, 0, 0)
|
||||
|
||||
self.myFont = coin.SoFont()
|
||||
self.myFont.name = "Arial,FreeSans,sans"
|
||||
# self.myFont.name = "FreeMono,FreeSans,sans"
|
||||
self.size = 20 # 24
|
||||
self.myFont.size.setValue(self.size)
|
||||
|
||||
self.SoText2 = coin.SoText2()
|
||||
self.SoText2.string = text
|
||||
|
||||
self.textSep.addChild(self.cam)
|
||||
self.textSep.addChild(self.trans)
|
||||
self.textSep.addChild(self.color)
|
||||
self.textSep.addChild(self.myFont)
|
||||
self.textSep.addChild(self.SoText2)
|
||||
self.activeDoc = FreeCADGui.ActiveDocument
|
||||
self.view = self.activeDoc.ActiveView
|
||||
self.viewer = self.view.getViewer()
|
||||
self.render = self.viewer.getSoRenderManager()
|
||||
self.isimage = False
|
||||
if image != "":
|
||||
self.add_image(image)
|
||||
self.isimage = True
|
||||
self.sup = self.render.addSuperimposition(self.textSep)
|
||||
self.displayed = True
|
||||
|
||||
# get position of label
|
||||
def get_position(self):
|
||||
return self.translation
|
||||
|
||||
# set position of label
|
||||
def set_position(self, trans):
|
||||
self.trans.translation = trans
|
||||
self.translation = trans
|
||||
|
||||
# set font
|
||||
def set_font(self, font):
|
||||
self.myFont.name = font
|
||||
|
||||
# set font size
|
||||
def set_font_size(self, font_size):
|
||||
self.myFont.size.setValue(font_size)
|
||||
|
||||
# set text of label
|
||||
def set_text(self, text):
|
||||
self.SoText2.string = text
|
||||
|
||||
# set colour of label
|
||||
def set_colour(self, colour):
|
||||
self.color.rgb = colour
|
||||
self.textSep.addChild(self.color)
|
||||
|
||||
# add or change the image with the label
|
||||
def add_image(self, image):
|
||||
self.remove_image()
|
||||
self.isimage = True
|
||||
self.myImage = coin.SoImage()
|
||||
self.myImage.filename.setValue(image)
|
||||
self.textSep.addChild(self.myImage)
|
||||
|
||||
# remove the image
|
||||
def remove_image(self):
|
||||
if self.isimage:
|
||||
# self.myImage = coin.SoImage()
|
||||
self.textSep.removeChild(self.myImage)
|
||||
self.isimage = False
|
||||
|
||||
# display the label
|
||||
def display(self):
|
||||
if not self.displayed:
|
||||
# display the Superimposition layer with :
|
||||
self.sup = self.render.addSuperimposition(self.textSep)
|
||||
self.displayed = True
|
||||
|
||||
# hide the label
|
||||
def hide(self):
|
||||
# hide the Superimposition layer with :
|
||||
if self.displayed:
|
||||
self.render.removeSuperimposition(self.sup)
|
||||
self.displayed = False
|
||||
|
||||
# help
|
||||
def help(self):
|
||||
print(
|
||||
"""
|
||||
Place Label on the screen with an optional image.
|
||||
Create an instance:
|
||||
import CreateLabels as CL
|
||||
label = CL.creatLabel(<position of label>, <title of label>, <optional image>)
|
||||
e.g.:
|
||||
label1 = CL.createLabel( (-0.7, -0.90, 0), "this is text")
|
||||
label2 = CL.createLabel( (+0.5, -0.90, 0), "this is a image", image = "mesh.jpg")
|
||||
Positions on screen:
|
||||
(-.9, .9, 0) top left
|
||||
(.9, .9, 0) upper right
|
||||
(-.9, -.9, 0) lower left
|
||||
(.9, -.9, 0) lower right
|
||||
|
||||
The following function are available:
|
||||
label1.set_position((0.7, 0.50, 0))
|
||||
pos= label1.get_position()
|
||||
label1.set_font("FreeMono,FreeSans,sans")
|
||||
label1.set_font_size(20)
|
||||
label1.set_text("hello world")
|
||||
label1.set_colour((0,1,0)) # colour of text
|
||||
label1.add_image("opera.jpg")
|
||||
label1.remove_image()
|
||||
label1.hide() - hide the label
|
||||
label1.display() - display the label, after hide
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
label1 = createLabel((-0.98, 0.90, 0), "this a new text")
|
||||
"""
|
||||
Examples:
|
||||
import CreateLabels as CL
|
||||
label1 = CL.createLabel( (+0.5, -0.90, 0), "this is a image", image = "mesh.jpg")
|
||||
label2 = CL.createLabel( (-0.7, -0.90, 0), "this is text")
|
||||
|
||||
label1.set_colour((0,1,0))
|
||||
label1.remove_image()
|
||||
label1.add_image("opera.jpg")
|
||||
label1.set_text("hello world")
|
||||
label1.set_position((+0.7, 0.50, 0))
|
||||
label1.set_font("FreeMono,FreeSans,sans")
|
||||
label1.hide()
|
||||
"""
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>335</width>
|
||||
<height>548</height>
|
||||
<width>477</width>
|
||||
<height>798</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -16,6 +16,12 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_result_type">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Result type</string>
|
||||
</property>
|
||||
@@ -158,6 +164,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="show_histogram">
|
||||
<property name="text">
|
||||
<string>Histogram</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -199,13 +212,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="show_histogram">
|
||||
<property name="text">
|
||||
<string>Histogram</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -213,8 +219,14 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_displacement">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Displacement</string>
|
||||
<string>Displacement Scaling</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
@@ -241,7 +253,10 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -251,14 +266,14 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Factor:</string>
|
||||
<string>Factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -274,24 +289,27 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Slider max:</string>
|
||||
<string>Slider Max</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -307,7 +325,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000.000000000000000</double>
|
||||
@@ -319,8 +337,187 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_animation">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>170</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Animation Control</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>435</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_1">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Number of Steps per Cycle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="steps">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhFormattedNumbersOnly</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>24.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>60</y>
|
||||
<width>435</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Number of Cycles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="loops">
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>4.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>90</y>
|
||||
<width>435</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Frame Rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="framerate">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhFormattedNumbersOnly</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>24.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="startButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>130</y>
|
||||
<width>435</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Toggles between Start and Stop</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Animation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_displacement_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>User defined equation</string>
|
||||
</property>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2015 Qingfeng Xia <qingfeng.xia()eng.ox.ac.uk> *
|
||||
# * Copyright (c) 2016 Bernd Hahnebach <bernd@bimstatik.org> *
|
||||
# * Copyright (c) 2024 PMcB *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
@@ -30,6 +31,9 @@ __url__ = "https://www.freecad.org"
|
||||
# \ingroup FEM
|
||||
# \brief task panel for mechanical ResultObjectPython
|
||||
|
||||
import CreateLabels
|
||||
import inspect, sys
|
||||
|
||||
try:
|
||||
import matplotlib
|
||||
|
||||
@@ -39,6 +43,7 @@ except Exception:
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import time, math
|
||||
|
||||
from PySide import QtCore
|
||||
from PySide import QtGui
|
||||
@@ -71,6 +76,12 @@ class _TaskPanel:
|
||||
self.result_widget = FreeCADGui.PySideUic.loadUi(ui_path + "ResultShow.ui")
|
||||
self.info_widget = FreeCADGui.PySideUic.loadUi(ui_path + "ResultHints.ui")
|
||||
self.form = [self.result_widget, self.info_widget]
|
||||
self.results_name = "No Contour Data"
|
||||
self.animate_inc = 1
|
||||
self.startAnimate = False
|
||||
self.animateText = []
|
||||
self.slider_max = False
|
||||
self.recurlim = min(200, sys.getrecursionlimit() / 2)
|
||||
|
||||
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
|
||||
self.restore_result_settings_in_dialog = self.fem_prefs.GetBool("RestoreResultDialog", True)
|
||||
@@ -79,7 +90,9 @@ class _TaskPanel:
|
||||
# result type radio buttons
|
||||
# TODO: move to combo box, to be independent from result types and result types count
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_none, QtCore.SIGNAL("toggled(bool)"), self.none_selected
|
||||
self.result_widget.rb_none,
|
||||
QtCore.SIGNAL("toggled(bool)"),
|
||||
self.none_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_abs_displacement,
|
||||
@@ -107,13 +120,19 @@ class _TaskPanel:
|
||||
self.temperature_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_vm_stress, QtCore.SIGNAL("toggled(bool)"), self.vm_stress_selected
|
||||
self.result_widget.rb_vm_stress,
|
||||
QtCore.SIGNAL("toggled(bool)"),
|
||||
self.vm_stress_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_maxprin, QtCore.SIGNAL("toggled(bool)"), self.max_prin_selected
|
||||
self.result_widget.rb_maxprin,
|
||||
QtCore.SIGNAL("toggled(bool)"),
|
||||
self.max_prin_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_minprin, QtCore.SIGNAL("toggled(bool)"), self.min_prin_selected
|
||||
self.result_widget.rb_minprin,
|
||||
QtCore.SIGNAL("toggled(bool)"),
|
||||
self.min_prin_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_max_shear_stress,
|
||||
@@ -131,11 +150,29 @@ class _TaskPanel:
|
||||
self.networkpressure_selected,
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.rb_peeq, QtCore.SIGNAL("toggled(bool)"), self.peeq_selected
|
||||
self.result_widget.rb_peeq,
|
||||
QtCore.SIGNAL("toggled(bool)"),
|
||||
self.peeq_selected,
|
||||
)
|
||||
|
||||
# stats
|
||||
self.result_widget.show_histogram.clicked.connect(self.show_histogram_clicked)
|
||||
# animate
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.hsb_displacement_factor,
|
||||
QtCore.SIGNAL("valueChanged(int)"),
|
||||
lambda dummy="", name="scale": self.value_changed(self, dummy, name),
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.sb_displacement_factor,
|
||||
QtCore.SIGNAL("valueChanged(double)"),
|
||||
lambda dummy="", name="factor": self.value_changed(self, dummy, name),
|
||||
)
|
||||
QtCore.QObject.connect(
|
||||
self.result_widget.startButton,
|
||||
QtCore.SIGNAL("clicked()"),
|
||||
lambda dummy="", name="startButton": self.value_changed(self, dummy, name),
|
||||
)
|
||||
|
||||
# displacement
|
||||
QtCore.QObject.connect(
|
||||
@@ -223,6 +260,12 @@ class _TaskPanel:
|
||||
# self.result_widget.hsb_displacement_factor.setValue(df)
|
||||
self.result_widget.sb_displacement_factor_max.setValue(dfm)
|
||||
self.result_widget.sb_displacement_factor.setValue(df)
|
||||
# animate
|
||||
self.startAnimate = False
|
||||
if FreeCAD.FEM_dialog["animate"][0] != -1:
|
||||
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])
|
||||
except Exception:
|
||||
self.restore_initial_result_dialog()
|
||||
|
||||
@@ -238,9 +281,10 @@ class _TaskPanel:
|
||||
# https://github.com/FreeCAD/FreeCAD/commit/3a7772d
|
||||
FreeCAD.FEM_dialog = {
|
||||
"results_type": "None",
|
||||
"show_disp": False,
|
||||
"disp_factor": 0.0,
|
||||
"show_disp": True, # False,
|
||||
"disp_factor": 5.0,
|
||||
"disp_factor_max": 100.0,
|
||||
"animate": [-1, -1, -1, -1], # steps, loops, rate, indicator (not used)
|
||||
}
|
||||
self.result_widget.sb_displacement_factor_max.setValue(100.0) # init non standard values
|
||||
|
||||
@@ -251,6 +295,7 @@ class _TaskPanel:
|
||||
return resulttools.get_stats(self.result_obj, type_name)
|
||||
|
||||
def none_selected(self, state):
|
||||
self.set_label(self.result_obj.Label, "No Contours")
|
||||
FreeCAD.FEM_dialog["results_type"] = "None"
|
||||
self.set_result_stats("mm", 0.0, 0.0)
|
||||
self.reset_mesh_color()
|
||||
@@ -303,7 +348,10 @@ class _TaskPanel:
|
||||
def vm_stress_selected(self, state):
|
||||
if len(self.result_obj.vonMises) > 0:
|
||||
self.result_selected(
|
||||
"Sabs", self.result_obj.vonMises, "MPa", translate("FEM", "von Mises Stress")
|
||||
"Sabs",
|
||||
self.result_obj.vonMises,
|
||||
"MPa",
|
||||
translate("FEM", "von Mises Stress"),
|
||||
)
|
||||
else:
|
||||
self.result_widget.rb_none.setChecked(True)
|
||||
@@ -312,7 +360,10 @@ class _TaskPanel:
|
||||
def max_shear_selected(self, state):
|
||||
if len(self.result_obj.MaxShear) > 0:
|
||||
self.result_selected(
|
||||
"MaxShear", self.result_obj.MaxShear, "MPa", translate("FEM", "Max Shear Stress")
|
||||
"MaxShear",
|
||||
self.result_obj.MaxShear,
|
||||
"MPa",
|
||||
translate("FEM", "Max Shear Stress"),
|
||||
)
|
||||
else:
|
||||
self.result_widget.rb_none.setChecked(True)
|
||||
@@ -333,7 +384,10 @@ class _TaskPanel:
|
||||
def temperature_selected(self, state):
|
||||
if len(self.result_obj.Temperature) > 0:
|
||||
self.result_selected(
|
||||
"Temp", self.result_obj.Temperature, "K", translate("FEM", "Temperature")
|
||||
"Temp",
|
||||
self.result_obj.Temperature,
|
||||
"K",
|
||||
translate("FEM", "Temperature"),
|
||||
)
|
||||
else:
|
||||
self.result_widget.rb_none.setChecked(True)
|
||||
@@ -342,7 +396,10 @@ class _TaskPanel:
|
||||
def massflowrate_selected(self, state):
|
||||
if len(self.result_obj.MassFlowRate) > 0:
|
||||
self.result_selected(
|
||||
"MFlow", self.result_obj.MassFlowRate, "kg/s", translate("FEM", "Mass Flow Rate")
|
||||
"MFlow",
|
||||
self.result_obj.MassFlowRate,
|
||||
"kg/s",
|
||||
translate("FEM", "Mass Flow Rate"),
|
||||
)
|
||||
else:
|
||||
self.result_widget.rb_none.setChecked(True)
|
||||
@@ -375,7 +432,10 @@ class _TaskPanel:
|
||||
def peeq_selected(self, state):
|
||||
if len(self.result_obj.Peeq) > 0:
|
||||
self.result_selected(
|
||||
"Peeq", self.result_obj.Peeq, "", translate("FEM", "Equivalent Plastic Strain")
|
||||
"Peeq",
|
||||
self.result_obj.Peeq,
|
||||
"",
|
||||
translate("FEM", "Equivalent Plastic Strain"),
|
||||
)
|
||||
else:
|
||||
self.result_widget.rb_none.setChecked(True)
|
||||
@@ -396,7 +456,10 @@ class _TaskPanel:
|
||||
QtGui.QMessageBox.information(
|
||||
None,
|
||||
self.result_obj.Label + " - " + translate("FEM", "Information"),
|
||||
translate("FEM", "No histogram available.\nPlease select a result type first."),
|
||||
translate(
|
||||
"FEM",
|
||||
"No histogram available.\nPlease select a result type first.",
|
||||
),
|
||||
)
|
||||
|
||||
def user_defined_text(self, equation):
|
||||
@@ -404,7 +467,6 @@ class _TaskPanel:
|
||||
self.result_widget.user_def_eq.toPlainText()
|
||||
|
||||
def calculate(self):
|
||||
|
||||
# Convert existing result values to numpy array
|
||||
# scalars
|
||||
P1 = np.array(self.result_obj.PrincipalMax)
|
||||
@@ -461,6 +523,7 @@ class _TaskPanel:
|
||||
self.update()
|
||||
self.restore_result_dialog()
|
||||
userdefined_eq = self.result_widget.user_def_eq.toPlainText() # Get equation to be used
|
||||
self.results_name = "User Defined: " + userdefined_eq
|
||||
|
||||
# https://forum.freecad.org/viewtopic.php?f=18&t=42425&start=10#p368774 ff
|
||||
# https://github.com/FreeCAD/FreeCAD/pull/3020
|
||||
@@ -533,6 +596,7 @@ class _TaskPanel:
|
||||
return scalar_list
|
||||
|
||||
def result_selected(self, res_type, res_values, res_unit, res_title):
|
||||
self.results_name = res_title
|
||||
FreeCAD.FEM_dialog["results_type"] = res_type
|
||||
(minm, maxm) = self.get_result_stats(res_type)
|
||||
self.update_colors_stats(res_values, res_unit, minm, maxm)
|
||||
@@ -555,6 +619,7 @@ class _TaskPanel:
|
||||
fig_manager.window.setWindowFlag(QtCore.Qt.Tool)
|
||||
|
||||
def update_colors_stats(self, res_values, res_unit, minm, maxm):
|
||||
self.set_label(self.result_obj.Label, self.results_name)
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
if self.suitable_results:
|
||||
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, res_values)
|
||||
@@ -596,6 +661,7 @@ class _TaskPanel:
|
||||
self.update_displacement()
|
||||
|
||||
def sb_disp_factor_max_changed(self, value):
|
||||
self.slider_max = True
|
||||
FreeCAD.FEM_dialog["disp_factor_max"] = value
|
||||
if value < self.result_widget.sb_displacement_factor.value():
|
||||
self.result_widget.sb_displacement_factor.setValue(value)
|
||||
@@ -605,19 +671,24 @@ class _TaskPanel:
|
||||
self.result_widget.hsb_displacement_factor.setValue(
|
||||
round(self.result_widget.sb_displacement_factor.value() / value * 100.0)
|
||||
)
|
||||
self.slider_max = False
|
||||
|
||||
def sb_disp_factor_changed(self, value):
|
||||
FreeCAD.FEM_dialog["disp_factor"] = value
|
||||
if value > self.result_widget.sb_displacement_factor_max.value():
|
||||
self.result_widget.sb_displacement_factor.setValue(
|
||||
self.result_widget.sb_displacement_factor_max.value()
|
||||
)
|
||||
if self.result_widget.sb_displacement_factor_max.value() == 0.0:
|
||||
self.result_widget.hsb_displacement_factor.setValue(0.0)
|
||||
else:
|
||||
self.result_widget.hsb_displacement_factor.setValue(
|
||||
round(value / self.result_widget.sb_displacement_factor_max.value() * 100.0)
|
||||
)
|
||||
# this bit of code causes:
|
||||
# RecursionError: maximum recursion depth exceeded
|
||||
# so check on the depth and don't exceed recurlim
|
||||
if len(inspect.stack(0)) < self.recurlim:
|
||||
FreeCAD.FEM_dialog["disp_factor"] = value
|
||||
if value > self.result_widget.sb_displacement_factor_max.value():
|
||||
self.result_widget.sb_displacement_factor.setValue(
|
||||
self.result_widget.sb_displacement_factor_max.value()
|
||||
)
|
||||
if self.result_widget.sb_displacement_factor_max.value() == 0.0:
|
||||
self.result_widget.hsb_displacement_factor.setValue(0.0)
|
||||
else:
|
||||
self.result_widget.hsb_displacement_factor.setValue(
|
||||
round(value / self.result_widget.sb_displacement_factor_max.value() * 100.0)
|
||||
)
|
||||
|
||||
def disable_empty_result_buttons(self):
|
||||
"""disable radio buttons if result does not exists in result object"""
|
||||
@@ -706,6 +777,99 @@ class _TaskPanel:
|
||||
# thus reset edit does not close the dialog, maybe don't call but set in edit instead
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
if len(self.animateText) > 0:
|
||||
for a in self.animateText:
|
||||
a.hide()
|
||||
self.animateText = []
|
||||
self.startAnimate = False
|
||||
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()
|
||||
|
||||
# animation start
|
||||
def animate_displacement(self):
|
||||
if "result_obj" in FreeCAD.FEM_dialog:
|
||||
if FreeCAD.FEM_dialog["result_obj"] != self.result_obj:
|
||||
self.update_displacement()
|
||||
self.result_widget.cb_show_displacement.setChecked(True)
|
||||
FreeCAD.FEM_dialog["result_obj"] = self.result_obj
|
||||
if self.suitable_results:
|
||||
self.mesh_obj.ViewObject.setNodeDisplacementByVectors(
|
||||
self.result_obj.NodeNumbers, self.result_obj.DisplacementVectors
|
||||
)
|
||||
self.result_widget.startButton.setText("Stop Animation")
|
||||
frame_rate = 10
|
||||
self.hsb_displacement_factor = self.result_widget.sb_displacement_factor.value()
|
||||
frame_rate = self.result_widget.framerate.value()
|
||||
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
|
||||
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):
|
||||
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:
|
||||
break
|
||||
try:
|
||||
self.result_widget.startButton.setText("Start Animation")
|
||||
except:
|
||||
pass
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
self.startAnimate = False
|
||||
|
||||
def value_changed(self, dummy, value, myType):
|
||||
# the only actions are:
|
||||
if myType == "startButton":
|
||||
if not self.startAnimate:
|
||||
self.startAnimate = True
|
||||
self.animate_displacement()
|
||||
else:
|
||||
self.startAnimate = False
|
||||
# # this is taken care of in the "ui"
|
||||
# # set the scale - scroll bar - Show
|
||||
# elif myType == "scale" and not self.slider_max:
|
||||
# if self.animate_inc == 0:
|
||||
# if self.result_widget.hsb_displacement_factor.value() > 1:
|
||||
# self.result_widget.sb_displacement_factor.setValue(
|
||||
# self.result_widget.hsb_displacement_factor.value()
|
||||
# )
|
||||
# self.animate_inc = 1 - self.animate_inc
|
||||
# # set the factor - spin - Factor
|
||||
# elif myType == "factor" and not self.slider_max:
|
||||
# if self.animate_inc == 0:
|
||||
# self.result_widget.hsb_displacement_factor.setValue(
|
||||
# int(self.result_widget.sb_displacement_factor.value())
|
||||
# )
|
||||
# self.animate_inc = 1 - self.animate_inc
|
||||
else:
|
||||
pass
|
||||
try:
|
||||
self.hsb_displacement_factor = self.result_widget.sb_displacement_factor.value()
|
||||
|
||||
except:
|
||||
pass
|
||||
return
|
||||
|
||||
def set_label(self, result_name, mesh_data):
|
||||
if len(self.animateText) == 0:
|
||||
self.animateText.append(CreateLabels.createLabel((-0.98, 0.90, 0), result_name))
|
||||
self.animateText.append(CreateLabels.createLabel((-0.98, 0.70, 0), mesh_data))
|
||||
else:
|
||||
self.animateText[1].set_text(mesh_data)
|
||||
pass
|
||||
|
||||
|
||||
# animation end
|
||||
|
||||
|
||||
# helper
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2015 Qingfeng Xia <qingfeng.xia()eng.ox.ac.uk> *
|
||||
# * Copyright (c) 2016 Bernd Hahnebach <bernd@bimstatik.org> *
|
||||
# * Copyright (c) 2024 PMcB *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
@@ -54,7 +55,8 @@ class VPResultMechanical(view_base_femconstraint.VPBaseFemConstraint):
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
# hide the mesh after result viewing is finished, but do not reset the coloring
|
||||
self.Object.Mesh.ViewObject.hide()
|
||||
# change this to not hide - PMcB
|
||||
# self.Object.Mesh.ViewObject.hide()
|
||||
return True
|
||||
|
||||
def claimChildren(self):
|
||||
|
||||
Reference in New Issue
Block a user