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
+
+
+
+
+
+
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