FEM: objects, use fem name sheme for object package names
This commit is contained in:
committed by
Yorik van Havre
parent
07ae0e56c4
commit
c85afd0e44
47
src/Mod/Fem/femguiobjects/FemSelectionObserver.py
Normal file
47
src/Mod/Fem/femguiobjects/FemSelectionObserver.py
Normal 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)
|
||||
|
||||
## @}
|
||||
204
src/Mod/Fem/femguiobjects/FemSelectionWidgets.py
Normal file
204
src/Mod/Fem/femguiobjects/FemSelectionWidgets.py
Normal 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)
|
||||
53
src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py
Normal file
53
src/Mod/Fem/femguiobjects/ViewProviderFemConstraint.py
Normal 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
|
||||
336
src/Mod/Fem/femguiobjects/_TaskPanelFemSolverControl.py
Normal file
336
src/Mod/Fem/femguiobjects/_TaskPanelFemSolverControl.py
Normal 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)
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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))
|
||||
@@ -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
|
||||
473
src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py
Normal file
473
src/Mod/Fem/femguiobjects/_ViewProviderFemElementFluid1D.py
Normal 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 = []
|
||||
272
src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py
Normal file
272
src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry1D.py
Normal 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 = []
|
||||
230
src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py
Normal file
230
src/Mod/Fem/femguiobjects/_ViewProviderFemElementGeometry2D.py
Normal 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 = []
|
||||
231
src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py
Normal file
231
src/Mod/Fem/femguiobjects/_ViewProviderFemElementRotation1D.py
Normal 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 = []
|
||||
692
src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py
Normal file
692
src/Mod/Fem/femguiobjects/_ViewProviderFemMaterial.py
Normal 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 = []
|
||||
@@ -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
|
||||
266
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py
Normal file
266
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshBoundaryLayer.py
Normal 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)
|
||||
288
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGmsh.py
Normal file
288
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGmsh.py
Normal 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
|
||||
285
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py
Normal file
285
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshGroup.py
Normal 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 = []
|
||||
281
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py
Normal file
281
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshRegion.py
Normal 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 = []
|
||||
53
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py
Normal file
53
src/Mod/Fem/femguiobjects/_ViewProviderFemMeshResult.py
Normal 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
|
||||
502
src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py
Normal file
502
src/Mod/Fem/femguiobjects/_ViewProviderFemResultMechanical.py
Normal 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
|
||||
350
src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py
Normal file
350
src/Mod/Fem/femguiobjects/_ViewProviderFemSolverCalculix.py
Normal 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
|
||||
29
src/Mod/Fem/femguiobjects/__init__.py
Normal file
29
src/Mod/Fem/femguiobjects/__init__.py
Normal 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
|
||||
Reference in New Issue
Block a user