Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86423803
materials.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Oct 6, 10:09
Size
17 KB
Mime Type
text/x-python
Expires
Tue, Oct 8, 10:09 (1 d, 21 h)
Engine
blob
Format
Raw Data
Handle
21420845
Attached To
R8831 BIMxBEM
materials.py
View Options
# coding: utf8
"""This module reads IfcRelSpaceBoundary from an IFC file and display them in FreeCAD
© All rights reserved.
ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, Laboratory CNPA, 2019-2020
See the LICENSE.TXT file for more details.
Author : Cyril Waechter
"""
import
typing
import
ifcopenshell
import
FreeCAD
from
freecad.bem
import
utils
if
typing
.
TYPE_CHECKING
:
from
freecad.bem.typing
import
(
# pylint: disable=no-name-in-module, import-error
MaterialFeature
,
LayerSetFeature
,
ConstituentSetFeature
,
)
class
MaterialCreator
:
def
__init__
(
self
,
ifc_importer
=
None
):
self
.
obj
=
None
self
.
materials
=
{}
self
.
material_layer_sets
=
{}
self
.
material_constituent_sets
=
{}
self
.
material_profile_sets
=
{}
self
.
ifc_scale
=
1
self
.
fc_scale
=
1
if
ifc_importer
:
self
.
ifc_scale
=
ifc_importer
.
ifc_scale
self
.
fc_scale
=
ifc_importer
.
fc_scale
self
.
ifc_importer
=
ifc_importer
def
create
(
self
,
obj
,
ifc_entity
):
self
.
obj
=
obj
self
.
parse_material
(
ifc_entity
)
def
parse_material
(
self
,
ifc_entity
):
self
.
parse_associations
(
ifc_entity
)
if
self
.
obj
.
Material
:
return
entity_type
=
ifcopenshell
.
util
.
element
.
get_type
(
ifc_entity
)
if
entity_type
:
self
.
parse_associations
(
entity_type
)
if
self
.
obj
.
Material
:
return
# When an element is composed of multiple elements
if
ifc_entity
.
IsDecomposedBy
:
# TODO: See in a real case how to handle every part and not only the first
ifc_entity
=
ifc_entity
.
IsDecomposedBy
[
0
]
.
RelatedObjects
[
0
]
self
.
parse_associations
(
ifc_entity
)
def
parse_associations
(
self
,
ifc_entity
):
for
association
in
ifc_entity
.
HasAssociations
:
if
association
.
is_a
(
"IfcRelAssociatesMaterial"
):
material_select
=
association
.
RelatingMaterial
if
self
.
is_material_definition
(
material_select
):
self
.
assign_material
(
material_select
)
elif
material_select
.
is_a
(
"IfcMaterialLayerSetUsage"
):
self
.
create_layer_set_usage
(
material_select
)
elif
material_select
.
is_a
(
"IfcMaterialList"
):
self
.
create_constituent_set_from_material_list
(
material_select
,
ifc_entity
)
else
:
raise
NotImplementedError
(
f
"{material_select.is_a()} not handled yet"
)
@staticmethod
def
is_material_definition
(
material_select
):
"""Material Definition is new to IFC4. So doing material_select.is_a("MaterialDefinition")
in IFC2x3 would return False event if it is in IFC4 schema."""
valid_class
=
(
"IfcMaterial"
,
"IfcMaterialLayer"
,
"IfcMaterialLayerSet"
,
"IfcMaterialProfile"
,
"IfcMaterialProfileSet"
,
"IfcMaterialConstituent"
,
"IfcMaterialConstituentSet"
,
)
return
material_select
.
is_a
()
in
valid_class
def
create_layer_set_usage
(
self
,
usage
):
self
.
assign_material
(
usage
.
ForLayerSet
)
self
.
obj
.
Material
.
LayerSetDirection
=
usage
.
LayerSetDirection
self
.
obj
.
Material
.
DirectionSense
=
usage
.
DirectionSense
def
assign_material
(
self
,
material_select
):
if
material_select
.
is_a
(
"IfcMaterial"
):
self
.
obj
.
Material
=
self
.
create_single
(
material_select
)
elif
material_select
.
is_a
(
"IfcMaterialLayerSet"
):
self
.
obj
.
Material
=
self
.
create_layer_set
(
material_select
)
utils
.
append
(
self
.
obj
.
Material
,
"AssociatedTo"
,
self
.
obj
)
elif
material_select
.
is_a
(
"IfcMaterialConstituentSet"
):
self
.
obj
.
Material
=
self
.
create_constituent_set
(
material_select
)
elif
material_select
.
is_a
(
"IfcMaterialProfileSet"
):
self
.
obj
.
Material
=
self
.
create_profile_set
(
material_select
)
else
:
raise
NotImplementedError
(
f
"{material_select.is_a()} not handled yet"
)
def
create_single
(
self
,
material
):
if
material
.
Name
not
in
self
.
materials
:
return
self
.
create_new_single
(
material
)
return
self
.
materials
[
material
.
Name
]
def
create_new_single
(
self
,
material
):
fc_material
=
Material
.
create
(
material
)
self
.
materials
[
material
.
Name
]
=
fc_material
return
fc_material
def
create_layer_set
(
self
,
layer_set
):
if
layer_set
.
LayerSetName
not
in
self
.
material_layer_sets
:
fc_layer_set
=
LayerSet
.
create
(
layer_set
)
layers
=
[]
layers_thickness
=
[]
for
layer
in
layer_set
.
MaterialLayers
:
layers
.
append
(
self
.
create_single
(
layer
.
Material
))
layers_thickness
.
append
(
layer
.
LayerThickness
*
self
.
ifc_scale
)
fc_layer_set
.
MaterialLayers
=
layers
fc_layer_set
.
Thicknesses
=
layers_thickness
if
not
fc_layer_set
.
TotalThickness
:
fc_layer_set
.
TotalThickness
=
sum
(
layers_thickness
)
*
self
.
fc_scale
self
.
material_layer_sets
[
fc_layer_set
.
IfcName
]
=
fc_layer_set
return
fc_layer_set
return
self
.
material_layer_sets
[
layer_set
.
LayerSetName
]
def
create_constituent_set
(
self
,
constituent_set
):
if
constituent_set
.
Name
not
in
self
.
material_constituent_sets
:
fc_constituent_set
=
ConstituentSet
.
create
(
constituent_set
)
constituents
=
[]
constituents_fraction
=
[]
constituents_categories
=
[]
for
constituent
in
constituent_set
.
MaterialConstituents
:
constituents
.
append
(
self
.
create_single
(
constituent
.
Material
))
constituents_fraction
.
append
(
constituent
.
Fraction
or
0
)
constituents_categories
.
append
(
constituent
.
Category
or
""
)
fc_constituent_set
.
MaterialConstituents
=
constituents
fc_constituent_set
.
Fractions
=
constituents_fraction
fc_constituent_set
.
Categories
=
constituents_categories
self
.
material_constituent_sets
[
fc_constituent_set
.
IfcName
]
=
fc_constituent_set
return
fc_constituent_set
return
self
.
material_constituent_sets
[
constituent_set
.
Name
]
def
create_constituent_set_from_material_list
(
self
,
material_list
,
ifc_element
):
constituent_set
=
ConstituentSet
.
create
()
constituent_set
.
IfcType
=
material_list
.
is_a
()
constituent_set
.
IfcName
=
self
.
get_type_name
(
ifc_element
)
constituent_set
.
Id
=
material_list
.
id
()
constituent_set
.
Label
=
f
"{constituent_set.Id}_{constituent_set.IfcName}"
materials
=
material_list
.
Materials
constituent_set
.
Fractions
=
[
1
/
len
(
materials
)]
*
len
(
materials
)
constituent_set
.
Categories
=
[
"MaterialList"
]
*
len
(
materials
)
material_constituents
=
list
()
for
material
in
materials
:
material_constituents
.
append
(
self
.
create_single
(
material
))
constituent_set
.
MaterialConstituents
=
material_constituents
self
.
obj
.
Material
=
constituent_set
def
create_profile_set
(
self
,
profile_set
):
if
profile_set
.
Name
not
in
self
.
material_profile_sets
:
fc_profile_set
=
ProfileSet
.
create
(
profile_set
)
profiles
=
[]
profiles_categories
=
[]
for
profile
in
profile_set
.
MaterialProfiles
:
profiles
.
append
(
self
.
create_single
(
profile
.
Material
))
profiles_categories
.
append
(
profile
.
Category
or
""
)
fc_profile_set
.
MaterialProfiles
=
profiles
fc_profile_set
.
Categories
=
profiles_categories
self
.
material_profile_sets
[
fc_profile_set
.
IfcName
]
=
fc_profile_set
return
fc_profile_set
return
self
.
material_profile_sets
[
profile_set
.
Name
]
def
get_type_name
(
self
,
ifc_element
):
if
ifc_element
.
is_a
(
"IfcTypeObject"
):
return
ifc_element
.
Name
if
ifc_element
.
ObjectType
:
return
ifc_element
.
ObjectType
for
definition
in
ifc_element
.
IsDefinedBy
:
if
definition
.
is_a
(
"IfcRelDefinesByType"
):
return
definition
.
RelatingType
.
Name
class
ConstituentSet
:
attributes
=
()
psets_dict
=
{}
parts_name
=
"Layers"
part_name
=
"Layer"
part_props
=
(
"MaterialConstituents"
,
"Fractions"
,
"Categories"
)
part_attribs
=
(
"Id"
,
"Fraction"
,
"Category"
)
def
__init__
(
self
,
obj
,
ifc_entity
):
self
.
ifc_entity
=
ifc_entity
self
.
_init_properties
(
obj
,
ifc_entity
)
self
.
Type
=
"MaterialConstituentSet"
# pylint: disable=invalid-name
obj
.
Proxy
=
self
@classmethod
def
create
(
cls
,
ifc_entity
=
None
)
->
"ConstituentSetFeature"
:
"""Stantard FreeCAD FeaturePython Object creation method
ifc_entity : Optionnally provide a base entity.
"""
obj
=
FreeCAD
.
ActiveDocument
.
addObject
(
"Part::FeaturePython"
,
"MaterialConstituentSet"
)
ConstituentSet
(
obj
,
ifc_entity
)
return
obj
def
_init_properties
(
self
,
obj
:
"ConstituentSetFeature"
,
ifc_entity
)
->
None
:
obj
.
addProperty
(
"App::PropertyString"
,
"IfcType"
,
"IFC"
)
obj
.
addProperty
(
"App::PropertyFloatList"
,
"Fractions"
,
"BEM"
)
obj
.
addProperty
(
"App::PropertyStringList"
,
"Categories"
,
"BEM"
)
ifc_attributes
=
"IFC Attributes"
obj
.
addProperty
(
"App::PropertyInteger"
,
"Id"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"IfcName"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"Description"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyLinkList"
,
"MaterialConstituents"
,
ifc_attributes
)
if
not
ifc_entity
:
return
obj
.
Id
=
ifc_entity
.
id
()
obj
.
IfcName
=
ifc_entity
.
Name
or
""
obj
.
Description
=
ifc_entity
.
Description
or
""
obj
.
Label
=
f
"{obj.Id}_{obj.IfcName}"
obj
.
IfcType
=
ifc_entity
.
is_a
()
class
LayerSet
:
attributes
=
(
"TotalThickness"
,)
psets_dict
=
{}
parts_name
=
"Layers"
part_name
=
"Layer"
part_props
=
(
"MaterialLayers"
,
"Thicknesses"
)
part_attribs
=
(
"Id"
,
"Thickness"
)
def
__init__
(
self
,
obj
:
"LayerSetFeature"
,
ifc_entity
)
->
None
:
self
.
ifc_entity
=
ifc_entity
self
.
_init_properties
(
obj
,
ifc_entity
)
self
.
materials
=
{}
self
.
Type
=
"MaterialLayerSet"
# pylint: disable=invalid-name
obj
.
Proxy
=
self
@classmethod
def
create
(
cls
,
ifc_entity
=
None
)
->
"ConstituentSetFeature"
:
"""Stantard FreeCAD FeaturePython Object creation method
ifc_entity : Optionnally provide a base entity.
"""
obj
=
FreeCAD
.
ActiveDocument
.
addObject
(
"Part::FeaturePython"
,
"Material"
)
LayerSet
(
obj
,
ifc_entity
)
return
obj
def
_init_properties
(
self
,
obj
:
"LayerSetFeature"
,
ifc_entity
)
->
None
:
obj
.
addProperty
(
"App::PropertyString"
,
"IfcType"
,
"IFC"
)
obj
.
addProperty
(
"App::PropertyFloatList"
,
"Thicknesses"
,
"BEM"
)
ifc_attributes
=
"IFC Attributes"
obj
.
addProperty
(
"App::PropertyInteger"
,
"Id"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyLinkList"
,
"MaterialLayers"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"IfcName"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"Description"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyLength"
,
"TotalThickness"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyEnumeration"
,
"LayerSetDirection"
,
ifc_attributes
)
.
LayerSetDirection
=
[
"AXIS1"
,
"AXIS2"
,
"AXIS3"
]
obj
.
addProperty
(
"App::PropertyEnumeration"
,
"DirectionSense"
,
ifc_attributes
)
.
DirectionSense
=
[
"POSITIVE"
,
"NEGATIVE"
]
obj
.
addProperty
(
"App::PropertyLinkListHidden"
,
"AssociatedTo"
,
ifc_attributes
)
if
not
ifc_entity
:
return
obj
.
Id
=
ifc_entity
.
id
()
obj
.
IfcName
=
ifc_entity
.
LayerSetName
or
""
# Description is new to IFC4 so IFC2x3 raise attribute error
try
:
obj
.
Description
=
ifc_entity
.
Description
or
""
except
AttributeError
:
pass
obj
.
Label
=
f
"{obj.Id}_{obj.IfcName}"
obj
.
IfcType
=
ifc_entity
.
is_a
()
if
ifc_entity
.
is_a
(
"IfcWall"
):
obj
.
LayerSetDirection
=
"AXIS2"
elif
ifc_entity
.
is_a
(
"IfcSlab"
)
or
ifc_entity
.
is_a
(
"IfcRoof"
):
obj
.
LayerSetDirection
=
"AXIS3"
obj
.
DirectionSense
=
"POSITIVE"
class
Material
:
attributes
=
(
"Category"
,)
psets_dict
=
{
"Pset_MaterialCommon"
:
(
"MassDensity"
,
"Porosity"
),
"Pset_MaterialOptical"
:
(
"VisibleTransmittance"
,
"SolarTransmittance"
,
"ThermalIrTransmittance"
,
"ThermalIrEmissivityBack"
,
"ThermalIrEmissivityFront"
,
),
"Pset_MaterialThermal"
:
(
"SpecificHeatCapacity"
,
"ThermalConductivity"
,
),
}
parts_name
=
""
part_name
=
""
part_props
=
()
part_attribs
=
()
def
__init__
(
self
,
obj
,
ifc_entity
=
None
):
self
.
ifc_entity
=
ifc_entity
self
.
_init_properties
(
obj
)
self
.
Type
=
"Material"
# pylint: disable=invalid-name
obj
.
Proxy
=
self
@classmethod
def
create
(
cls
,
ifc_entity
=
None
)
->
"MaterialFeature"
:
"""Stantard FreeCAD FeaturePython Object creation method
ifc_entity : Optionnally provide a base entity.
"""
obj
=
FreeCAD
.
ActiveDocument
.
addObject
(
"Part::FeaturePython"
,
"Material"
)
cls
(
obj
,
ifc_entity
)
return
obj
def
_init_properties
(
self
,
obj
)
->
None
:
obj
.
addProperty
(
"App::PropertyString"
,
"IfcType"
,
"IFC"
)
ifc_attributes
=
"IFC Attributes"
obj
.
addProperty
(
"App::PropertyInteger"
,
"Id"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"IfcName"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"Description"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"Category"
,
ifc_attributes
)
pset_name
=
"Pset_MaterialCommon"
obj
.
addProperty
(
"App::PropertyFloat"
,
"MassDensity"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"Porosity"
,
pset_name
)
pset_name
=
"Pset_MaterialOptical"
obj
.
addProperty
(
"App::PropertyFloat"
,
"VisibleTransmittance"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"SolarTransmittance"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"ThermalIrTransmittance"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"ThermalIrEmissivityBack"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"ThermalIrEmissivityFront"
,
pset_name
)
pset_name
=
"Pset_MaterialThermal"
obj
.
addProperty
(
"App::PropertyFloat"
,
"SpecificHeatCapacity"
,
pset_name
)
obj
.
addProperty
(
"App::PropertyFloat"
,
"ThermalConductivity"
,
pset_name
)
ifc_entity
=
self
.
ifc_entity
if
not
ifc_entity
:
return
obj
.
Id
=
ifc_entity
.
id
()
obj
.
IfcName
=
ifc_entity
.
Name
obj
.
Label
=
f
"{obj.Id}_{obj.IfcName}"
# Description is new to IFC4 so IFC2x3 raise attribute error
obj
.
Description
=
getattr
(
ifc_entity
,
"Description"
,
""
)
or
""
obj
.
IfcType
=
ifc_entity
.
is_a
()
for
pset
in
getattr
(
ifc_entity
,
"HasProperties"
,
()):
if
pset
.
Name
in
self
.
psets_dict
.
keys
():
for
prop
in
pset
.
Properties
:
if
prop
.
Name
in
self
.
psets_dict
[
pset
.
Name
]:
setattr
(
obj
,
prop
.
Name
,
prop
.
NominalValue
.
wrappedValue
)
class
ProfileSet
:
attributes
=
()
psets_dict
=
{}
parts_name
=
"Layers"
part_name
=
"Layer"
part_props
=
(
"MaterialProfiles"
,)
part_attribs
=
(
"Id"
,
"Category"
,
)
def
__init__
(
self
,
obj
,
ifc_entity
):
self
.
ifc_entity
=
ifc_entity
self
.
_init_properties
(
obj
,
ifc_entity
)
self
.
Type
=
"ProfileSet"
# pylint: disable=invalid-name
obj
.
Proxy
=
self
@classmethod
def
create
(
cls
,
ifc_entity
=
None
)
->
"ProfileSetFeature"
:
"""Stantard FreeCAD FeaturePython Object creation method
ifc_entity : Optionnally provide a base entity.
"""
obj
=
FreeCAD
.
ActiveDocument
.
addObject
(
"Part::FeaturePython"
,
"MaterialProfileSet"
)
ProfileSet
(
obj
,
ifc_entity
)
return
obj
def
_init_properties
(
self
,
obj
:
"ProfileSetFeature"
,
ifc_entity
)
->
None
:
obj
.
addProperty
(
"App::PropertyString"
,
"IfcType"
,
"IFC"
)
obj
.
addProperty
(
"App::PropertyStringList"
,
"Categories"
,
"BEM"
)
ifc_attributes
=
"IFC Attributes"
obj
.
addProperty
(
"App::PropertyInteger"
,
"Id"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"IfcName"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyString"
,
"Description"
,
ifc_attributes
)
obj
.
addProperty
(
"App::PropertyLinkList"
,
"MaterialProfiles"
,
ifc_attributes
)
if
not
ifc_entity
:
return
obj
.
Id
=
ifc_entity
.
id
()
obj
.
IfcName
=
ifc_entity
.
Name
or
""
obj
.
Description
=
ifc_entity
.
Description
or
""
obj
.
Label
=
f
"{obj.Id}_{obj.IfcName}"
obj
.
IfcType
=
ifc_entity
.
is_a
()
def
get_type
(
ifc_entity
):
if
ifc_entity
.
ObjectType
:
return
ifc_entity
.
ObjectType
for
definition
in
ifc_entity
.
IsDefinedBy
:
if
definition
.
is_a
(
"IfcRelDefineByType"
):
return
definition
.
RelatingType
.
Name
Event Timeline
Log In to Comment