This commit is contained in:
Andrej730
2024-05-29 17:39:41 +05:00
parent 3679fccfbd
commit 45a1655485
13 changed files with 260 additions and 140 deletions
@@ -198,8 +198,11 @@ class CostSchedulesData:
# data["DerivedUnitSymbol"] = "?" # data["DerivedUnitSymbol"] = "?"
# print("Total Cost", data["DerivedTotalCostQuantity"], cost_item.Name) # print("Total Cost", data["DerivedTotalCostQuantity"], cost_item.Name)
# TODO: dead code?
@classmethod @classmethod
def _get_object_quantities(cls, cost_item, element): def _get_object_quantities(
cls, cost_item: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
) -> list[int]:
if not element.is_a("IfcObject"): if not element.is_a("IfcObject"):
return [] return []
cost_quantities = cost_item.CostQuantities cost_quantities = cost_item.CostQuantities
@@ -28,6 +28,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.representation import ifcopenshell.util.representation
import ifcopenshell.util.placement import ifcopenshell.util.placement
import ifcopenshell.api import ifcopenshell.api
import blenderbim.core.geometry
import blenderbim.core.geometry as core import blenderbim.core.geometry as core
import blenderbim.core.aggregate import blenderbim.core.aggregate
import blenderbim.core.style import blenderbim.core.style
@@ -22,6 +22,7 @@ import blenderbim.bim.helper
import blenderbim.bim.handler import blenderbim.bim.handler
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.core.style as core import blenderbim.core.style as core
import ifcopenshell.api
import ifcopenshell.util.representation import ifcopenshell.util.representation
from blenderbim.bim.module.style.prop import switch_shading from blenderbim.bim.module.style.prop import switch_shading
from pathlib import Path from pathlib import Path
+33 -5
View File
@@ -16,16 +16,30 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Union
def enable_editing_aggregate(aggregator, obj=None): if TYPE_CHECKING:
import bpy
import ifcopenshell
import blenderbim.tool as tool
def enable_editing_aggregate(aggregator: tool.Aggregate, obj: bpy.types.Object) -> None:
aggregator.enable_editing(obj) aggregator.enable_editing(obj)
def disable_editing_aggregate(aggregator, obj=None): def disable_editing_aggregate(aggregator: tool.Aggregate, obj: bpy.types.Object) -> None:
aggregator.disable_editing(obj) aggregator.disable_editing(obj)
def assign_object(ifc, aggregator, collector, relating_obj=None, related_obj=None): def assign_object(
ifc: tool.Ifc,
aggregator: tool.Aggregate,
collector: tool.Collector,
relating_obj: Optional[bpy.types.Object] = None,
related_obj: Optional[bpy.types.Object] = None,
) -> Union[ifcopenshell.entity_instance, None]:
if not aggregator.can_aggregate(relating_obj, related_obj): if not aggregator.can_aggregate(relating_obj, related_obj):
return return
rel = ifc.run( rel = ifc.run(
@@ -37,7 +51,13 @@ def assign_object(ifc, aggregator, collector, relating_obj=None, related_obj=Non
return rel return rel
def unassign_object(ifc, aggregate, collector, relating_obj=None, related_obj=None): def unassign_object(
ifc: tool.Ifc,
aggregate: tool.Aggregate,
collector: tool.Collector,
relating_obj: Optional[bpy.types.Object] = None,
related_obj: Optional[bpy.types.Object] = None,
) -> None:
related_element = ifc.get_entity(related_obj) related_element = ifc.get_entity(related_obj)
container = aggregate.get_container(related_element) container = aggregate.get_container(related_element)
if not relating_obj: if not relating_obj:
@@ -52,7 +72,15 @@ def unassign_object(ifc, aggregate, collector, relating_obj=None, related_obj=No
collector.assign(related_obj) collector.assign(related_obj)
def add_part_to_object(ifc, aggregator, collector, blender, obj, part_class, part_name=None): def add_part_to_object(
ifc: tool.Ifc,
aggregator: tool.Aggregate,
collector: tool.Collector,
blender: tool.Blender,
obj: bpy.types.Object,
part_class: str,
part_name: Optional[str] = None,
) -> None:
part_obj = blender.create_ifc_object(ifc_class=part_class, name=part_name) part_obj = blender.create_ifc_object(ifc_class=part_class, name=part_name)
assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_obj) assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_obj)
blender.set_active_object(obj) blender.set_active_object(obj)
+41 -15
View File
@@ -16,15 +16,33 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Union
def unlink_material(ifc, obj=None): if TYPE_CHECKING:
import bpy
import ifcopenshell
import blenderbim.tool as tool
def unlink_material(ifc: tool.Ifc, obj: bpy.types.Material) -> None:
ifc.unlink(obj=obj) ifc.unlink(obj=obj)
def add_material(ifc, material, style, obj=None, name=None, category=None, description=None): def add_material(
ifc: tool.Ifc,
material: tool.Material,
style: tool.Style,
obj: Optional[bpy.types.Material] = None,
name: Optional[str] = None,
category: Optional[str] = None,
description: Optional[str] = None,
) -> ifcopenshell.entity_instance:
if not obj: if not obj:
obj = material.add_default_material_object(name) obj = material.add_default_material_object(name)
ifc_material = ifc.run("material.add_material", name=material.get_name(obj), category=category, description=description) ifc_material = ifc.run(
"material.add_material", name=material.get_name(obj), category=category, description=description
)
ifc.link(ifc_material, obj) ifc.link(ifc_material, obj)
ifc_style = style.get_style(obj) ifc_style = style.get_style(obj)
if ifc_style: if ifc_style:
@@ -36,14 +54,16 @@ def add_material(ifc, material, style, obj=None, name=None, category=None, descr
return ifc_material return ifc_material
def add_material_set(ifc, material, set_type=None): def add_material_set(ifc: tool.Ifc, material: tool.Material, set_type: str) -> ifcopenshell.entity_instance:
ifc_material = ifc.run("material.add_material_set", name="Unnamed", set_type=set_type) ifc_material = ifc.run("material.add_material_set", name="Unnamed", set_type=set_type)
if material.is_editing_materials(): if material.is_editing_materials():
material.import_material_definitions(material.get_active_material_type()) material.import_material_definitions(material.get_active_material_type())
return ifc_material return ifc_material
def remove_material(ifc, material_tool, style, material=None) -> bool: def remove_material(
ifc: tool.Ifc, material_tool: tool.Material, style: tool.Style, material: ifcopenshell.entity_instance
) -> bool:
"""returns True after deleting False,\n """returns True after deleting False,\n
returns False if material used in material sets and cannot be removed""" returns False if material used in material sets and cannot be removed"""
if material_tool.is_material_used_in_sets(material): if material_tool.is_material_used_in_sets(material):
@@ -58,31 +78,33 @@ def remove_material(ifc, material_tool, style, material=None) -> bool:
return True return True
def remove_material_set(ifc, material_tool, material=None): def remove_material_set(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None:
ifc.run("material.remove_material_set", material=material) ifc.run("material.remove_material_set", material=material)
if material_tool.is_editing_materials(): if material_tool.is_editing_materials():
material_tool.import_material_definitions(material_tool.get_active_material_type()) material_tool.import_material_definitions(material_tool.get_active_material_type())
def load_materials(material, material_type=None): def load_materials(material: tool.Material, material_type: str) -> None:
material.import_material_definitions(material_type) material.import_material_definitions(material_type)
material.enable_editing_materials() material.enable_editing_materials()
def disable_editing_materials(material): def disable_editing_materials(material: tool.Material) -> None:
material.disable_editing_materials() material.disable_editing_materials()
def select_by_material(material_tool, spatial, material=None): def select_by_material(
material_tool: tool.Material, spatial: tool.Spatial, material: ifcopenshell.entity_instance
) -> None:
spatial.select_products(material_tool.get_elements_by_material(material)) spatial.select_products(material_tool.get_elements_by_material(material))
def enable_editing_material(material_tool, material): def enable_editing_material(material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None:
material_tool.load_material_attributes(material) material_tool.load_material_attributes(material)
material_tool.enable_editing_material(material) material_tool.enable_editing_material(material)
def edit_material(ifc, material_tool, material): def edit_material(ifc: tool.Ifc, material_tool: tool.Material, material: ifcopenshell.entity_instance) -> None:
attributes = material_tool.get_material_attributes() attributes = material_tool.get_material_attributes()
ifc.run("material.edit_material", material=material, attributes=attributes) ifc.run("material.edit_material", material=material, attributes=attributes)
material_tool.sync_blender_material_name(material) material_tool.sync_blender_material_name(material)
@@ -92,11 +114,13 @@ def edit_material(ifc, material_tool, material):
material_tool.enable_editing_materials() material_tool.enable_editing_materials()
def disable_editing_material(material_tool): def disable_editing_material(material_tool: tool.Material) -> None:
material_tool.disable_editing_material() material_tool.disable_editing_material()
def assign_material(ifc, material_tool, material_type, objects): def assign_material(
ifc: tool.Ifc, material_tool: tool.Material, material_type: Union[str, None], objects: list[bpy.types.Object]
) -> None:
material_type = material_type or material_tool.get_active_object_material() material_type = material_type or material_tool.get_active_object_material()
material = material_tool.get_active_material() material = material_tool.get_active_material()
for obj in objects: for obj in objects:
@@ -109,7 +133,7 @@ def assign_material(ifc, material_tool, material_type, objects):
material_tool.add_material_to_set(material_set=assigned_material, material=material) material_tool.add_material_to_set(material_set=assigned_material, material=material)
def unassign_material(ifc, material_tool, objects): def unassign_material(ifc: tool.Ifc, material_tool: tool.Material, objects: list[bpy.types.Object]) -> None:
for obj in objects: for obj in objects:
element = ifc.get_entity(obj) element = ifc.get_entity(obj)
if element: if element:
@@ -125,7 +149,9 @@ def unassign_material(ifc, material_tool, objects):
ifc.run("material.unassign_material", products=[element]) ifc.run("material.unassign_material", products=[element])
def patch_non_parametric_mep_segment(ifc, material_tool, profile_tool, obj): def patch_non_parametric_mep_segment(
ifc: tool.Ifc, material_tool: tool.Material, profile_tool: tool.Profile, obj: bpy.types.Object
) -> None:
element = ifc.get_entity(obj) element = ifc.get_entity(obj)
if not element: if not element:
return return
+31 -13
View File
@@ -16,8 +16,16 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Any
def add_style(ifc, style, obj=None): if TYPE_CHECKING:
import bpy
import ifcopenshell
import blenderbim.tool as tool
def add_style(ifc: tool.Ifc, style: tool.Style, obj: bpy.types.Material) -> ifcopenshell.entity_instance:
element = ifc.run("style.add_style", name=style.get_name(obj)) element = ifc.run("style.add_style", name=style.get_name(obj))
ifc.link(element, obj) ifc.link(element, obj)
if style.can_support_rendering_style(obj): if style.can_support_rendering_style(obj):
@@ -33,18 +41,26 @@ def add_style(ifc, style, obj=None):
return element return element
def add_external_style(ifc, style, obj, attributes): def add_external_style(ifc: tool.Ifc, style: tool.Style, obj: bpy.types.Material, attributes: dict[str, Any]) -> None:
element = style.get_style(obj) element = style.get_style(obj)
ifc.run( ifc.run(
"style.add_surface_style", style=element, ifc_class="IfcExternallyDefinedSurfaceStyle", attributes=attributes "style.add_surface_style", style=element, ifc_class="IfcExternallyDefinedSurfaceStyle", attributes=attributes
) )
def update_external_style(ifc, style, external_style, attributes): # TODO: unused `style` argument?
def update_external_style(
ifc: tool.Ifc,
style: ifcopenshell.entity_instance,
external_style: ifcopenshell.entity_instance,
attributes: dict[str, Any],
) -> None:
ifc.run("style.edit_surface_style", style=external_style, attributes=attributes) ifc.run("style.edit_surface_style", style=external_style, attributes=attributes)
def remove_style(ifc, material, style_tool, style=None): def remove_style(
ifc: tool.Ifc, material: tool.Material, style_tool: tool.Style, style: ifcopenshell.entity_instance
) -> None:
obj = ifc.get_object(style) obj = ifc.get_object(style)
ifc.unlink(obj=obj, element=style) ifc.unlink(obj=obj, element=style)
ifc.run("style.remove_style", style=style) ifc.run("style.remove_style", style=style)
@@ -54,7 +70,7 @@ def remove_style(ifc, material, style_tool, style=None):
style_tool.import_presentation_styles(style_tool.get_active_style_type()) style_tool.import_presentation_styles(style_tool.get_active_style_type())
def update_style_colours(ifc, style, obj=None, verbose=False): def update_style_colours(ifc: tool.Ifc, style: tool.Style, obj: bpy.types.Material, verbose: bool = False) -> None:
element = style.get_style(obj) element = style.get_style(obj)
if style.can_support_rendering_style(obj): if style.can_support_rendering_style(obj):
@@ -91,7 +107,9 @@ def update_style_colours(ifc, style, obj=None, verbose=False):
style.record_shading(obj) style.record_shading(obj)
def update_style_textures(ifc, style, obj=None, representation=None): def update_style_textures(
ifc: tool.Ifc, style: tool.Style, obj: ifcopenshell.entity_instance, representation: ifcopenshell.entity_instance
) -> None:
element = style.get_style(obj) element = style.get_style(obj)
uv_maps = style.get_uv_maps(representation) uv_maps = style.get_uv_maps(representation)
@@ -111,34 +129,34 @@ def update_style_textures(ifc, style, obj=None, representation=None):
ifc.run("style.remove_surface_style", style=texture_style) ifc.run("style.remove_surface_style", style=texture_style)
def unlink_style(ifc, style=None): def unlink_style(ifc: tool.Ifc, style: ifcopenshell.entity_instance) -> None:
obj = ifc.get_object(style) obj = ifc.get_object(style)
ifc.unlink(obj=obj, element=style) ifc.unlink(obj=obj, element=style)
def enable_editing_style(style, obj=None): def enable_editing_style(style: tool.Style, obj: bpy.types.Material) -> None:
style.enable_editing(obj) style.enable_editing(obj)
style.import_surface_attributes(style.get_style(obj), obj) style.import_surface_attributes(style.get_style(obj), obj)
def disable_editing_style(style, obj=None): def disable_editing_style(style: tool.Style, obj: bpy.types.Material) -> None:
style.disable_editing(obj) style.disable_editing(obj)
def edit_style(ifc, style, obj=None): def edit_style(ifc: tool.Ifc, style: tool.Style, obj: bpy.types.Material) -> None:
attributes = style.export_surface_attributes(obj) attributes = style.export_surface_attributes(obj)
ifc.run("style.edit_presentation_style", style=style.get_style(obj), attributes=attributes) ifc.run("style.edit_presentation_style", style=style.get_style(obj), attributes=attributes)
style.disable_editing(obj) style.disable_editing(obj)
def load_styles(style, style_type=None): def load_styles(style: tool.Style, style_type: str) -> None:
style.import_presentation_styles(style_type) style.import_presentation_styles(style_type)
style.enable_editing_styles() style.enable_editing_styles()
def disable_editing_styles(style): def disable_editing_styles(style: tool.Style) -> None:
style.disable_editing_styles() style.disable_editing_styles()
def select_by_style(style_tool, spatial, style=None): def select_by_style(style_tool: tool.Style, spatial: tool.Spatial, style: ifcopenshell.entity_instance) -> None:
spatial.select_products(style_tool.get_elements_by_style(style)) spatial.select_products(style_tool.get_elements_by_style(style))
+7 -4
View File
@@ -20,6 +20,7 @@ import bpy
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
import ifcopenshell.util.element import ifcopenshell.util.element
from typing import Union
class Aggregate(blenderbim.core.tool.Aggregate): class Aggregate(blenderbim.core.tool.Aggregate):
@@ -46,19 +47,21 @@ class Aggregate(blenderbim.core.tool.Aggregate):
return False return False
@classmethod @classmethod
def disable_editing(cls, obj): def disable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMObjectAggregateProperties.is_editing = False obj.BIMObjectAggregateProperties.is_editing = False
@classmethod @classmethod
def enable_editing(cls, obj): def enable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMObjectAggregateProperties.is_editing = True obj.BIMObjectAggregateProperties.is_editing = True
@classmethod @classmethod
def get_container(cls, element): def get_container(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
return ifcopenshell.util.element.get_container(element) return ifcopenshell.util.element.get_container(element)
@classmethod @classmethod
def get_relating_object(cls, related_element): def get_relating_object(
cls, related_element: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]:
for rel in related_element.Decomposes: for rel in related_element.Decomposes:
if rel.is_a("IfcRelAggregates"): if rel.is_a("IfcRelAggregates"):
return rel.RelatingObject return rel.RelatingObject
+34 -26
View File
@@ -19,43 +19,45 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.core.material
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.helper import blenderbim.bim.helper
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.element import ifcopenshell.util.element
from typing import Union, Any
class Material(blenderbim.core.tool.Material): class Material(blenderbim.core.tool.Material):
@classmethod @classmethod
def add_default_material_object(cls, name): def add_default_material_object(cls, name: Union[str, None]) -> bpy.types.Material:
return bpy.data.materials.new(name or "Default") return bpy.data.materials.new(name or "Default")
@classmethod @classmethod
def delete_object(cls, obj): def delete_object(cls, obj: bpy.types.Material) -> None:
bpy.data.materials.remove(obj) bpy.data.materials.remove(obj)
@classmethod @classmethod
def disable_editing_materials(cls): def disable_editing_materials(cls) -> None:
bpy.context.scene.BIMMaterialProperties.is_editing = False bpy.context.scene.BIMMaterialProperties.is_editing = False
@classmethod @classmethod
def enable_editing_materials(cls): def enable_editing_materials(cls) -> None:
bpy.context.scene.BIMMaterialProperties.is_editing = True bpy.context.scene.BIMMaterialProperties.is_editing = True
@classmethod @classmethod
def get_active_material_type(cls): def get_active_material_type(cls) -> str:
return bpy.context.scene.BIMMaterialProperties.material_type return bpy.context.scene.BIMMaterialProperties.material_type
@classmethod @classmethod
def get_elements_by_material(cls, material): def get_elements_by_material(cls, material: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
return ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material) return ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)
@classmethod @classmethod
def get_name(cls, obj): def get_name(cls, obj: bpy.types.Material) -> str:
return obj.name return obj.name
@classmethod @classmethod
def import_material_definitions(cls, material_type): def import_material_definitions(cls, material_type: str) -> None:
props = bpy.context.scene.BIMMaterialProperties props = bpy.context.scene.BIMMaterialProperties
expanded_categories = {m.name for m in props.materials if m.is_expanded} expanded_categories = {m.name for m in props.materials if m.is_expanded}
props.materials.clear() props.materials.clear()
@@ -89,11 +91,11 @@ class Material(blenderbim.core.tool.Material):
new.total_elements = len(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)) new.total_elements = len(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material))
@classmethod @classmethod
def is_editing_materials(cls): def is_editing_materials(cls) -> bool:
return bpy.context.scene.BIMMaterialProperties.is_editing return bpy.context.scene.BIMMaterialProperties.is_editing
@classmethod @classmethod
def is_material_used_in_sets(cls, material): def is_material_used_in_sets(cls, material: ifcopenshell.entity_instance) -> bool:
for inverse in tool.Ifc.get().get_inverse(material): for inverse in tool.Ifc.get().get_inverse(material):
if inverse.is_a() in [ if inverse.is_a() in [
"IfcMaterialProfile", "IfcMaterialProfile",
@@ -105,48 +107,50 @@ class Material(blenderbim.core.tool.Material):
return False return False
@classmethod @classmethod
def load_material_attributes(cls, material): def load_material_attributes(cls, material: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMMaterialProperties props = bpy.context.scene.BIMMaterialProperties
props.material_attributes.clear() props.material_attributes.clear()
blenderbim.bim.helper.import_attributes2(material, props.material_attributes) blenderbim.bim.helper.import_attributes2(material, props.material_attributes)
@classmethod @classmethod
def enable_editing_material(cls, material): def enable_editing_material(cls, material: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMMaterialProperties props = bpy.context.scene.BIMMaterialProperties
props.active_material_id = material.id() props.active_material_id = material.id()
props.editing_material_type = "ATTRIBUTES" props.editing_material_type = "ATTRIBUTES"
@classmethod @classmethod
def get_material_attributes(cls): def get_material_attributes(cls) -> dict[str, Any]:
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMMaterialProperties.material_attributes) return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMMaterialProperties.material_attributes)
@classmethod @classmethod
def disable_editing_material(cls): def disable_editing_material(cls) -> None:
props = bpy.context.scene.BIMMaterialProperties props = bpy.context.scene.BIMMaterialProperties
props.active_material_id = 0 props.active_material_id = 0
props.editing_material_type = "" props.editing_material_type = ""
@classmethod @classmethod
def get_type(cls, element): def get_type(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
return ifcopenshell.util.element.get_type(element) return ifcopenshell.util.element.get_type(element)
@classmethod @classmethod
def get_active_object_material(cls): def get_active_object_material(cls) -> Union[str, None]:
active_obj = bpy.context.active_object active_obj = bpy.context.active_object
if not active_obj: if not active_obj:
return return
return active_obj.BIMObjectMaterialProperties.material_type return active_obj.BIMObjectMaterialProperties.material_type
@classmethod @classmethod
def get_active_material(cls): def get_active_material(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_id(int(bpy.context.active_object.BIMObjectMaterialProperties.material)) return tool.Ifc.get().by_id(int(bpy.context.active_object.BIMObjectMaterialProperties.material))
@classmethod @classmethod
def get_material(cls, element, should_inherit=False): def get_material(
cls, element: ifcopenshell.entity_instance, should_inherit: bool = False
) -> Union[ifcopenshell.entity_instance, None]:
return ifcopenshell.util.element.get_material(element, should_inherit=should_inherit) return ifcopenshell.util.element.get_material(element, should_inherit=should_inherit)
@classmethod @classmethod
def is_a_material_set(cls, material): def is_a_material_set(cls, material: ifcopenshell.entity_instance) -> bool:
return material.is_a() in [ return material.is_a() in [
"IfcMaterialConstituentSet", "IfcMaterialConstituentSet",
"IfcMaterialLayerSet", "IfcMaterialLayerSet",
@@ -154,7 +158,9 @@ class Material(blenderbim.core.tool.Material):
] ]
@classmethod @classmethod
def add_material_to_set(cls, material_set, material): def add_material_to_set(
cls, material_set: ifcopenshell.entity_instance, material: ifcopenshell.entity_instance
) -> None:
if material_set.is_a("IfcMaterialConstituentSet"): if material_set.is_a("IfcMaterialConstituentSet"):
if not material_set.MaterialConstituents: if not material_set.MaterialConstituents:
tool.Ifc.run( tool.Ifc.run(
@@ -195,7 +201,7 @@ class Material(blenderbim.core.tool.Material):
) )
@classmethod @classmethod
def has_material_profile(cls, element): def has_material_profile(cls, element: ifcopenshell.entity_instance) -> bool:
material = cls.get_material(element, should_inherit=False) material = cls.get_material(element, should_inherit=False)
inherited_material = cls.get_material(element, should_inherit=True) inherited_material = cls.get_material(element, should_inherit=True)
if material and "Profile" in material.is_a(): if material and "Profile" in material.is_a():
@@ -205,11 +211,13 @@ class Material(blenderbim.core.tool.Material):
return False return False
@classmethod @classmethod
def is_a_flow_segment(cls, element): def is_a_flow_segment(cls, element: ifcopenshell.entity_instance) -> bool:
return element.is_a("IfcFlowSegment") return element.is_a("IfcFlowSegment")
@classmethod @classmethod
def replace_material_with_material_profile(cls, element): def replace_material_with_material_profile(
cls, element: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
old_material = cls.get_material(element, should_inherit=False) old_material = cls.get_material(element, should_inherit=False)
old_inherited_material = cls.get_material(element, should_inherit=True) old_inherited_material = cls.get_material(element, should_inherit=True)
material = old_material if old_material and old_material.is_a("IfcMaterial") else None material = old_material if old_material and old_material.is_a("IfcMaterial") else None
@@ -225,14 +233,14 @@ class Material(blenderbim.core.tool.Material):
return material_profile return material_profile
@classmethod @classmethod
def update_elements_using_material(cls, material): def update_elements_using_material(cls, material: ifcopenshell.entity_instance) -> None:
# update elements that are using this material # update elements that are using this material
elements = ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material) elements = ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)
objects = [tool.Ifc.get_object(e) for e in elements] objects = [tool.Ifc.get_object(e) for e in elements]
tool.Geometry.reload_representation(objects) tool.Geometry.reload_representation(objects)
@classmethod @classmethod
def sync_blender_material_name(cls, material): def sync_blender_material_name(cls, material: ifcopenshell.entity_instance) -> None:
name = material.Name or "Unnamed" name = material.Name or "Unnamed"
obj = tool.Ifc.get_object(material) obj = tool.Ifc.get_object(material)
if obj: if obj:
@@ -245,7 +253,7 @@ class Material(blenderbim.core.tool.Material):
obj.name = name obj.name = name
@classmethod @classmethod
def get_style(cls, material): def get_style(cls, material: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
for material_representation in material.HasRepresentation: for material_representation in material.HasRepresentation:
for representation in material_representation.Representations: for representation in material_representation.Representations:
for item in representation.Items: for item in representation.Items:
+10 -5
View File
@@ -17,18 +17,23 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.placement import ifcopenshell.util.placement
import ifcopenshell.util.representation import ifcopenshell.util.representation
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
import PIL.ImageDraw
from blenderbim.bim.module.model.decorator import ProfileDecorator from blenderbim.bim.module.model.decorator import ProfileDecorator
from typing import Union
class Profile(blenderbim.core.tool.Profile): class Profile(blenderbim.core.tool.Profile):
@classmethod @classmethod
def draw_image_for_ifc_profile(cls, draw, profile, size): def draw_image_for_ifc_profile(
cls, draw: PIL.ImageDraw.ImageDraw, profile: ifcopenshell.entity_instance, size: float
) -> None:
"""generates image based on `profile` using `PIL.ImageDraw`""" """generates image based on `profile` using `PIL.ImageDraw`"""
settings = ifcopenshell.geom.settings() settings = ifcopenshell.geom.settings()
settings.set(settings.INCLUDE_CURVES, True) settings.set(settings.INCLUDE_CURVES, True)
@@ -57,11 +62,11 @@ class Profile(blenderbim.core.tool.Profile):
draw.line((tuple(grouped_verts[e[0]]), tuple(grouped_verts[e[1]])), fill="white", width=2) draw.line((tuple(grouped_verts[e[0]]), tuple(grouped_verts[e[1]])), fill="white", width=2)
@classmethod @classmethod
def is_editing_profile(cls): def is_editing_profile(cls) -> bool:
return ProfileDecorator.installed return bool(ProfileDecorator.installed)
@classmethod @classmethod
def get_profile(cls, element): def get_profile(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
representations = element.Representation representations = element.Representation
for representation in representations.Representations: for representation in representations.Representations:
if not representation.is_a("IfcShapeRepresentation"): if not representation.is_a("IfcShapeRepresentation"):
@@ -74,7 +79,7 @@ class Profile(blenderbim.core.tool.Profile):
return None return None
@classmethod @classmethod
def get_model_profiles(cls): def get_model_profiles(cls) -> list[ifcopenshell.entity_instance]:
return tool.Ifc.get().by_type("IfcProfileDef") return tool.Ifc.get().by_type("IfcProfileDef")
@classmethod @classmethod
+33 -18
View File
@@ -21,6 +21,7 @@ import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.representation import ifcopenshell.util.representation
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.placement
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.core.aggregate import blenderbim.core.aggregate
import blenderbim.core.geometry import blenderbim.core.geometry
@@ -29,17 +30,17 @@ import blenderbim.core.style
import blenderbim.tool as tool import blenderbim.tool as tool
from mathutils import Vector from mathutils import Vector
from blenderbim.bim.module.model.opening import FilledOpeningGenerator from blenderbim.bim.module.model.opening import FilledOpeningGenerator
from typing import Union, Optional from typing import Union, Optional, Any
class Root(blenderbim.core.tool.Root): class Root(blenderbim.core.tool.Root):
@classmethod @classmethod
def add_tracked_opening(cls, obj): def add_tracked_opening(cls, obj: bpy.types.Object) -> None:
new = bpy.context.scene.BIMModelProperties.openings.add() new = bpy.context.scene.BIMModelProperties.openings.add()
new.obj = obj new.obj = obj
@classmethod @classmethod
def assign_body_styles(cls, element, obj): def assign_body_styles(cls, element: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None:
# Should this even be here? Should it be in the geometry tool? # Should this even be here? Should it be in the geometry tool?
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW") body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if body: if body:
@@ -56,7 +57,7 @@ class Root(blenderbim.core.tool.Root):
) )
@classmethod @classmethod
def copy_representation(cls, source, dest): def copy_representation(cls, source: ifcopenshell.entity_instance, dest: ifcopenshell.entity_instance) -> None:
def exclude_callback(attribute): def exclude_callback(attribute):
return attribute.is_a("IfcProfileDef") and attribute.ProfileName return attribute.is_a("IfcProfileDef") and attribute.ProfileName
@@ -80,11 +81,13 @@ class Root(blenderbim.core.tool.Root):
] ]
@classmethod @classmethod
def does_type_have_representations(cls, element): def does_type_have_representations(cls, element: ifcopenshell.entity_instance) -> bool:
return bool(element.RepresentationMaps) return bool(element.RepresentationMaps)
@classmethod @classmethod
def get_decomposition_relationships(cls, objs): def get_decomposition_relationships(
cls, objs: list[bpy.types.Object]
) -> dict[ifcopenshell.entity_instance, dict[str, Any]]:
relationships = {} relationships = {}
for obj in objs: for obj in objs:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
@@ -96,7 +99,9 @@ class Root(blenderbim.core.tool.Root):
return relationships return relationships
@classmethod @classmethod
def get_connection_relationships(cls, objs): def get_connection_relationships(
cls, objs: list[bpy.types.Object]
) -> dict[ifcopenshell.entity_instance, dict[str, Any]]:
relationships = {} relationships = {}
for obj in objs: for obj in objs:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
@@ -119,7 +124,9 @@ class Root(blenderbim.core.tool.Root):
return relationships return relationships
@classmethod @classmethod
def get_element_representation(cls, element, context): def get_element_representation(
cls, element: ifcopenshell.entity_instance, context: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]:
if context.is_a("IfcGeometricRepresentationSubContext"): if context.is_a("IfcGeometricRepresentationSubContext"):
return ifcopenshell.util.representation.get_representation( return ifcopenshell.util.representation.get_representation(
element, element,
@@ -134,13 +141,13 @@ class Root(blenderbim.core.tool.Root):
return ifcopenshell.util.element.get_type(element) return ifcopenshell.util.element.get_type(element)
@classmethod @classmethod
def get_object_name(cls, obj): def get_object_name(cls, obj: bpy.types.Object) -> None:
if "." in obj.name and obj.name.split(".")[-1].isnumeric(): if "." in obj.name and obj.name.split(".")[-1].isnumeric():
return ".".join(obj.name.split(".")[:-1]) return ".".join(obj.name.split(".")[:-1])
return obj.name return obj.name
@classmethod @classmethod
def get_object_representation(cls, obj): def get_object_representation(cls, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]:
if obj.data and obj.data.BIMMeshProperties.ifc_definition_id: if obj.data and obj.data.BIMMeshProperties.ifc_definition_id:
return tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id) return tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
@@ -152,19 +159,21 @@ class Root(blenderbim.core.tool.Root):
return element.Representation.Representations[0] return element.Representation.Representations[0]
@classmethod @classmethod
def get_representation_context(cls, representation): def get_representation_context(cls, representation: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
return representation.ContextOfItems return representation.ContextOfItems
@classmethod @classmethod
def is_element_a(cls, element, ifc_class): def is_element_a(cls, element: ifcopenshell.entity_instance, ifc_class: str) -> bool:
return element.is_a(ifc_class) return element.is_a(ifc_class)
@classmethod @classmethod
def link_object_data(cls, source_obj, destination_obj): def link_object_data(cls, source_obj: bpy.types.Object, destination_obj: bpy.types.Object) -> None:
destination_obj.data = source_obj.data destination_obj.data = source_obj.data
@classmethod @classmethod
def recreate_decompositions(cls, relationships, old_to_new): def recreate_decompositions(
cls, relationships, old_to_new: dict[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]]
) -> None:
for subelement, data in relationships.items(): for subelement, data in relationships.items():
new_subelements = old_to_new.get(subelement) new_subelements = old_to_new.get(subelement)
new_elements = old_to_new.get(data["element"]) new_elements = old_to_new.get(data["element"])
@@ -227,7 +236,11 @@ class Root(blenderbim.core.tool.Root):
) )
@classmethod @classmethod
def recreate_connections(cls, relationship, old_to_new): def recreate_connections(
cls,
relationship: dict[ifcopenshell.entity_instance, dict[str, Any]],
old_to_new: dict[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]],
) -> None:
for element, data in relationship.items(): for element, data in relationship.items():
try: try:
new_relating_element = old_to_new.get(data["relating_element"])[0] new_relating_element = old_to_new.get(data["relating_element"])[0]
@@ -244,7 +257,9 @@ class Root(blenderbim.core.tool.Root):
) )
@classmethod @classmethod
def recreate_aggregate(cls, old_to_new): def recreate_aggregate(
cls, old_to_new: dict[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]]
) -> None:
for old, new in old_to_new.items(): for old, new in old_to_new.items():
old_aggregate = ifcopenshell.util.element.get_aggregate(old) old_aggregate = ifcopenshell.util.element.get_aggregate(old)
if old_aggregate: if old_aggregate:
@@ -301,7 +316,7 @@ class Root(blenderbim.core.tool.Root):
) )
@classmethod @classmethod
def set_object_name(cls, obj, element): def set_object_name(cls, obj: bpy.types.Object, element: ifcopenshell.entity_instance) -> None:
# This disables the Blender name event handler # This disables the Blender name event handler
obj.BIMObjectProperties.is_renaming = True obj.BIMObjectProperties.is_renaming = True
name = getattr(element, "Name", getattr(element, "AxisTag", None)) name = getattr(element, "Name", getattr(element, "AxisTag", None))
@@ -309,7 +324,7 @@ class Root(blenderbim.core.tool.Root):
obj.BIMObjectProperties.is_renaming = False obj.BIMObjectProperties.is_renaming = False
@classmethod @classmethod
def unlink_object(cls, obj): def unlink_object(cls, obj: bpy.types.Object) -> None:
tool.Ifc.unlink(obj=obj) tool.Ifc.unlink(obj=obj)
if hasattr(obj.data, "BIMMeshProperties"): if hasattr(obj.data, "BIMMeshProperties"):
obj.data.BIMMeshProperties.ifc_definition_id = 0 obj.data.BIMMeshProperties.ifc_definition_id = 0
+44 -38
View File
@@ -20,11 +20,12 @@ import bpy
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.representation
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.helper import blenderbim.bim.helper
from mathutils import Color from mathutils import Color
from typing import Union from typing import Union, Any, Optional
# fmt: off # fmt: off
TEXTURE_MAPS_BY_METHODS = { TEXTURE_MAPS_BY_METHODS = {
@@ -45,19 +46,19 @@ STYLE_PROPS_MAP = {
class Style(blenderbim.core.tool.Style): class Style(blenderbim.core.tool.Style):
@classmethod @classmethod
def can_support_rendering_style(cls, obj): def can_support_rendering_style(cls, obj: bpy.types.Material) -> bool:
return obj.use_nodes and hasattr(obj.node_tree, "nodes") return obj.use_nodes and hasattr(obj.node_tree, "nodes")
@classmethod @classmethod
def disable_editing(cls, obj): def disable_editing(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing = False obj.BIMStyleProperties.is_editing = False
@classmethod @classmethod
def disable_editing_external_style(cls, obj): def disable_editing_external_style(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing_external_style = False obj.BIMStyleProperties.is_editing_external_style = False
@classmethod @classmethod
def disable_editing_styles(cls): def disable_editing_styles(cls) -> None:
bpy.context.scene.BIMStylesProperties.is_editing = False bpy.context.scene.BIMStylesProperties.is_editing = False
@classmethod @classmethod
@@ -67,39 +68,40 @@ class Style(blenderbim.core.tool.Style):
return new_style return new_style
@classmethod @classmethod
def enable_editing(cls, obj): def enable_editing(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing = True obj.BIMStyleProperties.is_editing = True
@classmethod @classmethod
def enable_editing_external_style(cls, obj): def enable_editing_external_style(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing_external_style = True obj.BIMStyleProperties.is_editing_external_style = True
@classmethod @classmethod
def enable_editing_styles(cls): def enable_editing_styles(cls) -> None:
bpy.context.scene.BIMStylesProperties.is_editing = True bpy.context.scene.BIMStylesProperties.is_editing = True
@classmethod @classmethod
def export_surface_attributes(cls, obj): def export_surface_attributes(cls, obj: bpy.types.Material) -> dict[str, Any]:
return blenderbim.bim.helper.export_attributes(obj.BIMStyleProperties.attributes) return blenderbim.bim.helper.export_attributes(obj.BIMStyleProperties.attributes)
@classmethod @classmethod
def export_external_style_attributes(cls, obj): def export_external_style_attributes(cls, obj: bpy.types.Material) -> dict[str, Any]:
return blenderbim.bim.helper.export_attributes(obj.BIMStyleProperties.external_style_attributes) return blenderbim.bim.helper.export_attributes(obj.BIMStyleProperties.external_style_attributes)
@classmethod @classmethod
def get_active_style_type(cls): def get_active_style_type(cls) -> str:
return bpy.context.scene.BIMStylesProperties.style_type return bpy.context.scene.BIMStylesProperties.style_type
# TODO: `obj` argument is unused?
@classmethod @classmethod
def get_context(cls, obj): def get_context(cls, obj) -> Union[ifcopenshell.entity_instance, None]:
return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
@classmethod @classmethod
def get_elements_by_style(cls, style): def get_elements_by_style(cls, style: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
return ifcopenshell.util.element.get_elements_by_style(tool.Ifc.get(), style) return ifcopenshell.util.element.get_elements_by_style(tool.Ifc.get(), style)
@classmethod @classmethod
def get_name(cls, obj): def get_name(cls, obj: bpy.types.Material) -> str:
return obj.name return obj.name
@classmethod @classmethod
@@ -126,7 +128,7 @@ class Style(blenderbim.core.tool.Style):
return style_elements return style_elements
@classmethod @classmethod
def get_shading_style_data_from_props(cls) -> dict: def get_shading_style_data_from_props(cls) -> dict[str, Any]:
"""returns style data from blender props in similar way to `Loader.surface_style_to_dict` """returns style data from blender props in similar way to `Loader.surface_style_to_dict`
to be compatible with `Loader.create_surface_style_rendering`""" to be compatible with `Loader.create_surface_style_rendering`"""
surface_style_data = dict() surface_style_data = dict()
@@ -154,7 +156,7 @@ class Style(blenderbim.core.tool.Style):
return surface_style_data return surface_style_data
@classmethod @classmethod
def get_texture_style_data_from_props(cls) -> list[dict]: def get_texture_style_data_from_props(cls) -> list[dict[str, Any]]:
"""returns style data from blender props in similar way to `Loader.surface_texture_to_dict` """returns style data from blender props in similar way to `Loader.surface_texture_to_dict`
to be compatible with `Loader.create_surface_style_with_textures`""" to be compatible with `Loader.create_surface_style_with_textures`"""
props = bpy.context.scene.BIMStylesProperties props = bpy.context.scene.BIMStylesProperties
@@ -174,7 +176,7 @@ class Style(blenderbim.core.tool.Style):
return textures return textures
@classmethod @classmethod
def set_surface_style_props(cls): def set_surface_style_props(cls) -> None:
"""set blender style props based on currently edited IfcSurfaceStyle, """set blender style props based on currently edited IfcSurfaceStyle,
reset unrelated props to default values""" reset unrelated props to default values"""
@@ -241,7 +243,7 @@ class Style(blenderbim.core.tool.Style):
props["update_graph"] = prev_update_graph_value props["update_graph"] = prev_update_graph_value
@classmethod @classmethod
def get_surface_rendering_attributes(cls, obj, verbose=False): def get_surface_rendering_attributes(cls, obj: bpy.types.Material, verbose: bool = False) -> dict[str, Any]:
report = (lambda *x: print(*x)) if verbose else (lambda *x: None) report = (lambda *x: print(*x)) if verbose else (lambda *x: None)
def color_to_ifc_format(color): def color_to_ifc_format(color):
@@ -403,22 +405,22 @@ class Style(blenderbim.core.tool.Style):
return attributes return attributes
@classmethod @classmethod
def get_surface_rendering_style(cls, obj): def get_surface_rendering_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
style_elements = cls.get_style_elements(obj) style_elements = cls.get_style_elements(obj)
return style_elements.get("IfcSurfaceStyleRendering", None) return style_elements.get("IfcSurfaceStyleRendering", None)
@classmethod @classmethod
def get_texture_style(cls, obj): def get_texture_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
style_elements = cls.get_style_elements(obj) style_elements = cls.get_style_elements(obj)
return style_elements.get("IfcSurfaceStyleWithTextures", None) return style_elements.get("IfcSurfaceStyleWithTextures", None)
@classmethod @classmethod
def get_external_style(cls, obj): def get_external_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
style_elements = cls.get_style_elements(obj) style_elements = cls.get_style_elements(obj)
return style_elements.get("IfcExternallyDefinedSurfaceStyle", None) return style_elements.get("IfcExternallyDefinedSurfaceStyle", None)
@classmethod @classmethod
def get_surface_shading_attributes(cls, obj): def get_surface_shading_attributes(cls, obj: bpy.types.Material) -> dict[str, Any]:
data = { data = {
"SurfaceColour": { "SurfaceColour": {
"Name": None, "Name": None,
@@ -433,7 +435,7 @@ class Style(blenderbim.core.tool.Style):
return data return data
@classmethod @classmethod
def get_surface_shading_style(cls, obj): def get_surface_shading_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
if obj.BIMMaterialProperties.ifc_style_id: if obj.BIMMaterialProperties.ifc_style_id:
style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id) style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id)
items = [s for s in style.Styles if s.is_a() == "IfcSurfaceStyleShading"] items = [s for s in style.Styles if s.is_a() == "IfcSurfaceStyleShading"]
@@ -441,7 +443,7 @@ class Style(blenderbim.core.tool.Style):
return items[0] return items[0]
@classmethod @classmethod
def get_surface_texture_style(cls, obj): def get_surface_texture_style(cls, obj: bpy.types.Material) -> Union[ifcopenshell.entity_instance, None]:
if obj.BIMMaterialProperties.ifc_style_id: if obj.BIMMaterialProperties.ifc_style_id:
style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id) style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id)
items = [s for s in style.Styles if s.is_a("IfcSurfaceStyleWithTextures")] items = [s for s in style.Styles if s.is_a("IfcSurfaceStyleWithTextures")]
@@ -449,7 +451,7 @@ class Style(blenderbim.core.tool.Style):
return items[0] return items[0]
@classmethod @classmethod
def get_uv_maps(cls, representation): def get_uv_maps(cls, representation: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
items = [] items = []
for item in representation.Items: for item in representation.Items:
if item.is_a("IfcMappedItem"): if item.is_a("IfcMappedItem"):
@@ -464,7 +466,7 @@ class Style(blenderbim.core.tool.Style):
return results return results
@classmethod @classmethod
def get_style_ui_props_attributes(cls, style_type): def get_style_ui_props_attributes(cls, style_type: str) -> Union[bpy.types.PropertyGroup, None]:
props = bpy.context.scene.BIMStylesProperties props = bpy.context.scene.BIMStylesProperties
if style_type == "IfcExternallyDefinedSurfaceStyle": if style_type == "IfcExternallyDefinedSurfaceStyle":
return props.external_style_attributes return props.external_style_attributes
@@ -474,7 +476,7 @@ class Style(blenderbim.core.tool.Style):
return props.lighting_style_colours return props.lighting_style_colours
@classmethod @classmethod
def import_presentation_styles(cls, style_type): def import_presentation_styles(cls, style_type: str) -> None:
color_to_tuple = lambda x: (x.Red, x.Green, x.Blue) color_to_tuple = lambda x: (x.Red, x.Green, x.Blue)
props = bpy.context.scene.BIMStylesProperties props = bpy.context.scene.BIMStylesProperties
props.styles.clear() props.styles.clear()
@@ -497,13 +499,13 @@ class Style(blenderbim.core.tool.Style):
new.total_elements = len(ifcopenshell.util.element.get_elements_by_style(tool.Ifc.get(), style)) new.total_elements = len(ifcopenshell.util.element.get_elements_by_style(tool.Ifc.get(), style))
@classmethod @classmethod
def import_surface_attributes(cls, style, obj): def import_surface_attributes(cls, style: ifcopenshell.entity_instance, obj: bpy.types.Material) -> None:
attributes = obj.BIMStyleProperties.attributes attributes = obj.BIMStyleProperties.attributes
attributes.clear() attributes.clear()
blenderbim.bim.helper.import_attributes2(style, attributes) blenderbim.bim.helper.import_attributes2(style, attributes)
@classmethod @classmethod
def import_external_style_attributes(cls, style, obj): def import_external_style_attributes(cls, style: ifcopenshell.entity_instance, obj: bpy.types.Material) -> None:
attributes = obj.BIMStyleProperties.external_style_attributes attributes = obj.BIMStyleProperties.external_style_attributes
attributes.clear() attributes.clear()
blenderbim.bim.helper.import_attributes2(style, attributes) blenderbim.bim.helper.import_attributes2(style, attributes)
@@ -514,26 +516,26 @@ class Style(blenderbim.core.tool.Style):
return bool(external_style and external_style.Location and external_style.Location.endswith(".blend")) return bool(external_style and external_style.Location and external_style.Location.endswith(".blend"))
@classmethod @classmethod
def is_editing_styles(cls): def is_editing_styles(cls) -> bool:
return bpy.context.scene.BIMStylesProperties.is_editing return bpy.context.scene.BIMStylesProperties.is_editing
@classmethod @classmethod
def record_shading(cls, obj): def record_shading(cls, obj: bpy.types.Material) -> None:
obj.BIMMaterialProperties.shading_checksum = repr(np.array(obj.diffuse_color).tobytes()) obj.BIMMaterialProperties.shading_checksum = repr(np.array(obj.diffuse_color).tobytes())
@classmethod @classmethod
def select_elements(cls, elements): def select_elements(cls, elements: list[ifcopenshell.entity_instance]) -> None:
for element in elements: for element in elements:
obj = tool.Ifc.get_object(element) obj = tool.Ifc.get_object(element)
if obj: if obj:
obj.select_set(True) obj.select_set(True)
@classmethod @classmethod
def change_current_style_type(cls, blender_material, style_type): def change_current_style_type(cls, blender_material: bpy.types.Material, style_type: str) -> None:
blender_material.BIMStyleProperties.active_style_type = style_type blender_material.BIMStyleProperties.active_style_type = style_type
@classmethod @classmethod
def get_styled_items(cls, style): def get_styled_items(cls, style: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
inverses = list(ifc_file.get_inverse(style)) inverses = list(ifc_file.get_inverse(style))
@@ -554,13 +556,15 @@ class Style(blenderbim.core.tool.Style):
return items return items
@classmethod @classmethod
def assign_style_to_object(cls, style, obj): def assign_style_to_object(cls, style: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None:
"""assigns `style` to `object` current representation""" """assigns `style` to `object` current representation"""
representation = tool.Geometry.get_active_representation(obj) representation = tool.Geometry.get_active_representation(obj)
tool.Ifc.run("style.assign_representation_styles", shape_representation=representation, styles=[style]) tool.Ifc.run("style.assign_representation_styles", shape_representation=representation, styles=[style])
@classmethod @classmethod
def assign_style_to_representation_item(cls, representation_item, style=None): def assign_style_to_representation_item(
cls, representation_item: ifcopenshell.entity_instance, style: Optional[ifcopenshell.entity_instance] = None
) -> None:
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
if not representation_item.StyledByItem: if not representation_item.StyledByItem:
if style is None: if style is None:
@@ -574,12 +578,14 @@ class Style(blenderbim.core.tool.Style):
styled_item.Styles = (style,) styled_item.Styles = (style,)
@classmethod @classmethod
def get_representation_item_style(cls, representation_item): def get_representation_item_style(
cls, representation_item: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]:
for inverse in tool.Ifc.get().get_inverse(representation_item): for inverse in tool.Ifc.get().get_inverse(representation_item):
if inverse.is_a("IfcStyledItem"): if inverse.is_a("IfcStyledItem"):
for style in inverse.Styles: for style in inverse.Styles:
return style return style
@classmethod @classmethod
def reload_material_from_ifc(cls, blender_material): def reload_material_from_ifc(cls, blender_material: bpy.types.Material) -> None:
blender_material.BIMStyleProperties.active_style_type = blender_material.BIMStyleProperties.active_style_type blender_material.BIMStyleProperties.active_style_type = blender_material.BIMStyleProperties.active_style_type
+19 -13
View File
@@ -26,7 +26,7 @@ import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.cost import ifcopenshell.util.cost
import ifcopenshell.util.date import ifcopenshell.util.date
from typing import Union, Optional from typing import Union, Optional, Any
class IfcDataGetter: class IfcDataGetter:
@@ -41,17 +41,17 @@ class IfcDataGetter:
] ]
@staticmethod @staticmethod
def canonicalise_time(time): def canonicalise_time(time: Union[datetime.datetime, None]) -> str:
if not time: if not time:
return "-" return "-"
return time.strftime("%d/%m/%y") return time.strftime("%d/%m/%y")
@staticmethod @staticmethod
def get_root_costs(cost_schedule): def get_root_costs(cost_schedule: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
return [obj for rel in cost_schedule.Controls or [] for obj in rel.RelatedObjects or []] return [obj for rel in cost_schedule.Controls or [] for obj in rel.RelatedObjects or []]
@staticmethod @staticmethod
def get_cost_item_values(cost_item=None): def get_cost_item_values(cost_item: Union[ifcopenshell.entity_instance, None]) -> Union[list[dict[str, Any]], None]:
if not cost_item: if not cost_item:
return None return None
values = [] values = []
@@ -71,14 +71,14 @@ class IfcDataGetter:
return values return values
@staticmethod @staticmethod
def process_categories(cost_item, categories): def process_categories(cost_item: ifcopenshell.entity_instance, categories: set[str]) -> set[str]:
for cost_value in cost_item.CostValues or []: for cost_value in cost_item.CostValues or []:
if cost_value.Category: if cost_value.Category:
categories.add("{}{}".format(cost_value.Category, " Cost")) categories.add("{}{}".format(cost_value.Category, " Cost"))
return categories return categories
@staticmethod @staticmethod
def process_cost_item_categories(cost_item, categories): def process_cost_item_categories(cost_item: ifcopenshell.entity_instance, categories: set[str]) -> set[str]:
IfcDataGetter.process_categories(cost_item, categories) IfcDataGetter.process_categories(cost_item, categories)
for rel in cost_item.IsNestedBy or []: for rel in cost_item.IsNestedBy or []:
for child in rel.RelatedObjects or []: for child in rel.RelatedObjects or []:
@@ -86,14 +86,20 @@ class IfcDataGetter:
return categories return categories
@staticmethod @staticmethod
def get_cost_rates_categories(schedule): def get_cost_rates_categories(schedule: ifcopenshell.entity_instance) -> set[str]:
categories = set() categories = set()
for cost_item in IfcDataGetter.get_root_costs(schedule): for cost_item in IfcDataGetter.get_root_costs(schedule):
IfcDataGetter.process_cost_item_categories(cost_item, categories) IfcDataGetter.process_cost_item_categories(cost_item, categories)
return categories return categories
@staticmethod @staticmethod
def process_cost_data(file, cost_item, cost_items_data, index, hierarchy="1"): def process_cost_data(
file: ifcopenshell.file,
cost_item: ifcopenshell.entity_instance,
cost_items_data: list[dict[str, Any]],
index: int,
hierarchy: str = "1",
) -> None:
def listToString(s): def listToString(s):
return ", ".join([str(i) for i in s]) return ", ".join([str(i) for i in s])
@@ -134,7 +140,7 @@ class IfcDataGetter:
) )
@staticmethod @staticmethod
def get_cost_items_data(file, schedule): def get_cost_items_data(file: ifcopenshell.file, schedule: ifcopenshell.entity_instance) -> list[dict[str, Any]]:
cost_items_data = [] cost_items_data = []
index = 0 index = 0
for cost_item in IfcDataGetter.get_root_costs(schedule): for cost_item in IfcDataGetter.get_root_costs(schedule):
@@ -142,7 +148,7 @@ class IfcDataGetter:
return cost_items_data return cost_items_data
@staticmethod @staticmethod
def format_unit(unit): def format_unit(unit: ifcopenshell.entity_instance) -> str:
if unit.is_a("IfcContextDependentUnit"): if unit.is_a("IfcContextDependentUnit"):
return f"{unit.UnitType} / {unit.Name}" return f"{unit.UnitType} / {unit.Name}"
else: else:
@@ -152,7 +158,7 @@ class IfcDataGetter:
return f"{unit.UnitType} / {name}" return f"{unit.UnitType} / {name}"
@staticmethod @staticmethod
def get_cost_value_unit(cost_value=None): def get_cost_value_unit(cost_value: Optional[ifcopenshell.entity_instance] = None) -> Union[str, None]:
if not cost_value: if not cost_value:
return None return None
unit = cost_value.UnitBasis unit = cost_value.UnitBasis
@@ -161,9 +167,9 @@ class IfcDataGetter:
return IfcDataGetter.format_unit(unit.UnitComponent) return IfcDataGetter.format_unit(unit.UnitComponent)
@staticmethod @staticmethod
def get_cost_item_quantity(file, cost_item=None): def get_cost_item_quantity(file: ifcopenshell.file, cost_item: ifcopenshell.entity_instance) -> dict[str, Any]:
# TODO: handle multiple quantities, THOSE WHHICH ARE JUYST ASSIGNED TO THE COST ITEM DIRECTLY, NOT THROUGH OBJECTS. # TODO: handle multiple quantities, THOSE WHHICH ARE JUYST ASSIGNED TO THE COST ITEM DIRECTLY, NOT THROUGH OBJECTS.
def add_quantity(quantity, take_off_name): def add_quantity(quantity: ifcopenshell.entity_instance, take_off_name: str) -> float:
accounted_for.append(quantity) accounted_for.append(quantity)
if take_off_name == "": if take_off_name == "":
take_off_name = quantity[0] take_off_name = quantity[0]
@@ -833,7 +833,7 @@ def get_layers(
def get_container( def get_container(
element: ifcopenshell.entity_instance, should_get_direct: bool = False, ifc_class: Optional[str] = None element: ifcopenshell.entity_instance, should_get_direct: bool = False, ifc_class: Optional[str] = None
) -> ifcopenshell.entity_instance: ) -> Union[ifcopenshell.entity_instance, None]:
""" """
Retrieves the spatial structure container of an element. Retrieves the spatial structure container of an element.
@@ -849,7 +849,7 @@ def get_container(
example, you may be after the storey, not a space. example, you may be after the storey, not a space.
:type ifc_class: str, optional :type ifc_class: str, optional
:return: The direct or indirect container of the element or None. :return: The direct or indirect container of the element or None.
:rtype: ifcopenshell.entity_instance :rtype: Union[ifcopenshell.entity_instance, None]
Example: Example: