Download src/Mod/Fem/femobjects/base_fempostvisualizations.py from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 7.11 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Fem/femobjects/base_fempostvisualizations.py
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Fem/femobjects/base_fempostvisualizations.py
-
curl -L -o base_fempostvisualizations.py https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Fem/femobjects/base_fempostvisualizations.py
7.11 kB
| # *************************************************************************** | |
| # * Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> * | |
| # * * | |
| # * 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 FEM postprocessing data visualization base object" | |
| __author__ = "Stefan Tröger" | |
| __url__ = "https://www.freecad.org" | |
| ## @package base_fempostextractors | |
| # \ingroup FEM | |
| # \brief base objects for data visualizations | |
| from vtkmodules.vtkCommonDataModel import vtkTable | |
| from vtkmodules.vtkCommonCore import vtkDoubleArray | |
| from . import base_fempythonobject | |
| from . import base_fempostextractors | |
| # helper functions | |
| # ################ | |
| def is_visualization_object(obj): | |
| if not obj: | |
| return False | |
| if not hasattr(obj, "Proxy"): | |
| return False | |
| return hasattr(obj.Proxy, "VisualizationType") | |
| def get_visualization_type(obj): | |
| # returns the extractor type string, or throws exception if | |
| # not a extractor | |
| return obj.Proxy.VisualizationType | |
| def is_visualization_extractor_type(obj, vistype): | |
| # must be extractor | |
| if not base_fempostextractors.is_extractor_object(obj): | |
| return False | |
| # must be visualization object | |
| if not is_visualization_object(obj): | |
| return False | |
| # must be correct type | |
| if get_visualization_type(obj) != vistype: | |
| return False | |
| return True | |
| # Base class for all visualizations | |
| # It collects all data from its extraction objects into a table. | |
| # Note: Never use directly, always subclass! This class does not create a | |
| # Visualization variable, hence will not work correctly. | |
| class PostVisualization(base_fempythonobject.BaseFemPythonObject): | |
| def __init__(self, obj): | |
| super().__init__(obj) | |
| self.Type = "Fem::FemPostVisualization" | |
| obj.addExtension("App::GroupExtensionPython") | |
| self._setup_properties(obj) | |
| def _setup_properties(self, obj): | |
| pl = obj.PropertiesList | |
| for prop in self._get_properties(): | |
| if not prop.name in pl: | |
| prop.add_to_object(obj) | |
| def _get_properties(self): | |
| # override if subclass wants to add additional properties | |
| prop = [ | |
| base_fempostextractors._PropHelper( | |
| type="Fem::PropertyPostDataObject", | |
| name="Table", | |
| group="Base", | |
| doc="The data table that stores the data for visualization", | |
| value=vtkTable(), | |
| ), | |
| ] | |
| return prop | |
| def onDocumentRestored(self, obj): | |
| # if a new property was added we handle it by setup | |
| # Override if subclass needs to handle changed property type | |
| self._setup_properties(obj) | |
| def onChanged(self, obj, prop): | |
| # Ensure only correct child object types are in the group | |
| if prop == "Group": | |
| # check if all objects are allowed | |
| children = obj.Group | |
| for child in obj.Group: | |
| if not is_visualization_extractor_type(child, self.VisualizationType): | |
| FreeCAD.Console.PrintWarning( | |
| f"{child.Label} is not a {self.VisualizationType} extraction object, cannot be added" | |
| ) | |
| children.remove(child) | |
| if len(obj.Group) != len(children): | |
| obj.Group = children | |
| def execute(self, obj): | |
| # Collect all extractor child data into our table | |
| # Note: Each childs table can have different number of rows. We need | |
| # to pad the date for our table in this case | |
| rows = self.getLongestColumnLength(obj) | |
| table = vtkTable() | |
| for child in obj.Group: | |
| # If child has no Source, its table should be empty. However, | |
| # it would theoretical be possible that child source was set | |
| # to none without recompute, and the visualization was manually | |
| # recomputed afterwards | |
| if not child.Source and (child.Table.GetNumberOfColumns() > 0): | |
| FreeCAD.Console.PrintWarning( | |
| f"{child.Label} has data, but no Source object. Will be ignored" | |
| ) | |
| continue | |
| c_table = child.Table | |
| for i in range(c_table.GetNumberOfColumns()): | |
| c_array = c_table.GetColumn(i) | |
| array = vtkDoubleArray() | |
| if c_array.GetNumberOfTuples() == rows: | |
| # simple deep copy is enough | |
| array.DeepCopy(c_array) | |
| else: | |
| array.SetNumberOfComponents(c_array.GetNumberOfComponents()) | |
| array.SetNumberOfTuples(rows) | |
| array.Fill(0) # so that all non-used entries are set to 0 | |
| for j in range(c_array.GetNumberOfTuples()): | |
| array.SetTuple(j, c_array.GetTuple(j)) | |
| array.SetName(f"{child.Source.Name}: {c_array.GetName()}") | |
| table.AddColumn(array) | |
| obj.Table = table | |
| return False | |
| def getLongestColumnLength(self, obj): | |
| # iterate all extractor children and get the column lengths | |
| length = 0 | |
| for child in obj.Group: | |
| if base_fempostextractors.is_extractor_object(child): | |
| table = child.Table | |
| if table.GetNumberOfColumns() > 0: | |
| # we assume all columns of an extractor have same length | |
| num = table.GetColumn(0).GetNumberOfTuples() | |
| if num > length: | |
| length = num | |
| return length | |