FEM: objects, use fem name sheme for object package names

This commit is contained in:
Bernd Hahnebach
2018-01-25 07:16:45 +01:00
committed by Yorik van Havre
parent 07ae0e56c4
commit c85afd0e44
48 changed files with 94 additions and 93 deletions

View File

@@ -0,0 +1,47 @@
# ***************************************************************************
# * *
# * 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__ = "Selection Observer"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FreeCADGui
class FemSelectionObserver:
'''FemSelectionObserver'''
def __init__(self, parseSelectionFunction, print_message=''):
self.parseSelectionFunction = parseSelectionFunction
FreeCADGui.Selection.addObserver(self)
FreeCAD.Console.PrintMessage(print_message + "!\n")
def addSelection(self, docName, objName, sub, pos):
selected_object = FreeCAD.getDocument(docName).getObject(objName) # get the obj objName
self.added_obj = (selected_object, sub)
# on double click on a vertex of a solid sub is None and obj is the solid
self.parseSelectionFunction(self.added_obj)
## @}

View File

@@ -0,0 +1,204 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "FemSelectWidget"
__author__ = "Markus Hovorka"
__url__ = "http://www.freecadweb.org"
from PySide import QtGui
from PySide import QtCore
import FreeCADGui as Gui
class _Selector(QtGui.QWidget):
def __init__(self):
super(_Selector, self).__init__()
self._references = []
self._register = dict()
addBtn = QtGui.QPushButton(self.tr("Add"))
delBtn = QtGui.QPushButton(self.tr("Remove"))
addBtn.clicked.connect(self._add)
delBtn.clicked.connect(self._del)
btnLayout = QtGui.QHBoxLayout()
btnLayout.addWidget(addBtn)
btnLayout.addWidget(delBtn)
self._model = QtGui.QStandardItemModel()
self._view = SmallListView()
self._view.setModel(self._model)
self._helpTextLbl = QtGui.QLabel()
self._helpTextLbl.setWordWrap(True)
mainLayout = QtGui.QVBoxLayout()
mainLayout.addWidget(self._helpTextLbl)
mainLayout.addLayout(btnLayout)
mainLayout.addWidget(self._view)
self.setLayout(mainLayout)
def references(self):
return [entry for entry in self._references if entry[1]]
def setReferences(self, references):
self._references = []
self._updateReferences(references)
def setHelpText(self, text):
self._helpTextLbl.setText(text)
@QtCore.Slot()
def _add(self):
selection = self.getSelection()
self._updateReferences(selection)
@QtCore.Slot()
def _del(self):
selected = self._view.selectedIndexes()
for index in selected:
identifier = self._model.data(index)
obj, sub = self._register[identifier]
refIndex = self._getIndex(obj)
entry = self._references[refIndex]
newSub = tuple((x for x in entry[1] if x != sub))
self._references[refIndex] = (obj, newSub)
self._model.removeRow(index.row())
def _updateReferences(self, selection):
for obj, subList in selection:
index = self._getIndex(obj)
for sub in subList:
entry = self._references[index]
if sub not in entry[1]:
self._addToWidget(obj, sub)
newEntry = (obj, entry[1] + (sub,))
self._references[index] = newEntry
def _addToWidget(self, obj, sub):
identifier = "%s::%s" % (obj.Name, sub)
item = QtGui.QStandardItem(identifier)
self._model.appendRow(item)
self._register[identifier] = (obj, sub)
def _getIndex(self, obj):
for i, entry in enumerate(self._references):
if entry[0] == obj:
return i
self._references.append((obj, tuple()))
return len(self._references) - 1
def getSelection(self):
raise NotImplementedError()
class BoundarySelector(_Selector):
def __init__(self):
super(BoundarySelector, self).__init__()
self.setWindowTitle(self.tr("Select Faces/Edges/Vertexes"))
self.setHelpText(self.tr(
"To add references select them in the 3D view and then"
" click \"Add\"."))
def getSelection(self):
selection = []
for selObj in Gui.Selection.getSelectionEx():
if selObj.HasSubObjects:
item = (selObj.Object, tuple(selObj.SubElementNames))
selection.append(item)
return selection
class SolidSelector(_Selector):
def __init__(self):
super(SolidSelector, self).__init__()
self.setWindowTitle(self.tr("Select Solids"))
self.setHelpText(self.tr(
"Select elements part of the solid that shall be added"
" to the list. To than add the solid click \"Add\"."))
def getSelection(self):
selection = []
for selObj in Gui.Selection.getSelectionEx():
solids = set()
for sub in self._getObjects(selObj.Object, selObj.SubElementNames):
s = self._getSolidOfSub(selObj.Object, sub)
if s is not None:
solids.add(s)
if solids:
item = (selObj.Object, tuple(solids))
selection.append(item)
return selection
def _getObjects(self, obj, names):
objects = []
shape = obj.Shape
for n in names:
if n.startswith("Face"):
objects.append(shape.Faces[int(n[4:]) - 1])
elif n.startswith("Edge"):
objects.append(shape.Edges[int(n[4:]) - 1])
elif n.startswith("Vertex"):
objects.append(shape.Vertexes[int(n[6:]) - 1])
elif n.startswith("Solid"):
objects.append(shape.Solids[int(n[5:]) - 1])
return objects
def _getSolidOfSub(self, obj, sub):
foundSolids = set()
if sub.ShapeType == "Solid":
for solidId, solid in enumerate(obj.Shape.Solids):
if sub.isSame(solid):
foundSolids.add("Solid" + str(solidId + 1))
elif sub.ShapeType == "Face":
for solidId, solid in enumerate(obj.Shape.Solids):
if(self._findSub(sub, solid.Faces)):
foundSolids.add("Solid" + str(solidId + 1))
elif sub.ShapeType == "Edge":
for solidId, solid in enumerate(obj.Shape.Solids):
if(self._findSub(sub, solid.Edges)):
foundSolids.add("Solid" + str(solidId + 1))
elif sub.ShapeType == "Vertex":
for solidId, solid in enumerate(obj.Shape.Solids):
if(self._findSub(sub, solid.Vertexes)):
foundSolids.add("Solid" + str(solidId + 1))
if len(foundSolids) == 1:
return iter(foundSolids).next()
return None
def _findSub(self, sub, subList):
for i, s in enumerate(subList):
if s.isSame(sub):
return True
return False
class SmallListView(QtGui.QListView):
def sizeHint(self):
return QtCore.QSize(50, 50)

