diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index 6b33ee4ce8..bef52adbcf 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -247,7 +247,24 @@ def makeMeshGroup(base_mesh, use_label=False, name="FEMMeshGroup"): return obj -def makeMeshShapeNetgenObject(name="FEMMeshNetgen"): +def makeMeshBoundaryLayer(base_mesh, name="MeshBoundaryLayer"): + '''makeMeshBoundaryLayer([length], [name]): creates a FEM mesh BoundaryLayer object to define boundary layer properties''' + obj = FreeCAD.ActiveDocument.addObject("Fem::FeaturePython", name) + import PyObjects._FemMeshBoundaryLayer + PyObjects._FemMeshBoundaryLayer._FemMeshBoundaryLayer(obj) + + # obj.BaseMesh = base_mesh + # App::PropertyLinkList does not support append, we will use a temporary list to append the mesh BoundaryLayer obj. to the list + tmplist = base_mesh.MeshBoundaryLayerList + tmplist.append(obj) + base_mesh.MeshBoundaryLayerList = tmplist + if FreeCAD.GuiUp: + import PyGui._ViewProviderFemMeshBoundaryLayer + PyGui._ViewProviderFemMeshBoundaryLayer._ViewProviderFemMeshBoundaryLayer(obj.ViewObject) + return obj + + +def makeMeshShapeNetgenObject(name="MeshShapeNetgenObject"): '''makeMeshShapeNetgenObject(name): makes a Fem MeshShapeNetgenObject object''' obj = FreeCAD.ActiveDocument.addObject("Fem::FemMeshShapeNetgenObject", name) return obj @@ -302,7 +319,7 @@ def makeSolverZ88(name="Z88"): if FreeCAD.GuiUp: import PyGui._ViewProviderFemSolverZ88 PyGui._ViewProviderFemSolverZ88._ViewProviderFemSolverZ88(obj.ViewObject) - return obj + return obj ''' diff --git a/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui b/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui new file mode 100644 index 0000000000..66ab0c2f95 --- /dev/null +++ b/src/Mod/Fem/PyGui/TaskPanelFemMeshBoundaryLayer.ui @@ -0,0 +1,191 @@ + + + Form + + + + 0 + 0 + 386 + 500 + + + + Mesh boundary layer settings + + + + + + + 16777215 + 1677215 + + + + Parameter + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Max Layers + + + + + + + + 0 + 0 + + + + + 80 + 20 + + + + 0.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1.000000000000000 + + + 1000000000.000000000000000 + + + mm + + + 2 + + + 1.000000000000000 + + + + + + + 3 + + + + + + + Min/1st thickness + + + + + + + Growth ratio + + + + + + + 0.100000000000000 + + + 10.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + + + + References + + + + + + Add reference + + + + + + + + + + + + Solid + + + + + + + Face, Edge + + + true + + + + + + + <html><head/><body><p>Selection</p></body></html> + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + +
diff --git a/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py b/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py new file mode 100644 index 0000000000..0460983367 --- /dev/null +++ b/src/Mod/Fem/PyGui/_TaskPanelFemMeshBoundaryLayer.py @@ -0,0 +1,205 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - 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__ = "_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(float)"), self.bl_growth_rate_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.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 ' + 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_thicknes = 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 + + ############### identical to FemMeshRegion ############ + def reject(self): + if self.sel_server: + FreeCADGui.Selection.removeObserver(self.sel_server) + FreeCADGui.ActiveDocument.resetEdit() + return True + + 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 + 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) diff --git a/src/Mod/Fem/PyGui/_ViewProviderFemMeshBoundaryLayer.py b/src/Mod/Fem/PyGui/_ViewProviderFemMeshBoundaryLayer.py new file mode 100644 index 0000000000..4df9344e68 --- /dev/null +++ b/src/Mod/Fem/PyGui/_ViewProviderFemMeshBoundaryLayer.py @@ -0,0 +1,89 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - 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__ = "_ViewProviderFemMeshBoundaryLayer" +__author__ = "Bernd Hahnebach, Qingfeng Xia" +__url__ = "http://www.freecadweb.org" + +## @package ViewProviderFemMeshBoundaryLayer +# \ingroup FEM + +import FreeCAD +import FreeCADGui +from pivy import coin + + +class _ViewProviderFemMeshBoundaryLayer: + "A View Provider for the FemMeshBoundaryLayer object" + def __init__(self, vobj): + vobj.Proxy = self + + def getIcon(self): + return ":/icons/fem-femmesh-boundary-layer.svg" + + def attach(self, vobj): + self.ViewObject = vobj + self.Object = vobj.Object + self.standard = coin.SoGroup() + vobj.addDisplayMode(self.standard, "Standard") + + def getDisplayModes(self, obj): + return ["Standard"] + + def getDefaultDisplayMode(self): + return "Standard" + + def updateData(self, obj, prop): + return + + def onChanged(self, vobj, prop): + return + + def setEdit(self, vobj, mode=0): + # hide all meshes + for o in FreeCAD.ActiveDocument.Objects: + if o.isDerivedFrom("Fem::FemMeshObject"): + o.ViewObject.hide() + # show task panel + import PyGui._TaskPanelFemMeshBoundaryLayer + taskd = PyGui._TaskPanelFemMeshBoundaryLayer._TaskPanelFemMeshBoundaryLayer(self.Object) + taskd.obj = vobj.Object + FreeCADGui.Control.showDialog(taskd) + return True + + def unsetEdit(self, vobj, mode=0): + FreeCADGui.Control.closeDialog() + return + + def doubleClicked(self, vobj): + doc = FreeCADGui.getDocument(vobj.Object.Document) + if not doc.getInEdit(): + doc.setEdit(vobj.Object.Name) + else: + FreeCAD.Console.PrintError('Active Task Dialog found! Please close this one first!\n') + return True + + def __getstate__(self): + return None + + def __setstate__(self, state): + return None diff --git a/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py b/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py new file mode 100644 index 0000000000..f248d10ff3 --- /dev/null +++ b/src/Mod/Fem/PyObjects/_FemMeshBoundaryLayer.py @@ -0,0 +1,48 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - 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__ = "_FemMeshBoundaryLayer" +__author__ = "Bernd Hahnebach, Qingfeng Xia" +__url__ = "http://www.freecadweb.org" + +## @package FemMeshBoundaryLayer +# \ingroup FEM + + +class _FemMeshBoundaryLayer: + "The FemMeshBoundaryLayer object" + def __init__(self, obj): + obj.addProperty("App::PropertyInteger", "NumberOfLayers", "MeshBoundaryLayerProperties", + "set number of inflation layers for this boundary") + obj.NumberOfLayers = 3 + obj.addProperty("App::PropertyLength", "MinimumThickness", "MeshBoundaryLayerProperties", + "set minimum thickness,usually the first inflation layer") + obj.addProperty("App::PropertyFloat", "GrowthRate", "MeshBoundaryLayerProperties", + "set growth rate of inflation layers for smooth transition") + obj.GrowthRate = 1.0 + + obj.addProperty("App::PropertyLinkSubList", "References", "MeshBoundaryLayerShapes", "List of FEM mesh region shapes") + obj.Proxy = self + self.Type = "FemMeshBoundaryLayer" + + def execute(self, obj): + return