Merge branch 'FreeCAD:master' into master

This commit is contained in:
Zolko-123
2021-07-26 13:26:54 +02:00
committed by GitHub
69 changed files with 3406 additions and 284 deletions

View File

@@ -48,10 +48,17 @@ SET(FemExamples_SRCS
femexamples/buckling_platebuckling.py
femexamples/buckling_lateraltorsionalbuckling.py
femexamples/ccx_buckling_flexuralbuckling.py
femexamples/ccx_cantilever_base.py
femexamples/ccx_cantilever_base_edge.py
femexamples/ccx_cantilever_base_face.py
femexamples/ccx_cantilever_base_solid.py
femexamples/ccx_cantilever_ele_hexa20.py
femexamples/ccx_cantilever_ele_tetra4.py
femexamples/ccx_cantilever_ele_tria3.py
femexamples/ccx_cantilever_ele_tria6.py
femexamples/ccx_cantilever_ele_seg2.py
femexamples/ccx_cantilever_ele_seg3.py
femexamples/ccx_cantilever_faceload.py
femexamples/ccx_cantilever_nodeload.py
femexamples/ccx_cantilever_hexa20faceload.py
femexamples/ccx_cantilever_prescribeddisplacement.py
femexamples/constraint_centrif.py
femexamples/constraint_contact_shell_shell.py
@@ -87,7 +94,11 @@ SET(FemExampleMeshes_SRCS
femexamples/meshes/mesh_buckling_ibeam_tria6.py
femexamples/meshes/mesh_buckling_plate_tria6.py
femexamples/meshes/mesh_canticcx_hexa20.py
femexamples/meshes/mesh_canticcx_seg2.py
femexamples/meshes/mesh_canticcx_seg3.py
femexamples/meshes/mesh_canticcx_tetra10.py
femexamples/meshes/mesh_canticcx_tria3.py
femexamples/meshes/mesh_canticcx_tria6.py
femexamples/meshes/mesh_capacitance_two_balls_tetra10.py
femexamples/meshes/mesh_constraint_centrif_tetra10.py
femexamples/meshes/mesh_constraint_tie_tetra10.py
@@ -287,10 +298,10 @@ SET(FemTestsCcx_SRCS
femtest/data/calculix/box.FCStd
femtest/data/calculix/ccx_buckling_flexuralbuckling.dat
femtest/data/calculix/ccx_buckling_flexuralbuckling.inp
femtest/data/calculix/ccxcantilever_faceload.inp
femtest/data/calculix/ccxcantilever_hexa20.inp
femtest/data/calculix/ccxcantilever_nodeload.inp
femtest/data/calculix/ccxcantilever_prescribeddisplacement.inp
femtest/data/calculix/ccx_cantilever_faceload.inp
femtest/data/calculix/ccx_cantilever_ele_hexa20.inp
femtest/data/calculix/ccx_cantilever_nodeload.inp
femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp
femtest/data/calculix/constraint_centrif.inp
femtest/data/calculix/constraint_contact_shell_shell.FCStd
femtest/data/calculix/constraint_contact_shell_shell.inp
@@ -353,41 +364,41 @@ SET(FemTestsZ88Main_SRCS
SET(FemTestsZ88Ccxcantifl_SRCS
femtest/data/z88/__init__.py
femtest/data/z88/ccxcantilever_faceload/51.txt
femtest/data/z88/ccxcantilever_faceload/z88.dyn
femtest/data/z88/ccxcantilever_faceload/z88elp.txt
femtest/data/z88/ccxcantilever_faceload/z88i1.txt
femtest/data/z88/ccxcantilever_faceload/z88i2.txt
femtest/data/z88/ccxcantilever_faceload/z88i5.txt
femtest/data/z88/ccxcantilever_faceload/z88int.txt
femtest/data/z88/ccxcantilever_faceload/z88man.txt
femtest/data/z88/ccxcantilever_faceload/z88mat.txt
femtest/data/z88/ccx_cantilever_faceload/51.txt
femtest/data/z88/ccx_cantilever_faceload/z88.dyn
femtest/data/z88/ccx_cantilever_faceload/z88elp.txt
femtest/data/z88/ccx_cantilever_faceload/z88i1.txt
femtest/data/z88/ccx_cantilever_faceload/z88i2.txt
femtest/data/z88/ccx_cantilever_faceload/z88i5.txt
femtest/data/z88/ccx_cantilever_faceload/z88int.txt
femtest/data/z88/ccx_cantilever_faceload/z88man.txt
femtest/data/z88/ccx_cantilever_faceload/z88mat.txt
)
SET(FemTestsZ88Ccxcantihex_SRCS
femtest/data/z88/__init__.py
femtest/data/z88/ccxcantilever_hexa20/51.txt
femtest/data/z88/ccxcantilever_hexa20/z88.dyn
femtest/data/z88/ccxcantilever_hexa20/z88elp.txt
femtest/data/z88/ccxcantilever_hexa20/z88i1.txt
femtest/data/z88/ccxcantilever_hexa20/z88i2.txt
femtest/data/z88/ccxcantilever_hexa20/z88i5.txt
femtest/data/z88/ccxcantilever_hexa20/z88int.txt
femtest/data/z88/ccxcantilever_hexa20/z88man.txt
femtest/data/z88/ccxcantilever_hexa20/z88mat.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/51.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88.dyn
femtest/data/z88/ccx_cantilever_ele_hexa20/z88elp.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88i1.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88i2.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88i5.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88int.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88man.txt
femtest/data/z88/ccx_cantilever_ele_hexa20/z88mat.txt
)
SET(FemTestsZ88Ccxcantinl_SRCS
femtest/data/z88/__init__.py
femtest/data/z88/ccxcantilever_nodeload/51.txt
femtest/data/z88/ccxcantilever_nodeload/z88.dyn
femtest/data/z88/ccxcantilever_nodeload/z88elp.txt
femtest/data/z88/ccxcantilever_nodeload/z88i1.txt
femtest/data/z88/ccxcantilever_nodeload/z88i2.txt
femtest/data/z88/ccxcantilever_nodeload/z88i5.txt
femtest/data/z88/ccxcantilever_nodeload/z88int.txt
femtest/data/z88/ccxcantilever_nodeload/z88man.txt
femtest/data/z88/ccxcantilever_nodeload/z88mat.txt
femtest/data/z88/ccx_cantilever_nodeload/51.txt
femtest/data/z88/ccx_cantilever_nodeload/z88.dyn
femtest/data/z88/ccx_cantilever_nodeload/z88elp.txt
femtest/data/z88/ccx_cantilever_nodeload/z88i1.txt
femtest/data/z88/ccx_cantilever_nodeload/z88i2.txt
femtest/data/z88/ccx_cantilever_nodeload/z88i5.txt
femtest/data/z88/ccx_cantilever_nodeload/z88int.txt
femtest/data/z88/ccx_cantilever_nodeload/z88man.txt
femtest/data/z88/ccx_cantilever_nodeload/z88mat.txt
)
SET(FemTools_SRCS
@@ -462,9 +473,9 @@ INSTALL(FILES ${FemTestsElmer_SRCS} DESTINATION Mod/Fem/femtest/data/elmer)
INSTALL(FILES ${FemTestsMesh_SRCS} DESTINATION Mod/Fem/femtest/data/mesh)
INSTALL(FILES ${FemTestsOpen_SRCS} DESTINATION Mod/Fem/femtest/data/open)
INSTALL(FILES ${FemTestsZ88Main_SRCS} DESTINATION Mod/Fem/femtest/data/z88)
INSTALL(FILES ${FemTestsZ88Ccxcantifl_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccxcantilever_faceload)
INSTALL(FILES ${FemTestsZ88Ccxcantihex_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccxcantilever_hexa20)
INSTALL(FILES ${FemTestsZ88Ccxcantinl_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccxcantilever_nodeload)
INSTALL(FILES ${FemTestsZ88Ccxcantifl_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccx_cantilever_faceload)
INSTALL(FILES ${FemTestsZ88Ccxcantihex_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccx_cantilever_ele_hexa20)
INSTALL(FILES ${FemTestsZ88Ccxcantinl_SRCS} DESTINATION Mod/Fem/femtest/data/z88/ccx_cantilever_nodeload)
INSTALL(FILES ${FemTools_SRCS} DESTINATION Mod/Fem/femtools)

View File

@@ -0,0 +1,138 @@
# ***************************************************************************
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2020 Sudhanshu Dubey <sudhanshu.thethunder@gmail.com *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import FreeCAD
import Fem
import ObjectsFem
from .manager import get_meshname
from .manager import init_doc
def setup_cantilever_base_edge(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# geometric objects
# load line
load_line = doc.addObject("Part::Line", "LoadLine")
load_line.X1 = 0
load_line.Y1 = 0
load_line.Z1 = 1000
load_line.X2 = 0
load_line.Y2 = 0
load_line.Z2 = 0
# cantilever line
geom_obj = doc.addObject("Part::Line", "CantileverLine")
geom_obj.X1 = 0
geom_obj.Y1 = 500
geom_obj.Z1 = 500
geom_obj.X2 = 8000
geom_obj.Y2 = 500
geom_obj.Z2 = 500
doc.recompute()
if FreeCAD.GuiUp:
geom_obj.ViewObject.Document.activeView().viewAxonometric()
geom_obj.ViewObject.Document.activeView().fitAll()
# analysis
analysis = ObjectsFem.makeAnalysis(doc, "Analysis")
# solver
if solvertype == "calculix":
solver_obj = ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX")
elif solvertype == "ccxtools":
solver_obj = ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools")
solver_obj.WorkingDir = u""
else:
FreeCAD.Console.PrintWarning(
"Not known or not supported solver type: {}. "
"No solver object was created.\n".format(solvertype)
)
if solvertype == "calculix" or solvertype == "ccxtools":
solver_obj.AnalysisType = "static"
solver_obj.GeometricalNonlinearity = "linear"
solver_obj.ThermoMechSteadyState = False
solver_obj.MatrixSolverType = "default"
solver_obj.IterationsControlParameterTimeUse = False
solver_obj.SplitInputWriter = False
analysis.addObject(solver_obj)
# beam section
beamsection_obj = ObjectsFem.makeElementGeometry1D(
doc,
sectiontype="Rectangular",
width=1000.0,
height=1000.0,
name="BeamCrossSection"
)
analysis.addObject(beamsection_obj)
# material
material_obj = ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial")
mat = material_obj.Material
mat["Name"] = "Calculix-Steel"
mat["YoungsModulus"] = "210000 MPa"
mat["PoissonRatio"] = "0.30"
material_obj.Material = mat
analysis.addObject(material_obj)
# constraint fixed
con_fixed = ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed")
con_fixed.References = [(geom_obj, "Vertex1")]
analysis.addObject(con_fixed)
# constraint force
con_force = ObjectsFem.makeConstraintForce(doc, "ConstraintForce")
con_force.References = [(geom_obj, "Vertex2")]
con_force.Force = 9000000.0 # 9'000'000 N = 9 MN
con_force.Direction = (load_line, ["Edge1"])
con_force.Reversed = False
analysis.addObject(con_force)
# mesh
from .meshes.mesh_canticcx_seg3 import create_nodes, create_elements
fem_mesh = Fem.FemMesh()
control = create_nodes(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating nodes.\n")
control = create_elements(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "1D"
femmesh_obj.CharacteristicLengthMax = "1750.0 mm"
femmesh_obj.CharacteristicLengthMin = "1750.0 mm"
doc.recompute()
return doc

View File

@@ -0,0 +1,121 @@
# ***************************************************************************
# * Copyright (c) 2021 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import FreeCAD
import Fem
import ObjectsFem
from .manager import get_meshname
from .manager import init_doc
def setup_cantilever_base_face(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# geometric objects
geom_obj = doc.addObject("Part::Plane", "CanileverPlate")
geom_obj.Width = 1000
geom_obj.Length = 8000
geom_obj.Placement = FreeCAD.Placement(
FreeCAD.Vector(0, 500, 0),
FreeCAD.Rotation(0, 0, 90),
FreeCAD.Vector(1, 0, 0),
)
doc.recompute()
if FreeCAD.GuiUp:
geom_obj.ViewObject.Document.activeView().viewAxonometric()
geom_obj.ViewObject.Document.activeView().fitAll()
# analysis
analysis = ObjectsFem.makeAnalysis(doc, "Analysis")
# solver
if solvertype == "calculix":
solver_obj = ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX")
elif solvertype == "ccxtools":
solver_obj = ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools")
solver_obj.WorkingDir = u""
else:
FreeCAD.Console.PrintWarning(
"Not known or not supported solver type: {}. "
"No solver object was created.\n".format(solvertype)
)
if solvertype == "calculix" or solvertype == "ccxtools":
solver_obj.AnalysisType = "static"
solver_obj.GeometricalNonlinearity = "linear"
solver_obj.ThermoMechSteadyState = False
solver_obj.MatrixSolverType = "default"
solver_obj.IterationsControlParameterTimeUse = False
solver_obj.SplitInputWriter = False
analysis.addObject(solver_obj)
# shell thickness
thickness_obj = ObjectsFem.makeElementGeometry2D(doc, 1000, 'Thickness')
analysis.addObject(thickness_obj)
# material
material_obj = ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial")
mat = material_obj.Material
mat["Name"] = "Calculix-Steel"
mat["YoungsModulus"] = "210000 MPa"
mat["PoissonRatio"] = "0.30"
material_obj.Material = mat
analysis.addObject(material_obj)
# constraint fixed
con_fixed = ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed")
con_fixed.References = [(geom_obj, "Edge1")]
analysis.addObject(con_fixed)
# constraint force
con_force = ObjectsFem.makeConstraintForce(doc, "ConstraintForce")
con_force.References = [(geom_obj, "Edge3")]
con_force.Force = 9000000.0 # 9'000'000 N = 9 MN
con_force.Direction = (geom_obj, ["Edge3"])
con_force.Reversed = True
analysis.addObject(con_force)
# mesh
from .meshes.mesh_canticcx_tria6 import create_nodes, create_elements
fem_mesh = Fem.FemMesh()
control = create_nodes(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating nodes.\n")
control = create_elements(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0]
femmesh_obj.FemMesh = fem_mesh
femmesh_obj.Part = geom_obj
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.CharacteristicLengthMax = "500.0 mm"
doc.recompute()
return doc

View File

@@ -31,7 +31,7 @@ from .manager import get_meshname
from .manager import init_doc
def setup_cantileverbase(doc=None, solvertype="ccxtools"):
def setup_cantilever_base_solid(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:

View File

@@ -34,7 +34,7 @@ from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever hexa20 face load",
"name": "CCX cantilever hexa20 solid elements",
"meshtype": "solid",
"meshelement": "Hexa20",
"constraints": ["fixed", "force"],
@@ -48,11 +48,12 @@ def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_hexa20faceload import setup
from femexamples.ccx_cantilever_ele_hexa20 import setup
setup()
See forum topic post:
hexa20 elements and face load
...
"""
@@ -68,10 +69,15 @@ def setup(doc=None, solvertype="ccxtools"):
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup cantilever faceload and exchange the mesh
# setup cantilever faceload
doc = setup_with_faceload(doc, solvertype)
femmesh_obj = doc.getObject(get_meshname())
# delete explanation object wrongly added with setup faceload
if hasattr(doc, "Explanation_Report001"):
doc.removeObject("Explanation_Report001")
doc.recompute()
# load the hexa20 mesh
from .meshes.mesh_canticcx_hexa20 import create_nodes, create_elements
new_fem_mesh = Fem.FemMesh()

View File

@@ -0,0 +1,97 @@
# ***************************************************************************
# * Copyright (c) 2021 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import FreeCAD
import Fem
from . import manager
from .ccx_cantilever_base_edge import setup_cantilever_base_edge
from .manager import get_meshname
from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever seg2 beam elements",
"meshtype": "edge",
"meshelement": "Seg2",
"constraints": ["fixed", "force"],
"solvers": ["calculix"],
"material": "solid",
"equation": "mechanical"
}
def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_ele_seg2 import setup
setup()
See forum topic post (for seg3):
https://forum.freecadweb.org/viewtopic.php?f=18&t=16044
CalculiX cantilever modeled with seg2 beam elements
"""
def setup(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# explanation object
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever
doc = setup_cantilever_base_edge(doc, solvertype)
femmesh_obj = doc.getObject(get_meshname())
# load the seg2 mesh
from .meshes.mesh_canticcx_seg2 import create_nodes, create_elements
new_fem_mesh = Fem.FemMesh()
control = create_nodes(new_fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating nodes.\n")
control = create_elements(new_fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating elements.\n")
# overwrite mesh with the seg2 mesh
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "1D"
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "150.0 mm"
femmesh_obj.CharacteristicLengthMin = "150.0 mm"
doc.recompute()
return doc

View File

@@ -0,0 +1,71 @@
# ***************************************************************************
# * Copyright (c) 2021 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
from . import manager
from .ccx_cantilever_base_edge import setup_cantilever_base_edge
from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever seg3 beam elements",
"meshtype": "edge",
"meshelement": "Seg3",
"constraints": ["fixed", "force"],
"solvers": ["calculix"],
"material": "solid",
"equation": "mechanical"
}
def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_ele_seg3 import setup
setup()
See forum topic post:
https://forum.freecadweb.org/viewtopic.php?f=18&t=16044
CalculiX cantilever modeled with seg3 beam elements
"""
def setup(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# explanation object
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever
doc = setup_cantilever_base_edge(doc, solvertype)
doc.recompute()
return doc

View File

@@ -0,0 +1,83 @@
# ***************************************************************************
# * Copyright (c) 2019 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2020 Sudhanshu Dubey <sudhanshu.thethunder@gmail.com> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import Fem
from . import manager
from .ccx_cantilever_faceload import setup as setup_with_faceload
from .manager import get_meshname
from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever tetra4 solid elements",
"meshtype": "solid",
"meshelement": "Tetra4",
"constraints": ["fixed", "force"],
"solvers": ["calculix", "elmer", "z88"],
"material": "solid",
"equation": "mechanical"
}
def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_ele_tetra4 import setup
setup()
Tetra4 elements. There are really a lot needed thus mesh is cleared.
Mesh before run the example.
...
"""
def setup(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# explanation object
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup cantilever faceload and exchange the mesh
doc = setup_with_faceload(doc, solvertype)
femmesh_obj = doc.getObject(get_meshname())
# clear mesh and set meshing parameter
femmesh_obj.FemMesh = Fem.FemMesh()
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "3D"
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "150.0 mm"
femmesh_obj.CharacteristicLengthMin = "150.0 mm"
doc.recompute()
return doc

View File

@@ -0,0 +1,97 @@
# ***************************************************************************
# * Copyright (c) 2021 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import FreeCAD
import Fem
from . import manager
from .ccx_cantilever_base_face import setup_cantilever_base_face
from .manager import get_meshname
from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever tria3 face elements",
"meshtype": "face",
"meshelement": "Tria3",
"constraints": ["fixed", "force"],
"solvers": ["calculix"],
"material": "solid",
"equation": "mechanical"
}
def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_ele_tria3 import setup
setup()
See forum topic post:
CalculiX cantilever modeled with tria3 face elements
"""
def setup(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# explanation object
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever
doc = setup_cantilever_base_face(doc, solvertype)
femmesh_obj = doc.getObject(get_meshname())
# load the tria3 mesh
from .meshes.mesh_canticcx_tria3 import create_nodes, create_elements
new_fem_mesh = Fem.FemMesh()
control = create_nodes(new_fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating nodes.\n")
control = create_elements(new_fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating elements.\n")
# overwrite mesh with the tria3 mesh
femmesh_obj.FemMesh = new_fem_mesh
# set mesh obj parameter
femmesh_obj.SecondOrderLinear = False
femmesh_obj.ElementDimension = "2D"
femmesh_obj.ElementOrder = "1st"
femmesh_obj.CharacteristicLengthMax = "150.0 mm"
femmesh_obj.CharacteristicLengthMin = "150.0 mm"
doc.recompute()
return doc

View File

@@ -0,0 +1,70 @@
# ***************************************************************************
# * Copyright (c) 2021 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
from . import manager
from .ccx_cantilever_base_face import setup_cantilever_base_face
from .manager import init_doc
def get_information():
return {
"name": "CCX cantilever tria6 face elements",
"meshtype": "face",
"meshelement": "Tria6",
"constraints": ["fixed", "force"],
"solvers": ["calculix"],
"material": "solid",
"equation": "mechanical"
}
def get_explanation(header=""):
return header + """
To run the example from Python console use:
from femexamples.ccx_cantilever_ele_tria6 import setup
setup()
See forum topic post:
CalculiX cantilever modeled with face elements
"""
def setup(doc=None, solvertype="ccxtools"):
# init FreeCAD document
if doc is None:
doc = init_doc()
# explanation object
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever
doc = setup_cantilever_base_face(doc, solvertype)
doc.recompute()
return doc

View File

@@ -25,7 +25,7 @@
import ObjectsFem
from . import manager
from .ccx_cantilever_base import setup_cantileverbase
from .ccx_cantilever_base_solid import setup_cantilever_base_solid
from .manager import init_doc
@@ -65,8 +65,8 @@ def setup(doc=None, solvertype="ccxtools"):
# just keep the following line and change text string in get_explanation method
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever, apply 9 MN on surface of front end face
doc = setup_cantileverbase(doc, solvertype)
# setup CalculiX cantilever
doc = setup_cantilever_base_solid(doc, solvertype)
analysis = doc.Analysis
geom_obj = doc.Box

View File

@@ -25,7 +25,7 @@
import ObjectsFem
from . import manager
from .ccx_cantilever_base import setup_cantileverbase
from .ccx_cantilever_base_solid import setup_cantilever_base_solid
from .manager import init_doc
@@ -66,7 +66,7 @@ def setup(doc=None, solvertype="ccxtools"):
manager.add_explanation_obj(doc, get_explanation(manager.get_header(get_information())))
# setup CalculiX cantilever, apply 9 MN on the 4 nodes of the front end face
doc = setup_cantileverbase(doc, solvertype)
doc = setup_cantilever_base_solid(doc, solvertype)
analysis = doc.Analysis
geom_obj = doc.Box

View File

@@ -25,7 +25,7 @@
import ObjectsFem
from . import manager
from .ccx_cantilever_base import setup_cantileverbase
from .ccx_cantilever_base_solid import setup_cantilever_base_solid
from .manager import init_doc
@@ -72,7 +72,7 @@ def setup(doc=None, solvertype="ccxtools"):
# setup CalculiX cantilever
# apply a prescribed displacement of 250 mm in -z on the front end face
doc = setup_cantileverbase(doc, solvertype)
doc = setup_cantilever_base_solid(doc, solvertype)
analysis = doc.Analysis
geom_obj = doc.Box

View File

@@ -57,7 +57,9 @@ class FemExamples(QtGui.QWidget):
"__init__.py",
"__pycache__",
"boxanalysis_base.py",
"ccx_cantilever_base.py",
"ccx_cantilever_base_edge.py",
"ccx_cantilever_base_face.py",
"ccx_cantilever_base_solid.py",
"examplesgui.py",
"manager.py",
"meshes",

View File

@@ -72,33 +72,33 @@ def setup(doc=None, solvertype="ccxtools"):
# geometric objects
# name is important because the other method in this module use obj name
box_obj1 = doc.addObject('Part::Box', 'Box1')
box_obj1 = doc.addObject("Part::Box", "Box1")
box_obj1.Height = 10
box_obj1.Width = 10
box_obj1.Length = 20
box_obj2 = doc.addObject('Part::Box', 'Box2')
box_obj2 = doc.addObject("Part::Box", "Box2")
box_obj2.Height = 10
box_obj2.Width = 10
box_obj2.Length = 20
box_obj2.Placement.Base = (20, 0, 0)
box_obj3 = doc.addObject('Part::Box', 'Box3')
box_obj3 = doc.addObject("Part::Box", "Box3")
box_obj3.Height = 10
box_obj3.Width = 10
box_obj3.Length = 20
box_obj3.Placement.Base = (40, 0, 0)
box_obj4 = doc.addObject('Part::Box', 'Box4')
box_obj4 = doc.addObject("Part::Box", "Box4")
box_obj4.Height = 10
box_obj4.Width = 10
box_obj4.Length = 20
box_obj4.Placement.Base = (60, 0, 0)
box_obj5 = doc.addObject('Part::Box', 'Box5')
box_obj5 = doc.addObject("Part::Box", "Box5")
box_obj5.Height = 10
box_obj5.Width = 10
box_obj5.Length = 20
box_obj5.Placement.Base = (80, 0, 0)
# make a CompSolid out of the boxes, to be able to remesh with GUI
j = BOPTools.SplitFeatures.makeBooleanFragments(name='BooleanFragments')
j = BOPTools.SplitFeatures.makeBooleanFragments(name="BooleanFragments")
j.Objects = [box_obj1, box_obj2, box_obj3, box_obj4, box_obj5]
j.Mode = "CompSolid"
j.Proxy.execute(j)
@@ -108,7 +108,7 @@ def setup(doc=None, solvertype="ccxtools"):
for obj in j.ViewObject.Proxy.claimChildren():
obj.ViewObject.hide()
geom_obj = doc.addObject('Part::Feature', 'CompSolid')
geom_obj = doc.addObject("Part::Feature", "CompSolid")
geom_obj.Shape = j.Shape.CompSolids[0]
if FreeCAD.GuiUp:
j.ViewObject.hide()
@@ -142,33 +142,33 @@ def setup(doc=None, solvertype="ccxtools"):
analysis.addObject(solver_obj)
# material
material_obj1 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial1')
material_obj1 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial1")
material_obj1.References = [(doc.Box3, "Solid1")]
mat = material_obj1.Material
mat['Name'] = "Concrete-Generic"
mat['YoungsModulus'] = "32000 MPa"
mat['PoissonRatio'] = "0.17"
mat['Density'] = "0 kg/m^3"
mat["Name"] = "Concrete-Generic"
mat["YoungsModulus"] = "32000 MPa"
mat["PoissonRatio"] = "0.17"
mat["Density"] = "0 kg/m^3"
material_obj1.Material = mat
analysis.addObject(material_obj1)
material_obj2 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial2')
material_obj2 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial2")
material_obj2.References = [(doc.Box2, "Solid1"), (doc.Box4, "Solid1")]
mat = material_obj2.Material
mat['Name'] = "PLA"
mat['YoungsModulus'] = "3640 MPa"
mat['PoissonRatio'] = "0.36"
mat['Density'] = "0 kg/m^3"
mat["Name"] = "PLA"
mat["YoungsModulus"] = "3640 MPa"
mat["PoissonRatio"] = "0.36"
mat["Density"] = "0 kg/m^3"
material_obj2.Material = mat
analysis.addObject(material_obj2)
material_obj3 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial3')
material_obj3 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial3")
material_obj3.References = []
mat = material_obj3.Material
mat['Name'] = "Steel-Generic"
mat['YoungsModulus'] = "200000 MPa"
mat['PoissonRatio'] = "0.30"
mat['Density'] = "7900 kg/m^3"
mat["Name"] = "Steel-Generic"
mat["YoungsModulus"] = "200000 MPa"
mat["PoissonRatio"] = "0.30"
mat["Density"] = "7900 kg/m^3"
material_obj3.Material = mat
analysis.addObject(material_obj3)

View File

@@ -71,22 +71,22 @@ def setup(doc=None, solvertype="ccxtools"):
# geometric objects
# name is important because the other method in this module use obj name
# parts
face_obj1 = doc.addObject('Part::Plane', 'Face1')
face_obj1 = doc.addObject("Part::Plane", "Face1")
face_obj1.Width = 10
face_obj1.Length = 20
face_obj2 = doc.addObject('Part::Plane', 'Face2')
face_obj2 = doc.addObject("Part::Plane", "Face2")
face_obj2.Width = 10
face_obj2.Length = 20
face_obj2.Placement.Base = (20, 0, 0)
face_obj3 = doc.addObject('Part::Plane', 'Face3')
face_obj3 = doc.addObject("Part::Plane", "Face3")
face_obj3.Width = 10
face_obj3.Length = 20
face_obj3.Placement.Base = (40, 0, 0)
face_obj4 = doc.addObject('Part::Plane', 'Face4')
face_obj4 = doc.addObject("Part::Plane", "Face4")
face_obj4.Width = 10
face_obj4.Length = 20
face_obj4.Placement.Base = (60, 0, 0)
face_obj5 = doc.addObject('Part::Plane', 'Face5')
face_obj5 = doc.addObject("Part::Plane", "Face5")
face_obj5.Width = 10
face_obj5.Length = 20
face_obj5.Placement.Base = (80, 0, 0)
@@ -131,40 +131,40 @@ def setup(doc=None, solvertype="ccxtools"):
analysis.addObject(solver_obj)
# shell thickness
thickness_obj = ObjectsFem.makeElementGeometry2D(doc, 10, 'ShellThickness')
thickness_obj = ObjectsFem.makeElementGeometry2D(doc, 10, "ShellThickness")
analysis.addObject(thickness_obj)
# materials
material_obj1 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial1')
material_obj1 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial1")
material_obj1.References = [(doc.Face3, "Face1")]
mat = material_obj1.Material
mat['Name'] = "Concrete-Generic"
mat['YoungsModulus'] = "32000 MPa"
mat['PoissonRatio'] = "0.17"
mat['Density'] = "0 kg/m^3"
mat["Name"] = "Concrete-Generic"
mat["YoungsModulus"] = "32000 MPa"
mat["PoissonRatio"] = "0.17"
mat["Density"] = "0 kg/m^3"
material_obj1.Material = mat
analysis.addObject(material_obj1)
material_obj2 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial2')
material_obj2 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial2")
material_obj2.References = [
(doc.Face2, "Face1"),
(doc.Face4, "Face1")
]
mat = material_obj2.Material
mat['Name'] = "PLA"
mat['YoungsModulus'] = "3640 MPa"
mat['PoissonRatio'] = "0.36"
mat['Density'] = "0 kg/m^3"
mat["Name"] = "PLA"
mat["YoungsModulus"] = "3640 MPa"
mat["PoissonRatio"] = "0.36"
mat["Density"] = "0 kg/m^3"
material_obj2.Material = mat
analysis.addObject(material_obj2)
material_obj3 = ObjectsFem.makeMaterialSolid(doc, 'FemMaterial3')
material_obj3 = ObjectsFem.makeMaterialSolid(doc, "FemMaterial3")
material_obj3.References = []
mat = material_obj3.Material
mat['Name'] = "Steel-Generic"
mat['YoungsModulus'] = "200000 MPa"
mat['PoissonRatio'] = "0.30"
mat['Density'] = "7900 kg/m^3"
mat["Name"] = "Steel-Generic"
mat["YoungsModulus"] = "200000 MPa"
mat["PoissonRatio"] = "0.30"
mat["Density"] = "7900 kg/m^3"
material_obj3.Material = mat
analysis.addObject(material_obj3)

View File

@@ -0,0 +1,117 @@
def create_nodes(femmesh):
# nodes
femmesh.addNode(0.0, 500.0, 500.0, 1)
femmesh.addNode(8000.0, 500.0, 500.0, 2)
femmesh.addNode(148.14814814814792, 500.0, 500.0, 3)
femmesh.addNode(296.29629629629585, 500.0, 500.0, 4)
femmesh.addNode(444.4444444444438, 500.0, 500.0, 5)
femmesh.addNode(592.5925925925918, 500.0, 500.0, 6)
femmesh.addNode(740.7407407407396, 500.0, 500.0, 7)
femmesh.addNode(888.8888888888874, 500.0, 500.0, 8)
femmesh.addNode(1037.0370370370354, 500.0, 500.0, 9)
femmesh.addNode(1185.1851851851832, 500.0, 500.0, 10)
femmesh.addNode(1333.333333333331, 500.0, 500.0, 11)
femmesh.addNode(1481.4814814814792, 500.0, 500.0, 12)
femmesh.addNode(1629.6296296296275, 500.0, 500.0, 13)
femmesh.addNode(1777.7777777777753, 500.0, 500.0, 14)
femmesh.addNode(1925.9259259259236, 500.0, 500.0, 15)
femmesh.addNode(2074.0740740740716, 500.0, 500.0, 16)
femmesh.addNode(2222.22222222222, 500.0, 500.0, 17)
femmesh.addNode(2370.370370370368, 500.0, 500.0, 18)
femmesh.addNode(2518.5185185185155, 500.0, 500.0, 19)
femmesh.addNode(2666.666666666663, 500.0, 500.0, 20)
femmesh.addNode(2814.8148148148107, 500.0, 500.0, 21)
femmesh.addNode(2962.962962962958, 500.0, 500.0, 22)
femmesh.addNode(3111.1111111111054, 500.0, 500.0, 23)
femmesh.addNode(3259.259259259253, 500.0, 500.0, 24)
femmesh.addNode(3407.4074074074006, 500.0, 500.0, 25)
femmesh.addNode(3555.555555555548, 500.0, 500.0, 26)
femmesh.addNode(3703.7037037036957, 500.0, 500.0, 27)
femmesh.addNode(3851.851851851843, 500.0, 500.0, 28)
femmesh.addNode(3999.9999999999905, 500.0, 500.0, 29)
femmesh.addNode(4148.148148148138, 500.0, 500.0, 30)
femmesh.addNode(4296.296296296286, 500.0, 500.0, 31)
femmesh.addNode(4444.4444444444325, 500.0, 500.0, 32)
femmesh.addNode(4592.59259259258, 500.0, 500.0, 33)
femmesh.addNode(4740.740740740728, 500.0, 500.0, 34)
femmesh.addNode(4888.888888888877, 500.0, 500.0, 35)
femmesh.addNode(5037.037037037026, 500.0, 500.0, 36)
femmesh.addNode(5185.185185185173, 500.0, 500.0, 37)
femmesh.addNode(5333.333333333322, 500.0, 500.0, 38)
femmesh.addNode(5481.481481481471, 500.0, 500.0, 39)
femmesh.addNode(5629.6296296296205, 500.0, 500.0, 40)
femmesh.addNode(5777.777777777769, 500.0, 500.0, 41)
femmesh.addNode(5925.925925925918, 500.0, 500.0, 42)
femmesh.addNode(6074.074074074067, 500.0, 500.0, 43)
femmesh.addNode(6222.222222222214, 500.0, 500.0, 44)
femmesh.addNode(6370.370370370363, 500.0, 500.0, 45)
femmesh.addNode(6518.518518518513, 500.0, 500.0, 46)
femmesh.addNode(6666.6666666666615, 500.0, 500.0, 47)
femmesh.addNode(6814.81481481481, 500.0, 500.0, 48)
femmesh.addNode(6962.962962962959, 500.0, 500.0, 49)
femmesh.addNode(7111.111111111108, 500.0, 500.0, 50)
femmesh.addNode(7259.259259259256, 500.0, 500.0, 51)
femmesh.addNode(7407.407407407406, 500.0, 500.0, 52)
femmesh.addNode(7555.555555555554, 500.0, 500.0, 53)
femmesh.addNode(7703.703703703703, 500.0, 500.0, 54)
femmesh.addNode(7851.851851851851, 500.0, 500.0, 55)
return True
def create_elements(femmesh):
# elements
femmesh.addEdge([1, 3], 1)
femmesh.addEdge([3, 4], 2)
femmesh.addEdge([4, 5], 3)
femmesh.addEdge([5, 6], 4)
femmesh.addEdge([6, 7], 5)
femmesh.addEdge([7, 8], 6)
femmesh.addEdge([8, 9], 7)
femmesh.addEdge([9, 10], 8)
femmesh.addEdge([10, 11], 9)
femmesh.addEdge([11, 12], 10)
femmesh.addEdge([12, 13], 11)
femmesh.addEdge([13, 14], 12)
femmesh.addEdge([14, 15], 13)
femmesh.addEdge([15, 16], 14)
femmesh.addEdge([16, 17], 15)
femmesh.addEdge([17, 18], 16)
femmesh.addEdge([18, 19], 17)
femmesh.addEdge([19, 20], 18)
femmesh.addEdge([20, 21], 19)
femmesh.addEdge([21, 22], 20)
femmesh.addEdge([22, 23], 21)
femmesh.addEdge([23, 24], 22)
femmesh.addEdge([24, 25], 23)
femmesh.addEdge([25, 26], 24)
femmesh.addEdge([26, 27], 25)
femmesh.addEdge([27, 28], 26)
femmesh.addEdge([28, 29], 27)
femmesh.addEdge([29, 30], 28)
femmesh.addEdge([30, 31], 29)
femmesh.addEdge([31, 32], 30)
femmesh.addEdge([32, 33], 31)
femmesh.addEdge([33, 34], 32)
femmesh.addEdge([34, 35], 33)
femmesh.addEdge([35, 36], 34)
femmesh.addEdge([36, 37], 35)
femmesh.addEdge([37, 38], 36)
femmesh.addEdge([38, 39], 37)
femmesh.addEdge([39, 40], 38)
femmesh.addEdge([40, 41], 39)
femmesh.addEdge([41, 42], 40)
femmesh.addEdge([42, 43], 41)
femmesh.addEdge([43, 44], 42)
femmesh.addEdge([44, 45], 43)
femmesh.addEdge([45, 46], 44)
femmesh.addEdge([46, 47], 45)
femmesh.addEdge([47, 48], 46)
femmesh.addEdge([48, 49], 47)
femmesh.addEdge([49, 50], 48)
femmesh.addEdge([50, 51], 49)
femmesh.addEdge([51, 52], 50)
femmesh.addEdge([52, 53], 51)
femmesh.addEdge([53, 54], 52)
femmesh.addEdge([54, 55], 53)
femmesh.addEdge([55, 2], 54)
return True

View File

@@ -0,0 +1,24 @@
def create_nodes(femmesh):
# nodes
femmesh.addNode(0.0, 500.0, 500.0, 1)
femmesh.addNode(8000.0, 500.0, 500.0, 2)
femmesh.addNode(1600.0000000000023, 500.0, 500.0, 3)
femmesh.addNode(3200.000000000006, 500.0, 500.0, 4)
femmesh.addNode(4800.000000000003, 500.0, 500.0, 5)
femmesh.addNode(6399.999999999996, 500.0, 500.0, 6)
femmesh.addNode(800.0000000000011, 500.0, 500.0, 7)
femmesh.addNode(2400.000000000004, 500.0, 500.0, 8)
femmesh.addNode(4000.0000000000045, 500.0, 500.0, 9)
femmesh.addNode(5599.999999999999, 500.0, 500.0, 10)
femmesh.addNode(7199.999999999998, 500.0, 500.0, 11)
return True
def create_elements(femmesh):
# elements
femmesh.addEdge([1, 3, 7], 1)
femmesh.addEdge([3, 4, 8], 2)
femmesh.addEdge([4, 5, 9], 3)
femmesh.addEdge([5, 6, 10], 4)
femmesh.addEdge([6, 2, 11], 5)
return True

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,255 @@
def create_nodes(femmesh):
# nodes
femmesh.addNode(0.0, 500.0, 0.0, 1)
femmesh.addNode(0.0, 500.00000000000324, 1000.0, 2)
femmesh.addNode(8000.0, 500.0, 0.0, 3)
femmesh.addNode(8000.0, 500.00000000000324, 1000.0, 4)
femmesh.addNode(0.0, 500.0000000000001, 500.0, 5)
femmesh.addNode(0.0, 500.00000000000006, 250.0, 6)
femmesh.addNode(0.0, 500.00000000000017, 750.0, 7)
femmesh.addNode(500.0, 500.0, 0.0, 8)
femmesh.addNode(1000.0, 500.0, 0.0, 9)
femmesh.addNode(1500.0, 500.0, 0.0, 10)
femmesh.addNode(2000.0, 500.0, 0.0, 11)
femmesh.addNode(2500.0, 500.0, 0.0, 12)
femmesh.addNode(3000.0, 500.0, 0.0, 13)
femmesh.addNode(3500.0, 500.0, 0.0, 14)
femmesh.addNode(4000.0, 500.0, 0.0, 15)
femmesh.addNode(4500.0, 500.0, 0.0, 16)
femmesh.addNode(5000.0, 500.0, 0.0, 17)
femmesh.addNode(5500.0, 500.0, 0.0, 18)
femmesh.addNode(6000.0, 500.0, 0.0, 19)
femmesh.addNode(6500.0, 500.0, 0.0, 20)
femmesh.addNode(7000.0, 500.0, 0.0, 21)
femmesh.addNode(7500.0, 500.0, 0.0, 22)
femmesh.addNode(250.0, 500.0, 0.0, 23)
femmesh.addNode(750.0, 500.0, 0.0, 24)
femmesh.addNode(1250.0, 500.0, 0.0, 25)
femmesh.addNode(1750.0, 500.0, 0.0, 26)
femmesh.addNode(2250.0, 500.0, 0.0, 27)
femmesh.addNode(2750.0, 500.0, 0.0, 28)
femmesh.addNode(3250.0, 500.0, 0.0, 29)
femmesh.addNode(3750.0, 500.0, 0.0, 30)
femmesh.addNode(4250.0, 500.0, 0.0, 31)
femmesh.addNode(4750.0, 500.0, 0.0, 32)
femmesh.addNode(5250.0, 500.0, 0.0, 33)
femmesh.addNode(5750.0, 500.0, 0.0, 34)
femmesh.addNode(6250.0, 500.0, 0.0, 35)
femmesh.addNode(6750.0, 500.0, 0.0, 36)
femmesh.addNode(7250.0, 500.0, 0.0, 37)
femmesh.addNode(7750.0, 500.0, 0.0, 38)
femmesh.addNode(8000.0, 500.0000000000001, 500.0, 39)
femmesh.addNode(8000.0, 500.00000000000006, 250.0, 40)
femmesh.addNode(8000.0, 500.00000000000017, 750.0, 41)
femmesh.addNode(500.0, 500.0000000000002, 1000.0, 42)
femmesh.addNode(1000.0, 500.0000000000002, 1000.0, 43)
femmesh.addNode(1500.0, 500.0000000000002, 1000.0, 44)
femmesh.addNode(2000.0, 500.0000000000002, 1000.0, 45)
femmesh.addNode(2500.0, 500.0000000000002, 1000.0, 46)
femmesh.addNode(3000.0, 500.0000000000002, 1000.0, 47)
femmesh.addNode(3500.0, 500.0000000000002, 1000.0, 48)
femmesh.addNode(4000.0, 500.0000000000002, 1000.0, 49)
femmesh.addNode(4500.0, 500.0000000000002, 1000.0, 50)
femmesh.addNode(5000.0, 500.0000000000002, 1000.0, 51)
femmesh.addNode(5500.0, 500.0000000000002, 1000.0, 52)
femmesh.addNode(6000.0, 500.0000000000002, 1000.0, 53)
femmesh.addNode(6500.0, 500.0000000000002, 1000.0, 54)
femmesh.addNode(7000.0, 500.0000000000002, 1000.0, 55)
femmesh.addNode(7500.0, 500.0000000000002, 1000.0, 56)
femmesh.addNode(250.0, 500.0000000000002, 1000.0, 57)
femmesh.addNode(750.0, 500.0000000000002, 1000.0, 58)
femmesh.addNode(1250.0, 500.0000000000002, 1000.0, 59)
femmesh.addNode(1750.0, 500.0000000000002, 1000.0, 60)
femmesh.addNode(2250.0, 500.0000000000002, 1000.0, 61)
femmesh.addNode(2750.0, 500.0000000000002, 1000.0, 62)
femmesh.addNode(3250.0, 500.0000000000002, 1000.0, 63)
femmesh.addNode(3750.0, 500.0000000000002, 1000.0, 64)
femmesh.addNode(4250.0, 500.0000000000002, 1000.0, 65)
femmesh.addNode(4750.0, 500.0000000000002, 1000.0, 66)
femmesh.addNode(5250.0, 500.0000000000002, 1000.0, 67)
femmesh.addNode(5750.0, 500.0000000000002, 1000.0, 68)
femmesh.addNode(6250.0, 500.0000000000002, 1000.0, 69)
femmesh.addNode(6750.0, 500.0000000000002, 1000.0, 70)
femmesh.addNode(7250.0, 500.0000000000002, 1000.0, 71)
femmesh.addNode(7750.0, 500.0000000000002, 1000.0, 72)
femmesh.addNode(714.9234693877551, 500.0000000000001, 484.05612244897964, 73)
femmesh.addNode(1750.0, 500.0000000000001, 500.0, 74)
femmesh.addNode(2750.0, 500.0000000000001, 500.0, 75)
femmesh.addNode(3750.0, 500.0000000000001, 500.0, 76)
femmesh.addNode(4750.0, 500.0000000000001, 500.0, 77)
femmesh.addNode(5750.0, 500.0000000000001, 500.0, 78)
femmesh.addNode(6756.944444444443, 500.0000000000001, 489.5833333333333, 79)
femmesh.addNode(7301.463293650793, 500.0000000000001, 489.7073412698406, 80)
femmesh.addNode(1244.1539115646258, 500.0000000000001, 497.34268707482994, 81)
femmesh.addNode(2250.0, 500.0000000000001, 500.0, 82)
femmesh.addNode(3250.0, 500.0000000000001, 500.0, 83)
femmesh.addNode(4250.0, 500.0000000000001, 500.0, 84)
femmesh.addNode(5250.0, 500.0000000000001, 500.0, 85)
femmesh.addNode(6251.157407407407, 500.0000000000001, 498.2638888888889, 86)
femmesh.addNode(355.2776691684587, 500.0000000000001, 632.304566974645, 87)
femmesh.addNode(7660.398197179746, 500.00000000000017, 648.5965255878823, 88)
femmesh.addNode(7699.764777975907, 500.00000000000006, 310.456176890242, 89)
femmesh.addNode(314.0402277112428, 500.00000000000006, 323.27213788472494, 90)
femmesh.addNode(1122.0769557823128, 500.00000000000017, 748.6713435374149, 91)
femmesh.addNode(1372.0769557823128, 500.00000000000017, 748.6713435374149, 92)
femmesh.addNode(2125.0, 500.00000000000017, 750.0, 93)
femmesh.addNode(2375.0, 500.00000000000017, 750.0, 94)
femmesh.addNode(3125.0, 500.00000000000017, 750.0, 95)
femmesh.addNode(3375.0, 500.00000000000017, 750.0, 96)
femmesh.addNode(4125.0, 500.00000000000017, 750.0, 97)
femmesh.addNode(4375.0, 500.00000000000017, 750.0, 98)
femmesh.addNode(5125.0, 500.00000000000017, 750.0, 99)
femmesh.addNode(5375.0, 500.00000000000017, 750.0, 100)
femmesh.addNode(6125.5787037037035, 500.00000000000017, 749.1319444444445, 101)
femmesh.addNode(6375.5787037037035, 500.00000000000017, 749.1319444444445, 102)
femmesh.addNode(857.4617346938776, 500.00000000000017, 742.0280612244899, 103)
femmesh.addNode(979.5386904761904, 500.0000000000001, 490.6994047619048, 104)
femmesh.addNode(1497.0769557823128, 500.0000000000001, 498.67134353741494, 105)
femmesh.addNode(1625.0, 500.00000000000017, 750.0, 106)
femmesh.addNode(1875.0, 500.00000000000017, 750.0, 107)
femmesh.addNode(2000.0, 500.0000000000001, 500.0, 108)
femmesh.addNode(2500.0, 500.0000000000001, 500.0, 109)
femmesh.addNode(2625.0, 500.00000000000017, 750.0, 110)
femmesh.addNode(2875.0, 500.00000000000017, 750.0, 111)
femmesh.addNode(3000.0, 500.0000000000001, 500.0, 112)
femmesh.addNode(3500.0, 500.0000000000001, 500.0, 113)
femmesh.addNode(3625.0, 500.00000000000017, 750.0, 114)
femmesh.addNode(3875.0, 500.00000000000017, 750.0, 115)
femmesh.addNode(4000.0, 500.0000000000001, 500.0, 116)
femmesh.addNode(4500.0, 500.0000000000001, 500.0, 117)
femmesh.addNode(4625.0, 500.00000000000017, 750.0, 118)
femmesh.addNode(4875.0, 500.00000000000017, 750.0, 119)
femmesh.addNode(5000.0, 500.0000000000001, 500.0, 120)
femmesh.addNode(5500.0, 500.0000000000001, 500.0, 121)
femmesh.addNode(5625.0, 500.00000000000017, 750.0, 122)
femmesh.addNode(5875.0, 500.00000000000017, 750.0, 123)
femmesh.addNode(6000.5787037037035, 500.0000000000001, 499.13194444444446, 124)
femmesh.addNode(6504.050925925925, 500.0000000000001, 493.9236111111111, 125)
femmesh.addNode(6628.472222222222, 500.00000000000017, 744.7916666666666, 126)
femmesh.addNode(7150.731646825397, 500.00000000000006, 244.8536706349203, 127)
femmesh.addNode(7029.203869047618, 500.0000000000001, 489.64533730158695, 128)
femmesh.addNode(6878.472222222222, 500.00000000000006, 244.79166666666666, 129)
femmesh.addNode(6878.472222222222, 500.00000000000017, 744.7916666666666, 130)
femmesh.addNode(7150.731646825397, 500.00000000000017, 744.8536706349203, 131)
femmesh.addNode(7400.731646825397, 500.00000000000006, 244.8536706349203, 132)
femmesh.addNode(7400.731646825397, 500.00000000000017, 744.8536706349203, 133)
femmesh.addNode(857.4617346938776, 500.00000000000006, 242.02806122448982, 134)
femmesh.addNode(607.4617346938776, 500.00000000000006, 242.02806122448982, 135)
femmesh.addNode(1875.0, 500.00000000000006, 250.0, 136)
femmesh.addNode(1625.0, 500.00000000000006, 250.0, 137)
femmesh.addNode(2875.0, 500.00000000000006, 250.0, 138)
femmesh.addNode(2625.0, 500.00000000000006, 250.0, 139)
femmesh.addNode(3875.0, 500.00000000000006, 250.0, 140)
femmesh.addNode(3625.0, 500.00000000000006, 250.0, 141)
femmesh.addNode(4875.0, 500.00000000000006, 250.0, 142)
femmesh.addNode(4625.0, 500.00000000000006, 250.0, 143)
femmesh.addNode(5875.0, 500.00000000000006, 250.0, 144)
femmesh.addNode(5625.0, 500.00000000000006, 250.0, 145)
femmesh.addNode(6628.472222222222, 500.00000000000006, 244.79166666666666, 146)
femmesh.addNode(607.4617346938776, 500.00000000000017, 742.0280612244899, 147)
femmesh.addNode(1122.0769557823128, 500.00000000000006, 248.67134353741497, 148)
femmesh.addNode(1372.0769557823128, 500.00000000000006, 248.67134353741497, 149)
femmesh.addNode(2125.0, 500.00000000000006, 250.0, 150)
femmesh.addNode(2375.0, 500.00000000000006, 250.0, 151)
femmesh.addNode(3125.0, 500.00000000000006, 250.0, 152)
femmesh.addNode(3375.0, 500.00000000000006, 250.0, 153)
femmesh.addNode(4125.0, 500.00000000000006, 250.0, 154)
femmesh.addNode(4375.0, 500.00000000000006, 250.0, 155)
femmesh.addNode(5125.0, 500.00000000000006, 250.0, 156)
femmesh.addNode(5375.0, 500.00000000000006, 250.0, 157)
femmesh.addNode(6125.5787037037035, 500.00000000000006, 249.13194444444446, 158)
femmesh.addNode(6375.5787037037035, 500.00000000000006, 249.13194444444446, 159)
femmesh.addNode(514.4818485494989, 500.0000000000001, 403.66413016685226, 160)
femmesh.addNode(407.0201138556214, 500.00000000000006, 161.63606894236247, 161)
femmesh.addNode(177.63883458422936, 500.0000000000001, 566.1522834873225, 162)
femmesh.addNode(177.63883458422936, 500.00000000000017, 816.1522834873225, 163)
femmesh.addNode(427.63883458422936, 500.00000000000017, 816.1522834873225, 164)
femmesh.addNode(535.1005692781068, 500.0000000000001, 558.1803447118123, 165)
femmesh.addNode(7599.882388987953, 500.00000000000006, 155.228088445121, 166)
femmesh.addNode(7500.614035813351, 500.0000000000001, 400.08175908004125, 167)
femmesh.addNode(7830.199098589873, 500.00000000000017, 824.2982627939411, 168)
femmesh.addNode(7830.199098589873, 500.0000000000001, 574.2982627939411, 169)
femmesh.addNode(7580.199098589873, 500.00000000000017, 824.2982627939411, 170)
femmesh.addNode(7480.9307454152695, 500.0000000000001, 569.1519334288614, 171)
femmesh.addNode(334.65894843985075, 500.0000000000001, 477.788352429685, 172)
femmesh.addNode(7849.882388987953, 500.0000000000001, 405.228088445121, 173)
femmesh.addNode(7849.882388987953, 500.00000000000006, 155.228088445121, 174)
femmesh.addNode(157.0201138556214, 500.00000000000006, 161.63606894236247, 175)
femmesh.addNode(157.0201138556214, 500.0000000000001, 411.6360689423625, 176)
femmesh.addNode(7680.081487577827, 500.0000000000001, 479.52635123906214, 177)
return True
def create_elements(femmesh):
# elements
femmesh.addFace([43, 81, 44, 91, 92, 59], 37)
femmesh.addFace([45, 82, 46, 93, 94, 61], 38)
femmesh.addFace([47, 83, 48, 95, 96, 63], 39)
femmesh.addFace([49, 84, 50, 97, 98, 65], 40)
femmesh.addFace([51, 85, 52, 99, 100, 67], 41)
femmesh.addFace([53, 86, 54, 101, 102, 69], 42)
femmesh.addFace([43, 73, 81, 103, 104, 91], 43)
femmesh.addFace([44, 81, 74, 92, 105, 106], 44)
femmesh.addFace([45, 74, 82, 107, 108, 93], 45)
femmesh.addFace([46, 82, 75, 94, 109, 110], 46)
femmesh.addFace([47, 75, 83, 111, 112, 95], 47)
femmesh.addFace([48, 83, 76, 96, 113, 114], 48)
femmesh.addFace([49, 76, 84, 115, 116, 97], 49)
femmesh.addFace([50, 84, 77, 98, 117, 118], 50)
femmesh.addFace([51, 77, 85, 119, 120, 99], 51)
femmesh.addFace([52, 85, 78, 100, 121, 122], 52)
femmesh.addFace([53, 78, 86, 123, 124, 101], 53)
femmesh.addFace([54, 86, 79, 102, 125, 126], 54)
femmesh.addFace([21, 80, 79, 127, 128, 129], 55)
femmesh.addFace([55, 79, 80, 130, 128, 131], 56)
femmesh.addFace([21, 22, 80, 37, 132, 127], 57)
femmesh.addFace([55, 80, 56, 131, 133, 71], 58)
femmesh.addFace([8, 9, 73, 24, 134, 135], 59)
femmesh.addFace([10, 11, 74, 26, 136, 137], 60)
femmesh.addFace([12, 13, 75, 28, 138, 139], 61)
femmesh.addFace([14, 15, 76, 30, 140, 141], 62)
femmesh.addFace([16, 17, 77, 32, 142, 143], 63)
femmesh.addFace([18, 19, 78, 34, 144, 145], 64)
femmesh.addFace([20, 21, 79, 36, 129, 146], 65)
femmesh.addFace([42, 73, 43, 147, 103, 58], 66)
femmesh.addFace([44, 74, 45, 106, 107, 60], 67)
femmesh.addFace([46, 75, 47, 110, 111, 62], 68)
femmesh.addFace([48, 76, 49, 114, 115, 64], 69)
femmesh.addFace([50, 77, 51, 118, 119, 66], 70)
femmesh.addFace([52, 78, 53, 122, 123, 68], 71)
femmesh.addFace([54, 79, 55, 126, 130, 70], 72)
femmesh.addFace([9, 81, 73, 148, 104, 134], 73)
femmesh.addFace([10, 74, 81, 137, 105, 149], 74)
femmesh.addFace([11, 82, 74, 150, 108, 136], 75)
femmesh.addFace([12, 75, 82, 139, 109, 151], 76)
femmesh.addFace([13, 83, 75, 152, 112, 138], 77)
femmesh.addFace([14, 76, 83, 141, 113, 153], 78)
femmesh.addFace([15, 84, 76, 154, 116, 140], 79)
femmesh.addFace([16, 77, 84, 143, 117, 155], 80)
femmesh.addFace([17, 85, 77, 156, 120, 142], 81)
femmesh.addFace([18, 78, 85, 145, 121, 157], 82)
femmesh.addFace([19, 86, 78, 158, 124, 144], 83)
femmesh.addFace([20, 79, 86, 146, 125, 159], 84)
femmesh.addFace([9, 10, 81, 25, 149, 148], 85)
femmesh.addFace([11, 12, 82, 27, 151, 150], 86)
femmesh.addFace([13, 14, 83, 29, 153, 152], 87)
femmesh.addFace([15, 16, 84, 31, 155, 154], 88)
femmesh.addFace([17, 18, 85, 33, 157, 156], 89)
femmesh.addFace([19, 20, 86, 35, 159, 158], 90)
femmesh.addFace([8, 73, 90, 135, 160, 161], 91)
femmesh.addFace([2, 5, 87, 7, 162, 163], 92)
femmesh.addFace([2, 87, 42, 163, 164, 57], 93)
femmesh.addFace([42, 87, 73, 164, 165, 147], 94)
femmesh.addFace([22, 89, 80, 166, 167, 132], 95)
femmesh.addFace([4, 88, 39, 168, 169, 41], 96)
femmesh.addFace([4, 56, 88, 72, 170, 168], 97)
femmesh.addFace([56, 80, 88, 133, 171, 170], 98)
femmesh.addFace([73, 87, 90, 165, 172, 160], 99)
femmesh.addFace([3, 39, 89, 40, 173, 174], 100)
femmesh.addFace([3, 89, 22, 174, 166, 38], 101)
femmesh.addFace([1, 90, 5, 175, 176, 6], 102)
femmesh.addFace([1, 8, 90, 23, 161, 175], 103)
femmesh.addFace([80, 89, 88, 167, 177, 171], 104)
femmesh.addFace([5, 90, 87, 176, 172, 162], 105)
femmesh.addFace([39, 88, 89, 169, 177, 173], 106)
return True

View File

@@ -79,7 +79,7 @@ def setup(doc=None, solvertype="ccxtools"):
l4 = Part.makeLine((-142.5, 142.5, 0), (-142.5, -142.5, 0))
wire = Part.Wire([l1, l2, l3, l4])
shape = wire.extrude(Vector(0, 0, 1000))
geom_obj = doc.addObject('Part::Feature', 'SquareTube')
geom_obj = doc.addObject("Part::Feature", "SquareTube")
geom_obj.Shape = shape
doc.recompute()

View File

@@ -79,7 +79,7 @@ def setup(doc=None, solvertype="ccxtools"):
l4 = Part.makeLine((-142.5, 142.5, 0), (-142.5, -142.5, 0))
wire = Part.Wire([l1, l2, l3, l4])
shape = wire.extrude(Vector(0, 0, 1000))
geom_obj = doc.addObject('Part::Feature', 'SquareTube')
geom_obj = doc.addObject("Part::Feature", "SquareTube")
geom_obj.Shape = shape
points_forces = []
@@ -182,9 +182,9 @@ def setup(doc=None, solvertype="ccxtools"):
points_fixes.append(Part.Vertex(-71.25, 142.5, 1000.0))
points_fixes.append(Part.Vertex(-118.75, 142.5, 1000.0))
geoforces_obj = doc.addObject('Part::Feature', 'Forces')
geoforces_obj = doc.addObject("Part::Feature", "Forces")
geoforces_obj.Shape = Part.makeCompound(points_forces)
geofixes_obj = doc.addObject('Part::Feature', 'Fixes')
geofixes_obj = doc.addObject("Part::Feature", "Fixes")
geofixes_obj.Shape = Part.makeCompound(points_fixes)
doc.recompute()
@@ -237,59 +237,59 @@ def setup(doc=None, solvertype="ccxtools"):
# constraint fixed
con_fixed = ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed")
con_fixed.References = [
(geofixes_obj, 'Vertex6'),
(geofixes_obj, 'Vertex15'),
(geofixes_obj, 'Vertex5'),
(geofixes_obj, 'Vertex29'),
(geofixes_obj, 'Vertex42'),
(geofixes_obj, 'Vertex30'),
(geofixes_obj, 'Vertex9'),
(geofixes_obj, 'Vertex31'),
(geofixes_obj, 'Vertex33'),
(geofixes_obj, 'Vertex32'),
(geofixes_obj, 'Vertex3'),
(geofixes_obj, 'Vertex34'),
(geofixes_obj, 'Vertex46'),
(geofixes_obj, 'Vertex1'),
(geofixes_obj, 'Vertex36'),
(geofixes_obj, 'Vertex11'),
(geofixes_obj, 'Vertex38'),
(geofixes_obj, 'Vertex12'),
(geofixes_obj, 'Vertex39'),
(geofixes_obj, 'Vertex13'),
(geofixes_obj, 'Vertex40'),
(geofixes_obj, 'Vertex16'),
(geofixes_obj, 'Vertex35'),
(geofixes_obj, 'Vertex14'),
(geofixes_obj, 'Vertex47'),
(geofixes_obj, 'Vertex20'),
(geofixes_obj, 'Vertex37'),
(geofixes_obj, 'Vertex18'),
(geofixes_obj, 'Vertex41'),
(geofixes_obj, 'Vertex17'),
(geofixes_obj, 'Vertex10'),
(geofixes_obj, 'Vertex26'),
(geofixes_obj, 'Vertex43'),
(geofixes_obj, 'Vertex21'),
(geofixes_obj, 'Vertex44'),
(geofixes_obj, 'Vertex19'),
(geofixes_obj, 'Vertex4'),
(geofixes_obj, 'Vertex28'),
(geofixes_obj, 'Vertex48'),
(geofixes_obj, 'Vertex22'),
(geofixes_obj, 'Vertex8'),
(geofixes_obj, 'Vertex23'),
(geofixes_obj, 'Vertex7'),
(geofixes_obj, 'Vertex24'),
(geofixes_obj, 'Vertex45'),
(geofixes_obj, 'Vertex27'),
(geofixes_obj, 'Vertex2'),
(geofixes_obj, 'Vertex25')]
(geofixes_obj, "Vertex6"),
(geofixes_obj, "Vertex15"),
(geofixes_obj, "Vertex5"),
(geofixes_obj, "Vertex29"),
(geofixes_obj, "Vertex42"),
(geofixes_obj, "Vertex30"),
(geofixes_obj, "Vertex9"),
(geofixes_obj, "Vertex31"),
(geofixes_obj, "Vertex33"),
(geofixes_obj, "Vertex32"),
(geofixes_obj, "Vertex3"),
(geofixes_obj, "Vertex34"),
(geofixes_obj, "Vertex46"),
(geofixes_obj, "Vertex1"),
(geofixes_obj, "Vertex36"),
(geofixes_obj, "Vertex11"),
(geofixes_obj, "Vertex38"),
(geofixes_obj, "Vertex12"),
(geofixes_obj, "Vertex39"),
(geofixes_obj, "Vertex13"),
(geofixes_obj, "Vertex40"),
(geofixes_obj, "Vertex16"),
(geofixes_obj, "Vertex35"),
(geofixes_obj, "Vertex14"),
(geofixes_obj, "Vertex47"),
(geofixes_obj, "Vertex20"),
(geofixes_obj, "Vertex37"),
(geofixes_obj, "Vertex18"),
(geofixes_obj, "Vertex41"),
(geofixes_obj, "Vertex17"),
(geofixes_obj, "Vertex10"),
(geofixes_obj, "Vertex26"),
(geofixes_obj, "Vertex43"),
(geofixes_obj, "Vertex21"),
(geofixes_obj, "Vertex44"),
(geofixes_obj, "Vertex19"),
(geofixes_obj, "Vertex4"),
(geofixes_obj, "Vertex28"),
(geofixes_obj, "Vertex48"),
(geofixes_obj, "Vertex22"),
(geofixes_obj, "Vertex8"),
(geofixes_obj, "Vertex23"),
(geofixes_obj, "Vertex7"),
(geofixes_obj, "Vertex24"),
(geofixes_obj, "Vertex45"),
(geofixes_obj, "Vertex27"),
(geofixes_obj, "Vertex2"),
(geofixes_obj, "Vertex25")]
analysis.addObject(con_fixed)
# con_force1
con_force1 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce1")
con_force1.References = [(geoforces_obj, 'Vertex1'), (geoforces_obj, 'Vertex14')]
con_force1.References = [(geoforces_obj, "Vertex1"), (geoforces_obj, "Vertex14")]
con_force1.Force = 5555.56
con_force1.Direction = (geom_obj, ["Edge9"])
con_force1.Reversed = False
@@ -297,7 +297,7 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force2
con_force2 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce2")
con_force2.References = [(geoforces_obj, 'Vertex2'), (geoforces_obj, 'Vertex8')]
con_force2.References = [(geoforces_obj, "Vertex2"), (geoforces_obj, "Vertex8")]
con_force2.Force = 5555.56
con_force2.Direction = (geom_obj, ["Edge3"])
con_force2.Reversed = False
@@ -306,11 +306,11 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force3
con_force3 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce3")
con_force3.References = [
(geoforces_obj, 'Vertex20'),
(geoforces_obj, 'Vertex21'),
(geoforces_obj, 'Vertex22'),
(geoforces_obj, 'Vertex23'),
(geoforces_obj, 'Vertex24'), ]
(geoforces_obj, "Vertex20"),
(geoforces_obj, "Vertex21"),
(geoforces_obj, "Vertex22"),
(geoforces_obj, "Vertex23"),
(geoforces_obj, "Vertex24"), ]
con_force3.Force = 27777.78
con_force3.Direction = (geom_obj, ["Edge9"])
con_force3.Reversed = False
@@ -319,11 +319,11 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force4
con_force4 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce4")
con_force4.References = [
(geoforces_obj, 'Vertex9'),
(geoforces_obj, 'Vertex10'),
(geoforces_obj, 'Vertex11'),
(geoforces_obj, 'Vertex12'),
(geoforces_obj, 'Vertex13'), ]
(geoforces_obj, "Vertex9"),
(geoforces_obj, "Vertex10"),
(geoforces_obj, "Vertex11"),
(geoforces_obj, "Vertex12"),
(geoforces_obj, "Vertex13"), ]
con_force4.Force = 27777.78
con_force4.Direction = (geom_obj, ["Edge3"])
con_force4.Reversed = False
@@ -332,12 +332,12 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force5
con_force5 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce5")
con_force5.References = [
(geoforces_obj, 'Vertex43'),
(geoforces_obj, 'Vertex44'),
(geoforces_obj, 'Vertex45'),
(geoforces_obj, 'Vertex46'),
(geoforces_obj, 'Vertex47'),
(geoforces_obj, 'Vertex48'), ]
(geoforces_obj, "Vertex43"),
(geoforces_obj, "Vertex44"),
(geoforces_obj, "Vertex45"),
(geoforces_obj, "Vertex46"),
(geoforces_obj, "Vertex47"),
(geoforces_obj, "Vertex48"), ]
con_force5.Force = 66666.67
con_force5.Direction = (geom_obj, ["Edge9"])
con_force5.Reversed = False
@@ -346,12 +346,12 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force6
con_force6 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce6")
con_force6.References = [
(geoforces_obj, 'Vertex31'),
(geoforces_obj, 'Vertex32'),
(geoforces_obj, 'Vertex33'),
(geoforces_obj, 'Vertex34'),
(geoforces_obj, 'Vertex35'),
(geoforces_obj, 'Vertex36'), ]
(geoforces_obj, "Vertex31"),
(geoforces_obj, "Vertex32"),
(geoforces_obj, "Vertex33"),
(geoforces_obj, "Vertex34"),
(geoforces_obj, "Vertex35"),
(geoforces_obj, "Vertex36"), ]
con_force6.Force = 66666.67
con_force6.Direction = (geom_obj, ["Edge3"])
con_force6.Reversed = False
@@ -359,7 +359,7 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force7
con_force7 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce7")
con_force7.References = [(geoforces_obj, 'Vertex1'), (geoforces_obj, 'Vertex2')]
con_force7.References = [(geoforces_obj, "Vertex1"), (geoforces_obj, "Vertex2")]
con_force7.Force = 5555.56
con_force7.Direction = (geom_obj, ["Edge11"])
con_force7.Reversed = False
@@ -367,7 +367,7 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force8
con_force8 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce8")
con_force8.References = [(geoforces_obj, 'Vertex8'), (geoforces_obj, 'Vertex14')]
con_force8.References = [(geoforces_obj, "Vertex8"), (geoforces_obj, "Vertex14")]
con_force8.Force = 5555.56
con_force8.Direction = (geom_obj, ["Edge6"])
con_force8.Reversed = False
@@ -376,11 +376,11 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force9
con_force9 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce9")
con_force9.References = [
(geoforces_obj, 'Vertex3'),
(geoforces_obj, 'Vertex4'),
(geoforces_obj, 'Vertex5'),
(geoforces_obj, 'Vertex6'),
(geoforces_obj, 'Vertex7'), ]
(geoforces_obj, "Vertex3"),
(geoforces_obj, "Vertex4"),
(geoforces_obj, "Vertex5"),
(geoforces_obj, "Vertex6"),
(geoforces_obj, "Vertex7"), ]
con_force9.Force = 27777.78
con_force9.Direction = (geom_obj, ["Edge11"])
con_force9.Reversed = False
@@ -389,11 +389,11 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force10
con_force10 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce10")
con_force10.References = [
(geoforces_obj, 'Vertex15'),
(geoforces_obj, 'Vertex16'),
(geoforces_obj, 'Vertex17'),
(geoforces_obj, 'Vertex18'),
(geoforces_obj, 'Vertex19'), ]
(geoforces_obj, "Vertex15"),
(geoforces_obj, "Vertex16"),
(geoforces_obj, "Vertex17"),
(geoforces_obj, "Vertex18"),
(geoforces_obj, "Vertex19"), ]
con_force10.Force = 27777.78
con_force10.Direction = (geom_obj, ["Edge6"])
con_force10.Reversed = False
@@ -402,12 +402,12 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force11
con_force11 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce11")
con_force11.References = [
(geoforces_obj, 'Vertex25'),
(geoforces_obj, 'Vertex26'),
(geoforces_obj, 'Vertex27'),
(geoforces_obj, 'Vertex28'),
(geoforces_obj, 'Vertex29'),
(geoforces_obj, 'Vertex30'), ]
(geoforces_obj, "Vertex25"),
(geoforces_obj, "Vertex26"),
(geoforces_obj, "Vertex27"),
(geoforces_obj, "Vertex28"),
(geoforces_obj, "Vertex29"),
(geoforces_obj, "Vertex30"), ]
con_force11.Force = 66666.67
con_force11.Direction = (geom_obj, ["Edge11"])
con_force11.Reversed = False
@@ -416,12 +416,12 @@ def setup(doc=None, solvertype="ccxtools"):
# con_force12
con_force12 = ObjectsFem.makeConstraintForce(doc, name="ConstraintForce12")
con_force12.References = [
(geoforces_obj, 'Vertex37'),
(geoforces_obj, 'Vertex38'),
(geoforces_obj, 'Vertex39'),
(geoforces_obj, 'Vertex40'),
(geoforces_obj, 'Vertex41'),
(geoforces_obj, 'Vertex42'), ]
(geoforces_obj, "Vertex37"),
(geoforces_obj, "Vertex38"),
(geoforces_obj, "Vertex39"),
(geoforces_obj, "Vertex40"),
(geoforces_obj, "Vertex41"),
(geoforces_obj, "Vertex42"), ]
con_force12.Force = 66666.67
con_force12.Direction = (geom_obj, ["Edge6"])
con_force12.Reversed = False

View File

@@ -106,7 +106,8 @@ class Solve(run.Solve):
[binary, "-i", _inputFileName],
cwd=self.directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stderr=subprocess.PIPE
)
self.signalAbort.add(self._process.terminate)
# output = self._observeSolver(self._process)
self._process.communicate()
@@ -127,16 +128,23 @@ class Results(run.Results):
"User parameter:BaseApp/Preferences/Mod/Fem/General")
if not prefs.GetBool("KeepResultsOnReRun", False):
self.purge_results()
self.load_results_ccxfrd()
self.load_results_ccxdat()
self.load_results()
def purge_results(self):
# dat file will not be removed
# results from other solvers will be removed too
# the user should decide if purge should only delete the solver results or all results
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
if m.Mesh and femutils.is_of_type(m.Mesh, "Fem::MeshResult"):
self.analysis.Document.removeObject(m.Mesh.Name)
self.analysis.Document.removeObject(m.Name)
self.analysis.Document.recompute()
def load_results(self):
self.load_results_ccxfrd()
self.load_results_ccxdat()
def load_results_ccxfrd(self):
frd_result_file = os.path.join(
self.directory, _inputFileName + ".frd")

View File

@@ -48,7 +48,7 @@ def write_meshdata_constraint(f, femobj, force_obj, ccxwriter):
direction_vec = femobj["Object"].DirectionVector
for ref_shape in femobj["NodeLoadTable"]:
f.write("** " + ref_shape[0] + "\n")
f.write("** {}\n".format(ref_shape[0]))
for n in sorted(ref_shape[1]):
node_load = ref_shape[1][n]
if (direction_vec.x != 0.0):

View File

@@ -95,8 +95,8 @@ def run_fem_solver(solver, working_dir=None):
:note:
There is some legacy code to execute the old Calculix solver
(pre-framework) which behaives differently because it doesn't use a
:class:`Machine`.
(pre-framework) which behaives differently because it does not
use a :class:`Machine`.
"""
if solver.Proxy.Type == "Fem::SolverCcxTools":

View File

@@ -85,7 +85,7 @@ def get_binary(name):
Return the specific path set by the user in FreeCADs settings/parameter
system if set or the default binary name if no specific path is set. If no
path was found because the solver *name* isn't supported ``None`` is
path was found because the solver *name* is not supported ``None`` is
returned. This method does not check whether the binary actually exists
and is callable.
@@ -93,12 +93,15 @@ def get_binary(name):
"""
if name in _SOLVER_PARAM:
binary = _SOLVER_PARAM[name].get_binary()
FreeCAD.Console.PrintMessage('Solver binary path: {} \n'.format(binary))
FreeCAD.Console.PrintMessage(
'Solver binary path (returned from binary getter): {} \n'
.format(binary)
)
return binary
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
"Settings solver name: {} not found in "
"solver settings modules _SOLVER_PARAM dirctionary.\n"
.format(name)
)
return None
@@ -108,8 +111,8 @@ def get_write_comments(name):
""" Check whether "write_comments" is set for solver.
Returns ``True`` if the "write_comments" setting/parameter is set for the
solver with the id *name*. Returns ``False`` otherwise. If the solver isn't
supported ``None`` is returned.
solver with the id *name*. Returns ``False`` otherwise. If the solver is
not supported ``None`` is returned.
:param name: solver id as a ``str`` (see :mod:`femsolver.settings`)
"""
@@ -117,8 +120,8 @@ def get_write_comments(name):
return _SOLVER_PARAM[name].get_write_comments()
else:
FreeCAD.Console.PrintError(
'Settings solver name: {} not found in '
'solver settings modules _SOLVER_PARAM dirctionary.\n'
"Settings solver name: {} not found in "
"solver settings modules _SOLVER_PARAM dirctionary.\n"
.format(name)
)
return None
@@ -190,19 +193,31 @@ class _SolverDlg(object):
def get_binary(self):
# set the binary path to the FreeCAD defaults
# ATM pure unix shell commands without path names are used
# ATM pure unix shell commands without path names are used as standard
# TODO the binaries provieded with the FreeCAD distribution should be found
# without any additional user input
# see ccxttols, it works for Windows and Linux there
binary = self.default
FreeCAD.Console.PrintLog("Solver binary path: {} \n".format(binary))
FreeCAD.Console.PrintLog("Solver binary path default: {} \n".format(binary))
# check if use_default is set to True
# if True the standard binary path will be overwritten with a user binary path
if self.param_group.GetBool(self.use_default, True) is False:
binary = self.param_group.GetString(self.custom_path)
FreeCAD.Console.PrintLog("Solver binary path: {} \n".format(binary))
FreeCAD.Console.PrintLog("Solver binary path user setting: {} \n".format(binary))
# get the whole binary path name for the given command or binary path and return it
# None is returned if the binary has not been found
# The user does not know what exactly has going wrong.
from distutils.spawn import find_executable as find_bin
return find_bin(binary)
the_found_binary = find_bin(binary)
if the_found_binary is None:
FreeCAD.Console.PrintError(
"The binary has not been found. Full binary search path: {}\n"
.format(binary)
)
FreeCAD.Console.PrintLog("Solver binary found path: {}\n".format(the_found_binary))
return the_found_binary
def get_write_comments(self):
return self.param_group.GetBool(self.WRITE_COMMENTS_PARAM, True)

View File

@@ -72,7 +72,7 @@ class ControlTaskPanel(QtCore.QObject):
self.form.abortClicked.connect(self.abort)
self.form.directoryChanged.connect(self.updateMachine)
# Seems that the task panel doesn't get destroyed. Disconnect
# Seems that the task panel does not get destroyed. Disconnect
# as soon as the widget of the task panel gets destroyed.
self.form.destroyed.connect(self._disconnectMachine)
self.form.destroyed.connect(self._timer.stop)

View File

@@ -56,7 +56,7 @@ class FemInputWriter():
self.document = self.analysis.Document
# working dir
self.dir_name = dir_name
# if dir_name was not given or if it exists but isn't empty: create a temporary dir
# if dir_name was not given or if it exists but is not empty: create a temporary dir
# Purpose: makes sure the analysis can be run even on wired situation
if not dir_name:
FreeCAD.Console.PrintWarning(

View File

@@ -112,7 +112,7 @@ class Results(run.Results):
"User parameter:BaseApp/Preferences/Mod/Fem/General")
if not prefs.GetBool("KeepResultsOnReRun", False):
self.purge_results()
self.load_results_z88o2()
self.load_results()
def purge_results(self):
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
@@ -121,7 +121,8 @@ class Results(run.Results):
self.analysis.Document.removeObject(m.Name)
self.analysis.Document.recompute()
def load_results_z88o2(self):
def load_results(self):
# displacements from z88o2 file
disp_result_file = os.path.join(
self.directory, "z88o2.txt")
if os.path.isfile(disp_result_file):

View File

@@ -104,7 +104,7 @@ class TestSolverCalculix(unittest.TestCase):
self.input_file_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_faceload(
def test_ccx_cantilever_faceload(
self
):
from femexamples.ccx_cantilever_faceload import setup
@@ -112,15 +112,15 @@ class TestSolverCalculix(unittest.TestCase):
self.input_file_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_hexa20(
def test_ccx_cantilever_ele_hexa20(
self
):
from femexamples.ccx_cantilever_hexa20faceload import setup
from femexamples.ccx_cantilever_ele_hexa20 import setup
setup(self.document, "calculix")
self.input_file_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_nodeload(
def test_ccx_cantilever_nodeload(
self
):
from femexamples.ccx_cantilever_nodeload import setup
@@ -128,7 +128,7 @@ class TestSolverCalculix(unittest.TestCase):
self.input_file_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_prescribeddisplacement(
def test_ccx_cantilever_prescribeddisplacement(
self
):
from femexamples.ccx_cantilever_prescribeddisplacement import setup

View File

@@ -76,7 +76,7 @@ class TestSolverZ88(unittest.TestCase):
))
# ********************************************************************************************
def test_ccxcantilever_faceload(
def test_ccx_cantilever_faceload(
self
):
from femexamples.ccx_cantilever_faceload import setup
@@ -84,15 +84,15 @@ class TestSolverZ88(unittest.TestCase):
self.inputfile_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_hexa20(
def test_ccx_cantilever_ele_hexa20(
self
):
from femexamples.ccx_cantilever_hexa20faceload import setup
from femexamples.ccx_cantilever_ele_hexa20 import setup
setup(self.document, "z88")
self.inputfile_writing_test(get_namefromdef("test_"))
# ********************************************************************************************
def test_ccxcantilever_nodeload(
def test_ccx_cantilever_nodeload(
self
):
from femexamples.ccx_cantilever_nodeload import setup

View File

@@ -194,7 +194,14 @@ SET(Tools_Shape_SRCS
SET(PathTests_SRCS
PathTests/__init__.py
PathTests/boxtest.fcstd
PathTests/PathTestUtils.py
PathTests/test_adaptive.fcstd
PathTests/test_centroid_00.ngc
PathTests/test_geomop.fcstd
PathTests/test_holes00.fcstd
PathTests/test_linuxcnc_00.ngc
PathTests/TestPathAdaptive.py
PathTests/TestPathCore.py
PathTests/TestPathDeburr.py
PathTests/TestPathDepthParams.py
@@ -220,11 +227,6 @@ SET(PathTests_SRCS
PathTests/Tools/Bit/test-path-tool-bit-bit-00.fctb
PathTests/Tools/Library/test-path-tool-bit-library-00.fctl
PathTests/Tools/Shape/test-path-tool-bit-shape-00.fcstd
PathTests/boxtest.fcstd
PathTests/test_centroid_00.ngc
PathTests/test_geomop.fcstd
PathTests/test_holes00.fcstd
PathTests/test_linuxcnc_00.ngc
)
SET(PathImages_Ops

View File

@@ -42,6 +42,7 @@ Part = LazyLoader('Part', globals(), 'Part')
FeatureExtensions = LazyLoader('PathScripts.PathFeatureExtensions',
globals(),
'PathScripts.PathFeatureExtensions')
DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils')
if FreeCAD.GuiUp:
from pivy import coin
@@ -559,16 +560,16 @@ def Execute(op, obj):
def _get_working_edges(op, obj):
"""_get_working_edges(op, obj)...
'''_get_working_edges(op, obj)...
Compile all working edges from the Base Geometry selection (obj.Base)
for the current operation.
Additional modifications to selected region(face), such as extensions,
should be placed within this function.
"""
regions = list()
'''
all_regions = list()
edge_list = list()
avoidFeatures = list()
rawEdges = list()
# Get extensions and identify faces to avoid
extensions = FeatureExtensions.getExtensions(obj)
@@ -579,20 +580,30 @@ def _get_working_edges(op, obj):
# Get faces selected by user
for base, subs in obj.Base:
for sub in subs:
if sub not in avoidFeatures:
if obj.UseOutline:
face = base.Shape.getElement(sub)
# get outline with wire_A method used in PocketShape, but it does not play nicely later
# wire_A = TechDraw.findShapeOutline(face, 1, FreeCAD.Vector(0.0, 0.0, 1.0))
wire_B = face.Wires[0]
shape = Part.Face(wire_B)
else:
shape = base.Shape.getElement(sub)
regions.append(shape)
if sub.startswith("Face"):
if sub not in avoidFeatures:
if obj.UseOutline:
face = base.Shape.getElement(sub)
# get outline with wire_A method used in PocketShape, but it does not play nicely later
# wire_A = TechDraw.findShapeOutline(face, 1, FreeCAD.Vector(0.0, 0.0, 1.0))
wire_B = face.Wires[0]
shape = Part.Face(wire_B)
else:
shape = base.Shape.getElement(sub)
all_regions.append(shape)
elif sub.startswith("Edge"):
# Save edges for later processing
rawEdges.append(base.Shape.getElement(sub))
# Efor
# Return Extend Outline extension, OR regular edge extension
all_regions = regions
# Process selected edges
if rawEdges:
edgeWires = DraftGeomUtils.findWires(rawEdges)
if edgeWires:
for w in edgeWires:
for e in w.Edges:
edge_list.append([discretize(e)])
# Apply regular Extensions
op.exts = [] # pylint: disable=attribute-defined-outside-init
for ext in extensions:
@@ -605,10 +616,12 @@ def _get_working_edges(op, obj):
# Second face-combining method attempted
horizontal = PathGeom.combineHorizontalFaces(all_regions)
for f in horizontal:
for w in f.Wires:
for e in w.Edges:
edge_list.append([discretize(e)])
if horizontal:
obj.removalshape = Part.makeCompound(horizontal)
for f in horizontal:
for w in f.Wires:
for e in w.Edges:
edge_list.append([discretize(e)])
return edge_list
@@ -662,6 +675,9 @@ class PathAdaptive(PathOp.ObjectOp):
obj.addProperty("App::PropertyBool", "UseOutline", "Adaptive", "Uses the outline of the base geometry.")
obj.addProperty("Part::PropertyPartShape", "removalshape", "Path", "")
obj.setEditorMode('removalshape', 2) # hide
FeatureExtensions.initialize_properties(obj)
def opSetDefaultValues(self, obj, job):
@@ -703,6 +719,11 @@ class PathAdaptive(PathOp.ObjectOp):
"UseOutline",
"Adaptive",
"Uses the outline of the base geometry.")
if not hasattr(obj, "removalshape"):
obj.addProperty("Part::PropertyPartShape", "removalshape", "Path", "")
obj.setEditorMode('removalshape', 2) # hide
FeatureExtensions.initialize_properties(obj)

View File

@@ -440,7 +440,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage):
baseItem.setData(base[0].Label, QtCore.Qt.EditRole)
baseItem.setSelectable(False)
for sub in sorted(base[1]):
if sub.startswith('Face') or True:
if sub.startswith('Face'):
show = True
baseItem.appendRow(self.createItemForBaseModel(base[0], sub, edges, extensions))
if show:

View File

@@ -213,7 +213,8 @@ class JobCreate:
def setupTemplate(self):
templateFiles = []
for path in PathPreferences.searchPaths():
templateFiles.extend(self.templateFilesIn(path))
cleanPaths = [f.replace("\\", "/") for f in self.templateFilesIn(path)] # Standardize slashes used accross os platforms
templateFiles.extend(cleanPaths)
template = {}
for tFile in templateFiles:

View File

@@ -0,0 +1,459 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2021 Russell Johnson (russ4262) <russ4262@gmail.com> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * 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 *
# * *
# ***************************************************************************
import FreeCAD
import Part
import PathScripts.PathJob as PathJob
import PathScripts.PathAdaptive as PathAdaptive
import PathScripts.PathGeom as PathGeom
from PathTests.PathTestUtils import PathTestBase
if FreeCAD.GuiUp:
import PathScripts.PathAdaptiveGui as PathAdaptiveGui
import PathScripts.PathJobGui as PathJobGui
class TestPathAdaptive(PathTestBase):
'''Unit tests for the Adaptive operation.'''
@classmethod
def setUpClass(cls):
'''setUpClass()...
This method is called upon instantiation of this test class. Add code and objects here
that are needed for the duration of the test() methods in this class. In other words,
set up the 'global' test environment here; use the `setUp()` method to set up a 'local'
test environment.
This method does not have access to the class `self` reference, but it
is able to call static methods within this same class.
'''
# Open existing FreeCAD document with test geometry
doc = FreeCAD.open(FreeCAD.getHomePath() + 'Mod/Path/PathTests/test_adaptive.fcstd')
# Create Job object, adding geometry objects from file opened above
job = PathJob.Create('Job', [doc.Fusion], None)
job.GeometryTolerance.Value = 0.001
if FreeCAD.GuiUp:
job.ViewObject.Proxy = PathJobGui.ViewProvider(job.ViewObject)
# Instantiate an Adaptive operation for quering available properties
prototype = PathAdaptive.Create("Adaptive")
prototype.Base = [(doc.Fusion, ["Face3"])]
prototype.Label = "Prototype"
_addViewProvider(prototype)
doc.recompute()
@classmethod
def tearDownClass(cls):
'''tearDownClass()...
This method is called prior to destruction of this test class. Add code and objects here
that cleanup the test environment after the test() methods in this class have been executed.
This method does not have access to the class `self` reference. This method
is able to call static methods within this same class.
'''
# FreeCAD.Console.PrintMessage("TestPathAdaptive.tearDownClass()\n")
# Close geometry document without saving
FreeCAD.closeDocument(FreeCAD.ActiveDocument.Name)
# Setup and tear down methods called before and after each unit test
def setUp(self):
'''setUp()...
This method is called prior to each `test()` method. Add code and objects here
that are needed for multiple `test()` methods.
'''
self.doc = FreeCAD.ActiveDocument
self.con = FreeCAD.Console
def tearDown(self):
'''tearDown()...
This method is called after each test() method. Add cleanup instructions here.
Such cleanup instructions will likely undo those in the setUp() method.
'''
pass
# Unit tests
def test00(self):
'''test00() Empty test.'''
return
def test01(self):
'''test01() Verify path generated on Face3.'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Face3"])] # (base, subs_list)
adaptive.Label = "test01+"
adaptive.Comment = "test01() Verify path generated on Face3."
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
# moves = getGcodeMoves(adaptive.Path.Commands, includeRapids=False)
# operationMoves = "; ".join(moves)
# self.con.PrintMessage("test00_moves: " + operationMoves + "\n")
# self.assertTrue(expected_moves_test01 == operationMoves,
# "expected_moves_test01: {}\noperationMoves: {}".format(expected_moves_test01, operationMoves))
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
def test02(self):
'''test02() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different.'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] # (base, subs_list)
adaptive.Label = "test02+"
adaptive.Comment = "test02() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different."
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
def test03(self):
'''test03() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different.'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Face3", "Face10"])] # (base, subs_list)
adaptive.Label = "test03+"
adaptive.Comment = "test03() Verify path generated on adjacent, combined Face3 and Face10. The Z heights are different."
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = True
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
def test04(self):
'''test04() Verify path generated non-closed edges with differing Z-heights that are closed with Z=1 projection: "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19"])] # (base, subs_list)
adaptive.Label = "test04+"
adaptive.Comment = 'test04() Verify path generated non-closed edges with differing Z-heights that are closed with Z=1 projection: "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".'
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
def test05(self):
'''test05() Verify path generated closed wire with differing Z-heights: "Edge13", "Edge7", "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Edge13", "Edge7", "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19"])] # (base, subs_list)
adaptive.Label = "test05+"
adaptive.Comment = 'test05() Verify path generated closed wire with differing Z-heights: "Edge13", "Edge7", "Edge9", "Edge2", "Edge8", "Edge15", "Edge30", "Edge31", "Edge29", "Edge19".'
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
def test06(self):
'''test06() Verify path generated with outer and inner edge loops at same Z height: "Edge15", "Edge30", "Edge31", "Edge29", "Edge19", "Edge18", "Edge35", "Edge32", "Edge34", "Edge33".'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Edge15", "Edge30", "Edge31", "Edge29", "Edge19", "Edge18", "Edge35", "Edge32", "Edge34", "Edge33"])] # (base, subs_list)
adaptive.Label = "test06+"
adaptive.Comment = 'test06() Verify path generated with outer and inner edge loops at same Z height: "Edge15", "Edge30", "Edge31", "Edge29", "Edge19", "Edge18", "Edge35", "Edge32", "Edge34", "Edge33".'
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
# Check command count
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
# Check if any paths originate inside inner hole of donut. They should not.
isInBox = False
edges = [self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"]]
square = Part.Wire(edges)
sqrBB = square.BoundBox
minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0)
maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0)
for c in adaptive.Path.Commands:
if pathOriginatesInBox(c, minPoint, maxPoint):
isInBox = True
break
self.assertFalse(isInBox, "Paths originating within the inner hole.")
def test07(self):
'''test07() Verify path generated on donut-shaped Face10.'''
# Instantiate a Adaptive operation and set Base Geometry
adaptive = PathAdaptive.Create('Adaptive')
adaptive.Base = [(self.doc.Fusion, ["Face10"])] # (base, subs_list)
adaptive.Label = "test07+"
adaptive.Comment = "test07() Verify path generated on donut-shaped Face10."
# Set additional operation properties
# setDepthsAndHeights(adaptive)
adaptive.FinishingProfile = False
adaptive.HelixAngle = 75.0
adaptive.HelixDiameterLimit.Value = 1.0
adaptive.LiftDistance.Value = 1.0
adaptive.StepOver = 75
adaptive.UseOutline = False
adaptive.setExpression('StepDown', None)
adaptive.StepDown.Value = 20.0 # Have to set expression to None before numerical value assignment
_addViewProvider(adaptive)
self.doc.recompute()
self.assertTrue(len(adaptive.Path.Commands) > 100, "Command count not greater than 100.")
# Check if any paths originate inside inner hole of donut. They should not.
isInBox = False
edges = [self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"]]
square = Part.Wire(edges)
sqrBB = square.BoundBox
minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0)
maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0)
for c in adaptive.Path.Commands:
if pathOriginatesInBox(c, minPoint, maxPoint):
isInBox = True
break
self.assertFalse(isInBox, "Paths originating within the inner hole.")
# Set Adaptive op to only use the outline of the face.
adaptive.UseOutline = True
self.doc.recompute()
# Check if any paths originate inside inner hole of donut. They should not.
isInBox = False
edges = [self.doc.Fusion.Shape.getElement(e) for e in ["Edge35", "Edge32", "Edge33", "Edge34"]]
square = Part.Wire(edges)
sqrBB = square.BoundBox
minPoint = FreeCAD.Vector(sqrBB.XMin, sqrBB.YMin, 0.0)
maxPoint = FreeCAD.Vector(sqrBB.XMax, sqrBB.YMax, 0.0)
for c in adaptive.Path.Commands:
if pathOriginatesInBox(c, minPoint, maxPoint):
isInBox = True
break
self.assertTrue(isInBox, "No paths originating within the inner hole.")
# Eclass
def setDepthsAndHeights(op, strDep=20.0, finDep=0.0):
'''setDepthsAndHeights(op, strDep=20.0, finDep=0.0)... Sets default depths and heights for `op` passed to it'''
# Set start and final depth in order to eliminate effects of stock (and its default values)
op.setExpression('StartDepth', None)
op.StartDepth.Value = strDep
op.setExpression('FinalDepth', None)
op.FinalDepth.Value = finDep
# Set step down so as to only produce one layer path
op.setExpression('StepDown', None)
op.StepDown.Value = 20.0
# Set Heights
# default values used
def getGcodeMoves(cmdList, includeRapids=True, includeLines=True, includeArcs=True):
'''getGcodeMoves(cmdList, includeRapids=True, includeLines=True, includeArcs=True)...
Accepts command dict and returns point string coordinate.
'''
gcode_list = list()
last = FreeCAD.Vector(0.0, 0.0, 0.0)
for c in cmdList:
p = c.Parameters
name = c.Name
if includeRapids and name in ["G0", "G00"]:
gcode = name
x = last.x
y = last.y
z = last.z
if p.get("X"):
x = round(p["X"], 2)
gcode += " X" + str(x)
if p.get("Y"):
y = round(p["Y"], 2)
gcode += " Y" + str(y)
if p.get("Z"):
z = round(p["Z"], 2)
gcode += " Z" + str(z)
last.x = x
last.y = y
last.z = z
gcode_list.append(gcode)
elif includeLines and name in ["G1", "G01"]:
gcode = name
x = last.x
y = last.y
z = last.z
if p.get("X"):
x = round(p["X"], 2)
gcode += " X" + str(x)
if p.get("Y"):
y = round(p["Y"], 2)
gcode += " Y" + str(y)
if p.get("Z"):
z = round(p["Z"], 2)
gcode += " Z" + str(z)
last.x = x
last.y = y
last.z = z
gcode_list.append(gcode)
elif includeArcs and name in ["G2", "G3", "G02", "G03"]:
gcode = name
x = last.x
y = last.y
z = last.z
i = 0.0
j = 0.0
k = 0.0
if p.get("I"):
i = round(p["I"], 2)
gcode += " I" + str(i)
if p.get("J"):
j = round(p["J"], 2)
gcode += " J" + str(j)
if p.get("K"):
k = round(p["K"], 2)
gcode += " K" + str(k)
if p.get("X"):
x = round(p["X"], 2)
gcode += " X" + str(x)
if p.get("Y"):
y = round(p["Y"], 2)
gcode += " Y" + str(y)
if p.get("Z"):
z = round(p["Z"], 2)
gcode += " Z" + str(z)
gcode_list.append(gcode)
last.x = x
last.y = y
last.z = z
return gcode_list
def pathOriginatesInBox(cmd, minPoint, maxPoint):
p = cmd.Parameters
name = cmd.Name
if name in ["G0", "G00", "G1", "G01"]:
if p.get("X") and p.get("Y"):
x = p.get("X")
y = p.get("Y")
if x > minPoint.x and y > minPoint.y and x < maxPoint.x and y < maxPoint.y:
return True
return False
def _addViewProvider(adaptiveOp):
if FreeCAD.GuiUp:
PathOpGui = PathAdaptiveGui.PathOpGui
cmdRes = PathAdaptiveGui.Command.res
adaptiveOp.ViewObject.Proxy = PathOpGui.ViewProvider(adaptiveOp.ViewObject, cmdRes)
# Example string literal of expected path moves from an operation
# Expected moves for unit test01
expected_moves_test01 = "G1 X32.5 Y32.5 Z5.0; \
G1 X17.5 Y32.5 Z5.0; \
G1 X17.5 Y30.0 Z5.0; \
G1 X32.5 Y30.0 Z5.0; \
G1 X32.5 Y27.5 Z5.0; \
G1 X17.5 Y27.5 Z5.0; \
G1 X17.5 Y25.0 Z5.0; \
G1 X32.5 Y25.0 Z5.0; \
G1 X32.5 Y22.5 Z5.0; \
G1 X17.5 Y22.5 Z5.0; \
G1 X17.5 Y20.0 Z5.0; \
G1 X32.5 Y20.0 Z5.0; \
G1 X32.5 Y17.5 Z5.0; \
G1 X17.5 Y17.5 Z5.0"

Binary file not shown.

View File

@@ -22,50 +22,51 @@
import TestApp
from PathTests.TestPathLog import TestPathLog
from PathTests.TestPathPreferences import TestPathPreferences
from PathTests.TestPathPropertyBag import TestPathPropertyBag
from PathTests.TestPathCore import TestPathCore
#from PathTests.TestPathPost import PathPostTestCases
from PathTests.TestPathGeom import TestPathGeom
from PathTests.TestPathOpTools import TestPathOpTools
from PathTests.TestPathUtil import TestPathUtil
# from PathTests.TestPathPost import PathPostTestCases
from PathTests.TestPathAdaptive import TestPathAdaptive
from PathTests.TestPathCore import TestPathCore
from PathTests.TestPathDeburr import TestPathDeburr
from PathTests.TestPathDepthParams import depthTestCases
from PathTests.TestPathDressupHoldingTags import TestHoldingTags
from PathTests.TestPathDressupDogbone import TestDressupDogbone
from PathTests.TestPathStock import TestPathStock
from PathTests.TestPathTool import TestPathTool
from PathTests.TestPathToolBit import TestPathToolBit
from PathTests.TestPathTooltable import TestPathTooltable
from PathTests.TestPathToolController import TestPathToolController
from PathTests.TestPathDressupHoldingTags import TestHoldingTags
from PathTests.TestPathGeom import TestPathGeom
from PathTests.TestPathHelix import TestPathHelix
from PathTests.TestPathLog import TestPathLog
from PathTests.TestPathOpTools import TestPathOpTools
from PathTests.TestPathPreferences import TestPathPreferences
from PathTests.TestPathPropertyBag import TestPathPropertyBag
from PathTests.TestPathSetupSheet import TestPathSetupSheet
from PathTests.TestPathDeburr import TestPathDeburr
from PathTests.TestPathHelix import TestPathHelix
from PathTests.TestPathVoronoi import TestPathVoronoi
from PathTests.TestPathThreadMilling import TestPathThreadMilling
from PathTests.TestPathVcarve import TestPathVcarve
from PathTests.TestPathStock import TestPathStock
from PathTests.TestPathThreadMilling import TestPathThreadMilling
from PathTests.TestPathTool import TestPathTool
from PathTests.TestPathToolBit import TestPathToolBit
from PathTests.TestPathToolController import TestPathToolController
from PathTests.TestPathTooltable import TestPathTooltable
from PathTests.TestPathUtil import TestPathUtil
from PathTests.TestPathVcarve import TestPathVcarve
from PathTests.TestPathVoronoi import TestPathVoronoi
# dummy usage to get flake8 and lgtm quiet
False if TestApp.__name__ else True
False if TestPathLog.__name__ else True
False if TestPathCore.__name__ else True
False if TestPathGeom.__name__ else True
False if TestPathOpTools.__name__ else True
False if TestPathUtil.__name__ else True
False if depthTestCases.__name__ else True
False if TestHoldingTags.__name__ else True
False if TestApp.__name__ else True
False if TestDressupDogbone.__name__ else True
False if TestPathStock.__name__ else True
False if TestPathTool.__name__ else True
False if TestPathTooltable.__name__ else True
False if TestPathToolController.__name__ else True
False if TestPathSetupSheet.__name__ else True
False if TestHoldingTags.__name__ else True
False if TestPathAdaptive.__name__ else True
False if TestPathCore.__name__ else True
False if TestPathDeburr.__name__ else True
False if TestPathGeom.__name__ else True
False if TestPathHelix.__name__ else True
False if TestPathLog.__name__ else True
False if TestPathOpTools.__name__ else True
False if TestPathPreferences.__name__ else True
False if TestPathToolBit.__name__ else True
False if TestPathVoronoi.__name__ else True
False if TestPathThreadMilling.__name__ else True
False if TestPathVcarve.__name__ else True
False if TestPathPropertyBag.__name__ else True
False if TestPathSetupSheet.__name__ else True
False if TestPathStock.__name__ else True
False if TestPathThreadMilling.__name__ else True
False if TestPathTool.__name__ else True
False if TestPathToolBit.__name__ else True
False if TestPathToolController.__name__ else True
False if TestPathTooltable.__name__ else True
False if TestPathUtil.__name__ else True
False if TestPathVcarve.__name__ else True
False if TestPathVoronoi.__name__ else True