Merge pull request #347 from berndhahnebach/bhbdev056

FemGmshTool
This commit is contained in:
wwmayer
2016-11-23 13:52:53 +01:00
committed by GitHub
74 changed files with 2296 additions and 331 deletions

View File

@@ -136,6 +136,7 @@ PyMODINIT_FUNC initFem()
Fem::FeaturePython ::init();
Fem::FemMesh ::init();
Fem::FemMeshObject ::init();
Fem::FemMeshObjectPython ::init();
Fem::FemMeshShapeObject ::init();
Fem::FemMeshShapeNetgenObject ::init();
Fem::PropertyFemMesh ::init();

View File

@@ -68,23 +68,26 @@ SET(FemScripts_SRCS
_CommandBeamSection.py
_CommandControlSolver.py
_CommandConstraintSelfWeight.py
_CommandMechanicalMaterial.py
_CommandShowResult.py
_CommandMaterialMechanicalNonlinear.py
_CommandMeshFromShape.py
_CommandMechanicalMaterial.py
_CommandMeshGmshFromShape.py
_CommandMeshNetgenFromShape.py
_CommandPurgeResults.py
_CommandRunSolver.py
_CommandShellThickness.py
_CommandShowResult.py
_CommandSolverCalculix.py
_CommandSolverZ88.py
_FemBeamSection.py
_FemConstraintSelfWeight.py
_FemMaterialMechanicalNonlinear.py
_FemMeshGmsh.py
_FemShellThickness.py
_FemSolverCalculix.py
_FemSolverZ88.py
_MechanicalMaterial.py
_TaskPanelFemBeamSection.py
_TaskPanelFemMeshGmsh.py
_TaskPanelFemShellThickness.py
_TaskPanelFemSolverCalculix.py
_TaskPanelMechanicalMaterial.py
@@ -92,6 +95,7 @@ SET(FemScripts_SRCS
_ViewProviderFemBeamSection.py
_ViewProviderFemConstraintSelfWeight.py
_ViewProviderFemMaterialMechanicalNonlinear.py
_ViewProviderFemMeshGmsh.py
_ViewProviderFemShellThickness.py
_ViewProviderFemSolverCalculix.py
_ViewProviderFemSolverZ88.py
@@ -107,10 +111,12 @@ SET(FemScripts_SRCS
FemBeamSection.py
FemCommands.py
FemConstraintSelfWeight.py
FemGmshTools.py
FemInputWriter.py
FemInputWriterCcx.py
FemInputWriterZ88.py
FemMaterialMechanicalNonlinear.py
FemMeshGmsh.py
FemMeshTools.py
FemShellThickness.py
FemSolverCalculix.py
@@ -123,6 +129,7 @@ SET(FemScripts_SRCS
TestFem.py
z88DispReader.py
TaskPanelFemBeamSection.ui
TaskPanelFemMeshGmsh.ui
TaskPanelFemShellThickness.ui
TaskPanelFemSolverCalculix.ui
TaskPanelMechanicalMaterial.ui

View File

@@ -29,6 +29,7 @@
#include "FemMeshObject.h"
#include "FemMesh.h"
#include <App/DocumentObjectPy.h>
#include <App/FeaturePythonPyImp.h>
#include <Base/Placement.h>
using namespace Fem;
@@ -70,3 +71,25 @@ void FemMeshObject::onChanged(const Property* prop)
}
}
// Python feature ---------------------------------------------------------
namespace App {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(Fem::FemMeshObjectPython, Fem::FemMeshObject)
template<> const char* Fem::FemMeshObjectPython::getViewProviderName(void) const {
return "FemGui::ViewProviderFemMeshPython";
}
template<> PyObject* Fem::FemMeshObjectPython::getPyObject(void) {
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new App::FeaturePythonPyT<App::DocumentObjectPy>(this),true);
}
return Py::new_reference_to(PythonObject);
}
// explicit template instantiation
template class AppFemExport FeaturePythonT<Fem::FemMeshObject>;
}

View File

@@ -24,6 +24,7 @@
#ifndef Fem_FemMeshObject_H
#define Fem_FemMeshObject_H
#include <App/FeaturePython.h>
#include <App/GeoFeature.h>
#include <App/PropertyFile.h>
#include <App/PropertyGeo.h>
@@ -60,6 +61,9 @@ protected:
virtual void onChanged (const App::Property* prop);
};
typedef App::FeaturePythonT<FemMeshObject> FemMeshObjectPython;
} //namespace Fem

View File

@@ -28,8 +28,6 @@
#endif
#include "FemSolverObject.h"
#include <Base/FileInfo.h>
#include <App/FeaturePythonPyImp.h>
#include <App/DocumentObjectPy.h>
@@ -42,20 +40,7 @@ PROPERTY_SOURCE(Fem::FemSolverObject, App::DocumentObject)
FemSolverObject::FemSolverObject()
{
/*
ADD_PROPERTY_TYPE(SolverName,("Calculix"), "Data",Prop_None,"Solver program name");
ADD_PROPERTY_TYPE(Category,("FEM"), "Data",Prop_None,"FEM, CFD ...");
ADD_PROPERTY_TYPE(Module,(""), "Data",Prop_None,"Python module name");
ADD_PROPERTY_TYPE(ExternalCaseEditor,(""), "Data",Prop_None,"External case editor programe");
ADD_PROPERTY_TYPE(ExternalResultViewer,(""), "Data",Prop_None,"External result viewer name");
ADD_PROPERTY_TYPE(AnalysisType,("Static"), "Solver",Prop_None,"Specific analysis type");
ADD_PROPERTY_TYPE(WorkingDir,(Base::FileInfo::getTempPath()), "Solver",Prop_None,"Solver working directory");
ADD_PROPERTY_TYPE(InputCaseName,("TestCase"), "Solver",Prop_None,"Solver input file without suffix");
ADD_PROPERTY_TYPE(Parallel,(false), "Solver",Prop_None,"Run solver in parallel like MPI");
ADD_PROPERTY_TYPE(ResultObtained,(false), "Solver",Prop_None,"if true, result has been obtained");
*/
// Attributes are implemented in the FemSolverObjectPython
}
FemSolverObject::~FemSolverObject()

View File

