This commit is contained in:
Andrej730
2025-03-06 16:11:58 +05:00
parent 7458040949
commit 79940641b2
6 changed files with 38 additions and 25 deletions
@@ -561,9 +561,12 @@ class EditAssignedMaterial(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
self.file = tool.Ifc.get() self.file = tool.Ifc.get()
active_obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object active_obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
assert active_obj
props = active_obj.BIMObjectMaterialProperties props = active_obj.BIMObjectMaterialProperties
element = tool.Ifc.get_entity(active_obj) element = tool.Ifc.get_entity(active_obj)
assert element
material = ifcopenshell.util.element.get_material(element) material = ifcopenshell.util.element.get_material(element)
assert material
objects = tool.Blender.get_selected_objects() objects = tool.Blender.get_selected_objects()
+17 -9
View File
@@ -50,7 +50,7 @@ from bonsai.bim.module.geometry.helper import Helper
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData
from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.opening import FilledOpeningGenerator
from ifcopenshell.util.shape_builder import ShapeBuilder from ifcopenshell.util.shape_builder import ShapeBuilder
from typing import Optional, Union, TypeVar, Any, Iterable, Literal, TYPE_CHECKING, Sequence from typing import Optional, Union, TypeVar, Any, Iterable, Literal, TYPE_CHECKING, Sequence, TypedDict
T = TypeVar("T") T = TypeVar("T")
V_ = tool.Blender.V_ V_ = tool.Blender.V_
@@ -603,8 +603,16 @@ class Model(bonsai.core.tool.Model):
if not openings[i].obj: if not openings[i].obj:
openings.remove(i) openings.remove(i)
class MaterialLayerParameters(TypedDict):
"""Float values are in project units."""
layer_set_direction: Literal["AXIS1", "AXIS2", "AXIS3"]
thickness: float
offset: float
direction_sense: Literal["NEGATIVE", "POSITIVE"]
@classmethod @classmethod
def get_material_layer_parameters(cls, element: ifcopenshell.entity_instance) -> dict[str, Any]: def get_material_layer_parameters(cls, element: ifcopenshell.entity_instance) -> MaterialLayerParameters:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
layer_set_direction = "AXIS2" layer_set_direction = "AXIS2"
offset = 0.0 offset = 0.0
@@ -619,12 +627,12 @@ class Model(bonsai.core.tool.Model):
material = material.ForLayerSet material = material.ForLayerSet
if material.is_a("IfcMaterialLayerSet"): if material.is_a("IfcMaterialLayerSet"):
thickness = sum([l.LayerThickness for l in material.MaterialLayers]) * unit_scale thickness = sum([l.LayerThickness for l in material.MaterialLayers]) * unit_scale
return { return cls.MaterialLayerParameters(
"layer_set_direction": layer_set_direction, layer_set_direction=layer_set_direction,
"thickness": thickness, thickness=thickness,
"offset": offset, offset=offset,
"direction_sense": direction_sense, direction_sense=direction_sense,
} )
@classmethod @classmethod
def get_booleans( def get_booleans(
@@ -2045,7 +2053,7 @@ class Model(bonsai.core.tool.Model):
FilledOpeningGenerator().generate(filling_obj, voided_obj) FilledOpeningGenerator().generate(filling_obj, voided_obj)
@classmethod @classmethod
def add_extrusion_position(cls, extrusion: ifcopenshell.entity_instance, position: tuple) -> None: def add_extrusion_position(cls, extrusion: ifcopenshell.entity_instance, position: Vector) -> None:
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
new_position = ifc_file.createIfcAxis2Placement3D( new_position = ifc_file.createIfcAxis2Placement3D(
@@ -18,6 +18,7 @@
import ifcopenshell import ifcopenshell
import ifcopenshell.api.pset import ifcopenshell.api.pset
import ifcopenshell.util.element
from typing import Optional, Any from typing import Optional, Any
@@ -54,9 +54,7 @@ def copy_class(file: ifcopenshell.file, product: ifcopenshell.entity_instance) -
connections are still valid. connections are still valid.
:param product: The IfcProduct to copy. :param product: The IfcProduct to copy.
:type param: ifcopenshell.entity_instance
:return: The copied product :return: The copied product
:rtype: ifcopenshell.entity_instance
Example: Example:
@@ -70,26 +68,26 @@ def copy_class(file: ifcopenshell.file, product: ifcopenshell.entity_instance) -
""" """
usecase = Usecase() usecase = Usecase()
usecase.file = file usecase.file = file
usecase.settings = {"product": product} return usecase.execute(product)
return usecase.execute()
class Usecase: class Usecase:
file: ifcopenshell.file file: ifcopenshell.file
settings: dict[str, Any]
def execute(self): def execute(self, product: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
result = ifcopenshell.util.element.copy(self.file, self.settings["product"]) result = ifcopenshell.util.element.copy(self.file, product)
self.copy_direct_attributes(result) self.copy_direct_attributes(result)
self.copy_indirect_attributes(self.settings["product"], result) self.copy_indirect_attributes(product, result)
return result return result
def copy_direct_attributes(self, to_element): def copy_direct_attributes(self, to_element: ifcopenshell.entity_instance) -> None:
self.remove_representations(to_element) self.remove_representations(to_element)
self.copy_object_placements(to_element) self.copy_object_placements(to_element)
self.copy_psets(to_element) self.copy_psets(to_element)
def copy_indirect_attributes(self, from_element, to_element): def copy_indirect_attributes(
self, from_element: ifcopenshell.entity_instance, to_element: ifcopenshell.entity_instance
) -> None:
for inverse in self.file.get_inverse(from_element): for inverse in self.file.get_inverse(from_element):
if inverse.is_a("IfcRelDefinesByProperties"): if inverse.is_a("IfcRelDefinesByProperties"):
# Properties must not be shared between objects for convenience of authoring # Properties must not be shared between objects for convenience of authoring
@@ -175,13 +173,13 @@ class Usecase:
new_value.append(to_element) new_value.append(to_element)
inverse[i] = new_value inverse[i] = new_value
def remove_representations(self, element): def remove_representations(self, element: ifcopenshell.entity_instance) -> None:
if element.is_a("IfcProduct"): if element.is_a("IfcProduct"):
element.Representation = None element.Representation = None
elif element.is_a("IfcTypeProduct"): elif element.is_a("IfcTypeProduct"):
element.RepresentationMaps = None element.RepresentationMaps = None
def copy_object_placements(self, element): def copy_object_placements(self, element: ifcopenshell.entity_instance) -> None:
if not element.is_a("IfcProduct") or not element.ObjectPlacement: if not element.is_a("IfcProduct") or not element.ObjectPlacement:
return return
element.ObjectPlacement = ifcopenshell.util.element.copy(self.file, element.ObjectPlacement) element.ObjectPlacement = ifcopenshell.util.element.copy(self.file, element.ObjectPlacement)
@@ -189,7 +187,7 @@ class Usecase:
self.file, element.ObjectPlacement.RelativePlacement self.file, element.ObjectPlacement.RelativePlacement
) )
def copy_psets(self, element): def copy_psets(self, element: ifcopenshell.entity_instance) -> None:
if not element.is_a("IfcTypeObject") or not element.HasPropertySets: if not element.is_a("IfcTypeObject") or not element.HasPropertySets:
return return
element.HasPropertySets = [ element.HasPropertySets = [
@@ -20,7 +20,6 @@ from fractions import Fraction
from math import pi from math import pi
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import Iterable
from typing import Literal from typing import Literal
from typing import Optional from typing import Optional
from typing import Union from typing import Union
@@ -821,7 +820,8 @@ def iter_element_and_attributes_per_type(ifc_file: ifcopenshell.file, attr_type_
for element in ifc_file: for element in ifc_file:
entity = schema.declaration_by_name(element.is_a()) entity = schema.declaration_by_name(element.is_a())
attrs = entity.all_attributes() attrs = entity.all_attributes()
for attr, val, is_derived in zip(attrs, list(element), entity.derived()): attrs_derived: tuple[bool, ...] = entity.derived()
for attr, val, is_derived in zip(attrs, list(element), attrs_derived):
if is_derived: if is_derived:
continue continue
@@ -877,7 +877,7 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str = "
new_length = ifcopenshell.api.unit.add_conversion_based_unit(file_patched, name=target_units) new_length = ifcopenshell.api.unit.add_conversion_based_unit(file_patched, name=target_units)
# support tuple of tuples, as in IfcCartesianPointList3D.CoordList # support tuple of tuples, as in IfcCartesianPointList3D.CoordList
def convert_value(value): def convert_value(value: FloatOrSequenceOfFloats) -> FloatOrSequenceOfFloats:
if not isinstance(value, tuple): if not isinstance(value, tuple):
return convert_unit(value, old_length, new_length) return convert_unit(value, old_length, new_length)
return tuple(convert_value(v) for v in value) return tuple(convert_value(v) for v in value)
@@ -18,9 +18,12 @@
import test.bootstrap import test.bootstrap
import numpy as np import numpy as np
import ifcopenshell.api.context
import ifcopenshell.api.unit import ifcopenshell.api.unit
import ifcopenshell.api.root import ifcopenshell.api.root
import ifcopenshell.api.georeference import ifcopenshell.api.georeference
import ifcopenshell.api.pset
import ifcopenshell.util.element
import ifcopenshell.util.geolocation import ifcopenshell.util.geolocation
import ifcopenshell.util.unit as subject import ifcopenshell.util.unit as subject
from ifcopenshell.util.shape_builder import ShapeBuilder from ifcopenshell.util.shape_builder import ShapeBuilder