diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt
index 0178bffe84..3ba5a83c3e 100755
--- a/src/Mod/Fem/CMakeLists.txt
+++ b/src/Mod/Fem/CMakeLists.txt
@@ -223,6 +223,7 @@ if(BUILD_FEM_VTK_PYTHON)
femobjects/post_extract2D.py
femobjects/post_histogram.py
femobjects/post_lineplot.py
+ femobjects/post_table.py
)
endif(BUILD_FEM_VTK_PYTHON)
@@ -637,6 +638,7 @@ if(BUILD_FEM_VTK_PYTHON)
femtaskpanels/task_post_glyphfilter.py
femtaskpanels/task_post_histogram.py
femtaskpanels/task_post_lineplot.py
+ femtaskpanels/task_post_table.py
femtaskpanels/task_post_extractor.py
)
endif(BUILD_FEM_VTK_PYTHON)
@@ -666,6 +668,7 @@ SET(FemGuiViewProvider_SRCS
femviewprovider/view_base_femmeshelement.py
femviewprovider/view_base_femobject.py
femviewprovider/view_base_fempostvisualization.py
+ femviewprovider/view_base_fempostextractors.py
femviewprovider/view_constant_vacuumpermittivity.py
femviewprovider/view_constraint_bodyheatsource.py
femviewprovider/view_constraint_centrif.py
@@ -704,6 +707,7 @@ if(BUILD_FEM_VTK_PYTHON)
femviewprovider/view_post_extract.py
femviewprovider/view_post_histogram.py
femviewprovider/view_post_lineplot.py
+ femviewprovider/view_post_table.py
)
endif(BUILD_FEM_VTK_PYTHON)
diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt
index 7337afd833..7729f8af55 100755
--- a/src/Mod/Fem/Gui/CMakeLists.txt
+++ b/src/Mod/Fem/Gui/CMakeLists.txt
@@ -451,6 +451,7 @@ SET(FemGuiPythonUI_SRCS
Resources/ui/PostLineplotFieldViewEdit.ui
Resources/ui/PostLineplotFieldAppEdit.ui
Resources/ui/PostLineplotIndexAppEdit.ui
+ Resources/ui/PostTableFieldViewEdit.ui
)
ADD_CUSTOM_TARGET(FemPythonUi ALL
diff --git a/src/Mod/Fem/Gui/Resources/ui/PostHistogramFieldAppEdit.ui b/src/Mod/Fem/Gui/Resources/ui/PostHistogramFieldAppEdit.ui
index d100b81ab3..8e611e7790 100644
--- a/src/Mod/Fem/Gui/Resources/ui/PostHistogramFieldAppEdit.ui
+++ b/src/Mod/Fem/Gui/Resources/ui/PostHistogramFieldAppEdit.ui
@@ -65,7 +65,7 @@
-
- One field for all frames
+ One field for each frames
diff --git a/src/Mod/Fem/Gui/Resources/ui/PostTableFieldViewEdit.ui b/src/Mod/Fem/Gui/Resources/ui/PostTableFieldViewEdit.ui
new file mode 100644
index 0000000000..ada74b69b4
--- /dev/null
+++ b/src/Mod/Fem/Gui/Resources/ui/PostTableFieldViewEdit.ui
@@ -0,0 +1,43 @@
+
+
+ PostHistogramEdit
+
+
+
+ 0
+ 0
+ 259
+ 38
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ -
+
+
+ Name:
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py
index d40558f4bd..c21c219dda 100644
--- a/src/Mod/Fem/ObjectsFem.py
+++ b/src/Mod/Fem/ObjectsFem.py
@@ -770,6 +770,48 @@ def makePostHistogramIndexOverFrames(doc, name="IndexOverFrames1D"):
return obj
+def makePostTable(doc, name="Table"):
+ """makePostTable(document, [name]):
+ creates a FEM post processing histogram plot
+ """
+ obj = doc.addObject("App::FeaturePython", name)
+ from femobjects import post_table
+
+ post_table.PostTable(obj)
+ if FreeCAD.GuiUp:
+ from femviewprovider import view_post_table
+ view_post_table.VPPostTable(obj.ViewObject)
+ return obj
+
+
+def makePostTableFieldData(doc, name="FieldData1D"):
+ """makePostTableFieldData(document, [name]):
+ creates a FEM post processing data extractor for 1D Field data
+ """
+ obj = doc.addObject("App::FeaturePython", name)
+ from femobjects import post_table
+
+ post_table.PostTableFieldData(obj)
+ if FreeCAD.GuiUp:
+ from femviewprovider import view_post_table
+ view_post_table.VPPostTableFieldData(obj.ViewObject)
+ return obj
+
+
+def makePostTableIndexOverFrames(doc, name="IndexOverFrames1D"):
+ """makePostTableIndexOverFrames(document, [name]):
+ creates a FEM post processing data extractor for 1D Field data
+ """
+ obj = doc.addObject("App::FeaturePython", name)
+ from femobjects import post_table
+
+ post_table.PostTableIndexOverFrames(obj)
+ if FreeCAD.GuiUp:
+ from femviewprovider import view_post_table
+ view_post_table.VPPostTableIndexOverFrames(obj.ViewObject)
+ return obj
+
+
# ********* solver objects ***********************************************************************
def makeEquationDeformation(doc, base_solver=None, name="Deformation"):
"""makeEquationDeformation(document, [base_solver], [name]):
diff --git a/src/Mod/Fem/femcommands/commands.py b/src/Mod/Fem/femcommands/commands.py
index f4edc1586e..50461484a2 100644
--- a/src/Mod/Fem/femcommands/commands.py
+++ b/src/Mod/Fem/femcommands/commands.py
@@ -1293,4 +1293,5 @@ if "BUILD_FEM_VTK_PYTHON" in FreeCAD.__cmake__:
# setup all visualization commands (register by importing)
import femobjects.post_lineplot
import femobjects.post_histogram
+ import femobjects.post_table
post_visualization.setup_commands("FEM_PostVisualization")
diff --git a/src/Mod/Fem/femguiutils/extract_link_view.py b/src/Mod/Fem/femguiutils/extract_link_view.py
index e1611f8609..acd409765c 100644
--- a/src/Mod/Fem/femguiutils/extract_link_view.py
+++ b/src/Mod/Fem/femguiutils/extract_link_view.py
@@ -252,11 +252,13 @@ class _SummaryWidget(QtGui.QWidget):
self.extrButton.setIcon(extractor.ViewObject.Icon)
self.viewButton = self._button(extr_repr[1])
- size = self.viewButton.iconSize()
- size.setWidth(size.width()*2)
- self.viewButton.setIconSize(size)
- self.viewButton.setIcon(extr_repr[0])
-
+ if not extr_repr[0].isNull():
+ size = self.viewButton.iconSize()
+ size.setWidth(size.width()*2)
+ self.viewButton.setIconSize(size)
+ self.viewButton.setIcon(extr_repr[0])
+ else:
+ self.viewButton.setIconSize(QtCore.QSize(0,0))
self.rmButton = QtGui.QToolButton(self)
self.rmButton.setIcon(QtGui.QIcon.fromTheme("delete"))
diff --git a/src/Mod/Fem/femguiutils/vtk_table_view.py b/src/Mod/Fem/femguiutils/vtk_table_view.py
index df06c51ee0..95ebf1007e 100644
--- a/src/Mod/Fem/femguiutils/vtk_table_view.py
+++ b/src/Mod/Fem/femguiutils/vtk_table_view.py
@@ -34,14 +34,23 @@ from PySide import QtCore
class VtkTableModel(QtCore.QAbstractTableModel):
# Simple table model. Only supports single component columns
+ # One can supply a header_names dict to replace the table column names
+ # in the header. It is a dict "column_idx (int)" to "new name"" or
+ # "orig_name (str)" to "new name"
- def __init__(self):
+ def __init__(self, header_names = None):
super().__init__()
self._table = None
+ if header_names:
+ self._header = header_names
+ else:
+ self._header = {}
- def setTable(self, table):
+ def setTable(self, table, header_names = None):
self.beginResetModel()
self._table = table
+ if header_names:
+ self._header = header_names
self.endResetModel()
def rowCount(self, index):
@@ -70,7 +79,14 @@ class VtkTableModel(QtCore.QAbstractTableModel):
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
- return self._table.GetColumnName(section)
+ if section in self._header:
+ return self._header[section]
+
+ name = self._table.GetColumnName(section)
+ if name in self._header:
+ return self._header[name]
+
+ return name
if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
return section
diff --git a/src/Mod/Fem/femobjects/base_fempostvisualizations.py b/src/Mod/Fem/femobjects/base_fempostvisualizations.py
index fae9c58b6c..b16f41451f 100644
--- a/src/Mod/Fem/femobjects/base_fempostvisualizations.py
+++ b/src/Mod/Fem/femobjects/base_fempostvisualizations.py
@@ -21,42 +21,70 @@
# * *
# ***************************************************************************
-__title__ = "FreeCAD FEM postprocessing data exxtractor base objcts"
+__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 extractors
+# \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)
+ obj.addExtension("App::GroupExtensionPython")
self._setup_properties(obj)
+
def _setup_properties(self, obj):
pl = obj.PropertiesList
for prop in self._get_properties():
@@ -64,8 +92,96 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject):
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 _get_properties(self):
- return []
+
+ 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 (c_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 i in range(c_array.GetNumberOfTuples()):
+ array.SetTuple(i, c_array.GetTuple(i))
+
+ 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
diff --git a/src/Mod/Fem/femobjects/post_extract1D.py b/src/Mod/Fem/femobjects/post_extract1D.py
index 3540b6706a..425a594fae 100644
--- a/src/Mod/Fem/femobjects/post_extract1D.py
+++ b/src/Mod/Fem/femobjects/post_extract1D.py
@@ -29,6 +29,8 @@ __url__ = "https://www.freecad.org"
# \ingroup FEM
# \brief Post processing plot displaying lines
+import FreeCAD
+
from . import base_fempostextractors
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
@@ -176,9 +178,9 @@ class PostIndexOverFrames1D(base_fempostextractors.Extractor1D):
frame_array.SetTuple(i, idx, array)
if frame_array.GetNumberOfComponents() > 1:
- frame_array.SetName(f"{obj.XField} ({obj.XComponent})")
+ frame_array.SetName(f"{obj.XField} ({obj.XComponent}) @Idx {obj.Index}")
else:
- frame_array.SetName(f"{obj.XField}")
+ frame_array.SetName(f"{obj.XField} @Idx {obj.Index}")
self._x_array_component_to_table(obj, frame_array, table)
diff --git a/src/Mod/Fem/femobjects/post_extract2D.py b/src/Mod/Fem/femobjects/post_extract2D.py
index 60c9ac2df2..0b9e5c528e 100644
--- a/src/Mod/Fem/femobjects/post_extract2D.py
+++ b/src/Mod/Fem/femobjects/post_extract2D.py
@@ -29,6 +29,8 @@ __url__ = "https://www.freecad.org"
# \ingroup FEM
# \brief Post processing plot displaying lines
+import FreeCAD
+
from . import base_fempostextractors
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
@@ -207,9 +209,9 @@ class PostIndexOverFrames2D(base_fempostextractors.Extractor2D):
frame_x_array.SetName("Frames")
if frame_y_array.GetNumberOfComponents() > 1:
- frame_y_array.SetName(f"{obj.YField} ({obj.YComponent})")
+ frame_y_array.SetName(f"{obj.YField} ({obj.YComponent}) @Idx {obj.Index}")
else:
- frame_y_array.SetName(obj.YField)
+ frame_y_array.SetName(f"{obj.YField} @Idx {obj.Index}")
table.AddColumn(frame_x_array)
self._y_array_component_to_table(obj, frame_y_array, table)
diff --git a/src/Mod/Fem/femobjects/post_histogram.py b/src/Mod/Fem/femobjects/post_histogram.py
index bdcb4ad553..0a6277f5fe 100644
--- a/src/Mod/Fem/femobjects/post_histogram.py
+++ b/src/Mod/Fem/femobjects/post_histogram.py
@@ -29,17 +29,11 @@ __url__ = "https://www.freecad.org"
# \ingroup FEM
# \brief Post processing plot displaying histograms
-from . import base_fempythonobject
-_PropHelper = base_fempythonobject._PropHelper
from . import base_fempostextractors
from . import base_fempostvisualizations
from . import post_extract1D
-from vtkmodules.vtkCommonCore import vtkDoubleArray
-from vtkmodules.vtkCommonDataModel import vtkTable
-
-
from femguiutils import post_visualization
# register visualization and extractors
@@ -85,6 +79,7 @@ class PostHistogramFieldData(post_extract1D.PostFieldData1D):
"""
VisualizationType = "Histogram"
+
class PostHistogramIndexOverFrames(post_extract1D.PostIndexOverFrames1D):
"""
A 1D index extraction for histogram.
@@ -96,57 +91,11 @@ class PostHistogram(base_fempostvisualizations.PostVisualization):
"""
A post processing plot for showing extracted data as histograms
"""
-
VisualizationType = "Histogram"
- def __init__(self, obj):
- super().__init__(obj)
- obj.addExtension("App::GroupExtensionPython")
-
- def _get_properties(self):
- prop = [
- _PropHelper(
- type="Fem::PropertyPostDataObject",
- name="Table",
- group="Base",
- doc="The data table that stores the plotted data, one column per histogram",
- value=vtkTable(),
- ),
- ]
- return super()._get_properties() + prop
-
-
- def onChanged(self, obj, prop):
-
- if prop == "Group":
- # check if all objects are allowed
-
- children = obj.Group
- for child in obj.Group:
- if not is_histogram_extractor(child):
- FreeCAD.Console.PrintWarning(f"{child.Label} is not a data histogram data extraction object, cannot be added")
- children.remove(child)
-
- if len(obj.Group) != len(children):
- obj.Group = children
-
- def execute(self, obj):
-
- # during execution we collect all child data into our table
- table = vtkTable()
- for child in obj.Group:
-
- c_table = child.Table
- for i in range(c_table.GetNumberOfColumns()):
- c_array = c_table.GetColumn(i)
- # TODO: check which array type it is and use that one
- array = vtkDoubleArray()
- array.DeepCopy(c_array)
- array.SetName(f"{child.Source.Label}: {c_array.GetName()}")
- table.AddColumn(array)
-
- obj.Table = table
- return False
+
+
+
diff --git a/src/Mod/Fem/femobjects/post_lineplot.py b/src/Mod/Fem/femobjects/post_lineplot.py
index 06f844ebac..486241b367 100644
--- a/src/Mod/Fem/femobjects/post_lineplot.py
+++ b/src/Mod/Fem/femobjects/post_lineplot.py
@@ -29,17 +29,10 @@ __url__ = "https://www.freecad.org"
# \ingroup FEM
# \brief Post processing plot displaying lines
-from . import base_fempythonobject
-_PropHelper = base_fempythonobject._PropHelper
-
from . import base_fempostextractors
from . import base_fempostvisualizations
from . import post_extract2D
-from vtkmodules.vtkCommonCore import vtkDoubleArray
-from vtkmodules.vtkCommonDataModel import vtkTable
-
-
from femguiutils import post_visualization
# register visualization and extractors
@@ -85,6 +78,7 @@ class PostLineplotFieldData(post_extract2D.PostFieldData2D):
"""
VisualizationType = "Lineplot"
+
class PostLineplotIndexOverFrames(post_extract2D.PostIndexOverFrames2D):
"""
A 2D index extraction for lineplot.
@@ -97,56 +91,7 @@ class PostLineplot(base_fempostvisualizations.PostVisualization):
"""
A post processing plot for showing extracted data as line plots
"""
-
VisualizationType = "Lineplot"
- def __init__(self, obj):
- super().__init__(obj)
- obj.addExtension("App::GroupExtensionPython")
-
- def _get_properties(self):
- prop = [
- _PropHelper(
- type="Fem::PropertyPostDataObject",
- name="Table",
- group="Base",
- doc="The data table that stores the plotted data, two columns per lineplot (x,y)",
- value=vtkTable(),
- ),
- ]
- return super()._get_properties() + prop
-
-
- def onChanged(self, obj, prop):
-
- if prop == "Group":
- # check if all objects are allowed
-
- children = obj.Group
- for child in obj.Group:
- if not is_lineplot_extractor(child):
- FreeCAD.Console.PrintWarning(f"{child.Label} is not a data lineplot data extraction object, cannot be added")
- children.remove(child)
-
- if len(obj.Group) != len(children):
- obj.Group = children
-
- def execute(self, obj):
-
- # during execution we collect all child data into our table
- table = vtkTable()
- for child in obj.Group:
-
- c_table = child.Table
- for i in range(c_table.GetNumberOfColumns()):
- c_array = c_table.GetColumn(i)
- # TODO: check which array type it is and use that one
- array = vtkDoubleArray()
- array.DeepCopy(c_array)
- array.SetName(f"{child.Source.Label}: {c_array.GetName()}")
- table.AddColumn(array)
-
- obj.Table = table
- return False
diff --git a/src/Mod/Fem/femobjects/post_table.py b/src/Mod/Fem/femobjects/post_table.py
index f8798fbc23..3d7d7be689 100644
--- a/src/Mod/Fem/femobjects/post_table.py
+++ b/src/Mod/Fem/femobjects/post_table.py
@@ -21,191 +21,76 @@
# * *
# ***************************************************************************
-__title__ = "FreeCAD post line plot"
+__title__ = "FreeCAD post table"
__author__ = "Stefan Tröger"
__url__ = "https://www.freecad.org"
-## @package post_lineplot
+## @package post_table
# \ingroup FEM
-# \brief Post processing plot displaying lines
+# \brief Post processing plot displaying tables
-from . import base_fempythonobject
-_PropHelper = base_fempythonobject._PropHelper
-
-# helper function to extract plot object type
-def _get_extraction_subtype(obj):
- if hasattr(obj, 'Proxy') and hasattr(obj.Proxy, "Type"):
- return obj.Proxy.Type
-
- return "unknown"
+from . import base_fempostextractors
+from . import base_fempostvisualizations
+from . import post_extract1D
-class PostLinePlot(base_fempythonobject.BaseFemPythonObject):
+from femguiutils import post_visualization
+
+# register visualization and extractors
+post_visualization.register_visualization("Table",
+ ":/icons/FEM_PostSpreadsheet.svg",
+ "ObjectsFem",
+ "makePostTable")
+
+post_visualization.register_extractor("Table",
+ "TableFieldData",
+ ":/icons/FEM_PostField.svg",
+ "1D",
+ "Field",
+ "ObjectsFem",
+ "makePostTableFieldData")
+
+
+post_visualization.register_extractor("Table",
+ "TableIndexOverFrames",
+ ":/icons/FEM_PostIndex.svg",
+ "1D",
+ "Index",
+ "ObjectsFem",
+ "makePostTableIndexOverFrames")
+
+# Implementation
+# ##############
+
+def is_table_extractor(obj):
+
+ if not base_fempostextractors.is_extractor_object(obj):
+ return False
+
+ if not hasattr(obj.Proxy, "VisualizationType"):
+ return False
+
+ return obj.Proxy.VisualizationType == "Table"
+
+
+class PostTableFieldData(post_extract1D.PostFieldData1D):
"""
- A post processing extraction for plotting lines
+ A 1D Field extraction for tables.
"""
-
- Type = "App::FeaturePython"
-
- def __init__(self, obj):
- super().__init__(obj)
- obj.addExtension("App::GroupExtension")
- self._setup_properties(obj)
-
- def _setup_properties(self, obj):
-
- self.ExtractionType = "LinePlot"
-
- pl = obj.PropertiesList
- for prop in self._get_properties():
- if not prop.Name in pl:
- prop.add_to_object(obj)
-
- def _get_properties(self):
- prop = []
- return prop
-
- def onDocumentRestored(self, obj):
- self._setup_properties(self, obj):
-
- def onChanged(self, obj, prop):
-
- if prop == "Group":
- # check if all objects are allowed
-
- children = obj.Group
- for child in obj.Group:
- if _get_extraction_subtype(child) not in ["Line"]:
- children.remove(child)
-
- if len(obj.Group) != len(children):
- obj.Group = children
+ VisualizationType = "Table"
-class PostPlotLine(base_fempythonobject.BaseFemPythonObject):
+class PostTableIndexOverFrames(post_extract1D.PostIndexOverFrames1D):
+ """
+ A 1D index extraction for table.
+ """
+ VisualizationType = "Table"
- Type = "App::FeaturePython"
- def __init__(self, obj):
- super().__init__(obj)
- self._setup_properties(obj)
+class PostTable(base_fempostvisualizations.PostVisualization):
+ """
+ A post processing plot for showing extracted data as tables
+ """
+ VisualizationType = "Table"
- def _setup_properties(self, obj):
-
- self.ExtractionType = "Line"
-
- pl = obj.PropertiesList
- for prop in self._get_properties():
- if not prop.Name in pl:
- prop.add_to_object(obj)
-
- def _get_properties(self):
-
- prop = [
- _PropHelper(
- type="App::PropertyLink",
- name="Source",
- group="Line",
- doc="The data source, the line uses",
- value=None,
- ),
- _PropHelper(
- type="App::PropertyEnumeration",
- name="XField",
- group="X Data",
- doc="The field to use as X data",
- value=None,
- ),
- _PropHelper(
- type="App::PropertyEnumeration",
- name="XComponent",
- group="X Data",
- doc="Which part of the X field vector to use for the X axis",
- value=None,
- ),
- _PropHelper(
- type="App::PropertyEnumeration",
- name="YField",
- group="Y Data",
- doc="The field to use as Y data for the line plot",
- value=None,
- ),
- _PropHelper(
- type="App::PropertyEnumeration",
- name="YComponent",
- group="Y Data",
- doc="Which part of the Y field vector to use for the X axis",
- value=None,
- ),
- ]
- return prop
-
- def onDocumentRestored(self, obj):
- self._setup_properties(self, obj):
-
- def onChanged(self, obj, prop):
-
- if prop == "Source":
- # check if the source is a Post object
- if obj.Source and not obj.Source.isDerivedFrom("Fem::FemPostObject"):
- FreeCAD.Console.PrintWarning("Invalid object: Line source must be FemPostObject")
- obj.XField = []
- obj.YField = []
- obj.Source = None
-
- if prop == "XField":
- if not obj.Source:
- obj.XComponent = []
- return
-
- point_data = obj.Source.Data.GetPointData()
- if not point_data.HasArray(obj.XField):
- obj.XComponent = []
- return
-
- match point_data.GetArray(fields.index(obj.XField)).GetNumberOfComponents:
- case 1:
- obj.XComponent = ["Not a vector"]
- case 2:
- obj.XComponent = ["Magnitude", "X", "Y"]
- case 3:
- obj.XComponent = ["Magnitude", "X", "Y", "Z"]
-
- if prop == "YField":
- if not obj.Source:
- obj.YComponent = []
- return
-
- point_data = obj.Source.Data.GetPointData()
- if not point_data.HasArray(obj.YField):
- obj.YComponent = []
- return
-
- match point_data.GetArray(fields.index(obj.YField)).GetNumberOfComponents:
- case 1:
- obj.YComponent = ["Not a vector"]
- case 2:
- obj.YComponent = ["Magnitude", "X", "Y"]
- case 3:
- obj.YComponent = ["Magnitude", "X", "Y", "Z"]
-
- def onExecute(self, obj):
- # we need to make sure that we show the correct fields to the user as option for data extraction
-
- fields = []
- if obj.Source:
- point_data = obj.Source.Data.GetPointData()
- fields = [point_data.GetArrayName(i) for i in range(point_data.GetNumberOfArrays())]
-
- current_X = obj.XField
- obj.XField = fields
- if current_X in fields:
- obj.XField = current_X
-
- current_Y = obj.YField
- obj.YField = fields
- if current_Y in fields:
- obj.YField = current_Y
-
- return True
diff --git a/src/Mod/Fem/femtaskpanels/base_fempostpanel.py b/src/Mod/Fem/femtaskpanels/base_fempostpanel.py
index f90af0e260..3e26ac1ce5 100644
--- a/src/Mod/Fem/femtaskpanels/base_fempostpanel.py
+++ b/src/Mod/Fem/femtaskpanels/base_fempostpanel.py
@@ -60,6 +60,13 @@ class _BasePostTaskPanel(base_femtaskpanel._BaseTaskPanel):
if button == QtGui.QDialogButtonBox.Apply:
self.obj.Document.recompute()
+ def accept(self):
+ print("accept")
+ return super().accept()
+
+ def reject(self):
+ print("reject")
+ return super().reject()
# Helper functions
# ################
diff --git a/src/Mod/Fem/femtaskpanels/task_post_table.py b/src/Mod/Fem/femtaskpanels/task_post_table.py
new file mode 100644
index 0000000000..e17f584c01
--- /dev/null
+++ b/src/Mod/Fem/femtaskpanels/task_post_table.py
@@ -0,0 +1,94 @@
+# ***************************************************************************
+# * Copyright (c) 2025 Stefan Tröger *
+# * *
+# * 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 histogram plot task panel"
+__author__ = "Stefan Tröger"
+__url__ = "https://www.freecad.org"
+
+## @package task_post_histogram
+# \ingroup FEM
+# \brief task panel for post histogram plot
+
+from PySide import QtCore, QtGui
+
+import FreeCAD
+import FreeCADGui
+
+from . import base_fempostpanel
+from femguiutils import extract_link_view as elv
+from femguiutils import vtk_table_view
+
+class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
+ """
+ The TaskPanel for editing properties of glyph filter
+ """
+
+ def __init__(self, vobj):
+ super().__init__(vobj.Object)
+
+ # data widget
+ self.data_widget = QtGui.QWidget()
+ self.data_widget.show_table = QtGui.QPushButton()
+ self.data_widget.show_table.setText("Show table")
+
+ vbox = QtGui.QVBoxLayout()
+ vbox.addWidget(self.data_widget.show_table)
+ vbox.addSpacing(10)
+
+ extracts = elv.ExtractLinkView(self.obj, False, self)
+ vbox.addWidget(extracts)
+
+ self.data_widget.setLayout(vbox)
+ self.data_widget.setWindowTitle("Table data")
+ self.data_widget.setWindowIcon(FreeCADGui.getIcon(":/icons/FEM_PostSpreadsheet.svg"))
+
+
+ # histogram parameter widget
+ #self.view_widget = FreeCADGui.PySideUic.loadUi(
+ # FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/TaskPostTable.ui"
+ #)
+ #self.view_widget.setWindowTitle("Table view settings")
+ #self.view_widget.setWindowIcon(FreeCADGui.getIcon(":/icons/FEM_PostTable.svg"))
+
+ self.__init_widgets()
+
+ # form made from param and selection widget
+ self.form = [self.data_widget]
+
+
+ # Setup functions
+ # ###############
+
+ def __init_widgets(self):
+
+ # connect data widget
+ self.data_widget.show_table.clicked.connect(self.showTable)
+
+ # set current values to view widget
+ viewObj = self.obj.ViewObject
+
+
+ @QtCore.Slot()
+ def showTable(self):
+ self.obj.ViewObject.Proxy.show_visualization()
+
diff --git a/src/Mod/Fem/femviewprovider/view_post_extract.py b/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py
similarity index 92%
rename from src/Mod/Fem/femviewprovider/view_post_extract.py
rename to src/Mod/Fem/femviewprovider/view_base_fempostextractors.py
index b91c65cb45..46313ba890 100644
--- a/src/Mod/Fem/femviewprovider/view_post_extract.py
+++ b/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py
@@ -66,7 +66,7 @@ class VPPostExtractor:
def onChanged(self, vobj, prop):
- # one of our view properties was changed. Lets inform our parent plot
+ # one of our view properties was changed. Lets inform our parent visualization
# that this happend, as this is the one that needs to redraw
if prop == "Proxy":
@@ -92,6 +92,10 @@ class VPPostExtractor:
return True
+ def unsetEdit(self, vobj, mode=0):
+ FreeCADGui.Control.closeDialog()
+ return True
+
def doubleClicked(self, vobj):
guidoc = FreeCADGui.getDocument(vobj.Object.Document)
@@ -104,10 +108,20 @@ class VPPostExtractor:
return True
+ def dumps(self):
+ return None
+
+ def loads(self, state):
+ return None
+
+
+ # To be implemented by subclasses:
+ # ################################
+
def get_kw_args(self):
- # should return the plot keyword arguments that represent the properties
- # of the object
- return {}
+ # Returns the matplotlib plot keyword arguments that represent the
+ # properties of the object.
+ raise FreeCAD.Base.FreeCADError("Not implemented")
def get_app_edit_widget(self, post_dialog):
# Returns a widgets for editing the object (not viewprovider!)
@@ -125,10 +139,3 @@ class VPPostExtractor:
# Returns the preview tuple of icon and label: (QPixmap, str)
# Note: QPixmap in ratio 2:1
raise FreeCAD.Base.FreeCADError("Not implemented")
-
-
- def dumps(self):
- return None
-
- def loads(self, state):
- return None
diff --git a/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py b/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py
index 153537d669..20714b67c5 100644
--- a/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py
+++ b/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py
@@ -45,6 +45,8 @@ class VPPostVisualization:
def __init__(self, vobj):
vobj.Proxy = self
self._setup_properties(vobj)
+ vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
+
def _setup_properties(self, vobj):
pl = vobj.PropertiesList
@@ -52,16 +54,21 @@ class VPPostVisualization:
if not prop.name in pl:
prop.add_to_object(vobj)
+
def _get_properties(self):
return []
+
def attach(self, vobj):
self.Object = vobj.Object
self.ViewObject = vobj
+
def isShow(self):
+ # Mark ourself as visible in the tree
return True
+
def doubleClicked(self,vobj):
guidoc = FreeCADGui.getDocument(vobj.Object.Document)
@@ -71,21 +78,47 @@ class VPPostVisualization:
FreeCADGui.Control.closeDialog()
guidoc.resetEdit()
+ # open task dialog
guidoc.setEdit(vobj.Object.Name)
+
+ # show visualization
+ self.show_visualization()
+
return True
- def show_visualization(self):
- # shows the visualization without going into edit mode
- # to be implemented by subclasses
- pass
+ def unsetEdit(self, vobj, mode=0):
+ FreeCADGui.Control.closeDialog()
+ return True
- def get_kw_args(self, obj):
- # returns a dictionary with all visualization options needed for plotting
- # based on the view provider properties
- return {}
+ def updateData(self, obj, prop):
+ # If the data changed we need to update the visualization
+ if prop == "Table":
+ self.update_visualization()
+
+ def onChanged(self, vobj, prop):
+ # for all property changes we need to update the visualization
+ self.update_visualization()
+
+ def childViewPropertyChanged(self, vobj, prop):
+ # One of the extractors view properties has changed, we need to
+ # update the visualization
+ self.update_visualization()
def dumps(self):
return None
def loads(self, state):
return None
+
+
+ # To be implemented by subclasses:
+ # ################################
+
+ def update_visualization(self):
+ # The visualization data or any relevant view property has changed,
+ # and the visualization itself needs to update to reflect that
+ raise FreeCAD.Base.FreeCADError("Not implemented")
+
+ def show_visualization(self):
+ # Shows the visualization without going into edit mode
+ raise FreeCAD.Base.FreeCADError("Not implemented")
diff --git a/src/Mod/Fem/femviewprovider/view_post_histogram.py b/src/Mod/Fem/femviewprovider/view_post_histogram.py
index 777e3d15c0..2a6d817e70 100644
--- a/src/Mod/Fem/femviewprovider/view_post_histogram.py
+++ b/src/Mod/Fem/femviewprovider/view_post_histogram.py
@@ -42,7 +42,7 @@ import matplotlib as mpl
from vtkmodules.numpy_interface.dataset_adapter import VTKArray
-from . import view_post_extract
+from . import view_base_fempostextractors
from . import view_base_fempostvisualization
from femtaskpanels import task_post_histogram
@@ -244,7 +244,7 @@ class EditIndexAppWidget(QtGui.QWidget):
self._post_dialog._recompute()
-class VPPostHistogramFieldData(view_post_extract.VPPostExtractor):
+class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
"""
A View Provider for extraction of 1D field data specialy for histograms
"""
@@ -378,7 +378,7 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
def __init__(self, vobj):
super().__init__(vobj)
- vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
+
def _get_properties(self):
@@ -458,13 +458,10 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
]
return prop
+
def getIcon(self):
return ":/icons/FEM_PostHistogram.svg"
- def doubleClicked(self,vobj):
-
- self.show_visualization()
- super().doubleClicked(vobj)
def setEdit(self, vobj, mode):
@@ -482,24 +479,12 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
if not hasattr(self, "_plot") or not self._plot:
main = Plot.getMainWindow()
self._plot = Plot.Plot()
- self._plot.destroyed.connect(self.destroyed)
- self._dialog = QtGui.QDialog(main)
- box = QtGui.QVBoxLayout()
- box.addWidget(self._plot)
- self._dialog.resize(main.size().height()/2, main.size().height()/3) # keep it square
- self._dialog.setLayout(box)
+ self._plot.resize(main.size().height()/2, main.size().height()/3) # keep it square
+ self.update_visualization()
- self.drawPlot()
- self._dialog.show()
+ self._plot.show()
- def destroyed(self, obj):
- print("*********************************************************")
- print("**************** ******************")
- print("**************** destroy ******************")
- print("**************** ******************")
- print("*********************************************************")
-
def get_kw_args(self, obj):
view = obj.ViewObject
if not view or not hasattr(view, "Proxy"):
@@ -508,7 +493,8 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
return {}
return view.Proxy.get_kw_args()
- def drawPlot(self):
+
+ def update_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
return
@@ -579,26 +565,3 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
self._plot.update()
-
- def updateData(self, obj, prop):
- # we only react if the table changed, as then know that new data is available
- if prop == "Table":
- self.drawPlot()
-
-
- def onChanged(self, vobj, prop):
-
- # for all property changes we need to redraw the plot
- self.drawPlot()
-
- def childViewPropertyChanged(self, vobj, prop):
-
- # on of our extractors has a changed view property.
- self.drawPlot()
-
- def dumps(self):
- return None
-
-
- def loads(self, state):
- return None
diff --git a/src/Mod/Fem/femviewprovider/view_post_lineplot.py b/src/Mod/Fem/femviewprovider/view_post_lineplot.py
index f98a5bf1e4..29c0165275 100644
--- a/src/Mod/Fem/femviewprovider/view_post_lineplot.py
+++ b/src/Mod/Fem/femviewprovider/view_post_lineplot.py
@@ -42,9 +42,10 @@ import matplotlib as mpl
from vtkmodules.numpy_interface.dataset_adapter import VTKArray
-from . import view_post_extract
+from . import view_base_fempostextractors
from . import view_base_fempostvisualization
from femtaskpanels import task_post_lineplot
+from femguiutils import post_visualization as pv
_GuiPropHelper = view_base_fempostvisualization._GuiPropHelper
@@ -248,7 +249,7 @@ class EditIndexAppWidget(QtGui.QWidget):
self._post_dialog._recompute()
-class VPPostLineplotFieldData(view_post_extract.VPPostExtractor):
+class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor):
"""
A View Provider for extraction of 2D field data specialy for histograms
"""
@@ -376,7 +377,7 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
def __init__(self, vobj):
super().__init__(vobj)
- vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
+
def _get_properties(self):
@@ -435,13 +436,10 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
]
return prop
+
def getIcon(self):
return ":/icons/FEM_PostLineplot.svg"
- def doubleClicked(self,vobj):
-
- self.show_visualization()
- super().doubleClicked(vobj)
def setEdit(self, vobj, mode):
@@ -457,16 +455,13 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
def show_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
- self._plot = Plot.Plot()
main = Plot.getMainWindow()
- self._dialog = QtGui.QDialog(main)
- box = QtGui.QVBoxLayout()
- box.addWidget(self._plot)
- self._dialog.resize(main.size().height()/2, main.size().height()/3) # keep aspect ratio constant
- self._dialog.setLayout(box)
+ self._plot = Plot.Plot()
+ self._plot.resize(main.size().height()/2, main.size().height()/3) # keep the aspect ratio
+ self.update_visualization()
+
+ self._plot.show()
- self.drawPlot()
- self._dialog.show()
def get_kw_args(self, obj):
view = obj.ViewObject
@@ -476,7 +471,8 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
return {}
return view.Proxy.get_kw_args()
- def drawPlot(self):
+
+ def update_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
return
@@ -545,26 +541,3 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
self._plot.update()
-
- def updateData(self, obj, prop):
- # we only react if the table changed, as then know that new data is available
- if prop == "Table":
- self.drawPlot()
-
-
- def onChanged(self, vobj, prop):
-
- # for all property changes we need to redraw the plot
- self.drawPlot()
-
- def childViewPropertyChanged(self, vobj, prop):
-
- # on of our extractors has a changed view property.
- self.drawPlot()
-
- def dumps(self):
- return None
-
-
- def loads(self, state):
- return None
diff --git a/src/Mod/Fem/femviewprovider/view_post_table.py b/src/Mod/Fem/femviewprovider/view_post_table.py
new file mode 100644
index 0000000000..443667e31a
--- /dev/null
+++ b/src/Mod/Fem/femviewprovider/view_post_table.py
@@ -0,0 +1,287 @@
+# ***************************************************************************
+# * Copyright (c) 2025 Stefan Tröger *
+# * *
+# * 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 table ViewProvider for the document object"
+__author__ = "Stefan Tröger"
+__url__ = "https://www.freecad.org"
+
+## @package view_post_table
+# \ingroup FEM
+# \brief view provider for post table object
+
+import FreeCAD
+import FreeCADGui
+
+import Plot
+import FemGui
+from PySide import QtGui, QtCore
+
+import io
+import numpy as np
+import matplotlib as mpl
+
+from vtkmodules.numpy_interface.dataset_adapter import VTKArray
+
+from . import view_base_fempostextractors
+from . import view_base_fempostvisualization
+from femtaskpanels import task_post_table
+from femguiutils import vtk_table_view as vtv
+
+_GuiPropHelper = view_base_fempostvisualization._GuiPropHelper
+
+class EditViewWidget(QtGui.QWidget):
+
+ def __init__(self, obj, post_dialog):
+ super().__init__()
+
+ self._object = obj
+ self._post_dialog = post_dialog
+
+ # load the ui and set it up
+ self.widget = FreeCADGui.PySideUic.loadUi(
+ FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/PostTableFieldViewEdit.ui"
+ )
+ layout = QtGui.QVBoxLayout()
+ layout.addWidget(self.widget)
+ self.setLayout(layout)
+
+ self.__init_widget()
+
+ def __init_widget(self):
+ # set the other properties
+ self.widget.Name.setText(self._object.ViewObject.Name)
+ self.widget.Name.editingFinished.connect(self.legendChanged)
+
+ @QtCore.Slot()
+ def legendChanged(self):
+ self._object.ViewObject.Name = self.widget.Name.text()
+
+
+class EditFieldAppWidget(QtGui.QWidget):
+
+ def __init__(self, obj, post_dialog):
+ super().__init__()
+
+ self._object = obj
+ self._post_dialog = post_dialog
+
+ # load the ui and set it up (we reuse histogram, as we need the exact same)
+ self.widget = FreeCADGui.PySideUic.loadUi(
+ FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/PostHistogramFieldAppEdit.ui"
+ )
+ layout = QtGui.QVBoxLayout()
+ layout.addWidget(self.widget)
+ self.setLayout(layout)
+
+ self.__init_widget()
+
+ def __init_widget(self):
+ # set the other properties
+
+ self._post_dialog._enumPropertyToCombobox(self._object, "XField", self.widget.Field)
+ self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.Component)
+ self.widget.Extract.setChecked(self._object.ExtractFrames)
+
+ self.widget.Field.activated.connect(self.fieldChanged)
+ self.widget.Component.activated.connect(self.componentChanged)
+ self.widget.Extract.toggled.connect(self.extractionChanged)
+
+ @QtCore.Slot(int)
+ def fieldChanged(self, index):
+ self._object.XField = index
+ self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.Component)
+ self._post_dialog._recompute()
+
+ @QtCore.Slot(int)
+ def componentChanged(self, index):
+ self._object.XComponent = index
+ self._post_dialog._recompute()
+
+ @QtCore.Slot(bool)
+ def extractionChanged(self, extract):
+ self._object.ExtractFrames = extract
+ self._post_dialog._recompute()
+
+class EditIndexAppWidget(QtGui.QWidget):
+
+ def __init__(self, obj, post_dialog):
+ super().__init__()
+
+ self._object = obj
+ self._post_dialog = post_dialog
+
+ # load the ui and set it up (we reuse histogram, as we need the exact same)
+ self.widget = FreeCADGui.PySideUic.loadUi(
+ FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/PostHistogramIndexAppEdit.ui"
+ )
+ layout = QtGui.QVBoxLayout()
+ layout.addWidget(self.widget)
+ self.setLayout(layout)
+
+ self.__init_widget()
+
+ def __init_widget(self):
+ # set the other properties
+
+ self.widget.Index.setValue(self._object.Index)
+ self._post_dialog._enumPropertyToCombobox(self._object, "XField", self.widget.Field)
+ self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.Component)
+
+ self.widget.Index.valueChanged.connect(self.indexChanged)
+ self.widget.Field.activated.connect(self.fieldChanged)
+ self.widget.Component.activated.connect(self.componentChanged)
+
+ # sometimes wierd sizes occur with spinboxes
+ self.widget.Index.setMaximumHeight(self.widget.Field.sizeHint().height())
+
+ @QtCore.Slot(int)
+ def fieldChanged(self, index):
+ self._object.XField = index
+ self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.Component)
+ self._post_dialog._recompute()
+
+ @QtCore.Slot(int)
+ def componentChanged(self, index):
+ self._object.XComponent = index
+ self._post_dialog._recompute()
+
+ @QtCore.Slot(int)
+ def indexChanged(self, value):
+ self._object.Index = value
+ self._post_dialog._recompute()
+
+
+class VPPostTableFieldData(view_base_fempostextractors.VPPostExtractor):
+ """
+ A View Provider for extraction of 1D field data specialy for tables
+ """
+
+ def __init__(self, vobj):
+ super().__init__(vobj)
+
+ def _get_properties(self):
+
+ prop = [
+ _GuiPropHelper(
+ type="App::PropertyString",
+ name="Name",
+ group="Table",
+ doc="The name used in the table header. Default name is used if empty",
+ value="",
+ ),
+ ]
+ return super()._get_properties() + prop
+
+ def attach(self, vobj):
+ self.Object = vobj.Object
+ self.ViewObject = vobj
+
+ def getIcon(self):
+ return ":/icons/FEM_PostField.svg"
+
+ def get_app_edit_widget(self, post_dialog):
+ return EditFieldAppWidget(self.Object, post_dialog)
+
+ def get_view_edit_widget(self, post_dialog):
+ return EditViewWidget(self.Object, post_dialog)
+
+ def get_preview(self):
+ name = "----"
+ if self.ViewObject.Name:
+ name = self.ViewObject.Name
+ return (QtGui.QPixmap(), name)
+
+
+class VPPostTableIndexOverFrames(VPPostTableFieldData):
+ """
+ A View Provider for extraction of 1D index over frames data
+ """
+
+ def __init__(self, vobj):
+ super().__init__(vobj)
+
+ def getIcon(self):
+ return ":/icons/FEM_PostIndex.svg"
+
+ def get_app_edit_widget(self, post_dialog):
+ return EditIndexAppWidget(self.Object, post_dialog)
+
+
+class VPPostTable(view_base_fempostvisualization.VPPostVisualization):
+ """
+ A View Provider for Table plots
+ """
+
+ def __init__(self, vobj):
+ super().__init__(vobj)
+
+
+ def getIcon(self):
+ return ":/icons/FEM_PostSpreadsheet.svg"
+
+
+ def setEdit(self, vobj, mode):
+
+ # build up the task panel
+ taskd = task_post_table._TaskPanel(vobj)
+
+ #show it
+ FreeCADGui.Control.showDialog(taskd)
+
+ return True
+
+
+ def show_visualization(self):
+
+ if not hasattr(self, "_tableview") or not self._tableview:
+ self._tableModel = vtv.VtkTableModel()
+ self._tableview = vtv.VtkTableView(self._tableModel)
+ self.update_visualization()
+
+ self._tableview.show()
+
+
+ def update_visualization(self):
+
+ if not hasattr(self, "_tableModel") or not self._tableModel:
+ return
+
+ # we collect the header names from the viewproviders
+ table = self.Object.Table
+ header = {}
+ for child in self.Object.Group:
+
+ if not child.Source:
+ continue
+
+ new_name = child.ViewObject.Name
+ if new_name:
+ # this child uses a custom name. We try to find all
+ # columns that are from this child and use custom header for it
+ for i in range(table.GetNumberOfColumns()):
+ if child.Source.Name in table.GetColumnName(i):
+ header[table.GetColumnName(i)] = new_name
+
+ self._tableModel.setTable(self.Object.Table, header)
+
+