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

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot]
2025-06-16 18:26:48 +00:00
parent fa9aba2749
commit da4d5c919f
35 changed files with 447 additions and 348 deletions

View File

@@ -199,7 +199,7 @@ PyObject* FemPostFilterPy::getOutputAlgorithm(PyObject* args)
auto algorithm = getFemPostFilterPtr()->getFilterOutput();
PyObject* py_algorithm = vtkPythonUtil::GetObjectFromPointer(algorithm);
return Py::new_reference_to(py_algorithm);
return Py::new_reference_to(py_algorithm);
#else
PyErr_SetString(PyExc_NotImplementedError, "VTK python wrapper not available");
Py_Return;

View File

@@ -30,9 +30,9 @@
#include "FemPostObjectPy.cpp"
#ifdef FC_USE_VTK_PYTHON
#include <vtkDataSet.h>
#include <vtkPythonUtil.h>
#endif //BUILD_FEM_VTK
#include <vtkDataSet.h>
#include <vtkPythonUtil.h>
#endif // BUILD_FEM_VTK
using namespace Fem;
@@ -71,7 +71,7 @@ PyObject* FemPostObjectPy::getDataSet(PyObject* args)
auto dataset = getFemPostObjectPtr()->getDataSet();
if (dataset) {
PyObject* py_algorithm = vtkPythonUtil::GetObjectFromPointer(dataset);
return Py::new_reference_to(py_algorithm);
return Py::new_reference_to(py_algorithm);
}
return Py_None;
#else

View File

@@ -35,8 +35,8 @@
// clang-format on
#ifdef FC_USE_VTK_PYTHON
#include <vtkPythonUtil.h>
#endif //BUILD_FEM_VTK
#include <vtkPythonUtil.h>
#endif // BUILD_FEM_VTK
using namespace Fem;
@@ -329,7 +329,7 @@ PyObject* FemPostPipelinePy::getOutputAlgorithm(PyObject* args)
auto algorithm = getFemPostPipelinePtr()->getOutputAlgorithm();
PyObject* py_algorithm = vtkPythonUtil::GetObjectFromPointer(algorithm);
return Py::new_reference_to(py_algorithm);
return Py::new_reference_to(py_algorithm);
#else
PyErr_SetString(PyExc_NotImplementedError, "VTK python wrapper not available");
Py_Return;

View File

@@ -213,7 +213,11 @@ TaskPostWidget::TaskPostWidget(Gui::ViewProviderDocumentObject* view,
setWindowIcon(icon);
m_icon = icon;
m_connection = m_object->signalChanged.connect(boost::bind(&TaskPostWidget::handlePropertyChange, this, boost::placeholders::_1, boost::placeholders::_2));
m_connection =
m_object->signalChanged.connect(boost::bind(&TaskPostWidget::handlePropertyChange,
this,
boost::placeholders::_1,
boost::placeholders::_2));
}
TaskPostWidget::~TaskPostWidget()
@@ -404,7 +408,8 @@ void TaskDlgPost::modifyStandardButtons(QDialogButtonBox* box)
}
}
void TaskDlgPost::processCollapsedWidgets() {
void TaskDlgPost::processCollapsedWidgets()
{
for (auto& widget : Content) {
auto* task_box = dynamic_cast<Gui::TaskView::TaskBox*>(widget);
@@ -417,7 +422,7 @@ void TaskDlgPost::processCollapsedWidgets() {
if (!post_widget || !post_widget->initiallyCollapsed()) {
continue;
}
post_widget->setGeometry(QRect(QPoint(0,0), post_widget->sizeHint()));
post_widget->setGeometry(QRect(QPoint(0, 0), post_widget->sizeHint()));
task_box->hideGroupBox();
}
}
@@ -584,7 +589,8 @@ void TaskPostFrames::applyPythonCode()
// we apply the views widgets python code
}
bool TaskPostFrames::initiallyCollapsed() {
bool TaskPostFrames::initiallyCollapsed()
{
return (ui->FrameTable->rowCount() == 0);
}

View File

@@ -157,7 +157,8 @@ public:
virtual void apply() {};
// returns if the widget shall be collapsed when opening the task dialog
virtual bool initiallyCollapsed() {
virtual bool initiallyCollapsed()
{
return false;
};

View File

@@ -48,9 +48,7 @@ using namespace Gui;
// box to handle data extractions
TaskPostExtraction::TaskPostExtraction(ViewProviderFemPostObject* view, QWidget* parent)
: TaskPostWidget(view,
Gui::BitmapFactory().pixmap("FEM_PostHistogram"), QString(),
parent)
: TaskPostWidget(view, Gui::BitmapFactory().pixmap("FEM_PostHistogram"), QString(), parent)
{
// we load the python implementation, and try to get the widget from it, to add
// directly our widget
@@ -73,7 +71,7 @@ TaskPostExtraction::TaskPostExtraction(ViewProviderFemPostObject* view, QWidget*
m_panel = Py::Object(method.apply(args));
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.reportException();
}
@@ -97,7 +95,8 @@ TaskPostExtraction::TaskPostExtraction(ViewProviderFemPostObject* view, QWidget*
Base::Console().error("Unable to import data extraction widget\n");
};
TaskPostExtraction::~TaskPostExtraction() {
TaskPostExtraction::~TaskPostExtraction()
{
Base::PyGILStateLocker lock;
try {
@@ -123,7 +122,7 @@ void TaskPostExtraction::onPostDataChanged(Fem::FemPostObject* obj)
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.reportException();
}
};
@@ -139,7 +138,7 @@ bool TaskPostExtraction::isGuiTaskOnly()
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.reportException();
}
@@ -156,7 +155,7 @@ void TaskPostExtraction::apply()
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.reportException();
}
}
@@ -172,7 +171,7 @@ bool TaskPostExtraction::initiallyCollapsed()
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.reportException();
}

View File

@@ -218,7 +218,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
#ifdef FC_USE_VTK_PYTHON
<< "FEM_PostVisualization"
#endif
;
;
#endif
Gui::ToolBarItem* utils = new Gui::ToolBarItem(root);
@@ -374,7 +374,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
#ifdef FC_USE_VTK_PYTHON
<< "FEM_PostVisualization"
#endif
;
;
#endif
Gui::MenuItem* utils = new Gui::MenuItem;

View File

@@ -83,6 +83,7 @@ class FemWorkbench(Workbench):
# check vtk version to potentially find missmatchs
if "BUILD_FEM_VTK_PYTHON" in FreeCAD.__cmake__:
from femguiutils.vtk_module_handling import vtk_module_handling
vtk_module_handling()
def GetClassName(self):

View File

@@ -696,6 +696,7 @@ def makePostLineplot(doc, name="Lineplot"):
post_lineplot.PostLineplot(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_lineplot
view_post_lineplot.VPPostLineplot(obj.ViewObject)
return obj
@@ -710,6 +711,7 @@ def makePostLineplotFieldData(doc, name="FieldData2D"):
post_lineplot.PostLineplotFieldData(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_lineplot
view_post_lineplot.VPPostLineplotFieldData(obj.ViewObject)
return obj
@@ -724,6 +726,7 @@ def makePostLineplotIndexOverFrames(doc, name="IndexOverFrames2D"):
post_lineplot.PostLineplotIndexOverFrames(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_lineplot
view_post_lineplot.VPPostLineplotIndexOverFrames(obj.ViewObject)
return obj
@@ -738,6 +741,7 @@ def makePostHistogram(doc, name="Histogram"):
post_histogram.PostHistogram(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_histogram
view_post_histogram.VPPostHistogram(obj.ViewObject)
return obj
@@ -752,6 +756,7 @@ def makePostHistogramFieldData(doc, name="FieldData1D"):
post_histogram.PostHistogramFieldData(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_histogram
view_post_histogram.VPPostHistogramFieldData(obj.ViewObject)
return obj
@@ -766,6 +771,7 @@ def makePostHistogramIndexOverFrames(doc, name="IndexOverFrames1D"):
post_histogram.PostHistogramIndexOverFrames(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_histogram
view_post_histogram.VPPostHistogramIndexOverFrames(obj.ViewObject)
return obj
@@ -780,6 +786,7 @@ def makePostTable(doc, name="Table"):
post_table.PostTable(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_table
view_post_table.VPPostTable(obj.ViewObject)
return obj
@@ -794,6 +801,7 @@ def makePostTableFieldData(doc, name="FieldData1D"):
post_table.PostTableFieldData(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_table
view_post_table.VPPostTableFieldData(obj.ViewObject)
return obj
@@ -808,6 +816,7 @@ def makePostTableIndexOverFrames(doc, name="IndexOverFrames1D"):
post_table.PostTableIndexOverFrames(obj)
if FreeCAD.GuiUp:
from femviewprovider import view_post_table
view_post_table.VPPostTableIndexOverFrames(obj.ViewObject)
return obj

View File

@@ -1231,6 +1231,7 @@ class _PostFilterGlyph(CommandManager):
self.is_active = "with_vtk_selresult"
self.do_activated = "add_filter_set_edit"
# the string in add command will be the page name on FreeCAD wiki
FreeCADGui.addCommand("FEM_Analysis", _Analysis())
FreeCADGui.addCommand("FEM_ClippingPlaneAdd", _ClippingPlaneAdd())
@@ -1295,4 +1296,5 @@ if "BUILD_FEM_VTK_PYTHON" in FreeCAD.__cmake__:
import femobjects.post_table
from femguiutils import post_visualization
post_visualization.setup_commands("FEM_PostVisualization")

View File

@@ -381,6 +381,7 @@ class CommandManager:
# check if we should use python filter
from femguiutils.vtk_module_handling import vtk_compatibility_abort
if vtk_compatibility_abort(True):
return

View File

@@ -37,8 +37,7 @@ from vtkmodules.vtkCommonCore import vtkVersion
from vtkmodules.vtkCommonDataModel import vtkTable
from vtkmodules.vtkFiltersGeneral import vtkSplitColumnComponents
if vtkVersion.GetVTKMajorVersion() > 9 and \
vtkVersion.GetVTKMinorVersion() > 3:
if vtkVersion.GetVTKMajorVersion() > 9 and vtkVersion.GetVTKMinorVersion() > 3:
from vtkmodules.vtkFiltersCore import vtkAttributeDataToTableFilter
else:
from vtkmodules.vtkInfovisCore import vtkDataObjectToTable
@@ -51,6 +50,7 @@ import femobjects.base_fempostextractors as extr
from femtaskpanels.base_fempostpanel import _BasePostTaskPanel
from . import extract_link_view
ExtractLinkView = extract_link_view.ExtractLinkView
@@ -83,11 +83,10 @@ class DataExtraction(_BasePostTaskPanel):
# setup the extraction widget
self._extraction_view = ExtractLinkView(self.Object, True, self)
self.widget.layout().addSpacing(self.widget.Data.size().height()/3)
self.widget.layout().addSpacing(self.widget.Data.size().height() / 3)
self.widget.layout().addWidget(self._extraction_view)
self._extraction_view.repopulate()
@QtCore.Slot()
def showData(self):
@@ -96,7 +95,7 @@ class DataExtraction(_BasePostTaskPanel):
widget = vtk_table_view.VtkTableView(self.data_model)
layout = QtGui.QVBoxLayout()
layout.addWidget(widget)
layout.setContentsMargins(0,0,0,0)
layout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(layout)
dialog.resize(1500, 900)
@@ -110,7 +109,7 @@ class DataExtraction(_BasePostTaskPanel):
widget = vtk_table_view.VtkTableView(self.summary_model)
layout = QtGui.QVBoxLayout()
layout.addWidget(widget)
layout.setContentsMargins(0,0,0,0)
layout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(layout)
dialog.resize(600, 900)
@@ -126,8 +125,7 @@ class DataExtraction(_BasePostTaskPanel):
if not algo:
self.data_model.setTable(vtkTable())
if vtkVersion.GetVTKMajorVersion() > 9 and \
vtkVersion.GetVTKMinorVersion() > 3:
if vtkVersion.GetVTKMajorVersion() > 9 and vtkVersion.GetVTKMinorVersion() > 3:
filter = vtkAttributeDataToTableFilter()
else:
filter = vtkDataObjectToTable()

View File

@@ -44,6 +44,7 @@ translate = FreeCAD.Qt.translate
# a model showing available visualizations and possible extractions
# #################################################################
def build_new_visualization_tree_model():
# model that shows all options to create new visualizations
@@ -67,6 +68,7 @@ def build_new_visualization_tree_model():
return model
def build_add_to_visualization_tree_model():
# model that shows all possible visualization objects to add data to
@@ -92,7 +94,9 @@ def build_add_to_visualization_tree_model():
for ext in visualizations[vis_type].extractions:
icon = FreeCADGui.getIcon(ext.icon)
name = ext.name.removeprefix(vis_type)
ext_item = QtGui.QStandardItem(icon, translate("FEM", "Add {}").format(name))
ext_item = QtGui.QStandardItem(
icon, translate("FEM", "Add {}").format(name)
)
ext_item.setFlags(QtGui.Qt.ItemIsEnabled)
ext_item.setData(ext)
vis_item.appendRow(ext_item)
@@ -102,10 +106,13 @@ def build_add_to_visualization_tree_model():
return model
def build_post_object_item(post_object, extractions, vis_type):
# definitely build a item and add the extractions
post_item = QtGui.QStandardItem(post_object.ViewObject.Icon, translate("FEM", "From {}").format(post_object.Label))
post_item = QtGui.QStandardItem(
post_object.ViewObject.Icon, translate("FEM", "From {}").format(post_object.Label)
)
post_item.setFlags(QtGui.Qt.ItemIsEnabled)
post_item.setData(post_object)
@@ -150,9 +157,11 @@ def build_add_from_data_tree_model(vis_type):
return model
# implementation of GUI and its functionality
# ###########################################
class _ElideToolButton(QtGui.QToolButton):
# tool button that elides its text, and left align icon and text
@@ -174,7 +183,7 @@ class _ElideToolButton(QtGui.QToolButton):
button_size = super().sizeHint()
icn_size = self.iconSize()
min_margin = max((button_size - icn_size).height(), 6)
return QtCore.QSize(self.iconSize().width()+10, icn_size.height() + min_margin)
return QtCore.QSize(self.iconSize().width() + 10, icn_size.height() + min_margin)
def paintEvent(self, event):
@@ -190,11 +199,10 @@ class _ElideToolButton(QtGui.QToolButton):
margin = (self.height() - self.iconSize().height()) / 2
icn_width = self.iconSize().width()
if self._icon.isNull():
icn_width = 0;
icn_width = 0
fm = self.fontMetrics()
txt_size = self.width() - icn_width - 2*margin
txt_size = self.width() - icn_width - 2 * margin
if not self._icon.isNull():
# we add the margin between icon and text
txt_size -= margin
@@ -205,7 +213,7 @@ class _ElideToolButton(QtGui.QToolButton):
xpos = margin
if not self._icon.isNull() and txt_size < txt_min:
# center icon
xpos = self.width()/2 - self.iconSize().width()/2
xpos = self.width() / 2 - self.iconSize().width() / 2
if not self._icon.isNull():
match type(self._icon):
@@ -213,10 +221,12 @@ class _ElideToolButton(QtGui.QToolButton):
painter.drawPixmap(xpos, margin, self._icon.scaled(self.iconSize()))
xpos += self.iconSize().width()
case QtGui.QIcon:
self._icon.paint(painter, QtCore.QRect(QtCore.QPoint(margin, margin), self.iconSize()))
self._icon.paint(
painter, QtCore.QRect(QtCore.QPoint(margin, margin), self.iconSize())
)
xpos += self.iconSize().width()
xpos += margin # the margin to the text
xpos += margin # the margin to the text
if txt_size >= txt_min:
text = fm.elidedText(self._text, QtGui.Qt.ElideMiddle, txt_size)
@@ -227,7 +237,7 @@ class _ElideToolButton(QtGui.QToolButton):
class _TreeChoiceButton(QtGui.QToolButton):
selection = QtCore.Signal(object,object)
selection = QtCore.Signal(object, object)
def __init__(self, model):
super().__init__()
@@ -254,9 +264,10 @@ class _TreeChoiceButton(QtGui.QToolButton):
self.popup = QtGui.QWidgetAction(self)
self.popup.setDefaultWidget(self.tree_view)
self.setPopupMode(QtGui.QToolButton.InstantPopup)
self.addAction(self.popup);
self.addAction(self.popup)
QtCore.Slot(QtCore.QModelIndex)
def selectIndex(self, index):
item = self.model.itemFromIndex(index)
@@ -274,6 +285,7 @@ class _TreeChoiceButton(QtGui.QToolButton):
# check if we should be disabled
self.setEnabled(bool(model.rowCount()))
class _SettingsPopup(QtGui.QMenu):
close = QtCore.Signal()
@@ -297,7 +309,7 @@ class _SettingsPopup(QtGui.QMenu):
widget.setLayout(vbox)
vbox2 = QtGui.QVBoxLayout()
vbox2.setContentsMargins(0,0,0,0)
vbox2.setContentsMargins(0, 0, 0, 0)
vbox2.addWidget(widget)
self.setLayout(vbox2)
@@ -321,7 +333,7 @@ class _SettingsPopup(QtGui.QMenu):
class _SummaryWidget(QtGui.QWidget):
delete = QtCore.Signal(object, object) # to delete: document object, summary widget
delete = QtCore.Signal(object, object) # to delete: document object, summary widget
def __init__(self, st_object, extractor, post_dialog):
super().__init__()
@@ -335,17 +347,16 @@ class _SummaryWidget(QtGui.QWidget):
# build the UI
hbox = QtGui.QHBoxLayout()
hbox.setContentsMargins(6,0,6,0)
hbox.setContentsMargins(6, 0, 6, 0)
hbox.setSpacing(2)
self.extrButton = self._button(extractor.ViewObject.Icon, extr_label)
self.viewButton = self._button(extr_repr[0], extr_repr[1], 1)
size = self.viewButton.iconSize()
size.setWidth(size.width()*2)
size.setWidth(size.width() * 2)
self.viewButton.setIconSize(size)
if st_object:
self.stButton = self._button(st_object.ViewObject.Icon, st_object.Label)
hbox.addWidget(self.stButton)
@@ -357,7 +368,9 @@ class _SummaryWidget(QtGui.QWidget):
self.viewButton.hide()
self.warning = QtGui.QLabel(self)
self.warning.full_text = translate("FEM", "{}: Data source not available").format(extractor.Label)
self.warning.full_text = translate("FEM", "{}: Data source not available").format(
extractor.Label
)
hbox.addWidget(self.warning)
self.rmButton = QtGui.QToolButton(self)
@@ -371,16 +384,16 @@ class _SummaryWidget(QtGui.QWidget):
# add the separation line
vbox = QtGui.QVBoxLayout()
vbox.setContentsMargins(0,0,0,0)
vbox.setContentsMargins(0, 0, 0, 0)
vbox.setSpacing(5)
vbox.addItem(hbox)
self.frame = QtGui.QFrame(self)
self.frame.setFrameShape(QtGui.QFrame.HLine);
self.frame.setFrameShape(QtGui.QFrame.HLine)
vbox.addWidget(self.frame)
policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
self.setSizePolicy(policy)
#self.setMinimumSize(self.extrButton.sizeHint()+self.frame.sizeHint()*3)
# self.setMinimumSize(self.extrButton.sizeHint()+self.frame.sizeHint()*3)
self.setLayout(vbox)
# connect actions. We add functions to widget, as well as the data we need,
@@ -393,8 +406,7 @@ class _SummaryWidget(QtGui.QWidget):
self.rmButton.clicked.connect(self.deleteTriggered)
# make sure initial drawing happened
#self._redraw()
# self._redraw()
def _button(self, icon, text, stretch=2):
@@ -408,7 +420,6 @@ class _SummaryWidget(QtGui.QWidget):
btn.setSizePolicy(policy)
return btn
@QtCore.Slot()
def showVisualization(self):
if vis.is_visualization_object(self._st_object):
@@ -426,14 +437,18 @@ class _SummaryWidget(QtGui.QWidget):
# very weird values. Hence we build the coords of the widget
# ourself
summary = dialog.parent() # == self
summary = dialog.parent() # == self
base_widget = summary.parent()
viewport = summary.parent()
scroll = viewport.parent()
top_left = summary.geometry().topLeft() + base_widget.geometry().topLeft() + viewport.geometry().topLeft()
delta = (summary.width() - dialog.size().width())/2
local_point = QtCore.QPoint(top_left.x()+delta, top_left.y()+summary.height())
top_left = (
summary.geometry().topLeft()
+ base_widget.geometry().topLeft()
+ viewport.geometry().topLeft()
)
delta = (summary.width() - dialog.size().width()) / 2
local_point = QtCore.QPoint(top_left.x() + delta, top_left.y() + summary.height())
global_point = scroll.mapToGlobal(local_point)
dialog.setGeometry(QtCore.QRect(global_point, dialog.sizeHint()))
@@ -485,7 +500,6 @@ class _SummaryWidget(QtGui.QWidget):
self.extrButton.setToolTip(extr_label)
class ExtractLinkView(QtGui.QWidget):
def __init__(self, obj, is_source, post_dialog):
@@ -506,7 +520,7 @@ class ExtractLinkView(QtGui.QWidget):
self._scroll_view.setWidgetResizable(True)
self._scroll_widget = QtGui.QWidget(self._scroll_view)
vbox = QtGui.QVBoxLayout()
vbox.setContentsMargins(0,6,0,0)
vbox.setContentsMargins(0, 6, 0, 0)
vbox.addStretch()
self._scroll_widget.setLayout(vbox)
self._scroll_view.setWidget(self._scroll_widget)
@@ -541,7 +555,7 @@ class ExtractLinkView(QtGui.QWidget):
hbox.addWidget(self._add)
vbox = QtGui.QVBoxLayout()
vbox.setContentsMargins(0,0,0,0)
vbox.setContentsMargins(0, 0, 0, 0)
vbox.addItem(hbox)
vbox.addWidget(self._scroll_view)
@@ -616,7 +630,8 @@ class ExtractLinkView(QtGui.QWidget):
return None
QtCore.Slot(object, object) # visualization data, extraction data
QtCore.Slot(object, object) # visualization data, extraction data
def newVisualization(self, vis_data, ext_data):
FreeCADGui.addModule(vis_data.module)
@@ -630,17 +645,13 @@ class ExtractLinkView(QtGui.QWidget):
analysis = self._find_parent_analysis(self._object)
if analysis:
FreeCADGui.doCommand(
f"FreeCAD.ActiveDocument.{analysis.Name}.addObject(visualization)"
)
FreeCADGui.doCommand(f"FreeCAD.ActiveDocument.{analysis.Name}.addObject(visualization)")
# create extraction and add it
FreeCADGui.doCommand(
f"extraction = {ext_data.module}.{ext_data.factory}(FreeCAD.ActiveDocument)"
)
FreeCADGui.doCommand(
f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}"
)
FreeCADGui.doCommand(f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}")
# default values: color
color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property()
if color_prop:
@@ -648,15 +659,13 @@ class ExtractLinkView(QtGui.QWidget):
f"extraction.ViewObject.{color_prop} = visualization.ViewObject.Proxy.get_next_default_color()"
)
FreeCADGui.doCommand(
f"visualization.addObject(extraction)"
)
FreeCADGui.doCommand(f"visualization.addObject(extraction)")
self._post_dialog._recompute()
self.repopulate()
QtCore.Slot(object, object) # visualization object, extraction data
QtCore.Slot(object, object) # visualization object, extraction data
def addExtractionToVisualization(self, vis_obj, ext_data):
FreeCADGui.addModule(ext_data.module)
@@ -666,9 +675,7 @@ class ExtractLinkView(QtGui.QWidget):
FreeCADGui.doCommand(
f"extraction = {ext_data.module}.{ext_data.factory}(FreeCAD.ActiveDocument)"
)
FreeCADGui.doCommand(
f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}"
)
FreeCADGui.doCommand(f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}")
# default values: color
color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property()
@@ -677,14 +684,13 @@ class ExtractLinkView(QtGui.QWidget):
f"extraction.ViewObject.{color_prop} = (Gui.ActiveDocument.{vis_obj.Name}.Proxy.get_next_default_color())"
)
FreeCADGui.doCommand(
f"App.ActiveDocument.{vis_obj.Name}.addObject(extraction)"
)
FreeCADGui.doCommand(f"App.ActiveDocument.{vis_obj.Name}.addObject(extraction)")
self._post_dialog._recompute()
self.repopulate()
QtCore.Slot(object, object) # post object, extraction data
QtCore.Slot(object, object) # post object, extraction data
def addExtractionToPostObject(self, post_obj, ext_data):
FreeCADGui.addModule(ext_data.module)
@@ -694,9 +700,7 @@ class ExtractLinkView(QtGui.QWidget):
FreeCADGui.doCommand(
f"extraction = {ext_data.module}.{ext_data.factory}(FreeCAD.ActiveDocument)"
)
FreeCADGui.doCommand(
f"extraction.Source = FreeCAD.ActiveDocument.{post_obj.Name}"
)
FreeCADGui.doCommand(f"extraction.Source = FreeCAD.ActiveDocument.{post_obj.Name}")
# default values for color
color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property()
@@ -705,10 +709,7 @@ class ExtractLinkView(QtGui.QWidget):
f"extraction.ViewObject.{color_prop} = Gui.ActiveDocument.{self._object.Name}.Proxy.get_next_default_color()"
)
FreeCADGui.doCommand(
f"App.ActiveDocument.{self._object.Name}.addObject(extraction)"
)
FreeCADGui.doCommand(f"App.ActiveDocument.{self._object.Name}.addObject(extraction)")
self._post_dialog._recompute()
self.repopulate()

View File

@@ -45,6 +45,7 @@ import FreeCAD
_registry = {}
@dataclass
class _Extraction:
@@ -55,6 +56,7 @@ class _Extraction:
module: str
factory: str
@dataclass
class _Visualization:
@@ -64,6 +66,7 @@ class _Visualization:
factory: str
extractions: list[_Extraction]
# Register a visualization by type, icon and factory function
def register_visualization(visualization_type, icon, module, factory):
if visualization_type in _registry:
@@ -71,7 +74,10 @@ def register_visualization(visualization_type, icon, module, factory):
_registry[visualization_type] = _Visualization(visualization_type, icon, module, factory, [])
def register_extractor(visualization_type, extraction_type, icon, dimension, etype, module, factory):
def register_extractor(
visualization_type, extraction_type, icon, dimension, etype, module, factory
):
if not visualization_type in _registry:
raise ValueError("visualization not registered yet")
@@ -79,6 +85,7 @@ def register_extractor(visualization_type, extraction_type, icon, dimension, ety
extraction = _Extraction(extraction_type, icon, dimension, etype, module, factory)
_registry[visualization_type].extractions.append(extraction)
def get_registered_visualizations():
return copy.deepcopy(_registry)
@@ -86,6 +93,7 @@ def get_registered_visualizations():
def _to_command_name(name):
return "FEM_PostVisualization" + name
class _VisualizationGroupCommand:
def GetCommands(self):
@@ -97,14 +105,19 @@ class _VisualizationGroupCommand:
return 0
def GetResources(self):
return { 'MenuText': QtCore.QT_TRANSLATE_NOOP("FEM", 'Data Visualizations'),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("FEM", 'Different visualizations to show post processing data in')}
return {
"MenuText": QtCore.QT_TRANSLATE_NOOP("FEM", "Data Visualizations"),
"ToolTip": QtCore.QT_TRANSLATE_NOOP(
"FEM", "Different visualizations to show post processing data in"
),
}
def IsActive(self):
if not FreeCAD.ActiveDocument:
return False
import FemGui
return bool(FemGui.getActiveAnalysis())
@@ -120,12 +133,12 @@ class _VisualizationCommand:
tooltip = f"Create a {self._visualization_type} post processing data visualization"
return {
"Pixmap": vis.icon,
"MenuText": QtCore.QT_TRANSLATE_NOOP(cmd, "Create {}".format(self._visualization_type)),
"Accel": "",
"ToolTip": QtCore.QT_TRANSLATE_NOOP(cmd, tooltip),
"CmdType": "AlterDoc"
}
"Pixmap": vis.icon,
"MenuText": QtCore.QT_TRANSLATE_NOOP(cmd, "Create {}".format(self._visualization_type)),
"Accel": "",
"ToolTip": QtCore.QT_TRANSLATE_NOOP(cmd, tooltip),
"CmdType": "AlterDoc",
}
def IsActive(self):
# active analysis available
@@ -133,6 +146,7 @@ class _VisualizationCommand:
return False
import FemGui
return bool(FemGui.getActiveAnalysis())
def Activated(self):
@@ -144,17 +158,12 @@ class _VisualizationCommand:
FreeCADGui.addModule(vis.module)
FreeCADGui.addModule("FemGui")
FreeCADGui.doCommand(
f"obj = {vis.module}.{vis.factory}(FreeCAD.ActiveDocument)"
)
FreeCADGui.doCommand(
f"FemGui.getActiveAnalysis().addObject(obj)"
)
FreeCADGui.doCommand(f"obj = {vis.module}.{vis.factory}(FreeCAD.ActiveDocument)")
FreeCADGui.doCommand(f"FemGui.getActiveAnalysis().addObject(obj)")
FreeCADGui.Selection.clearSelection()
FreeCADGui.doCommand(
"FreeCADGui.ActiveDocument.setEdit(obj)"
)
FreeCADGui.doCommand("FreeCADGui.ActiveDocument.setEdit(obj)")
def setup_commands(toplevel_name):
# creates all visualization commands and registers them. The

View File

@@ -39,13 +39,14 @@ from vtkmodules.vtkIOCore import vtkDelimitedTextWriter
translate = FreeCAD.Qt.translate
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, header_names = None):
def __init__(self, header_names=None):
super().__init__()
self._table = None
if header_names:
@@ -53,7 +54,7 @@ class VtkTableModel(QtCore.QAbstractTableModel):
else:
self._header = {}
def setTable(self, table, header_names = None):
def setTable(self, table, header_names=None):
self.beginResetModel()
self._table = table
if header_names:
@@ -105,6 +106,7 @@ class VtkTableModel(QtCore.QAbstractTableModel):
def getTable(self):
return self._table
class VtkTableSummaryModel(QtCore.QAbstractTableModel):
# Simple model showing a summary of the table.
# Only supports single component columns
@@ -126,7 +128,7 @@ class VtkTableSummaryModel(QtCore.QAbstractTableModel):
return self._table.GetNumberOfColumns()
def columnCount(self, index):
return 2 # min, max
return 2 # min, max
def data(self, index, role):
@@ -143,7 +145,7 @@ class VtkTableSummaryModel(QtCore.QAbstractTableModel):
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return ["Min","Max"][section]
return ["Min", "Max"][section]
if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
return self._table.GetColumnName(section)
@@ -162,7 +164,7 @@ class VtkTableView(QtGui.QWidget):
self.model = model
layout = QtGui.QVBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# start with the toolbar
@@ -177,7 +179,9 @@ class VtkTableView(QtGui.QWidget):
copy_action.triggered.connect(self.copyToClipboard)
copy_action.setIcon(FreeCADGui.getIcon("edit-copy"))
shortcut = QtGui.QKeySequence(QtGui.QKeySequence.Copy)
copy_action.setToolTip(translate("FEM", "Copy selection to clipboard ({})".format(shortcut.toString())))
copy_action.setToolTip(
translate("FEM", "Copy selection to clipboard ({})".format(shortcut.toString()))
)
copy_action.setShortcut(shortcut)
self.toolbar.addAction(copy_action)
@@ -205,15 +209,19 @@ class VtkTableView(QtGui.QWidget):
@QtCore.Slot(bool)
def exportCsv(self, state):
file_path, filter = QtGui.QFileDialog.getSaveFileName(None, translate("FEM", "Save as csv file"), "", "CSV (*.csv)")
file_path, filter = QtGui.QFileDialog.getSaveFileName(
None, translate("FEM", "Save as csv file"), "", "CSV (*.csv)"
)
if not file_path:
FreeCAD.Console.PrintMessage(translate("FEM", "CSV file export aborted: no filename selected"))
FreeCAD.Console.PrintMessage(
translate("FEM", "CSV file export aborted: no filename selected")
)
return
writer = vtkDelimitedTextWriter()
writer.SetFileName(file_path)
writer.SetInputData(self.model.getTable());
writer.Write();
writer.SetInputData(self.model.getTable())
writer.Write()
@QtCore.Slot()
def copyToClipboard(self):
@@ -228,19 +236,18 @@ class VtkTableView(QtGui.QWidget):
previous = selection.pop(0)
for current in selection:
data = self.model.data(previous, QtCore.Qt.DisplayRole);
data = self.model.data(previous, QtCore.Qt.DisplayRole)
copy_table += str(data)
if current.row() != previous.row():
copy_table += '\n'
copy_table += "\n"
else:
copy_table += '\t'
copy_table += "\t"
previous = current
copy_table += str(self.model.data(selection[-1], QtCore.Qt.DisplayRole))
copy_table += '\n'
copy_table += "\n"
clipboard = QtGui.QApplication.instance().clipboard()
clipboard.setText(copy_table)

View File

@@ -36,22 +36,26 @@ from vtkmodules.vtkCommonDataModel import vtkTable
from PySide.QtCore import QT_TRANSLATE_NOOP
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
# helper functions
# ################
def is_extractor_object(obj):
if not hasattr(obj, "Proxy"):
return False
return hasattr(obj.Proxy, "ExtractionType")
def get_extraction_type(obj):
# returns the extractor type string, or throws exception if
# not a extractor
return obj.Proxy.ExtractionType
def get_extraction_dimension(obj):
# returns the extractor dimension string, or throws exception if
# not a extractor
@@ -104,7 +108,6 @@ class Extractor(base_fempythonobject.BaseFemPythonObject):
FreeCAD.Console.PrintWarning("Invalid object: Line source must be FemPostObject")
obj.Source = None
def get_vtk_table(self, obj):
if not obj.DataTable:
obj.DataTable = vtkTable()
@@ -135,7 +138,6 @@ class Extractor1D(Extractor):
def __init__(self, obj):
super().__init__(obj)
def _get_properties(self):
prop = [
_PropHelper(
@@ -149,14 +151,15 @@ class Extractor1D(Extractor):
type="App::PropertyEnumeration",
name="XComponent",
group="X Data",
doc=QT_TRANSLATE_NOOP("FEM", "Which part of the X field vector to use for the X axis"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Which part of the X field vector to use for the X axis"
),
value=[],
),
]
return super()._get_properties() + prop
def onChanged(self, obj, prop):
super().onChanged(obj, prop)
@@ -213,7 +216,7 @@ class Extractor1D(Extractor):
if array.GetNumberOfComponents() == 1:
table.AddColumn(array)
else:
component_array = vtkDoubleArray();
component_array = vtkDoubleArray()
component_array.SetNumberOfComponents(1)
component_array.SetNumberOfTuples(array.GetNumberOfTuples())
c_idx = obj.getEnumerationsOfProperty("XComponent").index(obj.XComponent)
@@ -233,7 +236,7 @@ class Extractor1D(Extractor):
array.SetNumberOfTuples(num)
array.SetNumberOfComponents(1)
for i in range(num):
array.SetValue(i,i)
array.SetValue(i, i)
case "Position":
@@ -266,6 +269,7 @@ class Extractor1D(Extractor):
return label
class Extractor2D(Extractor1D):
ExtractionDimension = "2D"
@@ -273,7 +277,6 @@ class Extractor2D(Extractor1D):
def __init__(self, obj):
super().__init__(obj)
def _get_properties(self):
prop = [
_PropHelper(
@@ -287,14 +290,15 @@ class Extractor2D(Extractor1D):
type="App::PropertyEnumeration",
name="YComponent",
group="Y Data",
doc=QT_TRANSLATE_NOOP("FEM", "Which part of the Y field vector to use for the Y axis"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Which part of the Y field vector to use for the Y axis"
),
value=[],
),
]
return super()._get_properties() + prop
def onChanged(self, obj, prop):
super().onChanged(obj, prop)
@@ -348,7 +352,7 @@ class Extractor2D(Extractor1D):
if array.GetNumberOfComponents() == 1:
table.AddColumn(array)
else:
component_array = vtkDoubleArray();
component_array = vtkDoubleArray()
component_array.SetNumberOfComponents(1)
component_array.SetNumberOfTuples(array.GetNumberOfTuples())
c_idx = obj.getEnumerationsOfProperty("YComponent").index(obj.YComponent)

View File

@@ -38,6 +38,7 @@ from . import base_fempostextractors
# helper functions
# ################
def is_visualization_object(obj):
if not obj:
return False
@@ -71,27 +72,23 @@ def is_visualization_extractor_type(obj, vistype):
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():
if not prop.name in pl:
prop.add_to_object(obj)
def _get_properties(self):
# override if subclass wants to add additional properties
@@ -106,14 +103,12 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject):
]
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
@@ -123,13 +118,14 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject):
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")
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
@@ -144,7 +140,9 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject):
# 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")
FreeCAD.Console.PrintWarning(
f"{child.Label} has data, but no Source object. Will be ignored"
)
continue
c_table = child.Table
@@ -159,18 +157,16 @@ class PostVisualization(base_fempythonobject.BaseFemPythonObject):
else:
array.SetNumberOfComponents(c_array.GetNumberOfComponents())
array.SetNumberOfTuples(rows)
array.Fill(0) # so that all non-used entries are set to 0
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

