Merge branch 'FreeCAD:master' into master

This commit is contained in:
Zolko-123
2021-07-21 15:33:44 +02:00
committed by GitHub
12 changed files with 329 additions and 199 deletions

View File

@@ -246,7 +246,7 @@
<double>2.000000000000000</double>
</property>
<property name="maximum" stdset="0">
<double>2000000000.000000000000000</double>
<double>90000000000.000000000000000</double>
</property>
<property name="unit" stdset="0">
<string notr="true">Pa</string>

View File

@@ -638,7 +638,7 @@ class MeshSetsGetter():
if self.member.geos_beamsection:
# we will need to split the beam even for one beamobj
# because no beam in z-direction can be used in ccx without a special adjustment
# thus they need an own ccx_elset
# thus they need an own matgeoset
self.get_element_rotation1D_elements()
# get the element ids for face and edge elements and write them into the objects
@@ -726,15 +726,15 @@ class MeshSetsGetter():
{"short": beamrot_data["ShortName"]},
{"short": "D" + str(i)}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["beamsection_obj"] = beamsec_obj
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["beamsection_obj"] = beamsec_obj
# normal for this direction
ccx_elset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(ccx_elset)
matgeoset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_single_mat_multiple_beam(self):
mat_obj = self.member.mats_linear[0]["Object"]
@@ -753,15 +753,15 @@ class MeshSetsGetter():
{"short": beamrot_data["ShortName"]},
{"short": "D" + str(i)}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["beamsection_obj"] = beamsec_obj
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["beamsection_obj"] = beamsec_obj
# normal for this direction
ccx_elset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(ccx_elset)
matgeoset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_single_beam(self):
beamsec_obj = self.member.geos_beamsection[0]["Object"]
@@ -779,15 +779,15 @@ class MeshSetsGetter():
{"short": beamrot_data["ShortName"]},
{"short": "D" + str(i)}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["beamsection_obj"] = beamsec_obj
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["beamsection_obj"] = beamsec_obj
# normal for this direction
ccx_elset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(ccx_elset)
matgeoset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_multiple_beam(self):
beamrot_data = self.member.geos_beamrotation[0]
@@ -810,15 +810,15 @@ class MeshSetsGetter():
{"short": beamrot_data["ShortName"]},
{"short": "D" + str(i)}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["beamsection_obj"] = beamsec_obj
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["beamsection_obj"] = beamsec_obj
# normal for this direction
ccx_elset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(ccx_elset)
matgeoset["beam_normal"] = beamdirection["normal"]
self.mat_geo_sets.append(matgeoset)
# fluid
def get_mat_geo_sets_single_mat_single_fluid(self):
@@ -826,13 +826,13 @@ class MeshSetsGetter():
fluidsec_obj = self.member.geos_fluidsection[0]["Object"]
elset_data = self.ccx_eedges
names = [{"short": "M0"}, {"short": "F0"}]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_single_mat_multiple_fluid(self):
mat_obj = self.member.mats_linear[0]["Object"]
@@ -840,13 +840,13 @@ class MeshSetsGetter():
fluidsec_obj = fluidsec_data["Object"]
elset_data = fluidsec_data["FEMElements"]
names = [{"short": "M0"}, {"short": fluidsec_data["ShortName"]}]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_single_fluid(self):
fluidsec_obj = self.member.geos_fluidsection[0]["Object"]
@@ -854,13 +854,13 @@ class MeshSetsGetter():
mat_obj = mat_data["Object"]
elset_data = mat_data["FEMElements"]
names = [{"short": mat_data["ShortName"]}, {"short": "F0"}]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_multiple_fluid(self):
for fluidsec_data in self.member.geos_fluidsection:
@@ -876,13 +876,13 @@ class MeshSetsGetter():
{"short": mat_data["ShortName"]},
{"short": fluidsec_data["ShortName"]}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_short(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_short(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["fluidsection_obj"] = fluidsec_obj
self.mat_geo_sets.append(matgeoset)
# shell
def get_mat_geo_sets_single_mat_single_shell(self):
@@ -893,13 +893,13 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": "M0"},
{"long": shellth_obj.Name, "short": "S0"}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_single_mat_multiple_shell(self):
mat_obj = self.member.mats_linear[0]["Object"]
@@ -910,13 +910,13 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": "M0"},
{"long": shellth_obj.Name, "short": shellth_data["ShortName"]}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_single_shell(self):
shellth_obj = self.member.geos_shellthickness[0]["Object"]
@@ -927,13 +927,13 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
{"long": shellth_obj.Name, "short": "S0"}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(matgeoset)
def get_mat_geo_sets_multiple_mat_multiple_shell(self):
for shellth_data in self.member.geos_shellthickness:
@@ -949,13 +949,13 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
{"long": shellth_obj.Name, "short": shellth_data["ShortName"]}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
ccx_elset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
matgeoset["shellthickness_obj"] = shellth_obj
self.mat_geo_sets.append(matgeoset)
# solid
def get_mat_geo_sets_single_mat_solid(self):
@@ -965,12 +965,12 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": "M0"},
{"long": "Solid", "short": "Solid"}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
self.mat_geo_sets.append(matgeoset)
print(self.mat_geo_sets)
def get_mat_geo_sets_multiple_mat_solid(self):
@@ -981,12 +981,12 @@ class MeshSetsGetter():
{"long": mat_obj.Name, "short": mat_data["ShortName"]},
{"long": "Solid", "short": "Solid"}
]
ccx_elset = {}
ccx_elset["ccx_elset"] = elset_data
ccx_elset["ccx_elset_name"] = get_ccx_elset_name_standard(names)
ccx_elset["mat_obj_name"] = mat_obj.Name
ccx_elset["ccx_mat_name"] = mat_obj.Material["Name"]
self.mat_geo_sets.append(ccx_elset)
matgeoset = {}
matgeoset["ccx_elset"] = elset_data
matgeoset["ccx_elset_name"] = get_elset_name_standard(names)
matgeoset["mat_obj_name"] = mat_obj.Name
matgeoset["ccx_mat_name"] = mat_obj.Material["Name"]
self.mat_geo_sets.append(matgeoset)
# ************************************************************************************************
@@ -1003,40 +1003,41 @@ class MeshSetsGetter():
# TODO write comment into input file to elset ids and elset attributes
def get_ccx_elset_name_standard(names):
def get_elset_name_standard(names):
# standard max length = 80
ccx_elset_name = ""
elset_name = ""
for name in names:
ccx_elset_name += name["long"]
if len(ccx_elset_name) < 81:
return ccx_elset_name
elset_name += name["long"]
if len(elset_name) < 81:
return elset_name
else:
ccx_elset_name = ""
elset_name = ""
for name in names:
ccx_elset_name += name["short"]
if len(ccx_elset_name) < 81:
return ccx_elset_name
elset_name += name["short"]
if len(elset_name) < 81:
return elset_name
else:
error = (
"FEM: Trouble in ccx input file, because an "
"FEM: Trouble in elset name, because an "
"elset name is longer than 80 character! {}\n"
.format(ccx_elset_name)
.format(elset_name)
)
raise Exception(error)
def get_ccx_elset_name_short(names):
# restricted max length = 20 (beam elsets)
ccx_elset_name = ""
def get_elset_name_short(names):
# restricted max length = 20 (elsets)
# in CalculiX solver input this is needed for beam elsets
elset_name = ""
for name in names:
ccx_elset_name += name["short"]
if len(ccx_elset_name) < 21:
return ccx_elset_name
elset_name += name["short"]
if len(elset_name) < 21:
return elset_name
else:
error = (
"FEM: Trouble in ccx input file, because an"
"beam elset name is longer than 20 characters! {}\n"
.format(ccx_elset_name)
"FEM: Trouble in elset name, because an"
"short elset name is longer than 20 characters! {}\n"
.format(elset_name)
)
raise Exception(error)

View File

@@ -48,7 +48,7 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
# Fluid sections:
# fluidsection Liquid inlet outlet objs requires special element definition
# to fill ccxwriter.FluidInletoutlet_ele list the ccx_elset are needed
# to fill ccxwriter.FluidInletoutlet_ele list the mat_geo_sets are needed
# thus this has to be after the creation of mat_geo_sets
# different pipe cross sections will generate mat_geo_sets
@@ -58,14 +58,14 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
"{}_inout_nodes.txt".format(ccxwriter.mesh_name)
)
def get_fluidsection_inoutlet_obj_if_setdata(ccx_elset):
def get_fluidsection_inoutlet_obj_if_setdata(matgeoset):
if (
ccx_elset["ccx_elset"]
matgeoset["ccx_elset"]
# use six to be sure to be Python 2.7 and 3.x compatible
and not isinstance(ccx_elset["ccx_elset"], six.string_types)
and "fluidsection_obj" in ccx_elset # fluid mesh
and not isinstance(matgeoset["ccx_elset"], six.string_types)
and "fluidsection_obj" in matgeoset # fluid mesh
):
fluidsec_obj = ccx_elset["fluidsection_obj"]
fluidsec_obj = matgeoset["fluidsection_obj"]
if (
fluidsec_obj.SectionType == "Liquid"
and (
@@ -77,12 +77,12 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
return None
def is_fluidsection_inoutlet_setnames_possible(mat_geo_sets):
for ccx_elset in mat_geo_sets:
for matgeoset in mat_geo_sets:
if (
ccx_elset["ccx_elset"]
and "fluidsection_obj" in ccx_elset # fluid mesh
matgeoset["ccx_elset"]
and "fluidsection_obj" in matgeoset # fluid mesh
):
fluidsec_obj = ccx_elset["fluidsection_obj"]
fluidsec_obj = matgeoset["fluidsection_obj"]
if (
fluidsec_obj.SectionType == "Liquid"
and (
@@ -95,13 +95,13 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
# collect elementIDs for fluidsection Liquid inlet outlet objs
# if they have element data (happens if not "eall")
for ccx_elset in ccxwriter.mat_geo_sets:
fluidsec_obj = get_fluidsection_inoutlet_obj_if_setdata(ccx_elset)
for matgeoset in ccxwriter.mat_geo_sets:
fluidsec_obj = get_fluidsection_inoutlet_obj_if_setdata(matgeoset)
if fluidsec_obj is None:
continue
elsetchanged = False
counter = 0
for elid in ccx_elset["ccx_elset"]:
for elid in matgeoset["ccx_elset"]:
counter = counter + 1
if (elsetchanged is False) \
and (fluidsec_obj.LiquidSectionType == "PIPE INLET"):
@@ -111,7 +111,7 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
)
elsetchanged = True
elif (fluidsec_obj.LiquidSectionType == "PIPE OUTLET") \
and (counter == len(ccx_elset["ccx_elset"])):
and (counter == len(matgeoset["ccx_elset"])):
# 3rd index is to track which line nr the element is defined
ccxwriter.FluidInletoutlet_ele.append(
[str(elid), fluidsec_obj.LiquidSectionType, 0]

View File

@@ -32,14 +32,14 @@ def write_femelement_geometry(f, ccxwriter):
f.write("\n{}\n".format(59 * "*"))
f.write("** Sections\n")
for ccx_elset in ccxwriter.mat_geo_sets:
if ccx_elset["ccx_elset"]:
elsetdef = "ELSET={}, ".format(ccx_elset["ccx_elset_name"])
material = "MATERIAL={}".format(ccx_elset["mat_obj_name"])
for matgeoset in ccxwriter.mat_geo_sets:
if matgeoset["ccx_elset"]:
elsetdef = "ELSET={}, ".format(matgeoset["ccx_elset_name"])
material = "MATERIAL={}".format(matgeoset["mat_obj_name"])
if "beamsection_obj"in ccx_elset: # beam mesh
beamsec_obj = ccx_elset["beamsection_obj"]
normal = ccx_elset["beam_normal"]
if "beamsection_obj"in matgeoset: # beam mesh
beamsec_obj = matgeoset["beamsection_obj"]
normal = matgeoset["beam_normal"]
if beamsec_obj.SectionType == "Rectangular":
height = beamsec_obj.RectHeight.getValueAs("mm").Value
width = beamsec_obj.RectWidth.getValueAs("mm").Value
@@ -79,8 +79,8 @@ def write_femelement_geometry(f, ccxwriter):
f.write(section_def)
f.write(section_geo)
f.write(section_nor)
elif "fluidsection_obj"in ccx_elset: # fluid mesh
fluidsec_obj = ccx_elset["fluidsection_obj"]
elif "fluidsection_obj"in matgeoset: # fluid mesh
fluidsec_obj = matgeoset["fluidsection_obj"]
if fluidsec_obj.SectionType == "Liquid":
section_type = fluidsec_obj.LiquidSectionType
if (section_type == "PIPE INLET") or (section_type == "PIPE OUTLET"):
@@ -101,8 +101,8 @@ def write_femelement_geometry(f, ccxwriter):
"""
f.write(section_def)
f.write(section_geo)
elif "shellthickness_obj"in ccx_elset: # shell mesh
shellth_obj = ccx_elset["shellthickness_obj"]
elif "shellthickness_obj"in matgeoset: # shell mesh
shellth_obj = matgeoset["shellthickness_obj"]
section_def = "*SHELL SECTION, {}{}\n".format(elsetdef, material)
thickness = shellth_obj.Thickness.getValueAs("mm").Value
section_geo = "{:.13G}\n".format(thickness)

View File

@@ -35,13 +35,13 @@ def write_femelement_matgeosets(f, ccxwriter):
f.write("\n{}\n".format(59 * "*"))
f.write("** Element sets for materials and FEM element type (solid, shell, beam, fluid)\n")
for ccx_elset in ccxwriter.mat_geo_sets:
for matgeoset in ccxwriter.mat_geo_sets:
f.write("*ELSET,ELSET={}\n".format(ccx_elset["ccx_elset_name"]))
f.write("*ELSET,ELSET={}\n".format(matgeoset["ccx_elset_name"]))
# use six to be sure to be Python 2.7 and 3.x compatible
if isinstance(ccx_elset["ccx_elset"], six.string_types):
f.write("{}\n".format(ccx_elset["ccx_elset"]))
if isinstance(matgeoset["ccx_elset"], six.string_types):
f.write("{}\n".format(matgeoset["ccx_elset"]))
else:
for elid in ccx_elset["ccx_elset"]:
for elid in matgeoset["ccx_elset"]:
f.write(str(elid) + ",\n")

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2018 sliptonic <shopinthewoods@gmail.com> *
# * Copyright (c) 2020 Schildkroet *
# * Copyright (c) 2020-2021 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -86,14 +86,14 @@ def toolDepthAndOffset(width, extraDepth, tool, printInfo):
extraOffset = -width if angle == 180 else (extraDepth / tan)
offset = toolOffset + extraOffset
return (depth, offset, suppressInfo)
return (depth, offset, extraOffset, suppressInfo)
class ObjectDeburr(PathEngraveBase.ObjectOp):
'''Proxy class for Deburr operation.'''
def opFeatures(self, obj):
return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant
return PathOp.FeatureTool | PathOp.FeatureHeights | PathOp.FeatureStepDown | PathOp.FeatureBaseEdges | PathOp.FeatureBaseFaces | PathOp.FeatureCoolant | PathOp.FeatureBaseGeometry
def initOperation(self, obj):
PathLog.track(obj.Label)
@@ -123,7 +123,7 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
if not hasattr(self, 'printInfo'):
self.printInfo = True
try:
(depth, offset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo)
(depth, offset, extraOffset, suppressInfo) = toolDepthAndOffset(obj.Width.Value, obj.ExtraDepth.Value, self.tool, self.printInfo)
self.printInfo = not suppressInfo
except ValueError as e:
msg = "{} \n No path will be generated".format(e)
@@ -136,42 +136,129 @@ class ObjectDeburr(PathEngraveBase.ObjectOp):
self.basewires = [] # pylint: disable=attribute-defined-outside-init
self.adjusted_basewires = [] # pylint: disable=attribute-defined-outside-init
wires = []
for base, subs in obj.Base:
edges = []
basewires = []
max_h = -99999
radius_top = 0
radius_bottom = 0
for f in subs:
sub = base.Shape.getElement(f)
if type(sub) == Part.Edge:
if type(sub) == Part.Edge: # Edge
edges.append(sub)
elif type(sub) == Part.Face and sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1): # Angled face
# If an angled face is selected, the lower edge is projected to the height of the upper edge,
# to simulate an edge
# Find z value of upper edge
for edge in sub.Edges:
for p0 in edge.Vertexes:
if p0.Point.z > max_h:
max_h = p0.Point.z
# Find biggest radius for top/bottom
for edge in sub.Edges:
if Part.Circle == type(edge.Curve):
if edge.Vertexes[0].Point.z == max_h:
if edge.Curve.Radius > radius_top:
radius_top = edge.Curve.Radius
else:
if edge.Curve.Radius > radius_bottom:
radius_bottom = edge.Curve.Radius
# Search for lower edge and raise it to height of upper edge
for edge in sub.Edges:
if Part.Circle == type(edge.Curve): # Edge is a circle
if edge.Vertexes[0].Point.z < max_h:
if edge.Closed: # Circle
# New center
center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h)
new_edge = Part.makeCircle(edge.Curve.Radius, center, FreeCAD.Vector(0, 0, 1))
edges.append(new_edge)
# Modify offset for inner angled faces
if radius_bottom < radius_top:
offset -= 2 * extraOffset
break
else: # Arc
if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z:
# Arc vertexes are on same layer
l1 = math.sqrt((edge.Vertexes[0].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[0].Point.y - edge.Curve.Center.y)**2)
l2 = math.sqrt((edge.Vertexes[1].Point.x - edge.Curve.Center.x)**2 + (edge.Vertexes[1].Point.y - edge.Curve.Center.y)**2)
# New center
center = FreeCAD.Vector(edge.Curve.Center.x, edge.Curve.Center.y, max_h)
# Calculate angles based on x-axis (0 - PI/2)
start_angle = math.acos((edge.Vertexes[0].Point.x - edge.Curve.Center.x) / l1)
end_angle = math.acos((edge.Vertexes[1].Point.x - edge.Curve.Center.x) / l2)
# Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle
if edge.Vertexes[0].Point.y < edge.Curve.Center.y:
start_angle *= -1
if edge.Vertexes[1].Point.y < edge.Curve.Center.y:
end_angle *= -1
# Create new arc
new_edge = Part.ArcOfCircle(Part.Circle(center, FreeCAD.Vector(0,0,1), edge.Curve.Radius), start_angle, end_angle).toShape()
edges.append(new_edge)
# Modify offset for inner angled faces
if radius_bottom < radius_top:
offset -= 2 * extraOffset
break
else: # Line
if edge.Vertexes[0].Point.z == edge.Vertexes[1].Point.z and edge.Vertexes[0].Point.z < max_h:
new_edge = Part.Edge(Part.LineSegment(FreeCAD.Vector(edge.Vertexes[0].Point.x, edge.Vertexes[0].Point.y, max_h), FreeCAD.Vector(edge.Vertexes[1].Point.x, edge.Vertexes[1].Point.y, max_h)))
edges.append(new_edge)
elif sub.Wires:
basewires.extend(sub.Wires)
else:
else: # Flat face
basewires.append(Part.Wire(sub.Edges))
self.edges = edges # pylint: disable=attribute-defined-outside-init
for edgelist in Part.sortEdges(edges):
basewires.append(Part.Wire(edgelist))
self.basewires.extend(basewires)
# Set default side
side = ["Outside"]
for w in basewires:
self.adjusted_basewires.append(w)
wire = PathOpTools.offsetWire(w, base.Shape, offset, True) #, obj.Side)
wire = PathOpTools.offsetWire(w, base.Shape, offset, True, side)
if wire:
wires.append(wire)
# # Save Outside or Inside
# obj.Side = side[0]
# Set direction of op
forward = (obj.Direction == 'CW')
# Set value of side
obj.Side = side[0]
# Check side extra for angled faces
if radius_top > radius_bottom:
obj.Side = "Inside"
zValues = []
z = 0
if obj.StepDown.Value != 0:
while z + obj.StepDown.Value < depth:
z = z + obj.StepDown.Value
zValues.append(z)
zValues.append(depth)
PathLog.track(obj.Label, depth, zValues)
@@ -208,5 +295,6 @@ def Create(name, obj=None):
'''Create(name) ... Creates and returns a Deburr operation.'''
if obj is None:
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
obj.Proxy = ObjectDeburr(obj, name)
return obj

View File

@@ -55,15 +55,6 @@ class TaskPanelBaseGeometryPage(PathOpGui.TaskPanelBaseGeometryPage):
return super(TaskPanelBaseGeometryPage, self)
def addBaseGeometry(self, selection):
for sel in selection:
if sel.HasSubObjects:
# selectively add some elements of the drawing to the Base
for sub in sel.SubObjects:
if isinstance(sub, Part.Face):
if sub.normalAt(0, 0) != FreeCAD.Vector(0, 0, 1):
PathLog.info(translate("Path", "Ignoring non-horizontal Face"))
return
self.super().addBaseGeometry(selection)

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2017 LTS <SammelLothar@gmx.de> under LGPL *
# * Copyright (c) 2020 Schildkroet *
# * Copyright (c) 2020-2021 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -113,6 +113,7 @@ class ObjectDressup:
def getDirectionOfPath(self, obj):
op = PathDressup.baseOp(obj.Base)
if hasattr(op, 'Side') and op.Side == 'Outside':
if hasattr(op, 'Direction') and op.Direction == 'CW':
return 'left'
@@ -131,12 +132,16 @@ class ObjectDressup:
return ''
def normalize(self, Vector):
vx = 0
vy = 0
x = Vector.x
y = Vector.y
length = math.sqrt(x*x + y*y)
if((math.fabs(length)) > 0.0000000000001):
vx = round(x / length, 3)
vy = round(y / length, 3)
return FreeCAD.Vector(vx, vy, 0)
def invert(self, Vector):

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
# * Copyright (c) 2021 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -342,8 +343,11 @@ def edgeForCmd(cmd, startPoint):
PathLog.debug("StartPoint:{}".format(startPoint))
PathLog.debug("MidPoint:{}".format(midPoint))
PathLog.debug("EndPoint:{}".format(endPoint))
return Part.Edge(Part.Arc(startPoint, midPoint, endPoint))
if pointsCoincide(startPoint, endPoint, 0.001):
return Part.makeCircle(R, center, FreeCAD.Vector(0, 0, 1))
else:
return Part.Edge(Part.Arc(startPoint, midPoint, endPoint))
# It's a Helix
#print('angle: A=%.2f B=%.2f' % (getAngle(A)/math.pi, getAngle(B)/math.pi))

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2018 sliptonic <shopinthewoods@gmail.com> *
# * Copyright (c) 2021 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -143,7 +144,7 @@ def orientWire(w, forward=True):
PathLog.track('orientWire - ok')
return wire
def offsetWire(wire, base, offset, forward):#, Side = None):
def offsetWire(wire, base, offset, forward, Side = None):
'''offsetWire(wire, base, offset, forward) ... offsets the wire away from base and orients the wire accordingly.
The function tries to avoid most of the pitfalls of Part.makeOffset2D which is possible because all offsetting
happens in the XY plane.
@@ -158,14 +159,53 @@ def offsetWire(wire, base, offset, forward):#, Side = None):
# https://www.freecadweb.org/wiki/Part%20Offset2D
# it's easy to construct them manually though
z = -1 if forward else 1
edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z))
if base.isInside(edge.Vertexes[0].Point, offset/2, True):
new_edge = Part.makeCircle(curve.Radius + offset, curve.Center, FreeCAD.Vector(0, 0, z))
if base.isInside(new_edge.Vertexes[0].Point, offset/2, True):
if offset > curve.Radius or PathGeom.isRoughly(offset, curve.Radius):
# offsetting a hole by its own radius (or more) makes the hole vanish
return None
edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z))
w = Part.Wire([edge])
return w
if Side:
Side[0] = "Inside"
print("inside")
new_edge = Part.makeCircle(curve.Radius - offset, curve.Center, FreeCAD.Vector(0, 0, -z))
return Part.Wire([new_edge])
if Part.Circle == type(curve) and not wire.isClosed():
# Process arc segment
z = -1 if forward else 1
l1 = math.sqrt((edge.Vertexes[0].Point.x - curve.Center.x)**2 + (edge.Vertexes[0].Point.y - curve.Center.y)**2)
l2 = math.sqrt((edge.Vertexes[1].Point.x - curve.Center.x)**2 + (edge.Vertexes[1].Point.y - curve.Center.y)**2)
# Calculate angles based on x-axis (0 - PI/2)
start_angle = math.acos((edge.Vertexes[0].Point.x - curve.Center.x) / l1)
end_angle = math.acos((edge.Vertexes[1].Point.x - curve.Center.x) / l2)
# Angles are based on x-axis (Mirrored on x-axis) -> negative y value means negative angle
if edge.Vertexes[0].Point.y < curve.Center.y:
start_angle *= -1
if edge.Vertexes[1].Point.y < curve.Center.y:
end_angle *= -1
if (edge.Vertexes[0].Point.x > curve.Center.x or edge.Vertexes[1].Point.x > curve.Center.x) and curve.AngleXU < 0:
tmp = start_angle
start_angle = end_angle
end_angle = tmp
# Inside / Outside
if base.isInside(edge.Vertexes[0].Point, offset/2, True):
offset *= -1
if Side:
Side[0] = "Inside"
# Create new arc
if curve.AngleXU > 0:
edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius+offset), start_angle, end_angle).toShape()
else:
edge = Part.ArcOfCircle(Part.Circle(curve.Center, FreeCAD.Vector(0,0,1), curve.Radius-offset), start_angle, end_angle).toShape()
return Part.Wire([edge])
if Part.Line == type(curve) or Part.LineSegment == type(curve):
# offsetting a single edge doesn't work because there is an infinite
# possible planes into which the edge could be offset
@@ -197,12 +237,12 @@ def offsetWire(wire, base, offset, forward):#, Side = None):
if wire.isClosed():
if not base.isInside(owire.Edges[0].Vertexes[0].Point, offset/2, True):
PathLog.track('closed - outside')
# if Side:
# Side[0] = "Outside"
if Side:
Side[0] = "Outside"
return orientWire(owire, forward)
PathLog.track('closed - inside')
# if Side:
# Side[0] = "Inside"
if Side:
Side[0] = "Inside"
try:
owire = wire.makeOffset2D(-offset)
except Exception: # pylint: disable=broad-except

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2015 Dan Falck <ddfalck@gmail.com> *
# * Copyright (c) 2021 Schildkroet *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
@@ -115,7 +116,7 @@ class CHAMFERGate(PathBaseGate):
subShape = shape.getElement(sub)
if subShape.ShapeType == 'Edge':
return True
elif (subShape.ShapeType == 'Face' and subShape.normalAt(0, 0) == FreeCAD.Vector(0, 0, 1)):
elif (subShape.ShapeType == 'Face'):
return True
return False

View File

@@ -38,7 +38,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
tool.FlatRadius = 0
tool.CuttingEdgeAngle = 180
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True)
self.assertRoughly(0.01, depth)
self.assertRoughly(9, offset)
self.assertFalse(info)
@@ -46,7 +46,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
# legacy tools - no problem, same result
tool.CuttingEdgeAngle = 0
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.01, tool, True)
self.assertRoughly(0.01, depth)
self.assertRoughly(9, offset)
self.assertFalse(info)
@@ -57,12 +57,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
tool.FlatRadius = 0
tool.CuttingEdgeAngle = 90
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
self.assertRoughly(1, depth)
self.assertRoughly(0, offset)
self.assertFalse(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.2, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.2, tool, True)
self.assertRoughly(1.2, depth)
self.assertRoughly(0.2, offset)
self.assertFalse(info)
@@ -73,12 +73,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
tool.FlatRadius = 0.3
tool.CuttingEdgeAngle = 90
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
self.assertRoughly(1, depth)
self.assertRoughly(0.3, offset)
self.assertFalse(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(2, 0.2, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(2, 0.2, tool, True)
self.assertRoughly(2.2, depth)
self.assertRoughly(0.5, offset)
self.assertFalse(info)
@@ -91,12 +91,12 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
td = 1.73205
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0, tool, True)
self.assertRoughly(td, depth)
self.assertRoughly(10, offset)
self.assertFalse(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(3, 1, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(3, 1, tool, True)
self.assertRoughly(td * 3 + 1, depth)
self.assertRoughly(10 + td, offset)
self.assertFalse(info)
@@ -109,15 +109,15 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
self.Diameter = dia
tool = FakeEndmill(10)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True)
self.assertRoughly(0.1, depth)
self.assertRoughly(4, offset)
self.assertTrue(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
self.assertRoughly(0.1, depth)
self.assertRoughly(4, offset)
self.assertTrue(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
self.assertRoughly(0.1, depth)
self.assertRoughly(4, offset)
self.assertTrue(info)
@@ -131,15 +131,15 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
self.CuttingEdgeAngle = angle
tool = FakePointyBit(10, 90)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, True)
self.assertRoughly(1.1, depth)
self.assertRoughly(0.1, offset)
self.assertTrue(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
self.assertRoughly(1.1, depth)
self.assertRoughly(0.1, offset)
self.assertTrue(info)
(depth, offset, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
(depth, offset, __, info) = PathDeburr.toolDepthAndOffset(1, 0.1, tool, not info)
self.assertRoughly(1.1, depth)
self.assertRoughly(0.1, offset)
self.assertTrue(info)