@@ -25,11 +25,7 @@
#ifndef Fem_FemSolverObject_H
#define Fem_FemSolverObject_H
#include <App/DocumentObject.h>
#include <App/PropertyUnits.h>
#include <App/PropertyStandard.h>
#include <App/FeaturePython.h>
#include "FemSolverObject.h"
namespace Fem
{
@@ -43,29 +39,7 @@ public:
FemSolverObject(void);
virtual ~FemSolverObject();
/*
/// Solver name, unique to identify solver in registered_solver dict
App::PropertyString SolverName;
/// CAE category like FEM, all capitalised letters
App::PropertyString Category;
/// python module name
App::PropertyString Module;
/// Path or program name for external case editor, empty string means using FreeCAD to view
App::PropertyString ExternalCaseEditor;
/// Path to External Result Viewer like Paraview, empty string means using FreeCAD
App::PropertyString ExternalResultViewer;
/// for FEM: Static, Frequency, etc
App::PropertyString AnalysisType;
/// Path of working dir for the solver
App::PropertyString WorkingDir;
/// name for the case file without suffix
App::PropertyString InputCaseName;
/// run parallel in MPI (message passing interface)/multiple cores or serial(single CPU)
App::PropertyBool Parallel;
/// result has been obtained, purge result may be needed for rerun
App::PropertyBool ResultObtained;
*/
// Attributes are implemented in the FemSolverObjectPython
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {

View File

@@ -24,7 +24,7 @@ INSTALL(
TestFem.py
FemCommands.py
_CommandMeshFromShape.py
_CommandMeshNetgenFromShape.py
_CommandPurgeResults.py
_CommandRunSolver.py
_CommandControlSolver.py
@@ -36,6 +36,15 @@ INSTALL(
FemAnalysis.py
_CommandAnalysis.py
FemMeshGmsh.py
_FemMeshGmsh.py
_ViewProviderFemMeshGmsh.py
_CommandMeshGmshFromShape.py
_TaskPanelFemMeshGmsh.py
TaskPanelFemMeshGmsh.ui
FemGmshTools.py
FemBeamSection.py
_FemBeamSection.py
_ViewProviderFemBeamSection.py
@@ -50,6 +59,11 @@ INSTALL(
_TaskPanelFemShellThickness.py
TaskPanelFemShellThickness.ui
FemConstraintSelfWeight.py
_FemConstraintSelfWeight.py
_ViewProviderFemConstraintSelfWeight.py
_CommandConstraintSelfWeight.py
MechanicalMaterial.py
_MechanicalMaterial.py
_ViewProviderMechanicalMaterial.py
@@ -85,11 +99,6 @@ INSTALL(
_ViewProviderFemSolverZ88.py
_CommandSolverZ88.py
FemConstraintSelfWeight.py
_FemConstraintSelfWeight.py
_ViewProviderFemConstraintSelfWeight.py
_CommandConstraintSelfWeight.py
DESTINATION
Mod/Fem
)

View File

@@ -20,8 +20,6 @@
# * *
# ***************************************************************************
import FreeCAD
__title__ = "FEM Analysis managment"
__author__ = "Juergen Riegel"
__url__ = "http://www.freecadweb.org"
@@ -29,6 +27,9 @@ __url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
def makeFemAnalysis(name):
'''makeFemAnalysis(name): makes a Fem Analysis object'''
obj = FreeCAD.ActiveDocument.addObject("Fem::FemAnalysisPython", name)

View File

@@ -24,12 +24,12 @@ __title__ = "FemBeamSection"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemBeamSection
## \addtogroup FEM
# @{
def makeFemBeamSection(width=20.0, height=20.0, name="BeamSection"):
'''makeFemBeamSection([width], [height], [name]): creates an beamsection object to define a cross section'''

View File

@@ -25,15 +25,15 @@ __title__ = "Fem Commands"
__author__ = "Przemo Firszt"
__url__ = "http://www.freecadweb.org"
import FreeCAD
## \addtogroup FEM
# @{
import FreeCAD
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore
## \addtogroup FEM
# @{
class FemCommands(object):
def __init__(self):

View File

@@ -24,12 +24,12 @@ __title__ = "FemConstraintSelfWeight"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemConstraintSelfWeight
## \addtogroup FEM
# @{
def makeFemConstraintSelfWeight(name="FemConstraintSelfWeight"):
'''makeFemFemConstraintSelfWeight([name]): creates an self weight object to define a gravity load'''

271
src/Mod/Fem/FemGmshTools.py Normal file
View File

@@ -0,0 +1,271 @@
# ***************************************************************************
# * *
# * 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__ = "Tools for the work with GMSH mesher"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import Fem
import subprocess
import tempfile
from platform import system
class FemGmshTools():
def __init__(self, gmsh_mesh_obj, analysis=None):
self.mesh_obj = gmsh_mesh_obj
if analysis:
self.analysis = analysis
# group meshing turned on
else:
self.analysis = None
# group meshing turned off
# part to mesh
self.part_obj = self.mesh_obj.Part
# clmax, ElementSizeMax: float, 0.0 = 1e+22
self.clmax = self.mesh_obj.ElementSizeMax
if self.clmax == 0.0:
self.clmax = 1e+22
# clmin, ElementSizeMin: float
self.clmin = self.mesh_obj.ElementSizeMin
# order, ElementOrder: ['Auto', '1st', '2nd']
self.order = self.mesh_obj.ElementOrder
if self.order == '1st':
self.order = '1'
elif self.order == 'Auto' or self.order == '2nd':
self.order = '2'
else:
print('Error in order')
# dimension, ElementDimension: ['Auto', '1D', '2D', '3D']
self.dimension = self.mesh_obj.ElementDimension
def create_mesh(self):
print("\nWe gone start GMSH FEM mesh run!")
print(' Part to mesh: Name --> ' + self.part_obj.Name + ', Label --> ' + self.part_obj.Label + ', ShapeType --> ' + self.part_obj.Shape.ShapeType)
print(' ElementSizeMax: ' + str(self.clmax))
print(' ElementSizeMin: ' + str(self.clmin))
print(' ElementOrder: ' + self.order)
self.get_dimension()
self.get_tmp_file_paths()
self.get_gmsh_command()
self.get_group_data()
self.write_part_file()
self.write_geo()
error = self.run_gmsh_with_geo()
self.read_and_set_new_mesh()
return error
def get_dimension(self):
# Dimension
# GMSH uses the hightest availabe.
# A use case for not auto would be a surface (2D) mesh of a solid or other 3d shape
if self.dimension == 'Auto':
shty = self.part_obj.Shape.ShapeType
if shty == 'Solid' or shty == 'CompSolid':
# print('Found: ' + shty)
self.dimension = '3'
elif shty == 'Face' or shty == 'Shell':
# print('Found: ' + shty)
self.dimension = '2'
elif shty == 'Edge' or shty == 'Wire':
# print('Found: ' + shty)
self.dimension = '1'
elif shty == 'Vertex':
# print('Found: ' + shty)
FreeCAD.Console.PrintError("You can not mesh a Vertex.\n")
self.dimension = '0'
elif shty == 'Compound':
print('Found: ' + shty)
print('I do not know what is inside your Compound. Dimension was set to 3 anyway.')
# TODO check contents of Compound
# use dimension 3 on any shape works for 2D and 1d meshes as well !
# but not in combination with sewfaces or connectfaces
self.dimension = '3'
else:
self.dimension = '0'
FreeCAD.Console.PrintError('Could not retrive Dimension from shape type. Please choose dimension.')
elif self.dimension == '3D':
self.dimension = '3'
elif self.dimension == '2D':
self.dimension = '2'
elif self.dimension == '1D':
self.dimension = '1'
else:
print('Error in dimension')
print(' ElementDimension: ' + self.dimension)
def get_tmp_file_paths(self):
if system() == "Linux":
path_sep = "/"
elif system() == "Windows":
path_sep = "\\"
else:
path_sep = "/"
tmpdir = tempfile.gettempdir()
# geometry file
self.temp_file_geometry = tmpdir + path_sep + self.part_obj.Name + '_Geometry.brep'
print(' ' + self.temp_file_geometry)
# mesh file
self.mesh_name = self.part_obj.Name + '_Mesh_TmpGmsh'
self.temp_file_mesh = tmpdir + path_sep + self.mesh_name + '.unv'
print(' ' + self.temp_file_mesh)
# GMSH input file
self.temp_file_geo = tmpdir + path_sep + 'shape2mesh.geo'
print(' ' + self.temp_file_geo)
def get_gmsh_command(self):
self.gmsh_bin = None
gmsh_std_location = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").GetBool("UseStandardGmshLocation")
if gmsh_std_location:
if system() == "Windows":
gmsh_path = FreeCAD.getHomePath() + "bin/gmsh.exe"
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").SetString("gmshBinaryPath", gmsh_path)
self.gmsh_bin = gmsh_path
elif system() == "Linux":
p1 = subprocess.Popen(['which', 'gmsh'], stdout=subprocess.PIPE)
if p1.wait() == 0:
gmsh_path = p1.stdout.read().split('\n')[0]
elif p1.wait() == 1:
error_message = "GMSH binary gmsh not found in standard system binary path. Please install gmsh or set path to binary in FEM preferences tab GMSH.\n"
# if FreeCAD.GuiUp:
# QtGui.QMessageBox.critical(None, "No GMSH binary ccx", error_message)
raise Exception(error_message)
self.gmsh_bin = gmsh_path
else:
if not self.gmsh_bin:
self.gmsh_bin = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").GetString("gmshBinaryPath", "")
if not self.gmsh_bin: # in prefs not set, we will try to use something reasonable
if system() == "Linux":
self.gmsh_bin = "gmsh"
elif system() == "Windows":
self.gmsh_bin = FreeCAD.getHomePath() + "bin/gmsh.exe"
else:
self.gmsh_bin = "gmsh"
self.gmsh_bin = self.gmsh_bin
print(' ' + self.gmsh_bin)
def get_group_data(self):
if self.analysis:
print(' Group meshing.')
import FemMeshTools
self.group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj)
print(self.group_elements)
else:
print(' NO group meshing.')
def write_part_file(self):
self.part_obj.Shape.exportBrep(self.temp_file_geometry)
def write_geo(self):
geo = open(self.temp_file_geo, "w")
geo.write('Merge "' + self.temp_file_geometry + '";\n')
geo.write("\n")
if self.analysis and self.group_elements:
print(' We gone have found elements to make mesh groups for!')
geo.write("// group data\n")
# we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH
for group in self.group_elements:
gdata = self.group_elements[group]
# print(gdata)
# geo.write("// " + group + "\n")
ele_nr = ''
if gdata[0].startswith('Solid'):
physical_type = 'Volume'
for ele in gdata:
ele_nr += (ele.lstrip('Solid') + ', ')
elif gdata[0].startswith('Face'):
physical_type = 'Surface'
for ele in gdata:
ele_nr += (ele.lstrip('Face') + ', ')
elif gdata[0].startswith('Edge') or gdata[0].startswith('Vertex'):
geo.write("// " + group + " group data not written. Edges or Vertexes group data not supported.\n")
print(' Groups for Edges or Vertexes reference shapes not handeled yet.')
if ele_nr:
ele_nr = ele_nr.rstrip(', ')
# print(ele_nr)
geo.write('Physical ' + physical_type + '("' + group + '") = {' + ele_nr + '};\n')
geo.write("\n")
geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n")
geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n")
geo.write("Mesh.ElementOrder = " + self.order + ";\n")
geo.write("//Mesh.HighOrderOptimize = 1;\n") # but does not really work, in GUI it does
geo.write("Mesh.Algorithm3D = 1;\n")
geo.write("Mesh.Algorithm = 2;\n")
geo.write("Mesh " + self.dimension + ";\n")
geo.write("Mesh.Format = 2;\n") # unv
if self.analysis and self.group_elements:
geo.write("// For each group save not only the elements but the nodes too.;\n")
geo.write("Mesh.SaveGroupsOfNodes = 1;\n")
geo.write("// Needed for Group meshing too, because for one material there is no group defined;\n") # belongs to Mesh.SaveAll but anly needed if there are groups
geo.write("// Ignore Physical definitions and save all elements;\n")
geo.write("Mesh.SaveAll = 1;\n")
geo.write("\n")
geo.write('Save "' + self.temp_file_mesh + '";\n')
geo.write("\n\n")
geo.write("//////////////////////////////////////////////////////////////////////\n")
geo.write("// GMSH documentation:\n")
geo.write("// http://gmsh.info/doc/texinfo/gmsh.html#Mesh\n")
geo.write("//\n")
geo.write("// We do not check if something went wrong, like negative jacobians etc. You can run GMSH manually yourself: \n")
geo.write("//\n")
geo.write("// to see full GMSH log, run in bash:\n")
geo.write("// " + self.gmsh_bin + " - " + self.temp_file_geo + "\n")
geo.write("//\n")
geo.write("// to run GMSH and keep file in GMSH GUI (with log), run in bash:\n")
geo.write("// " + self.gmsh_bin + " " + self.temp_file_geo + "\n")
geo.close
def run_gmsh_with_geo(self):
self.error = False
comandlist = [self.gmsh_bin, '-', self.temp_file_geo]
# print(comandlist)
try:
p = subprocess.Popen(comandlist, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = p.communicate()
# print(output) # stdout is still cut at some point but the warnings are in stderr and thus printed :-)
# print(error)
except:
error = 'Error executing: {}\n'.format(self.gmsh_command)
FreeCAD.Console.PrintError(error)
self.error = True
return error
def read_and_set_new_mesh(self):
if not self.error:
fem_mesh = Fem.read(self.temp_file_mesh)
self.mesh_obj.FemMesh = fem_mesh
print(' The Part should have a pretty new FEM mesh!')
else:
print('No mesh was created.')
del self.temp_file_geometry
del self.temp_file_mesh
# @}

View File

@@ -20,27 +20,17 @@
# * *
# ***************************************************************************
'''
- next step would be save the constraints node and element data in the in the FreeCAD FEM Mesh Object
and link them to the appropriate constraint object
- if the informations are used by the FEM Mesh file exporter FreeCAD would support writing FEM Mesh Groups
- which is a most needed feature of FEM module
- smesh supports mesh groups, how about pythonbinding in FreeCAD. Is there somethin implemented allready?
'''
__title__ = "FemInputWriter"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FemMeshTools
import os
## \addtogroup FEM
# @{
class FemInputWriter():
def __init__(self,
@@ -85,6 +75,7 @@ class FemInputWriter():
self.femnodes_mesh = {}
self.femelement_table = {}
self.constraint_conflict_nodes = []
self.femnodes_ele_table = {}
def get_constraints_fixed_nodes(self):
# get nodes
@@ -159,9 +150,25 @@ class FemInputWriter():
def get_constraints_pressure_faces(self):
# TODO see comments in get_constraints_force_nodeloads(), it applies here too. Mhh it applies to all constraints ...
'''
# depreciated version
# get the faces and face numbers
for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
femobj['PressureFaces'] = FemMeshTools.get_pressure_obj_faces(self.femmesh, femobj)
# print femobj['PressureFaces']
femobj['PressureFaces'] = FemMeshTools.get_pressure_obj_faces_depreciated(self.femmesh, femobj)
# print(femobj['PressureFaces'])
'''
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
if not self.femelement_table:
self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh)
if not self.femnodes_ele_table:
self.femnodes_ele_table = FemMeshTools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table)
for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object']
pressure_faces = FemMeshTools.get_pressure_obj_faces(self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj)
# print(len(pressure_faces))
femobj['PressureFaces'] = [(femobj['Object'].Name + ': face load', pressure_faces)]
# print(femobj['PressureFaces'])
# @}

View File

@@ -21,11 +21,12 @@
# * *
# ***************************************************************************
__title__ = "FemInputWriterCcx"
__author__ = "Przemo Firszt, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import os
@@ -34,8 +35,6 @@ import time
import FemMeshTools
import FemInputWriter
## \addtogroup FEM
# @{
class FemInputWriterCcx(FemInputWriter.FemInputWriter):
def __init__(self,
@@ -66,7 +65,7 @@ class FemInputWriterCcx(FemInputWriter.FemInputWriter):
print('FemInputWriterCcx --> self.file_name --> ' + self.file_name)
def write_calculix_input_file(self):
if self.solver_obj.SplitInputWriter == True:
if self.solver_obj.SplitInputWriter is True:
self.write_calculix_splitted_input_file()
else:
self.write_calculix_one_input_file()
@@ -974,7 +973,12 @@ class FemInputWriterCcx(FemInputWriter.FemInputWriter):
if all_found is False:
if not self.femelement_table:
self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh)
FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects)
# we gone use the binary search for get_femelements_by_femnodes(), thus we need the parameter values self.femnodes_ele_table
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
if not self.femnodes_ele_table:
self.femnodes_ele_table = FemMeshTools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table)
FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects, self.femnodes_ele_table)
for mat_data in self.material_objects:
mat_obj = mat_data['Object']
ccx_elset = {}

View File

@@ -20,19 +20,18 @@
# * *
# ***************************************************************************
__title__ = "FemInputWriterZ88"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FemMeshTools
import importZ88Mesh
import FemInputWriter
## \addtogroup FEM
# @{
class FemInputWriterZ88(FemInputWriter.FemInputWriter):
def __init__(self,

View File

@@ -24,13 +24,13 @@ __title__ = "FemMaterialMechanicalNonlinear"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FemGui
import _FemMaterialMechanicalNonlinear
## \addtogroup FEM
# @{
def makeFemMaterialMechanicalNonlinear(base_material, name="MechanicalMaterialNonlinear"):
'''makeFemMaterialMechanicalNonlinear(base_material, [name]): creates an nonlinear material object'''

View File

@@ -0,0 +1,43 @@
# ***************************************************************************
# * *
# * 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__ = "FemMeshGmsh"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemMeshGmsh
def makeFemMeshGmsh(name="FEMMeshGMSH"):
'''makeFemMeshGmsh(name): makes a GMSH FEM mesh object'''
obj = FreeCAD.ActiveDocument.addObject("Fem::FemMeshObjectPython", name)
_FemMeshGmsh._FemMeshGmsh(obj)
if FreeCAD.GuiUp:
import _ViewProviderFemMeshGmsh
_ViewProviderFemMeshGmsh._ViewProviderFemMeshGmsh(obj.ViewObject)
return obj
# @}

View File

@@ -20,35 +20,39 @@
# * *
# ***************************************************************************
__title__ = "Tools for the work with FEM meshes"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
## \addtogroup FEM
# @{
def get_femnodes_by_femobj_with_references(femmesh, femobj):
node_set = []
if femmesh.GroupCount:
node_set = get_femnode_set_from_group_data(femmesh, femobj)
# print 'node_set_group: ', node_set
# print('node_set_group: ', node_set)
if not node_set:
node_set = get_femnodes_by_references(femmesh, femobj['Object'].References)
# print 'node_set_nogroup: ', node_set
# print('node_set_nogroup: ', node_set)
return node_set
def get_femelements_by_references(femmesh, femelement_table, references):
def get_femelements_by_references(femmesh, femelement_table, references, femnodes_ele_table=None):
'''get the femelements for a list of references
'''
references_femelements = []
for ref in references:
ref_femnodes = get_femnodes_by_refshape(femmesh, ref) # femnodes for the current ref
references_femelements += get_femelements_by_femnodes(femelement_table, ref_femnodes) # femelements for all references
if femnodes_ele_table:
# blind fast binary search, works for volumes only
references_femelements += get_femelements_by_femnodes_bin(femelement_table, femnodes_ele_table, ref_femnodes) # femelements for all references
else:
# standars search
references_femelements += get_femelements_by_femnodes_std(femelement_table, ref_femnodes) # femelements for all references
return references_femelements
@@ -103,12 +107,160 @@ def get_femelement_table(femmesh):
return femelement_table
def get_femelements_by_femnodes(femelement_table, node_list):
def get_femnodes_ele_table(femnodes_mesh, femelement_table):
'''the femnodes_ele_table contains for each node its membership in elements
{nodeID : [[eleID, NodePosition], [], ...], nodeID : [[], [], ...], ...}
stored informatation are:
element number, the number of nodes per element, the position of the node in the element.
The position of the node in the element is coded as a set bit at that position in a bit array (integer)
Fixme: the number of nodes per element should be replaced by the type of the element
but I did not know, how to get this from the mesh.
Since the femelement_table contains either volume or face or edgemesh the femnodes_ele_table only
has either volume or face or edge elements, see get_femelement_table()
'''
femnodes_ele_table = {} # node_dict in ulrichs class
for n in femnodes_mesh: # initialize it with sorted node keys and empty lists
femnodes_ele_table[n] = []
for ele in femelement_table:
ele_list = femelement_table[ele]
# print(ele_list)
pos = int(1)
for ele_node in ele_list:
femnodes_ele_table[ele_node].append([ele, pos])
pos = pos << 1
print('len femnodes_ele_table:' + str(len(femnodes_ele_table)))
# print('femnodes_ele_table: ', femnodes_ele_table)
return femnodes_ele_table
def get_copy_of_empty_femelement_table(femelement_table):
'''{eleID : 0, eleID : 0, ...}
'''
empty_femelement_table = {}
for ele in femelement_table: # initialize it with sorted element keys and empty int
empty_femelement_table[ele] = 0
return empty_femelement_table.copy()
def get_bit_pattern_dict(femelement_table, femnodes_ele_table, node_set):
'''Now we are looking for nodes inside of the Faces = filling the bit_pattern_dict
{eleID : [lenEleNodes, binary_position]}
see forumpost for a ver good explanation whats really happening
http://forum.freecadweb.org/viewtopic.php?f=18&p=141133&sid=013c93f496a63872951d2ce521702ffa#p141108
The bit_pattern_dict holds later an integer (bit array) for each element, which gives us
the information we are searching for:
Is this element part of the node list (searching for elements) or has this element a face we are searching for?
The number in the ele_dict is organized as a bit array.
The corresponding bit is set, if the node of the node_set is contained in the element.
'''
print('len femnodes_ele_table:' + str(len(femnodes_ele_table)))
print('len node_set: ' + str(len(node_set)))
# print('node_set: ', node_set)
bit_pattern_dict = get_copy_of_empty_femelement_table(femelement_table)
# # initializing the bit_pattern_dict
for ele in femelement_table:
len_ele = len(femelement_table[ele])
bit_pattern_dict[ele] = [len_ele, 0]
for node in node_set:
for nList in femnodes_ele_table[node]:
bit_pattern_dict[nList[0]][1] += nList[1]
print('len bit_pattern_dict:' + str(len(bit_pattern_dict)))
# print('bit_pattern_dict: ', bit_pattern_dict)
return bit_pattern_dict
def get_ccxelement_faces_from_binary_search(bit_pattern_dict):
'''get the CalculiX element face numbers
'''
tet10_mask = {
119: 1,
411: 2,
717: 3,
814: 4}
tet4_mask = {
7: 1,
11: 2,
13: 3,
14: 4}
hex8_mask = {
240: 1,
15: 2,
102: 3,
204: 4,
153: 5,
51: 6}
hex20_mask = {
61680: 1,
3855: 2,
402022: 3,
804044: 4,
624793: 5,
201011: 6}
pent6_mask = {
56: 1,
7: 2,
54: 3,
45: 4,
27: 5}
pent15_mask = {
3640: 1,
455: 2,
25782: 3,
22829: 4,
12891: 5}
vol_dict = {
4: tet4_mask,
6: pent6_mask,
8: hex8_mask,
10: tet10_mask,
15: pent15_mask,
20: hex20_mask}
faces = []
for ele in bit_pattern_dict:
mask_dict = vol_dict[bit_pattern_dict[ele][0]]
for key in mask_dict:
if (key & bit_pattern_dict[ele][1]) == key:
faces.append([ele, mask_dict[key]])
print('found Faces: ', len(faces))
print('faces: ', faces)
return faces
def get_femelements_by_femnodes_bin(femelement_table, femnodes_ele_table, node_list):
'''for every femelement of femelement_table
if all nodes of the femelement are in node_list,
the femelement is added to the list which is returned
blind fast binary search, but workd for volumes only
'''
print('binary search: get_femelements_by_femnodes_bin')
vol_masks = {
4: 15,
6: 63,
8: 255,
10: 1023,
15: 32767,
20: 1048575}
# Now we are looking for nodes inside of the Volumes = filling the bit_pattern_dict
print('len femnodes_ele_table:' + str(len(femnodes_ele_table)))
bit_pattern_dict = get_bit_pattern_dict(femelement_table, femnodes_ele_table, node_list)
# search
ele_list = [] # The ele_list contains the result of the search.
for ele in bit_pattern_dict:
# print('bit_pattern_dict[ele][0]: ', bit_pattern_dict[ele][0])
if bit_pattern_dict[ele][1] == vol_masks[bit_pattern_dict[ele][0]]:
ele_list.append(ele)
print('found Volumes: ', len(ele_list))
print(' volumes: ', len(ele_list))
return ele_list
def get_femelements_by_femnodes_std(femelement_table, node_list):
'''for every femelement of femelement_table
if all nodes of the femelement are in node_list,
the femelement is added to the list which is returned
e: elementlist
nodes: nodelist '''
print('std search: get_femelements_by_femnodes_std')
e = [] # elementlist
for elementID in sorted(femelement_table):
nodecount = 0
@@ -172,11 +324,11 @@ def get_femvolumeelements_by_femfacenodes(femelement_table, node_list):
e.append(elementID)
else:
FreeCAD.Console.PrintError('Error in get_femvolumeelements_by_femfacenodes(): not known volume element: ' + el_nd_ct + '\n')
# print sorted(e)
# print(sorted(e))
return e
def get_femelement_sets(femmesh, femelement_table, fem_objects): # fem_objects = FreeCAD FEM document objects
def get_femelement_sets(femmesh, femelement_table, fem_objects, femnodes_ele_table=None): # fem_objects = FreeCAD FEM document objects
# get femelements for reference shapes of each obj.References
count_femelements = 0
referenced_femelements = []
@@ -186,7 +338,7 @@ def get_femelement_sets(femmesh, femelement_table, fem_objects): # fem_objects
fem_object['ShortName'] = get_elset_short_name(obj, fem_object_i) # unique short identifier
if obj.References:
ref_shape_femelements = []
ref_shape_femelements = get_femelements_by_references(femmesh, femelement_table, obj.References)
ref_shape_femelements = get_femelements_by_references(femmesh, femelement_table, obj.References, femnodes_ele_table)
referenced_femelements += ref_shape_femelements
count_femelements += len(ref_shape_femelements)
fem_object['FEMElements'] = ref_shape_femelements
@@ -213,10 +365,11 @@ def get_femnode_set_from_group_data(femmesh, fem_object):
# we assume the mesh group data fits with the reference shapes, no check is done in this regard !!!
# what happens if a reference shape was changed, but the mesh and the mesh groups were not created new !?!
obj = fem_object['Object']
group_nodes = None
if femmesh.GroupCount:
for g in femmesh.Groups:
grp_name = femmesh.getGroupName(g)
if grp_name.startswith(obj.Name + '_'):
if grp_name.startswith(obj.Name):
if femmesh.getGroupElementType(g) == "Node":
print("Constraint: " + obj.Name + " --> " + "mesh group: " + grp_name)
group_nodes = femmesh.getGroupElements(g) # == ref_shape_femelements
@@ -235,7 +388,7 @@ def get_femelement_sets_from_group_data(femmesh, fem_objects):
if femmesh.GroupCount:
for g in femmesh.Groups:
grp_name = femmesh.getGroupName(g)
if grp_name.startswith(obj.Name + '_'):
if grp_name.startswith(obj.Name):
if femmesh.getGroupElementType(g) == "Volume":
print("Constraint: " + obj.Name + " --> " + "mesh group: " + grp_name)
group_elements = femmesh.getGroupElements(g) # == ref_shape_femelements
@@ -372,7 +525,7 @@ def get_force_obj_edge_nodeload_table(femmesh, femelement_table, femnodes_mesh,
return force_obj_node_load_table
def get_pressure_obj_faces(femmesh, femobj):
def get_pressure_obj_faces_depreciated(femmesh, femobj):
pressure_faces = []
for o, elem_tup in femobj['Object'].References:
for elem in elem_tup:
@@ -384,6 +537,16 @@ def get_pressure_obj_faces(femmesh, femobj):
return pressure_faces
def get_pressure_obj_faces(femmesh, femelement_table, femnodes_ele_table, femobj):
# get the nodes
prs_face_node_set = get_femnodes_by_femobj_with_references(femmesh, femobj) # sorted and duplicates removed
# print('prs_face_node_set: ', prs_face_node_set)
# fill the bit_pattern_dict and search for the faces
bit_pattern_dict = get_bit_pattern_dict(femelement_table, femnodes_ele_table, prs_face_node_set)
pressure_faces = get_ccxelement_faces_from_binary_search(bit_pattern_dict)
return pressure_faces
def get_force_obj_face_nodeload_table(femmesh, femelement_table, femnodes_mesh, frc_obj):
# force_obj_node_load_table = [('refshape_name.elemname',node_load_table), ..., ('refshape_name.elemname',node_load_table)]
force_obj_node_load_table = []
@@ -483,7 +646,7 @@ def get_ref_edgenodes_table(femmesh, femelement_table, refedge):
# FIXME duplicate_mesh_elements: as soon as contact ans springs are supported the user should decide on which edge the load is applied
edge_table = delete_duplicate_mesh_elements(edge_table)
elif is_edge_femmesh(femmesh):
refedge_fem_edgeelements = get_femelements_by_femnodes(femelement_table, refedge_nodes)
refedge_fem_edgeelements = get_femelements_by_femnodes_std(femelement_table, refedge_nodes)
for elem in refedge_fem_edgeelements:
edge_table[elem] = femelement_table[elem] # { edgeID : ( nodeID, ... , nodeID )} # all nodes off this femedgeelement
return edge_table
@@ -571,10 +734,10 @@ def get_ref_facenodes_table(femmesh, femelement_table, ref_face):
face_table[mf] = femmesh.getElementNodes(mf)
elif is_face_femmesh(femmesh):
ref_face_nodes = femmesh.getNodesByFace(ref_face)
ref_face_elements = get_femelements_by_femnodes(femelement_table, ref_face_nodes)
ref_face_elements = get_femelements_by_femnodes_std(femelement_table, ref_face_nodes)
for mf in ref_face_elements:
face_table[mf] = femelement_table[mf]
# print face_table
# print(face_table)
return face_table
@@ -588,10 +751,10 @@ def build_mesh_faces_of_volume_elements(face_table, femelement_table):
index = femelement_table[veID].index(n)
# print(index)
face_nodenumber_table[veID].append(index + 1) # lokale node number = index + 1
# print 'VolElement:', veID
# print ' --> ', femelement_table[veID]
# print ' --> ', face_table[veID]
# print ' --> ', face_nodenumber_table[veID]
# print('VolElement:', veID)
# print(' --> ', femelement_table[veID])
# print(' --> ', face_table[veID])
# print(' --> ', face_nodenumber_table[veID])
for veID in face_nodenumber_table:
vol_node_ct = len(femelement_table[veID])
face_node_indexs = sorted(face_nodenumber_table[veID])
@@ -681,7 +844,7 @@ def build_mesh_faces_of_volume_elements(face_table, femelement_table):
i -= 1 # node_number starts with 1, index starts with 0 --> index = node number - 1
face_nodes.append(femelement_table[veID][i])
face_table[veID] = face_nodes # reset the entry in face_table
# print ' --> ', face_table[veID]
# print(' --> ', face_table[veID])
return face_table
@@ -840,13 +1003,13 @@ def get_analysis_group_elements(aAnalysis, aPart):
{ConstraintName : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...}
'''
aShape = aPart.Shape
group_elements = {}
group_elements = {} # { name : [element, element, ... , element]}
empty_references = []
for m in aAnalysis.Member:
if hasattr(m, "References"):
# print(m.Name)
key = m.Name
indexes = []
elements = []
stype = None
if m.References:
for r in m.References:
@@ -868,117 +1031,134 @@ def get_analysis_group_elements(aAnalysis, aPart):
# print(ref_shape)
found_element = find_element_in_shape(aShape, ref_shape)
if found_element is not None:
indexes.append(found_element)
elements.append(found_element)
else:
FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n')
print(' ' + m.Name)
print(' ' + str(m.References))
print(' ' + r[0].Name)
group_elements[key] = [stype, sorted(indexes)]
group_elements[key] = sorted(elements)
else:
print('Empty reference: ' + m.Name)
print(' Empty reference: ' + m.Name)
empty_references.append(m)
if empty_references:
if len(empty_references) == 1:
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape)
else:
FreeCAD.Console.PrintError('Error: more than one object with empty references!\n')
print(empty_references)
FreeCAD.Console.PrintError('Problem: more than one object with empty references.\n')
print('We gone try to get the empty material references anyway.\n')
# ShellThickness and BeamSection could have empty references, but on solid meshes only materials should have empty references
for er in empty_references:
print(er.Name)
group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape)
# check if all groups have elements:
for g in group_elements:
# print group_elements[g][1]
if len(group_elements[g][1]) == 0:
# print(group_elements[g])
if len(group_elements[g]) == 0:
FreeCAD.Console.PrintError('Error: shapes for: ' + g + 'not found!\n')
return group_elements
def get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape):
'''get the elementIDs if the Reference shape is empty
see get_analysis_group_elements()
see get_analysis_group_elements() for more informatations
on solid meshes only material objects could have an empty reference without beeing something wrong!
face meshes could have empty ShellThickness and edge meshes could have empty BeamSection
'''
# print(group_elements)
material_ref_shapes = []
material_shape_type = ''
missed_material_refshapes = []
empty_reference_material = None
for m in aAnalysis.Member:
# only materials could have an empty reference without beeing something wrong!
if m.isDerivedFrom("App::MaterialObjectPython"):
if hasattr(m, "References") and m.References:
if not material_shape_type:
material_shape_type = group_elements[m.Name][0]
elif material_shape_type != group_elements[m.Name][0]:
print('Problem, material shape type does not match get_anlysis_empty_references_group_elements')
for i in group_elements[m.Name][1]:
material_ref_shapes.append(i)
elif hasattr(m, "References") and not m.References:
if hasattr(m, "References") and not m.References:
if not empty_reference_material:
empty_reference_material = m.Name
else:
print('Problem in get_anlysis_empty_references_group_elements, we seams to have two materials with empty referneces')
FreeCAD.Console.PrintError('Problem in get_anlysis_empty_references_group_elements, we seams to have two or more materials with empty referneces')
return {}
elif hasattr(m, "References") and m.References:
# ShapeType ot the group elements, strip the number of the first group element
# http://stackoverflow.com/questions/12851791/removing-numbers-from-string
group_shape_type = ''.join(i for i in group_elements[m.Name][0] if not i.isdigit())
if not material_shape_type:
material_shape_type = group_shape_type
elif material_shape_type != group_shape_type:
FreeCAD.Console.PrintError('Problem, material shape type does not match get_anlysis_empty_references_group_elements')
for ele in group_elements[m.Name]:
material_ref_shapes.append(ele)
if material_shape_type == 'Solid':
# print(len(aShape.Solids))
for i in range(len(aShape.Solids)):
if i not in material_ref_shapes:
missed_material_refshapes.append(i)
ele = 'Solid' + str(i + 1)
if ele not in material_ref_shapes:
missed_material_refshapes.append(ele)
elif material_shape_type == 'Face':
# print(len(aShape.Faces))
for i in range(len(aShape.Faces)):
if i not in material_ref_shapes:
missed_material_refshapes.append(i)
ele = 'Face' + str(i + 1)
if ele not in material_ref_shapes:
missed_material_refshapes.append(ele)
elif material_shape_type == 'Edge':
# print(len(aShape.Edges))
for i in range(len(aShape.Edges)):
if i not in material_ref_shapes:
missed_material_refshapes.append(i)
ele = 'Edge' + str(i + 1)
if ele not in material_ref_shapes:
missed_material_refshapes.append(ele)
else:
print('It seams we only have one material with no reference shapes. Means the whole solid is one material. Since we only support material groups for Solids at the moment this should be Solid')
material_shape_type = 'Solid'
missed_material_refshapes.append(0)
print(' One material with no reference shapes. No need to make a group for materials.')
# make no changes group_elements
return group_elements
# print(sorted(material_ref_shapes))
# print(sorted(missed_material_refshapes))
# print(group_elements)
group_elements[empty_reference_material] = [material_shape_type, sorted(missed_material_refshapes)]
group_elements[empty_reference_material] = sorted(missed_material_refshapes)
# print(group_elements)
return group_elements
def find_element_in_shape(aShape, anElement):
# import Part
if anElement.ShapeType == 'Solid' or anElement.ShapeType == 'CompSolid':
ele_st = anElement.ShapeType
if ele_st == 'Solid' or ele_st == 'CompSolid':
for index, solid in enumerate(aShape.Solids):
# print(is_same_geometry(solid, anElement))
if is_same_geometry(solid, anElement):
# print(index)
# Part.show(aShape.Solids[index])
return index
ele = ele_st + str(index + 1)
return ele
FreeCAD.Console.PrintError('Solid ' + str(anElement) + ' not found in: ' + str(aShape) + '\n')
if anElement.ShapeType == 'Solid' and aShape.ShapeType == 'Solid':
if ele_st == 'Solid' and aShape.ShapeType == 'Solid':
print('We have been searching for a Solid in a Solid and we have not found it. In most cases this should be searching for a Solid inside a CompSolid. Check the ShapeType of your Part to mesh.')
# Part.show(anElement)
# Part.show(aShape)
elif anElement.ShapeType == 'Face' or anElement.ShapeType == 'Shell':
elif ele_st == 'Face' or ele_st == 'Shell':
for index, face in enumerate(aShape.Faces):
# print(is_same_geometry(face, anElement))
if is_same_geometry(face, anElement):
# print(index)
# Part.show(aShape.Faces[index])
return index
elif anElement.ShapeType == 'Edge' or anElement.ShapeType == 'Wire':
for index, face in enumerate(aShape.Edges):
# print(is_same_geometry(face, anElement))
if is_same_geometry(face, anElement):
ele = ele_st + str(index + 1)
return ele
elif ele_st == 'Edge' or ele_st == 'Wire':
for index, edge in enumerate(aShape.Edges):
# print(is_same_geometry(edge, anElement))
if is_same_geometry(edge, anElement):
# print(index)
# Part.show(aShape.Edges[index])
return index
elif anElement.ShapeType == 'Vertex':
for index, face in enumerate(aShape.Vertexes):
# print(is_same_geometry(face, anElement))
if is_same_geometry(face, anElement):
ele = ele_st + str(index + 1)
return ele
elif ele_st == 'Vertex':
for index, vertex in enumerate(aShape.Vertexes):
# print(is_same_geometry(vertex, anElement))
if is_same_geometry(vertex, anElement):
# print(index)
# Part.show(aShape.Vertexes[index])
return index
elif anElement.ShapeType == 'Compound':
ele = ele_st + str(index + 1)
return ele
elif ele_st == 'Compound':
FreeCAD.Console.PrintError('Compound is not supported.\n')

View File

@@ -24,12 +24,12 @@ __title__ = "Selection Observer"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FreeCADGui
## \addtogroup FEM
# @{
class FemSelectionObserver:
'''FemSelectionObserver'''

View File

@@ -24,12 +24,12 @@ __title__ = "FemShellThickness"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemShellThickness
## \addtogroup FEM
# @{
def makeFemShellThickness(thickness=20.0, name="ShellThickness"):
'''makeFemShellThickness([thickness], [name]): creates an shellthickness object to define a plate thickness'''

View File

@@ -24,12 +24,12 @@ __title__ = "FemSolverCalculix"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemSolverCalculix
## \addtogroup FEM
# @{
def makeFemSolverCalculix(name="CalculiX"):
'''makeSolverCalculix(name): makes a Calculix solver object'''

View File

@@ -24,12 +24,12 @@ __title__ = "FemSolverZ88"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _FemSolverZ88
## \addtogroup FEM
# @{
def makeFemSolverZ88(name="Z88"):
'''makeSolverZ88(name): makes a Z88 solver object'''

View File

@@ -21,17 +21,16 @@
# * *
# ***************************************************************************
__title__ = "Fem Tools super class"
__author__ = "Przemo Firszt, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
from PySide import QtCore
## \addtogroup FEM
# @{
class FemTools(QtCore.QRunnable, QtCore.QObject):
## The constructor

View File

@@ -21,11 +21,12 @@
# * *
# ***************************************************************************
__title__ = "FemToolsCcx"
__author__ = "Przemo Firszt, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FemTools
@@ -33,8 +34,6 @@ from PySide import QtCore
if FreeCAD.GuiUp:
from PySide import QtGui
## \addtogroup FEM
# @{
class FemToolsCcx(FemTools.FemTools):
@@ -242,6 +241,9 @@ class FemToolsCcx(FemTools.FemTools):
for m in self.analysis.Member:
if m.isDerivedFrom("Fem::FemResultObject"):
self.results_present = True
break
else:
FreeCAD.Console.PrintError('FEM: No result object in active Analysis.\n')
else:
raise Exception('FEM: No results found at {}!'.format(frd_result_file))
@@ -256,7 +258,7 @@ class FemToolsCcx(FemTools.FemTools):
else:
raise Exception('FEM: No .dat results found at {}!'.format(dat_result_file))
if mode_frequencies:
print(mode_frequencies)
# print(mode_frequencies)
for m in self.analysis.Member:
if m.isDerivedFrom("Fem::FemResultObject") and m.Eigenmode > 0:
for mf in mode_frequencies:

View File

@@ -20,19 +20,18 @@
# * *
# ***************************************************************************
__title__ = "FemToolsZ88"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import FemTools
from PySide import QtCore
from PySide.QtGui import QApplication
## \addtogroup FEM
# @{
class FemToolsZ88(FemTools.FemTools):
@@ -110,8 +109,7 @@ class FemToolsZ88(FemTools.FemTools):
self.z88_binary = z88_path
else:
if not z88_binary:
self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Z88")
z88_binary = self.fem_prefs.GetString("z88BinaryPath", "")
z88_binary = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Z88").GetString("z88BinaryPath", "")
if not z88_binary:
if system() == "Linux":
z88_binary = "z88r"

View File

@@ -35,6 +35,7 @@
#include "PropertyFemMeshItem.h"
#include "DlgSettingsFemGeneralImp.h"
#include "DlgSettingsFemCcxImp.h"
#include "DlgSettingsFemGmshImp.h"
#include "DlgSettingsFemZ88Imp.h"
#include "ViewProviderFemMesh.h"
#include "ViewProviderFemMeshShape.h"
@@ -109,6 +110,7 @@ PyMODINIT_FUNC initFemGui()
FemGui::ViewProviderFemAnalysis ::init();
FemGui::ViewProviderFemAnalysisPython ::init();
FemGui::ViewProviderFemMesh ::init();
FemGui::ViewProviderFemMeshPython ::init();
FemGui::ViewProviderFemMeshShape ::init();
FemGui::ViewProviderFemMeshShapeNetgen ::init();
FemGui::ViewProviderSolver ::init();
@@ -153,6 +155,7 @@ PyMODINIT_FUNC initFemGui()
// register preferences pages
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGeneralImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemCcxImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGmshImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
new Gui::PrefPageProducer<FemGui::DlgSettingsFemZ88Imp> (QT_TRANSLATE_NOOP("QObject","FEM"));
// add resources and reloads the translators

View File

@@ -44,6 +44,7 @@ SOURCE_GROUP("Python" FILES ${Python_SRCS})
set(FemGui_MOC_HDRS
DlgSettingsFemCcxImp.h
DlgSettingsFemGeneralImp.h
DlgSettingsFemGmshImp.h
DlgSettingsFemZ88Imp.h
PropertyFemMeshItem.h
TaskObjectName.h
@@ -83,6 +84,7 @@ SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS})
set(FemGui_UIC_SRCS
DlgSettingsFemCcx.ui
DlgSettingsFemGeneral.ui
DlgSettingsFemGmsh.ui
DlgSettingsFemZ88.ui
TaskCreateNodeSet.ui
TaskObjectName.ui
@@ -125,6 +127,9 @@ SET(FemGui_DLG_SRCS
DlgSettingsFemGeneral.ui
DlgSettingsFemGeneralImp.cpp
DlgSettingsFemGeneralImp.h
DlgSettingsFemGmsh.ui
DlgSettingsFemGmshImp.cpp
DlgSettingsFemGmshImp.h
DlgSettingsFemZ88.ui
DlgSettingsFemZ88Imp.cpp
DlgSettingsFemZ88Imp.h

View File

@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FemGui::DlgSettingsFemGmshImp</class>
<widget class="QWidget" name="FemGui::DlgSettingsFemGmshImp">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>372</width>
<height>144</height>
</rect>
</property>
<property name="windowTitle">
<string>GMSH</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="gb_gmsh_param">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="title">
<string>GMSH</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<layout class="QGridLayout" name="gl_01">
<item row="0" column="2">
<widget class="Gui::PrefCheckBox" name="cb_gmsh_binary_std">
<property name="text">
<string>Use standard gmsh binary path</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseStandardGmshLocation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Gmsh</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="l_gmsh_binary_std">
<property name="text">
<string>GMSH binary</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="l_gmsh_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>gmsh binary path</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="Gui::PrefFileChooser" name="fc_gmsh_binary_path" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Leave blank to use default gmsh binary file</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>gmshBinaryPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Gmsh</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::FileChooser</class>
<extends>QWidget</extends>
<header>Gui/FileDialog.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefFileChooser</class>
<extends>Gui::FileChooser</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources/Fem.qrc"/>
</resources>
<connections>
<connection>
<sender>cb_gmsh_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>l_gmsh_binary_path</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>406</x>
<y>45</y>
</hint>
<hint type="destinationlabel">
<x>148</x>
<y>68</y>
</hint>
</hints>
</connection>
<connection>
<sender>cb_gmsh_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>fc_gmsh_binary_path</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>406</x>
<y>45</y>
</hint>
<hint type="destinationlabel">
<x>406</x>
<y>68</y>
</hint>
</hints>
</connection>
<connection>
<sender>cb_gmsh_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>l_gmsh_binary_path</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>406</x>
<y>45</y>
</hint>
<hint type="destinationlabel">
<x>148</x>
<y>68</y>
</hint>
</hints>
</connection>
<connection>
<sender>cb_gmsh_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>fc_gmsh_binary_path</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>406</x>
<y>45</y>
</hint>
<hint type="destinationlabel">
<x>406</x>
<y>68</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (c) 2016 FreeCAD Developers *
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
* Based on src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#include "Gui/Application.h"
#include "DlgSettingsFemGmshImp.h"
#include <Gui/PrefWidgets.h>
using namespace FemGui;
DlgSettingsFemGmshImp::DlgSettingsFemGmshImp( QWidget* parent )
: PreferencePage( parent )
{
this->setupUi(this);
}
DlgSettingsFemGmshImp::~DlgSettingsFemGmshImp()
{
// no need to delete child widgets, Qt does it all for us
}
void DlgSettingsFemGmshImp::saveSettings()
{
cb_gmsh_binary_std->onSave();
fc_gmsh_binary_path->onSave();
}
void DlgSettingsFemGmshImp::loadSettings()
{
cb_gmsh_binary_std->onRestore();
fc_gmsh_binary_path->onRestore();
}
/**
* Sets the strings of the subwidgets using the current language.
*/
void DlgSettingsFemGmshImp::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
}
else {
QWidget::changeEvent(e);
}
}
#include "moc_DlgSettingsFemGmshImp.cpp"

View File

@@ -0,0 +1,50 @@
/**************************************************************************
* Copyright (c) 2016 FreeCAD Developers *
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
* Based on src/Mod/Fem/Gui/DlgSettingsFemCcx.h *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef FEMGUI_DLGSETTINGSFEMGMSHIMP_H
#define FEMGUI_DLGSETTINGSFEMGMSHIMP_H
#include "ui_DlgSettingsFemGmsh.h"
#include <Gui/PropertyPage.h>
namespace FemGui {
class DlgSettingsFemGmshImp : public Gui::Dialog::PreferencePage, public Ui_DlgSettingsFemGmshImp
{
Q_OBJECT
public:
DlgSettingsFemGmshImp( QWidget* parent = 0 );
~DlgSettingsFemGmshImp();
protected:
void saveSettings();
void loadSettings();
void changeEvent(QEvent *e);
};
} // namespace FemGui
#endif // FEMGUI_DLGSETTINGSFEMGMSHIMP_H

View File

@@ -1,6 +1,8 @@
<RCC>
<qresource>
<file>icons/fem-fem-mesh-from-shape.svg</file>
<file>icons/fem-fem-mesh-gmsh-from-shape.svg</file>
<file>icons/fem-fem-mesh-netgen-from-shape.svg</file>
<file>icons/fem-fem-mesh-create-node-by-poly.svg</file>
<file>icons/fem-analysis.svg</file>
<file>icons/fem-cfd-analysis.svg</file>

View File

@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2860"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
sodipodi:docname="fem-fem-mesh-gmsh-from-shape.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2862">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3692"
cx="45.883327"
cy="28.869568"
fx="45.883327"
fy="28.869568"
r="19.467436"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3703"
gradientUnits="userSpaceOnUse"
cx="135.38333"
cy="97.369568"
fx="135.38333"
fy="97.369568"
r="19.467436"
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)" />
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3705"
gradientUnits="userSpaceOnUse"
cx="148.88333"
cy="81.869568"
fx="148.88333"
fy="81.869568"
r="19.467436"
gradientTransform="matrix(1.3852588,-5.1367833e-2,3.7056289e-2,0.9993132,-60.392403,7.7040438)" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2868" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.556349"
inkscape:cx="46.201605"
inkscape:cy="36.413493"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="2560"
inkscape:window-height="1392"
inkscape:window-x="-2"
inkscape:window-y="25"
inkscape:window-maximized="1" />
<metadata
id="metadata2865">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3618"
transform="translate(-129.7515,-68.681262)">
<path
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.07586193;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 164.25407,125.89934 L 185.75844,120.53301 L 191.3165,115.1667 L 181.45756,113.73568 L 164.25407,125.89934 z"
id="path3546" />
<path
style="opacity:1;fill:url(#radialGradient3705);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 152.88222,77.612314 L 133.06781,84.791524 L 163.56337,88.940395 L 163.98885,124.71349 L 180.09861,114.12316 L 180.67448,79.738312 L 152.88222,77.612314 z"
id="rect3522"
sodipodi:nodetypes="ccccccc" />
<path
style="opacity:1;fill:url(#radialGradient3703);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 133.33785,84.998317 L 164.04669,88.363932 L 164.04669,124.84112 L 132.92286,119.77634 L 133.33785,84.998317 z"
id="rect3520"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:1;fill:url(#radialGradient3692);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 163.81279,88.408895 L 180.53877,80.000095"
id="path3536" />
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10.545455,17.272727 L 9.6363636,52"
id="path2390" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 18.545455,18 C 18.545455,18.060606 18.545455,18.121212 18.545455,18 z"
id="path2392" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 16,53.454545 C 16.060606,53.454545 16.121212,53.454545 16,53.454545 z"
id="path2394" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 19.090909,53.818182 L 20,18.909091"
id="path2398"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 28.545455,19.272727 L 27.454545,55.454545"
id="path2400" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10.727273,17.090909 C 10.969697,17.090909 10.969697,17.090909 10.727273,17.090909 z"
id="path2402" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 28.545455,8.7272727 C 28.545455,8.7878788 28.545455,8.8484848 28.545455,8.7272727 z"
id="path2404" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 27.636364,9.0909091 C 27.575758,9.0909091 27.515152,9.0909091 27.636364,9.0909091 z"
id="path2406" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 29.090909,9.6363637 C 28.839485,9.9151131 11.048018,15.903965 10.727273,16.545455"
id="path2408"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 37,10.181818 C 36.748576,10.460567 20.048018,17.722146 20.636364,18.181818"
id="path2410"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 45.28032,10.909091 C 45.028896,11.18784 28.328338,18.449419 28.916684,18.909091"
id="path2412"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 52.007593,18.727273 C 51.756169,19.006022 35.055611,26.267601 35.643957,26.727273"
id="path2414"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 52.007593,26.727273 C 51.756169,27.006022 35.055611,34.267601 35.643957,34.727273"
id="path2416"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 51.28032,34.727273 C 51.028896,35.006022 34.328338,42.267601 34.916684,42.727273"
id="path2418"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 50.734866,41.636364 C 50.483442,41.915113 33.782884,49.176692 34.37123,49.636364"
id="path2420"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 3.8181818,23.636364 C 4.0606061,23.636364 4.0606061,23.636364 3.8181818,23.636364 z"
id="path2422" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 3.6363636,23.636364 L 34.545455,26.909091"
id="path2424" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34,34.909091 L 3.8181818,31.454545"
id="path2426" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34.181818,43.454545 L 2.9090909,40.181818"
id="path2432" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34,49.818182 L 3.4545455,46.545455"
id="path2434" />
<text
xml:space="preserve"
style="font-size:39.81731415px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:condensed;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Comfortaa;-inkscape-font-specification:Comfortaa Light Condensed"
x="30.467127"
y="34.934822"
id="text3014-3"
sodipodi:linespacing="125%"
inkscape:transform-center-x="22.121859"
inkscape:transform-center-y="-23.950112"><tspan
sodipodi:role="line"
id="tspan3016-6"
x="30.467127"
y="34.934822"
style="font-size:56px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">G</tspan></text>
<text
xml:space="preserve"
style="font-size:39.81731415px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:condensed;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Comfortaa;-inkscape-font-specification:Comfortaa Light Condensed"
x="31.865446"
y="33.462196"
id="text3014"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3016"
x="31.865446"
y="33.462196"
style="font-size:56px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">G</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2860"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
sodipodi:docname="fem-fem-mesh-netgen-from-shape.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2862">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3692"
cx="45.883327"
cy="28.869568"
fx="45.883327"
fy="28.869568"
r="19.467436"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3703"
gradientUnits="userSpaceOnUse"
cx="135.38333"
cy="97.369568"
fx="135.38333"
fy="97.369568"
r="19.467436"
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)" />
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#faff2b;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#ffaa00;stop-opacity:1;" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3377"
id="radialGradient3705"
gradientUnits="userSpaceOnUse"
cx="148.88333"
cy="81.869568"
fx="148.88333"
fy="81.869568"
r="19.467436"
gradientTransform="matrix(1.3852588,-5.1367833e-2,3.7056289e-2,0.9993132,-60.392403,7.7040438)" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2868" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="9.7619234"
inkscape:cy="40.839396"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1280"
inkscape:window-height="1115"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="0" />
<metadata
id="metadata2865">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3618"
transform="translate(-129.7515,-68.681262)">
<path
style="opacity:0.66523605;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.07586193;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 164.25407,125.89934 L 185.75844,120.53301 L 191.3165,115.1667 L 181.45756,113.73568 L 164.25407,125.89934 z"
id="path3546" />
<path
style="opacity:1;fill:url(#radialGradient3705);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 152.88222,77.612314 L 133.06781,84.791524 L 163.56337,88.940395 L 163.98885,124.71349 L 180.09861,114.12316 L 180.67448,79.738312 L 152.88222,77.612314 z"
id="rect3522"
sodipodi:nodetypes="ccccccc" />
<path
style="opacity:1;fill:url(#radialGradient3703);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 133.33785,84.998317 L 164.04669,88.363932 L 164.04669,124.84112 L 132.92286,119.77634 L 133.33785,84.998317 z"
id="rect3520"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:1;fill:url(#radialGradient3692);fill-opacity:1;fill-rule:evenodd;stroke:#7b5600;stroke-width:2.20000005;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 163.81279,88.408895 L 180.53877,80.000095"
id="path3536" />
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10.545455,17.272727 L 9.6363636,52"
id="path2390" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 18.545455,18 C 18.545455,18.060606 18.545455,18.121212 18.545455,18 z"
id="path2392" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 16,53.454545 C 16.060606,53.454545 16.121212,53.454545 16,53.454545 z"
id="path2394" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 19.090909,53.818182 L 20,18.909091"
id="path2398"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 28.545455,19.272727 L 27.454545,55.454545"
id="path2400" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 10.727273,17.090909 C 10.969697,17.090909 10.969697,17.090909 10.727273,17.090909 z"
id="path2402" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 28.545455,8.7272727 C 28.545455,8.7878788 28.545455,8.8484848 28.545455,8.7272727 z"
id="path2404" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 27.636364,9.0909091 C 27.575758,9.0909091 27.515152,9.0909091 27.636364,9.0909091 z"
id="path2406" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 29.090909,9.6363637 C 28.839485,9.9151131 11.048018,15.903965 10.727273,16.545455"
id="path2408"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 37,10.181818 C 36.748576,10.460567 20.048018,17.722146 20.636364,18.181818"
id="path2410"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 45.28032,10.909091 C 45.028896,11.18784 28.328338,18.449419 28.916684,18.909091"
id="path2412"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 52.007593,18.727273 C 51.756169,19.006022 35.055611,26.267601 35.643957,26.727273"
id="path2414"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 52.007593,26.727273 C 51.756169,27.006022 35.055611,34.267601 35.643957,34.727273"
id="path2416"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 51.28032,34.727273 C 51.028896,35.006022 34.328338,42.267601 34.916684,42.727273"
id="path2418"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 50.734866,41.636364 C 50.483442,41.915113 33.782884,49.176692 34.37123,49.636364"
id="path2420"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 3.8181818,23.636364 C 4.0606061,23.636364 4.0606061,23.636364 3.8181818,23.636364 z"
id="path2422" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 3.6363636,23.636364 L 34.545455,26.909091"
id="path2424" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34,34.909091 L 3.8181818,31.454545"
id="path2426" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34.181818,43.454545 L 2.9090909,40.181818"
id="path2432" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 34,49.818182 L 3.4545455,46.545455"
id="path2434" />
<text
xml:space="preserve"
style="font-size:21.4082737px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:condensed;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Comfortaa;-inkscape-font-specification:Comfortaa Light Condensed"
x="30.022514"
y="34.590149"
id="text3014-3"
sodipodi:linespacing="125%"
inkscape:transform-center-x="11.894093"
inkscape:transform-center-y="-12.877075"><tspan
sodipodi:role="line"
id="tspan3016-6"
x="30.022514"
y="34.590149"
style="font-size:56px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">N</tspan></text>
<text
xml:space="preserve"
style="font-size:21.4082737px;font-style:normal;font-variant:normal;font-weight:300;font-stretch:condensed;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Comfortaa;-inkscape-font-specification:Comfortaa Light Condensed"
x="32.172535"
y="32.538422"
id="text3014"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3016"
x="32.172535"
y="32.538422"
style="font-size:56px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">N</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -2464,3 +2464,15 @@ void ViewProviderFEMMeshBuilder::createMesh(const App::Property* prop,
}
// Python feature -----------------------------------------------------------------------
namespace Gui {
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(FemGui::ViewProviderFemMeshPython, FemGui::ViewProviderFemMesh)
/// @endcond
// explicit template instantiation
template class FemGuiExport ViewProviderPythonFeatureT<ViewProviderFemMesh>;
}

View File

@@ -26,6 +26,7 @@
#include <Gui/ViewProviderGeometryObject.h>
#include <Gui/ViewProviderBuilder.h>
#include <Gui/ViewProviderPythonFeature.h>
#include <CXX/Objects.hxx>
@@ -163,6 +164,9 @@ private:
class Private;
};
typedef Gui::ViewProviderPythonFeatureT<ViewProviderFemMesh> ViewProviderFemMeshPython;
} //namespace FemGui

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="ViewProviderPy"
Father="ViewProviderDocumentObjectPy"
Name="ViewProviderFemMeshPy"
Twin="ViewProviderFemMesh"
TwinPointer="ViewProviderFemMesh"
Include="Mod/Fem/Gui/ViewProviderFemMesh.h"
Namespace="FemGui"
FatherInclude="Gui/ViewProviderPy.h"
FatherInclude="Gui/ViewProviderDocumentObjectPy.h"
FatherNamespace="Gui"
Constructor="false"
Delete="false">

View File

@@ -58,13 +58,14 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
*fem << "Fem_Analysis"
<< "Fem_SolverCalculix"
// << "Fem_SolverZ88"
<< "Fem_MeshFromShape"
<< "Fem_MeshNetgenFromShape"
<< "Fem_MeshGmshFromShape"
<< "Fem_MechanicalMaterial"
<< "Fem_MaterialMechanicalNonlinear"
<< "Fem_BeamSection"
<< "Fem_ShellThickness"
<< "Separator"
<< "Fem_CreateNodesSet"
//<< "Fem_CreateNodesSet"
<< "Separator"
<< "Fem_ConstraintFixed"
<< "Fem_ConstraintDisplacement"
@@ -75,12 +76,11 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "Fem_ConstraintSelfWeight"
<< "Fem_ConstraintForce"
<< "Fem_ConstraintPressure"
<< "Separator"
<< "Fem_ConstraintBearing"
<< "Fem_ConstraintGear"
<< "Fem_ConstraintPulley"
<< "Separator"
<< "Fem_ConstraintFluidBoundary"
//<< "Separator"
//<< "Fem_ConstraintBearing"
//<< "Fem_ConstraintGear"
//<< "Fem_ConstraintPulley"
//<< "Fem_ConstraintFluidBoundary"
<< "Separator"
<< "Fem_ConstraintTemperature"
<< "Fem_ConstraintHeatflux"
@@ -119,7 +119,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
*fem << "Fem_Analysis"
<< "Fem_SolverCalculix"
<< "Fem_SolverZ88"
<< "Fem_MeshFromShape"
<< "Fem_MeshNetgenFromShape"
<< "Fem_MeshGmshFromShape"
<< "Fem_MechanicalMaterial"
<< "Fem_MaterialMechanicalNonlinear"
<< "Fem_BeamSection"

View File

@@ -25,10 +25,8 @@
# * Juergen Riegel 2002 *
# ***************************************************************************/
import FreeCAD
FreeCAD.addExportType("TetGen file (*.poly)", "convert2TetGen")
FreeCAD.addImportType("FEM formats (*.unv *.med *.dat *.bdf)", "Fem")
if("BUILD_FEM_VTK" in FreeCAD.__cmake__):

View File

@@ -29,7 +29,6 @@
#* Juergen Riegel 2002 *
#***************************************************************************/
import FreeCAD
import FreeCADGui
@@ -50,8 +49,8 @@ class FemWorkbench (Workbench):
import _CommandRunSolver
import _CommandPurgeResults
import _CommandControlSolver
import _CommandMeshFromShape
import _CommandMeshGmshFromShape
import _CommandMeshNetgenFromShape
import _CommandAnalysis
import _CommandShellThickness
import _CommandBeamSection

View File

@@ -24,12 +24,12 @@ __title__ = "MechanicalMaterial"
__author__ = "Juergen Riegel, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## \addtogroup FEM
# @{
import FreeCAD
import _MechanicalMaterial
## \addtogroup FEM
# @{
def makeMechanicalMaterial(name):
'''makeMaterial(name): makes an Material

View File

@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GmshMesh</class>
<widget class="QWidget" name="GmshMesh">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>413</height>
</rect>
</property>
<property name="windowTitle">
<string>FEM Mesh by GMSH </string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="gb01_mesh_params">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>1677215</height>
</size>
</property>
<property name="title">
<string>FEM Mesh Parameter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<layout class="QFormLayout" name="formLayout_1">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="l_dimension">
<property name="text">
<string>Mesh element dimension:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cb_dimension"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="l_order">
<property name="text">
<string>Mesh element order:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cb_order"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="l_max">
<property name="text">
<string>Max element size (0.0 = Auto):</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::InputField" name="if_max">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="singleStep" stdset="0">
<double>1.000000000000000</double>
</property>
<property name="maximum" stdset="0">
<double>1000000000.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
<property name="decimals" stdset="0">
<number>2</number>
</property>
<property name="value" stdset="0">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="l_min">
<property name="text">
<string>Min element size (0.0 = Auto):</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="Gui::InputField" name="if_min">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="singleStep" stdset="0">
<double>1.000000000000000</double>
</property>
<property name="maximum" stdset="0">
<double>1000000000.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
<property name="decimals" stdset="0">
<number>2</number>
</property>
<property name="value" stdset="0">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb03_run_gmsh">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>1677215</height>
</size>
</property>
<property name="title">
<string>GMSH</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="1">
<layout class="QGridLayout" name="gl_actions">
<item row="1" column="0">
<widget class="QLabel" name="l_time">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Time:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QTextEdit" name="te_output">
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandAnalysis(FemCommands):
@@ -58,11 +56,6 @@ class _CommandAnalysis(FemCommands):
if (len(sel) == 1):
if(sel[0].isDerivedFrom("Fem::FemMeshObject")):
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.activeDocument()." + sel[0].Name + "]")
if(sel[0].isDerivedFrom("Part::Feature")):
FreeCADGui.doCommand("App.activeDocument().addObject('Fem::FemMeshShapeNetgenObject', '" + sel[0].Name + "_Mesh')")
FreeCADGui.doCommand("App.activeDocument().ActiveObject.Shape = App.activeDocument()." + sel[0].Name)
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.activeDocument().ActiveObject]")
FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name)")
FreeCADGui.Selection.clearSelection()
if FreeCAD.GuiUp:

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandBeamSection(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandConstraintSelfWeight(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandControlSolver(FemCommands):

View File

@@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore
import FreeCADGui
import FemGui
from PySide import QtCore
class _CommandMaterialMechanicalNonlinear(FemCommands):

View File

@@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore
import FreeCADGui
import FemGui
from PySide import QtCore
class _CommandMechanicalMaterial(FemCommands):

View File

@@ -0,0 +1,65 @@
# ***************************************************************************
# * *
# * 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__ = "Command GMSH Mesh From Shape"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package CommandMeshGmshFromShape
# \ingroup FEM
import FreeCAD
from FemCommands import FemCommands
import FreeCADGui
import FemGui
from PySide import QtCore
class _CommandMeshGmshFromShape(FemCommands):
# the Fem_MeshGmshFromShape command definition
def __init__(self):
super(_CommandMeshGmshFromShape, self).__init__()
self.resources = {'Pixmap': 'fem-fem-mesh-gmsh-from-shape',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "FEM mesh from shape by GMSH"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "Create a FEM mesh from a shape by GMSH mesher")}
self.is_active = 'with_part_feature'
def Activated(self):
FreeCAD.ActiveDocument.openTransaction("Create FEM mesh by GMSH")
FreeCADGui.addModule("FemGui")
sel = FreeCADGui.Selection.getSelection()
if (len(sel) == 1):
if(sel[0].isDerivedFrom("Part::Feature")):
mesh_obj_name = sel[0].Name + "_Mesh"
FreeCADGui.addModule("FemMeshGmsh")
FreeCADGui.doCommand("FemMeshGmsh.makeFemMeshGmsh('" + mesh_obj_name + "')")
FreeCADGui.doCommand("App.ActiveDocument.ActiveObject.Part = App.ActiveDocument." + sel[0].Name)
if FemGui.getActiveAnalysis():
FreeCADGui.addModule("FemGui")
FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.ActiveDocument.ActiveObject]")
FreeCADGui.doCommand("Gui.ActiveDocument.setEdit(App.ActiveDocument.ActiveObject.Name)")
FreeCADGui.Selection.clearSelection()
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Fem_MeshGmshFromShape', _CommandMeshGmshFromShape())

