This commit is contained in:
Andrej730
2025-07-10 11:30:46 +05:00
parent 8a6eb1b60f
commit 05cb06a28e
6 changed files with 32 additions and 17 deletions
@@ -28,9 +28,12 @@ import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.material as core import bonsai.core.material as core
import bonsai.bim.module.model.profile as model_profile import bonsai.bim.module.model.profile as model_profile
from typing import Any, Union, TYPE_CHECKING from typing import Any, Union, TYPE_CHECKING, Literal
from bonsai.bim.module.model import wall, slab from bonsai.bim.module.model import wall, slab
if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
class LoadMaterials(bpy.types.Operator): class LoadMaterials(bpy.types.Operator):
bl_idname = "bim.load_materials" bl_idname = "bim.load_materials"
@@ -508,7 +511,9 @@ class EnableEditingAssignedMaterial(bpy.types.Operator):
bonsai.bim.helper.import_attributes2(material, props.material_set_attributes) bonsai.bim.helper.import_attributes2(material, props.material_set_attributes)
return {"FINISHED"} return {"FINISHED"}
def import_attributes(self, name, prop, data): def import_attributes(
self, name: str, prop: Union["Attribute", None], data: dict[str, Any]
) -> None | Literal[True]:
if name == "CardinalPoint": if name == "CardinalPoint":
# TODO: complain to buildingSMART # TODO: complain to buildingSMART
cardinal_point_map = { cardinal_point_map = {
@@ -532,6 +537,7 @@ class EnableEditingAssignedMaterial(bpy.types.Operator):
18: "right in line with the shear centre", 18: "right in line with the shear centre",
19: "top in line with the shear centre", 19: "top in line with the shear centre",
} }
assert prop
prop.data_type = "enum" prop.data_type = "enum"
prop.enum_items = json.dumps(cardinal_point_map) prop.enum_items = json.dumps(cardinal_point_map)
if data[name]: if data[name]:
@@ -30,6 +30,7 @@ import bonsai.tool as tool
from math import degrees from math import degrees
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from bonsai.bim.module.structural.decorator import LoadsDecorator from bonsai.bim.module.structural.decorator import LoadsDecorator
from typing import Literal
class ShowLoads(bpy.types.Operator): class ShowLoads(bpy.types.Operator):
@@ -40,6 +41,7 @@ class ShowLoads(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def modal(self, context, event): def modal(self, context, event):
assert context.screen
if event.type == "F5": if event.type == "F5":
LoadsDecorator.update() LoadsDecorator.update()
for area in context.screen.areas: for area in context.screen.areas:
@@ -54,6 +56,7 @@ class ShowLoads(bpy.types.Operator):
return {"PASS_THROUGH"} return {"PASS_THROUGH"}
def invoke(self, context, event): def invoke(self, context, event):
assert context.window and context.window_manager and context.screen
collection = bpy.data.collections.get("IfcStructuralItem") collection = bpy.data.collections.get("IfcStructuralItem")
if collection is None: if collection is None:
self.report({"ERROR"}, "No IfcStructuralItems found.") self.report({"ERROR"}, "No IfcStructuralItems found.")
@@ -87,6 +90,7 @@ class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator):
props = tool.Structural.get_object_structural_props(obj) props = tool.Structural.get_object_structural_props(obj)
file = tool.Ifc.get() file = tool.Ifc.get()
related_structural_connection = file.by_id(oprops.ifc_definition_id) related_structural_connection = file.by_id(oprops.ifc_definition_id)
assert props.relating_structural_member
relating_structural_member = tool.Ifc.get_entity(props.relating_structural_member) relating_structural_member = tool.Ifc.get_entity(props.relating_structural_member)
assert relating_structural_member assert relating_structural_member
if not relating_structural_member.is_a("IfcStructuralMember"): if not relating_structural_member.is_a("IfcStructuralMember"):
@@ -613,7 +617,7 @@ class EnableEditingStructuralLoadCase(bpy.types.Operator):
) )
return {"FINISHED"} return {"FINISHED"}
def import_attributes(self, name, prop, data): def import_attributes(self, name: str, prop: object, data: object) -> None | Literal[False]:
if name in ["SelfWeightCoefficients"]: if name in ["SelfWeightCoefficients"]:
return False return False
+5 -3
View File
@@ -46,7 +46,7 @@ class Context(bonsai.core.tool.Context):
props.context_attributes.clear() props.context_attributes.clear()
context = cls.get_context() context = cls.get_context()
def callback(name: str, prop, data) -> Union[bool, None]: def callback(name: str, prop: Union[Attribute, None], data: dict[str, Any]) -> Union[bool, None]:
if context.is_a("IfcGeometricRepresentationSubContext"): if context.is_a("IfcGeometricRepresentationSubContext"):
if name == "Precision": if name == "Precision":
props.context_attributes.remove(props.context_attributes.find("Precision")) props.context_attributes.remove(props.context_attributes.find("Precision"))
@@ -57,8 +57,9 @@ class Context(bonsai.core.tool.Context):
elif name == "TargetScale": elif name == "TargetScale":
props.context_attributes.remove(props.context_attributes.find("TargetScale")) props.context_attributes.remove(props.context_attributes.find("TargetScale"))
scale_denominator = None scale_denominator = None
if data.get(name) is not None and data.get(name) != 0: value = data.get(name)
scale_denominator = 1.0 / data.get(name) if value not in (None, 0):
scale_denominator = 1.0 / value
new_prop = props.context_attributes.add() new_prop = props.context_attributes.add()
new_prop.name = "ScaleDenominator" new_prop.name = "ScaleDenominator"
new_prop.data_type = "float" new_prop.data_type = "float"
@@ -68,6 +69,7 @@ class Context(bonsai.core.tool.Context):
else: # IfcGeometricRepresentationContext else: # IfcGeometricRepresentationContext
# Import precision as a string because Blender has problem displaying 1e-7 and smaller numbers in UI. # Import precision as a string because Blender has problem displaying 1e-7 and smaller numbers in UI.
if name == "Precision": if name == "Precision":
assert prop
prop.data_type = "string" prop.data_type = "string"
bonsai.bim.helper.import_attributes(context.is_a(), props.context_attributes, context.get_info(), callback) bonsai.bim.helper.import_attributes(context.is_a(), props.context_attributes, context.get_info(), callback)
+11 -8
View File
@@ -22,6 +22,7 @@ import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.api.cost import ifcopenshell.api.cost
import ifcopenshell.api.document
import ifcopenshell.api.nest import ifcopenshell.api.nest
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.date import ifcopenshell.util.date
@@ -34,6 +35,7 @@ from typing import Optional, Any, Union, Literal, TYPE_CHECKING, assert_never
from collections.abc import Generator from collections.abc import Generator
if TYPE_CHECKING: if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
from bonsai.bim.module.cost.prop import BIMCostProperties, CostItemQuantity from bonsai.bim.module.cost.prop import BIMCostProperties, CostItemQuantity
@@ -415,7 +417,13 @@ class Cost(bonsai.core.tool.Cost):
@classmethod @classmethod
def load_cost_item_value_attributes(cls, cost_value: ifcopenshell.entity_instance) -> None: def load_cost_item_value_attributes(cls, cost_value: ifcopenshell.entity_instance) -> None:
def import_attributes(name, prop, data, cost_value, is_rates, props_collection): props = cls.get_cost_props()
props.cost_value_attributes.clear()
props_collection = props.cost_value_attributes
# is_rates = cls.is_active_schedule_of_rates()
is_rates = True # so it is possible to assign a cost item rate that it not only from a Schedule of Rate
def import_attributes_callback(name: str, prop: Union[Attribute, None], data) -> None | Literal[True]:
if name == "AppliedValue": if name == "AppliedValue":
# TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure) # TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure)
prop = props_collection.add() prop = props_collection.add()
@@ -452,14 +460,9 @@ class Cost(bonsai.core.tool.Cost):
break break
return True return True
props = cls.get_cost_props() bonsai.bim.helper.import_attributes2(
props.cost_value_attributes.clear() cost_value, props.cost_value_attributes, callback=import_attributes_callback
# is_rates = cls.is_active_schedule_of_rates()
is_rates = True # so it is possible to assign a cost item rate that it not only from a Schedule of Rate
callback = lambda name, prop, data: import_attributes(
name, prop, data, cost_value, is_rates, props.cost_value_attributes
) )
bonsai.bim.helper.import_attributes2(cost_value, props.cost_value_attributes, callback=callback)
@classmethod @classmethod
def calculate_applied_value( def calculate_applied_value(
+1 -1
View File
@@ -91,7 +91,7 @@ class Owner(bonsai.core.tool.Owner):
address = cls.get_address() address = cls.get_address()
def callback(name: str, prop, data: dict[str, Any]) -> None: def callback(name: str, prop: object, data: dict[str, Any]) -> None:
if name in cls.ADDREESS_ATTRIBUTE_TYPES: if name in cls.ADDREESS_ATTRIBUTE_TYPES:
collection = cls.get_address_collection(name) collection = cls.get_address_collection(name)
for line in data[name] or []: for line in data[name] or []:
@@ -20,11 +20,11 @@ import ifcopenshell
import ifcopenshell.api.spatial import ifcopenshell.api.spatial
import ifcopenshell.util.representation import ifcopenshell.util.representation
from ifcopenshell import entity_instance from ifcopenshell import entity_instance
import typing from typing import Union
def add_survey_point( def add_survey_point(
file: ifcopenshell.file, survey_point: entity_instance, site: entity_instance = None file: ifcopenshell.file, survey_point: entity_instance, site: Union[entity_instance, None] = None
) -> entity_instance: ) -> entity_instance:
""" """
Adds a single survey point to the model based on IFC Concept Template 4.1.7.1.2.5. Adds a single survey point to the model based on IFC Concept Template 4.1.7.1.2.5.