View File

@@ -0,0 +1,53 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "_Base ViewProvider"
__author__ = "Markus Hovorka"
__url__ = "http://www.freecadweb.org"
import FreeCAD
if FreeCAD.GuiUp:
from pivy import coin
class ViewProxy(object):
"""Proxy View Provider for Pythons base constraint."""
def __init__(self, vobj):
vobj.Proxy = self
def attach(self, vobj):
default = coin.SoGroup()
vobj.addDisplayMode(default, "Default")
def getDisplayModes(self, obj):
"Return a list of display modes."
modes = ["Default"]
return modes
def getDefaultDisplayMode(self):
return "Default"
def setDisplayMode(self, mode):
return mode

View File

@@ -0,0 +1,336 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "Solver Job Control Task Panel"
__author__ = "Markus Hovorka"
__url__ = "http://www.freecadweb.org"
from PySide import QtCore
from PySide import QtGui
import FreeCADGui as Gui
import femsolver.run
import femsolver.report
_UPDATE_INTERVAL = 50
_REPORT_TITLE = "Run Report"
_REPORT_ERR = (
"Failed to run. Please try again after all"
"of the following errors are resolved.")
class ControlTaskPanel(QtCore.QObject):
machineChanged = QtCore.Signal(object)
machineStarted = QtCore.Signal(object)
machineStopped = QtCore.Signal(object)
machineStatusChanged = QtCore.Signal(str)
machineStatusCleared = QtCore.Signal()
machineTimeChanged = QtCore.Signal(float)
machineStateChanged = QtCore.Signal(float)
def __init__(self, machine):
super(ControlTaskPanel, self).__init__()
self.form = ControlWidget()
self._machine = None
# Timer that updates the duration indicator.
self._timer = QtCore.QTimer()
self._timer.setInterval(_UPDATE_INTERVAL)
self._timer.timeout.connect(self._timeProxy)
# Connect object to widget.
self.form.writeClicked.connect(self.write)
self.form.editClicked.connect(self.edit)
self.form.runClicked.connect(self.run)
self.form.abortClicked.connect(self.abort)
self.form.directoryChanged.connect(self.updateMachine)
# Seems that the task panel doesn't get destroyed. Disconnect
# as soon as the widget of the task panel gets destroyed.
self.form.destroyed.connect(self._disconnectMachine)
self.form.destroyed.connect(self._timer.stop)
self.form.destroyed.connect(
lambda: self.machineStatusChanged.disconnect(
self.form.appendStatus))
# Connect all proxy signals.
self.machineStarted.connect(self._timer.start)
self.machineStarted.connect(self.form.updateState)
self.machineStopped.connect(self._timer.stop)
self.machineStopped.connect(self._displayReport)
self.machineStopped.connect(self.form.updateState)
self.machineStatusChanged.connect(self.form.appendStatus)
self.machineStatusCleared.connect(self.form.clearStatus)
self.machineTimeChanged.connect(self.form.setTime)
self.machineStateChanged.connect(
lambda: self.form.updateState(self.machine))
self.machineChanged.connect(self._updateTimer)
# Set initial machine. Signal updates the widget.
self.machineChanged.connect(self.updateWidget)
self.form.destroyed.connect(
lambda: self.machineChanged.disconnect(self.updateWidget))
self.machine = machine
@property
def machine(self):
return self._machine
@machine.setter
def machine(self, value):
self._connectMachine(value)
self._machine = value
self.machineChanged.emit(value)
@QtCore.Slot()
def write(self):
self.machine.reset()
self.machine.target = femsolver.run.PREPARE
self.machine.start()
@QtCore.Slot()
def run(self):
self.machine.reset(femsolver.run.SOLVE)
self.machine.target = femsolver.run.RESULTS
self.machine.start()
@QtCore.Slot()
def edit(self):
self.machine.reset(femsolver.run.SOLVE)
self.machine.solver.Proxy.edit(
self.machine.directory)
@QtCore.Slot()
def abort(self):
self.machine.abort()
@QtCore.Slot()
def updateWidget(self):
self.form.setDirectory(self.machine.directory)
self.form.setStatus(self.machine.status)
self.form.setTime(self.machine.time)
self.form.updateState(self.machine)
@QtCore.Slot()
def updateMachine(self):
if self.form.directory() != self.machine.directory:
self.machine = femsolver.run.getMachine(
self.machine.solver, self.form.directory())
@QtCore.Slot()
def _updateTimer(self):
if self.machine.running:
self._timer.start()
@QtCore.Slot(object)
def _displayReport(self, machine):
text = _REPORT_ERR if machine.failed else None
femsolver.report.display(machine.report, _REPORT_TITLE, text)
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
def reject(self):
Gui.ActiveDocument.resetEdit()
def _connectMachine(self, machine):
self._disconnectMachine()
machine.signalStatus.add(self._statusProxy)
machine.signalStatusCleared.add(self._statusClearedProxy)
machine.signalStarted.add(self._startedProxy)
machine.signalStopped.add(self._stoppedProxy)
machine.signalState.add(self._stateProxy)
def _disconnectMachine(self):
if self.machine is not None:
self.machine.signalStatus.remove(self._statusProxy)
self.machine.signalStatusCleared.add(self._statusClearedProxy)
self.machine.signalStarted.remove(self._startedProxy)
self.machine.signalStopped.remove(self._stoppedProxy)
self.machine.signalState.remove(self._stateProxy)
def _startedProxy(self):
self.machineStarted.emit(self.machine)
def _stoppedProxy(self):
self.machineStopped.emit(self.machine)
def _statusProxy(self, line):
self.machineStatusChanged.emit(line)
def _statusClearedProxy(self):
self.machineStatusCleared.emit()
def _timeProxy(self):
time = self.machine.time
self.machineTimeChanged.emit(time)
def _stateProxy(self):
state = self.machine.state
self.machineStateChanged.emit(state)
class ControlWidget(QtGui.QWidget):
writeClicked = QtCore.Signal()
editClicked = QtCore.Signal()
runClicked = QtCore.Signal()
abortClicked = QtCore.Signal()
directoryChanged = QtCore.Signal()
def __init__(self, parent=None):
super(ControlWidget, self).__init__(parent)
self._setupUi()
self._inputFileName = ""
def _setupUi(self):
self.setWindowTitle(self.tr("Solver Control"))
# Working directory group box
self._directoryTxt = QtGui.QLineEdit()
self._directoryTxt.editingFinished.connect(self.directoryChanged)
directoryBtt = QtGui.QToolButton()
directoryBtt.setText("...")
directoryBtt.clicked.connect(self._selectDirectory)
directoryLyt = QtGui.QHBoxLayout()
directoryLyt.addWidget(self._directoryTxt)
directoryLyt.addWidget(directoryBtt)
self._directoryGrp = QtGui.QGroupBox()
self._directoryGrp.setTitle(self.tr("Working Directory"))
self._directoryGrp.setLayout(directoryLyt)
# Action buttons (Write, Edit, Run)
self._writeBtt = QtGui.QPushButton(self.tr("Write"))
self._editBtt = QtGui.QPushButton(self.tr("Edit"))
self._runBtt = QtGui.QPushButton()
self._writeBtt.clicked.connect(self.writeClicked)
self._editBtt.clicked.connect(self.editClicked)
actionLyt = QtGui.QGridLayout()
actionLyt.addWidget(self._writeBtt, 0, 0)
actionLyt.addWidget(self._editBtt, 0, 1)
actionLyt.addWidget(self._runBtt, 1, 0, 1, 2)
# Solver status log
self._statusEdt = QtGui.QPlainTextEdit()
self._statusEdt.setReadOnly(True)
# Elapsed time indicator
timeHeaderLbl = QtGui.QLabel(self.tr("Elapsed Time:"))
self._timeLbl = QtGui.QLabel()
timeLyt = QtGui.QHBoxLayout()
timeLyt.addWidget(timeHeaderLbl)
timeLyt.addWidget(self._timeLbl)
timeLyt.addStretch()
timeLyt.setContentsMargins(0, 0, 0, 0)
self._timeWid = QtGui.QWidget()
self._timeWid.setLayout(timeLyt)
# Main layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self._directoryGrp)
layout.addLayout(actionLyt)
layout.addWidget(self._statusEdt)
layout.addWidget(self._timeWid)
self.setLayout(layout)
@QtCore.Slot(str)
def setStatus(self, text):
if text is None:
text = ""
self._statusEdt.setPlainText(text)
self._statusEdt.moveCursor(QtGui.QTextCursor.End)
def status(self):
return self._statusEdt.plainText()
@QtCore.Slot(str)
def appendStatus(self, line):
self._statusEdt.moveCursor(QtGui.QTextCursor.End)
self._statusEdt.insertPlainText(line)
self._statusEdt.moveCursor(QtGui.QTextCursor.End)
@QtCore.Slot(str)
def clearStatus(self):
self._statusEdt.setPlainText("")
@QtCore.Slot(float)
def setTime(self, time):
timeStr = "<b>%05.1f</b>" % time if time is not None else ""
self._timeLbl.setText(timeStr)
def time(self):
if (self._timeLbl.text() == ""):
return None
return float(self._timeLbl.text())
@QtCore.Slot(float)
def setDirectory(self, directory):
self._directoryTxt.setText(directory)
def directory(self):
return self._directoryTxt.text()
@QtCore.Slot(int)
def updateState(self, machine):
if machine.state <= femsolver.run.PREPARE:
self._writeBtt.setText(self.tr("Write"))
self._editBtt.setText(self.tr("Edit"))
self._runBtt.setText(self.tr("Run"))
elif machine.state <= femsolver.run.SOLVE:
self._writeBtt.setText(self.tr("Re-write"))
self._editBtt.setText(self.tr("Edit"))
self._runBtt.setText(self.tr("Run"))
else:
self._writeBtt.setText(self.tr("Re-write"))
self._editBtt.setText(self.tr("Edit"))
self._runBtt.setText(self.tr("Re-run"))
if machine.running:
self._runBtt.setText(self.tr("Abort"))
self.setRunning(machine)
@QtCore.Slot()
def _selectDirectory(self):
path = QtGui.QFileDialog.getExistingDirectory(self)
self.setDirectory(path)
self.directoryChanged.emit()
def setRunning(self, machine):
if machine.running:
self._runBtt.clicked.connect(self.runClicked)
self._runBtt.clicked.disconnect()
self._runBtt.clicked.connect(self.abortClicked)
self._directoryGrp.setDisabled(True)
self._writeBtt.setDisabled(True)
self._editBtt.setDisabled(True)
else:
self._runBtt.clicked.connect(self.abortClicked)
self._runBtt.clicked.disconnect()
self._runBtt.clicked.connect(self.runClicked)
self._directoryGrp.setDisabled(False)
self._writeBtt.setDisabled(False)
self._editBtt.setDisabled(
not machine.solver.Proxy.editSupported() or
machine.state < femsolver.run.PREPARE)