View File

@@ -20,32 +20,30 @@
# * *
# ***************************************************************************
__title__ = "Command Mesh From Shape"
__title__ = "Command Mesh Netgen From Shape"
__author__ = "Juergen Riegel"
__url__ = "http://www.freecadweb.org"
## @package CommandMeshFromShape
## @package CommandMeshNetgenFromShape
# \ingroup FEM
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandMeshFromShape(FemCommands):
# the Fem_MeshFromShape command definition
class _CommandMeshNetgenFromShape(FemCommands):
# the Fem_MeshNetgenFromShape command definition
def __init__(self):
super(_CommandMeshFromShape, self).__init__()
self.resources = {'Pixmap': 'fem-fem-mesh-from-shape',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid shape")}
super(_CommandMeshNetgenFromShape, self).__init__()
self.resources = {'Pixmap': 'fem-fem-mesh-netgen-from-shape',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape by Netgen"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid or face shape by Netgen internal mesher")}
self.is_active = 'with_part_feature'
def Activated(self):
FreeCAD.ActiveDocument.openTransaction("Create FEM mesh")
FreeCAD.ActiveDocument.openTransaction("Create FEM mesh Netgen")
FreeCADGui.addModule("FemGui")
sel = FreeCADGui.Selection.getSelection()
if (len(sel) == 1):
@@ -58,4 +56,4 @@ class _CommandMeshFromShape(FemCommands):
if FreeCAD.GuiUp:
FreeCADGui.addCommand('Fem_MeshFromShape', _CommandMeshFromShape())
FreeCADGui.addCommand('Fem_MeshNetgenFromShape', _CommandMeshNetgenFromShape())

