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"] = "?"
# print("Total Cost", data["DerivedTotalCostQuantity"], cost_item.Name)
# TODO: dead code?
@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"):
return []
cost_quantities = cost_item.CostQuantities
@@ -28,6 +28,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.representation
import ifcopenshell.util.placement
import ifcopenshell.api
import blenderbim.core.geometry
import blenderbim.core.geometry as core
import blenderbim.core.aggregate
import blenderbim.core.style
@@ -22,6 +22,7 @@ import blenderbim.bim.helper
import blenderbim.bim.handler
import blenderbim.tool as tool
import blenderbim.core.style as core
import ifcopenshell.api
import ifcopenshell.util.representation
from blenderbim.bim.module.style.prop import switch_shading
from pathlib import Path
+33 -5
View File
@@ -16,16 +16,30 @@
# 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/>.
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)
def disable_editing_aggregate(aggregator, obj=None):
def disable_editing_aggregate(aggregator: tool.Aggregate, obj: bpy.types.Object) -> None:
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):
return
rel = ifc.run(
@@ -37,7 +51,13 @@ def assign_object(ifc, aggregator, collector, relating_obj=None, related_obj=Non
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)
container = aggregate.get_container(related_element)
if not relating_obj:
@@ -52,7 +72,15 @@ def unassign_object(ifc, aggregate, collector, relating_obj=None, related_obj=No
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)
assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_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
# 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)
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:
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_style = style.get_style(obj)
if ifc_style:
@@ -36,14 +54,16 @@ def add_material(ifc, material, style, obj=None, name=None, category=None, descr
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)
if material.is_editing_materials():
material.import_material_definitions(material.get_active_material_type())
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 False if material used in material sets and cannot be removed"""
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
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)
if material_tool.is_editing_materials():
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.enable_editing_materials()
def disable_editing_materials(material):
def disable_editing_materials(material: tool.Material) -> None:
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))
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.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()
ifc.run("material.edit_material", material=material, attributes=attributes)
material_tool.sync_blender_material_name(material)
@@ -92,11 +114,13 @@ def edit_material(ifc, material_tool, material):
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()
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 = material_tool.get_active_material()
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)
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:
element = ifc.get_entity(obj)
if element:
@@ -125,7 +149,9 @@ def unassign_material(ifc, material_tool, objects):
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)
if not element:
return
+31 -13
View File
@@ -16,8 +16,16 @@
# 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/>.
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))
ifc.link(element, obj)
if style.can_support_rendering_style(obj):
@@ -33,18 +41,26 @@ def add_style(ifc, style, obj=None):
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)
ifc.run(
"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)
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)
ifc.unlink(obj=obj, element=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())
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)
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)
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)
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)
def unlink_style(ifc, style=None):
def unlink_style(ifc: tool.Ifc, style: ifcopenshell.entity_instance) -> None:
obj = ifc.get_object(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.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)
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)
ifc.run("style.edit_presentation_style", style=style.get_style(obj), attributes=attributes)
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.enable_editing_styles()
def disable_editing_styles(style):
def disable_editing_styles(style: tool.Style) -> None:
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))
+7 -4
View File
@@ -20,6 +20,7 @@ import bpy
import blenderbim.core.tool
import blenderbim.tool as tool
import ifcopenshell.util.element
from typing import Union
class Aggregate(blenderbim.core.tool.Aggregate):
@@ -46,19 +47,21 @@ class Aggregate(blenderbim.core.tool.Aggregate):
return False
@classmethod
def disable_editing(cls, obj):
def disable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMObjectAggregateProperties.is_editing = False
@classmethod
def enable_editing(cls, obj):
def enable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMObjectAggregateProperties.is_editing = True
@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)
@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:
if rel.is_a("IfcRelAggregates"):
return rel.RelatingObject
+34 -26
View File
@@ -19,43 +19,45 @@
import bpy
import ifcopenshell
import blenderbim.core.tool
import blenderbim.core.material
import blenderbim.tool as tool
import blenderbim.bim.helper
import ifcopenshell.util.unit
import ifcopenshell.util.element
from typing import Union, Any
class Material(blenderbim.core.tool.Material):
@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")
@classmethod
def delete_object(cls, obj):
def delete_object(cls, obj: bpy.types.Material) -> None:
bpy.data.materials.remove(obj)
@classmethod
def disable_editing_materials(cls):
def disable_editing_materials(cls) -> None:
bpy.context.scene.BIMMaterialProperties.is_editing = False
@classmethod
def enable_editing_materials(cls):
def enable_editing_materials(cls) -> None:
bpy.context.scene.BIMMaterialProperties.is_editing = True
@classmethod
def get_active_material_type(cls):
def get_active_material_type(cls) -> str:
return bpy.context.scene.BIMMaterialProperties.material_type
@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)
@classmethod
def get_name(cls, obj):
def get_name(cls, obj: bpy.types.Material) -> str:
return obj.name
@classmethod
def import_material_definitions(cls, material_type):
def import_material_definitions(cls, material_type: str) -> None:
props = bpy.context.scene.BIMMaterialProperties
expanded_categories = {m.name for m in props.materials if m.is_expanded}
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))
@classmethod
def is_editing_materials(cls):
def is_editing_materials(cls) -> bool:
return bpy.context.scene.BIMMaterialProperties.is_editing
@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):
if inverse.is_a() in [
"IfcMaterialProfile",
@@ -105,48 +107,50 @@ class Material(blenderbim.core.tool.Material):
return False
@classmethod
def load_material_attributes(cls, material):
def load_material_attributes(cls, material: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMMaterialProperties
props.material_attributes.clear()
blenderbim.bim.helper.import_attributes2(material, props.material_attributes)
@classmethod
def enable_editing_material(cls, material):
def enable_editing_material(cls, material: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMMaterialProperties
props.active_material_id = material.id()
props.editing_material_type = "ATTRIBUTES"
@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)
@classmethod
def disable_editing_material(cls):
def disable_editing_material(cls) -> None:
props = bpy.context.scene.BIMMaterialProperties
props.active_material_id = 0
props.editing_material_type = ""
@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)
@classmethod
def get_active_object_material(cls):
def get_active_object_material(cls) -> Union[str, None]:
active_obj = bpy.context.active_object
if not active_obj:
return
return active_obj.BIMObjectMaterialProperties.material_type
@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))
@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)
@classmethod
def is_a_material_set(cls, material):
def is_a_material_set(cls, material: ifcopenshell.entity_instance) -> bool:
return material.is_a() in [
"IfcMaterialConstituentSet",
"IfcMaterialLayerSet",
@@ -154,7 +158,9 @@ class Material(blenderbim.core.tool.Material):
]
@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 not material_set.MaterialConstituents:
tool.Ifc.run(
@@ -195,7 +201,7 @@ class Material(blenderbim.core.tool.Material):
)
@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)
inherited_material = cls.get_material(element, should_inherit=True)
if material and "Profile" in material.is_a():
@@ -205,11 +211,13 @@ class Material(blenderbim.core.tool.Material):
return False
@classmethod
def is_a_flow_segment(cls, element):
def is_a_flow_segment(cls, element: ifcopenshell.entity_instance) -> bool:
return element.is_a("IfcFlowSegment")
@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_inherited_material = cls.get_material(element, should_inherit=True)
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
@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
elements = ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)
objects = [tool.Ifc.get_object(e) for e in elements]
tool.Geometry.reload_representation(objects)
@classmethod
def sync_blender_material_name(cls, material):
def sync_blender_material_name(cls, material: ifcopenshell.entity_instance) -> None:
name = material.Name or "Unnamed"
obj = tool.Ifc.get_object(material)
if obj:
@@ -245,7 +253,7 @@ class Material(blenderbim.core.tool.Material):
obj.name = name
@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 representation in material_representation.Representations:
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/>.
import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.util.element
import ifcopenshell.util.unit
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import blenderbim.core.tool
import blenderbim.tool as tool
import PIL.ImageDraw
from blenderbim.bim.module.model.decorator import ProfileDecorator
from typing import Union
class Profile(blenderbim.core.tool.Profile):
@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`"""
settings = ifcopenshell.geom.settings()
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)
@classmethod
def is_editing_profile(cls):
return ProfileDecorator.installed
def is_editing_profile(cls) -> bool:
return bool(ProfileDecorator.installed)
@classmethod
def get_profile(cls, element):
def get_profile(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
representations = element.Representation
for representation in representations.Representations:
if not representation.is_a("IfcShapeRepresentation"):
@@ -74,7 +79,7 @@ class Profile(blenderbim.core.tool.Profile):
return None
@classmethod
def get_model_profiles(cls):
def get_model_profiles(cls) -> list[ifcopenshell.entity_instance]:
return tool.Ifc.get().by_type("IfcProfileDef")
@classmethod
+33 -18
View File
@@ -21,6 +21,7 @@ import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.representation
import ifcopenshell.util.element
import ifcopenshell.util.placement
import blenderbim.core.tool
import blenderbim.core.aggregate
import blenderbim.core.geometry
@@ -29,17 +30,17 @@ import blenderbim.core.style
import blenderbim.tool as tool
from mathutils import Vector
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):
@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.obj = obj
@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?
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
if body:
@@ -56,7 +57,7 @@ class Root(blenderbim.core.tool.Root):
)
@classmethod
def copy_representation(cls, source, dest):
def copy_representation(cls, source: ifcopenshell.entity_instance, dest: ifcopenshell.entity_instance) -> None:
def exclude_callback(attribute):
return attribute.is_a("IfcProfileDef") and attribute.ProfileName
@@ -80,11 +81,13 @@ class Root(blenderbim.core.tool.Root):
]
@classmethod
def does_type_have_representations(cls, element):
def does_type_have_representations(cls, element: ifcopenshell.entity_instance) -> bool:
return bool(element.RepresentationMaps)
@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 = {}
for obj in objs:
element = tool.Ifc.get_entity(obj)
@@ -96,7 +99,9 @@ class Root(blenderbim.core.tool.Root):
return relationships
@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 = {}
for obj in objs:
element = tool.Ifc.get_entity(obj)
@@ -119,7 +124,9 @@ class Root(blenderbim.core.tool.Root):
return relationships
@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"):
return ifcopenshell.util.representation.get_representation(
element,
@@ -134,13 +141,13 @@ class Root(blenderbim.core.tool.Root):
return ifcopenshell.util.element.get_type(element)
@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():
return ".".join(obj.name.split(".")[:-1])
return obj.name
@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:
return tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
element = tool.Ifc.get_entity(obj)
@@ -152,19 +159,21 @@ class Root(blenderbim.core.tool.Root):
return element.Representation.Representations[0]
@classmethod
def get_representation_context(cls, representation):
def get_representation_context(cls, representation: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
return representation.ContextOfItems
@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)
@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
@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():
new_subelements = old_to_new.get(subelement)
new_elements = old_to_new.get(data["element"])
@@ -227,7 +236,11 @@ class Root(blenderbim.core.tool.Root):
)
@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():
try:
new_relating_element = old_to_new.get(data["relating_element"])[0]
@@ -244,7 +257,9 @@ class Root(blenderbim.core.tool.Root):
)
@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():
old_aggregate = ifcopenshell.util.element.get_aggregate(old)
if old_aggregate:
@@ -301,7 +316,7 @@ class Root(blenderbim.core.tool.Root):
)
@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
obj.BIMObjectProperties.is_renaming = True
name = getattr(element, "Name", getattr(element, "AxisTag", None))
@@ -309,7 +324,7 @@ class Root(blenderbim.core.tool.Root):
obj.BIMObjectProperties.is_renaming = False
@classmethod
def unlink_object(cls, obj):
def unlink_object(cls, obj: bpy.types.Object) -> None:
tool.Ifc.unlink(obj=obj)
if hasattr(obj.data, "BIMMeshProperties"):
obj.data.BIMMeshProperties.ifc_definition_id = 0
+44 -38
View File
@@ -20,11 +20,12 @@ import bpy
import numpy as np
import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.representation
import blenderbim.core.tool
import blenderbim.tool as tool
import blenderbim.bim.helper
from mathutils import Color
from typing import Union
from typing import Union, Any, Optional
# fmt: off
TEXTURE_MAPS_BY_METHODS = {
@@ -45,19 +46,19 @@ STYLE_PROPS_MAP = {
class Style(blenderbim.core.tool.Style):
@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")
@classmethod
def disable_editing(cls, obj):
def disable_editing(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing = False
@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
@classmethod
def disable_editing_styles(cls):
def disable_editing_styles(cls) -> None:
bpy.context.scene.BIMStylesProperties.is_editing = False
@classmethod
@@ -67,39 +68,40 @@ class Style(blenderbim.core.tool.Style):
return new_style
@classmethod
def enable_editing(cls, obj):
def enable_editing(cls, obj: bpy.types.Material) -> None:
obj.BIMStyleProperties.is_editing = True
@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
@classmethod
def enable_editing_styles(cls):
def enable_editing_styles(cls) -> None:
bpy.context.scene.BIMStylesProperties.is_editing = True
@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)
@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)
@classmethod
def get_active_style_type(cls):
def get_active_style_type(cls) -> str:
return bpy.context.scene.BIMStylesProperties.style_type
# TODO: `obj` argument is unused?
@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")
@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)
@classmethod
def get_name(cls, obj):
def get_name(cls, obj: bpy.types.Material) -> str:
return obj.name
@classmethod
@@ -126,7 +128,7 @@ class Style(blenderbim.core.tool.Style):
return style_elements
@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`
to be compatible with `Loader.create_surface_style_rendering`"""
surface_style_data = dict()
@@ -154,7 +156,7 @@ class Style(blenderbim.core.tool.Style):
return surface_style_data
@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`
to be compatible with `Loader.create_surface_style_with_textures`"""
props = bpy.context.scene.BIMStylesProperties
@@ -174,7 +176,7 @@ class Style(blenderbim.core.tool.Style):
return textures
@classmethod
def set_surface_style_props(cls):
def set_surface_style_props(cls) -> None:
"""set blender style props based on currently edited IfcSurfaceStyle,
reset unrelated props to default values"""
@@ -241,7 +243,7 @@ class Style(blenderbim.core.tool.Style):
props["update_graph"] = prev_update_graph_value
@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)
def color_to_ifc_format(color):
@@ -403,22 +405,22 @@ class Style(blenderbim.core.tool.Style):
return attributes
@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)
return style_elements.get("IfcSurfaceStyleRendering", None)
@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)
return style_elements.get("IfcSurfaceStyleWithTextures", None)
@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)
return style_elements.get("IfcExternallyDefinedSurfaceStyle", None)
@classmethod
def get_surface_shading_attributes(cls, obj):
def get_surface_shading_attributes(cls, obj: bpy.types.Material) -> dict[str, Any]:
data = {
"SurfaceColour": {
"Name": None,
@@ -433,7 +435,7 @@ class Style(blenderbim.core.tool.Style):
return data
@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:
style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id)
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]
@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:
style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id)
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]
@classmethod
def get_uv_maps(cls, representation):
def get_uv_maps(cls, representation: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
items = []
for item in representation.Items:
if item.is_a("IfcMappedItem"):
@@ -464,7 +466,7 @@ class Style(blenderbim.core.tool.Style):
return results
@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
if style_type == "IfcExternallyDefinedSurfaceStyle":
return props.external_style_attributes
@@ -474,7 +476,7 @@ class Style(blenderbim.core.tool.Style):
return props.lighting_style_colours
@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)
props = bpy.context.scene.BIMStylesProperties
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))
@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.clear()
blenderbim.bim.helper.import_attributes2(style, attributes)
@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.clear()
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"))
@classmethod
def is_editing_styles(cls):
def is_editing_styles(cls) -> bool:
return bpy.context.scene.BIMStylesProperties.is_editing
@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())
@classmethod
def select_elements(cls, elements):
def select_elements(cls, elements: list[ifcopenshell.entity_instance]) -> None:
for element in elements:
obj = tool.Ifc.get_object(element)
if obj:
obj.select_set(True)
@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
@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()
inverses = list(ifc_file.get_inverse(style))
@@ -554,13 +556,15 @@ class Style(blenderbim.core.tool.Style):
return items
@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"""
representation = tool.Geometry.get_active_representation(obj)
tool.Ifc.run("style.assign_representation_styles", shape_representation=representation, styles=[style])
@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()
if not representation_item.StyledByItem:
if style is None:
@@ -574,12 +578,14 @@ class Style(blenderbim.core.tool.Style):
styled_item.Styles = (style,)
@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):
if inverse.is_a("IfcStyledItem"):
for style in inverse.Styles:
return style
@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
+19 -13
View File
@@ -26,7 +26,7 @@ import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.cost
import ifcopenshell.util.date
from typing import Union, Optional
from typing import Union, Optional, Any
class IfcDataGetter:
@@ -41,17 +41,17 @@ class IfcDataGetter:
]
@staticmethod
def canonicalise_time(time):
def canonicalise_time(time: Union[datetime.datetime, None]) -> str:
if not time:
return "-"
return time.strftime("%d/%m/%y")
@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 []]
@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:
return None
values = []
@@ -71,14 +71,14 @@ class IfcDataGetter:
return values
@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 []:
if cost_value.Category:
categories.add("{}{}".format(cost_value.Category, " Cost"))
return categories
@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)
for rel in cost_item.IsNestedBy or []:
for child in rel.RelatedObjects or []:
@@ -86,14 +86,20 @@ class IfcDataGetter:
return categories
@staticmethod
def get_cost_rates_categories(schedule):
def get_cost_rates_categories(schedule: ifcopenshell.entity_instance) -> set[str]:
categories = set()
for cost_item in IfcDataGetter.get_root_costs(schedule):
IfcDataGetter.process_cost_item_categories(cost_item, categories)
return categories
@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):
return ", ".join([str(i) for i in s])
@@ -134,7 +140,7 @@ class IfcDataGetter:
)
@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 = []
index = 0
for cost_item in IfcDataGetter.get_root_costs(schedule):
@@ -142,7 +148,7 @@ class IfcDataGetter:
return cost_items_data
@staticmethod
def format_unit(unit):
def format_unit(unit: ifcopenshell.entity_instance) -> str:
if unit.is_a("IfcContextDependentUnit"):
return f"{unit.UnitType} / {unit.Name}"
else:
@@ -152,7 +158,7 @@ class IfcDataGetter:
return f"{unit.UnitType} / {name}"
@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:
return None
unit = cost_value.UnitBasis
@@ -161,9 +167,9 @@ class IfcDataGetter:
return IfcDataGetter.format_unit(unit.UnitComponent)
@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.
def add_quantity(quantity, take_off_name):
def add_quantity(quantity: ifcopenshell.entity_instance, take_off_name: str) -> float:
accounted_for.append(quantity)
if take_off_name == "":
take_off_name = quantity[0]
@@ -833,7 +833,7 @@ def get_layers(
def get_container(
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.
@@ -849,7 +849,7 @@ def get_container(
example, you may be after the storey, not a space.
:type ifc_class: str, optional
:return: The direct or indirect container of the element or None.
:rtype: ifcopenshell.entity_instance
:rtype: Union[ifcopenshell.entity_instance, None]
Example: