FEM: task panels, move them into the view provider modules

This commit is contained in:
Bernd Hahnebach
2017-12-15 19:58:59 +01:00
committed by Yorik van Havre
parent b030184f89
commit bb8fdeccc7
21 changed files with 2733 additions and 3019 deletions

View File

@@ -155,16 +155,6 @@ SET(FemTestsElmer_SRCS
SET(FemGuiScripts_SRCS
PyGui/__init__.py
PyGui/_TaskPanelFemElementFluid1D.py
PyGui/_TaskPanelFemElementGeometry1D.py
PyGui/_TaskPanelFemElementGeometry2D.py
PyGui/_TaskPanelFemMaterial.py
PyGui/_TaskPanelFemMeshBoundaryLayer.py
PyGui/_TaskPanelFemMeshGmsh.py
PyGui/_TaskPanelFemMeshGroup.py
PyGui/_TaskPanelFemMeshRegion.py
PyGui/_TaskPanelFemResultShow.py
PyGui/_TaskPanelFemSolverCalculix.py
PyGui/_TaskPanelFemSolverControl.py
PyGui/_ViewProviderFemConstraintBodyHeatSource.py
PyGui/_ViewProviderFemConstraintElectrostaticPotential.py

View File

@@ -1,416 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Ofentse Kgoa <kgoaot@eskom.co.za> *
# * Based on the FemElementGeometry1D by Bernd Hahnebach *
# * *
# * 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__ = "_TaskPanelFemElementFluid1D"
__author__ = "Ofentse Kgoa"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemElementFluid1D
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
import PyObjects._FemElementFluid1D
class _TaskPanelFemElementFluid1D:
'''The TaskPanel for editing References property of FemElementFluid1D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementFluid1D.ui")
QtCore.QObject.connect(self.form.btn_add, QtCore.SIGNAL("clicked()"), self.add_references)
QtCore.QObject.connect(self.form.btn_remove, QtCore.SIGNAL("clicked()"), self.remove_reference)
QtCore.QObject.connect(self.form.cb_section_type, QtCore.SIGNAL("activated(int)"), self.sectiontype_changed)
QtCore.QObject.connect(self.form.cb_liquid_section_type, QtCore.SIGNAL("activated(int)"), self.liquidsectiontype_changed)
QtCore.QObject.connect(self.form.if_manning_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.manning_area_changed)
QtCore.QObject.connect(self.form.if_manning_radius, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.manning_radius_changed)
QtCore.QObject.connect(self.form.sb_manning_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.manning_coefficient_changed)
QtCore.QObject.connect(self.form.if_enlarge_area1, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.enlarge_area1_changed)
QtCore.QObject.connect(self.form.if_enlarge_area2, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.enlarge_area2_changed)
QtCore.QObject.connect(self.form.if_contract_area1, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.contract_area1_changed)
QtCore.QObject.connect(self.form.if_contract_area2, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.contract_area2_changed)
QtCore.QObject.connect(self.form.if_inletpressure, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.inlet_pressure_changed)
QtCore.QObject.connect(self.form.if_outletpressure, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.outlet_pressure_changed)
QtCore.QObject.connect(self.form.if_inletflowrate, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.inlet_flowrate_changed)
QtCore.QObject.connect(self.form.if_outletflowrate, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.outlet_flowrate_changed)
QtCore.QObject.connect(self.form.gb_inletpressure, QtCore.SIGNAL("clicked(bool)"), self.inlet_pressure_active)
QtCore.QObject.connect(self.form.gb_outletpressure, QtCore.SIGNAL("clicked(bool)"), self.outlet_pressure_active)
QtCore.QObject.connect(self.form.gb_inletflowrate, QtCore.SIGNAL("clicked(bool)"), self.inlet_flowrate_active)
QtCore.QObject.connect(self.form.gb_outletflowrate, QtCore.SIGNAL("clicked(bool)"), self.outlet_flowrate_active)
QtCore.QObject.connect(self.form.if_entrance_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.entrance_pipe_area_changed)
QtCore.QObject.connect(self.form.if_entrance_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.entrance_area_changed)
QtCore.QObject.connect(self.form.if_diaphragm_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.diaphragm_pipe_area_changed)
QtCore.QObject.connect(self.form.if_diaphragm_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.diaphragm_area_changed)
QtCore.QObject.connect(self.form.if_bend_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.bend_pipe_area_changed)
QtCore.QObject.connect(self.form.sb_bradius_pdiameter, QtCore.SIGNAL("valueChanged(double)"), self.bradius_pdiameter_changed)
QtCore.QObject.connect(self.form.sb_bend_angle, QtCore.SIGNAL("valueChanged(double)"), self.bend_angle_changed)
QtCore.QObject.connect(self.form.sb_bend_loss_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.bend_loss_coefficient_changed)
QtCore.QObject.connect(self.form.if_gatevalve_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.gatevalve_pipe_area_changed)
QtCore.QObject.connect(self.form.sb_gatevalve_closing_coeff, QtCore.SIGNAL("valueChanged(double)"), self.gatevalve_closing_coeff_changed)
QtCore.QObject.connect(self.form.if_colebrooke_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_pipe_area_changed)
QtCore.QObject.connect(self.form.if_colebrooke_radius, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_radius_changed)
QtCore.QObject.connect(self.form.if_colebrooke_grain_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_grain_diameter_changed)
QtCore.QObject.connect(self.form.sb_colebrooke_form_factor, QtCore.SIGNAL("valueChanged(double)"), self.colebrooke_form_factor_changed)
QtCore.QObject.connect(self.form.tw_pump_characteristics, QtCore.SIGNAL("cellChanged(int, int)"), self.pump_characteristics_changed)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.form.cb_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_fluid_types)
self.form.cb_liquid_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_liquid_types)
self.form.cb_gas_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_gas_types)
self.form.cb_channel_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_channel_types)
self.get_fluidsection_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_fluidsection_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_fluidsection_props(self):
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.SectionType = self.obj.SectionType
self.LiquidSectionType = self.obj.LiquidSectionType
self.ManningArea = self.obj.ManningArea
self.ManningRadius = self.obj.ManningRadius
self.ManningCoefficient = self.obj.ManningCoefficient
self.EnlargeArea1 = self.obj.EnlargeArea1
self.EnlargeArea2 = self.obj.EnlargeArea2
self.ContractArea1 = self.obj.ContractArea1
self.ContractArea2 = self.obj.ContractArea2
self.OutletPressure = self.obj.OutletPressure
self.InletPressure = self.obj.InletPressure
self.OutletFlowRate = self.obj.OutletFlowRate
self.InletFlowRate = self.obj.InletFlowRate
self.OutletPressureActive = self.obj.OutletPressureActive
self.InletPressureActive = self.obj.InletPressureActive
self.OutletFlowRateActive = self.obj.OutletFlowRateActive
self.InletFlowRateActive = self.obj.InletFlowRateActive
self.EntrancePipeArea = self.obj.EntrancePipeArea
self.EntranceArea = self.obj.EntranceArea
self.DiaphragmPipeArea = self.obj.DiaphragmPipeArea
self.DiaphragmArea = self.obj.DiaphragmArea
self.BendPipeArea = self.obj.BendPipeArea
self.BendRadiusDiameter = self.obj.BendRadiusDiameter
self.BendAngle = self.obj.BendAngle
self.BendLossCoefficient = self.obj.BendLossCoefficient
self.GateValvePipeArea = self.obj.GateValvePipeArea
self.GateValveClosingCoeff = self.obj.GateValveClosingCoeff
self.ColebrookeArea = self.obj.ColebrookeArea
self.ColebrookeRadius = self.obj.ColebrookeRadius
self.ColebrookeGrainDiameter = self.obj.ColebrookeGrainDiameter
self.ColebrookeFormFactor = self.obj.ColebrookeFormFactor
self.PumpFlowRate = self.obj.PumpFlowRate
self.PumpHeadLoss = self.obj.PumpHeadLoss
def set_fluidsection_props(self):
self.obj.References = self.references
self.obj.LiquidSectionType = self.LiquidSectionType
self.obj.SectionType = self.SectionType
self.obj.ManningArea = self.ManningArea
self.obj.ManningRadius = self.ManningRadius
self.obj.ManningCoefficient = self.ManningCoefficient
self.obj.EnlargeArea1 = self.EnlargeArea1
self.obj.EnlargeArea2 = self.EnlargeArea2
self.obj.ContractArea1 = self.ContractArea1
self.obj.ContractArea2 = self.ContractArea2
self.obj.OutletPressure = self.OutletPressure
self.obj.InletPressure = self.InletPressure
self.obj.OutletFlowRate = self.OutletFlowRate
self.obj.InletFlowRate = self.InletFlowRate
self.obj.OutletPressureActive = self.OutletPressureActive
self.obj.InletPressureActive = self.InletPressureActive
self.obj.OutletFlowRateActive = self.OutletFlowRateActive
self.obj.InletFlowRateActive = self.InletFlowRateActive
self.obj.EntrancePipeArea = self.EntrancePipeArea
self.obj.EntranceArea = self.EntranceArea
self.obj.DiaphragmPipeArea = self.DiaphragmPipeArea
self.obj.DiaphragmArea = self.DiaphragmArea
self.obj.BendPipeArea = self.BendPipeArea
self.obj.BendRadiusDiameter = self.BendRadiusDiameter
self.obj.BendAngle = self.BendAngle
self.obj.BendLossCoefficient = self.BendLossCoefficient
self.obj.GateValvePipeArea = self.GateValvePipeArea
self.obj.GateValveClosingCoeff = self.GateValveClosingCoeff
self.obj.ColebrookeArea = self.ColebrookeArea
self.obj.ColebrookeRadius = self.ColebrookeRadius
self.obj.ColebrookeGrainDiameter = self.ColebrookeGrainDiameter
self.obj.ColebrookeFormFactor = self.ColebrookeFormFactor
self.obj.PumpFlowRate = self.PumpFlowRate
self.obj.PumpHeadLoss = self.PumpHeadLoss
def update(self):
'fills the widgets'
index_sectiontype = self.form.cb_section_type.findText(self.SectionType)
self.form.cb_section_type.setCurrentIndex(index_sectiontype)
self.form.sw_section_type.setCurrentIndex(index_sectiontype)
index_liquidsectiontype = self.form.cb_liquid_section_type.findText(self.LiquidSectionType)
self.form.cb_liquid_section_type.setCurrentIndex(index_liquidsectiontype)
self.form.sw_liquid_section_type.setCurrentIndex(index_liquidsectiontype)
self.form.if_manning_area.setText(self.ManningArea.UserString)
self.form.if_manning_radius.setText(self.ManningRadius.UserString)
self.form.sb_manning_coefficient.setValue(self.ManningCoefficient)
self.form.if_enlarge_area1.setText(self.EnlargeArea1.UserString)
self.form.if_enlarge_area2.setText(self.EnlargeArea2.UserString)
self.form.if_contract_area1.setText(self.ContractArea1.UserString)
self.form.if_contract_area2.setText(self.ContractArea2.UserString)
self.form.if_inletpressure.setText(FreeCAD.Units.Quantity(1000 * self.InletPressure, FreeCAD.Units.Pressure).UserString)
self.form.if_outletpressure.setText(FreeCAD.Units.Quantity(1000 * self.OutletPressure, FreeCAD.Units.Pressure).UserString)
self.form.if_inletflowrate.setText(str(self.InletFlowRate))
self.form.if_outletflowrate.setText(str(self.OutletFlowRate))
self.form.gb_inletpressure.setChecked(self.InletPressureActive)
self.form.gb_outletpressure.setChecked(self.OutletPressureActive)
self.form.gb_inletflowrate.setChecked(self.InletFlowRateActive)
self.form.gb_outletflowrate.setChecked(self.OutletFlowRateActive)
self.form.if_entrance_pipe_area.setText(self.EntrancePipeArea.UserString)
self.form.if_entrance_area.setText(self.EntranceArea.UserString)
self.form.if_diaphragm_pipe_area.setText(self.DiaphragmPipeArea.UserString)
self.form.if_diaphragm_area.setText(self.DiaphragmArea.UserString)
self.form.if_bend_pipe_area.setText(self.BendPipeArea.UserString)
self.form.sb_bradius_pdiameter.setValue(self.BendRadiusDiameter)
self.form.sb_bend_angle.setValue(self.BendAngle)
self.form.sb_bend_loss_coefficient.setValue(self.BendLossCoefficient)
self.form.if_gatevalve_pipe_area.setText(self.GateValvePipeArea.UserString)
self.form.sb_gatevalve_closing_coeff.setValue(self.GateValveClosingCoeff)
self.form.if_colebrooke_pipe_area.setText(self.ColebrookeArea.UserString)
self.form.if_colebrooke_radius.setText(self.ColebrookeRadius.UserString)
self.form.if_colebrooke_grain_diameter.setText(self.ColebrookeGrainDiameter.UserString)
self.form.sb_colebrooke_form_factor.setValue(self.ColebrookeFormFactor)
for i in range(len(self.PumpFlowRate)):
self.form.tw_pump_characteristics.setItem(i, 0, QtGui.QTableWidgetItem(str(self.PumpFlowRate[i])))
self.form.tw_pump_characteristics.setItem(i, 1, QtGui.QTableWidgetItem(str(self.PumpHeadLoss[i])))
self.rebuild_list_References()
def sectiontype_changed(self, index):
if index < 0:
return
self.form.cb_section_type.setCurrentIndex(index)
self.form.sw_section_type.setCurrentIndex(index)
self.SectionType = str(self.form.cb_section_type.itemText(index)) # form returns unicode
def liquidsectiontype_changed(self, index):
if index < 0:
return
self.form.cb_liquid_section_type.setCurrentIndex(index)
self.form.sw_liquid_section_type.setCurrentIndex(index)
self.LiquidSectionType = str(self.form.cb_liquid_section_type.itemText(index)) # form returns unicode
def manning_area_changed(self, base_quantity_value):
self.ManningArea = base_quantity_value
def manning_radius_changed(self, base_quantity_value):
self.ManningRadius = base_quantity_value
def manning_coefficient_changed(self, base_quantity_value):
self.ManningCoefficient = base_quantity_value
def enlarge_area1_changed(self, base_quantity_value):
self.EnlargeArea1 = base_quantity_value
def enlarge_area2_changed(self, base_quantity_value):
self.EnlargeArea2 = base_quantity_value
def contract_area1_changed(self, base_quantity_value):
self.ContractArea1 = base_quantity_value
def contract_area2_changed(self, base_quantity_value):
self.ContractArea2 = base_quantity_value
def inlet_pressure_changed(self, base_quantity_value):
self.InletPressure = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("MPa"))
def outlet_pressure_changed(self, base_quantity_value):
self.OutletPressure = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("MPa"))
def inlet_flowrate_changed(self, base_quantity_value):
self.InletFlowRate = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("kg/s"))
def outlet_flowrate_changed(self, base_quantity_value):
self.OutletFlowRate = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("kg/s"))
def inlet_pressure_active(self, active):
self.InletPressureActive = active
def outlet_pressure_active(self, active):
self.OutletPressureActive = active
def inlet_flowrate_active(self, active):
self.InletFlowRateActive = active
def outlet_flowrate_active(self, active):
self.OutletFlowRateActive = active
def entrance_pipe_area_changed(self, base_quantity_value):
self.EntrancePipeArea = base_quantity_value
def entrance_area_changed(self, base_quantity_value):
self.EntranceArea = base_quantity_value
def diaphragm_pipe_area_changed(self, base_quantity_value):
self.DiaphragmPipeArea = base_quantity_value
def diaphragm_area_changed(self, base_quantity_value):
self.DiaphragmArea = base_quantity_value
def bend_pipe_area_changed(self, base_quantity_value):
self.BendPipeArea = base_quantity_value
def bradius_pdiameter_changed(self, base_quantity_value):
self.BendRadiusDiameter = base_quantity_value
def bend_angle_changed(self, base_quantity_value):
self.BendAngle = base_quantity_value
def bend_loss_coefficient_changed(self, base_quantity_value):
self.BendLossCoefficient = base_quantity_value
def gatevalve_pipe_area_changed(self, base_quantity_value):
self.GateValvePipeArea = base_quantity_value
def gatevalve_closing_coeff_changed(self, base_quantity_value):
self.GateValveClosingCoeff = base_quantity_value
def colebrooke_pipe_area_changed(self, base_quantity_value):
self.ColebrookeArea = base_quantity_value
def colebrooke_radius_changed(self, base_quantity_value):
self.ColebrookeRadius = base_quantity_value
def colebrooke_grain_diameter_changed(self, base_quantity_value):
self.ColebrookeGrainDiameter = base_quantity_value
def colebrooke_form_factor_changed(self, base_quantity_value):
self.ColebrookeFormFactor = base_quantity_value
def pump_characteristics_changed(self, row, column):
if column == 0:
self.PumpFlowRate[row] = float(self.form.tw_pump_characteristics.item(row, column).text())
else:
self.PumpHeadLoss[row] = float(self.form.tw_pump_characteristics.item(row, column).text())
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Edges by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Edge':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,215 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2015 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemElementGeometry1D"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemElementGeometry1D
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
import PyObjects._FemElementGeometry1D
class _TaskPanelFemElementGeometry1D:
'''The TaskPanel for editing References property of FemElementGeometry1D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementGeometry1D.ui")
QtCore.QObject.connect(self.form.cb_crosssectiontype, QtCore.SIGNAL("activated(int)"), self.sectiontype_changed)
QtCore.QObject.connect(self.form.if_rec_height, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.rec_height_changed)
QtCore.QObject.connect(self.form.if_rec_width, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.rec_width_changed)
QtCore.QObject.connect(self.form.if_circ_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.circ_diameter_changed)
QtCore.QObject.connect(self.form.if_pipe_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.pipe_diameter_changed)
QtCore.QObject.connect(self.form.if_pipe_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.pipe_thickness_changed)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.form.cb_crosssectiontype.addItems(PyObjects._FemElementGeometry1D._FemElementGeometry1D.known_beam_types) # it is inside the class thus double _FemElementGeometry1D
self.get_beamsection_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_beamsection_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_beamsection_props(self):
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.SectionType = self.obj.SectionType
self.RectHeight = self.obj.RectHeight
self.RectWidth = self.obj.RectWidth
self.CircDiameter = self.obj.CircDiameter
self.PipeDiameter = self.obj.PipeDiameter
self.PipeThickness = self.obj.PipeThickness
def set_beamsection_props(self):
self.obj.References = self.references
self.obj.SectionType = self.SectionType
self.obj.RectHeight = self.RectHeight
self.obj.RectWidth = self.RectWidth
self.obj.CircDiameter = self.CircDiameter
self.obj.PipeDiameter = self.PipeDiameter
self.obj.PipeThickness = self.PipeThickness
def update(self):
'fills the widgets'
index_crosssectiontype = self.form.cb_crosssectiontype.findText(self.SectionType)
self.form.cb_crosssectiontype.setCurrentIndex(index_crosssectiontype)
self.form.if_rec_height.setText(self.RectHeight.UserString)
self.form.if_rec_width.setText(self.RectWidth.UserString)
self.form.if_circ_diameter.setText(self.CircDiameter.UserString)
self.form.if_pipe_diameter.setText(self.PipeDiameter.UserString)
self.form.if_pipe_thickness.setText(self.PipeThickness.UserString)
self.rebuild_list_References()
def sectiontype_changed(self, index):
if index < 0:
return
self.form.cb_crosssectiontype.setCurrentIndex(index)
self.SectionType = str(self.form.cb_crosssectiontype.itemText(index)) # form returns unicode
def rec_height_changed(self, base_quantity_value):
self.RectHeight = base_quantity_value
def rec_width_changed(self, base_quantity_value):
self.RectWidth = base_quantity_value
def circ_diameter_changed(self, base_quantity_value):
self.CircDiameter = base_quantity_value
def pipe_diameter_changed(self, base_quantity_value):
self.PipeDiameter = base_quantity_value
def pipe_thickness_changed(self, base_quantity_value):
self.PipeThickness = base_quantity_value
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Edges by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Edge':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,173 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2015 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemElementGeometry2D"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package FemElementGeometry2D
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
class _TaskPanelFemElementGeometry2D:
'''The TaskPanel for editing References property of FemElementGeometry2D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementGeometry2D.ui")
QtCore.QObject.connect(self.form.if_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.thickness_changed)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_shellthickness_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_shellthickness_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_shellthickness_props(self):
self.thickness = self.obj.Thickness
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_shellthickness_props(self):
self.obj.References = self.references
self.obj.Thickness = self.thickness
def update(self):
'fills the widgets'
self.form.if_thickness.setText(self.thickness.UserString)
self.rebuild_list_References()
def thickness_changed(self, base_quantity_value):
self.thickness = base_quantity_value
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Faces by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Face':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,642 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2013 - Juergen Riegel <FreeCAD@juergen-riegel.net> *
# * *
# * 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__ = "_TaskPanelFemMaterial"
__author__ = "Juergen Riegel, Bernd Hahnebach, Qingfeng Xia"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMaterial
# \ingroup FEM
import sys
import FreeCAD
import FreeCADGui
from FreeCAD import Units
from PySide import QtCore, QtGui
from PySide.QtGui import QFileDialog, QMessageBox
if sys.version_info.major >= 3:
unicode = str
class _TaskPanelFemMaterial:
'''The editmode TaskPanel for FemMaterial objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces and Edges by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.material = self.obj.Material
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMaterial.ui")
QtCore.QObject.connect(self.form.pushButton_MatWeb, QtCore.SIGNAL("clicked()"), self.goto_MatWeb)
QtCore.QObject.connect(self.form.pushButton_saveas, QtCore.SIGNAL("clicked()"), self.export_material)
QtCore.QObject.connect(self.form.cb_materials, QtCore.SIGNAL("activated(int)"), self.choose_material)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
# basic properties must be provided
QtCore.QObject.connect(self.form.input_fd_density, QtCore.SIGNAL("valueChanged(double)"), self.density_changed)
# mechanical properties
QtCore.QObject.connect(self.form.input_fd_young_modulus, QtCore.SIGNAL("valueChanged(double)"), self.ym_changed)
QtCore.QObject.connect(self.form.spinBox_poisson_ratio, QtCore.SIGNAL("valueChanged(double)"), self.pr_changed)
# thermal properties
QtCore.QObject.connect(self.form.input_fd_thermal_conductivity, QtCore.SIGNAL("valueChanged(double)"), self.tc_changed)
QtCore.QObject.connect(self.form.input_fd_expansion_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.tec_changed)
QtCore.QObject.connect(self.form.input_fd_specific_heat, QtCore.SIGNAL("valueChanged(double)"), self.sh_changed)
# fluidic properties, only volumetric thermal expansion coeff makes sense
QtCore.QObject.connect(self.form.input_fd_kinematic_viscosity, QtCore.SIGNAL("valueChanged(double)"), self.kinematic_viscosity_changed)
QtCore.QObject.connect(self.form.input_fd_vol_expansion_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.vtec_changed)
# hide some groupBox according to material category
self.form.label_category.setText(self.obj.Category)
if self.obj.Category == 'Fluid':
self.form.groupBox_mechanical.setVisible(0)
self.form.label_expansion_coefficient.setVisible(0)
self.form.input_fd_expansion_coefficient.setVisible(0)
else:
self.form.groupBox_fluidic.setVisible(0)
self.form.label_vol_expansion_coefficient.setVisible(0)
self.form.input_fd_vol_expansion_coefficient.setVisible(0)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.import_materials()
previous_mat_path = self.get_material_path(self.material)
if not previous_mat_path:
material_name = self.get_material_name(self.material)
if material_name != 'None':
FreeCAD.Console.PrintMessage("Previously used material cannot be found in material directories. Using transient material.\n")
self.add_transient_material(self.material)
index = self.form.cb_materials.findData(material_name)
else:
if not self.material:
index = self.form.cb_materials.findText(material_name)
else:
FreeCAD.Console.PrintMessage("None material was previously used. Reload values.\n")
self.add_transient_material(self.material)
index = self.form.cb_materials.findData(material_name)
self.choose_material(index)
else:
index = self.form.cb_materials.findData(previous_mat_path)
self.choose_material(index)
self.has_equal_references_shape_types()
self.rebuild_list_References()
def accept(self):
self.setback_listobj_visibility()
# print(self.material)
self.remove_active_sel_server()
if self.has_equal_references_shape_types():
self.obj.Material = self.material
self.obj.References = self.references
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
doc.Document.recompute()
def reject(self):
self.setback_listobj_visibility()
self.remove_active_sel_server()
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
def remove_active_sel_server(self):
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def has_equal_references_shape_types(self):
import femmesh.meshtools as FemMeshTools
ref_shty = ''
for ref in self.references:
r = FemMeshTools.get_element(ref[0], ref[1]) # the method getElement(element) does not return Solid elements
# print(' ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
if not ref_shty:
ref_shty = r.ShapeType
if r.ShapeType != ref_shty:
message = 'Multiple shape types are not allowed in the reference list.\n'
FreeCAD.Console.PrintError(message)
QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
return False
return True
def goto_MatWeb(self):
import webbrowser
webbrowser.open("http://matweb.com")
def check_material_keys(self):
if 'Density' in self.material:
if 'Density' not in str(Units.Unit(self.material['Density'])):
print('Density in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['Density'] = '0 kg/m^3'
else:
print('Density not found in material data of: ' + self.material['Name'])
self.material['Density'] = '0 kg/m^3'
if self.obj.Category == 'Solid':
# mechanical properties
if 'YoungsModulus' in self.material:
if 'Pressure' not in str(Units.Unit(self.material['YoungsModulus'])): # unit type of YoungsModulus is Pressure
print('YoungsModulus in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['YoungsModulus'] = '0 MPa'
else:
print('YoungsModulus not found in material data of: ' + self.material['Name'])
self.material['YoungsModulus'] = '0 MPa'
if 'PoissonRatio' not in self.material: # PoissonRatio does not have a unit, we do not gone check for a unit
print('PoissonRatio not found in material data of: ' + self.material['Name'])
self.material['PoissonRatio'] = '0'
if self.obj.Category == 'Fluid':
# Fluidic properties
if 'KinematicViscosity' in self.material:
if 'KinematicViscosity' not in str(Units.Unit(self.material['KinematicViscosity'])):
print('KinematicViscosity in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['KinematicViscosity'] = '0 m^2/s'
else:
print('KinematicViscosity not found in material data of: ' + self.material['Name'])
self.material['KinematicViscosity'] = '0 m^2/s'
if 'VolumetricThermalExpansionCoefficient' in self.material:
if 'ThermalExpansionCoefficient' not in str(Units.Unit(self.material['VolumetricThermalExpansionCoefficient'])): # unit type of VolumetricThermalExpansionCoefficient is ThermalExpansionCoefficient
print('VolumetricThermalExpansionCoefficient in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['VolumetricThermalExpansionCoefficient'] = '0 m/m/K'
else:
print('VolumetricThermalExpansionCoefficient not found in material data of: ' + self.material['Name'])
self.material['VolumetricThermalExpansionCoefficient'] = '0 m/m/K'
# Thermal properties
if 'ThermalConductivity' in self.material:
if 'ThermalConductivity' not in str(Units.Unit(self.material['ThermalConductivity'])):
print('ThermalConductivity in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['ThermalConductivity'] = '0 W/m/K'
else:
print('ThermalConductivity not found in material data of: ' + self.material['Name'])
self.material['ThermalConductivity'] = '0 W/m/K'
if 'ThermalExpansionCoefficient' in self.material:
if 'ThermalExpansionCoefficient' not in str(Units.Unit(self.material['ThermalExpansionCoefficient'])):
print('ThermalExpansionCoefficient in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['ThermalExpansionCoefficient'] = '0 um/m/K'
else:
print('ThermalExpansionCoefficient not found in material data of: ' + self.material['Name'])
self.material['ThermalExpansionCoefficient'] = '0 um/m/K'
if 'SpecificHeat' in self.material:
if 'SpecificHeat' not in str(Units.Unit(self.material['SpecificHeat'])):
print('SpecificHeat in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['SpecificHeat'] = '0 J/kg/K'
else:
print('SpecificHeat not found in material data of: ' + self.material['Name'])
self.material['SpecificHeat'] = '0 J/kg/K'
def ym_changed(self, value):
# FreeCADs standard unit for stress is kPa
old_ym = Units.Quantity(self.material['YoungsModulus']).getValueAs("kPa")
variation = 0.001
if value:
if not (1 - variation < float(old_ym) / value < 1 + variation):
# YoungsModulus has changed
material = self.material
material['YoungsModulus'] = unicode(value) + " kPa"
self.material = material
def density_changed(self, value):
# FreeCADs standard unit for density is kg/mm^3
old_density = Units.Quantity(self.material['Density']).getValueAs("kg/m^3")
variation = 0.001
if value:
if not (1 - variation < float(old_density) / value < 1 + variation):
# density has changed
material = self.material
value_in_kg_per_m3 = value * 1e9
material['Density'] = unicode(value_in_kg_per_m3) + " kg/m^3" # SvdW:Keep density in SI units for easier readability
self.material = material
def pr_changed(self, value):
old_pr = Units.Quantity(self.material['PoissonRatio'])
variation = 0.001
if value:
if not (1 - variation < float(old_pr) / value < 1 + variation):
# PoissonRatio has changed
material = self.material
material['PoissonRatio'] = unicode(value)
self.material = material
def tc_changed(self, value):
old_tc = Units.Quantity(self.material['ThermalConductivity']).getValueAs("W/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_tc) / value < 1 + variation):
# ThermalConductivity has changed
material = self.material
value_in_W_per_mK = value * 1e-3 # To compensate for use of SI units
material['ThermalConductivity'] = unicode(value_in_W_per_mK) + " W/m/K"
self.material = material
def tec_changed(self, value):
old_tec = Units.Quantity(self.material['ThermalExpansionCoefficient']).getValueAs("um/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_tec) / value < 1 + variation):
# ThermalExpansionCoefficient has changed
material = self.material
value_in_um_per_mK = value * 1e6 # To compensate for use of SI units
material['ThermalExpansionCoefficient'] = unicode(value_in_um_per_mK) + " um/m/K"
self.material = material
def sh_changed(self, value):
old_sh = Units.Quantity(self.material['SpecificHeat']).getValueAs("J/kg/K")
variation = 0.001
if value:
if not (1 - variation < float(old_sh) / value < 1 + variation):
# SpecificHeat has changed
material = self.material
value_in_J_per_kgK = value * 1e-6 # To compensate for use of SI units
material['SpecificHeat'] = unicode(value_in_J_per_kgK) + " J/kg/K"
self.material = material
################ fluidic #########################
def vtec_changed(self, value):
old_vtec = Units.Quantity(self.material['VolumetricThermalExpansionCoefficient']).getValueAs("m/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_vtec) / value < 1 + variation):
# VolumetricThermalExpansionCoefficient has changed
material = self.material
value_in_one_per_K = value
material['VolumetricThermalExpansionCoefficient'] = unicode(value_in_one_per_K) + " m/m/K"
self.material = material
def kinematic_viscosity_changed(self, value):
old_nu = Units.Quantity(self.material['KinematicViscosity']).getValueAs("m^2/s")
variation = 0.000001
if value:
if not (1 - variation < float(old_nu) / value < 1 + variation):
# KinematicViscosity has changed
material = self.material
value_in_m2_per_second = value
material['KinematicViscosity'] = unicode(value_in_m2_per_second) + " m^2/s"
self.material = material
def choose_material(self, index):
if index < 0:
return
mat_file_path = self.form.cb_materials.itemData(index)
self.material = self.materials[mat_file_path]
self.form.cb_materials.setCurrentIndex(index)
self.check_material_keys()
self.set_mat_params_in_combo_box(self.material)
gen_mat_desc = ""
if 'Description' in self.material:
gen_mat_desc = self.material['Description']
self.form.l_mat_description.setText(gen_mat_desc)
def get_material_name(self, material):
if 'Name' in self.material:
return self.material['Name']
else:
return 'None'
def get_material_path(self, material):
for a_mat in self.materials:
unmatched_items = set(self.materials[a_mat].items()) ^ set(material.items())
if len(unmatched_items) == 0:
return a_mat
return ""
def set_mat_params_in_combo_box(self, matmap):
if 'YoungsModulus' in matmap:
ym_new_unit = "MPa"
ym = FreeCAD.Units.Quantity(matmap['YoungsModulus'])
ym_with_new_unit = ym.getValueAs(ym_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(ym_with_new_unit, ym_new_unit))
self.form.input_fd_young_modulus.setText(q.UserString)
if 'PoissonRatio' in matmap:
self.form.spinBox_poisson_ratio.setValue(float(matmap['PoissonRatio']))
# Fluidic properties
if 'KinematicViscosity' in matmap:
nu_new_unit = "m^2/s"
nu = FreeCAD.Units.Quantity(matmap['KinematicViscosity'])
nu_with_new_unit = nu.getValueAs(nu_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(nu_with_new_unit, nu_new_unit))
self.form.input_fd_kinematic_viscosity.setText(q.UserString)
# For isotropic materials the volumetric thermal expansion coefficient is three times the linear coefficient:
if 'VolumetricThermalExpansionCoefficient' in matmap: # linear, only for solid
vtec_new_unit = "m/m/K"
vtec = FreeCAD.Units.Quantity(matmap['VolumetricThermalExpansionCoefficient'])
vtec_with_new_unit = vtec.getValueAs(vtec_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(vtec_with_new_unit, vtec_new_unit))
self.form.input_fd_vol_expansion_coefficient.setText(q.UserString)
if 'Density' in matmap:
density_new_unit = "kg/m^3"
density = FreeCAD.Units.Quantity(matmap['Density'])
density_with_new_unit = density.getValueAs(density_new_unit)
#self.form.input_fd_density.setText("{} {}".format(density_with_new_unit, density_new_unit))
q = FreeCAD.Units.Quantity("{} {}".format(density_with_new_unit, density_new_unit))
self.form.input_fd_density.setText(q.UserString)
# thermal properties
if 'ThermalConductivity' in matmap:
tc_new_unit = "W/m/K"
tc = FreeCAD.Units.Quantity(matmap['ThermalConductivity'])
tc_with_new_unit = tc.getValueAs(tc_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(tc_with_new_unit, tc_new_unit))
self.form.input_fd_thermal_conductivity.setText(q.UserString)
if 'ThermalExpansionCoefficient' in matmap: # linear, only for solid
tec_new_unit = "um/m/K"
tec = FreeCAD.Units.Quantity(matmap['ThermalExpansionCoefficient'])
tec_with_new_unit = tec.getValueAs(tec_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(tec_with_new_unit, tec_new_unit))
self.form.input_fd_expansion_coefficient.setText(q.UserString)
if 'SpecificHeat' in matmap:
sh_new_unit = "J/kg/K"
sh = FreeCAD.Units.Quantity(matmap['SpecificHeat'])
sh_with_new_unit = sh.getValueAs(sh_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(sh_with_new_unit, sh_new_unit))
self.form.input_fd_specific_heat.setText(q.UserString)
def add_transient_material(self, material):
material_name = self.get_material_name(material)
self.form.cb_materials.addItem(QtGui.QIcon(":/icons/help-browser.svg"), material_name, material_name)
self.materials[material_name] = material
######################## material import and export ###################
def import_materials(self):
self.materials = {}
self.pathList = []
self.form.cb_materials.clear()
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
if self.obj.Category == 'Fluid':
self.import_fluid_materials()
else:
self.import_solid_materials()
def import_solid_materials(self):
use_built_in_materials = self.fem_prefs.GetBool("UseBuiltInMaterials", True)
if use_built_in_materials:
system_mat_dir = FreeCAD.getResourceDir() + "/Mod/Material/StandardMaterial"
self.add_mat_dir(system_mat_dir, ":/icons/freecad.svg")
use_mat_from_config_dir = self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True)
if use_mat_from_config_dir:
user_mat_dirname = FreeCAD.getUserAppDataDir() + "Materials"
self.add_mat_dir(user_mat_dirname, ":/icons/preferences-general.svg")
use_mat_from_custom_dir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
if use_mat_from_custom_dir:
custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
self.add_mat_dir(custom_mat_dir, ":/icons/user.svg")
def import_fluid_materials(self):
#use_built_in_materials = self.fem_prefs.GetBool("UseBuiltInMaterials", True)
#if use_built_in_materials:
system_mat_dir = FreeCAD.getResourceDir() + "/Mod/Material/FluidMaterial"
self.add_mat_dir(system_mat_dir, ":/icons/freecad.svg")
use_mat_from_config_dir = self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True)
if use_mat_from_config_dir:
user_mat_dirname = FreeCAD.getUserAppDataDir() + "FluidMaterial"
self.add_mat_dir(user_mat_dirname, ":/icons/preferences-general.svg")
use_mat_from_custom_dir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
if use_mat_from_custom_dir:
custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
self.add_mat_dir(custom_mat_dir, ":/icons/user.svg")
def add_mat_dir(self, mat_dir, icon):
import glob
import os
import Material
mat_file_extension = ".FCMat"
ext_len = len(mat_file_extension)
dir_path_list = glob.glob(mat_dir + '/*' + mat_file_extension)
self.pathList = self.pathList + dir_path_list
material_name_list = []
for a_path in dir_path_list:
material_name = os.path.basename(a_path[:-ext_len])
self.materials[a_path] = Material.importFCMat(a_path)
material_name_list.append([material_name, a_path])
material_name_list.sort()
for mat in material_name_list:
self.form.cb_materials.addItem(QtGui.QIcon(icon), mat[0], mat[1])
def export_FCMat(self, fileName, matDict):
"""
Write a material dictionary to a FCMat file, a version without group support, with Python3
<https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Material/Material.py>
"""
try:
import ConfigParser as configparser
except:
import configparser # Python 3
# himport string
Config = configparser.ConfigParser()
Config.optionxform = str # disable conversion all uppercase leter in key into lower case
# ignore creating group, just fill all into group 'FCMat'
grp = 'FCMat'
if not Config.has_section(grp):
Config.add_section(grp)
for x in matDict.keys():
Config.set(grp, x, matDict[x])
Preamble = "# This is a FreeCAD material-card file\n\n"
# Writing our configuration file to 'example.cfg'
with open(fileName, 'wb') as configfile:
configfile.write(Preamble)
Config.write(configfile)
def export_material(self):
import os
if self.obj.Category == 'Fluid':
MaterialDir = 'FluidMaterial'
else:
MaterialDir = 'Material'
_UseMaterialsFromCustomDir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
if _UseMaterialsFromCustomDir and _dir != "" and os.path.isdir(_dir):
TargetDir = self.fem_prefs.GetString("CustomMaterialsDir", "")
elif self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True):
TargetDir = FreeCAD.getUserAppDataDir() + os.path.sep + MaterialDir # $HOME/.FreeCAD
else:
FreeCAD.Console.PrintMessage("Customed material saving directory is not setup in Fem preference")
if not os.path.exists(TargetDir):
os.mkdir(TargetDir)
saveName, Filter = QFileDialog.getSaveFileName(None, "Save a Material property file", TargetDir, "*.FCMat")
if not saveName == "":
print(saveName)
knownMaterials = [self.form.cb_materials.itemText(i) for i in range(self.form.cb_materials.count())]
material_name = os.path.basename(saveName[:-len('.FCMat')])
if material_name not in knownMaterials:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully save the Material property file: " + saveName + "\n")
else:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully overwritren the Material property file: " + saveName + "\n")
"""
msgBox = QMessageBox()
msgBox.setText("FcMat file name {} has existed in {} or system folder, overwriting?\n".format(saveName, TargetDir))
msgBox.addButton(QMessageBox.Yes)
msgBox.addButton(QMessageBox.No)
msgBox.setDefaultButton(QMessageBox.No)
ret = msgBox.exec_()
if ret == QMessageBox.Yes:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully overwritren the Material property file: "+ saveName + "\n")
"""
###################geometry reference selection #################
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
if ref[1]:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
else:
refname_to_compare_listentry = ref[0].Name
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' --> ', selection[0].Name, ' --> ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
if ref[1]:
item_name = ref[0].Name + ':' + ref[1]
else:
item_name = ref[0].Name
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,204 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemMeshBoundaryLayer"
__author__ = "Bernd Hahnebach, Qingfeng Xia"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMeshBoundaryLayer
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
class _TaskPanelFemMeshBoundaryLayer:
'''The TaskPanel for editing References property of FemMeshBoundaryLayer objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces for 3D, Edges for 2D by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui")
QtCore.QObject.connect(self.form.bl_number_of_layers, QtCore.SIGNAL("valueChanged(int)"), self.bl_number_of_layers_changed)
QtCore.QObject.connect(self.form.bl_min_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.bl_min_thickness_changed)
QtCore.QObject.connect(self.form.bl_growth_rate, QtCore.SIGNAL("valueChanged(double)"), self.bl_growth_rate_changed) # becareful of signal signature for QDoubleSpinbox
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_mesh_boundarylayer_props()
self.update()
def get_mesh_boundarylayer_props(self):
self.bl_min_thickness = self.obj.MinimumThickness
self.bl_number_of_layers = self.obj.NumberOfLayers
self.bl_growth_rate = self.obj.GrowthRate
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_mesh_boundarylayer_props(self):
self.obj.MinimumThickness = self.bl_min_thickness
self.obj.NumberOfLayers = self.bl_number_of_layers
self.obj.GrowthRate = self.bl_growth_rate
self.obj.References = self.references
def update(self):
'fills the widgets with data'
self.form.bl_min_thickness.setText(self.bl_min_thickness.UserString)
self.form.bl_number_of_layers.setValue(self.bl_number_of_layers)
self.form.bl_growth_rate.setValue(self.bl_growth_rate)
self.rebuild_list_References()
def bl_min_thickness_changed(self, base_quantity_value):
self.bl_min_thickness = base_quantity_value
def bl_number_of_layers_changed(self, value):
self.bl_number_of_layers = value
def bl_growth_rate_changed(self, value):
self.bl_growth_rate = value
def accept(self):
self.set_mesh_boundarylayer_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
############### identical to FemMeshRegion ############
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)

View File

@@ -1,174 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemMeshGmsh"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMeshGmsh
# \ingroup FEM
import FreeCAD
import time
import PyObjects._FemMeshGmsh
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
class _TaskPanelFemMeshGmsh:
'''The TaskPanel for editing References property of FemMeshGmsh objects and creation of new FEM mesh'''
def __init__(self, obj):
self.mesh_obj = obj
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshGmsh.ui")
self.Timer = QtCore.QTimer()
self.Timer.start(100) # 100 milli seconds
self.gmsh_runs = False
self.console_message_gmsh = ''
QtCore.QObject.connect(self.form.if_max, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.max_changed)
QtCore.QObject.connect(self.form.if_min, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.min_changed)
QtCore.QObject.connect(self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension)
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
self.form.cb_dimension.addItems(PyObjects._FemMeshGmsh._FemMeshGmsh.known_element_dimensions)
self.get_mesh_params()
self.get_active_analysis()
self.update()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel)
# show a OK, a apply and a Cancel button
# def reject() is called on Cancel button
# def clicked(self, button) is needed, to access the apply button
def accept(self):
self.set_mesh_params()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def clicked(self, button):
if button == QtGui.QDialogButtonBox.Apply:
self.set_mesh_params()
self.run_gmsh()
def get_mesh_params(self):
self.clmax = self.mesh_obj.CharacteristicLengthMax
self.clmin = self.mesh_obj.CharacteristicLengthMin
self.dimension = self.mesh_obj.ElementDimension
def set_mesh_params(self):
self.mesh_obj.CharacteristicLengthMax = self.clmax
self.mesh_obj.CharacteristicLengthMin = self.clmin
self.mesh_obj.ElementDimension = self.dimension
def update(self):
'fills the widgets'
self.form.if_max.setText(self.clmax.UserString)
self.form.if_min.setText(self.clmin.UserString)
index_dimension = self.form.cb_dimension.findText(self.dimension)
self.form.cb_dimension.setCurrentIndex(index_dimension)
def console_log(self, message="", color="#000000"):
self.console_message_gmsh = self.console_message_gmsh + '<font color="#0000FF">{0:4.1f}:</font> <font color="{1}">{2}</font><br>'.\
format(time.time() - self.Start, color, message.encode('utf-8', 'replace'))
self.form.te_output.setText(self.console_message_gmsh)
self.form.te_output.moveCursor(QtGui.QTextCursor.End)
def update_timer_text(self):
# print('timer1')
if self.gmsh_runs:
print('timer2')
# print('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def max_changed(self, base_quantity_value):
self.clmax = base_quantity_value
def min_changed(self, base_quantity_value):
self.clmin = base_quantity_value
def choose_dimension(self, index):
if index < 0:
return
self.form.cb_dimension.setCurrentIndex(index)
self.dimension = str(self.form.cb_dimension.itemText(index)) # form returns unicode
def run_gmsh(self):
QApplication.setOverrideCursor(Qt.WaitCursor)
part = self.obj.Part
if self.mesh_obj.MeshRegionList:
if part.Shape.ShapeType == "Compound" and hasattr(part, "Proxy"): # other part obj might not have a Proxy, thus an exception would be raised
if (part.Proxy.Type == "FeatureBooleanFragments" or part.Proxy.Type == "FeatureSlice" or part.Proxy.Type == "FeatureXOR"):
error_message = "The mesh to shape is a boolean split tools Compound and the mesh has mesh region list. Gmsh could return unexpected meshes in such circumstances. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
QtGui.QMessageBox.critical(None, "Shape to mesh is a BooleanFragmentsCompound and mesh regions are defined", error_message)
self.Start = time.time()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.console_message_gmsh = ''
self.gmsh_runs = True
self.console_log("We are going to start ...")
self.get_active_analysis()
import femmesh.gmshtools as gmshtools
gmsh_mesh = gmshtools.GmshTools(self.obj, self.analysis)
self.console_log("Start Gmsh ...")
error = ''
try:
error = gmsh_mesh.create_mesh()
except:
import sys
print("Unexpected error when creating mesh: ", sys.exc_info()[0])
if error:
print(error)
self.console_log('Gmsh had warnings ...')
self.console_log(error, '#FF0000')
else:
self.console_log('Clean run of Gmsh')
self.console_log("Gmsh done!")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.Timer.stop()
self.update()
QApplication.restoreOverrideCursor()
def get_active_analysis(self):
import FemGui
self.analysis = FemGui.getActiveAnalysis()
if self.analysis:
for m in FemGui.getActiveAnalysis().Group:
if m.Name == self.mesh_obj.Name:
print('Active analysis found: ' + self.analysis.Name)
return
else:
# print('Mesh is not member of active analysis, means no group meshing')
self.analysis = None # no group meshing
else:
# print('No active analyis, means no group meshing')
self.analysis = None # no group meshing

View File

@@ -1,224 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemMeshGroup"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMeshGroup
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
class _TaskPanelFemMeshGroup:
'''The TaskPanel for editing References property of FemMeshGroup objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces, Edges and Vertices by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshGroup.ui")
QtCore.QObject.connect(self.form.rb_name, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_name)
QtCore.QObject.connect(self.form.rb_label, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_label)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_meshgroup_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_meshgroup_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_meshgroup_props(self):
self.use_label = self.obj.UseLabel
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_meshgroup_props(self):
self.obj.References = self.references
self.obj.UseLabel = self.use_label
def update(self):
'fills the widgets'
self.form.rb_name.setChecked(not self.use_label)
self.form.rb_label.setChecked(self.use_label)
self.rebuild_list_References()
def choose_exportidentifier_name(self, state):
self.use_label = not state
def choose_exportidentifier_label(self, state):
self.use_label = state
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,219 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * 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__ = "_TaskPanelFemMeshRegion"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMeshRegion
# \ingroup FEM
import FreeCAD
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
class _TaskPanelFemMeshRegion:
'''The TaskPanel for editing References property of FemMeshRegion objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces, Edges and Vertices by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshRegion.ui")
QtCore.QObject.connect(self.form.if_elelen, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.elelen_changed)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_meshregion_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_meshregion_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_meshregion_props(self):
self.elelen = self.obj.CharacteristicLength
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_meshregion_props(self):
self.obj.References = self.references
self.obj.CharacteristicLength = self.elelen
def update(self):
'fills the widgets'
self.form.if_elelen.setText(self.elelen.UserString)
self.rebuild_list_References()
def elelen_changed(self, base_quantity_value):
self.elelen = base_quantity_value
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -1,421 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2013-2015 - Juergen Riegel <FreeCAD@juergen-riegel.net> *
# * *
# * 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__ = "Result Control Task Panel"
__author__ = "Juergen Riegel, Michael Hindley"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemResultShow
# \ingroup FEM
import FreeCAD
import numpy as np
import FreeCADGui
import FemGui
import femresult.resulttools as resulttools
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
class _TaskPanelFemResultShow:
'''The task panel for the post-processing'''
def __init__(self, obj):
self.result_obj = obj
self.mesh_obj = self.result_obj.Mesh
# task panel should be started by use of setEdit of view provider
# in view provider checks: Mesh, active analysis and if Mesh and result are in active analysis
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemResultShow.ui")
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
self.restore_result_settings_in_dialog = self.fem_prefs.GetBool("RestoreResultDialog", True)
# Connect Signals and Slots
# result type radio buttons
QtCore.QObject.connect(self.form.rb_none, QtCore.SIGNAL("toggled(bool)"), self.none_selected)
QtCore.QObject.connect(self.form.rb_abs_displacement, QtCore.SIGNAL("toggled(bool)"), self.abs_displacement_selected)
QtCore.QObject.connect(self.form.rb_x_displacement, QtCore.SIGNAL("toggled(bool)"), self.x_displacement_selected)
QtCore.QObject.connect(self.form.rb_y_displacement, QtCore.SIGNAL("toggled(bool)"), self.y_displacement_selected)
QtCore.QObject.connect(self.form.rb_z_displacement, QtCore.SIGNAL("toggled(bool)"), self.z_displacement_selected)
QtCore.QObject.connect(self.form.rb_temperature, QtCore.SIGNAL("toggled(bool)"), self.temperature_selected)
QtCore.QObject.connect(self.form.rb_vm_stress, QtCore.SIGNAL("toggled(bool)"), self.vm_stress_selected)
QtCore.QObject.connect(self.form.rb_maxprin, QtCore.SIGNAL("toggled(bool)"), self.max_prin_selected)
QtCore.QObject.connect(self.form.rb_minprin, QtCore.SIGNAL("toggled(bool)"), self.min_prin_selected)
QtCore.QObject.connect(self.form.rb_max_shear_stress, QtCore.SIGNAL("toggled(bool)"), self.max_shear_selected)
QtCore.QObject.connect(self.form.rb_massflowrate, QtCore.SIGNAL("toggled(bool)"), self.massflowrate_selected)
QtCore.QObject.connect(self.form.rb_networkpressure, QtCore.SIGNAL("toggled(bool)"), self.networkpressure_selected)
QtCore.QObject.connect(self.form.rb_peeq, QtCore.SIGNAL("toggled(bool)"), self.peeq_selected)
# displacement
QtCore.QObject.connect(self.form.cb_show_displacement, QtCore.SIGNAL("clicked(bool)"), self.show_displacement)
QtCore.QObject.connect(self.form.hsb_displacement_factor, QtCore.SIGNAL("valueChanged(int)"), self.hsb_disp_factor_changed)
QtCore.QObject.connect(self.form.sb_displacement_factor, QtCore.SIGNAL("valueChanged(int)"), self.sb_disp_factor_changed)
QtCore.QObject.connect(self.form.sb_displacement_factor_max, QtCore.SIGNAL("valueChanged(int)"), self.sb_disp_factor_max_changed)
# user defined equation
QtCore.QObject.connect(self.form.user_def_eq, QtCore.SIGNAL("textchanged()"), self.user_defined_text)
QtCore.QObject.connect(self.form.calculate, QtCore.SIGNAL("clicked()"), self.calculate)
self.update()
if self.restore_result_settings_in_dialog:
self.restore_result_dialog()
else:
self.restore_initial_result_dialog()
def restore_result_dialog(self):
try:
rt = FreeCAD.FEM_dialog["results_type"]
if rt == "None":
self.form.rb_none.setChecked(True)
self.none_selected(True)
elif rt == "Uabs":
self.form.rb_abs_displacement.setChecked(True)
self.abs_displacement_selected(True)
elif rt == "U1":
self.form.rb_x_displacement.setChecked(True)
self.x_displacement_selected(True)
elif rt == "U2":
self.form.rb_y_displacement.setChecked(True)
self.y_displacement_selected(True)
elif rt == "U3":
self.form.rb_z_displacement.setChecked(True)
self.z_displacement_selected(True)
elif rt == "Temp":
self.form.rb_temperature.setChecked(True)
self.temperature_selected(True)
elif rt == "Sabs":
self.form.rb_vm_stress.setChecked(True)
self.vm_stress_selected(True)
elif rt == "MaxPrin":
self.form.rb_maxprin.setChecked(True)
self.max_prin_selected(True)
elif rt == "MinPrin":
self.form.rb_minprin.setChecked(True)
self.min_prin_selected(True)
elif rt == "MaxShear":
self.form.rb_max_shear_stress.setChecked(True)
self.max_shear_selected(True)
elif rt == "MFlow":
self.form.rb_massflowrate.setChecked(True)
self.massflowrate_selected(True)
elif rt == "NPress":
self.form.rb_networkpressure.setChecked(True)
self.networkpressure_selected(True)
elif rt == "Peeq":
self.form.rb_peeq.setChecked(True)
self.peeq_selected(True)
sd = FreeCAD.FEM_dialog["show_disp"]
self.form.cb_show_displacement.setChecked(sd)
self.show_displacement(sd)
df = FreeCAD.FEM_dialog["disp_factor"]
dfm = FreeCAD.FEM_dialog["disp_factor_max"]
self.form.hsb_displacement_factor.setMaximum(dfm)
self.form.hsb_displacement_factor.setValue(df)
self.form.sb_displacement_factor_max.setValue(dfm)
self.form.sb_displacement_factor.setValue(df)
except:
self.restore_initial_result_dialog()
def restore_initial_result_dialog(self):
FreeCAD.FEM_dialog = {"results_type": "None", "show_disp": False,
"disp_factor": 0, "disp_factor_max": 100}
self.reset_mesh_deformation()
self.reset_mesh_color()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
def get_result_stats(self, type_name):
return resulttools.get_stats(self.result_obj, type_name)
def none_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "None"
self.set_result_stats("mm", 0.0, 0.0, 0.0)
self.reset_mesh_color()
def abs_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Uabs"
self.select_displacement_type("Uabs")
def x_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U1"
self.select_displacement_type("U1")
def y_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U2"
self.select_displacement_type("U2")
def z_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U3"
self.select_displacement_type("U3")
def vm_stress_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Sabs"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.StressValues)
(minm, avg, maxm) = self.get_result_stats("Sabs")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def max_shear_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MaxShear"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.MaxShear)
(minm, avg, maxm) = self.get_result_stats("MaxShear")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def max_prin_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MaxPrin"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.PrincipalMax)
(minm, avg, maxm) = self.get_result_stats("MaxPrin")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def temperature_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Temp"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.Temperature)
(minm, avg, maxm) = self.get_result_stats("Temp")
self.set_result_stats("K", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def massflowrate_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MFlow"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.MassFlowRate)
(minm, avg, maxm) = self.get_result_stats("MFlow")
self.set_result_stats("kg/s", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def networkpressure_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "NPress"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.NetworkPressure)
(minm, avg, maxm) = self.get_result_stats("NPress")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def min_prin_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MinPrin"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.PrincipalMin)
(minm, avg, maxm) = self.get_result_stats("MinPrin")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def peeq_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Peeq"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.Peeq)
(minm, avg, maxm) = self.get_result_stats("Peeq")
self.set_result_stats("", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def user_defined_text(self, equation):
FreeCAD.FEM_dialog["results_type"] = "user"
self.form.user_def_eq.toPlainText()
def calculate(self):
FreeCAD.FEM_dialog["results_type"] = "None"
self.update()
self.restore_result_dialog()
# Convert existing values to numpy array
P1 = np.array(self.result_obj.PrincipalMax)
P2 = np.array(self.result_obj.PrincipalMed)
P3 = np.array(self.result_obj.PrincipalMin)
Von = np.array(self.result_obj.StressValues)
Peeq = np.array(self.result_obj.Peeq)
T = np.array(self.result_obj.Temperature)
MF = np.array(self.result_obj.MassFlowRate)
NP = np.array(self.result_obj.NetworkPressure)
dispvectors = np.array(self.result_obj.DisplacementVectors)
x = np.array(dispvectors[:, 0])
y = np.array(dispvectors[:, 1])
z = np.array(dispvectors[:, 2])
stressvectors = np.array(self.result_obj.StressVectors)
sx = np.array(stressvectors[:, 0])
sy = np.array(stressvectors[:, 1])
sz = np.array(stressvectors[:, 2])
strainvectors = np.array(self.result_obj.StrainVectors)
ex = np.array(strainvectors[:, 0])
ey = np.array(strainvectors[:, 1])
ez = np.array(strainvectors[:, 2])
userdefined_eq = self.form.user_def_eq.toPlainText() # Get equation to be used
UserDefinedFormula = eval(userdefined_eq).tolist()
self.result_obj.UserDefined = UserDefinedFormula
minm = min(UserDefinedFormula)
avg = sum(UserDefinedFormula) / len(UserDefinedFormula)
maxm = max(UserDefinedFormula)
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, UserDefinedFormula)
self.set_result_stats("", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
del x, y, z, T, Von, Peeq, P1, P2, P3, sx, sy, sz, ex, ey, ez, MF, NP # Dummy use to get around flake8, varibles not being used
def select_displacement_type(self, disp_type):
QApplication.setOverrideCursor(Qt.WaitCursor)
if disp_type == "Uabs":
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.DisplacementLengths)
else:
match = {"U1": 0, "U2": 1, "U3": 2}
d = zip(*self.result_obj.DisplacementVectors)
displacements = list(d[match[disp_type]])
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, displacements)
(minm, avg, maxm) = self.get_result_stats(disp_type)
self.set_result_stats("mm", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def set_result_stats(self, unit, minm, avg, maxm):
self.form.le_min.setProperty("unit", unit)
self.form.le_min.setText("{:.6} {}".format(minm, unit))
self.form.le_avg.setProperty("unit", unit)
self.form.le_avg.setText("{:.6} {}".format(avg, unit))
self.form.le_max.setProperty("unit", unit)
self.form.le_max.setText("{:.6} {}".format(maxm, unit))
def update_displacement(self, factor=None):
if factor is None:
if FreeCAD.FEM_dialog["show_disp"]:
factor = self.form.hsb_displacement_factor.value()
else:
factor = 0.0
self.mesh_obj.ViewObject.applyDisplacement(factor)
def show_displacement(self, checked):
QApplication.setOverrideCursor(Qt.WaitCursor)
FreeCAD.FEM_dialog["show_disp"] = checked
if "result_obj" in FreeCAD.FEM_dialog:
if FreeCAD.FEM_dialog["result_obj"] != self.result_obj:
self.update_displacement()
FreeCAD.FEM_dialog["result_obj"] = self.result_obj
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeDisplacementByVectors(self.result_obj.NodeNumbers, self.result_obj.DisplacementVectors)
self.update_displacement()
QtGui.qApp.restoreOverrideCursor()
def hsb_disp_factor_changed(self, value):
self.form.sb_displacement_factor.setValue(value)
self.update_displacement()
def sb_disp_factor_max_changed(self, value):
FreeCAD.FEM_dialog["disp_factor_max"] = value
self.form.hsb_displacement_factor.setMaximum(value)
def sb_disp_factor_changed(self, value):
FreeCAD.FEM_dialog["disp_factor"] = value
self.form.hsb_displacement_factor.setValue(value)
def disable_empty_result_buttons(self):
''' disable radio buttons if result does not exists in result object'''
'''assignments
DisplacementLengths --> rb_abs_displacement
DisplacementVectors --> rb_x_displacement, rb_y_displacement, rb_z_displacement
Temperature --> rb_temperature
StressValues --> rb_vm_stress
PrincipalMax --> rb_maxprin
PrincipalMin --> rb_minprin
MaxShear --> rb_max_shear_stress
MassFlowRate --> rb_massflowrate
NetworkPressure --> rb_networkpressure
Peeq --> rb_peeq'''
if len(self.result_obj.DisplacementLengths) == 0:
self.form.rb_abs_displacement.setEnabled(0)
if len(self.result_obj.DisplacementVectors) == 0:
self.form.rb_x_displacement.setEnabled(0)
self.form.rb_y_displacement.setEnabled(0)
self.form.rb_z_displacement.setEnabled(0)
if len(self.result_obj.Temperature) == 0:
self.form.rb_temperature.setEnabled(0)
if len(self.result_obj.StressValues) == 0:
self.form.rb_vm_stress.setEnabled(0)
if len(self.result_obj.PrincipalMax) == 0:
self.form.rb_maxprin.setEnabled(0)
if len(self.result_obj.PrincipalMin) == 0:
self.form.rb_minprin.setEnabled(0)
if len(self.result_obj.MaxShear) == 0:
self.form.rb_max_shear_stress.setEnabled(0)
if len(self.result_obj.MassFlowRate) == 0:
self.form.rb_massflowrate.setEnabled(0)
if len(self.result_obj.NetworkPressure) == 0:
self.form.rb_networkpressure.setEnabled(0)
if len(self.result_obj.Peeq) == 0:
self.form.rb_peeq.setEnabled(0)
def update(self):
self.suitable_results = False
self.disable_empty_result_buttons()
if (self.mesh_obj.FemMesh.NodeCount == len(self.result_obj.NodeNumbers)):
self.suitable_results = True
hide_parts_constraints()
else:
if not self.mesh_obj.FemMesh.VolumeCount:
error_message = 'FEM: Graphical bending stress output for beam or shell FEM Meshes not yet supported.\n'
FreeCAD.Console.PrintError(error_message)
QtGui.QMessageBox.critical(None, 'No result object', error_message)
else:
error_message = 'FEM: Result node numbers are not equal to FEM Mesh NodeCount.\n'
FreeCAD.Console.PrintError(error_message)
QtGui.QMessageBox.critical(None, 'No result object', error_message)
def reset_mesh_deformation(self):
self.mesh_obj.ViewObject.applyDisplacement(0.0)
def reset_mesh_color(self):
self.mesh_obj.ViewObject.NodeColor = {}
self.mesh_obj.ViewObject.ElementColor = {}
node_numbers = self.mesh_obj.FemMesh.Nodes.keys()
zero_values = [0] * len(node_numbers)
self.mesh_obj.ViewObject.setNodeColorByScalars(node_numbers, zero_values)
def reject(self):
FreeCADGui.Control.closeDialog() # if the taks panell is called from Command obj is not in edit mode thus reset edit does not cleses the dialog, may be do not call but set in edit instead
FreeCADGui.ActiveDocument.resetEdit()
# helper
def hide_parts_constraints():
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
hide_constraints = fem_prefs.GetBool("HideConstraint", False)
if hide_constraints:
for o in FreeCAD.ActiveDocument.Objects:
if o.isDerivedFrom('Fem::FemAnalysis'):
for acnstrmesh in FemGui.getActiveAnalysis().Group:
if "Constraint" in acnstrmesh.TypeId:
acnstrmesh.ViewObject.Visibility = False
break

View File

@@ -1,293 +0,0 @@
# ***************************************************************************
# * *
# * Copyright (c) 2013-2015 - Juergen Riegel <FreeCAD@juergen-riegel.net> *
# * *
# * 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__ = "CalculiX Job Control Task Panel"
__author__ = "Juergen Riegel"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemSolverCalculix
# \ingroup FEM
import FemToolsCcx
import FreeCAD
import os
import sys
import time
import FreeCADGui
import FemGui
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
if sys.version_info.major >= 3:
unicode = str
class _TaskPanelFemSolverCalculix:
def __init__(self, solver_object):
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemSolverCalculix.ui")
self.ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
ccx_binary = self.ccx_prefs.GetString("ccxBinaryPath", "")
if ccx_binary:
self.CalculixBinary = ccx_binary
print ("Using CalculiX binary path from FEM preferences: {}".format(ccx_binary))
else:
from platform import system
if system() == 'Linux':
self.CalculixBinary = 'ccx'
elif system() == 'Windows':
self.CalculixBinary = FreeCAD.getHomePath() + 'bin/ccx.exe'
else:
self.CalculixBinary = 'ccx'
self.solver_object = solver_object
self.Calculix = QtCore.QProcess()
self.Timer = QtCore.QTimer()
self.Timer.start(300)
self.fem_console_message = ''
# Connect Signals and Slots
QtCore.QObject.connect(self.form.tb_choose_working_dir, QtCore.SIGNAL("clicked()"), self.choose_working_dir)
QtCore.QObject.connect(self.form.pb_write_inp, QtCore.SIGNAL("clicked()"), self.write_input_file_handler)
QtCore.QObject.connect(self.form.pb_edit_inp, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile)
QtCore.QObject.connect(self.form.pb_run_ccx, QtCore.SIGNAL("clicked()"), self.runCalculix)
QtCore.QObject.connect(self.form.rb_static_analysis, QtCore.SIGNAL("clicked()"), self.select_static_analysis)
QtCore.QObject.connect(self.form.rb_frequency_analysis, QtCore.SIGNAL("clicked()"), self.select_frequency_analysis)
QtCore.QObject.connect(self.form.rb_thermomech_analysis, QtCore.SIGNAL("clicked()"), self.select_thermomech_analysis)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("started()"), self.calculixStarted)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("stateChanged(QProcess::ProcessState)"), self.calculixStateChanged)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("error(QProcess::ProcessError)"), self.calculixError)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("finished(int)"), self.calculixFinished)
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.UpdateText)
self.update()
def getStandardButtons(self):
# only show a close button
# def accept() in no longer needed, since there is no OK button
return int(QtGui.QDialogButtonBox.Close)
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
def update(self):
'fills the widgets'
self.form.le_working_dir.setText(self.solver_object.WorkingDir)
if self.solver_object.AnalysisType == 'static':
self.form.rb_static_analysis.setChecked(True)
elif self.solver_object.AnalysisType == 'frequency':
self.form.rb_frequency_analysis.setChecked(True)
elif self.solver_object.AnalysisType == 'thermomech':
self.form.rb_thermomech_analysis.setChecked(True)
return
def femConsoleMessage(self, message="", color="#000000"):
self.fem_console_message = self.fem_console_message + '<font color="#0000FF">{0:4.1f}:</font> <font color="{1}">{2}</font><br>'.\
format(time.time() - self.Start, color, message.encode('utf-8', 'replace'))
self.form.textEdit_Output.setText(self.fem_console_message)
self.form.textEdit_Output.moveCursor(QtGui.QTextCursor.End)
def printCalculiXstdout(self):
out = self.Calculix.readAllStandardOutput()
if out.isEmpty():
self.femConsoleMessage("CalculiX stdout is empty", "#FF0000")
else:
try:
out = unicode(out, 'utf-8', 'replace')
rx = QtCore.QRegExp("\\*ERROR.*\\n\\n")
rx.setMinimal(True)
pos = rx.indexIn(out)
while not pos < 0:
match = rx.cap(0)
FreeCAD.Console.PrintError(match.strip().replace('\n', ' ') + '\n')
pos = rx.indexIn(out, pos + 1)
out = os.linesep.join([s for s in out.splitlines() if s])
self.femConsoleMessage(out.replace('\n', '<br>'))
except UnicodeDecodeError:
self.femConsoleMessage("Error converting stdout from CalculiX", "#FF0000")
def UpdateText(self):
if(self.Calculix.state() == QtCore.QProcess.ProcessState.Running):
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def calculixError(self, error):
print ("Error() {}".format(error))
self.femConsoleMessage("CalculiX execute error: {}".format(error), "#FF0000")
def calculixStarted(self):
print ("calculixStarted()")
print (self.Calculix.state())
self.form.pb_run_ccx.setText("Break CalculiX")
def calculixStateChanged(self, newState):
if (newState == QtCore.QProcess.ProcessState.Starting):
self.femConsoleMessage("Starting CalculiX...")
if (newState == QtCore.QProcess.ProcessState.Running):
self.femConsoleMessage("CalculiX is running...")
if (newState == QtCore.QProcess.ProcessState.NotRunning):
self.femConsoleMessage("CalculiX stopped.")
def calculixFinished(self, exitCode):
print ("calculixFinished() {}".format(exitCode))
print (self.Calculix.state())
# Restore previous cwd
QtCore.QDir.setCurrent(self.cwd)
self.printCalculiXstdout()
self.Timer.stop()
self.femConsoleMessage("CalculiX done!", "#00AA00")
self.form.pb_run_ccx.setText("Re-run CalculiX")
self.femConsoleMessage("Loading result sets...")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.reset_mesh_purge_results_checked()
fea.inp_file_name = self.inp_file_name
QApplication.setOverrideCursor(Qt.WaitCursor)
try:
fea.load_results()
except:
QApplication.restoreOverrideCursor()
majorVersion, minorVersion = fea.get_ccx_version()
if majorVersion == 2 and minorVersion <= 10:
message = "The used CalculiX version {}.{} creates broken output files.\n" \
"Please upgrade to a newer version.".format(majorVersion, minorVersion)
QtGui.QMessageBox.warning(None, "Upgrade CalculiX", message)
raise
else:
QApplication.restoreOverrideCursor()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def choose_working_dir(self):
current_wd = self.setup_working_dir()
wd = QtGui.QFileDialog.getExistingDirectory(None, 'Choose CalculiX working directory',
current_wd)
if wd:
self.solver_object.WorkingDir = wd
else:
self.solver_object.WorkingDir = current_wd
self.form.le_working_dir.setText(self.solver_object.WorkingDir)
def write_input_file_handler(self):
self.Start = time.time()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
QApplication.restoreOverrideCursor()
if self.check_prerequisites_helper():
QApplication.setOverrideCursor(Qt.WaitCursor)
self.inp_file_name = ""
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.set_analysis_type(self.solver_object.AnalysisType)
fea.update_objects()
fea.write_inp_file()
if fea.inp_file_name != "":
self.inp_file_name = fea.inp_file_name
self.femConsoleMessage("Write completed.")
self.form.pb_edit_inp.setEnabled(True)
self.form.pb_run_ccx.setEnabled(True)
else:
self.femConsoleMessage("Write .inp file failed!", "#FF0000")
QApplication.restoreOverrideCursor()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def check_prerequisites_helper(self):
self.Start = time.time()
self.femConsoleMessage("Check dependencies...")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.update_objects()
message = fea.check_prerequisites()
if message != "":
QtGui.QMessageBox.critical(None, "Missing prerequisit(s)", message)
return False
return True
def start_ext_editor(self, ext_editor_path, filename):
if not hasattr(self, "ext_editor_process"):
self.ext_editor_process = QtCore.QProcess()
if self.ext_editor_process.state() != QtCore.QProcess.Running:
self.ext_editor_process.start(ext_editor_path, [filename])
def editCalculixInputFile(self):
print ('editCalculixInputFile {}'.format(self.inp_file_name))
if self.ccx_prefs.GetBool("UseInternalEditor", True):
FemGui.open(self.inp_file_name)
else:
ext_editor_path = self.ccx_prefs.GetString("ExternalEditorPath", "")
if ext_editor_path:
self.start_ext_editor(ext_editor_path, self.inp_file_name)
else:
print ("External editor is not defined in FEM preferences. Falling back to internal editor")
FemGui.open(self.inp_file_name)
def runCalculix(self):
print ('runCalculix')
self.Start = time.time()
self.femConsoleMessage("CalculiX binary: {}".format(self.CalculixBinary))
self.femConsoleMessage("Run CalculiX...")
# run Calculix
print ('run CalculiX at: {} with: {}'.format(self.CalculixBinary, os.path.splitext(self.inp_file_name)[0]))
# change cwd because ccx may crash if directory has no write permission
# there is also a limit of the length of file names so jump to the document directory
self.cwd = QtCore.QDir.currentPath()
fi = QtCore.QFileInfo(self.inp_file_name)
QtCore.QDir.setCurrent(fi.path())
self.Calculix.start(self.CalculixBinary, ['-i', fi.baseName()])
QApplication.restoreOverrideCursor()
def select_analysis_type(self, analysis_type):
if self.solver_object.AnalysisType != analysis_type:
self.solver_object.AnalysisType = analysis_type
self.form.pb_edit_inp.setEnabled(False)
self.form.pb_run_ccx.setEnabled(False)
def select_static_analysis(self):
self.select_analysis_type('static')
def select_frequency_analysis(self):
self.select_analysis_type('frequency')
def select_thermomech_analysis(self):
self.select_analysis_type('thermomech')
# That function overlaps with FemToolsCcx setup_working_dir and could be removed when the one from FemToolsCcx would be used
def setup_working_dir(self):
wd = self.solver_object.WorkingDir
if not (os.path.isdir(wd)):
try:
os.makedirs(wd)
except:
print ("Dir \'{}\' from FEM preferences doesn't exist and cannot be created.".format(wd))
import tempfile
wd = tempfile.gettempdir()
print ("Dir \'{}\' will be used instead.".format(wd))
return wd

View File

@@ -30,11 +30,17 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
import PyObjects._FemElementFluid1D
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemElementFluid1D:
"A View Provider for the FemElementFluid1D object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -42,6 +48,7 @@ class _ViewProviderFemElementFluid1D:
return ":/icons/fem-fluid-section.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -60,8 +67,7 @@ class _ViewProviderFemElementFluid1D:
return
def setEdit(self, vobj, mode=0):
import PyGui._TaskPanelFemElementFluid1D
taskd = PyGui._TaskPanelFemElementFluid1D._TaskPanelFemElementFluid1D(self.Object)
taskd = _TaskPanelFemElementFluid1D(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -83,3 +89,385 @@ class _ViewProviderFemElementFluid1D:
def __setstate__(self, state):
return None
class _TaskPanelFemElementFluid1D:
'''The TaskPanel for editing References property of FemElementFluid1D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementFluid1D.ui")
QtCore.QObject.connect(self.form.btn_add, QtCore.SIGNAL("clicked()"), self.add_references)
QtCore.QObject.connect(self.form.btn_remove, QtCore.SIGNAL("clicked()"), self.remove_reference)
QtCore.QObject.connect(self.form.cb_section_type, QtCore.SIGNAL("activated(int)"), self.sectiontype_changed)
QtCore.QObject.connect(self.form.cb_liquid_section_type, QtCore.SIGNAL("activated(int)"), self.liquidsectiontype_changed)
QtCore.QObject.connect(self.form.if_manning_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.manning_area_changed)
QtCore.QObject.connect(self.form.if_manning_radius, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.manning_radius_changed)
QtCore.QObject.connect(self.form.sb_manning_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.manning_coefficient_changed)
QtCore.QObject.connect(self.form.if_enlarge_area1, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.enlarge_area1_changed)
QtCore.QObject.connect(self.form.if_enlarge_area2, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.enlarge_area2_changed)
QtCore.QObject.connect(self.form.if_contract_area1, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.contract_area1_changed)
QtCore.QObject.connect(self.form.if_contract_area2, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.contract_area2_changed)
QtCore.QObject.connect(self.form.if_inletpressure, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.inlet_pressure_changed)
QtCore.QObject.connect(self.form.if_outletpressure, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.outlet_pressure_changed)
QtCore.QObject.connect(self.form.if_inletflowrate, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.inlet_flowrate_changed)
QtCore.QObject.connect(self.form.if_outletflowrate, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.outlet_flowrate_changed)
QtCore.QObject.connect(self.form.gb_inletpressure, QtCore.SIGNAL("clicked(bool)"), self.inlet_pressure_active)
QtCore.QObject.connect(self.form.gb_outletpressure, QtCore.SIGNAL("clicked(bool)"), self.outlet_pressure_active)
QtCore.QObject.connect(self.form.gb_inletflowrate, QtCore.SIGNAL("clicked(bool)"), self.inlet_flowrate_active)
QtCore.QObject.connect(self.form.gb_outletflowrate, QtCore.SIGNAL("clicked(bool)"), self.outlet_flowrate_active)
QtCore.QObject.connect(self.form.if_entrance_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.entrance_pipe_area_changed)
QtCore.QObject.connect(self.form.if_entrance_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.entrance_area_changed)
QtCore.QObject.connect(self.form.if_diaphragm_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.diaphragm_pipe_area_changed)
QtCore.QObject.connect(self.form.if_diaphragm_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.diaphragm_area_changed)
QtCore.QObject.connect(self.form.if_bend_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.bend_pipe_area_changed)
QtCore.QObject.connect(self.form.sb_bradius_pdiameter, QtCore.SIGNAL("valueChanged(double)"), self.bradius_pdiameter_changed)
QtCore.QObject.connect(self.form.sb_bend_angle, QtCore.SIGNAL("valueChanged(double)"), self.bend_angle_changed)
QtCore.QObject.connect(self.form.sb_bend_loss_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.bend_loss_coefficient_changed)
QtCore.QObject.connect(self.form.if_gatevalve_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.gatevalve_pipe_area_changed)
QtCore.QObject.connect(self.form.sb_gatevalve_closing_coeff, QtCore.SIGNAL("valueChanged(double)"), self.gatevalve_closing_coeff_changed)
QtCore.QObject.connect(self.form.if_colebrooke_pipe_area, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_pipe_area_changed)
QtCore.QObject.connect(self.form.if_colebrooke_radius, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_radius_changed)
QtCore.QObject.connect(self.form.if_colebrooke_grain_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.colebrooke_grain_diameter_changed)
QtCore.QObject.connect(self.form.sb_colebrooke_form_factor, QtCore.SIGNAL("valueChanged(double)"), self.colebrooke_form_factor_changed)
QtCore.QObject.connect(self.form.tw_pump_characteristics, QtCore.SIGNAL("cellChanged(int, int)"), self.pump_characteristics_changed)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.form.cb_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_fluid_types)
self.form.cb_liquid_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_liquid_types)
self.form.cb_gas_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_gas_types)
self.form.cb_channel_section_type.addItems(PyObjects._FemElementFluid1D._FemElementFluid1D.known_channel_types)
self.get_fluidsection_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_fluidsection_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_fluidsection_props(self):
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.SectionType = self.obj.SectionType
self.LiquidSectionType = self.obj.LiquidSectionType
self.ManningArea = self.obj.ManningArea
self.ManningRadius = self.obj.ManningRadius
self.ManningCoefficient = self.obj.ManningCoefficient
self.EnlargeArea1 = self.obj.EnlargeArea1
self.EnlargeArea2 = self.obj.EnlargeArea2
self.ContractArea1 = self.obj.ContractArea1
self.ContractArea2 = self.obj.ContractArea2
self.OutletPressure = self.obj.OutletPressure
self.InletPressure = self.obj.InletPressure
self.OutletFlowRate = self.obj.OutletFlowRate
self.InletFlowRate = self.obj.InletFlowRate
self.OutletPressureActive = self.obj.OutletPressureActive
self.InletPressureActive = self.obj.InletPressureActive
self.OutletFlowRateActive = self.obj.OutletFlowRateActive
self.InletFlowRateActive = self.obj.InletFlowRateActive
self.EntrancePipeArea = self.obj.EntrancePipeArea
self.EntranceArea = self.obj.EntranceArea
self.DiaphragmPipeArea = self.obj.DiaphragmPipeArea
self.DiaphragmArea = self.obj.DiaphragmArea
self.BendPipeArea = self.obj.BendPipeArea
self.BendRadiusDiameter = self.obj.BendRadiusDiameter
self.BendAngle = self.obj.BendAngle
self.BendLossCoefficient = self.obj.BendLossCoefficient
self.GateValvePipeArea = self.obj.GateValvePipeArea
self.GateValveClosingCoeff = self.obj.GateValveClosingCoeff
self.ColebrookeArea = self.obj.ColebrookeArea
self.ColebrookeRadius = self.obj.ColebrookeRadius
self.ColebrookeGrainDiameter = self.obj.ColebrookeGrainDiameter
self.ColebrookeFormFactor = self.obj.ColebrookeFormFactor
self.PumpFlowRate = self.obj.PumpFlowRate
self.PumpHeadLoss = self.obj.PumpHeadLoss
def set_fluidsection_props(self):
self.obj.References = self.references
self.obj.LiquidSectionType = self.LiquidSectionType
self.obj.SectionType = self.SectionType
self.obj.ManningArea = self.ManningArea
self.obj.ManningRadius = self.ManningRadius
self.obj.ManningCoefficient = self.ManningCoefficient
self.obj.EnlargeArea1 = self.EnlargeArea1
self.obj.EnlargeArea2 = self.EnlargeArea2
self.obj.ContractArea1 = self.ContractArea1
self.obj.ContractArea2 = self.ContractArea2
self.obj.OutletPressure = self.OutletPressure
self.obj.InletPressure = self.InletPressure
self.obj.OutletFlowRate = self.OutletFlowRate
self.obj.InletFlowRate = self.InletFlowRate
self.obj.OutletPressureActive = self.OutletPressureActive
self.obj.InletPressureActive = self.InletPressureActive
self.obj.OutletFlowRateActive = self.OutletFlowRateActive
self.obj.InletFlowRateActive = self.InletFlowRateActive
self.obj.EntrancePipeArea = self.EntrancePipeArea
self.obj.EntranceArea = self.EntranceArea
self.obj.DiaphragmPipeArea = self.DiaphragmPipeArea
self.obj.DiaphragmArea = self.DiaphragmArea
self.obj.BendPipeArea = self.BendPipeArea
self.obj.BendRadiusDiameter = self.BendRadiusDiameter
self.obj.BendAngle = self.BendAngle
self.obj.BendLossCoefficient = self.BendLossCoefficient
self.obj.GateValvePipeArea = self.GateValvePipeArea
self.obj.GateValveClosingCoeff = self.GateValveClosingCoeff
self.obj.ColebrookeArea = self.ColebrookeArea
self.obj.ColebrookeRadius = self.ColebrookeRadius
self.obj.ColebrookeGrainDiameter = self.ColebrookeGrainDiameter
self.obj.ColebrookeFormFactor = self.ColebrookeFormFactor
self.obj.PumpFlowRate = self.PumpFlowRate
self.obj.PumpHeadLoss = self.PumpHeadLoss
def update(self):
'fills the widgets'
index_sectiontype = self.form.cb_section_type.findText(self.SectionType)
self.form.cb_section_type.setCurrentIndex(index_sectiontype)
self.form.sw_section_type.setCurrentIndex(index_sectiontype)
index_liquidsectiontype = self.form.cb_liquid_section_type.findText(self.LiquidSectionType)
self.form.cb_liquid_section_type.setCurrentIndex(index_liquidsectiontype)
self.form.sw_liquid_section_type.setCurrentIndex(index_liquidsectiontype)
self.form.if_manning_area.setText(self.ManningArea.UserString)
self.form.if_manning_radius.setText(self.ManningRadius.UserString)
self.form.sb_manning_coefficient.setValue(self.ManningCoefficient)
self.form.if_enlarge_area1.setText(self.EnlargeArea1.UserString)
self.form.if_enlarge_area2.setText(self.EnlargeArea2.UserString)
self.form.if_contract_area1.setText(self.ContractArea1.UserString)
self.form.if_contract_area2.setText(self.ContractArea2.UserString)
self.form.if_inletpressure.setText(FreeCAD.Units.Quantity(1000 * self.InletPressure, FreeCAD.Units.Pressure).UserString)
self.form.if_outletpressure.setText(FreeCAD.Units.Quantity(1000 * self.OutletPressure, FreeCAD.Units.Pressure).UserString)
self.form.if_inletflowrate.setText(str(self.InletFlowRate))
self.form.if_outletflowrate.setText(str(self.OutletFlowRate))
self.form.gb_inletpressure.setChecked(self.InletPressureActive)
self.form.gb_outletpressure.setChecked(self.OutletPressureActive)
self.form.gb_inletflowrate.setChecked(self.InletFlowRateActive)
self.form.gb_outletflowrate.setChecked(self.OutletFlowRateActive)
self.form.if_entrance_pipe_area.setText(self.EntrancePipeArea.UserString)
self.form.if_entrance_area.setText(self.EntranceArea.UserString)
self.form.if_diaphragm_pipe_area.setText(self.DiaphragmPipeArea.UserString)
self.form.if_diaphragm_area.setText(self.DiaphragmArea.UserString)
self.form.if_bend_pipe_area.setText(self.BendPipeArea.UserString)
self.form.sb_bradius_pdiameter.setValue(self.BendRadiusDiameter)
self.form.sb_bend_angle.setValue(self.BendAngle)
self.form.sb_bend_loss_coefficient.setValue(self.BendLossCoefficient)
self.form.if_gatevalve_pipe_area.setText(self.GateValvePipeArea.UserString)
self.form.sb_gatevalve_closing_coeff.setValue(self.GateValveClosingCoeff)
self.form.if_colebrooke_pipe_area.setText(self.ColebrookeArea.UserString)
self.form.if_colebrooke_radius.setText(self.ColebrookeRadius.UserString)
self.form.if_colebrooke_grain_diameter.setText(self.ColebrookeGrainDiameter.UserString)
self.form.sb_colebrooke_form_factor.setValue(self.ColebrookeFormFactor)
for i in range(len(self.PumpFlowRate)):
self.form.tw_pump_characteristics.setItem(i, 0, QtGui.QTableWidgetItem(str(self.PumpFlowRate[i])))
self.form.tw_pump_characteristics.setItem(i, 1, QtGui.QTableWidgetItem(str(self.PumpHeadLoss[i])))
self.rebuild_list_References()
def sectiontype_changed(self, index):
if index < 0:
return
self.form.cb_section_type.setCurrentIndex(index)
self.form.sw_section_type.setCurrentIndex(index)
self.SectionType = str(self.form.cb_section_type.itemText(index)) # form returns unicode
def liquidsectiontype_changed(self, index):
if index < 0:
return
self.form.cb_liquid_section_type.setCurrentIndex(index)
self.form.sw_liquid_section_type.setCurrentIndex(index)
self.LiquidSectionType = str(self.form.cb_liquid_section_type.itemText(index)) # form returns unicode
def manning_area_changed(self, base_quantity_value):
self.ManningArea = base_quantity_value
def manning_radius_changed(self, base_quantity_value):
self.ManningRadius = base_quantity_value
def manning_coefficient_changed(self, base_quantity_value):
self.ManningCoefficient = base_quantity_value
def enlarge_area1_changed(self, base_quantity_value):
self.EnlargeArea1 = base_quantity_value
def enlarge_area2_changed(self, base_quantity_value):
self.EnlargeArea2 = base_quantity_value
def contract_area1_changed(self, base_quantity_value):
self.ContractArea1 = base_quantity_value
def contract_area2_changed(self, base_quantity_value):
self.ContractArea2 = base_quantity_value
def inlet_pressure_changed(self, base_quantity_value):
self.InletPressure = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("MPa"))
def outlet_pressure_changed(self, base_quantity_value):
self.OutletPressure = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("MPa"))
def inlet_flowrate_changed(self, base_quantity_value):
self.InletFlowRate = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("kg/s"))
def outlet_flowrate_changed(self, base_quantity_value):
self.OutletFlowRate = float(FreeCAD.Units.Quantity(base_quantity_value).getValueAs("kg/s"))
def inlet_pressure_active(self, active):
self.InletPressureActive = active
def outlet_pressure_active(self, active):
self.OutletPressureActive = active
def inlet_flowrate_active(self, active):
self.InletFlowRateActive = active
def outlet_flowrate_active(self, active):
self.OutletFlowRateActive = active
def entrance_pipe_area_changed(self, base_quantity_value):
self.EntrancePipeArea = base_quantity_value
def entrance_area_changed(self, base_quantity_value):
self.EntranceArea = base_quantity_value
def diaphragm_pipe_area_changed(self, base_quantity_value):
self.DiaphragmPipeArea = base_quantity_value
def diaphragm_area_changed(self, base_quantity_value):
self.DiaphragmArea = base_quantity_value
def bend_pipe_area_changed(self, base_quantity_value):
self.BendPipeArea = base_quantity_value
def bradius_pdiameter_changed(self, base_quantity_value):
self.BendRadiusDiameter = base_quantity_value
def bend_angle_changed(self, base_quantity_value):
self.BendAngle = base_quantity_value
def bend_loss_coefficient_changed(self, base_quantity_value):
self.BendLossCoefficient = base_quantity_value
def gatevalve_pipe_area_changed(self, base_quantity_value):
self.GateValvePipeArea = base_quantity_value
def gatevalve_closing_coeff_changed(self, base_quantity_value):
self.GateValveClosingCoeff = base_quantity_value
def colebrooke_pipe_area_changed(self, base_quantity_value):
self.ColebrookeArea = base_quantity_value
def colebrooke_radius_changed(self, base_quantity_value):
self.ColebrookeRadius = base_quantity_value
def colebrooke_grain_diameter_changed(self, base_quantity_value):
self.ColebrookeGrainDiameter = base_quantity_value
def colebrooke_form_factor_changed(self, base_quantity_value):
self.ColebrookeFormFactor = base_quantity_value
def pump_characteristics_changed(self, row, column):
if column == 0:
self.PumpFlowRate[row] = float(self.form.tw_pump_characteristics.item(row, column).text())
else:
self.PumpHeadLoss[row] = float(self.form.tw_pump_characteristics.item(row, column).text())
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Edges by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Edge':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -29,11 +29,17 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
import PyObjects._FemElementGeometry1D
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemElementGeometry1D:
"A View Provider for the FemElementGeometry1D object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -41,6 +47,7 @@ class _ViewProviderFemElementGeometry1D:
return ":/icons/fem-beam-section.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -59,8 +66,7 @@ class _ViewProviderFemElementGeometry1D:
return
def setEdit(self, vobj, mode=0):
import PyGui._TaskPanelFemElementGeometry1D
taskd = PyGui._TaskPanelFemElementGeometry1D._TaskPanelFemElementGeometry1D(self.Object)
taskd = _TaskPanelFemElementGeometry1D(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -82,3 +88,185 @@ class _ViewProviderFemElementGeometry1D:
def __setstate__(self, state):
return None
class _TaskPanelFemElementGeometry1D:
'''The TaskPanel for editing References property of FemElementGeometry1D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementGeometry1D.ui")
QtCore.QObject.connect(self.form.cb_crosssectiontype, QtCore.SIGNAL("activated(int)"), self.sectiontype_changed)
QtCore.QObject.connect(self.form.if_rec_height, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.rec_height_changed)
QtCore.QObject.connect(self.form.if_rec_width, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.rec_width_changed)
QtCore.QObject.connect(self.form.if_circ_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.circ_diameter_changed)
QtCore.QObject.connect(self.form.if_pipe_diameter, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.pipe_diameter_changed)
QtCore.QObject.connect(self.form.if_pipe_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.pipe_thickness_changed)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.form.cb_crosssectiontype.addItems(PyObjects._FemElementGeometry1D._FemElementGeometry1D.known_beam_types) # it is inside the class thus double _FemElementGeometry1D
self.get_beamsection_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_beamsection_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_beamsection_props(self):
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.SectionType = self.obj.SectionType
self.RectHeight = self.obj.RectHeight
self.RectWidth = self.obj.RectWidth
self.CircDiameter = self.obj.CircDiameter
self.PipeDiameter = self.obj.PipeDiameter
self.PipeThickness = self.obj.PipeThickness
def set_beamsection_props(self):
self.obj.References = self.references
self.obj.SectionType = self.SectionType
self.obj.RectHeight = self.RectHeight
self.obj.RectWidth = self.RectWidth
self.obj.CircDiameter = self.CircDiameter
self.obj.PipeDiameter = self.PipeDiameter
self.obj.PipeThickness = self.PipeThickness
def update(self):
'fills the widgets'
index_crosssectiontype = self.form.cb_crosssectiontype.findText(self.SectionType)
self.form.cb_crosssectiontype.setCurrentIndex(index_crosssectiontype)
self.form.if_rec_height.setText(self.RectHeight.UserString)
self.form.if_rec_width.setText(self.RectWidth.UserString)
self.form.if_circ_diameter.setText(self.CircDiameter.UserString)
self.form.if_pipe_diameter.setText(self.PipeDiameter.UserString)
self.form.if_pipe_thickness.setText(self.PipeThickness.UserString)
self.rebuild_list_References()
def sectiontype_changed(self, index):
if index < 0:
return
self.form.cb_crosssectiontype.setCurrentIndex(index)
self.SectionType = str(self.form.cb_crosssectiontype.itemText(index)) # form returns unicode
def rec_height_changed(self, base_quantity_value):
self.RectHeight = base_quantity_value
def rec_width_changed(self, base_quantity_value):
self.RectWidth = base_quantity_value
def circ_diameter_changed(self, base_quantity_value):
self.CircDiameter = base_quantity_value
def pipe_diameter_changed(self, base_quantity_value):
self.PipeDiameter = base_quantity_value
def pipe_thickness_changed(self, base_quantity_value):
self.PipeThickness = base_quantity_value
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Edges by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Edge':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -29,11 +29,16 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemElementGeometry2D:
"A View Provider for the FemElementGeometry2D object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -41,6 +46,7 @@ class _ViewProviderFemElementGeometry2D:
return ":/icons/fem-shell-thickness.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -59,8 +65,7 @@ class _ViewProviderFemElementGeometry2D:
return
def setEdit(self, vobj, mode=0):
import PyGui._TaskPanelFemElementGeometry2D
taskd = PyGui._TaskPanelFemElementGeometry2D._TaskPanelFemElementGeometry2D(self.Object)
taskd = _TaskPanelFemElementGeometry2D(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -82,3 +87,144 @@ class _ViewProviderFemElementGeometry2D:
def __setstate__(self, state):
return None
class _TaskPanelFemElementGeometry2D:
'''The TaskPanel for editing References property of FemElementGeometry2D objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemElementGeometry2D.ui")
QtCore.QObject.connect(self.form.if_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.thickness_changed)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_shellthickness_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_shellthickness_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_shellthickness_props(self):
self.thickness = self.obj.Thickness
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_shellthickness_props(self):
self.obj.References = self.references
self.obj.Thickness = self.thickness
def update(self):
'fills the widgets'
self.form.if_thickness.setText(self.thickness.UserString)
self.rebuild_list_References()
def thickness_changed(self, base_quantity_value):
self.thickness = base_quantity_value
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
print_message = "Select Faces by single click on them to add them to the list"
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
# print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape"):
if selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if elt.ShapeType == 'Face':
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -31,6 +31,17 @@ import FreeCAD
import FreeCADGui
# for the panel
from FreeCAD import Units
from PySide import QtCore
from PySide import QtGui
from PySide.QtGui import QFileDialog
from PySide.QtGui import QMessageBox
import sys
if sys.version_info.major >= 3:
unicode = str
class _ViewProviderFemMaterial:
"A View Provider for the FemMaterial object"
@@ -51,8 +62,7 @@ class _ViewProviderFemMaterial:
return
def setEdit(self, vobj, mode):
import PyGui._TaskPanelFemMaterial
taskd = PyGui._TaskPanelFemMaterial._TaskPanelFemMaterial(self.Object)
taskd = _TaskPanelFemMaterial(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -75,3 +85,608 @@ class _ViewProviderFemMaterial:
def __setstate__(self, state):
return None
class _TaskPanelFemMaterial:
'''The editmode TaskPanel for FemMaterial objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces and Edges by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.material = self.obj.Material
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMaterial.ui")
QtCore.QObject.connect(self.form.pushButton_MatWeb, QtCore.SIGNAL("clicked()"), self.goto_MatWeb)
QtCore.QObject.connect(self.form.pushButton_saveas, QtCore.SIGNAL("clicked()"), self.export_material)
QtCore.QObject.connect(self.form.cb_materials, QtCore.SIGNAL("activated(int)"), self.choose_material)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
# basic properties must be provided
QtCore.QObject.connect(self.form.input_fd_density, QtCore.SIGNAL("valueChanged(double)"), self.density_changed)
# mechanical properties
QtCore.QObject.connect(self.form.input_fd_young_modulus, QtCore.SIGNAL("valueChanged(double)"), self.ym_changed)
QtCore.QObject.connect(self.form.spinBox_poisson_ratio, QtCore.SIGNAL("valueChanged(double)"), self.pr_changed)
# thermal properties
QtCore.QObject.connect(self.form.input_fd_thermal_conductivity, QtCore.SIGNAL("valueChanged(double)"), self.tc_changed)
QtCore.QObject.connect(self.form.input_fd_expansion_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.tec_changed)
QtCore.QObject.connect(self.form.input_fd_specific_heat, QtCore.SIGNAL("valueChanged(double)"), self.sh_changed)
# fluidic properties, only volumetric thermal expansion coeff makes sense
QtCore.QObject.connect(self.form.input_fd_kinematic_viscosity, QtCore.SIGNAL("valueChanged(double)"), self.kinematic_viscosity_changed)
QtCore.QObject.connect(self.form.input_fd_vol_expansion_coefficient, QtCore.SIGNAL("valueChanged(double)"), self.vtec_changed)
# hide some groupBox according to material category
self.form.label_category.setText(self.obj.Category)
if self.obj.Category == 'Fluid':
self.form.groupBox_mechanical.setVisible(0)
self.form.label_expansion_coefficient.setVisible(0)
self.form.input_fd_expansion_coefficient.setVisible(0)
else:
self.form.groupBox_fluidic.setVisible(0)
self.form.label_vol_expansion_coefficient.setVisible(0)
self.form.input_fd_vol_expansion_coefficient.setVisible(0)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.import_materials()
previous_mat_path = self.get_material_path(self.material)
if not previous_mat_path:
material_name = self.get_material_name(self.material)
if material_name != 'None':
FreeCAD.Console.PrintMessage("Previously used material cannot be found in material directories. Using transient material.\n")
self.add_transient_material(self.material)
index = self.form.cb_materials.findData(material_name)
else:
if not self.material:
index = self.form.cb_materials.findText(material_name)
else:
FreeCAD.Console.PrintMessage("None material was previously used. Reload values.\n")
self.add_transient_material(self.material)
index = self.form.cb_materials.findData(material_name)
self.choose_material(index)
else:
index = self.form.cb_materials.findData(previous_mat_path)
self.choose_material(index)
self.has_equal_references_shape_types()
self.rebuild_list_References()
def accept(self):
self.setback_listobj_visibility()
# print(self.material)
self.remove_active_sel_server()
if self.has_equal_references_shape_types():
self.obj.Material = self.material
self.obj.References = self.references
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
doc.Document.recompute()
def reject(self):
self.setback_listobj_visibility()
self.remove_active_sel_server()
doc = FreeCADGui.getDocument(self.obj.Document)
doc.resetEdit()
def remove_active_sel_server(self):
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def has_equal_references_shape_types(self):
import femmesh.meshtools as FemMeshTools
ref_shty = ''
for ref in self.references:
r = FemMeshTools.get_element(ref[0], ref[1]) # the method getElement(element) does not return Solid elements
# print(' ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1])
if not ref_shty:
ref_shty = r.ShapeType
if r.ShapeType != ref_shty:
message = 'Multiple shape types are not allowed in the reference list.\n'
FreeCAD.Console.PrintError(message)
QMessageBox.critical(None, "Multiple ShapeTypes not allowed", message)
return False
return True
def goto_MatWeb(self):
import webbrowser
webbrowser.open("http://matweb.com")
def check_material_keys(self):
if 'Density' in self.material:
if 'Density' not in str(Units.Unit(self.material['Density'])):
print('Density in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['Density'] = '0 kg/m^3'
else:
print('Density not found in material data of: ' + self.material['Name'])
self.material['Density'] = '0 kg/m^3'
if self.obj.Category == 'Solid':
# mechanical properties
if 'YoungsModulus' in self.material:
if 'Pressure' not in str(Units.Unit(self.material['YoungsModulus'])): # unit type of YoungsModulus is Pressure
print('YoungsModulus in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['YoungsModulus'] = '0 MPa'
else:
print('YoungsModulus not found in material data of: ' + self.material['Name'])
self.material['YoungsModulus'] = '0 MPa'
if 'PoissonRatio' not in self.material: # PoissonRatio does not have a unit, we do not gone check for a unit
print('PoissonRatio not found in material data of: ' + self.material['Name'])
self.material['PoissonRatio'] = '0'
if self.obj.Category == 'Fluid':
# Fluidic properties
if 'KinematicViscosity' in self.material:
if 'KinematicViscosity' not in str(Units.Unit(self.material['KinematicViscosity'])):
print('KinematicViscosity in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['KinematicViscosity'] = '0 m^2/s'
else:
print('KinematicViscosity not found in material data of: ' + self.material['Name'])
self.material['KinematicViscosity'] = '0 m^2/s'
if 'VolumetricThermalExpansionCoefficient' in self.material:
if 'ThermalExpansionCoefficient' not in str(Units.Unit(self.material['VolumetricThermalExpansionCoefficient'])): # unit type of VolumetricThermalExpansionCoefficient is ThermalExpansionCoefficient
print('VolumetricThermalExpansionCoefficient in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['VolumetricThermalExpansionCoefficient'] = '0 m/m/K'
else:
print('VolumetricThermalExpansionCoefficient not found in material data of: ' + self.material['Name'])
self.material['VolumetricThermalExpansionCoefficient'] = '0 m/m/K'
# Thermal properties
if 'ThermalConductivity' in self.material:
if 'ThermalConductivity' not in str(Units.Unit(self.material['ThermalConductivity'])):
print('ThermalConductivity in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['ThermalConductivity'] = '0 W/m/K'
else:
print('ThermalConductivity not found in material data of: ' + self.material['Name'])
self.material['ThermalConductivity'] = '0 W/m/K'
if 'ThermalExpansionCoefficient' in self.material:
if 'ThermalExpansionCoefficient' not in str(Units.Unit(self.material['ThermalExpansionCoefficient'])):
print('ThermalExpansionCoefficient in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['ThermalExpansionCoefficient'] = '0 um/m/K'
else:
print('ThermalExpansionCoefficient not found in material data of: ' + self.material['Name'])
self.material['ThermalExpansionCoefficient'] = '0 um/m/K'
if 'SpecificHeat' in self.material:
if 'SpecificHeat' not in str(Units.Unit(self.material['SpecificHeat'])):
print('SpecificHeat in material data seams to have no unit or a wrong unit (reset the value): ' + self.material['Name'])
self.material['SpecificHeat'] = '0 J/kg/K'
else:
print('SpecificHeat not found in material data of: ' + self.material['Name'])
self.material['SpecificHeat'] = '0 J/kg/K'
def ym_changed(self, value):
# FreeCADs standard unit for stress is kPa
old_ym = Units.Quantity(self.material['YoungsModulus']).getValueAs("kPa")
variation = 0.001
if value:
if not (1 - variation < float(old_ym) / value < 1 + variation):
# YoungsModulus has changed
material = self.material
material['YoungsModulus'] = unicode(value) + " kPa"
self.material = material
def density_changed(self, value):
# FreeCADs standard unit for density is kg/mm^3
old_density = Units.Quantity(self.material['Density']).getValueAs("kg/m^3")
variation = 0.001
if value:
if not (1 - variation < float(old_density) / value < 1 + variation):
# density has changed
material = self.material
value_in_kg_per_m3 = value * 1e9
material['Density'] = unicode(value_in_kg_per_m3) + " kg/m^3" # SvdW:Keep density in SI units for easier readability
self.material = material
def pr_changed(self, value):
old_pr = Units.Quantity(self.material['PoissonRatio'])
variation = 0.001
if value:
if not (1 - variation < float(old_pr) / value < 1 + variation):
# PoissonRatio has changed
material = self.material
material['PoissonRatio'] = unicode(value)
self.material = material
def tc_changed(self, value):
old_tc = Units.Quantity(self.material['ThermalConductivity']).getValueAs("W/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_tc) / value < 1 + variation):
# ThermalConductivity has changed
material = self.material
value_in_W_per_mK = value * 1e-3 # To compensate for use of SI units
material['ThermalConductivity'] = unicode(value_in_W_per_mK) + " W/m/K"
self.material = material
def tec_changed(self, value):
old_tec = Units.Quantity(self.material['ThermalExpansionCoefficient']).getValueAs("um/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_tec) / value < 1 + variation):
# ThermalExpansionCoefficient has changed
material = self.material
value_in_um_per_mK = value * 1e6 # To compensate for use of SI units
material['ThermalExpansionCoefficient'] = unicode(value_in_um_per_mK) + " um/m/K"
self.material = material
def sh_changed(self, value):
old_sh = Units.Quantity(self.material['SpecificHeat']).getValueAs("J/kg/K")
variation = 0.001
if value:
if not (1 - variation < float(old_sh) / value < 1 + variation):
# SpecificHeat has changed
material = self.material
value_in_J_per_kgK = value * 1e-6 # To compensate for use of SI units
material['SpecificHeat'] = unicode(value_in_J_per_kgK) + " J/kg/K"
self.material = material
################ fluidic #########################
def vtec_changed(self, value):
old_vtec = Units.Quantity(self.material['VolumetricThermalExpansionCoefficient']).getValueAs("m/m/K")
variation = 0.001
if value:
if not (1 - variation < float(old_vtec) / value < 1 + variation):
# VolumetricThermalExpansionCoefficient has changed
material = self.material
value_in_one_per_K = value
material['VolumetricThermalExpansionCoefficient'] = unicode(value_in_one_per_K) + " m/m/K"
self.material = material
def kinematic_viscosity_changed(self, value):
old_nu = Units.Quantity(self.material['KinematicViscosity']).getValueAs("m^2/s")
variation = 0.000001
if value:
if not (1 - variation < float(old_nu) / value < 1 + variation):
# KinematicViscosity has changed
material = self.material
value_in_m2_per_second = value
material['KinematicViscosity'] = unicode(value_in_m2_per_second) + " m^2/s"
self.material = material
def choose_material(self, index):
if index < 0:
return
mat_file_path = self.form.cb_materials.itemData(index)
self.material = self.materials[mat_file_path]
self.form.cb_materials.setCurrentIndex(index)
self.check_material_keys()
self.set_mat_params_in_combo_box(self.material)
gen_mat_desc = ""
if 'Description' in self.material:
gen_mat_desc = self.material['Description']
self.form.l_mat_description.setText(gen_mat_desc)
def get_material_name(self, material):
if 'Name' in self.material:
return self.material['Name']
else:
return 'None'
def get_material_path(self, material):
for a_mat in self.materials:
unmatched_items = set(self.materials[a_mat].items()) ^ set(material.items())
if len(unmatched_items) == 0:
return a_mat
return ""
def set_mat_params_in_combo_box(self, matmap):
if 'YoungsModulus' in matmap:
ym_new_unit = "MPa"
ym = FreeCAD.Units.Quantity(matmap['YoungsModulus'])
ym_with_new_unit = ym.getValueAs(ym_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(ym_with_new_unit, ym_new_unit))
self.form.input_fd_young_modulus.setText(q.UserString)
if 'PoissonRatio' in matmap:
self.form.spinBox_poisson_ratio.setValue(float(matmap['PoissonRatio']))
# Fluidic properties
if 'KinematicViscosity' in matmap:
nu_new_unit = "m^2/s"
nu = FreeCAD.Units.Quantity(matmap['KinematicViscosity'])
nu_with_new_unit = nu.getValueAs(nu_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(nu_with_new_unit, nu_new_unit))
self.form.input_fd_kinematic_viscosity.setText(q.UserString)
# For isotropic materials the volumetric thermal expansion coefficient is three times the linear coefficient:
if 'VolumetricThermalExpansionCoefficient' in matmap: # linear, only for solid
vtec_new_unit = "m/m/K"
vtec = FreeCAD.Units.Quantity(matmap['VolumetricThermalExpansionCoefficient'])
vtec_with_new_unit = vtec.getValueAs(vtec_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(vtec_with_new_unit, vtec_new_unit))
self.form.input_fd_vol_expansion_coefficient.setText(q.UserString)
if 'Density' in matmap:
density_new_unit = "kg/m^3"
density = FreeCAD.Units.Quantity(matmap['Density'])
density_with_new_unit = density.getValueAs(density_new_unit)
#self.form.input_fd_density.setText("{} {}".format(density_with_new_unit, density_new_unit))
q = FreeCAD.Units.Quantity("{} {}".format(density_with_new_unit, density_new_unit))
self.form.input_fd_density.setText(q.UserString)
# thermal properties
if 'ThermalConductivity' in matmap:
tc_new_unit = "W/m/K"
tc = FreeCAD.Units.Quantity(matmap['ThermalConductivity'])
tc_with_new_unit = tc.getValueAs(tc_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(tc_with_new_unit, tc_new_unit))
self.form.input_fd_thermal_conductivity.setText(q.UserString)
if 'ThermalExpansionCoefficient' in matmap: # linear, only for solid
tec_new_unit = "um/m/K"
tec = FreeCAD.Units.Quantity(matmap['ThermalExpansionCoefficient'])
tec_with_new_unit = tec.getValueAs(tec_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(tec_with_new_unit, tec_new_unit))
self.form.input_fd_expansion_coefficient.setText(q.UserString)
if 'SpecificHeat' in matmap:
sh_new_unit = "J/kg/K"
sh = FreeCAD.Units.Quantity(matmap['SpecificHeat'])
sh_with_new_unit = sh.getValueAs(sh_new_unit)
q = FreeCAD.Units.Quantity("{} {}".format(sh_with_new_unit, sh_new_unit))
self.form.input_fd_specific_heat.setText(q.UserString)
def add_transient_material(self, material):
material_name = self.get_material_name(material)
self.form.cb_materials.addItem(QtGui.QIcon(":/icons/help-browser.svg"), material_name, material_name)
self.materials[material_name] = material
######################## material import and export ###################
def import_materials(self):
self.materials = {}
self.pathList = []
self.form.cb_materials.clear()
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
if self.obj.Category == 'Fluid':
self.import_fluid_materials()
else:
self.import_solid_materials()
def import_solid_materials(self):
use_built_in_materials = self.fem_prefs.GetBool("UseBuiltInMaterials", True)
if use_built_in_materials:
system_mat_dir = FreeCAD.getResourceDir() + "/Mod/Material/StandardMaterial"
self.add_mat_dir(system_mat_dir, ":/icons/freecad.svg")
use_mat_from_config_dir = self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True)
if use_mat_from_config_dir:
user_mat_dirname = FreeCAD.getUserAppDataDir() + "Materials"
self.add_mat_dir(user_mat_dirname, ":/icons/preferences-general.svg")
use_mat_from_custom_dir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
if use_mat_from_custom_dir:
custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
self.add_mat_dir(custom_mat_dir, ":/icons/user.svg")
def import_fluid_materials(self):
#use_built_in_materials = self.fem_prefs.GetBool("UseBuiltInMaterials", True)
#if use_built_in_materials:
system_mat_dir = FreeCAD.getResourceDir() + "/Mod/Material/FluidMaterial"
self.add_mat_dir(system_mat_dir, ":/icons/freecad.svg")
use_mat_from_config_dir = self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True)
if use_mat_from_config_dir:
user_mat_dirname = FreeCAD.getUserAppDataDir() + "FluidMaterial"
self.add_mat_dir(user_mat_dirname, ":/icons/preferences-general.svg")
use_mat_from_custom_dir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
if use_mat_from_custom_dir:
custom_mat_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
self.add_mat_dir(custom_mat_dir, ":/icons/user.svg")
def add_mat_dir(self, mat_dir, icon):
import glob
import os
import Material
mat_file_extension = ".FCMat"
ext_len = len(mat_file_extension)
dir_path_list = glob.glob(mat_dir + '/*' + mat_file_extension)
self.pathList = self.pathList + dir_path_list
material_name_list = []
for a_path in dir_path_list:
material_name = os.path.basename(a_path[:-ext_len])
self.materials[a_path] = Material.importFCMat(a_path)
material_name_list.append([material_name, a_path])
material_name_list.sort()
for mat in material_name_list:
self.form.cb_materials.addItem(QtGui.QIcon(icon), mat[0], mat[1])
def export_FCMat(self, fileName, matDict):
"""
Write a material dictionary to a FCMat file, a version without group support, with Python3
<https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Material/Material.py>
"""
try:
import ConfigParser as configparser
except:
import configparser # Python 3
# himport string
Config = configparser.ConfigParser()
Config.optionxform = str # disable conversion all uppercase leter in key into lower case
# ignore creating group, just fill all into group 'FCMat'
grp = 'FCMat'
if not Config.has_section(grp):
Config.add_section(grp)
for x in matDict.keys():
Config.set(grp, x, matDict[x])
Preamble = "# This is a FreeCAD material-card file\n\n"
# Writing our configuration file to 'example.cfg'
with open(fileName, 'wb') as configfile:
configfile.write(Preamble)
Config.write(configfile)
def export_material(self):
import os
if self.obj.Category == 'Fluid':
MaterialDir = 'FluidMaterial'
else:
MaterialDir = 'Material'
_UseMaterialsFromCustomDir = self.fem_prefs.GetBool("UseMaterialsFromCustomDir", True)
_dir = self.fem_prefs.GetString("CustomMaterialsDir", "")
if _UseMaterialsFromCustomDir and _dir != "" and os.path.isdir(_dir):
TargetDir = self.fem_prefs.GetString("CustomMaterialsDir", "")
elif self.fem_prefs.GetBool("UseMaterialsFromConfigDir", True):
TargetDir = FreeCAD.getUserAppDataDir() + os.path.sep + MaterialDir # $HOME/.FreeCAD
else:
FreeCAD.Console.PrintMessage("Customed material saving directory is not setup in Fem preference")
if not os.path.exists(TargetDir):
os.mkdir(TargetDir)
saveName, Filter = QFileDialog.getSaveFileName(None, "Save a Material property file", TargetDir, "*.FCMat")
if not saveName == "":
print(saveName)
knownMaterials = [self.form.cb_materials.itemText(i) for i in range(self.form.cb_materials.count())]
material_name = os.path.basename(saveName[:-len('.FCMat')])
if material_name not in knownMaterials:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully save the Material property file: " + saveName + "\n")
else:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully overwritren the Material property file: " + saveName + "\n")
"""
msgBox = QMessageBox()
msgBox.setText("FcMat file name {} has existed in {} or system folder, overwriting?\n".format(saveName, TargetDir))
msgBox.addButton(QMessageBox.Yes)
msgBox.addButton(QMessageBox.No)
msgBox.setDefaultButton(QMessageBox.No)
ret = msgBox.exec_()
if ret == QMessageBox.Yes:
self.export_FCMat(saveName, self.obj.Material)
FreeCAD.Console.PrintMessage("Successfully overwritren the Material property file: "+ saveName + "\n")
"""
###################geometry reference selection #################
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
if ref[1]:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
else:
refname_to_compare_listentry = ref[0].Name
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' --> ', selection[0].Name, ' --> ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
if ref[1]:
item_name = ref[0].Name + ':' + ref[1]
else:
item_name = ref[0].Name
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -29,11 +29,16 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemMeshBoundaryLayer:
"A View Provider for the FemMeshBoundaryLayer object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -41,6 +46,7 @@ class _ViewProviderFemMeshBoundaryLayer:
return ":/icons/fem-femmesh-boundary-layer.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -64,8 +70,7 @@ class _ViewProviderFemMeshBoundaryLayer:
if o.isDerivedFrom("Fem::FemMeshObject"):
o.ViewObject.hide()
# show task panel
import PyGui._TaskPanelFemMeshBoundaryLayer
taskd = PyGui._TaskPanelFemMeshBoundaryLayer._TaskPanelFemMeshBoundaryLayer(self.Object)
taskd = _TaskPanelFemMeshBoundaryLayer(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -87,3 +92,175 @@ class _ViewProviderFemMeshBoundaryLayer:
def __setstate__(self, state):
return None
class _TaskPanelFemMeshBoundaryLayer:
'''The TaskPanel for editing References property of FemMeshBoundaryLayer objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces for 3D, Edges for 2D by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui")
QtCore.QObject.connect(self.form.bl_number_of_layers, QtCore.SIGNAL("valueChanged(int)"), self.bl_number_of_layers_changed)
QtCore.QObject.connect(self.form.bl_min_thickness, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.bl_min_thickness_changed)
QtCore.QObject.connect(self.form.bl_growth_rate, QtCore.SIGNAL("valueChanged(double)"), self.bl_growth_rate_changed) # becareful of signal signature for QDoubleSpinbox
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_mesh_boundarylayer_props()
self.update()
def get_mesh_boundarylayer_props(self):
self.bl_min_thickness = self.obj.MinimumThickness
self.bl_number_of_layers = self.obj.NumberOfLayers
self.bl_growth_rate = self.obj.GrowthRate
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_mesh_boundarylayer_props(self):
self.obj.MinimumThickness = self.bl_min_thickness
self.obj.NumberOfLayers = self.bl_number_of_layers
self.obj.GrowthRate = self.bl_growth_rate
self.obj.References = self.references
def update(self):
'fills the widgets with data'
self.form.bl_min_thickness.setText(self.bl_min_thickness.UserString)
self.form.bl_number_of_layers.setValue(self.bl_number_of_layers)
self.form.bl_growth_rate.setValue(self.bl_growth_rate)
self.rebuild_list_References()
def bl_min_thickness_changed(self, base_quantity_value):
self.bl_min_thickness = base_quantity_value
def bl_number_of_layers_changed(self, value):
self.bl_number_of_layers = value
def bl_growth_rate_changed(self, value):
self.bl_growth_rate = value
def accept(self):
self.set_mesh_boundarylayer_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
############### identical to FemMeshRegion ############
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)

View File

@@ -32,8 +32,18 @@ import FreeCADGui
import FemGui
# for the panel
import PyObjects._FemMeshGmsh
from PySide import QtCore
from PySide import QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
import time
class _ViewProviderFemMeshGmsh:
"A View Provider for the FemMeshGmsh object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -52,8 +62,7 @@ class _ViewProviderFemMeshGmsh:
def setEdit(self, vobj, mode):
self.ViewObject.show() # show the mesh on edit if it is hided
import PyGui._TaskPanelFemMeshGmsh
taskd = PyGui._TaskPanelFemMeshGmsh._TaskPanelFemMeshGmsh(self.Object)
taskd = _TaskPanelFemMeshGmsh(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -139,3 +148,141 @@ class _ViewProviderFemMeshGmsh:
except Exception as err:
FreeCAD.Console.PrintError("Error in onDelete: " + err.message)
return True
class _TaskPanelFemMeshGmsh:
'''The TaskPanel for editing References property of FemMeshGmsh objects and creation of new FEM mesh'''
def __init__(self, obj):
self.mesh_obj = obj
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshGmsh.ui")
self.Timer = QtCore.QTimer()
self.Timer.start(100) # 100 milli seconds
self.gmsh_runs = False
self.console_message_gmsh = ''
QtCore.QObject.connect(self.form.if_max, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.max_changed)
QtCore.QObject.connect(self.form.if_min, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.min_changed)
QtCore.QObject.connect(self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension)
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
self.form.cb_dimension.addItems(PyObjects._FemMeshGmsh._FemMeshGmsh.known_element_dimensions)
self.get_mesh_params()
self.get_active_analysis()
self.update()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel)
# show a OK, a apply and a Cancel button
# def reject() is called on Cancel button
# def clicked(self, button) is needed, to access the apply button
def accept(self):
self.set_mesh_params()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def clicked(self, button):
if button == QtGui.QDialogButtonBox.Apply:
self.set_mesh_params()
self.run_gmsh()
def get_mesh_params(self):
self.clmax = self.mesh_obj.CharacteristicLengthMax
self.clmin = self.mesh_obj.CharacteristicLengthMin
self.dimension = self.mesh_obj.ElementDimension
def set_mesh_params(self):
self.mesh_obj.CharacteristicLengthMax = self.clmax
self.mesh_obj.CharacteristicLengthMin = self.clmin
self.mesh_obj.ElementDimension = self.dimension
def update(self):
'fills the widgets'
self.form.if_max.setText(self.clmax.UserString)
self.form.if_min.setText(self.clmin.UserString)
index_dimension = self.form.cb_dimension.findText(self.dimension)
self.form.cb_dimension.setCurrentIndex(index_dimension)
def console_log(self, message="", color="#000000"):
self.console_message_gmsh = self.console_message_gmsh + '<font color="#0000FF">{0:4.1f}:</font> <font color="{1}">{2}</font><br>'.\
format(time.time() - self.Start, color, message.encode('utf-8', 'replace'))
self.form.te_output.setText(self.console_message_gmsh)
self.form.te_output.moveCursor(QtGui.QTextCursor.End)
def update_timer_text(self):
# print('timer1')
if self.gmsh_runs:
print('timer2')
# print('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def max_changed(self, base_quantity_value):
self.clmax = base_quantity_value
def min_changed(self, base_quantity_value):
self.clmin = base_quantity_value
def choose_dimension(self, index):
if index < 0:
return
self.form.cb_dimension.setCurrentIndex(index)
self.dimension = str(self.form.cb_dimension.itemText(index)) # form returns unicode
def run_gmsh(self):
QApplication.setOverrideCursor(Qt.WaitCursor)
part = self.obj.Part
if self.mesh_obj.MeshRegionList:
if part.Shape.ShapeType == "Compound" and hasattr(part, "Proxy"): # other part obj might not have a Proxy, thus an exception would be raised
if (part.Proxy.Type == "FeatureBooleanFragments" or part.Proxy.Type == "FeatureSlice" or part.Proxy.Type == "FeatureXOR"):
error_message = "The mesh to shape is a boolean split tools Compound and the mesh has mesh region list. Gmsh could return unexpected meshes in such circumstances. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
QtGui.QMessageBox.critical(None, "Shape to mesh is a BooleanFragmentsCompound and mesh regions are defined", error_message)
self.Start = time.time()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.console_message_gmsh = ''
self.gmsh_runs = True
self.console_log("We are going to start ...")
self.get_active_analysis()
import femmesh.gmshtools as gmshtools
gmsh_mesh = gmshtools.GmshTools(self.obj, self.analysis)
self.console_log("Start Gmsh ...")
error = ''
try:
error = gmsh_mesh.create_mesh()
except:
import sys
print("Unexpected error when creating mesh: ", sys.exc_info()[0])
if error:
print(error)
self.console_log('Gmsh had warnings ...')
self.console_log(error, '#FF0000')
else:
self.console_log('Clean run of Gmsh')
self.console_log("Gmsh done!")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
self.Timer.stop()
self.update()
QApplication.restoreOverrideCursor()
def get_active_analysis(self):
import FemGui
self.analysis = FemGui.getActiveAnalysis()
if self.analysis:
for m in FemGui.getActiveAnalysis().Group:
if m.Name == self.mesh_obj.Name:
print('Active analysis found: ' + self.analysis.Name)
return
else:
# print('Mesh is not member of active analysis, means no group meshing')
self.analysis = None # no group meshing
else:
# print('No active analyis, means no group meshing')
self.analysis = None # no group meshing

View File

@@ -29,7 +29,11 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemMeshGroup:
@@ -41,6 +45,7 @@ class _ViewProviderFemMeshGroup:
return ":/icons/fem-femmesh-from-shape.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -64,8 +69,7 @@ class _ViewProviderFemMeshGroup:
if o.isDerivedFrom("Fem::FemMeshObject"):
o.ViewObject.hide()
# show task panel
import PyGui._TaskPanelFemMeshGroup
taskd = PyGui._TaskPanelFemMeshGroup._TaskPanelFemMeshGroup(self.Object)
taskd = _TaskPanelFemMeshGroup(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -87,3 +91,195 @@ class _ViewProviderFemMeshGroup:
def __setstate__(self, state):
return None
class _TaskPanelFemMeshGroup:
'''The TaskPanel for editing References property of FemMeshGroup objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces, Edges and Vertices by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshGroup.ui")
QtCore.QObject.connect(self.form.rb_name, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_name)
QtCore.QObject.connect(self.form.rb_label, QtCore.SIGNAL("toggled(bool)"), self.choose_exportidentifier_label)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_meshgroup_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_meshgroup_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_meshgroup_props(self):
self.use_label = self.obj.UseLabel
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_meshgroup_props(self):
self.obj.References = self.references
self.obj.UseLabel = self.use_label
def update(self):
'fills the widgets'
self.form.rb_name.setChecked(not self.use_label)
self.form.rb_label.setChecked(self.use_label)
self.rebuild_list_References()
def choose_exportidentifier_name(self, state):
self.use_label = not state
def choose_exportidentifier_label(self, state):
self.use_label = state
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -29,11 +29,16 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
from pivy import coin
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemMeshRegion:
"A View Provider for the FemMeshRegion object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -41,6 +46,7 @@ class _ViewProviderFemMeshRegion:
return ":/icons/fem-femmesh-region.svg"
def attach(self, vobj):
from pivy import coin
self.ViewObject = vobj
self.Object = vobj.Object
self.standard = coin.SoGroup()
@@ -64,8 +70,7 @@ class _ViewProviderFemMeshRegion:
if o.isDerivedFrom("Fem::FemMeshObject"):
o.ViewObject.hide()
# show task panel
import PyGui._TaskPanelFemMeshRegion
taskd = PyGui._TaskPanelFemMeshRegion._TaskPanelFemMeshRegion(self.Object)
taskd = _TaskPanelFemMeshRegion(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
@@ -87,3 +92,190 @@ class _ViewProviderFemMeshRegion:
def __setstate__(self, state):
return None
class _TaskPanelFemMeshRegion:
'''The TaskPanel for editing References property of FemMeshRegion objects'''
def __init__(self, obj):
FreeCADGui.Selection.clearSelection()
self.sel_server = None
self.obj = obj
self.selection_mode_solid = False
self.selection_mode_std_print_message = "Select Faces, Edges and Vertices by single click on them to add them to the list."
self.selection_mode_solid_print_message = "Select Solids by single click on a Face or Edge which belongs to the Solid, to add the Solid to the list."
self.obj_notvisible = []
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemMeshRegion.ui")
QtCore.QObject.connect(self.form.if_elelen, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.elelen_changed)
QtCore.QObject.connect(self.form.rb_standard, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_standard)
QtCore.QObject.connect(self.form.rb_solid, QtCore.SIGNAL("toggled(bool)"), self.choose_selection_mode_solid)
QtCore.QObject.connect(self.form.pushButton_Reference, QtCore.SIGNAL("clicked()"), self.add_references)
self.form.list_References.itemSelectionChanged.connect(self.select_clicked_reference_shape)
self.form.list_References.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.form.list_References.connect(self.form.list_References, QtCore.SIGNAL("customContextMenuRequested(QPoint)"), self.references_list_right_clicked)
self.get_meshregion_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_meshregion_props()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def reject(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
FreeCADGui.ActiveDocument.resetEdit()
return True
def get_meshregion_props(self):
self.elelen = self.obj.CharacteristicLength
self.references = []
if self.obj.References:
self.tuplereferences = self.obj.References
self.get_references()
def set_meshregion_props(self):
self.obj.References = self.references
self.obj.CharacteristicLength = self.elelen
def update(self):
'fills the widgets'
self.form.if_elelen.setText(self.elelen.UserString)
self.rebuild_list_References()
def elelen_changed(self, base_quantity_value):
self.elelen = base_quantity_value
def choose_selection_mode_standard(self, state):
self.selection_mode_solid = not state
if self.sel_server and not self.selection_mode_solid:
print(self.selection_mode_std_print_message)
def choose_selection_mode_solid(self, state):
self.selection_mode_solid = state
if self.sel_server and self.selection_mode_solid:
print(self.selection_mode_solid_print_message)
def get_references(self):
for ref in self.tuplereferences:
for elem in ref[1]:
self.references.append((ref[0], elem))
def references_list_right_clicked(self, QPos):
self.form.contextMenu = QtGui.QMenu()
menu_item = self.form.contextMenu.addAction("Remove Reference")
if not self.references:
menu_item.setDisabled(True)
self.form.connect(menu_item, QtCore.SIGNAL("triggered()"), self.remove_reference)
parentPosition = self.form.list_References.mapToGlobal(QtCore.QPoint(0, 0))
self.form.contextMenu.move(parentPosition + QPos)
self.form.contextMenu.show()
def remove_reference(self):
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
self.references.remove(ref)
self.rebuild_list_References()
def add_references(self):
'''Called if Button add_reference is triggered'''
# in constraints EditTaskPanel the selection is active as soon as the taskpanel is open
# here the addReference button EditTaskPanel has to be triggered to start selection mode
self.setback_listobj_visibility()
FreeCADGui.Selection.clearSelection()
# start SelectionObserver and parse the function to add the References to the widget
if self.selection_mode_solid: # print message on button click
print_message = self.selection_mode_solid_print_message
else:
print_message = self.selection_mode_std_print_message
if not self.sel_server:
# if we do not check, we would start a new SelectionObserver on every click on addReference button
# but close only one SelectionObserver on leaving the task panel
from . import FemSelectionObserver
self.sel_server = FemSelectionObserver.FemSelectionObserver(self.selectionParser, print_message)
def selectionParser(self, selection):
print('selection: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
if hasattr(selection[0], "Shape") and selection[1]:
elt = selection[0].Shape.getElement(selection[1])
if self.selection_mode_solid:
# in solid selection mode use edges and faces for selection of a solid
solid_to_add = None
if elt.ShapeType == 'Edge':
found_edge = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Edges:
if elt.isSame(e):
if not found_edge:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Edge belongs to more than one solid\n')
solid_to_add = None
found_edge = True
elif elt.ShapeType == 'Face':
found_face = False
for i, s in enumerate(selection[0].Shape.Solids):
for e in s.Faces:
if elt.isSame(e):
if not found_face:
solid_to_add = str(i + 1)
else:
FreeCAD.Console.PrintMessage('Face belongs to more than one solid\n')
solid_to_add = None
found_edge = True
if solid_to_add:
selection = (selection[0], 'Solid' + solid_to_add)
print('selection element changed to Solid: ', selection[0].Shape.ShapeType, ' ', selection[0].Name, ' ', selection[1])
else:
return
if selection not in self.references:
self.references.append(selection)
self.rebuild_list_References()
else:
FreeCAD.Console.PrintMessage(selection[0].Name + ' --> ' + selection[1] + ' is in reference list already!\n')
def rebuild_list_References(self):
self.form.list_References.clear()
items = []
for ref in self.references:
item_name = ref[0].Name + ':' + ref[1]
items.append(item_name)
for listItemName in sorted(items):
self.form.list_References.addItem(listItemName)
def select_clicked_reference_shape(self):
self.setback_listobj_visibility()
if self.sel_server:
FreeCADGui.Selection.removeObserver(self.sel_server)
self.sel_server = None
if not self.sel_server:
if not self.references:
return
currentItemName = str(self.form.list_References.currentItem().text())
for ref in self.references:
refname_to_compare_listentry = ref[0].Name + ':' + ref[1]
if refname_to_compare_listentry == currentItemName:
# print( 'found: shape: ' + ref[0].Name + ' element: ' + ref[1])
if not ref[0].ViewObject.Visibility:
self.obj_notvisible.append(ref[0])
ref[0].ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(ref[0], ref[1])
def setback_listobj_visibility(self):
'''set back Visibility of the list objects
'''
for obj in self.obj_notvisible:
obj.ViewObject.Visibility = False
self.obj_notvisible = []

View File

@@ -30,12 +30,20 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
import FreeCADGui
# for the panel
import FemGui
import femresult.resulttools as resulttools
from PySide import QtCore
from PySide import QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
import numpy as np
class _ViewProviderFemResultMechanical:
"""A View Provider for the FemResultObject Python dervied FemResult class
"""
"A View Provider for the FemResultObject Python dervied FemResult class"
def __init__(self, vobj):
vobj.Proxy = self
@@ -69,14 +77,14 @@ class _ViewProviderFemResultMechanical:
hide_femmeshes_postpiplines()
# only show the FEM result mesh
self.Object.Mesh.ViewObject.show()
import PyGui._TaskPanelFemResultShow
taskd = PyGui._TaskPanelFemResultShow._TaskPanelFemResultShow(self.Object)
taskd = _TaskPanelFemResultShow(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
else:
error_message = 'FEM: Result object has no appropriate FEM mesh.\n'
FreeCAD.Console.PrintError(error_message)
from PySide import QtGui
QtGui.QMessageBox.critical(None, 'No result object', error_message)
return False
@@ -103,9 +111,392 @@ class _ViewProviderFemResultMechanical:
return True
class _TaskPanelFemResultShow:
'''The task panel for the post-processing'''
def __init__(self, obj):
self.result_obj = obj
self.mesh_obj = self.result_obj.Mesh
# task panel should be started by use of setEdit of view provider
# in view provider checks: Mesh, active analysis and if Mesh and result are in active analysis
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemResultShow.ui")
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
self.restore_result_settings_in_dialog = self.fem_prefs.GetBool("RestoreResultDialog", True)
# Connect Signals and Slots
# result type radio buttons
QtCore.QObject.connect(self.form.rb_none, QtCore.SIGNAL("toggled(bool)"), self.none_selected)
QtCore.QObject.connect(self.form.rb_abs_displacement, QtCore.SIGNAL("toggled(bool)"), self.abs_displacement_selected)
QtCore.QObject.connect(self.form.rb_x_displacement, QtCore.SIGNAL("toggled(bool)"), self.x_displacement_selected)
QtCore.QObject.connect(self.form.rb_y_displacement, QtCore.SIGNAL("toggled(bool)"), self.y_displacement_selected)
QtCore.QObject.connect(self.form.rb_z_displacement, QtCore.SIGNAL("toggled(bool)"), self.z_displacement_selected)
QtCore.QObject.connect(self.form.rb_temperature, QtCore.SIGNAL("toggled(bool)"), self.temperature_selected)
QtCore.QObject.connect(self.form.rb_vm_stress, QtCore.SIGNAL("toggled(bool)"), self.vm_stress_selected)
QtCore.QObject.connect(self.form.rb_maxprin, QtCore.SIGNAL("toggled(bool)"), self.max_prin_selected)
QtCore.QObject.connect(self.form.rb_minprin, QtCore.SIGNAL("toggled(bool)"), self.min_prin_selected)
QtCore.QObject.connect(self.form.rb_max_shear_stress, QtCore.SIGNAL("toggled(bool)"), self.max_shear_selected)
QtCore.QObject.connect(self.form.rb_massflowrate, QtCore.SIGNAL("toggled(bool)"), self.massflowrate_selected)
QtCore.QObject.connect(self.form.rb_networkpressure, QtCore.SIGNAL("toggled(bool)"), self.networkpressure_selected)
QtCore.QObject.connect(self.form.rb_peeq, QtCore.SIGNAL("toggled(bool)"), self.peeq_selected)
# displacement
QtCore.QObject.connect(self.form.cb_show_displacement, QtCore.SIGNAL("clicked(bool)"), self.show_displacement)
QtCore.QObject.connect(self.form.hsb_displacement_factor, QtCore.SIGNAL("valueChanged(int)"), self.hsb_disp_factor_changed)
QtCore.QObject.connect(self.form.sb_displacement_factor, QtCore.SIGNAL("valueChanged(int)"), self.sb_disp_factor_changed)
QtCore.QObject.connect(self.form.sb_displacement_factor_max, QtCore.SIGNAL("valueChanged(int)"), self.sb_disp_factor_max_changed)
# user defined equation
QtCore.QObject.connect(self.form.user_def_eq, QtCore.SIGNAL("textchanged()"), self.user_defined_text)
QtCore.QObject.connect(self.form.calculate, QtCore.SIGNAL("clicked()"), self.calculate)
self.update()
if self.restore_result_settings_in_dialog:
self.restore_result_dialog()
else:
self.restore_initial_result_dialog()
def restore_result_dialog(self):
try:
rt = FreeCAD.FEM_dialog["results_type"]
if rt == "None":
self.form.rb_none.setChecked(True)
self.none_selected(True)
elif rt == "Uabs":
self.form.rb_abs_displacement.setChecked(True)
self.abs_displacement_selected(True)
elif rt == "U1":
self.form.rb_x_displacement.setChecked(True)
self.x_displacement_selected(True)
elif rt == "U2":
self.form.rb_y_displacement.setChecked(True)
self.y_displacement_selected(True)
elif rt == "U3":
self.form.rb_z_displacement.setChecked(True)
self.z_displacement_selected(True)
elif rt == "Temp":
self.form.rb_temperature.setChecked(True)
self.temperature_selected(True)
elif rt == "Sabs":
self.form.rb_vm_stress.setChecked(True)
self.vm_stress_selected(True)
elif rt == "MaxPrin":
self.form.rb_maxprin.setChecked(True)
self.max_prin_selected(True)
elif rt == "MinPrin":
self.form.rb_minprin.setChecked(True)
self.min_prin_selected(True)
elif rt == "MaxShear":
self.form.rb_max_shear_stress.setChecked(True)
self.max_shear_selected(True)
elif rt == "MFlow":
self.form.rb_massflowrate.setChecked(True)
self.massflowrate_selected(True)
elif rt == "NPress":
self.form.rb_networkpressure.setChecked(True)
self.networkpressure_selected(True)
elif rt == "Peeq":
self.form.rb_peeq.setChecked(True)
self.peeq_selected(True)
sd = FreeCAD.FEM_dialog["show_disp"]
self.form.cb_show_displacement.setChecked(sd)
self.show_displacement(sd)
df = FreeCAD.FEM_dialog["disp_factor"]
dfm = FreeCAD.FEM_dialog["disp_factor_max"]
self.form.hsb_displacement_factor.setMaximum(dfm)
self.form.hsb_displacement_factor.setValue(df)
self.form.sb_displacement_factor_max.setValue(dfm)
self.form.sb_displacement_factor.setValue(df)
except:
self.restore_initial_result_dialog()
def restore_initial_result_dialog(self):
FreeCAD.FEM_dialog = {"results_type": "None", "show_disp": False,
"disp_factor": 0, "disp_factor_max": 100}
self.reset_mesh_deformation()
self.reset_mesh_color()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
def get_result_stats(self, type_name):
return resulttools.get_stats(self.result_obj, type_name)
def none_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "None"
self.set_result_stats("mm", 0.0, 0.0, 0.0)
self.reset_mesh_color()
def abs_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Uabs"
self.select_displacement_type("Uabs")
def x_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U1"
self.select_displacement_type("U1")
def y_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U2"
self.select_displacement_type("U2")
def z_displacement_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "U3"
self.select_displacement_type("U3")
def vm_stress_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Sabs"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.StressValues)
(minm, avg, maxm) = self.get_result_stats("Sabs")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def max_shear_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MaxShear"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.MaxShear)
(minm, avg, maxm) = self.get_result_stats("MaxShear")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def max_prin_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MaxPrin"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.PrincipalMax)
(minm, avg, maxm) = self.get_result_stats("MaxPrin")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def temperature_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Temp"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.Temperature)
(minm, avg, maxm) = self.get_result_stats("Temp")
self.set_result_stats("K", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def massflowrate_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MFlow"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.MassFlowRate)
(minm, avg, maxm) = self.get_result_stats("MFlow")
self.set_result_stats("kg/s", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def networkpressure_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "NPress"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.NetworkPressure)
(minm, avg, maxm) = self.get_result_stats("NPress")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def min_prin_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "MinPrin"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.PrincipalMin)
(minm, avg, maxm) = self.get_result_stats("MinPrin")
self.set_result_stats("MPa", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def peeq_selected(self, state):
FreeCAD.FEM_dialog["results_type"] = "Peeq"
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.Peeq)
(minm, avg, maxm) = self.get_result_stats("Peeq")
self.set_result_stats("", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def user_defined_text(self, equation):
FreeCAD.FEM_dialog["results_type"] = "user"
self.form.user_def_eq.toPlainText()
def calculate(self):
FreeCAD.FEM_dialog["results_type"] = "None"
self.update()
self.restore_result_dialog()
# Convert existing values to numpy array
P1 = np.array(self.result_obj.PrincipalMax)
P2 = np.array(self.result_obj.PrincipalMed)
P3 = np.array(self.result_obj.PrincipalMin)
Von = np.array(self.result_obj.StressValues)
Peeq = np.array(self.result_obj.Peeq)
T = np.array(self.result_obj.Temperature)
MF = np.array(self.result_obj.MassFlowRate)
NP = np.array(self.result_obj.NetworkPressure)
dispvectors = np.array(self.result_obj.DisplacementVectors)
x = np.array(dispvectors[:, 0])
y = np.array(dispvectors[:, 1])
z = np.array(dispvectors[:, 2])
stressvectors = np.array(self.result_obj.StressVectors)
sx = np.array(stressvectors[:, 0])
sy = np.array(stressvectors[:, 1])
sz = np.array(stressvectors[:, 2])
strainvectors = np.array(self.result_obj.StrainVectors)
ex = np.array(strainvectors[:, 0])
ey = np.array(strainvectors[:, 1])
ez = np.array(strainvectors[:, 2])
userdefined_eq = self.form.user_def_eq.toPlainText() # Get equation to be used
UserDefinedFormula = eval(userdefined_eq).tolist()
self.result_obj.UserDefined = UserDefinedFormula
minm = min(UserDefinedFormula)
avg = sum(UserDefinedFormula) / len(UserDefinedFormula)
maxm = max(UserDefinedFormula)
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, UserDefinedFormula)
self.set_result_stats("", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
del x, y, z, T, Von, Peeq, P1, P2, P3, sx, sy, sz, ex, ey, ez, MF, NP # Dummy use to get around flake8, varibles not being used
def select_displacement_type(self, disp_type):
QApplication.setOverrideCursor(Qt.WaitCursor)
if disp_type == "Uabs":
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, self.result_obj.DisplacementLengths)
else:
match = {"U1": 0, "U2": 1, "U3": 2}
d = zip(*self.result_obj.DisplacementVectors)
displacements = list(d[match[disp_type]])
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeColorByScalars(self.result_obj.NodeNumbers, displacements)
(minm, avg, maxm) = self.get_result_stats(disp_type)
self.set_result_stats("mm", minm, avg, maxm)
QtGui.qApp.restoreOverrideCursor()
def set_result_stats(self, unit, minm, avg, maxm):
self.form.le_min.setProperty("unit", unit)
self.form.le_min.setText("{:.6} {}".format(minm, unit))
self.form.le_avg.setProperty("unit", unit)
self.form.le_avg.setText("{:.6} {}".format(avg, unit))
self.form.le_max.setProperty("unit", unit)
self.form.le_max.setText("{:.6} {}".format(maxm, unit))
def update_displacement(self, factor=None):
if factor is None:
if FreeCAD.FEM_dialog["show_disp"]:
factor = self.form.hsb_displacement_factor.value()
else:
factor = 0.0
self.mesh_obj.ViewObject.applyDisplacement(factor)
def show_displacement(self, checked):
QApplication.setOverrideCursor(Qt.WaitCursor)
FreeCAD.FEM_dialog["show_disp"] = checked
if "result_obj" in FreeCAD.FEM_dialog:
if FreeCAD.FEM_dialog["result_obj"] != self.result_obj:
self.update_displacement()
FreeCAD.FEM_dialog["result_obj"] = self.result_obj
if self.suitable_results:
self.mesh_obj.ViewObject.setNodeDisplacementByVectors(self.result_obj.NodeNumbers, self.result_obj.DisplacementVectors)
self.update_displacement()
QtGui.qApp.restoreOverrideCursor()
def hsb_disp_factor_changed(self, value):
self.form.sb_displacement_factor.setValue(value)
self.update_displacement()
def sb_disp_factor_max_changed(self, value):
FreeCAD.FEM_dialog["disp_factor_max"] = value
self.form.hsb_displacement_factor.setMaximum(value)
def sb_disp_factor_changed(self, value):
FreeCAD.FEM_dialog["disp_factor"] = value
self.form.hsb_displacement_factor.setValue(value)
def disable_empty_result_buttons(self):
''' disable radio buttons if result does not exists in result object'''
'''assignments
DisplacementLengths --> rb_abs_displacement
DisplacementVectors --> rb_x_displacement, rb_y_displacement, rb_z_displacement
Temperature --> rb_temperature
StressValues --> rb_vm_stress
PrincipalMax --> rb_maxprin
PrincipalMin --> rb_minprin
MaxShear --> rb_max_shear_stress
MassFlowRate --> rb_massflowrate
NetworkPressure --> rb_networkpressure
Peeq --> rb_peeq'''
if len(self.result_obj.DisplacementLengths) == 0:
self.form.rb_abs_displacement.setEnabled(0)
if len(self.result_obj.DisplacementVectors) == 0:
self.form.rb_x_displacement.setEnabled(0)
self.form.rb_y_displacement.setEnabled(0)
self.form.rb_z_displacement.setEnabled(0)
if len(self.result_obj.Temperature) == 0:
self.form.rb_temperature.setEnabled(0)
if len(self.result_obj.StressValues) == 0:
self.form.rb_vm_stress.setEnabled(0)
if len(self.result_obj.PrincipalMax) == 0:
self.form.rb_maxprin.setEnabled(0)
if len(self.result_obj.PrincipalMin) == 0:
self.form.rb_minprin.setEnabled(0)
if len(self.result_obj.MaxShear) == 0:
self.form.rb_max_shear_stress.setEnabled(0)
if len(self.result_obj.MassFlowRate) == 0:
self.form.rb_massflowrate.setEnabled(0)
if len(self.result_obj.NetworkPressure) == 0:
self.form.rb_networkpressure.setEnabled(0)
if len(self.result_obj.Peeq) == 0:
self.form.rb_peeq.setEnabled(0)
def update(self):
self.suitable_results = False
self.disable_empty_result_buttons()
if (self.mesh_obj.FemMesh.NodeCount == len(self.result_obj.NodeNumbers)):
self.suitable_results = True
hide_parts_constraints()
else:
if not self.mesh_obj.FemMesh.VolumeCount:
error_message = 'FEM: Graphical bending stress output for beam or shell FEM Meshes not yet supported.\n'
FreeCAD.Console.PrintError(error_message)
QtGui.QMessageBox.critical(None, 'No result object', error_message)
else:
error_message = 'FEM: Result node numbers are not equal to FEM Mesh NodeCount.\n'
FreeCAD.Console.PrintError(error_message)
QtGui.QMessageBox.critical(None, 'No result object', error_message)
def reset_mesh_deformation(self):
self.mesh_obj.ViewObject.applyDisplacement(0.0)
def reset_mesh_color(self):
self.mesh_obj.ViewObject.NodeColor = {}
self.mesh_obj.ViewObject.ElementColor = {}
node_numbers = self.mesh_obj.FemMesh.Nodes.keys()
zero_values = [0] * len(node_numbers)
self.mesh_obj.ViewObject.setNodeColorByScalars(node_numbers, zero_values)
def reject(self):
FreeCADGui.Control.closeDialog() # if the taks panell is called from Command obj is not in edit mode thus reset edit does not cleses the dialog, may be do not call but set in edit instead
FreeCADGui.ActiveDocument.resetEdit()
# helper
def hide_femmeshes_postpiplines():
# hide all visible FEM mesh objects and VTK FemPostPipeline objects
for o in FreeCAD.ActiveDocument.Objects:
if o.isDerivedFrom("Fem::FemMeshObject") or o.isDerivedFrom("Fem::FemPostPipeline"):
o.ViewObject.hide()
def hide_parts_constraints():
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
hide_constraints = fem_prefs.GetBool("HideConstraint", False)
if hide_constraints:
for o in FreeCAD.ActiveDocument.Objects:
if o.isDerivedFrom('Fem::FemAnalysis'):
for acnstrmesh in FemGui.getActiveAnalysis().Group:
if "Constraint" in acnstrmesh.TypeId:
acnstrmesh.ViewObject.Visibility = False
break

View File

@@ -32,8 +32,22 @@ import FreeCADGui
import FemGui
# for the panel
import FemToolsCcx
from PySide import QtCore
from PySide import QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
import os
import time
import sys
if sys.version_info.major >= 3:
unicode = str
class _ViewProviderFemSolverCalculix:
"A View Provider for the FemSolverCalculix object"
def __init__(self, vobj):
vobj.Proxy = self
@@ -51,8 +65,7 @@ class _ViewProviderFemSolverCalculix:
return
def setEdit(self, vobj, mode=0):
import PyGui._TaskPanelFemSolverCalculix
taskd = PyGui._TaskPanelFemSolverCalculix._TaskPanelFemSolverCalculix(self.Object)
taskd = _TaskPanelFemSolverCalculix(self.Object)
FreeCADGui.Control.showDialog(taskd)
return True
@@ -83,3 +96,255 @@ class _ViewProviderFemSolverCalculix:
def __setstate__(self, state):
return None
class _TaskPanelFemSolverCalculix:
'''The TaskPanel for CalculiX ccx tools solver object'''
def __init__(self, solver_object):
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/PyGui/TaskPanelFemSolverCalculix.ui")
self.ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
ccx_binary = self.ccx_prefs.GetString("ccxBinaryPath", "")
if ccx_binary:
self.CalculixBinary = ccx_binary
print ("Using CalculiX binary path from FEM preferences: {}".format(ccx_binary))
else:
from platform import system
if system() == 'Linux':
self.CalculixBinary = 'ccx'
elif system() == 'Windows':
self.CalculixBinary = FreeCAD.getHomePath() + 'bin/ccx.exe'
else:
self.CalculixBinary = 'ccx'
self.solver_object = solver_object
self.Calculix = QtCore.QProcess()
self.Timer = QtCore.QTimer()
self.Timer.start(300)
self.fem_console_message = ''
# Connect Signals and Slots
QtCore.QObject.connect(self.form.tb_choose_working_dir, QtCore.SIGNAL("clicked()"), self.choose_working_dir)
QtCore.QObject.connect(self.form.pb_write_inp, QtCore.SIGNAL("clicked()"), self.write_input_file_handler)
QtCore.QObject.connect(self.form.pb_edit_inp, QtCore.SIGNAL("clicked()"), self.editCalculixInputFile)
QtCore.QObject.connect(self.form.pb_run_ccx, QtCore.SIGNAL("clicked()"), self.runCalculix)
QtCore.QObject.connect(self.form.rb_static_analysis, QtCore.SIGNAL("clicked()"), self.select_static_analysis)
QtCore.QObject.connect(self.form.rb_frequency_analysis, QtCore.SIGNAL("clicked()"), self.select_frequency_analysis)
QtCore.QObject.connect(self.form.rb_thermomech_analysis, QtCore.SIGNAL("clicked()"), self.select_thermomech_analysis)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("started()"), self.calculixStarted)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("stateChanged(QProcess::ProcessState)"), self.calculixStateChanged)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("error(QProcess::ProcessError)"), self.calculixError)
QtCore.QObject.connect(self.Calculix, QtCore.SIGNAL("finished(int)"), self.calculixFinished)
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.UpdateText)
self.update()
def getStandardButtons(self):
# only show a close button
# def accept() in no longer needed, since there is no OK button
return int(QtGui.QDialogButtonBox.Close)
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
def update(self):
'fills the widgets'
self.form.le_working_dir.setText(self.solver_object.WorkingDir)
if self.solver_object.AnalysisType == 'static':
self.form.rb_static_analysis.setChecked(True)
elif self.solver_object.AnalysisType == 'frequency':
self.form.rb_frequency_analysis.setChecked(True)
elif self.solver_object.AnalysisType == 'thermomech':
self.form.rb_thermomech_analysis.setChecked(True)
return
def femConsoleMessage(self, message="", color="#000000"):
self.fem_console_message = self.fem_console_message + '<font color="#0000FF">{0:4.1f}:</font> <font color="{1}">{2}</font><br>'.\
format(time.time() - self.Start, color, message.encode('utf-8', 'replace'))
self.form.textEdit_Output.setText(self.fem_console_message)
self.form.textEdit_Output.moveCursor(QtGui.QTextCursor.End)
def printCalculiXstdout(self):
out = self.Calculix.readAllStandardOutput()
if out.isEmpty():
self.femConsoleMessage("CalculiX stdout is empty", "#FF0000")
else:
try:
out = unicode(out, 'utf-8', 'replace')
rx = QtCore.QRegExp("\\*ERROR.*\\n\\n")
rx.setMinimal(True)
pos = rx.indexIn(out)
while not pos < 0:
match = rx.cap(0)
FreeCAD.Console.PrintError(match.strip().replace('\n', ' ') + '\n')
pos = rx.indexIn(out, pos + 1)
out = os.linesep.join([s for s in out.splitlines() if s])
self.femConsoleMessage(out.replace('\n', '<br>'))
except UnicodeDecodeError:
self.femConsoleMessage("Error converting stdout from CalculiX", "#FF0000")
def UpdateText(self):
if(self.Calculix.state() == QtCore.QProcess.ProcessState.Running):
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def calculixError(self, error):
print ("Error() {}".format(error))
self.femConsoleMessage("CalculiX execute error: {}".format(error), "#FF0000")
def calculixStarted(self):
print ("calculixStarted()")
print (self.Calculix.state())
self.form.pb_run_ccx.setText("Break CalculiX")
def calculixStateChanged(self, newState):
if (newState == QtCore.QProcess.ProcessState.Starting):
self.femConsoleMessage("Starting CalculiX...")
if (newState == QtCore.QProcess.ProcessState.Running):
self.femConsoleMessage("CalculiX is running...")
if (newState == QtCore.QProcess.ProcessState.NotRunning):
self.femConsoleMessage("CalculiX stopped.")
def calculixFinished(self, exitCode):
print ("calculixFinished() {}".format(exitCode))
print (self.Calculix.state())
# Restore previous cwd
QtCore.QDir.setCurrent(self.cwd)
self.printCalculiXstdout()
self.Timer.stop()
self.femConsoleMessage("CalculiX done!", "#00AA00")
self.form.pb_run_ccx.setText("Re-run CalculiX")
self.femConsoleMessage("Loading result sets...")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.reset_mesh_purge_results_checked()
fea.inp_file_name = self.inp_file_name
QApplication.setOverrideCursor(Qt.WaitCursor)
try:
fea.load_results()
except:
QApplication.restoreOverrideCursor()
majorVersion, minorVersion = fea.get_ccx_version()
if majorVersion == 2 and minorVersion <= 10:
message = "The used CalculiX version {}.{} creates broken output files.\n" \
"Please upgrade to a newer version.".format(majorVersion, minorVersion)
QtGui.QMessageBox.warning(None, "Upgrade CalculiX", message)
raise
else:
QApplication.restoreOverrideCursor()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def choose_working_dir(self):
current_wd = self.setup_working_dir()
wd = QtGui.QFileDialog.getExistingDirectory(None, 'Choose CalculiX working directory',
current_wd)
if wd:
self.solver_object.WorkingDir = wd
else:
self.solver_object.WorkingDir = current_wd
self.form.le_working_dir.setText(self.solver_object.WorkingDir)
def write_input_file_handler(self):
self.Start = time.time()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
QApplication.restoreOverrideCursor()
if self.check_prerequisites_helper():
QApplication.setOverrideCursor(Qt.WaitCursor)
self.inp_file_name = ""
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.set_analysis_type(self.solver_object.AnalysisType)
fea.update_objects()
fea.write_inp_file()
if fea.inp_file_name != "":
self.inp_file_name = fea.inp_file_name
self.femConsoleMessage("Write completed.")
self.form.pb_edit_inp.setEnabled(True)
self.form.pb_run_ccx.setEnabled(True)
else:
self.femConsoleMessage("Write .inp file failed!", "#FF0000")
QApplication.restoreOverrideCursor()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def check_prerequisites_helper(self):
self.Start = time.time()
self.femConsoleMessage("Check dependencies...")
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
fea = FemToolsCcx.FemToolsCcx(None, self.solver_object)
fea.update_objects()
message = fea.check_prerequisites()
if message != "":
QtGui.QMessageBox.critical(None, "Missing prerequisit(s)", message)
return False
return True
def start_ext_editor(self, ext_editor_path, filename):
if not hasattr(self, "ext_editor_process"):
self.ext_editor_process = QtCore.QProcess()
if self.ext_editor_process.state() != QtCore.QProcess.Running:
self.ext_editor_process.start(ext_editor_path, [filename])
def editCalculixInputFile(self):
print ('editCalculixInputFile {}'.format(self.inp_file_name))
if self.ccx_prefs.GetBool("UseInternalEditor", True):
FemGui.open(self.inp_file_name)
else:
ext_editor_path = self.ccx_prefs.GetString("ExternalEditorPath", "")
if ext_editor_path:
self.start_ext_editor(ext_editor_path, self.inp_file_name)
else:
print ("External editor is not defined in FEM preferences. Falling back to internal editor")
FemGui.open(self.inp_file_name)
def runCalculix(self):
print ('runCalculix')
self.Start = time.time()
self.femConsoleMessage("CalculiX binary: {}".format(self.CalculixBinary))
self.femConsoleMessage("Run CalculiX...")
# run Calculix
print ('run CalculiX at: {} with: {}'.format(self.CalculixBinary, os.path.splitext(self.inp_file_name)[0]))
# change cwd because ccx may crash if directory has no write permission
# there is also a limit of the length of file names so jump to the document directory
self.cwd = QtCore.QDir.currentPath()
fi = QtCore.QFileInfo(self.inp_file_name)
QtCore.QDir.setCurrent(fi.path())
self.Calculix.start(self.CalculixBinary, ['-i', fi.baseName()])
QApplication.restoreOverrideCursor()
def select_analysis_type(self, analysis_type):
if self.solver_object.AnalysisType != analysis_type:
self.solver_object.AnalysisType = analysis_type
self.form.pb_edit_inp.setEnabled(False)
self.form.pb_run_ccx.setEnabled(False)
def select_static_analysis(self):
self.select_analysis_type('static')
def select_frequency_analysis(self):
self.select_analysis_type('frequency')
def select_thermomech_analysis(self):
self.select_analysis_type('thermomech')
# That function overlaps with FemToolsCcx setup_working_dir and could be removed when the one from FemToolsCcx would be used
def setup_working_dir(self):
wd = self.solver_object.WorkingDir
if not (os.path.isdir(wd)):
try:
os.makedirs(wd)
except:
print ("Dir \'{}\' from FEM preferences doesn't exist and cannot be created.".format(wd))
import tempfile
wd = tempfile.gettempdir()
print ("Dir \'{}\' will be used instead.".format(wd))
return wd