View File

@@ -30,10 +30,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
import FemTools
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandPurgeResults(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
import FreeCADGui
from PySide import QtCore, QtGui
class _CommandRunSolver(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandShellThickness(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
import FreeCADGui
from PySide import QtCore, QtGui
class _CommandShowResult(FemCommands):

View File

@@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore
import FreeCADGui
import FemGui
from PySide import QtCore
class _CommandSolverCalculix(FemCommands):

View File

@@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org"
import FreeCAD
from FemCommands import FemCommands
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import FreeCADGui
from PySide import QtCore
class _CommandSolverZ88(FemCommands):

View File

@@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org"
## @package FemBeamSection
# \ingroup FEM
class _FemBeamSection:
"The FemBeamSection object"
def __init__(self, obj):

View File

@@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org"
## @package FemConstraintSelfWeight
# \ingroup FEM
class _FemConstraintSelfWeight:
"The FemConstraintSelfWeight object"
def __init__(self, obj):

View File

@@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org"
## @package FemMaterialMechanicalNonLinear
# \ingroup FEM
class _FemMaterialMechanicalNonlinear:
"The FemMaterialMechanicalNonlinear object"
def __init__(self, obj):

View File

@@ -0,0 +1,69 @@
# ***************************************************************************
# * *
# * 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__ = "_FemMeshGmsh"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package FemMeshGmsh
# \ingroup FEM
class _FemMeshGmsh():
"""The Fem::FemMeshObject's Proxy python type, add GMSH specific properties
"""
# they will be used from the task panel too, thus they need to be outside of the __init__
known_element_dimensions = ['Auto', '1D', '2D', '3D']
known_element_orders = ['Auto', '1st', '2nd']
def __init__(self, obj):
self.Type = "FemMeshGmsh"
self.Object = obj # keep a ref to the DocObj for nonGui usage
obj.Proxy = self # link between App::DocumentObject to this object
obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh")
obj.Part = None
obj.addProperty("App::PropertyFloat", "ElementSizeMax", "FEM Mesh Params", "Max mesh element size (0.0 = infinity)")
obj.ElementSizeMax = 0.0 # will be 1e+22
obj.addProperty("App::PropertyFloat", "ElementSizeMin", "FEM Mesh Params", "Min mesh element size")
obj.ElementSizeMin = 0.0
obj.addProperty("App::PropertyEnumeration", "ElementDimension", "FEM Mesh Params", "Dimension of mesh elements (Auto = according ShapeType of part to mesh)")
obj.ElementDimension = _FemMeshGmsh.known_element_dimensions
obj.ElementDimension = 'Auto' # according ShapeType of Part to mesh
obj.addProperty("App::PropertyEnumeration", "ElementOrder", "FEM Mesh Params", "Order of mesh elements (Auto will be 2nd)")
obj.ElementOrder = _FemMeshGmsh.known_element_orders
obj.ElementOrder = 'Auto' # = 2nd
def execute(self, obj):
return
def __getstate__(self):
return self.Type
def __setstate__(self, state):
if state:
self.Type = state

View File

@@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org"
## @package FemShellThickness
# \ingroup FEM
class _FemShellThickness:
"The FemShellThickness object"
def __init__(self, obj):

View File

@@ -42,7 +42,7 @@ class _FemSolverCalculix():
obj.addProperty("App::PropertyString", "SolverType", "Base", "Type of the solver", 1) # the 1 set the property to ReadOnly
obj.SolverType = str(self.Type)
fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General")
# fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") # not needed ATM
ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx")
obj.addProperty("App::PropertyPath", "WorkingDir", "Fem", "Working directory for calculations, will only be used it is left blank in preferences")

View File

@@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org"
## @package MechanicalMaterial
# \ingroup FEM
class _MechanicalMaterial:
"The Material object"
def __init__(self, obj):

View File

@@ -0,0 +1,170 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 - Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
__title__ = "_TaskPanelFemMeshGmsh"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
## @package TaskPanelFemMeshGmsh
# \ingroup FEM
import FreeCAD
import time
import _FemMeshGmsh
import FreeCADGui
from PySide import QtGui
from PySide import QtCore
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
class _TaskPanelFemMeshGmsh:
'''The TaskPanel for editing References property of FemMeshGmsh objects and creation of new FEM mesh'''
def __init__(self, obj):
self.mesh_obj = obj
self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/TaskPanelFemMeshGmsh.ui")
self.Timer = QtCore.QTimer()
self.Timer.start(100) # 100 milli seconds
self.gmsh_runs = False
self.console_message_gmsh = ''
QtCore.QObject.connect(self.form.if_max, QtCore.SIGNAL("valueChanged(double)"), self.max_changed)
QtCore.QObject.connect(self.form.if_min, QtCore.SIGNAL("valueChanged(double)"), self.min_changed)
QtCore.QObject.connect(self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension)
QtCore.QObject.connect(self.form.cb_order, QtCore.SIGNAL("activated(int)"), self.choose_order)
QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text)
self.form.cb_dimension.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_dimensions)
self.form.cb_order.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_orders)
self.get_mesh_params()
self.get_active_analysis()
self.update()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Close)
# show a apply and a close button
# def reject() is called on close button
# def clicked(self, button) is needed, to access the apply button
# def accept() in no longer needed, since there is no OK button
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.recompute()
return True
def clicked(self, button):
if button == QtGui.QDialogButtonBox.Apply:
self.run_gmsh()
def get_mesh_params(self):
self.clmax = self.mesh_obj.ElementSizeMax
self.clmin = self.mesh_obj.ElementSizeMin
self.order = self.mesh_obj.ElementOrder
self.dimension = self.mesh_obj.ElementDimension
def set_mesh_params(self):
self.mesh_obj.ElementSizeMax = self.clmax
self.mesh_obj.ElementSizeMin = self.clmin
self.mesh_obj.ElementOrder = self.order
self.mesh_obj.ElementDimension = self.dimension
def update(self):
'fills the widgets'
self.form.if_max.setText("{} mm".format(self.clmax))
self.form.if_min.setText("{} mm".format(self.clmin))
index_dimension = self.form.cb_dimension.findText(self.dimension)
self.form.cb_dimension.setCurrentIndex(index_dimension)
index_order = self.form.cb_order.findText(self.order)
self.form.cb_order.setCurrentIndex(index_order)
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, value):
self.clmax = float(value)
def min_changed(self, value):
self.clmin = float(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 choose_order(self, index):
if index < 0:
return
self.form.cb_order.setCurrentIndex(index)
self.order = str(self.form.cb_order.itemText(index)) # form returns unicode
def run_gmsh(self):
QApplication.setOverrideCursor(Qt.WaitCursor)
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 gone start ...")
self.get_active_analysis()
self.set_mesh_params()
import FemGmshTools
gmsh_mesh = FemGmshTools.FemGmshTools(self.obj, self.analysis)
self.console_log("Start GMSH ...")
error = gmsh_mesh.create_mesh()
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().Member:
if m.Name == self.mesh_obj.Name:
print(self.analysis.Name)
return
else:
# print('Mesh is not member of active analysis, means no group meshing')
self.analysis = None # no group meshing
else:
# print('No active analyis, means no group meshing')
self.analysis = None # no group meshing

View File

@@ -31,13 +31,11 @@ import FemToolsCcx
import FreeCAD
import os
import time
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
import FreeCADGui
import FemGui
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
class _TaskPanelFemSolverCalculix:
@@ -83,6 +81,25 @@ class _TaskPanelFemSolverCalculix:
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'))
@@ -152,26 +169,6 @@ class _TaskPanelFemSolverCalculix:
QApplication.restoreOverrideCursor()
self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start))
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Close)
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 accept(self):
FreeCADGui.ActiveDocument.resetEdit()
def reject(self):
FreeCADGui.ActiveDocument.resetEdit()
def choose_working_dir(self):
current_wd = self.setup_working_dir()
wd = QtGui.QFileDialog.getExistingDirectory(None, 'Choose CalculiX working directory',

View File

@@ -31,12 +31,11 @@ import FreeCAD
import FemTools
import numpy as np
if FreeCAD.GuiUp:
import FreeCADGui
import FemGui
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
import FreeCADGui
import FemGui
from PySide import QtCore, QtGui
from PySide.QtCore import Qt
from PySide.QtGui import QApplication
class _TaskPanelShowResult:
@@ -304,10 +303,6 @@ class _TaskPanelShowResult:
def update(self):
self.MeshObject = None
self.result_object = get_results_object(FreeCADGui.Selection.getSelection())
# Disable temperature radio button if it does ot exist in results
if len(self.result_object.Temperature) == 1:
self.form.rb_temperature.setEnabled(0)
for i in FemGui.getActiveAnalysis().Member:
if i.isDerivedFrom("Fem::FemMeshObject"):
self.MeshObject = i
@@ -315,13 +310,21 @@ class _TaskPanelShowResult:
self.suitable_results = False
if self.result_object:
# Disable temperature radio button if it does ot exist in results
if len(self.result_object.Temperature) == 1:
self.form.rb_temperature.setEnabled(0)
if (self.MeshObject.FemMesh.NodeCount == len(self.result_object.NodeNumbers)):
self.suitable_results = True
else:
if not self.MeshObject.FemMesh.VolumeCount:
FreeCAD.Console.PrintError('Graphical bending stress output for beam or shell FEM Meshes not yet supported!\n')
FreeCAD.Console.PrintError('FEM: Graphical bending stress output for beam or shell FEM Meshes not yet supported.\n')
else:
FreeCAD.Console.PrintError('Result node numbers are not equal to FEM Mesh NodeCount!\n')
FreeCAD.Console.PrintError('FEM: Result node numbers are not equal to FEM Mesh NodeCount.\n')
else:
error_message = 'FEM: Result task panel, no result object to display results for.\n'
FreeCAD.Console.PrintError(error_message)
QtGui.QMessageBox.critical(None, 'No result object', error_message)
def accept(self):
FreeCADGui.Control.closeDialog()

View File

@@ -0,0 +1,111 @@
# ***************************************************************************
# * *
# * 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
class _ViewProviderFemMeshGmsh:
"A View Provider for the FemMeshGmsh object"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/fem-fem-mesh-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
import _TaskPanelFemMeshGmsh
taskd = _TaskPanelFemMeshGmsh._TaskPanelFemMeshGmsh(self.Object)
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self, vobj, mode):
FreeCADGui.Control.closeDialog()
return
def doubleClicked(self, vobj):
# 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!!!
if FemGui.getActiveAnalysis() is not None:
if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument:
if self.Object in FemGui.getActiveAnalysis().Member:
if not gui_doc.getInEdit():
gui_doc.setEdit(vobj.Object.Name)
else:
FreeCAD.Console.PrintError('Activate the analysis this mesh belongs to!\n')
else:
print('Mesh does not belong to the active analysis.')
for o in gui_doc.Document.Objects:
if o.isDerivedFrom('Fem::FemAnalysisPython'):
for m in o.Member:
if m == self.Object:
FemGui.setActiveAnalysis(o)
print('Analysis the Mesh belongs too was activated.')
gui_doc.setEdit(vobj.Object.Name)
break
else:
FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n')
else:
# no active analysis, we gone have a look if the obj belongs to a non active analysis,
for o in gui_doc.Document.Objects:
if o.isDerivedFrom('Fem::FemAnalysisPython'):
for m in o.Member:
if m == self.Object:
FemGui.setActiveAnalysis(o)
print('Analysis the Mesh belongs too was activated.')
gui_doc.setEdit(vobj.Object.Name)
break
else:
print('Mesh GMSH object does not belong to an analysis. Group meshing will is deactivated.')
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