View File

@@ -33,6 +33,7 @@ import FreeCAD
from . import base_fempostextractors
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
from vtkmodules.vtkCommonCore import vtkDoubleArray
@@ -53,11 +54,14 @@ class PostFieldData1D(base_fempostextractors.Extractor1D):
super().__init__(obj)
def _get_properties(self):
prop =[ _PropHelper(
prop = [
_PropHelper(
type="App::PropertyBool",
name="ExtractFrames",
group="Multiframe",
doc=QT_TRANSLATE_NOOP("FEM", "Specify if the field shall be extracted for every available frame"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Specify if the field shall be extracted for every available frame"
),
value=False,
),
]
@@ -77,14 +81,16 @@ class PostFieldData1D(base_fempostextractors.Extractor1D):
obj.Table = table
return
timesteps=[]
timesteps = []
if obj.ExtractFrames:
# check if we have timesteps
info = obj.Source.getOutputAlgorithm().GetOutputInformation(0)
if info.Has(vtkStreamingDemandDrivenPipeline.TIME_STEPS()):
timesteps = info.Get(vtkStreamingDemandDrivenPipeline.TIME_STEPS())
else:
FreeCAD.Console.PrintWarning("No frames available in data, ignoring \"ExtractFrames\" property")
FreeCAD.Console.PrintWarning(
'No frames available in data, ignoring "ExtractFrames" property'
)
if not timesteps:
# get the dataset and extract the correct array
@@ -124,11 +130,14 @@ class PostIndexOverFrames1D(base_fempostextractors.Extractor1D):
super().__init__(obj)
def _get_properties(self):
prop =[_PropHelper(
prop = [
_PropHelper(
type="App::PropertyInteger",
name="Index",
group="X Data",
doc=QT_TRANSLATE_NOOP("FEM", "Specify for which index the data should be extracted"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Specify for which index the data should be extracted"
),
value=0,
),
]
@@ -154,7 +163,6 @@ class PostIndexOverFrames1D(base_fempostextractors.Extractor1D):
if info.Has(vtkStreamingDemandDrivenPipeline.TIME_STEPS()):
timesteps = info.Get(vtkStreamingDemandDrivenPipeline.TIME_STEPS())
algo = obj.Source.getOutputAlgorithm()
frame_array = vtkDoubleArray()
idx = obj.Index
@@ -168,8 +176,10 @@ class PostIndexOverFrames1D(base_fempostextractors.Extractor1D):
array = self._x_array_from_dataset(obj, dataset, copy=False)
# safeguard for invalid access
if idx < 0 or array.GetNumberOfTuples()-1 < idx:
raise Exception(f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}")
if idx < 0 or array.GetNumberOfTuples() - 1 < idx:
raise Exception(
f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}"
)
if not setup:
frame_array.SetNumberOfComponents(array.GetNumberOfComponents())
@@ -183,14 +193,15 @@ class PostIndexOverFrames1D(base_fempostextractors.Extractor1D):
array = self._x_array_from_dataset(obj, dataset, copy=False)
# safeguard for invalid access
if idx < 0 or array.GetNumberOfTuples()-1 < idx:
raise Exception(f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}")
if idx < 0 or array.GetNumberOfTuples() - 1 < idx:
raise Exception(
f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}"
)
frame_array.SetNumberOfComponents(array.GetNumberOfComponents())
frame_array.SetNumberOfTuples(1)
frame_array.SetTuple(0, idx, array)
if frame_array.GetNumberOfComponents() > 1:
frame_array.SetName(f"{obj.XField} ({obj.XComponent}) @Idx {obj.Index}")
else:

View File

@@ -33,6 +33,7 @@ import FreeCAD
from . import base_fempostextractors
from . import base_fempythonobject
_PropHelper = base_fempythonobject._PropHelper
from vtkmodules.vtkCommonCore import vtkDoubleArray
@@ -53,17 +54,19 @@ class PostFieldData2D(base_fempostextractors.Extractor2D):
super().__init__(obj)
def _get_properties(self):
prop =[ _PropHelper(
prop = [
_PropHelper(
type="App::PropertyBool",
name="ExtractFrames",
group="Multiframe",
doc=QT_TRANSLATE_NOOP("FEM", "Specify if the field shall be extracted for every available frame"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Specify if the field shall be extracted for every available frame"
),
value=False,
),
]
return super()._get_properties() + prop
def execute(self, obj):
# on execution we populate the vtk table
@@ -85,7 +88,9 @@ class PostFieldData2D(base_fempostextractors.Extractor2D):
if info.Has(vtkStreamingDemandDrivenPipeline.TIME_STEPS()):
timesteps = info.Get(vtkStreamingDemandDrivenPipeline.TIME_STEPS())
else:
FreeCAD.Console.PrintWarning("No frames available in data, ignoring \"ExtractFrames\" property")
FreeCAD.Console.PrintWarning(
'No frames available in data, ignoring "ExtractFrames" property'
)
if not timesteps:
# get the dataset and extract the correct array
@@ -140,11 +145,14 @@ class PostIndexOverFrames2D(base_fempostextractors.Extractor2D):
super().__init__(obj)
def _get_properties(self):
prop =[_PropHelper(
prop = [
_PropHelper(
type="App::PropertyInteger",
name="Index",
group="Data",
doc=QT_TRANSLATE_NOOP("FEM", "Specify for which point index the data should be extracted"),
doc=QT_TRANSLATE_NOOP(
"FEM", "Specify for which point index the data should be extracted"
),
value=0,
),
]
@@ -178,7 +186,6 @@ class PostIndexOverFrames2D(base_fempostextractors.Extractor2D):
if info.Has(vtkStreamingDemandDrivenPipeline.TIME_STEPS()):
timesteps = info.Get(vtkStreamingDemandDrivenPipeline.TIME_STEPS())
algo = obj.Source.getOutputAlgorithm()
frame_x_array = vtkDoubleArray()
@@ -198,8 +205,10 @@ class PostIndexOverFrames2D(base_fempostextractors.Extractor2D):
array = self._y_array_from_dataset(obj, dataset, copy=False)
# safeguard for invalid access
if idx < 0 or array.GetNumberOfTuples()-1 < idx:
raise Exception(f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}")
if idx < 0 or array.GetNumberOfTuples() - 1 < idx:
raise Exception(
f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}"
)
if not setup:
frame_y_array.SetNumberOfComponents(array.GetNumberOfComponents())
@@ -211,21 +220,22 @@ class PostIndexOverFrames2D(base_fempostextractors.Extractor2D):
else:
frame_x_array.SetNumberOfTuples(1)
frame_x_array.SetNumberOfComponents(1)
frame_x_array.SetTuple1(0,0)
frame_x_array.SetTuple1(0, 0)
algo.Update()
dataset = algo.GetOutputDataObject(0)
array = self._y_array_from_dataset(obj, dataset, copy=False)
# safeguard for invalid access
if idx < 0 or array.GetNumberOfTuples()-1 < idx:
raise Exception(f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}")
if idx < 0 or array.GetNumberOfTuples() - 1 < idx:
raise Exception(
f"Invalid index: {idx} is not in range 0 - {array.GetNumberOfTuples()-1}"
)
frame_y_array.SetNumberOfComponents(array.GetNumberOfComponents())
frame_y_array.SetNumberOfTuples(1)
frame_y_array.SetTuple(0, idx, array)
frame_x_array.SetName("Frames")
if frame_y_array.GetNumberOfComponents() > 1:
frame_y_array.SetName(f"{obj.YField} ({obj.YComponent}) @Idx {obj.Index}")

View File

@@ -33,6 +33,7 @@ import FreeCAD
# check vtk version to potentially find missmatchs
from femguiutils.vtk_module_handling import vtk_module_handling
vtk_module_handling()
# IMPORTANT: Never import vtk directly. Often vtk is compiled with different QT

View File

@@ -31,6 +31,7 @@ __url__ = "https://www.freecad.org"
# check vtk version to potentially find missmatchs
from femguiutils.vtk_module_handling import vtk_module_handling
vtk_module_handling()
from . import base_fempostextractors
@@ -40,31 +41,35 @@ from . import post_extract1D
from femguiutils import post_visualization
# register visualization and extractors
post_visualization.register_visualization("Histogram",
":/icons/FEM_PostHistogram.svg",
"ObjectsFem",
"makePostHistogram")
post_visualization.register_visualization(
"Histogram", ":/icons/FEM_PostHistogram.svg", "ObjectsFem", "makePostHistogram"
)
post_visualization.register_extractor("Histogram",
"HistogramFieldData",
":/icons/FEM_PostField.svg",
"1D",
"Field",
"ObjectsFem",
"makePostHistogramFieldData")
post_visualization.register_extractor(
"Histogram",
"HistogramFieldData",
":/icons/FEM_PostField.svg",
"1D",
"Field",
"ObjectsFem",
"makePostHistogramFieldData",
)
post_visualization.register_extractor("Histogram",
"HistogramIndexOverFrames",
":/icons/FEM_PostIndex.svg",
"1D",
"Index",
"ObjectsFem",
"makePostHistogramIndexOverFrames")
post_visualization.register_extractor(
"Histogram",
"HistogramIndexOverFrames",
":/icons/FEM_PostIndex.svg",
"1D",
"Index",
"ObjectsFem",
"makePostHistogramIndexOverFrames",
)
# Implementation
# ##############
def is_histogram_extractor(obj):
if not base_fempostextractors.is_extractor_object(obj):
@@ -80,6 +85,7 @@ class PostHistogramFieldData(post_extract1D.PostFieldData1D):
"""
A 1D Field extraction for histograms.
"""
VisualizationType = "Histogram"
@@ -87,6 +93,7 @@ class PostHistogramIndexOverFrames(post_extract1D.PostIndexOverFrames1D):
"""
A 1D index extraction for histogram.
"""
VisualizationType = "Histogram"
@@ -94,13 +101,5 @@ class PostHistogram(base_fempostvisualizations.PostVisualization):
"""
A post processing plot for showing extracted data as histograms
"""
VisualizationType = "Histogram"

View File

@@ -31,6 +31,7 @@ __url__ = "https://www.freecad.org"
# check vtk version to potentially find missmatchs
from femguiutils.vtk_module_handling import vtk_module_handling
vtk_module_handling()
from . import base_fempostextractors
@@ -40,31 +41,35 @@ from . import post_extract2D
from femguiutils import post_visualization
# register visualization and extractors
post_visualization.register_visualization("Lineplot",
":/icons/FEM_PostLineplot.svg",
"ObjectsFem",
"makePostLineplot")
post_visualization.register_visualization(
"Lineplot", ":/icons/FEM_PostLineplot.svg", "ObjectsFem", "makePostLineplot"
)
post_visualization.register_extractor("Lineplot",
"LineplotFieldData",
":/icons/FEM_PostField.svg",
"2D",
"Field",
"ObjectsFem",
"makePostLineplotFieldData")
post_visualization.register_extractor(
"Lineplot",
"LineplotFieldData",
":/icons/FEM_PostField.svg",
"2D",
"Field",
"ObjectsFem",
"makePostLineplotFieldData",
)
post_visualization.register_extractor("Lineplot",
"LineplotIndexOverFrames",
":/icons/FEM_PostIndex.svg",
"2D",
"Index",
"ObjectsFem",
"makePostLineplotIndexOverFrames")
post_visualization.register_extractor(
"Lineplot",
"LineplotIndexOverFrames",
":/icons/FEM_PostIndex.svg",
"2D",
"Index",
"ObjectsFem",
"makePostLineplotIndexOverFrames",
)
# Implementation
# ##############
def is_lineplot_extractor(obj):
if not base_fempostextractors.is_extractor_object(obj):
@@ -80,6 +85,7 @@ class PostLineplotFieldData(post_extract2D.PostFieldData2D):
"""
A 2D Field extraction for lineplot.
"""
VisualizationType = "Lineplot"
@@ -87,15 +93,13 @@ class PostLineplotIndexOverFrames(post_extract2D.PostIndexOverFrames2D):
"""
A 2D index extraction for lineplot.
"""
VisualizationType = "Lineplot"
VisualizationType = "Lineplot"
class PostLineplot(base_fempostvisualizations.PostVisualization):
"""
A post processing plot for showing extracted data as line plots
"""
VisualizationType = "Lineplot"

View File

@@ -31,6 +31,7 @@ __url__ = "https://www.freecad.org"
# check vtk version to potentially find missmatchs
from femguiutils.vtk_module_handling import vtk_module_handling
vtk_module_handling()
from . import base_fempostextractors
@@ -40,31 +41,35 @@ from . import post_extract1D
from femguiutils import post_visualization
# register visualization and extractors
post_visualization.register_visualization("Table",
":/icons/FEM_PostSpreadsheet.svg",
"ObjectsFem",
"makePostTable")
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",
"TableFieldData",
":/icons/FEM_PostField.svg",
"1D",
"Field",
"ObjectsFem",
"makePostTableFieldData",
)
post_visualization.register_extractor("Table",
"TableIndexOverFrames",
":/icons/FEM_PostIndex.svg",
"1D",
"Index",
"ObjectsFem",
"makePostTableIndexOverFrames")
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):
@@ -80,6 +85,7 @@ class PostTableFieldData(post_extract1D.PostFieldData1D):
"""
A 1D Field extraction for tables.
"""
VisualizationType = "Table"
@@ -87,6 +93,7 @@ class PostTableIndexOverFrames(post_extract1D.PostIndexOverFrames1D):
"""
A 1D index extraction for table.
"""
VisualizationType = "Table"
@@ -94,6 +101,5 @@ class PostTable(base_fempostvisualizations.PostVisualization):
"""
A post processing plot for showing extracted data as tables
"""
VisualizationType = "Table"

View File

@@ -53,7 +53,9 @@ class _BasePostTaskPanel(base_femtaskpanel._BaseTaskPanel):
# ##########################
def getStandardButtons(self):
return QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel
return (
QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel
)
def clicked(self, button):
# apply button hit?
@@ -63,8 +65,9 @@ class _BasePostTaskPanel(base_femtaskpanel._BaseTaskPanel):
def open(self):
# open a new transaction if non is open
if not FreeCAD.getActiveTransaction():
FreeCAD.ActiveDocument.openTransaction(translate("FEM", "Edit {}").format(self.obj.Label))
FreeCAD.ActiveDocument.openTransaction(
translate("FEM", "Edit {}").format(self.obj.Label)
)
# Helper functions
# ################
@@ -83,6 +86,3 @@ class _BasePostTaskPanel(base_femtaskpanel._BaseTaskPanel):
cbox.setCurrentText(getattr(obj, prop))
cbox.blockSignals(False)

View File

@@ -52,6 +52,3 @@ class _ExtractorTaskPanel(base_fempostpanel._BasePostTaskPanel):
view.setWindowIcon(obj.ViewObject.Icon)
self.form = [app, view]

View File

@@ -56,7 +56,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
# form made from param and selection widget
self.form = [self.widget, vobj.createDisplayTaskWidget()]
# Setup functions
# ###############

View File

@@ -40,6 +40,7 @@ from femguiutils import vtk_table_view
translate = FreeCAD.Qt.translate
class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
"""
The TaskPanel for editing properties of glyph filter
@@ -68,7 +69,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
self.data_widget.setWindowTitle(translate("FEM", "Histogram data"))
self.data_widget.setWindowIcon(FreeCADGui.getIcon(":/icons/FEM_PostHistogram.svg"))
# histogram parameter widget
self.view_widget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/TaskPostHistogram.ui"
@@ -81,7 +81,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
# form made from param and selection widget
self.form = [self.data_widget, self.view_widget]
# Setup functions
# ###############
@@ -121,12 +120,13 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
self.view_widget.BarWidth.valueChanged.connect(self.barWidthChanged)
self.view_widget.HatchWidth.valueChanged.connect(self.hatchWidthChanged)
QtCore.Slot()
def showPlot(self):
self.obj.ViewObject.Proxy.show_visualization()
QtCore.Slot()
def showTable(self):
# TODO: make data model update when object is recomputed
@@ -137,49 +137,58 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
widget = vtk_table_view.VtkTableView(data_model)
layout = QtGui.QVBoxLayout()
layout.addWidget(widget)
layout.setContentsMargins(0,0,0,0)
layout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(layout)
dialog.resize(1500, 900)
dialog.show()
QtCore.Slot(int)
def binsChanged(self, bins):
self.obj.ViewObject.Bins = bins
QtCore.Slot(int)
def typeChanged(self, idx):
self.obj.ViewObject.Type = idx
QtCore.Slot(bool)
def comulativeChanged(self, state):
self.obj.ViewObject.Cumulative = state
QtCore.Slot()
def titleChanged(self):
self.obj.ViewObject.Title = self.view_widget.Title.text()
QtCore.Slot()
def xLabelChanged(self):
self.obj.ViewObject.XLabel = self.view_widget.XLabel.text()
QtCore.Slot()
def yLabelChanged(self):
self.obj.ViewObject.YLabel = self.view_widget.YLabel.text()
QtCore.Slot(int)
def legendPosChanged(self, idx):
self.obj.ViewObject.LegendLocation = idx
QtCore.Slot(bool)
def legendShowChanged(self, state):
self.obj.ViewObject.Legend = state
QtCore.Slot(float)
def barWidthChanged(self, value):
self.obj.ViewObject.BarWidth = value
QtCore.Slot(float)
def hatchWidthChanged(self, value):
self.obj.ViewObject.HatchLineWidth = value

View File

@@ -40,6 +40,7 @@ from femguiutils import vtk_table_view
translate = FreeCAD.Qt.translate
class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
"""
The TaskPanel for editing properties of glyph filter
@@ -68,7 +69,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
self.data_widget.setWindowTitle(translate("FEM", "Lineplot data"))
self.data_widget.setWindowIcon(FreeCADGui.getIcon(":/icons/FEM_PostLineplot.svg"))
# lineplot parameter widget
self.view_widget = FreeCADGui.PySideUic.loadUi(
FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/TaskPostLineplot.ui"
@@ -81,7 +81,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
# form made from param and selection widget
self.form = [self.data_widget, self.view_widget]
# Setup functions
# ###############
@@ -104,7 +103,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
self.view_widget.LegendShow.setChecked(viewObj.Legend)
self._enumPropertyToCombobox(viewObj, "LegendLocation", self.view_widget.LegendPos)
# connect callbacks
self.view_widget.Scale.activated.connect(self.scaleChanged)
self.view_widget.Grid.toggled.connect(self.gridChanged)
@@ -116,12 +114,13 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
self.view_widget.LegendShow.toggled.connect(self.legendShowChanged)
self.view_widget.LegendPos.activated.connect(self.legendPosChanged)
QtCore.Slot()
def showPlot(self):
self.obj.ViewObject.Proxy.show_visualization()
QtCore.Slot()
def showTable(self):
# TODO: make data model update when object is recomputed
@@ -132,37 +131,43 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
widget = vtk_table_view.VtkTableView(data_model)
layout = QtGui.QVBoxLayout()
layout.addWidget(widget)
layout.setContentsMargins(0,0,0,0)
layout.setContentsMargins(0, 0, 0, 0)
dialog.setLayout(layout)
dialog.resize(1500, 900)
dialog.show()
QtCore.Slot(int)
def scaleChanged(self, idx):
self.obj.ViewObject.Scale = idx
QtCore.Slot(bool)
def gridChanged(self, state):
self.obj.ViewObject.Grid = state
QtCore.Slot()
def titleChanged(self):
self.obj.ViewObject.Title = self.view_widget.Title.text()
QtCore.Slot()
def xLabelChanged(self):
self.obj.ViewObject.XLabel = self.view_widget.XLabel.text()
QtCore.Slot()
def yLabelChanged(self):
self.obj.ViewObject.YLabel = self.view_widget.YLabel.text()
QtCore.Slot(int)
def legendPosChanged(self, idx):
self.obj.ViewObject.LegendLocation = idx
QtCore.Slot(bool)
def legendShowChanged(self, state):
self.obj.ViewObject.Legend = state

View File

@@ -39,6 +39,7 @@ from femguiutils import extract_link_view as elv
translate = FreeCAD.Qt.translate
class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
"""
The TaskPanel for editing properties of glyph filter
@@ -68,7 +69,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
# form made from param and selection widget
self.form = [self.data_widget]
# Setup functions
# ###############
@@ -77,8 +77,6 @@ class _TaskPanel(base_fempostpanel._BasePostTaskPanel):
# connect data widget
self.data_widget.show_table.clicked.connect(self.showTable)
@QtCore.Slot()
def showTable(self):
self.obj.ViewObject.Proxy.show_visualization()

View File

@@ -40,6 +40,7 @@ from femobjects.base_fempythonobject import _PropHelper
False if FemGui.__name__ else True # flake8, dummy FemGui usage
class _GuiPropHelper(_PropHelper):
"""
Helper class to manage property data inside proxy objects.

View File

@@ -1,4 +1,3 @@
# ***************************************************************************
# * Copyright (c) 2025 Stefan Tröger <stefantroeger@gmx.net> *
# * *
@@ -37,6 +36,7 @@ from PySide import QtGui
from femtaskpanels import task_post_extractor
class VPPostExtractor:
"""
A View Provider for extraction of data
@@ -74,18 +74,18 @@ class VPPostExtractor:
if not group:
return
if (hasattr(group.ViewObject, "Proxy") and
hasattr(group.ViewObject.Proxy, "childViewPropertyChanged")):
if hasattr(group.ViewObject, "Proxy") and hasattr(
group.ViewObject.Proxy, "childViewPropertyChanged"
):
group.ViewObject.Proxy.childViewPropertyChanged(vobj, prop)
def setEdit(self, vobj, mode):
# build up the task panel
taskd = task_post_extractor._ExtractorTaskPanel(vobj.Object)
#show it
# show it
FreeCADGui.Control.showDialog(taskd)
return True
@@ -112,7 +112,6 @@ class VPPostExtractor:
def loads(self, state):
return None
# To be implemented by subclasses:
# ################################

View File

@@ -32,6 +32,7 @@ __url__ = "https://www.freecad.org"
import FreeCAD
import FreeCADGui
class VPPostVisualization:
"""
A View Provider for visualization objects
@@ -42,23 +43,19 @@ class VPPostVisualization:
self._setup_properties(vobj)
vobj.addExtension("Gui::ViewProviderGroupExtensionPython")
def _setup_properties(self, vobj):
pl = vobj.PropertiesList
for prop in self._get_properties():
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
@@ -66,7 +63,7 @@ class VPPostVisualization:
def getDisplayModes(self, obj):
return ["Dialog"]
def doubleClicked(self,vobj):
def doubleClicked(self, vobj):
guidoc = FreeCADGui.getDocument(vobj.Object.Document)
@@ -107,7 +104,6 @@ class VPPostVisualization:
def loads(self, state):
return None
# To be implemented by subclasses:
# ################################

View File

@@ -48,6 +48,7 @@ from . import view_base_fempostvisualization
from femtaskpanels import task_post_histogram
from . import view_base_femobject
_GuiPropHelper = view_base_femobject._GuiPropHelper
@@ -92,12 +93,11 @@ class EditViewWidget(QtGui.QWidget):
self.widget.HatchDensity.setMaximumHeight(self.widget.Hatch.sizeHint().height())
self.widget.LineWidth.setMaximumHeight(self.widget.LineStyle.sizeHint().height())
def _setup_color_button(self, button, fcColor, callback):
barColor = QtGui.QColor(*[v*255 for v in fcColor])
barColor = QtGui.QColor(*[v * 255 for v in fcColor])
icon_size = button.iconSize()
icon_size.setWidth(icon_size.width()*2)
icon_size.setWidth(icon_size.width() * 2)
button.setIconSize(icon_size)
pixmap = QtGui.QPixmap(icon_size)
pixmap.fill(barColor)
@@ -114,7 +114,6 @@ class EditViewWidget(QtGui.QWidget):
button.addAction(action)
button.setPopupMode(QtGui.QToolButton.InstantPopup)
@QtCore.Slot(QtGui.QColor)
def lineColorChanged(self, color):
@@ -199,6 +198,7 @@ class EditFieldAppWidget(QtGui.QWidget):
self._object.ExtractFrames = extract
self._post_dialog._recompute()
class EditIndexAppWidget(QtGui.QWidget):
def __init__(self, obj, post_dialog):
@@ -279,7 +279,7 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
name="Hatch",
group="HistogramBar",
doc=QT_TRANSLATE_NOOP("FEM", "The hatch pattern drawn in the bar"),
value=['None', '/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'],
value=["None", "/", "\\", "|", "-", "+", "x", "o", "O", ".", "*"],
),
_GuiPropHelper(
type="App::PropertyIntegerConstraint",
@@ -293,13 +293,15 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
name="LineColor",
group="HistogramLine",
doc=QT_TRANSLATE_NOOP("FEM", "The color the data bin area is drawn with"),
value=(0, 0, 0, 1), # black
value=(0, 0, 0, 1), # black
),
_GuiPropHelper(
type="App::PropertyFloatConstraint",
name="LineWidth",
group="HistogramLine",
doc=QT_TRANSLATE_NOOP("FEM", "The width of the bar, between 0 and 1 (1 being without gaps)"),
doc=QT_TRANSLATE_NOOP(
"FEM", "The width of the bar, between 0 and 1 (1 being without gaps)"
),
value=(1, 0, 99, 0.1),
),
_GuiPropHelper(
@@ -307,7 +309,7 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
name="LineStyle",
group="HistogramLine",
doc=QT_TRANSLATE_NOOP("FEM", "The style the line is drawn in"),
value=['None', '-', '--', '-.', ':'],
value=["None", "-", "--", "-.", ":"],
),
]
return super()._get_properties() + prop
@@ -327,13 +329,13 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
def get_preview(self):
fig = mpl.pyplot.figure(figsize=(0.4,0.2), dpi=500)
ax = mpl.pyplot.Axes(fig, [0., 0., 2, 1])
fig = mpl.pyplot.figure(figsize=(0.4, 0.2), dpi=500)
ax = mpl.pyplot.Axes(fig, [0.0, 0.0, 2, 1])
ax.set_axis_off()
fig.add_axes(ax)
kwargs = self.get_kw_args()
patch = mpl.patches.Rectangle(xy=(0,0), width=2, height=1, **kwargs)
patch = mpl.patches.Rectangle(xy=(0, 0), width=2, height=1, **kwargs)
ax.add_patch(patch)
data = io.BytesIO()
@@ -355,7 +357,7 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor):
kwargs["linestyle"] = self.ViewObject.LineStyle
kwargs["linewidth"] = self.ViewObject.LineWidth
if self.ViewObject.Hatch != "None":
kwargs["hatch"] = self.ViewObject.Hatch*self.ViewObject.HatchDensity
kwargs["hatch"] = self.ViewObject.Hatch * self.ViewObject.HatchDensity
return kwargs
@@ -386,7 +388,6 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
def __init__(self, vobj):
super().__init__(vobj)
def _get_properties(self):
prop = [
@@ -394,7 +395,9 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
type="App::PropertyBool",
name="Cumulative",
group="Histogram",
doc=QT_TRANSLATE_NOOP("FEM", "If be the bars shoud show the cumulative sum left to rigth"),
doc=QT_TRANSLATE_NOOP(
"FEM", "If be the bars shoud show the cumulative sum left to rigth"
),
value=False,
),
_GuiPropHelper(
@@ -402,13 +405,15 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
name="Type",
group="Histogram",
doc=QT_TRANSLATE_NOOP("FEM", "The type of histogram plotted"),
value=["bar","barstacked", "step", "stepfilled"],
value=["bar", "barstacked", "step", "stepfilled"],
),
_GuiPropHelper(
type="App::PropertyFloatConstraint",
name="BarWidth",
group="Histogram",
doc=QT_TRANSLATE_NOOP("FEM", "The width of the bar, between 0 and 1 (1 being without gaps)"),
doc=QT_TRANSLATE_NOOP(
"FEM", "The width of the bar, between 0 and 1 (1 being without gaps)"
),
value=(0.9, 0, 1, 0.05),
),
_GuiPropHelper(
@@ -458,29 +463,36 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
name="LegendLocation",
group="Plot",
doc=QT_TRANSLATE_NOOP("FEM", "Determines if the legend is plotted"),
value=['best','upper right','upper left','lower left','lower right','right',
'center left','center right','lower center','upper center','center'],
value=[
"best",
"upper right",
"upper left",
"lower left",
"lower right",
"right",
"center left",
"center right",
"lower center",
"upper center",
"center",
],
),
]
return prop
def getIcon(self):
return ":/icons/FEM_PostHistogram.svg"
def setEdit(self, vobj, mode):
# build up the task panel
taskd = task_post_histogram._TaskPanel(vobj)
#show it
# show it
FreeCADGui.Control.showDialog(taskd)
return True
def show_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
@@ -489,12 +501,11 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
self._plot.setWindowTitle(self.Object.Label)
self._plot.setParent(main)
self._plot.setWindowFlags(QtGui.Qt.Dialog)
self._plot.resize(main.size().height()/2, main.size().height()/3) # keep it square
self._plot.resize(main.size().height() / 2, main.size().height() / 3) # keep it square
self.update_visualization()
self._plot.show()
def get_kw_args(self, obj):
view = obj.ViewObject
if not view or not hasattr(view, "Proxy"):
@@ -503,7 +514,6 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
return {}
return view.Proxy.get_kw_args()
def update_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
@@ -523,7 +533,7 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
kwargs = self.get_kw_args(child)
# iterate over the table and plot all
color_factor = np.linspace(1,0.5,table.GetNumberOfColumns())
color_factor = np.linspace(1, 0.5, table.GetNumberOfColumns())
legend_multiframe = table.GetNumberOfColumns() > 1
for i in range(table.GetNumberOfColumns()):
@@ -532,7 +542,7 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
for key in kwargs:
if "color" in key:
value = np.array(kwargs[key])*color_factor[i]
value = np.array(kwargs[key]) * color_factor[i]
args[key] = mpl.colors.to_hex(value)
full_args.append(args)
@@ -581,7 +591,7 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization):
self._plot.axes.set_ylabel(self.ViewObject.YLabel)
if self.ViewObject.Legend and labels:
self._plot.axes.legend(loc = self.ViewObject.LegendLocation)
self._plot.axes.legend(loc=self.ViewObject.LegendLocation)
self._plot.update()