View File

@@ -0,0 +1,35 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "view provider for constraint body heat source object"
__author__ = "Markus Hovorka, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
from . import ViewProviderFemConstraint
class ViewProxy(ViewProviderFemConstraint.ViewProxy):
def getIcon(self):
return ":/icons/fem-constraint-heatflux.svg"

View File

@@ -0,0 +1,121 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "Elmer Solver Object"
__author__ = "Markus Hovorka, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
import FreeCAD as App
import femtools.femutils as FemUtils
from . import ViewProviderFemConstraint
from FreeCAD import Units
import FreeCADGui as Gui
from . import FemSelectionWidgets
class ViewProxy(ViewProviderFemConstraint.ViewProxy):
def getIcon(self):
return ":/icons/fem-constraint-electrostatic-potential.svg"
def setEdit(self, vobj, mode=0):
task = _TaskPanel(vobj.Object)
Gui.Control.showDialog(task)
def unsetEdit(self, vobj, mode=0):
Gui.Control.closeDialog()
def doubleClicked(self, vobj):
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
Gui.ActiveDocument.setEdit(vobj.Object.Name)
return True
class _TaskPanel(object):
def __init__(self, obj):
self._obj = obj
self._refWidget = FemSelectionWidgets.BoundarySelector()
self._refWidget.setReferences(obj.References)
self._paramWidget = Gui.PySideUic.loadUi(
App.getHomePath() + "Mod/Fem/Resources/ui/ElectrostaticPotential.ui")
self._initParamWidget()
self.form = [self._refWidget, self._paramWidget]
analysis = FemUtils.findAnalysisOfMember(obj)
self._mesh = FemUtils.getSingleMember(analysis, "Fem::FemMeshObject")
self._part = self._mesh.Part if self._mesh is not None else None
self._partVisible = None
self._meshVisible = None
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
self._partVisible = self._part.ViewObject.isVisible()
self._mesh.ViewObject.hide()
self._part.ViewObject.show()
def reject(self):
self._restoreVisibility()
return True
def accept(self):
if self._obj.References != self._refWidget.references():
self._obj.References = self._refWidget.references()
self._applyWidgetChanges()
self._obj.Document.recompute()
self._restoreVisibility()
return True
def _restoreVisibility(self):
if self._mesh is not None and self._part is not None:
if self._meshVisible:
self._mesh.ViewObject.show()
else:
self._mesh.ViewObject.hide()
if self._partVisible:
self._part.ViewObject.show()
else:
self._part.ViewObject.hide()
def _initParamWidget(self):
unit = "V"
q = Units.Quantity("{} {}".format(self._obj.Potential, unit))
self._paramWidget.potentialTxt.setText(
q.UserString)
self._paramWidget.potentialBox.setChecked(
not self._obj.PotentialEnabled)
self._paramWidget.potentialConstantBox.setChecked(
self._obj.PotentialConstant)
def _applyWidgetChanges(self):
unit = "V"
self._obj.PotentialEnabled = \
not self._paramWidget.potentialBox.isChecked()
if self._obj.PotentialEnabled:
quantity = Units.Quantity(self._paramWidget.potentialTxt.text())
self._obj.Potential = float(quantity.getValueAs(unit))
self._obj.PotentialConstant = self._paramWidget.potentialConstantBox.isChecked()