View File

@@ -20,7 +20,7 @@
# * *
# ***************************************************************************
__title__ = "_FemViewProviderSolverCalculix"
__title__ = "_ViewProviderFemSolverCalculix"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"

View File

@@ -20,7 +20,7 @@
# * *
# ***************************************************************************
__title__ = "_FemViewProviderSolverZ88"
__title__ = "_ViewProviderFemSolverZ88"
__author__ = "Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"

View File

@@ -20,10 +20,6 @@
# * *
# ***************************************************************************
import FreeCAD
import os
__title__ = "ccxDatReader"
__author__ = "Przemo Firszt"
__url__ = "http://www.freecadweb.org"
@@ -31,6 +27,10 @@ __url__ = "http://www.freecadweb.org"
## @package ccxDatReader
# \ingroup FEM
import FreeCAD
import os
if open.__module__ == '__builtin__':
# because we'll redefine open below
pyopen = open

View File

@@ -22,12 +22,6 @@
# * *
# ***************************************************************************
import FreeCAD
import os
from math import pow, sqrt
import numpy as np
__title__ = "FreeCAD Calculix library"
__author__ = "Juergen Riegel , Michael Hindley, Bernd Hahnebach"
__url__ = "http://www.freecadweb.org"
@@ -35,6 +29,12 @@ __url__ = "http://www.freecadweb.org"
## @package ccxFrdReader
# \ingroup FEM
import FreeCAD
import os
from math import pow, sqrt
import numpy as np
if open.__module__ == '__builtin__':
pyopen = open # because we'll redefine open below
@@ -331,6 +331,8 @@ def readResult(frd_input):
elements_found = False
frd_file.close()
if not nodes:
FreeCAD.Console.PrintError('FEM: No nodes found in Frd file.\n')
return {'Nodes': nodes,
'Hexa8Elem': elements_hexa8, 'Penta6Elem': elements_penta6, 'Tetra4Elem': elements_tetra4, 'Tetra10Elem': elements_tetra10,
'Penta15Elem': elements_penta15, 'Hexa20Elem': elements_hexa20, 'Tria3Elem': elements_tria3, 'Tria6Elem': elements_tria6,

View File

@@ -20,11 +20,6 @@
# * *
# ***************************************************************************
import FemMeshTools
import FreeCAD
import os
import string
__title__ = "FreeCAD .inp file reader"
__author__ = "Frantisek Loeffelmann "
__url__ = "http://www.freecadweb.org"
@@ -33,6 +28,12 @@ __date__ = "04/08/2016"
## @package importInpMesh
# \ingroup FEM
import FemMeshTools
import FreeCAD
import os
import string
if open.__module__ == '__builtin__':
pyopen = open # because we'll redefine open below

View File

@@ -20,12 +20,6 @@
# * *
# ***************************************************************************
import FreeCAD
import os
import FemMeshTools
__title__ = "FreeCAD Z88 Mesh reader and writer"
__author__ = "Bernd Hahnebach "
__url__ = "http://www.freecadweb.org"
@@ -33,6 +27,11 @@ __url__ = "http://www.freecadweb.org"
## @package importZ88Mesh
# \ingroup FEM
import FreeCAD
import os
import FemMeshTools
Debug = False
if open.__module__ == '__builtin__':

View File

@@ -547,7 +547,7 @@ FemConstraintFixed,3
** Element + CalculiX face + load in [MPa]
** written by write_constraints_pressure function
*DLOAD
** face load on shape: Box:Face2
** FemConstraintPressure: face load
635,P1,1000.0
638,P3,1000.0
641,P2,1000.0

View File

@@ -20,12 +20,6 @@
# * *
# ***************************************************************************
import FreeCAD
import os
from math import pow, sqrt
__title__ = "FreeCAD Z88 Disp Reader"
__author__ = "Bernd Hahnebach "
__url__ = "http://www.freecadweb.org"
@@ -33,6 +27,11 @@ __url__ = "http://www.freecadweb.org"
## @package z88DispReader
# \ingroup FEM
import FreeCAD
import os
from math import pow, sqrt
Debug = False
if open.__module__ == '__builtin__':