View File

@@ -48,8 +48,10 @@ from . import view_base_fempostvisualization
from femtaskpanels import task_post_lineplot
from . import view_base_femobject
_GuiPropHelper = view_base_femobject._GuiPropHelper
class EditViewWidget(QtGui.QWidget):
def __init__(self, obj, post_dialog):
@@ -91,9 +93,9 @@ class EditViewWidget(QtGui.QWidget):
def _setup_color_button(self, button, fcColor, callback):
barColor = QtGui.QColor(*[v*255 for v in fcColor])
barColor = QtGui.QColor(*[v * 255 for v in fcColor])
icon_size = button.iconSize()
icon_size.setWidth(icon_size.width()*2)
icon_size.setWidth(icon_size.width() * 2)
button.setIconSize(icon_size)
pixmap = QtGui.QPixmap(icon_size)
pixmap.fill(barColor)
@@ -110,7 +112,6 @@ class EditViewWidget(QtGui.QWidget):
button.addAction(action)
button.setPopupMode(QtGui.QToolButton.InstantPopup)
@QtCore.Slot(QtGui.QColor)
def colorChanged(self, color):
@@ -163,9 +164,13 @@ class EditFieldAppWidget(QtGui.QWidget):
# set the other properties
self._post_dialog._enumPropertyToCombobox(self._object, "XField", self.widget.XField)
self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.XComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "XComponent", self.widget.XComponent
)
self._post_dialog._enumPropertyToCombobox(self._object, "YField", self.widget.YField)
self._post_dialog._enumPropertyToCombobox(self._object, "YComponent", self.widget.YComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "YComponent", self.widget.YComponent
)
self.widget.Extract.setChecked(self._object.ExtractFrames)
self.widget.XField.activated.connect(self.xFieldChanged)
@@ -177,7 +182,9 @@ class EditFieldAppWidget(QtGui.QWidget):
@QtCore.Slot(int)
def xFieldChanged(self, index):
self._object.XField = index
self._post_dialog._enumPropertyToCombobox(self._object, "XComponent", self.widget.XComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "XComponent", self.widget.XComponent
)
self._post_dialog._recompute()
@QtCore.Slot(int)
@@ -188,7 +195,9 @@ class EditFieldAppWidget(QtGui.QWidget):
@QtCore.Slot(int)
def yFieldChanged(self, index):
self._object.YField = index
self._post_dialog._enumPropertyToCombobox(self._object, "YComponent", self.widget.YComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "YComponent", self.widget.YComponent
)
self._post_dialog._recompute()
@QtCore.Slot(int)
@@ -225,7 +234,9 @@ class EditIndexAppWidget(QtGui.QWidget):
self.widget.Index.setValue(self._object.Index)
self._post_dialog._enumPropertyToCombobox(self._object, "YField", self.widget.YField)
self._post_dialog._enumPropertyToCombobox(self._object, "YComponent", self.widget.YComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "YComponent", self.widget.YComponent
)
self.widget.Index.valueChanged.connect(self.indexChanged)
self.widget.YField.activated.connect(self.yFieldChanged)
@@ -242,7 +253,9 @@ class EditIndexAppWidget(QtGui.QWidget):
@QtCore.Slot(int)
def yFieldChanged(self, index):
self._object.YField = index
self._post_dialog._enumPropertyToCombobox(self._object, "YComponent", self.widget.YComponent)
self._post_dialog._enumPropertyToCombobox(
self._object, "YComponent", self.widget.YComponent
)
self._post_dialog._recompute()
@QtCore.Slot(int)
@@ -282,7 +295,7 @@ class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor):
name="LineStyle",
group="Lineplot",
doc=QT_TRANSLATE_NOOP("FEM", "The style the line is drawn in"),
value=['-', '--', '-.', ':', 'None'],
value=["-", "--", "-.", ":", "None"],
),
_GuiPropHelper(
type="App::PropertyFloatConstraint",
@@ -296,7 +309,7 @@ class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor):
name="MarkerStyle",
group="Lineplot",
doc=QT_TRANSLATE_NOOP("FEM", "The style the data markers are drawn with"),
value=['None', '*', '+', 's', '.', 'o', 'x'],
value=["None", "*", "+", "s", ".", "o", "x"],
),
_GuiPropHelper(
type="App::PropertyFloatConstraint",
@@ -325,13 +338,13 @@ class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor):
# Returns the preview tuple of icon and label: (QPixmap, str)
# Note: QPixmap in ratio 2:1
fig = mpl.pyplot.figure(figsize=(0.2,0.1), dpi=1000)
ax = mpl.pyplot.Axes(fig, [0., 0., 1., 1.])
fig = mpl.pyplot.figure(figsize=(0.2, 0.1), dpi=1000)
ax = mpl.pyplot.Axes(fig, [0.0, 0.0, 1.0, 1.0])
ax.set_axis_off()
fig.add_axes(ax)
kwargs = self.get_kw_args()
kwargs["markevery"] = [1]
ax.plot([0,0.5,1],[0.5,0.5,0.5], **kwargs)
ax.plot([0, 0.5, 1], [0.5, 0.5, 0.5], **kwargs)
data = io.BytesIO()
mpl.pyplot.savefig(data, bbox_inches=0, transparent=True)
mpl.pyplot.close()
@@ -341,7 +354,6 @@ class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor):
return (pixmap, self.ViewObject.Legend)
def get_kw_args(self):
# builds kw args from the properties
kwargs = {}
@@ -383,7 +395,6 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
def __init__(self, vobj):
super().__init__(vobj)
def _get_properties(self):
prop = [
@@ -391,7 +402,9 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
type="App::PropertyBool",
name="Grid",
group="Lineplot",
doc=QT_TRANSLATE_NOOP("FEM", "If be the bars shoud show the cumulative sum left to rigth"),
doc=QT_TRANSLATE_NOOP(
"FEM", "If be the bars shoud show the cumulative sum left to rigth"
),
value=True,
),
_GuiPropHelper(
@@ -399,9 +412,9 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
name="Scale",
group="Lineplot",
doc=QT_TRANSLATE_NOOP("FEM", "The scale the axis are drawn in"),
value=["linear","semi-log x", "semi-log y", "log"],
value=["linear", "semi-log x", "semi-log y", "log"],
),
_GuiPropHelper(
_GuiPropHelper(
type="App::PropertyString",
name="Title",
group="Plot",
@@ -434,29 +447,36 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
name="LegendLocation",
group="Plot",
doc=QT_TRANSLATE_NOOP("FEM", "Determines if the legend is plotted"),
value=['best','upper right','upper left','lower left','lower right','right',
'center left','center right','lower center','upper center','center'],
value=[
"best",
"upper right",
"upper left",
"lower left",
"lower right",
"right",
"center left",
"center right",
"lower center",
"upper center",
"center",
],
),
]
return prop
def getIcon(self):
return ":/icons/FEM_PostLineplot.svg"
def setEdit(self, vobj, mode):
# build up the task panel
taskd = task_post_lineplot._TaskPanel(vobj)
#show it
# show it
FreeCADGui.Control.showDialog(taskd)
return True
def show_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
@@ -465,12 +485,13 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
self._plot.setWindowTitle(self.Object.Label)
self._plot.setParent(main)
self._plot.setWindowFlags(QtGui.Qt.Dialog)
self._plot.resize(main.size().height()/2, main.size().height()/3) # keep the aspect ratio
self._plot.resize(
main.size().height() / 2, main.size().height() / 3
) # keep the aspect ratio
self.update_visualization()
self._plot.show()
def get_kw_args(self, obj):
view = obj.ViewObject
if not view or not hasattr(view, "Proxy"):
@@ -479,7 +500,6 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
return {}
return view.Proxy.get_kw_args()
def update_visualization(self):
if not hasattr(self, "_plot") or not self._plot:
@@ -496,10 +516,10 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
kwargs = self.get_kw_args(child)
# iterate over the table and plot all (note: column 0 is always X!)
color_factor = np.linspace(1,0.5,int(table.GetNumberOfColumns()/2))
color_factor = np.linspace(1, 0.5, int(table.GetNumberOfColumns() / 2))
legend_multiframe = table.GetNumberOfColumns() > 2
for i in range(0,table.GetNumberOfColumns(),2):
for i in range(0, table.GetNumberOfColumns(), 2):
plotted = True
@@ -507,13 +527,13 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
tmp_args = {}
for key in kwargs:
if "color" in key:
value = np.array(kwargs[key])*color_factor[int(i/2)]
value = np.array(kwargs[key]) * color_factor[int(i / 2)]
tmp_args[key] = mpl.colors.to_hex(value)
else:
tmp_args[key] = kwargs[key]
xdata = VTKArray(table.GetColumn(i))
ydata = VTKArray(table.GetColumn(i+1))
ydata = VTKArray(table.GetColumn(i + 1))
# ensure points are visible if it is a single datapoint
if len(xdata) == 1 and tmp_args["marker"] == "None":
@@ -524,13 +544,13 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
if not legend_multiframe:
label = child.ViewObject.Legend
else:
postfix = table.GetColumnName(i+1).split("-")[-1]
postfix = table.GetColumnName(i + 1).split("-")[-1]
label = child.ViewObject.Legend + " - " + postfix
else:
legend_prefix = ""
if len(self.Object.Group) > 1:
legend_prefix = child.Source.Label + ": "
label = legend_prefix + table.GetColumnName(i+1)
label = legend_prefix + table.GetColumnName(i + 1)
match self.ViewObject.Scale:
case "log":
@@ -550,7 +570,7 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
self._plot.axes.set_ylabel(self.ViewObject.YLabel)
if self.ViewObject.Legend and plotted:
self._plot.axes.legend(loc = self.ViewObject.LegendLocation)
self._plot.axes.legend(loc=self.ViewObject.LegendLocation)
self._plot.axes.grid(self.ViewObject.Grid)
self._plot.update()
@@ -561,4 +581,3 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization):
i = len(self.Object.Group)
cmap = mpl.pyplot.get_cmap("tab10")
return cmap(i)