View File

@@ -0,0 +1,141 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "view provider for constraint flow velocity object"
__author__ = "Markus Hovorka, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
import FreeCAD as App
import femtools.femutils as FemUtils
from . import ViewProviderFemConstraint
from FreeCAD import Units
import FreeCADGui as Gui
from . import FemSelectionWidgets
class ViewProxy(ViewProviderFemConstraint.ViewProxy):
def getIcon(self):
return ":/icons/fem-constraint-flow-velocity.svg"
def setEdit(self, vobj, mode=0):
task = _TaskPanel(vobj.Object)
Gui.Control.showDialog(task)
def unsetEdit(self, vobj, mode=0):
Gui.Control.closeDialog()
def doubleClicked(self, vobj):
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
Gui.ActiveDocument.setEdit(vobj.Object.Name)
return True
class _TaskPanel(object):
def __init__(self, obj):
self._obj = obj
self._refWidget = FemSelectionWidgets.BoundarySelector()
self._refWidget.setReferences(obj.References)
self._paramWidget = Gui.PySideUic.loadUi(
App.getHomePath() + "Mod/Fem/Resources/ui/FlowVelocity.ui")
self._initParamWidget()
self.form = [self._refWidget, self._paramWidget]
analysis = FemUtils.findAnalysisOfMember(obj)
self._mesh = FemUtils.getSingleMember(analysis, "Fem::FemMeshObject")
self._part = None
if hasattr(self._mesh, "Part"): # Geometry of Gmesh mesh obj
self._part = self._mesh.Part
elif hasattr(self._mesh, "Shape"): # Geometry of Netgen mesh obj
self._part = self._mesh.Shape
self._partVisible = None
self._meshVisible = None
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
self._partVisible = self._part.ViewObject.isVisible()
self._mesh.ViewObject.hide()
self._part.ViewObject.show()
def reject(self):
self._restoreVisibility()
return True
def accept(self):
if self._obj.References != self._refWidget.references():
self._obj.References = self._refWidget.references()
self._applyWidgetChanges()
self._obj.Document.recompute()
self._restoreVisibility()
return True
def _restoreVisibility(self):
if self._mesh is not None and self._part is not None:
if self._meshVisible:
self._mesh.ViewObject.show()
else:
self._mesh.ViewObject.hide()
if self._partVisible:
self._part.ViewObject.show()
else:
self._part.ViewObject.hide()
def _initParamWidget(self):
unit = "m/s"
self._paramWidget.velocityXTxt.setText(
str(self._obj.VelocityX) + unit)
self._paramWidget.velocityYTxt.setText(
str(self._obj.VelocityY) + unit)
self._paramWidget.velocityZTxt.setText(
str(self._obj.VelocityZ) + unit)
self._paramWidget.velocityXBox.setChecked(
not self._obj.VelocityXEnabled)
self._paramWidget.velocityYBox.setChecked(
not self._obj.VelocityYEnabled)
self._paramWidget.velocityZBox.setChecked(
not self._obj.VelocityZEnabled)
self._paramWidget.normalBox.setChecked(
self._obj.NormalToBoundary)
def _applyWidgetChanges(self):
unit = "m/s"
self._obj.VelocityXEnabled = \
not self._paramWidget.velocityXBox.isChecked()
if self._obj.VelocityXEnabled:
quantity = Units.Quantity(self._paramWidget.velocityXTxt.text())
self._obj.VelocityX = float(quantity.getValueAs(unit))
self._obj.VelocityYEnabled = \
not self._paramWidget.velocityYBox.isChecked()
if self._obj.VelocityYEnabled:
quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
self._obj.VelocityY = float(quantity.getValueAs(unit))
self._obj.VelocityZEnabled = \
not self._paramWidget.velocityZBox.isChecked()
if self._obj.VelocityZEnabled:
quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
self._obj.VelocityZ = float(quantity.getValueAs(unit))
self._obj.NormalToBoundary = self._paramWidget.normalBox.isChecked()

View File

@@ -0,0 +1,129 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
# * *
# * 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__ = "view provider for constraint initial flow velocity object"
__author__ = "Markus Hovorka, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
import FreeCAD as App
import femtools.femutils as FemUtils
from . import ViewProviderFemConstraint
from FreeCAD import Units
import FreeCADGui as Gui
class ViewProxy(ViewProviderFemConstraint.ViewProxy):
def getIcon(self):
return ":/icons/fem-constraint-initial-flow-velocity.svg"
def setEdit(self, vobj, mode=0):
task = _TaskPanel(vobj.Object)
Gui.Control.showDialog(task)
def unsetEdit(self, vobj, mode=0):
Gui.Control.closeDialog()
def doubleClicked(self, vobj):
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
Gui.ActiveDocument.setEdit(vobj.Object.Name)
return True
class _TaskPanel(object):
def __init__(self, obj):
self._obj = obj
self._paramWidget = Gui.PySideUic.loadUi(
App.getHomePath() + "Mod/Fem/Resources/ui/InitialFlowVelocity.ui")
self._initParamWidget()
self.form = [self._paramWidget]
analysis = FemUtils.findAnalysisOfMember(obj)
self._mesh = FemUtils.getSingleMember(analysis, "Fem::FemMeshObject")
self._part = self._mesh.Part if self._mesh is not None else None
self._partVisible = None
self._meshVisible = None
def open(self):
if self._mesh is not None and self._part is not None:
self._meshVisible = self._mesh.ViewObject.isVisible()
self._partVisible = self._part.ViewObject.isVisible()
self._mesh.ViewObject.hide()
self._part.ViewObject.show()
def reject(self):
self._restoreVisibility()
return True
def accept(self):
self._applyWidgetChanges()
self._obj.Document.recompute()
self._restoreVisibility()
return True
def _restoreVisibility(self):
if self._mesh is not None and self._part is not None:
if self._meshVisible:
self._mesh.ViewObject.show()
else:
self._mesh.ViewObject.hide()
if self._partVisible:
self._part.ViewObject.show()
else:
self._part.ViewObject.hide()
def _initParamWidget(self):
unit = "m/s"
self._paramWidget.velocityXTxt.setText(
str(self._obj.VelocityX) + unit)
self._paramWidget.velocityYTxt.setText(
str(self._obj.VelocityY) + unit)
self._paramWidget.velocityZTxt.setText(
str(self._obj.VelocityZ) + unit)
self._paramWidget.velocityXBox.setChecked(
not self._obj.VelocityXEnabled)
self._paramWidget.velocityYBox.setChecked(
not self._obj.VelocityYEnabled)
self._paramWidget.velocityZBox.setChecked(
not self._obj.VelocityZEnabled)
def _applyWidgetChanges(self):
unit = "m/s"
self._obj.VelocityXEnabled = \
not self._paramWidget.velocityXBox.isChecked()
if self._obj.VelocityXEnabled:
quantity = Units.Quantity(self._paramWidget.velocityXTxt.text())
self._obj.VelocityX = float(quantity.getValueAs(unit))
self._obj.VelocityYEnabled = \
not self._paramWidget.velocityYBox.isChecked()
if self._obj.VelocityYEnabled:
quantity = Units.Quantity(self._paramWidget.velocityYTxt.text())
self._obj.VelocityY = float(quantity.getValueAs(unit))
self._obj.VelocityZEnabled = \
not self._paramWidget.velocityZBox.isChecked()
if self._obj.VelocityZEnabled:
quantity = Units.Quantity(self._paramWidget.velocityZTxt.text())
self._obj.VelocityZ = float(quantity.getValueAs(unit))

View File

@@ -0,0 +1,53 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemConstraintSelfWeight"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemConstraintSelfWeight
# \ingroup FEM
class _ViewProviderFemConstraintSelfWeight:
"A View Provider for the FemConstraintSelfWeight object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-constraint-selfweight.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def __getstate__(self):
return None
def __setstate__(self, state):
return None

View File

@@ -0,0 +1,473 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemElementFluid1D"
__author__ = "Ofentse Kgoa"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemElementFluid1D
# \ingroup FEM
import FreeCAD
import FreeCADGui
# for the panel
from femobjects import _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
def getIcon(self):
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()
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):
taskd = _TaskPanelFemElementFluid1D(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
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/Resources/ui/ElementFluid1D.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(_FemElementFluid1D._FemElementFluid1D.known_fluid_types)
self.form.cb_liquid_section_type.addItems(_FemElementFluid1D._FemElementFluid1D.known_liquid_types)
self.form.cb_gas_section_type.addItems(_FemElementFluid1D._FemElementFluid1D.known_gas_types)
self.form.cb_channel_section_type.addItems(_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

@@ -0,0 +1,272 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemElementGeometry1D"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemElementGeometry1D
# \ingroup FEM
import FreeCAD
import FreeCADGui
# for the panel
from femobjects import _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
def getIcon(self):
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()
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):
taskd = _TaskPanelFemElementGeometry1D(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
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/Resources/ui/ElementGeometry1D.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(_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

@@ -0,0 +1,230 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemElementGeometry2D"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemElementGeometry2D
# \ingroup FEM
import FreeCAD
import FreeCADGui
# 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
def getIcon(self):
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()
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):
taskd = _TaskPanelFemElementGeometry2D(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
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/Resources/ui/ElementGeometry2D.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

@@ -0,0 +1,231 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - 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__ = "_ViewProviderFemElementRotation1D"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemElementRotation1D
# \ingroup FEM
import FreeCAD
import FreeCADGui
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemElementRotation1D:
"A View Provider for the FemElementRotation1D object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-beam-rotation.svg"
def attach(self, vobj):
from pivy import coin
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
'''
# do not activate the task panel, since rotation with reference shapes is not yet supported
def setEdit(self, vobj, mode=0):
taskd = _TaskPanelFemElementRotation1D(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
class _TaskPanelFemElementRotation1D:
'''The TaskPanel for editing References property of FemElementRotation1D 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/Resources/ui/ElementRotation1D.ui")
QtCore.QObject.connect(self.form.if_rotation, QtCore.SIGNAL("valueChanged(Base::Quantity)"), self.rotation_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_beamsection_props()
self.update()
def accept(self):
self.setback_listobj_visibility()
self.set_beamrotation_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.Rotation = self.obj.Rotation
def set_beamrotation_props(self):
self.obj.References = self.references
self.obj.Rotation = self.Rotation
def update(self):
'fills the widgets'
self.form.if_rotation.setText(self.Rotation.UserString)
self.rebuild_list_References()
def rotation_changed(self, base_quantity_value):
self.Rotation = 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

@@ -0,0 +1,692 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMaterial"
__author__ = "Juergen Riegel, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package _ViewProviderFemMaterial
# \ingroup FEM
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"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-material.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def setEdit(self, vobj, mode):
taskd = _TaskPanelFemMaterial(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self, vobj, mode):
FreeCADGui.Control.closeDialog()
return
# overwrite the doubleClicked to make sure no other Material taskd (and thus no selection observer) is still active
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
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/Resources/ui/Material.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

@@ -0,0 +1,63 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMaterialMechanicalNonlinear"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMaterialMechanicalNonLinear
# \ingroup FEM
from pivy import coin
class _ViewProviderFemMaterialMechanicalNonlinear:
"A View Provider for the FemMaterialMechanicalNonlinear object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-material-nonlinear.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 __getstate__(self):
return None
def __setstate__(self, state):
return None

View File

@@ -0,0 +1,266 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMeshBoundaryLayer"
__author__ = "Bernd Hahnebach, Qingfeng Xia"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMeshBoundaryLayer
# \ingroup FEM
import FreeCAD
import FreeCADGui
# 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
def getIcon(self):
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()
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
taskd = _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
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/Resources/ui/MeshBoundaryLayer.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

@@ -0,0 +1,288 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMeshGmsh"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMeshGmsh
# \ingroup FEM
import FreeCAD
import FreeCADGui
import FemGui
# for the panel
from femobjects import _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
def getIcon(self):
return ":/icons/fem-femmesh-from-shape.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def setEdit(self, vobj, mode):
self.ViewObject.show() # show the mesh on edit if it is hided
taskd = _TaskPanelFemMeshGmsh(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self, vobj, mode):
FreeCADGui.Control.closeDialog()
self.ViewObject.hide() # hide the mesh after edit is finished
return
def doubleClicked(self, vobj):
FreeCADGui.activateWorkbench('FemWorkbench')
# Group meshing is only active on active analysis, we should make sure the analysis the mesh belongs too is active
gui_doc = FreeCADGui.getDocument(vobj.Object.Document)
if not gui_doc.getInEdit():
# may be go the other way around and just activate the analysis the user has doubleClicked on ?!
# not a fast one, we need to iterate over all member of all analysis to know to which analyis the object belongs too!!!
# first check if there is an analysis in the active document
found_an_analysis = False
for o in gui_doc.Document.Objects:
if o.isDerivedFrom('Fem::FemAnalysisPython'):
found_an_analysis = True
break
if found_an_analysis:
if FemGui.getActiveAnalysis() is not None:
if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument:
if self.Object in FemGui.getActiveAnalysis().Group:
if not gui_doc.getInEdit():
gui_doc.setEdit(vobj.Object.Name)
else:
FreeCAD.Console.PrintError('Activate the analysis this Gmsh FEM mesh object belongs too!\n')
else:
print('Gmsh FEM mesh object does not belong to the active analysis.')
found_mesh_analysis = False
for o in gui_doc.Document.Objects:
if o.isDerivedFrom('Fem::FemAnalysisPython'):
for m in o.Group:
if m == self.Object:
found_mesh_analysis = True
FemGui.setActiveAnalysis(o)
print('The analysis the Gmsh FEM mesh object belongs too was found and activated: ' + o.Name)
gui_doc.setEdit(vobj.Object.Name)
break
if not found_mesh_analysis:
print('Gmsh FEM mesh object does not belong to an analysis. Analysis group meshing will be deactivated.')
gui_doc.setEdit(vobj.Object.Name)
else:
FreeCAD.Console.PrintError('Active analysis is not in active document.')
else:
print('No active analysis in active document, we are going to have a look if the Gmsh FEM mesh object belongs to a non active analysis.')
found_mesh_analysis = False
for o in gui_doc.Document.Objects:
if o.isDerivedFrom('Fem::FemAnalysisPython'):
for m in o.Group:
if m == self.Object:
found_mesh_analysis = True
FemGui.setActiveAnalysis(o)
print('The analysis the Gmsh FEM mesh object belongs to was found and activated: ' + o.Name)
gui_doc.setEdit(vobj.Object.Name)
break
if not found_mesh_analysis:
print('Gmsh FEM mesh object does not belong to an analysis. Analysis group meshing will be deactivated.')
gui_doc.setEdit(vobj.Object.Name)
else:
print('No analysis in the active document.')
gui_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
def claimChildren(self):
return (self.Object.MeshRegionList + self.Object.MeshGroupList + self.Object.MeshBoundaryLayerList)
def onDelete(self, feature, subelements):
try:
for obj in self.claimChildren():
obj.ViewObject.show()
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/Resources/ui/MeshGmsh.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(_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

@@ -0,0 +1,285 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMeshGroup"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMeshGroup
# \ingroup FEM
import FreeCAD
import FreeCADGui
# for the panel
from PySide import QtCore
from PySide import QtGui
class _ViewProviderFemMeshGroup:
"A View Provider for the FemMeshGroup object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
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()
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
taskd = _TaskPanelFemMeshGroup(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
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/Resources/ui/MeshGroup.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

@@ -0,0 +1,281 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemMeshRegion"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMeshRegion
# \ingroup FEM
import FreeCAD
import FreeCADGui
# 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
def getIcon(self):
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()
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
taskd = _TaskPanelFemMeshRegion(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
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/Resources/ui/MeshRegion.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

@@ -0,0 +1,53 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - 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__ = "_ViewProviderFemMeshResult"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemMeshResult
# \ingroup FEM
class _ViewProviderFemMeshResult:
"A View Provider for the FemMeshResult object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-femmesh-result.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def __getstate__(self):
return None
def __setstate__(self, state):
return None

View File

@@ -0,0 +1,502 @@
#***************************************************************************
#* *
#* Copyright (c) 2015 - Qingfeng Xia <qingfeng.xia()eng.ox.ac.uk> *
#* *
#* 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__ = "ViewProvider for FEM mechanical ResultObjectPython"
__author__ = "Qingfeng Xia, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package _ViewProviderFemResultMechanical
# \ingroup FEM
# \brief FreeCAD ViewProvider for mechanical ResultObjectPython in FEM workbench
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"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
"""after load from FCStd file, self.icon does not exist, return constant path instead"""
return ":/icons/fem-result.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def doubleClicked(self, vobj):
if FreeCADGui.activeWorkbench().name() != 'FemWorkbench':
FreeCADGui.activateWorkbench("FemWorkbench")
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 setEdit(self, vobj, mode=0):
if hasattr(self.Object, "Mesh") and self.Object.Mesh:
hide_femmeshes_postpiplines()
# only show the FEM result mesh
self.Object.Mesh.ViewObject.show()
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
def unsetEdit(self, vobj, mode=0):
FreeCADGui.Control.closeDialog()
self.Object.Mesh.ViewObject.hide() # hide the mesh after result viewing is finished, but do not reset the coloring
return
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def claimChildren(self):
return [self.Object.Mesh] # claimChildren needs to return a list !
def onDelete(self, feature, subelements):
try:
for obj in self.claimChildren():
obj.ViewObject.show()
except Exception as err:
FreeCAD.Console.PrintError("Error in onDelete: " + err.message)
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/Resources/ui/ResultShow.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

@@ -0,0 +1,350 @@
# ***************************************************************************
# * *
# * 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__ = "_ViewProviderFemSolverCalculix"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package ViewProviderFemSolverCalculix
# \ingroup FEM
import FreeCAD
import FreeCADGui
import FemGui
# for the panel
from femtools import ccxtools
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
def getIcon(self):
return ":/icons/fem-solver.svg"
def attach(self, vobj):
self.ViewObject = vobj
self.Object = vobj.Object
def updateData(self, obj, prop):
return
def onChanged(self, vobj, prop):
return
def setEdit(self, vobj, mode=0):
taskd = _TaskPanelFemSolverCalculix(self.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():
# may be go the other way around and just activate the analysis the user has doubleClicked on ?!
if FemGui.getActiveAnalysis() is not None:
if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument:
if self.Object in FemGui.getActiveAnalysis().Group:
doc.setEdit(vobj.Object.Name)
else:
FreeCAD.Console.PrintError('Activate the analysis this solver belongs to!\n')
else:
FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n')
else:
FreeCAD.Console.PrintError('No active Analysis found!\n')
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
class _TaskPanelFemSolverCalculix:
'''The TaskPanel for CalculiX ccx tools solver object'''
def __init__(self, solver_object):
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/Resources/ui/SolverCalculix.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 = ccxtools.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 = ccxtools.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 = ccxtools.FemToolsCcx(None, self.solver_object)
fea.update_objects()
message = fea.check_prerequisites()
if message != "":
QtGui.QMessageBox.critical(None, "Missing prerequisite(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 ccxtools setup_working_dir and could be removed when the one from ccxtools 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

@@ -0,0 +1,29 @@
# ***************************************************************************
# * *
# * Copyright (c) 2017 - 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__ = "Fem Gui modules"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package PyGui
# \ingroup Fem
# \brief Fem Gui module