View File

@@ -41,8 +41,10 @@ from femtaskpanels import task_post_table
from femguiutils import vtk_table_view as vtv
from . import view_base_femobject
_GuiPropHelper = view_base_femobject._GuiPropHelper
class EditViewWidget(QtGui.QWidget):
def __init__(self, obj, post_dialog):
@@ -116,6 +118,7 @@ class EditFieldAppWidget(QtGui.QWidget):
self._object.ExtractFrames = extract
self._post_dialog._recompute()
class EditIndexAppWidget(QtGui.QWidget):
def __init__(self, obj, post_dialog):
@@ -180,7 +183,9 @@ class VPPostTableFieldData(view_base_fempostextractors.VPPostExtractor):
type="App::PropertyString",
name="Name",
group="Table",
doc=QT_TRANSLATE_NOOP("FEM", "The name used in the table header. Default name is used if empty"),
doc=QT_TRANSLATE_NOOP(
"FEM", "The name used in the table header. Default name is used if empty"
),
value="",
),
]
@@ -232,22 +237,19 @@ class VPPostTable(view_base_fempostvisualization.VPPostVisualization):
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
# show it
FreeCADGui.Control.showDialog(taskd)
return True
def show_visualization(self):
if not hasattr(self, "_tableview") or not self._tableview:
@@ -257,13 +259,14 @@ class VPPostTable(view_base_fempostvisualization.VPPostVisualization):
self._tableview.setWindowTitle(self.Object.Label)
self._tableview.setParent(main)
self._tableview.setWindowFlags(QtGui.Qt.Dialog)
self._tableview.resize(main.size().height()/2, main.size().height()/3) # keep the aspect ratio
self._tableview.resize(
main.size().height() / 2, main.size().height() / 3
) # keep the aspect ratio
self.update_visualization()
self._tableview.show()
def update_visualization(self):
if not hasattr(self, "_tableModel") or not self._tableModel:
@@ -286,5 +289,3 @@ class VPPostTable(view_base_fempostvisualization.VPPostVisualization):
header[table.GetColumnName(i)] = new_name
self._tableModel.setTable(self.Object.Table, header)