Run black on BBIM

This commit is contained in:
Dion Moult
2024-07-26 12:19:21 +10:00
parent e7b791f4a2
commit 1fef4c5857
91 changed files with 747 additions and 582 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
[tool.black] [tool.black]
line-length = 120 line-length = 120
extend-exclude = 'src/ifcopenshell-python/ifcopenshell/express/*' include = 'src/(bcf|bcfserver|blenderbim|bsdd|foundationserver|ifc2ca|ifc4d|ifc5d|ifcbimtester|ifcblender|ifccityjson|ifcclash|ifccsv|ifcdiff|ifcfm|ifcpatch|ifctester|ifcopenshell-python|ifcsverchok|opencdeserver)/.*.py$'
extend-exclude = '(src/ifcopenshell-python/ifcopenshell/express/*|src/ifc2ca/templates/*)'
[tool.pyright] [tool.pyright]
reportInvalidTypeForm = false reportInvalidTypeForm = false
@@ -88,4 +88,3 @@ class AggregateData:
total = len(product_linked_agg_group[0].RelatedObjects) total = len(product_linked_agg_group[0].RelatedObjects)
return total return total
@@ -133,9 +133,8 @@ class BIM_PT_linked_aggregate(Panel):
props = obj.BIMObjectAggregateProperties props = obj.BIMObjectAggregateProperties
row = layout.row(align=True) row = layout.row(align=True)
if element.Decomposes: if element.Decomposes:
Number_Linked_Aggregates = AggregateData.data['total_linked_aggregate'] Number_Linked_Aggregates = AggregateData.data["total_linked_aggregate"]
if not Number_Linked_Aggregates: if not Number_Linked_Aggregates:
row.label(text="Not a Linked Aggregate") row.label(text="Not a Linked Aggregate")
else: else:
@@ -151,6 +150,3 @@ class BIM_PT_linked_aggregate(Panel):
op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X") op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X")
else: else:
row.label(text="Not an Aggregate") row.label(text="Not an Aggregate")
@@ -45,8 +45,7 @@ def draw_ui(context, layout, attributes):
row.label(text=attribute["name"]) row.label(text=attribute["name"])
# row.label(text=attribute["value"]) # row.label(text=attribute["value"])
op = row.operator("bim.select_similar", text=attribute["value"], icon="NONE", emboss=False) op = row.operator("bim.select_similar", text=attribute["value"], icon="NONE", emboss=False)
op.key = attribute['name'] op.key = attribute["name"]
# TODO: reimplement, see #1222 # TODO: reimplement, see #1222
# if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name: # if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
@@ -66,10 +66,7 @@ class LoadBcfProject(bpy.types.Operator):
if bcfxml.version.version_id.startswith("2"): if bcfxml.version.version_id.startswith("2"):
print("No project, we will create one for BBIM.") print("No project, we will create one for BBIM.")
bcfxml.project_info = bcf.v2.model.ProjectExtension( bcfxml.project_info = bcf.v2.model.ProjectExtension(
project=bcf.v2.model.Project( project=bcf.v2.model.Project(name=nameless, project_id=str(uuid.uuid4())), extension_schema=""
name=nameless,
project_id=str(uuid.uuid4())
), extension_schema=""
) )
if bcfxml.project.name is None: if bcfxml.project.name is None:
bcfxml.project.name = nameless bcfxml.project.name = nameless
@@ -971,13 +968,14 @@ class ActivateBcfViewpoint(bpy.types.Operator):
self.set_colours(viewpoint) self.set_colours(viewpoint)
def set_exceptions(self, viewpoint, context): def set_exceptions(self, viewpoint, context):
if ( if not hasattr(viewpoint.visualization_info.components, "visibility") or not hasattr(
not hasattr(viewpoint.visualization_info.components, "visibility") viewpoint.visualization_info.components.visibility.exceptions, "component"
or not hasattr(viewpoint.visualization_info.components.visibility.exceptions, "component")
): ):
return return
exception_global_ids = {v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions.component or []} exception_global_ids = {
v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions.component or []
}
# print("default_visibility: {}".format(viewpoint.visualization_info.components.visibility.default_visibility)) # print("default_visibility: {}".format(viewpoint.visualization_info.components.visibility.default_visibility))
if viewpoint.visualization_info.components.visibility.default_visibility: if viewpoint.visualization_info.components.visibility.default_visibility:
@@ -1034,7 +1032,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
context.area.type = old context.area.type = old
def set_openings_visibility(self, is_visible, context): def set_openings_visibility(self, is_visible, context):
pass # We no longer have an openings collection pass # We no longer have an openings collection
def set_selection(self, viewpoint): def set_selection(self, viewpoint):
if not viewpoint.visualization_info.components or not viewpoint.visualization_info.components.selection: if not viewpoint.visualization_info.components or not viewpoint.visualization_info.components.selection:
@@ -1147,7 +1145,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
# https://github.com/buildingSMART/BCF-XML/tree/release_3_0/Documentation#coloring # https://github.com/buildingSMART/BCF-XML/tree/release_3_0/Documentation#coloring
if lv == 8: if lv == 8:
t = tuple(int(value[i : i + lv // 4], 16) for i in range(0, lv, lv // 4)) t = tuple(int(value[i : i + lv // 4], 16) for i in range(0, lv, lv // 4))
col = [t[1] / 255.0, t[2] / 255.0, t[3] / 255.0, t[0] / 255.0] col = [t[1] / 255.0, t[2] / 255.0, t[3] / 255.0, t[0] / 255.0]
else: else:
t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3)) t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3))
col = [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1] col = [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1]
@@ -603,7 +603,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
objs = context.selected_objects objs = context.selected_objects
if not any((element:=tool.Ifc.get_entity(obj)) and element.is_a("IfcSpace") for obj in objs): if not any((element := tool.Ifc.get_entity(obj)) and element.is_a("IfcSpace") for obj in objs):
self.report({"INFO"}, "No IfcSpace elements selected.") self.report({"INFO"}, "No IfcSpace elements selected.")
return {"FINISHED"} return {"FINISHED"}
@@ -166,9 +166,9 @@ class BrickschemaReferencesData:
results.append( results.append(
{ {
"id": reference.id(), "id": reference.id(),
"identification": reference.ItemReference "identification": (
if tool.Ifc.get_schema() == "IFC2X3" reference.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else reference.Identification
else reference.Identification, ),
"name": reference.Name or "Unnamed", "name": reference.Name or "Unnamed",
} }
) )
@@ -34,6 +34,7 @@ import blenderbim.core.brick as core
import blenderbim.tool.brick as tool import blenderbim.tool.brick as tool
from blenderbim.tool.brick import BrickStore from blenderbim.tool.brick import BrickStore
def update_active_brick_index(self, context): def update_active_brick_index(self, context):
BrickschemaData.is_loaded = False BrickschemaData.is_loaded = False
@@ -66,11 +67,11 @@ def get_brick_relations(self, context):
return relations return relations
def update_view(self, context): def update_view(self, context):
root = context.scene.BIMBrickProperties.brick_list_root root = context.scene.BIMBrickProperties.brick_list_root
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=False) core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=False)
def split_screen_update_view(self, context): def split_screen_update_view(self, context):
root = context.scene.BIMBrickProperties.split_screen_brick_list_root root = context.scene.BIMBrickProperties.split_screen_brick_list_root
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=True) core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=True)
@@ -108,7 +109,11 @@ class BIMBrickProperties(PropertyGroup):
# create relations split screen # create relations split screen
split_screen_toggled: BoolProperty(name="Split Screen Toggled", default=False) split_screen_toggled: BoolProperty(name="Split Screen Toggled", default=False)
split_screen_bricks: CollectionProperty(name="Split Screen Bricks", type=Brick) split_screen_bricks: CollectionProperty(name="Split Screen Bricks", type=Brick)
split_screen_active_brick_index: IntProperty(name="Split Screen Active Brick Index", update=update_active_brick_index) split_screen_active_brick_index: IntProperty(
name="Split Screen Active Brick Index", update=update_active_brick_index
)
split_screen_active_brick_class: StringProperty(name="Split Screen Active Brick Class") split_screen_active_brick_class: StringProperty(name="Split Screen Active Brick Class")
split_screen_brick_breadcrumbs: CollectionProperty(name="Split Screen Brick Breadcrumbs", type=StrProperty) split_screen_brick_breadcrumbs: CollectionProperty(name="Split Screen Brick Breadcrumbs", type=StrProperty)
split_screen_brick_list_root: EnumProperty(name="Split Screen Brick List Root", items=get_brick_roots, update=split_screen_update_view) split_screen_brick_list_root: EnumProperty(
name="Split Screen Brick List Root", items=get_brick_roots, update=split_screen_update_view
)
@@ -194,7 +194,9 @@ class BIM_PT_brickschema_viewport(Panel):
row = grid_right.row() row = grid_right.row()
BIM_UL_bricks.split_screen = True BIM_UL_bricks.split_screen = True
row.template_list("BIM_UL_bricks", "", self.props, "split_screen_bricks", self.props, "split_screen_active_brick_index") row.template_list(
"BIM_UL_bricks", "", self.props, "split_screen_bricks", self.props, "split_screen_active_brick_index"
)
if BrickschemaData.data["active_relations"]: if BrickschemaData.data["active_relations"]:
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -213,7 +215,13 @@ class BIM_PT_brickschema_viewport(Panel):
row.label(text="No selection", icon="INFO") row.label(text="No selection", icon="INFO")
else: else:
prop_with_search(row, self.props, "new_brick_relation_type", text="") prop_with_search(row, self.props, "new_brick_relation_type", text="")
row.label(text=split_screen_selection.label if split_screen_selection.label else split_screen_selection.name) row.label(
text=(
split_screen_selection.label
if split_screen_selection.label
else split_screen_selection.name
)
)
row.operator("bim.add_brick_relation", text="", icon="ADD") row.operator("bim.add_brick_relation", text="", icon="ADD")
elif self.props.brick_create_relations_toggled: elif self.props.brick_create_relations_toggled:
@@ -234,7 +242,11 @@ class BIM_PT_brickschema_viewport(Panel):
row.label(text=relation["object_name"]) row.label(text=relation["object_name"])
row = split.row(align=True) row = split.row(align=True)
row.column().alignment = "RIGHT" row.column().alignment = "RIGHT"
if self.props.brick_edit_relations_toggled and relation["predicate_uri"] and relation["predicate_name"] != "type": if (
self.props.brick_edit_relations_toggled
and relation["predicate_uri"]
and relation["predicate_name"] != "type"
):
op = row.operator("bim.remove_brick_relation", text="", icon="UNLINKED") op = row.operator("bim.remove_brick_relation", text="", icon="UNLINKED")
op.predicate = relation["predicate_uri"] op.predicate = relation["predicate_uri"]
op.object = relation["object_uri"] op.object = relation["object_uri"]
@@ -263,6 +275,7 @@ class BIM_UL_bricks(UIList):
row = split.row() row = split.row()
row.label(text=str(item.total_items)) row.label(text=str(item.total_items))
class BIM_PT_ifc_brickschema_references(Panel): class BIM_PT_ifc_brickschema_references(Panel):
bl_label = "Brickschema References" bl_label = "Brickschema References"
bl_idname = "BIM_PT_ifc_brickschema_references" bl_idname = "BIM_PT_ifc_brickschema_references"
@@ -297,7 +310,7 @@ class BIM_PT_ifc_brickschema_references(Panel):
row.label(text="No IFC Libraries: save the Brick project to create a new library", icon="ERROR") row.label(text="No IFC Libraries: save the Brick project to create a new library", icon="ERROR")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="Libraries must have location pointing to a \".ttl\" file", icon="INFO") row.label(text='Libraries must have location pointing to a ".ttl" file', icon="INFO")
return return
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -507,8 +507,6 @@ class CadOffset(bpy.types.Operator):
local_direction = (rotation_i @ direction).normalized() local_direction = (rotation_i @ direction).normalized()
normals.append(local_direction) normals.append(local_direction)
if len(normals) == 2: if len(normals) == 2:
# https://stackoverflow.com/a/54042831/9627415 # https://stackoverflow.com/a/54042831/9627415
new_normal = (normals[0].lerp(normals[1], 0.5)).normalized() new_normal = (normals[0].lerp(normals[1], 0.5)).normalized()
@@ -70,7 +70,7 @@ class ClashDecorator:
blf.color(font_id, *color) blf.color(font_id, *color)
if coords_2d: if coords_2d:
w, h = blf.dimensions(font_id, text) w, h = blf.dimensions(font_id, text)
coords_2d -= Vector((w * .5, 0)) coords_2d -= Vector((w * 0.5, 0))
blf.position(font_id, coords_2d[0], coords_2d[1], 0) blf.position(font_id, coords_2d[0], coords_2d[1], 0)
blf.draw(font_id, text) # Set your text here blf.draw(font_id, text) # Set your text here
@@ -496,4 +496,3 @@ class SelectSmartGroup(bpy.types.Operator):
with bpy.context.temp_override(**context_override): with bpy.context.temp_override(**context_override):
bpy.ops.view3d.view_selected() bpy.ops.view3d.view_selected()
return {"FINISHED"} return {"FINISHED"}
@@ -105,7 +105,7 @@ class BIM_PT_object_constraints(Panel):
if constraint["type"] == "IfcObjective": if constraint["type"] == "IfcObjective":
icon = "LIGHT" icon = "LIGHT"
else: else:
continue # Metric not implemented continue # Metric not implemented
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text=constraint["name"]) row.label(text=constraint["name"])
row.operator("bim.unassign_constraint", text="", icon="X").constraint = constraint["id"] row.operator("bim.unassign_constraint", text="", icon="X").constraint = constraint["id"]
@@ -164,7 +164,14 @@ class CostSchedulesData:
if unit: if unit:
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit) data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
if quantity.is_a("IfcPhysicalSimpleQuantity"): if quantity.is_a("IfcPhysicalSimpleQuantity"):
measure_class = quantity.wrapped_data.declaration().as_entity().attribute_by_index(3).type_of_attribute().declared_type().name() measure_class = (
quantity.wrapped_data.declaration()
.as_entity()
.attribute_by_index(3)
.type_of_attribute()
.declared_type()
.name()
)
if "Count" in measure_class: if "Count" in measure_class:
data["UnitSymbol"] = "U" data["UnitSymbol"] = "U"
@@ -47,14 +47,14 @@ class BIM_PT_cost_schedules(Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
if CostSchedulesData.data["total_cost_schedules"]: if CostSchedulesData.data["total_cost_schedules"]:
row.alignment = "RIGHT" row.alignment = "RIGHT"
row.operator("bim.export_cost_schedules",icon="EXPORT",text="Export All Schedules") row.operator("bim.export_cost_schedules", icon="EXPORT", text="Export All Schedules")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT") row.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT")
else: else:
row.label(text="No Cost Schedules found.", icon="TEXT") row.label(text="No Cost Schedules found.", icon="TEXT")
row.operator("bim.add_cost_schedule", icon="ADD", text="") row.operator("bim.add_cost_schedule", icon="ADD", text="")
row.operator("bim.import_cost_schedule_csv",icon="IMPORT",text="") row.operator("bim.import_cost_schedule_csv", icon="IMPORT", text="")
for schedule in CostSchedulesData.data["schedules"]: for schedule in CostSchedulesData.data["schedules"]:
self.draw_cost_schedule_ui(schedule) self.draw_cost_schedule_ui(schedule)
@@ -96,9 +96,9 @@ class BIM_PT_cost_schedules(Panel):
text="{}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]), icon="LINENUMBERS_ON" text="{}[{}]".format(cost_schedule["name"], cost_schedule["predefined_type"]), icon="LINENUMBERS_ON"
) )
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule["id"] row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule["id"]
row.operator( row.operator("bim.enable_editing_cost_schedule_attributes", text="", icon="GREASEPENCIL").cost_schedule = (
"bim.enable_editing_cost_schedule_attributes", text="", icon="GREASEPENCIL" cost_schedule["id"]
).cost_schedule = cost_schedule["id"] )
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule["id"] row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule["id"]
if self.props.active_cost_schedule_id == cost_schedule["id"]: if self.props.active_cost_schedule_id == cost_schedule["id"]:
if self.props.is_editing == "COST_SCHEDULE_ATTRIBUTES": if self.props.is_editing == "COST_SCHEDULE_ATTRIBUTES":
@@ -616,9 +616,9 @@ class BIM_UL_cost_items_trait:
def draw_parent_operator(self, row, cost_item_id): def draw_parent_operator(self, row, cost_item_id):
if self.props.active_cost_item_id: if self.props.active_cost_item_id:
if self.props.active_cost_item_id != cost_item_id: if self.props.active_cost_item_id != cost_item_id:
op = row.operator( op = row.operator("bim.change_parent_cost_item", text="", icon="LINKED", emboss=False).new_parent = (
"bim.change_parent_cost_item", text="", icon="LINKED", emboss=False cost_item_id
).new_parent = cost_item_id )
else: else:
row.label(text="", icon="BLANK1") row.label(text="", icon="BLANK1")
@@ -18,7 +18,8 @@
import bpy import bpy
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
#from blenderbim.bim.module.spatial.data import SpatialData
# from blenderbim.bim.module.spatial.data import SpatialData
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -30,10 +31,13 @@ from bpy.props import (
FloatVectorProperty, FloatVectorProperty,
CollectionProperty, CollectionProperty,
) )
#import blenderbim.tool as tool
#import blenderbim.core.geometry # import blenderbim.tool as tool
#import ifcopenshell # import blenderbim.core.geometry
# import ifcopenshell
class BIMCoveringProperties(PropertyGroup): class BIMCoveringProperties(PropertyGroup):
ceiling_height: bpy.props.FloatProperty(name="ceiling_height", default=2.7, subtype="DISTANCE", description="Ceiling height") ceiling_height: bpy.props.FloatProperty(
name="ceiling_height", default=2.7, subtype="DISTANCE", description="Ceiling height"
)
@@ -128,6 +128,3 @@ class BIM_PT_ifccsv(Panel):
row = layout.row(align=True) row = layout.row(align=True)
row.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper()) row.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper())
row.operator("bim.import_ifccsv", icon="IMPORT") row.operator("bim.import_ifccsv", icon="IMPORT")
@@ -90,9 +90,9 @@ class BIM_PT_debug(Panel):
row.operator("bim.select_high_polygon_meshes").threshold = context.scene.BIMDebugProperties.number_of_polygons row.operator("bim.select_high_polygon_meshes").threshold = context.scene.BIMDebugProperties.number_of_polygons
row.prop(props, "number_of_polygons", text="") row.prop(props, "number_of_polygons", text="")
row = layout.split(factor=0.7, align=True) row = layout.split(factor=0.7, align=True)
row.operator( row.operator("bim.select_highest_polygon_meshes").percentile = (
"bim.select_highest_polygon_meshes" context.scene.BIMDebugProperties.percentile_of_polygons
).percentile = context.scene.BIMDebugProperties.percentile_of_polygons )
row.prop(props, "percentile_of_polygons", text="") row.prop(props, "percentile_of_polygons", text="")
row = layout.split(factor=0.5, align=True) row = layout.split(factor=0.5, align=True)
@@ -140,9 +140,9 @@ class BIM_PT_debug(Panel):
op = row.operator("bim.print_object_placement", icon="OBJECT_ORIGIN", text="") op = row.operator("bim.print_object_placement", icon="OBJECT_ORIGIN", text="")
op.step_id = attribute.int_value op.step_id = attribute.int_value
if attribute.int_value: if attribute.int_value:
row.operator( row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="" attribute.int_value
).step_id = attribute.int_value )
if props.inverse_attributes: if props.inverse_attributes:
layout.label(text="Inverse attributes:") layout.label(text="Inverse attributes:")
@@ -152,9 +152,9 @@ class BIM_PT_debug(Panel):
row.prop(attribute, "name", text="") row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="") row.prop(attribute, "string_value", text="")
if attribute.int_value: if attribute.int_value:
row.operator( row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="" attribute.int_value
).step_id = attribute.int_value )
if props.inverse_references: if props.inverse_references:
layout.label(text="Inverse references:") layout.label(text="Inverse references:")
@@ -163,6 +163,6 @@ class BIM_PT_debug(Panel):
row = layout.row(align=True) row = layout.row(align=True)
row.prop(attribute, "string_value", text="") row.prop(attribute, "string_value", text="")
if attribute.int_value: if attribute.int_value:
row.operator( row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="" attribute.int_value
).step_id = attribute.int_value )
@@ -29,6 +29,7 @@
import bpy import bpy
from blenderbim.bim.module.demo.data import DemoData from blenderbim.bim.module.demo.data import DemoData
# Every panel in the interface correlates to one of these classes. If you enable # Every panel in the interface correlates to one of these classes. If you enable
# the "Developer Extras" option in Blender, then you can actually right click on # the "Developer Extras" option in Blender, then you can actually right click on
# any panel in Blender, and click "Edit Source". This will bring you to a ui.py # any panel in Blender, and click "Edit Source". This will bring you to a ui.py
@@ -159,7 +159,7 @@ class BaseDecorator:
objecttype = "NOTDEFINED" objecttype = "NOTDEFINED"
def __init__(self): def __init__(self):
self.font_id = 0 # 0 is the default font self.font_id = 0 # 0 is the default font
# POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated # POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR") self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
@@ -2020,7 +2020,6 @@ class DecorationsHandler:
for decorator in self.decorators.values(): for decorator in self.decorators.values():
decorator.font_id = font_id decorator.font_id = font_id
def get_objects_and_decorators(self, collection): def get_objects_and_decorators(self, collection):
# TODO: do it in data instead of the handler for performance? # TODO: do it in data instead of the handler for performance?
results = [] results = []
@@ -41,9 +41,8 @@ def set_active_camera_resolution(scene):
props = scene.camera.data.BIMCameraProperties props = scene.camera.data.BIMCameraProperties
ortho_scale = max((props.width, props.height)) ortho_scale = max((props.width, props.height))
aspect_ratio = props.width / props.height aspect_ratio = props.width / props.height
if ( if (scene.camera.data.ortho_scale != ortho_scale) or (
(scene.camera.data.ortho_scale != ortho_scale) scene.render.resolution_x / scene.render.resolution_y != aspect_ratio
or (scene.render.resolution_x / scene.render.resolution_y != aspect_ratio)
): ):
scene.camera.data.ortho_scale = ortho_scale scene.camera.data.ortho_scale = ortho_scale
@@ -127,7 +127,7 @@ def format_distance(
precision=None, precision=None,
decimal_places=None, decimal_places=None,
suppress_zero_inches=False, suppress_zero_inches=False,
in_unit_length = False in_unit_length=False,
): ):
s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented) s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented)
@@ -141,9 +141,9 @@ def format_distance(
# Imperial Formatting # Imperial Formatting
if unit_system == "IMPERIAL": if unit_system == "IMPERIAL":
if in_unit_length: if in_unit_length:
if unit_length == 'INCHES': if unit_length == "INCHES":
toInches = 1 toInches = 1
if unit_length == 'FEET': if unit_length == "FEET":
toInches = 11.9999 toInches = 11.9999
else: else:
toInches = 39.3700787401574887 toInches = 39.3700787401574887
@@ -222,10 +222,10 @@ def format_distance(
# METRIC FORMATTING # METRIC FORMATTING
elif unit_system == "METRIC": elif unit_system == "METRIC":
if in_unit_length: if in_unit_length:
if unit_length == 'CENTIMETERS': if unit_length == "CENTIMETERS":
value = value/100 value = value / 100
if unit_length == 'MILLIMETERS': if unit_length == "MILLIMETERS":
value = value/1000 value = value / 1000
if precision: if precision:
value = precision * round(float(value) / precision) value = precision * round(float(value) / precision)
@@ -123,18 +123,18 @@ class BIM_PT_element_filters(Panel):
self.layout, props.include_filter_groups, ElementFiltersData, "drawing_include" self.layout, props.include_filter_groups, ElementFiltersData, "drawing_include"
) )
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.operator( row.operator("bim.edit_element_filter", icon="CHECKMARK", text="Save Include Filter").filter_mode = (
"bim.edit_element_filter", icon="CHECKMARK", text="Save Include Filter" "INCLUDE"
).filter_mode = "INCLUDE" )
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE" row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
elif props.filter_mode == "EXCLUDE": elif props.filter_mode == "EXCLUDE":
blenderbim.bim.helper.draw_filter( blenderbim.bim.helper.draw_filter(
self.layout, props.exclude_filter_groups, ElementFiltersData, "drawing_exclude" self.layout, props.exclude_filter_groups, ElementFiltersData, "drawing_exclude"
) )
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.operator( row.operator("bim.edit_element_filter", icon="CHECKMARK", text="Save Exclude Filter").filter_mode = (
"bim.edit_element_filter", icon="CHECKMARK", text="Save Exclude Filter" "EXCLUDE"
).filter_mode = "EXCLUDE" )
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE" row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
else: else:
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -260,9 +260,9 @@ class BIM_PT_drawings(Panel):
row2 = col.row(align=True) row2 = col.row(align=True)
row2.operator("bim.remove_drawing", icon="X", text="").drawing = active_drawing.ifc_definition_id row2.operator("bim.remove_drawing", icon="X", text="").drawing = active_drawing.ifc_definition_id
row2.operator( row2.operator("bim.duplicate_drawing", icon="COPYDOWN", text="").drawing = (
"bim.duplicate_drawing", icon="COPYDOWN", text="" active_drawing.ifc_definition_id
).drawing = active_drawing.ifc_definition_id )
col = row.column() col = row.column()
col.alignment = "RIGHT" col.alignment = "RIGHT"
@@ -339,9 +339,9 @@ class BIM_PT_schedules(Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.alignment = "RIGHT" row.alignment = "RIGHT"
row.operator("bim.open_schedule", icon="URL", text="").schedule = active_schedule.ifc_definition_id row.operator("bim.open_schedule", icon="URL", text="").schedule = active_schedule.ifc_definition_id
row.operator( row.operator("bim.build_schedule", icon="LINENUMBERS_ON", text="").schedule = (
"bim.build_schedule", icon="LINENUMBERS_ON", text="" active_schedule.ifc_definition_id
).schedule = active_schedule.ifc_definition_id )
row.operator("bim.remove_schedule", icon="X", text="").schedule = active_schedule.ifc_definition_id row.operator("bim.remove_schedule", icon="X", text="").schedule = active_schedule.ifc_definition_id
self.layout.template_list( self.layout.template_list(
@@ -612,13 +612,13 @@ class BIM_UL_sheets(bpy.types.UIList):
row = layout.row(align=True) row = layout.row(align=True)
if item.is_sheet: if item.is_sheet:
if item.is_expanded: if item.is_expanded:
row.operator( row.operator("bim.contract_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").sheet = (
"bim.contract_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" item.ifc_definition_id
).sheet = item.ifc_definition_id )
else: else:
row.operator( row.operator("bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").sheet = (
"bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" item.ifc_definition_id
).sheet = item.ifc_definition_id )
row.label(text=f"{item.identification} - {item.name}") row.label(text=f"{item.identification} - {item.name}")
else: else:
@@ -39,6 +39,7 @@ class SelectFMIfcFile(MultipleFileSelector):
self.update_props(props, "ifc_file", props.ifc_files) self.update_props(props, "ifc_file", props.ifc_files)
return {"FINISHED"} return {"FINISHED"}
class ExecuteIfcFM(bpy.types.Operator): class ExecuteIfcFM(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm" bl_idname = "bim.execute_ifcfm"
bl_label = "Execute IfcFM" bl_label = "Execute IfcFM"
@@ -85,15 +85,15 @@ class BIM_MT_object_set_origin(Menu):
bl_label = "IFC Set Origin" bl_label = "IFC Set Origin"
def draw(self, context): def draw(self, context):
self.layout.operator( self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Geometry to Origin").origin_type = (
"bim.override_origin_set", icon="PLUGIN", text="IFC Geometry to Origin" "GEOMETRY_ORIGIN"
).origin_type = "GEOMETRY_ORIGIN" )
self.layout.operator( self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Geometry").origin_type = (
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Geometry" "ORIGIN_GEOMETRY"
).origin_type = "ORIGIN_GEOMETRY" )
self.layout.operator( self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Origin to 3D Cursor").origin_type = (
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to 3D Cursor" "ORIGIN_CURSOR"
).origin_type = "ORIGIN_CURSOR" )
self.layout.operator( self.layout.operator(
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Center of Mass (Surface)" "bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Center of Mass (Surface)"
).origin_type = "ORIGIN_CENTER_OF_MASS" ).origin_type = "ORIGIN_CENTER_OF_MASS"
@@ -118,6 +118,7 @@ class ConvertGlobalToLocal(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
core.convert_global_to_local(tool.Georeference) core.convert_global_to_local(tool.Georeference)
class ConvertAngleToCoordinates(bpy.types.Operator, tool.Ifc.Operator): class ConvertAngleToCoordinates(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.convert_angle_to_coord" bl_idname = "bim.convert_angle_to_coord"
bl_label = "Convert Angle To Y Axis" bl_label = "Convert Angle To Y Axis"
@@ -101,9 +101,9 @@ class LibraryReferencesData:
results.append( results.append(
{ {
"id": library.id(), "id": library.id(),
"identification": library.ItemReference "identification": (
if tool.Ifc.get_schema() == "IFC2X3" library.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else library.Identification
else library.Identification, ),
"name": library.Name or "Unnamed", "name": library.Name or "Unnamed",
} }
) )
@@ -34,10 +34,12 @@ classes = (
ui.BIM_PT_solar, ui.BIM_PT_solar,
) )
def register(): def register():
bpy.types.Scene.radiance_exporter_properties = bpy.props.PointerProperty(type=prop.RadianceExporterProperties) bpy.types.Scene.radiance_exporter_properties = bpy.props.PointerProperty(type=prop.RadianceExporterProperties)
bpy.types.Scene.BIMSolarProperties = bpy.props.PointerProperty(type=prop.BIMSolarProperties) bpy.types.Scene.BIMSolarProperties = bpy.props.PointerProperty(type=prop.BIMSolarProperties)
def unregister(): def unregister():
del bpy.types.Scene.radiance_exporter_properties del bpy.types.Scene.radiance_exporter_properties
del bpy.types.Scene.BIMSolarProperties del bpy.types.Scene.BIMSolarProperties
@@ -87,7 +87,6 @@ class SolarDecorator:
blf.position(self.font_id, co[0], co[1], 0) blf.position(self.font_id, co[0], co[1], 0)
blf.draw(self.font_id, line) blf.draw(self.font_id, line)
def draw_geometry(self, context): def draw_geometry(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences() self.addon_prefs = tool.Blender.get_addon_preferences()
decorator_color_special = self.addon_prefs.decorator_color_special decorator_color_special = self.addon_prefs.decorator_color_special
@@ -153,8 +152,7 @@ class SolarDecorator:
analemma_verts = sun_position.sun_calc.calc_analemma(context, h) analemma_verts = sun_position.sun_calc.calc_analemma(context, h)
coords.extend([origin @ v for v in analemma_verts]) coords.extend([origin @ v for v in analemma_verts])
for i in range(len(analemma_verts) - 1): for i in range(len(analemma_verts) - 1):
indices.append((coord_offset + i, indices.append((coord_offset + i, coord_offset + i + 1))
coord_offset + i+1))
coord_offset += len(analemma_verts) coord_offset += len(analemma_verts)
self.draw_batch("LINES", coords, decorator_color_special, indices) self.draw_batch("LINES", coords, decorator_color_special, indices)
@@ -37,13 +37,14 @@ from blenderbim.bim.module.light.data import SolarData
ifc_materials = [] ifc_materials = []
class ExportOBJ(bpy.types.Operator): class ExportOBJ(bpy.types.Operator):
"""Exports the IFC File to OBJ""" """Exports the IFC File to OBJ"""
bl_idname = "export_scene.radiance" bl_idname = "export_scene.radiance"
bl_label = "Export" bl_label = "Export"
bl_description = "Export the IFC to OBJ" bl_description = "Export the IFC to OBJ"
def execute(self, context): def execute(self, context):
# Get the output directory # Get the output directory
@@ -52,7 +53,6 @@ class ExportOBJ(bpy.types.Operator):
context.scene.radiance_exporter_properties.is_exporting = True context.scene.radiance_exporter_properties.is_exporting = True
# Conversion from IFC to OBJ # Conversion from IFC to OBJ
# Settings for obj # Settings for obj
settings = ifcopenshell.geom.settings() settings = ifcopenshell.geom.settings()
@@ -110,21 +110,22 @@ class ExportOBJ(bpy.types.Operator):
serialiser.finalize() serialiser.finalize()
context.scene.radiance_exporter_properties.is_exporting = False context.scene.radiance_exporter_properties.is_exporting = False
self.report({'INFO'}, "Exported OBJ file to: {}".format(obj_file_path)) self.report({"INFO"}, "Exported OBJ file to: {}".format(obj_file_path))
return {'FINISHED'} return {"FINISHED"}
class RadianceRender(bpy.types.Operator): class RadianceRender(bpy.types.Operator):
"""Radiance Rendering""" """Radiance Rendering"""
bl_idname = "render_scene.radiance" bl_idname = "render_scene.radiance"
bl_label = "Render" bl_label = "Render"
bl_description = "Renders the scene using Radiance" bl_description = "Renders the scene using Radiance"
def execute(self, context): def execute(self, context):
if pr is None: if pr is None:
self.report({'ERROR'}, "PyRadiance is not available. Cannot perform rendering.") self.report({"ERROR"}, "PyRadiance is not available. Cannot perform rendering.")
return {'CANCELLED'} return {"CANCELLED"}
# Get the resolution from the user input # Get the resolution from the user input
props = context.scene.radiance_exporter_properties props = context.scene.radiance_exporter_properties
@@ -138,11 +139,10 @@ class RadianceRender(bpy.types.Operator):
obj_file_path = os.path.join(output_dir, "model.obj") obj_file_path = os.path.join(output_dir, "model.obj")
camera = self.get_active_camera(context) camera = self.get_active_camera(context)
if camera is None: if camera is None:
self.report({'ERROR'}, "No active camera found in the scene. Please add a camera and set it as active.") self.report({"ERROR"}, "No active camera found in the scene. Please add a camera and set it as active.")
return {'CANCELLED'} return {"CANCELLED"}
# Get camera position and direction # Get camera position and direction
camera_position, camera_direction = self.get_camera_data(camera) camera_position, camera_direction = self.get_camera_data(camera)
@@ -156,13 +156,12 @@ class RadianceRender(bpy.types.Operator):
# l = line.strip().split(" ") # l = line.strip().split(" ")
# style.append(l[1]) # style.append(l[1])
# Check if json file is empty or not # Check if json file is empty or not
props = context.scene.radiance_exporter_properties props = context.scene.radiance_exporter_properties
if props.use_json_file: if props.use_json_file:
# Load data from JSON file # Load data from JSON file
with open(props.json_file, 'r') as file: with open(props.json_file, "r") as file:
data = json.load(file) data = json.load(file)
else: else:
# Use in-UI material mappings # Use in-UI material mappings
@@ -170,7 +169,6 @@ class RadianceRender(bpy.types.Operator):
print(data) print(data)
# Create materials.rad file # Create materials.rad file
materials_file = os.path.join(output_dir, "materials.rad") materials_file = os.path.join(output_dir, "materials.rad")
with open(materials_file, "w") as file: with open(materials_file, "w") as file:
@@ -190,19 +188,19 @@ class RadianceRender(bpy.types.Operator):
# print(i) # print(i)
# file.write("inherit alias " + i + " " + data.get(i, "white") + "\n") # file.write("inherit alias " + i + " " + data.get(i, "white") + "\n")
self.report({'INFO'}, "Exported Materials Rad file to: {}".format(materials_file)) self.report({"INFO"}, "Exported Materials Rad file to: {}".format(materials_file))
# Run obj2mesh # Run obj2mesh
rtm_file_path = os.path.join(output_dir, "model.rtm") rtm_file_path = os.path.join(output_dir, "model.rtm")
mesh_file_path = save_obj2mesh_output(obj_file_path, rtm_file_path, matfiles=[materials_file]) mesh_file_path = save_obj2mesh_output(obj_file_path, rtm_file_path, matfiles=[materials_file])
# subprocess.run(["obj2mesh", "-a", materials_file, obj_file_path, rtm_file_path]) # subprocess.run(["obj2mesh", "-a", materials_file, obj_file_path, rtm_file_path])
self.report({'INFO'}, "obj2mesh output: {}".format(mesh_file_path)) self.report({"INFO"}, "obj2mesh output: {}".format(mesh_file_path))
scene_file = os.path.join(output_dir, "scene.rad") scene_file = os.path.join(output_dir, "scene.rad")
with open(scene_file, "w") as file: with open(scene_file, "w") as file:
# file.write("void mesh model\n1 " + rtm_file_path + "\n0\n0\n") # file.write("void mesh model\n1 " + rtm_file_path + "\n0\n0\n")
file.write('void mesh model\n1 "' + rtm_file_path + '"\n0\n0\n') file.write('void mesh model\n1 "' + rtm_file_path + '"\n0\n0\n')
self.report({'INFO'}, "Exported Scene file to: {}".format(scene_file)) self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file))
# Py Radiance Rendering code # Py Radiance Rendering code
scene = pr.Scene("ascene") scene = pr.Scene("ascene")
@@ -216,26 +214,31 @@ class RadianceRender(bpy.types.Operator):
aview = pr.View(position=camera_position, direction=camera_direction) aview = pr.View(position=camera_position, direction=camera_direction)
scene.add_view(aview) scene.add_view(aview)
image = pr.render(scene, ambbounce=1, resolution=(resolution_x, resolution_y), image = pr.render(
quality=quality, detail=detail, variability=variability) scene,
ambbounce=1,
resolution=(resolution_x, resolution_y),
quality=quality,
detail=detail,
variability=variability,
)
output_path = os.path.join(output_dir, f"{output_file_name}.{output_file_format.lower()}") output_path = os.path.join(output_dir, f"{output_file_name}.{output_file_format.lower()}")
if output_file_format == 'HDR': if output_file_format == "HDR":
with open(output_path, "wb") as wtr: with open(output_path, "wb") as wtr:
wtr.write(image) wtr.write(image)
else: else:
pass pass
self.report({"INFO"}, "Radiance rendering completed. Output: {}".format(output_path))
self.report({'INFO'}, "Radiance rendering completed. Output: {}".format(output_path)) return {"FINISHED"}
return {'FINISHED'}
def get_active_camera(self, context): def get_active_camera(self, context):
if context.scene.camera: if context.scene.camera:
return context.scene.camera return context.scene.camera
for obj in context.scene.objects: for obj in context.scene.objects:
if obj.type == 'CAMERA': if obj.type == "CAMERA":
return obj return obj
return None return None
@@ -256,10 +259,11 @@ class RadianceRender(bpy.types.Operator):
resolution_y = props.radiance_resolution_y resolution_y = props.radiance_resolution_y
return resolution_x, resolution_y return resolution_x, resolution_y
def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **kwargs): def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **kwargs):
output_bytes = pr.obj2mesh(inp, **kwargs) output_bytes = pr.obj2mesh(inp, **kwargs)
with open(output_file, 'wb') as f: with open(output_file, "wb") as f:
f.write(output_bytes) f.write(output_bytes)
return output_file return output_file
@@ -333,6 +337,7 @@ class ViewFromSun(bpy.types.Operator):
props.hour = props.hour # Just to refresh camera position props.hour = props.hour # Just to refresh camera position
return {"FINISHED"} return {"FINISHED"}
class RefreshIFCMaterials(bpy.types.Operator): class RefreshIFCMaterials(bpy.types.Operator):
bl_idname = "bim.refresh_ifc_materials" bl_idname = "bim.refresh_ifc_materials"
bl_label = "Refresh IFC Materials" bl_label = "Refresh IFC Materials"
@@ -350,4 +355,4 @@ class RefreshIFCMaterials(bpy.types.Operator):
if not props.get_material_mapping(style_name): if not props.get_material_mapping(style_name):
props.add_material_mapping(style_id, style_name) props.add_material_mapping(style_id, style_name)
return {'FINISHED'} return {"FINISHED"}
@@ -174,19 +174,14 @@ class RadianceExporterProperties(PropertyGroup):
use_json_file: BoolProperty( use_json_file: BoolProperty(
name="Upload JSON", name="Upload JSON",
description="Toggle between uploading a JSON file and using in-UI material mapping", description="Toggle between uploading a JSON file and using in-UI material mapping",
default=False default=False,
) )
is_exporting: bpy.props.BoolProperty( is_exporting: bpy.props.BoolProperty(
name="Is Exporting", name="Is Exporting", description="Whether the OBJ export is in progress", default=False
description="Whether the OBJ export is in progress",
default=False
) )
material_mappings: bpy.props.CollectionProperty( material_mappings: bpy.props.CollectionProperty(type=bpy.types.PropertyGroup, name="Material Mappings")
type= bpy.types.PropertyGroup,
name="Material Mappings"
)
should_load_from_memory: BoolProperty( should_load_from_memory: BoolProperty(
name="Load from Memory", name="Load from Memory",
@@ -194,86 +189,69 @@ class RadianceExporterProperties(PropertyGroup):
) )
radiance_resolution_x: IntProperty( radiance_resolution_x: IntProperty(
name="X", name="X", description="Horizontal resolution of the output image", default=1920, min=1
description="Horizontal resolution of the output image",
default=1920,
min=1
) )
radiance_resolution_y: IntProperty( radiance_resolution_y: IntProperty(
name="Y", name="Y", description="Vertical resolution of the output image", default=1080, min=1
description="Vertical resolution of the output image",
default=1080,
min=1
) )
output_dir: StringProperty( output_dir: StringProperty(
name="Output Directory", name="Output Directory",
description="Directory to output Radiance files", description="Directory to output Radiance files",
default="", default="",
subtype="DIR_PATH", subtype="DIR_PATH",
update=lambda self, context: self.update_output_dir(context) update=lambda self, context: self.update_output_dir(context),
) )
ifc_file: StringProperty( ifc_file: StringProperty(
name="IFC File", name="IFC File",
description="Path to the IFC file", description="Path to the IFC file",
default="", default="",
subtype="FILE_PATH", subtype="FILE_PATH",
update=lambda self, context: self.update_ifc_file(context) update=lambda self, context: self.update_ifc_file(context),
) )
json_file: StringProperty( json_file: StringProperty(
name="JSON File", name="JSON File",
description="Path to the JSON file", description="Path to the JSON file",
default="", default="",
subtype="FILE_PATH", subtype="FILE_PATH",
update=lambda self, context: self.update_json_file(context) update=lambda self, context: self.update_json_file(context),
) )
radiance_quality: EnumProperty( radiance_quality: EnumProperty(
name="Quality", name="Quality",
description="Radiance rendering quality", description="Radiance rendering quality",
items=[ items=[("LOW", "Low", "Low quality"), ("MEDIUM", "Medium", "Medium quality"), ("HIGH", "High", "High quality")],
('LOW', "Low", "Low quality"), default="MEDIUM",
('MEDIUM', "Medium", "Medium quality"),
('HIGH', "High", "High quality")
],
default='MEDIUM'
) )
radiance_detail: EnumProperty( radiance_detail: EnumProperty(
name="Detail", name="Detail",
description="Radiance rendering detail", description="Radiance rendering detail",
items=[ items=[("LOW", "Low", "Low detail"), ("MEDIUM", "Medium", "Medium detail"), ("HIGH", "High", "High detail")],
('LOW', "Low", "Low detail"), default="MEDIUM",
('MEDIUM', "Medium", "Medium detail"),
('HIGH', "High", "High detail")
],
default='MEDIUM'
) )
radiance_variability: EnumProperty( radiance_variability: EnumProperty(
name="Variability", name="Variability",
description="Radiance rendering variability", description="Radiance rendering variability",
items=[ items=[
('LOW', "Low", "Low variability"), ("LOW", "Low", "Low variability"),
('MEDIUM', "Medium", "Medium variability"), ("MEDIUM", "Medium", "Medium variability"),
('HIGH', "High", "High variability") ("HIGH", "High", "High variability"),
], ],
default="MEDIUM", default="MEDIUM",
) )
output_file_name: StringProperty( output_file_name: StringProperty(
name="Output File Name", name="Output File Name", description="Name of the output image file (without extension)", default="render"
description="Name of the output image file (without extension)",
default="render"
) )
output_file_format: EnumProperty( output_file_format: EnumProperty(
name="Output File Format", name="Output File Format",
description="Format of the output image file", description="Format of the output image file",
items=[ items=[
('HDR', "HDR", "High Dynamic Range"), ("HDR", "HDR", "High Dynamic Range"),
], ],
default='HDR' default="HDR",
) )
class BIMSolarProperties(PropertyGroup): class BIMSolarProperties(PropertyGroup):
sites: EnumProperty(items=get_sites, name="Sites") sites: EnumProperty(items=get_sites, name="Sites")
latitude: FloatProperty(name="Latitude", min=-90, max=90, update=update_latlong) latitude: FloatProperty(name="Latitude", min=-90, max=90, update=update_latlong)
@@ -26,11 +26,12 @@ sun_position = tool.Blender.get_sun_position_addon()
class BIM_PT_radiance_exporter(bpy.types.Panel): class BIM_PT_radiance_exporter(bpy.types.Panel):
"""Creates a Panel in the render properties window""" """Creates a Panel in the render properties window"""
bl_label = "Radiance Exporter" bl_label = "Radiance Exporter"
bl_idname = "BIM_PT_radiance_exporter" bl_idname = "BIM_PT_radiance_exporter"
bl_options = {'DEFAULT_CLOSED'} bl_options = {"DEFAULT_CLOSED"}
bl_space_type = 'PROPERTIES' bl_space_type = "PROPERTIES"
bl_region_type = 'WINDOW' bl_region_type = "WINDOW"
bl_context = "scene" bl_context = "scene"
bl_parent_id = "BIM_PT_tab_lighting" bl_parent_id = "BIM_PT_tab_lighting"
@@ -52,7 +53,6 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
row = layout.row() row = layout.row()
row.prop(props, "output_dir") row.prop(props, "output_dir")
row = layout.row() row = layout.row()
layout.prop(props, "use_json_file") layout.prop(props, "use_json_file")
@@ -69,7 +69,6 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
layout.operator("bim.refresh_ifc_materials") layout.operator("bim.refresh_ifc_materials")
layout.separator() layout.separator()
row = layout.row() row = layout.row()
row.label(text="Resolution") row.label(text="Resolution")
@@ -104,12 +103,14 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
row.operator("render_scene.radiance", text="Radiance Render") row.operator("render_scene.radiance", text="Radiance Render")
row.enabled = not props.is_exporting row.enabled = not props.is_exporting
class BIM_PT_solar(bpy.types.Panel): class BIM_PT_solar(bpy.types.Panel):
"""Creates a Panel in the render properties window""" """Creates a Panel in the render properties window"""
bl_label = "Solar Access / Shadow" bl_label = "Solar Access / Shadow"
bl_idname = "BIM_PT_solar" bl_idname = "BIM_PT_solar"
bl_space_type = 'PROPERTIES' bl_space_type = "PROPERTIES"
bl_region_type = 'WINDOW' bl_region_type = "WINDOW"
bl_context = "scene" bl_context = "scene"
bl_parent_id = "BIM_PT_tab_solar_analysis" bl_parent_id = "BIM_PT_tab_solar_analysis"
bl_options = {"HIDE_HEADER"} bl_options = {"HIDE_HEADER"}
@@ -135,7 +136,7 @@ class BIM_PT_solar(bpy.types.Panel):
sun_props = context.scene.sun_pos_properties sun_props = context.scene.sun_pos_properties
row = self.layout.row() row = self.layout.row()
row.prop(sun_props, "coordinates", icon='URL') row.prop(sun_props, "coordinates", icon="URL")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "latitude") row.prop(props, "latitude")
row.prop(props, "longitude") row.prop(props, "longitude")
@@ -146,20 +147,24 @@ class BIM_PT_solar(bpy.types.Panel):
row.operator("bim.import_true_north", icon="IMPORT", text="") row.operator("bim.import_true_north", icon="IMPORT", text="")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "month", text={ row.prop(
1: "January", props,
2: "February", "month",
3: "March", text={
4: "April", 1: "January",
5: "May", 2: "February",
6: "June", 3: "March",
7: "July", 4: "April",
8: "August", 5: "May",
9: "September", 6: "June",
10: "October", 7: "July",
11: "November", 8: "August",
12: "December", 9: "September",
}[props.month]) 10: "October",
11: "November",
12: "December",
}[props.month],
)
row.prop(props, "day") row.prop(props, "day")
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -258,7 +258,9 @@ class ObjectMaterialData:
precision = bpy.context.scene.DocProperties.imperial_precision precision = bpy.context.scene.DocProperties.imperial_precision
else: else:
precision = None precision = None
formatted_thickness = format_distance(total_thickness, precision=precision, suppress_zero_inches=True, in_unit_length = True) formatted_thickness = format_distance(
total_thickness, precision=precision, suppress_zero_inches=True, in_unit_length=True
)
data["name"] = f"{formatted_thickness} - {data['name']}" data["name"] = f"{formatted_thickness} - {data['name']}"
if item.is_a("IfcMaterial"): if item.is_a("IfcMaterial"):
data["material"] = item.Name or "Unnamed" data["material"] = item.Name or "Unnamed"
@@ -235,7 +235,10 @@ class BIM_PT_object_material(Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="----- Exterior -----") row.label(text="----- Exterior -----")
for index, set_item in enumerate(ObjectMaterialData.data["set_items"]): for index, set_item in enumerate(ObjectMaterialData.data["set_items"]):
if len(self.props.material_set_item_profile_attributes) and self.props.active_material_set_item_id == set_item["id"]: if (
len(self.props.material_set_item_profile_attributes)
and self.props.active_material_set_item_id == set_item["id"]
):
self.draw_editable_set_item_profile_ui(set_item) self.draw_editable_set_item_profile_ui(set_item)
elif self.props.active_material_set_item_id == set_item["id"]: elif self.props.active_material_set_item_id == set_item["id"]:
self.draw_editable_set_item_ui(set_item) self.draw_editable_set_item_ui(set_item)
@@ -341,7 +344,9 @@ class BIM_PT_object_material(Panel):
precision = bpy.context.scene.DocProperties.imperial_precision precision = bpy.context.scene.DocProperties.imperial_precision
else: else:
precision = None precision = None
formatted_thickness = format_distance(total_thickness, precision=precision, suppress_zero_inches=True, in_unit_length = True) formatted_thickness = format_distance(
total_thickness, precision=precision, suppress_zero_inches=True, in_unit_length=True
)
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text=f"Total Thickness: {formatted_thickness}") row.label(text=f"Total Thickness: {formatted_thickness}")
@@ -149,7 +149,7 @@ class EditArray(bpy.types.Operator, tool.Ifc.Operator):
tool.Blender.Modifier.Array.set_children_lock_state(element, self.item, True) tool.Blender.Modifier.Array.set_children_lock_state(element, self.item, True)
tool.Blender.Modifier.Array.constrain_children_to_parent(element) tool.Blender.Modifier.Array.constrain_children_to_parent(element)
#clears the relating_array_object so it doesn't show again next time # clears the relating_array_object so it doesn't show again next time
props.relating_array_object = None props.relating_array_object = None
return {"FINISHED"} return {"FINISHED"}
@@ -285,8 +285,11 @@ class SelectAllArrayObjects(bpy.types.Operator):
array_objects = tool.Blender.Modifier.Array.get_all_objects(parent_element) array_objects = tool.Blender.Modifier.Array.get_all_objects(parent_element)
tool.Blender.set_objects_selection( tool.Blender.set_objects_selection(
context, active_object=array_objects[0], selected_objects=array_objects, clear_previous_selection=False context,
) active_object=array_objects[0],
selected_objects=array_objects,
clear_previous_selection=False,
)
return {"FINISHED"} return {"FINISHED"}
@@ -53,7 +53,7 @@ class AuthoringData:
cls.data["ifc_element_type"] = cls.ifc_element_type cls.data["ifc_element_type"] = cls.ifc_element_type
cls.data["ifc_classes"] = cls.ifc_classes() cls.data["ifc_classes"] = cls.ifc_classes()
cls.data["relating_type_id"] = cls.relating_type_id() # only after .ifc_classes() cls.data["relating_type_id"] = cls.relating_type_id() # only after .ifc_classes()
cls.data["predefined_type"] = cls.predefined_type() # only after .relating_type_id() cls.data["predefined_type"] = cls.predefined_type() # only after .relating_type_id()
cls.data["type_class"] = cls.type_class() cls.data["type_class"] = cls.type_class()
# only after .type_class() # only after .type_class()
@@ -541,7 +541,9 @@ class MEPGenerator:
ifc_representation_class=None, ifc_representation_class=None,
) )
rel = ifcopenshell.api.run("material.assign_material", ifc_file, products=[element], type="IfcMaterialProfileSet") rel = ifcopenshell.api.run(
"material.assign_material", ifc_file, products=[element], type="IfcMaterialProfileSet"
)
profile_set = rel.RelatingMaterial profile_set = rel.RelatingMaterial
material_profile = ifcopenshell.api.run( material_profile = ifcopenshell.api.run(
"material.add_profile", ifc_file, profile_set=profile_set, material=material "material.add_profile", ifc_file, profile_set=profile_set, material=material
@@ -99,9 +99,6 @@ def is_object_array_applicable(self, obj):
return ifcopenshell.util.element.get_pset(element, "BBIM_Array") return ifcopenshell.util.element.get_pset(element, "BBIM_Array")
class BIMModelProperties(PropertyGroup): class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
relating_type_id: bpy.props.EnumProperty( relating_type_id: bpy.props.EnumProperty(
@@ -226,8 +223,6 @@ class BIMArrayProperties(PropertyGroup):
) )
class BIMStairProperties(PropertyGroup): class BIMStairProperties(PropertyGroup):
def validate_nosing_value(self, context): def validate_nosing_value(self, context):
if self.stair_type != "WOOD/STEEL" and self.nosing_length < 0: if self.stair_type != "WOOD/STEEL" and self.nosing_length < 0:
@@ -61,10 +61,13 @@ class GenerateSpacesFromWalls(bpy.types.Operator, tool.Ifc.Operator):
def msg_no_active_object(self, context): def msg_no_active_object(self, context):
self.layout.label(text="No active object. Please select a wall") self.layout.label(text="No active object. Please select a wall")
def msg_no_active_wall(self, context): def msg_no_active_wall(self, context):
self.layout.label(text="The active object is not a wall. Please select a wall.") self.layout.label(text="The active object is not a wall. Please select a wall.")
def msg_no_container(self, context): def msg_no_container(self, context):
self.layout.label(text="The wall is not contained. Please the selected wall in a building container") self.layout.label(text="The wall is not contained. Please the selected wall in a building container")
def msg_no_selected_objects(self, context): def msg_no_selected_objects(self, context):
self.layout.label(text="No selected objects found. Please select walls.") self.layout.label(text="No selected objects found. Please select walls.")
@@ -147,6 +147,7 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator):
"edges": output_node.inputs["Edges"].sv_get(deepcopy=False, default=[]), "edges": output_node.inputs["Edges"].sv_get(deepcopy=False, default=[]),
"polygons": output_node.inputs["Polygons"].sv_get(deepcopy=False, default=[]), "polygons": output_node.inputs["Polygons"].sv_get(deepcopy=False, default=[]),
} }
# sv_get returns array of 1 element arrays, for convenience we reduce it to just 1 level array # sv_get returns array of 1 element arrays, for convenience we reduce it to just 1 level array
def try_first_element(x): def try_first_element(x):
return x[0] if x else x return x[0] if x else x
@@ -79,7 +79,11 @@ def get_actor_type_enum(self, context):
return [ return [
("IfcPerson", "Person", get_entity_doc(version, "IfcPerson").get("description", "")), ("IfcPerson", "Person", get_entity_doc(version, "IfcPerson").get("description", "")),
("IfcOrganization", "Organisation", get_entity_doc(version, "IfcOrganization").get("description", "")), ("IfcOrganization", "Organisation", get_entity_doc(version, "IfcOrganization").get("description", "")),
("IfcPersonAndOrganization", "User", get_entity_doc(version, "IfcPersonAndOrganization").get("description", "")), (
"IfcPersonAndOrganization",
"User",
get_entity_doc(version, "IfcPersonAndOrganization").get("description", ""),
),
] ]
@@ -127,7 +127,9 @@ class CreateProject(bpy.types.Operator):
bpy.data.meshes.remove(mesh) bpy.data.meshes.remove(mesh)
for mat in bpy.data.materials: for mat in bpy.data.materials:
bpy.data.materials.remove(mat) bpy.data.materials.remove(mat)
core.create_project(tool.Ifc, tool.Georeference, tool.Project, tool.Spatial, schema=props.export_schema, template=template) core.create_project(
tool.Ifc, tool.Georeference, tool.Project, tool.Spatial, schema=props.export_schema, template=template
)
blenderbim.bim.schema.reload(tool.Ifc.get().schema_identifier) blenderbim.bim.schema.reload(tool.Ifc.get().schema_identifier)
tool.Blender.register_toolbar() tool.Blender.register_toolbar()
@@ -170,6 +170,7 @@ def get_group_qto_names(self, context):
qtonames[ifc_class] = blender_formatted_enum_from_psets(psets) qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
return qtonames[ifc_class] return qtonames[ifc_class]
def get_profile_pset_names(self, context): def get_profile_pset_names(self, context):
global psetnames global psetnames
pprops = context.scene.BIMProfileProperties pprops = context.scene.BIMProfileProperties
@@ -147,7 +147,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type, allow_remov
row.scale_y = 0.8 row.scale_y = 0.8
row.label(text=prop["Name"]) row.label(text=prop["Name"])
op = row.operator("bim.select_similar", text=str(prop["NominalValue"]), icon="NONE", emboss=False) op = row.operator("bim.select_similar", text=str(prop["NominalValue"]), icon="NONE", emboss=False)
op.key = pset['Name'] op.key = pset["Name"]
if not has_props_displayed: if not has_props_displayed:
row = box.row() row = box.row()
@@ -75,7 +75,9 @@ class PsetTemplatesData:
pset_dir = os.path.join(bpy.context.scene.BIMProperties.data_dir, "pset") pset_dir = os.path.join(bpy.context.scene.BIMProperties.data_dir, "pset")
files = os.listdir(pset_dir) files = os.listdir(pset_dir)
for f in files: for f in files:
results.append((os.path.join(pset_dir, f), os.path.splitext(os.path.basename(f))[0], "Global Pset Template")) results.append(
(os.path.join(pset_dir, f), os.path.splitext(os.path.basename(f))[0], "Global Pset Template")
)
pset_dir = tool.Ifc.resolve_uri(bpy.context.scene.BIMProperties.pset_dir) pset_dir = tool.Ifc.resolve_uri(bpy.context.scene.BIMProperties.pset_dir)
if os.path.isdir(pset_dir): if os.path.isdir(pset_dir):
@@ -350,9 +350,9 @@ class BIM_UL_resources(UIList):
"bim.contract_resource", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" "bim.contract_resource", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
).resource = item.ifc_definition_id ).resource = item.ifc_definition_id
else: else:
row.operator( row.operator("bim.expand_resource", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").resource = (
"bim.expand_resource", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" item.ifc_definition_id
).resource = item.ifc_definition_id )
else: else:
row.label(text="", icon="DOT") row.label(text="", icon="DOT")
row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]]) row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]])
@@ -201,7 +201,10 @@ class IfcClassData:
if element: if element:
if element.is_a("IfcOpeningElement") or element.is_a("IfcOpeningStandardCase"): if element.is_a("IfcOpeningElement") or element.is_a("IfcOpeningStandardCase"):
return False return False
if element.is_a() in ("IfcWindowStyle", "IfcDoorStyle"): #see https://github.com/IfcOpenShell/IfcOpenShell/issues/4622#issuecomment-2095676368 if element.is_a() in (
"IfcWindowStyle",
"IfcDoorStyle",
): # see https://github.com/IfcOpenShell/IfcOpenShell/issues/4622#issuecomment-2095676368
return True return True
for product in cls.ifc_products(): for product in cls.ifc_products():
if element.is_a(product[0]): if element.is_a(product[0]):
@@ -361,9 +361,7 @@ class SaveColourscheme(Operator, tool.Ifc.Operator):
description["colourscheme_query"] = query description["colourscheme_query"] = query
group.Description = json.dumps(description) group.Description = json.dumps(description)
else: else:
description = json.dumps( description = json.dumps({"type": "BBIM_Search", "colourscheme": colourscheme, "colourscheme_query": query})
{"type": "BBIM_Search", "colourscheme": colourscheme, "colourscheme_query": query}
)
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), name=self.name, description=description) group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), name=self.name, description=description)
def invoke(self, context, event): def invoke(self, context, event):
@@ -355,6 +355,7 @@ def update_task_bar_list(self, context):
else: else:
tool.Sequence.remove_task_bar(self.ifc_definition_id) tool.Sequence.remove_task_bar(self.ifc_definition_id)
class Task(PropertyGroup): class Task(PropertyGroup):
name: StringProperty(name="Name", update=updateTaskName) name: StringProperty(name="Name", update=updateTaskName)
identification: StringProperty(name="Identification", update=updateTaskIdentification) identification: StringProperty(name="Identification", update=updateTaskIdentification)
@@ -188,9 +188,9 @@ class BIM_PT_work_schedules(Panel):
row1.label(text="Schedule tools") row1.label(text="Schedule tools")
row1 = col.row(align=True) row1 = col.row(align=True)
row1.alignment = "RIGHT" row1.alignment = "RIGHT"
row1.operator( row1.operator("bim.generate_gantt_chart", text="Generate Gantt", icon="NLA").work_schedule = (
"bim.generate_gantt_chart", text="Generate Gantt", icon="NLA" work_schedule_id
).work_schedule = work_schedule_id )
row1.operator( row1.operator(
"bim.recalculate_schedule", text="Re-calculate Schedule", icon="FILE_REFRESH" "bim.recalculate_schedule", text="Re-calculate Schedule", icon="FILE_REFRESH"
).work_schedule = work_schedule_id ).work_schedule = work_schedule_id
@@ -226,9 +226,9 @@ class BIM_PT_work_schedules(Panel):
) )
col2 = grid.column() col2 = grid.column()
row = col2.row(align=True) row = col2.row(align=True)
row.operator( row.operator("bim.enable_editing_work_schedule_tasks", text="Tasks", icon="ACTION").work_schedule = (
"bim.enable_editing_work_schedule_tasks", text="Tasks", icon="ACTION" work_schedule_id
).work_schedule = work_schedule_id )
row.operator( row.operator(
"bim.enable_editing_work_schedule", text="Attributes", icon="GREASEPENCIL" "bim.enable_editing_work_schedule", text="Attributes", icon="GREASEPENCIL"
).work_schedule = work_schedule_id ).work_schedule = work_schedule_id
@@ -266,12 +266,12 @@ class BIM_PT_work_schedules(Panel):
row2.prop(self.props, "enable_reorder", text="", icon="SORTALPHA") row2.prop(self.props, "enable_reorder", text="", icon="SORTALPHA")
row2.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING") row2.operator("bim.enable_editing_task_sequence", text="", icon="TRACKING")
row2.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id row2.operator("bim.enable_editing_task_time", text="", icon="TIME").task = ifc_definition_id
row2.operator( row2.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = (
"bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO" ifc_definition_id
).task = ifc_definition_id )
row2.operator( row2.operator("bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL").task = (
"bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL" ifc_definition_id
).task = ifc_definition_id )
row.operator("bim.add_task", text="Add", icon="ADD").task = ifc_definition_id row.operator("bim.add_task", text="Add", icon="ADD").task = ifc_definition_id
row.operator("bim.duplicate_task", text="Copy", icon="DUPLICATE").task = ifc_definition_id row.operator("bim.duplicate_task", text="Copy", icon="DUPLICATE").task = ifc_definition_id
row.operator("bim.remove_task", text="Delete", icon="X").task = ifc_definition_id row.operator("bim.remove_task", text="Delete", icon="X").task = ifc_definition_id
@@ -876,13 +876,13 @@ class BIM_UL_tasks(UIList):
row.label(text="", icon="BLANK1") row.label(text="", icon="BLANK1")
if item.has_children: if item.has_children:
if item.is_expanded: if item.is_expanded:
row.operator( row.operator("bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").task = (
"bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN" item.ifc_definition_id
).task = item.ifc_definition_id )
else: else:
row.operator( row.operator("bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").task = (
"bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT" item.ifc_definition_id
).task = item.ifc_definition_id )
else: else:
row.label(text="", icon="DOT") row.label(text="", icon="DOT")
@@ -59,7 +59,9 @@ def register():
bpy.utils.register_tool(workspace.SpatialTool, after={"bim.annotation_tool"}, separator=False, group=False) bpy.utils.register_tool(workspace.SpatialTool, after={"bim.annotation_tool"}, separator=False, group=False)
bpy.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties) bpy.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties)
bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties) bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
bpy.types.Scene.BIMSpatialDecompositionProperties = bpy.props.PointerProperty(type=prop.BIMSpatialDecompositionProperties) bpy.types.Scene.BIMSpatialDecompositionProperties = bpy.props.PointerProperty(
type=prop.BIMSpatialDecompositionProperties
)
def unregister(): def unregister():
@@ -109,7 +109,7 @@ class BIM_PT_spatial_decomposition(Panel):
SpatialDecompositionData.load() SpatialDecompositionData.load()
self.props = context.scene.BIMSpatialDecompositionProperties self.props = context.scene.BIMSpatialDecompositionProperties
if SpatialDecompositionData.data['default_container']: if SpatialDecompositionData.data["default_container"]:
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label( row.label(
text=f"Default: {SpatialDecompositionData.data['default_container']}", text=f"Default: {SpatialDecompositionData.data['default_container']}",
@@ -226,7 +226,7 @@ class StructuralLoadsData:
cls.data = { cls.data = {
"total_loads": cls.total_loads(), "total_loads": cls.total_loads(),
"load_classes": cls.load_classes(), "load_classes": cls.load_classes(),
"structural_load_types": cls.structural_load_types() "structural_load_types": cls.structural_load_types(),
} }
cls.is_loaded = True cls.is_loaded = True
@@ -42,9 +42,9 @@ def get_applicable_structural_load_types(self, context):
def updateApplicableStructuralLoadTypes(self, context): def updateApplicableStructuralLoadTypes(self, context):
StructuralLoadCasesData.data[ StructuralLoadCasesData.data["applicable_structural_load_types"] = (
"applicable_structural_load_types" StructuralLoadCasesData.applicable_structural_load_types()
] = StructuralLoadCasesData.applicable_structural_load_types() )
def get_applicable_structural_loads(self, context): def get_applicable_structural_loads(self, context):
@@ -388,9 +388,9 @@ class BIM_PT_structural_load_cases(Panel):
elif self.props.active_load_case_id: elif self.props.active_load_case_id:
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case["id"] row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case["id"]
else: else:
row.operator( row.operator("bim.enable_editing_structural_load_case_groups", text="", icon="GHOST_ENABLED").load_case = (
"bim.enable_editing_structural_load_case_groups", text="", icon="GHOST_ENABLED" load_case["id"]
).load_case = load_case["id"] )
row.operator("bim.enable_editing_structural_load_case", text="", icon="GREASEPENCIL").load_case = load_case[ row.operator("bim.enable_editing_structural_load_case", text="", icon="GREASEPENCIL").load_case = load_case[
"id" "id"
] ]
@@ -547,9 +547,9 @@ class BIM_PT_boundary_conditions(Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
prop_with_search(row, self.props, "boundary_condition_types", text="") prop_with_search(row, self.props, "boundary_condition_types", text="")
row.operator( row.operator("bim.add_boundary_condition", text="", icon="ADD").ifc_class = (
"bim.add_boundary_condition", text="", icon="ADD" self.props.boundary_condition_types
).ifc_class = self.props.boundary_condition_types )
else: else:
row.operator("bim.load_boundary_conditions", text="", icon="GREASEPENCIL") row.operator("bim.load_boundary_conditions", text="", icon="GREASEPENCIL")
@@ -191,9 +191,9 @@ class BIM_PT_ports(Panel):
if connected_obj_name: if connected_obj_name:
connected_obj = bpy.data.objects[connected_obj_name] connected_obj = bpy.data.objects[connected_obj_name]
cols[3].operator("bim.disconnect_port", text="", icon="UNLINKED").element_id = port.id() cols[3].operator("bim.disconnect_port", text="", icon="UNLINKED").element_id = port.id()
cols[4].operator( cols[4].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF" connected_obj.BIMObjectProperties.ifc_definition_id
).ifc_id = connected_obj.BIMObjectProperties.ifc_definition_id )
cols[5].label(text=connected_obj_name) cols[5].label(text=connected_obj_name)
else: else:
cols[3].label(text="", icon="UNLINKED") cols[3].label(text="", icon="UNLINKED")
@@ -248,9 +248,9 @@ class BIM_PT_port(Panel):
relating_object = bpy.data.objects[relating_object_name] relating_object = bpy.data.objects[relating_object_name]
row.label(text="Port located on:") row.label(text="Port located on:")
row.label(text=relating_object_name) row.label(text=relating_object_name)
row.operator( row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF" relating_object.BIMObjectProperties.ifc_definition_id
).ifc_id = relating_object.BIMObjectProperties.ifc_definition_id )
# object connected to the port # object connected to the port
row = layout.row(align=True) row = layout.row(align=True)
@@ -259,9 +259,9 @@ class BIM_PT_port(Panel):
connected_object = bpy.data.objects[connected_object_name] connected_object = bpy.data.objects[connected_object_name]
row.label(text="Port connected to:") row.label(text="Port connected to:")
row.label(text=connected_object_name) row.label(text=connected_object_name)
row.operator( row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF" connected_object.BIMObjectProperties.ifc_definition_id
).ifc_id = connected_object.BIMObjectProperties.ifc_definition_id )
else: else:
row.label(text="Port is not connected to any element") row.label(text="Port is not connected to any element")
@@ -308,9 +308,9 @@ class BIM_PT_flow_controls(Panel):
op.flow_control = control_id op.flow_control = control_id
op.flow_element = flow_element_id op.flow_element = flow_element_id
op.assign = False op.assign = False
row.operator( row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF" displayed_object.BIMObjectProperties.ifc_definition_id
).ifc_id = displayed_object.BIMObjectProperties.ifc_definition_id )
row.label(text=f"{displayed_object_name}") row.label(text=f"{displayed_object_name}")
element = tool.Ifc.get_entity(context.active_object) element = tool.Ifc.get_entity(context.active_object)
@@ -32,7 +32,7 @@ classes = (
prop.IfcTesterProperties, prop.IfcTesterProperties,
ui.BIM_PT_tester, ui.BIM_PT_tester,
ui.BIM_UL_tester_specifications, ui.BIM_UL_tester_specifications,
ui.BIM_UL_tester_failed_entities ui.BIM_UL_tester_failed_entities,
) )
@@ -42,4 +42,3 @@ def register():
def unregister(): def unregister():
del bpy.types.Scene.IfcTesterProperties del bpy.types.Scene.IfcTesterProperties
@@ -98,7 +98,7 @@ class BIM_PT_tester(Panel):
row = box.row(align=True) row = box.row(align=True)
row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL") row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL")
if not requirement["status"]: if not requirement["status"]:
op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY") op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY")
op2 = row.operator("bim.select_failed_entities", text="", icon="RESTRICT_SELECT_OFF") op2 = row.operator("bim.select_failed_entities", text="", icon="RESTRICT_SELECT_OFF")
op.spec_index = props.active_specification_index op.spec_index = props.active_specification_index
op.req_index = i op.req_index = i
@@ -88,7 +88,7 @@ class BIM_PT_type(Panel):
if TypeData.data["relating_type"]: if TypeData.data["relating_type"]:
row.label(text=TypeData.data["relating_type"]["name"]) row.label(text=TypeData.data["relating_type"]["name"])
op = row.operator("bim.select_type", icon="OBJECT_DATA", text="") op = row.operator("bim.select_type", icon="OBJECT_DATA", text="")
op.relating_type = 0 #will only select the relating types of only the selected objects op.relating_type = 0 # will only select the relating types of only the selected objects
row.operator("bim.select_similar_type", icon="RESTRICT_SELECT_OFF", text="") row.operator("bim.select_similar_type", icon="RESTRICT_SELECT_OFF", text="")
row.operator("bim.enable_editing_type", icon="GREASEPENCIL", text="") row.operator("bim.enable_editing_type", icon="GREASEPENCIL", text="")
row.operator("bim.unassign_type", icon="X", text="") row.operator("bim.unassign_type", icon="X", text="")
+2 -1
View File
@@ -141,6 +141,7 @@ class SelectURIAttribute(bpy.types.Operator):
context.window_manager.fileselect_add(self) context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"} return {"RUNNING_MODAL"}
class MultipleFileSelector(bpy.types.Operator): class MultipleFileSelector(bpy.types.Operator):
bl_label = "Select Multiple Files" bl_label = "Select Multiple Files"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
@@ -156,11 +157,11 @@ class MultipleFileSelector(bpy.types.Operator):
new.name = os.path.join(dirname, f.name) new.name = os.path.join(dirname, f.name)
setattr(props, single_file, self.filepath) setattr(props, single_file, self.filepath)
def invoke(self, context, event): def invoke(self, context, event):
context.window_manager.fileselect_add(self) context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"} return {"RUNNING_MODAL"}
class SelectIfcFile(bpy.types.Operator, IFCFileSelector): class SelectIfcFile(bpy.types.Operator, IFCFileSelector):
bl_idname = "bim.select_ifc_file" bl_idname = "bim.select_ifc_file"
bl_label = "Select IFC File" bl_label = "Select IFC File"
+1 -3
View File
@@ -45,9 +45,7 @@ def assign_object(
relating_object = ifc.get_entity(relating_obj) relating_object = ifc.get_entity(relating_obj)
if aggregator.has_physical_body_representation(relating_object): if aggregator.has_physical_body_representation(relating_object):
raise AggregateRepresentationError raise AggregateRepresentationError
rel = ifc.run( rel = ifc.run("aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=relating_object)
"aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=relating_object
)
collector.assign(relating_obj) collector.assign(relating_obj)
collector.assign(related_obj) collector.assign(related_obj)
aggregator.disable_editing(related_obj) aggregator.disable_editing(related_obj)
+5 -1
View File
@@ -133,7 +133,11 @@ def convert_ifc_to_brick(brick, namespace=None, library=None):
for element in distribution_elements: for element in distribution_elements:
feeds = brick.get_element_feeds(element) feeds = brick.get_element_feeds(element)
for downstream_equipment in feeds: for downstream_equipment in feeds:
brick.add_relation(equipment_uris[element], "https://brickschema.org/schema/Brick#feeds", equipment_uris[downstream_equipment]) brick.add_relation(
equipment_uris[element],
"https://brickschema.org/schema/Brick#feeds",
equipment_uris[downstream_equipment],
)
brick.run_refresh_brick_viewer() brick.run_refresh_brick_viewer()
+1
View File
@@ -40,6 +40,7 @@
# described in regular sentences in under 50 lines. That is the purpose of the # described in regular sentences in under 50 lines. That is the purpose of the
# core. # core.
# Here's the simplest possible core function. It does one thing only. Remember: # Here's the simplest possible core function. It does one thing only. Remember:
# core functions delegate tasks to tools, so all core functions need at least # core functions delegate tasks to tools, so all core functions need at least
# one tool. # one tool.
+8 -1
View File
@@ -25,7 +25,14 @@ if TYPE_CHECKING:
import blenderbim.tool as tool import blenderbim.tool as tool
def create_project(ifc: tool.Ifc, georeference: tool.Georeference, project: tool.Project, spatial: tool.Spatial, schema: str, template: Optional[str] = None) -> None: def create_project(
ifc: tool.Ifc,
georeference: tool.Georeference,
project: tool.Project,
spatial: tool.Spatial,
schema: str,
template: Optional[str] = None,
) -> None:
if ifc.get(): if ifc.get():
return return
+4 -3
View File
@@ -149,7 +149,10 @@ class Brick(blenderbim.core.tool.Brick):
<{brick_uri}> rdfs:label ?label . <{brick_uri}> rdfs:label ?label .
} }
LIMIT 1 LIMIT 1
""".replace("{brick_uri}", brick_uri)) """.replace(
"{brick_uri}", brick_uri
)
)
name = None name = None
for row in query: for row in query:
name = str(row.get("label")) name = str(row.get("label"))
@@ -442,8 +445,6 @@ class Brick(blenderbim.core.tool.Brick):
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear() bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
class BrickStore: class BrickStore:
schema = None # this is now a os path schema = None # this is now a os path
path = None # file path if the project was loaded in path = None # file path if the project was loaded in
@@ -30,12 +30,14 @@ from math import pi
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from shapely import Polygon, MultiPolygon from shapely import Polygon, MultiPolygon
class Covering(blenderbim.core.tool.Covering): class Covering(blenderbim.core.tool.Covering):
@classmethod @classmethod
def get_z_from_ceiling_height(cls): def get_z_from_ceiling_height(cls):
props = bpy.context.scene.BIMCoveringProperties props = bpy.context.scene.BIMCoveringProperties
return props.ceiling_height return props.ceiling_height
# def toggle_spaces_visibility_wired_and_textured(cls, spaces): # def toggle_spaces_visibility_wired_and_textured(cls, spaces):
# first_obj = tool.Ifc.get_object(spaces[0]) # first_obj = tool.Ifc.get_object(spaces[0])
# if bpy.data.objects[first_obj.name].display_type == "TEXTURED": # if bpy.data.objects[first_obj.name].display_type == "TEXTURED":
+1
View File
@@ -13,6 +13,7 @@ try:
except ImportError: except ImportError:
print("Warning: GitPython not available.") print("Warning: GitPython not available.")
class IfcGit: class IfcGit:
@classmethod @classmethod
def init_repo(cls, path_dir): def init_repo(cls, path_dir):
+1
View File
@@ -28,6 +28,7 @@ from typing import Optional, Union, Literal
QuantityTypes = Literal["Q_LENGTH", "Q_AREA", "Q_VOLUME"] QuantityTypes = Literal["Q_LENGTH", "Q_AREA", "Q_VOLUME"]
class Qto(blenderbim.core.tool.Qto): class Qto(blenderbim.core.tool.Qto):
@classmethod @classmethod
def get_radius_of_selected_vertices(cls, obj: bpy.types.Object) -> float: def get_radius_of_selected_vertices(cls, obj: bpy.types.Object) -> float:
+3 -3
View File
@@ -29,6 +29,7 @@
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
import os import os
# import sys # import sys
# sys.path.insert(0, os.path.abspath('.')) # sys.path.insert(0, os.path.abspath('.'))
@@ -103,7 +104,7 @@ html_theme_options = {
"color-link--hover": "#d98014", "color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014", "color-link--visited--hover": "#d98014",
"color-admonition-text": "#651fff", "color-admonition-text": "#651fff",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji" "font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji",
}, },
"dark_css_variables": { "dark_css_variables": {
"color-brand-primary": "#39b54a", "color-brand-primary": "#39b54a",
@@ -118,9 +119,8 @@ html_theme_options = {
"color-link--hover": "#d98014", "color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014", "color-link--visited--hover": "#d98014",
"color-admonition-text": "#EEEEEC", "color-admonition-text": "#EEEEEC",
"font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji" "font-stack": "Nunito, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji",
}, },
"footer_icons": [ "footer_icons": [
{ {
"name": "IfcOpenShell", "name": "IfcOpenShell",
@@ -1,5 +1,6 @@
try: try:
import bpy import bpy
# Ensure it's not fake-bpy-module. # Ensure it's not fake-bpy-module.
if not hasattr(bpy, "context"): if not hasattr(bpy, "context"):
raise ModuleNotFoundError raise ModuleNotFoundError
@@ -1,22 +1,26 @@
import ifcopenshell import ifcopenshell
from brickschema.graph import Graph from brickschema.graph import Graph
class Generator():
class Generator:
def __init__(self): def __init__(self):
self.file = ifcopenshell.file(schema='IFC4') self.file = ifcopenshell.file(schema="IFC4")
self.schema = Graph() self.schema = Graph()
self.schema.load_file("Brick.ttl") # stable 1.3 loaded from external file self.schema.load_file("Brick.ttl") # stable 1.3 loaded from external file
def generate(self): def generate(self):
classification = self.file.create_entity('IfcClassification', **{ classification = self.file.create_entity(
'Source': 'Brick', "IfcClassification",
'Edition': 'August-11', **{
'EditionDate': '2023-08-11', "Source": "Brick",
'Name': 'Brick', "Edition": "August-11",
'Description': '', "EditionDate": "2023-08-11",
'Location': 'https://brickschema.org/schema/Brick', "Name": "Brick",
'ReferenceTokens': [] "Description": "",
}) "Location": "https://brickschema.org/schema/Brick",
"ReferenceTokens": [],
}
)
query = self.schema.query( query = self.schema.query(
""" """
@@ -58,7 +62,7 @@ class Generator():
# description is the entity's definition # description is the entity's definition
description = row.get("definition") description = row.get("definition")
if not description: if not description:
description = '' description = ""
# name is the entity's label if it exists, else the name in the URI # name is the entity's label if it exists, else the name in the URI
name = row.get("label") name = row.get("label")
@@ -66,12 +70,10 @@ class Generator():
name = location.split("#")[-1].replace("_", " ") name = location.split("#")[-1].replace("_", " ")
# create the reference # create the reference
ref = self.file.create_entity('IfcClassificationReference', **{ ref = self.file.create_entity(
'Location': location, "IfcClassificationReference",
'Description': description, **{"Location": location, "Description": description, "Identification": name, "Name": name}
'Identification': name, )
'Name': name
})
# get all parents of the entity # get all parents of the entity
query = self.schema.query( query = self.schema.query(
@@ -105,7 +107,8 @@ class Generator():
# save this reference for future reference sources # save this reference for future reference sources
references[location.toPython()] = ref references[location.toPython()] = ref
self.file.write('Brick.ifc') self.file.write("Brick.ifc")
generator = Generator() generator = Generator()
generator.generate() generator.generate()
+28 -23
View File
@@ -1,30 +1,35 @@
import csv import csv
import os import os
import json import json
#import pystache
# import pystache
import subprocess import subprocess
import ifcopenshell import ifcopenshell
from pathlib import Path from pathlib import Path
class Generator():
class Generator:
def __init__(self): def __init__(self):
self.file = ifcopenshell.file(schema='IFC4') self.file = ifcopenshell.file(schema="IFC4")
self.out_dir = './' self.out_dir = "./"
def generate(self): def generate(self):
classification = self.file.create_entity('IfcClassification', **{ classification = self.file.create_entity(
'Source': 'VBIS', "IfcClassification",
'Edition': 'May-20', **{
'EditionDate': '2020-05-01', "Source": "VBIS",
'Name': 'VBIS', "Edition": "May-20",
'Description': '', "EditionDate": "2020-05-01",
'Location': 'https://vbis.com.au/', "Name": "VBIS",
'ReferenceTokens': ['-'] "Description": "",
}) "Location": "https://vbis.com.au/",
"ReferenceTokens": ["-"],
}
)
# We assume all the Excel spreadsheets are re-exported in CSV format # We assume all the Excel spreadsheets are re-exported in CSV format
for filename in Path('./').glob('*.csv'): for filename in Path("./").glob("*.csv"):
with open(filename, newline='') as csvfile: with open(filename, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=',', quotechar='"') reader = csv.reader(csvfile, delimiter=",", quotechar='"')
name = None name = None
levels = [None, None, None, None] levels = [None, None, None, None]
ref = classification ref = classification
@@ -39,17 +44,17 @@ class Generator():
name = row[2] name = row[2]
elif row[3]: elif row[3]:
name = row[3] name = row[3]
ref = self.file.create_entity('IfcClassificationReference', **{ ref = self.file.create_entity(
'Identification': row[4], "IfcClassificationReference", **{"Identification": row[4], "Name": name}
'Name': name )
}) cur_level = len(row[4].split("-")) - 1
cur_level = len(row[4].split('-')) - 1
levels[cur_level] = ref levels[cur_level] = ref
if cur_level == 0: if cur_level == 0:
ref.ReferencedSource = classification ref.ReferencedSource = classification
else: else:
ref.ReferencedSource = levels[cur_level-1] ref.ReferencedSource = levels[cur_level - 1]
self.file.write('VBIS.ifc') self.file.write("VBIS.ifc")
generator = Generator() generator = Generator()
generator.generate() generator.generate()
@@ -7,86 +7,92 @@ import ifcopenshell
import ifcopenshell.guid import ifcopenshell.guid
import os import os
class IFC4Extractor: class IFC4Extractor:
def __init__(self, xml_file): def __init__(self, xml_file):
self.xml_file = xml_file self.xml_file = xml_file
self.tree = ET.parse(self.xml_file) self.tree = ET.parse(self.xml_file)
self.root = self.tree.getroot() self.root = self.tree.getroot()
self.ns = {'xs': 'http://www.w3.org/2001/XMLSchema'} self.ns = {"xs": "http://www.w3.org/2001/XMLSchema"}
self.file = ifcopenshell.file() self.file = ifcopenshell.file()
self.data = { self.data = {
'BB/SfB (3/4 cijfers)': {'source': 'Regie der Gebouwen', 'tokens': ['.']}, "BB/SfB (3/4 cijfers)": {"source": "Regie der Gebouwen", "tokens": ["."]},
'BIMTypeCode': {'source': 'BIMStockholm', 'tokens': None}, "BIMTypeCode": {"source": "BIMStockholm", "tokens": None},
'Common Arrangement of Work Sections (CAWS)': {'source': 'NBS', 'tokens': ['/']}, "Common Arrangement of Work Sections (CAWS)": {"source": "NBS", "tokens": ["/"]},
'CBI Classification - Level 2': {'source': 'Masterspec', 'tokens': None}, "CBI Classification - Level 2": {"source": "Masterspec", "tokens": None},
'CBI Classification - Level 4': {'source': 'Masterspec', 'tokens': None}, "CBI Classification - Level 4": {"source": "Masterspec", "tokens": None},
'Rumsfunktionskoder CC001 - 001': {'source': 'BIMAlliance', 'tokens': ['-']}, "Rumsfunktionskoder CC001 - 001": {"source": "BIMAlliance", "tokens": ["-"]},
'CCS': {'source': 'Molio', 'tokens': None}, "CCS": {"source": "Molio", "tokens": None},
'CCTB': {'source': 'CCT-Bâtiments', 'tokens': ['.']}, "CCTB": {"source": "CCT-Bâtiments", "tokens": ["."]},
'Funktionskoder Regionservice CD001 - 001': {'source': 'BIMAlliance', 'tokens': None}, "Funktionskoder Regionservice CD001 - 001": {"source": "BIMAlliance", "tokens": None},
'Rumsfunktion Blekinge CD002 - 001': {'source': 'BIMAlliance', 'tokens': None}, "Rumsfunktion Blekinge CD002 - 001": {"source": "BIMAlliance", "tokens": None},
'EcoQuaestor Codetabel': {'source': 'EcoQuaestor', 'tokens': ['.', '-']}, "EcoQuaestor Codetabel": {"source": "EcoQuaestor", "tokens": [".", "-"]},
'GuBIMclass CA': {'source': 'GuBIMClass', 'tokens': ['.']}, "GuBIMclass CA": {"source": "GuBIMClass", "tokens": ["."]},
'GuBIMclass ES': {'source': 'GuBIMClass', 'tokens': ['.']}, "GuBIMclass ES": {"source": "GuBIMClass", "tokens": ["."]},
'MasterFormat': {'source': 'CSI', 'tokens': [' ', '.']}, "MasterFormat": {"source": "CSI", "tokens": [" ", "."]},
'NATSPEC Worksections': {'source': 'NATSPEC', 'tokens': None}, "NATSPEC Worksections": {"source": "NATSPEC", "tokens": None},
'NBS Create': {'source': 'NBS', 'tokens': ['_', '/']}, "NBS Create": {"source": "NBS", "tokens": ["_", "/"]},
'NL/SfB (4 cijfers)': {'source': 'BIMLoket', 'tokens': ['.']}, "NL/SfB (4 cijfers)": {"source": "BIMLoket", "tokens": ["."]},
'NS 3451 - Bygningsdelstabell': {'source': 'Standard Norge', 'tokens': None}, "NS 3451 - Bygningsdelstabell": {"source": "Standard Norge", "tokens": None},
'OmniClass': {'source': 'OmniClass', 'tokens': ['-', ' ']}, "OmniClass": {"source": "OmniClass", "tokens": ["-", " "]},
'ÖNORM 6241-2': {'source': 'freeBIM 2', 'tokens': None}, "ÖNORM 6241-2": {"source": "freeBIM 2", "tokens": None},
'RICS NRM1': {'source': 'RICS', 'tokens': ['.']}, "RICS NRM1": {"source": "RICS", "tokens": ["."]},
'RICS NRM3': {'source': 'RICS', 'tokens': ['.']}, "RICS NRM3": {"source": "RICS", "tokens": ["."]},
'SFG20': {'source': 'SFG20', 'tokens': ['-']}, "SFG20": {"source": "SFG20", "tokens": ["-"]},
'SINAPI': {'source': 'Caixa', 'tokens': ['/']}, "SINAPI": {"source": "Caixa", "tokens": ["/"]},
'STABU-Element': {'source': 'STABU', 'tokens': ['.']}, "STABU-Element": {"source": "STABU", "tokens": ["."]},
'TALO 2000 Building Component Classification': {'source': 'Rakennustieto', 'tokens': ['.']}, "TALO 2000 Building Component Classification": {"source": "Rakennustieto", "tokens": ["."]},
'TALO 2000 Hankenimikkeistö': {'source': 'Rakennustieto', 'tokens': ['.']}, "TALO 2000 Hankenimikkeistö": {"source": "Rakennustieto", "tokens": ["."]},
'Uniclass': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']}, "Uniclass": {"source": "RIBA Enterprises Ltd", "tokens": ["_"]},
'Uniclass 2015': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']}, "Uniclass 2015": {"source": "RIBA Enterprises Ltd", "tokens": ["_"]},
'UniFormat': {'source': 'UniFormat', 'tokens': ['.']}, "UniFormat": {"source": "UniFormat", "tokens": ["."]},
'Uniformat': {'source': 'UniFormat', 'tokens': ['.']}, "Uniformat": {"source": "UniFormat", "tokens": ["."]},
'VMSW': {'source': 'VMSW', 'tokens': ['.']} "VMSW": {"source": "VMSW", "tokens": ["."]},
} }
def extract(self): def extract(self):
for system in self.tree.findall('Classification/System'): for system in self.tree.findall("Classification/System"):
project = self.file.create_entity('IfcProjectLibrary', Name=system.find('Name').text) project = self.file.create_entity("IfcProjectLibrary", Name=system.find("Name").text)
parent = self.file.create_entity('IfcClassification', **{ parent = self.file.create_entity(
'Source': self.data[system.find('Name').text]['source'], "IfcClassification",
'Edition': system.find('EditionVersion').text, **{
'EditionDate': self.get_edition_date(system), "Source": self.data[system.find("Name").text]["source"],
'Name': system.find('Name').text, "Edition": system.find("EditionVersion").text,
'Description': system.find('Description').text, "EditionDate": self.get_edition_date(system),
'Location': system.find('Source').text, "Name": system.find("Name").text,
'ReferenceTokens': self.data[system.find('Name').text]['tokens'] "Description": system.find("Description").text,
}) "Location": system.find("Source").text,
self.file.createIfcRelAssociatesClassification( "ReferenceTokens": self.data[system.find("Name").text]["tokens"],
ifcopenshell.guid.new(), None, None, None, [project], parent) },
children = system.findall('Items/Item') )
self.file.createIfcRelAssociatesClassification(ifcopenshell.guid.new(), None, None, None, [project], parent)
children = system.findall("Items/Item")
self.get_children(children, parent) self.get_children(children, parent)
def get_children(self, children, parent): def get_children(self, children, parent):
for child in children: for child in children:
reference = self.file.create_entity('IfcClassificationReference', **{ reference = self.file.create_entity(
'Identification': child.find('ID').text, "IfcClassificationReference",
'Name': child.find('Name').text, **{
'ReferencedSource': parent, "Identification": child.find("ID").text,
'Description': child.find('Description').text "Name": child.find("Name").text,
}) "ReferencedSource": parent,
children = child.find('Children') "Description": child.find("Description").text,
},
)
children = child.find("Children")
if children: if children:
self.get_children(children, reference) self.get_children(children, reference)
def get_edition_date(self, system): def get_edition_date(self, system):
d = system.find('EditionDate') d = system.find("EditionDate")
return '{}-{:02}-{:02}'.format( return "{}-{:02}-{:02}".format(d.find("Year").text, int(d.find("Month").text), int(d.find("Day").text))
d.find('Year').text, int(d.find('Month').text), int(d.find('Day').text))
def export(self, filename): def export(self, filename):
self.file.write(filename) self.file.write(filename)
for filename in os.listdir('xml/'):
extractor = IFC4Extractor(f'xml/{filename}') for filename in os.listdir("xml/"):
extractor = IFC4Extractor(f"xml/{filename}")
extractor.extract() extractor.extract()
extractor.export(f'ifc/{filename[0:-3]}ifc') extractor.export(f"ifc/{filename[0:-3]}ifc")
+28 -10
View File
@@ -155,10 +155,16 @@ class LibraryGenerator:
self.create_line_type("MEDIUM", "medium") self.create_line_type("MEDIUM", "medium")
self.create_line_type("THICK", "thick") self.create_line_type("THICK", "thick")
self.create_line_type("STRONG", "strong") self.create_line_type("STRONG", "strong")
self.create_text_type("SETOUT-TAG", "setout-tag", ["E ``round({{easting}}, 0.001)``", "N ``round({{northing}}, 0.001)``"]) self.create_text_type(
"SETOUT-TAG", "setout-tag", ["E ``round({{easting}}, 0.001)``", "N ``round({{northing}}, 0.001)``"]
)
self.create_text_type("DOOR-TAG", "door-tag", ["{{type.Name}}", "{{Name}}"]) self.create_text_type("DOOR-TAG", "door-tag", ["{{type.Name}}", "{{Name}}"])
self.create_text_type("WINDOW-TAG", "window-tag", ["{{Name}}"]) self.create_text_type("WINDOW-TAG", "window-tag", ["{{Name}}"])
self.create_text_type("SPACE-TAG", "space-tag", ["{{Name}}", "{{Description}}", "``round({{Qto_SpaceBaseQuantities.NetFloorArea}}, 0.01)``"]) self.create_text_type(
"SPACE-TAG",
"space-tag",
["{{Name}}", "{{Description}}", "``round({{Qto_SpaceBaseQuantities.NetFloorArea}}, 0.01)``"],
)
self.create_text_type("MATERIAL-TAG", "rectangle-tag", ["{{material.Name}}"]) self.create_text_type("MATERIAL-TAG", "rectangle-tag", ["{{material.Name}}"])
self.create_text_type("TYPE-TAG", "capsule-tag", ["{{type.Name}}"]) self.create_text_type("TYPE-TAG", "capsule-tag", ["{{type.Name}}"])
self.create_text_type("NAME-TAG", "capsule-tag", ["{{Name}}"]) self.create_text_type("NAME-TAG", "capsule-tag", ["{{Name}}"])
@@ -189,9 +195,11 @@ class LibraryGenerator:
self.file.createIfcDirection((0.0, 0.0, 1.0)), self.file.createIfcDirection((0.0, 0.0, 1.0)),
self.file.createIfcDirection((1.0, 0.0, 0.0)), self.file.createIfcDirection((1.0, 0.0, 0.0)),
) )
items.append(self.file.createIfcTextLiteralWithExtent( items.append(
literal, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), "center" self.file.createIfcTextLiteralWithExtent(
)) literal, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), "center"
)
)
representation = self.file.createIfcShapeRepresentation( representation = self.file.createIfcShapeRepresentation(
self.representations["model_annotation"], self.representations["model_annotation"],
@@ -205,22 +213,30 @@ class LibraryGenerator:
def create_layer_type(self, ifc_class, name, thickness): def create_layer_type(self, ifc_class, name, thickness):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") rel = ifcopenshell.api.run(
"material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet"
)
layer_set = rel.RelatingMaterial layer_set = rel.RelatingMaterial
layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.material) layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.material)
layer.LayerThickness = thickness layer.LayerThickness = thickness
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
return element return element
def create_profile_type(self, ifc_class, name, profile): def create_profile_type(self, ifc_class, name, profile):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") rel = ifcopenshell.api.run(
"material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet"
)
profile_set = rel.RelatingMaterial profile_set = rel.RelatingMaterial
material_profile = ifcopenshell.api.run( material_profile = ifcopenshell.api.run(
"material.add_profile", self.file, profile_set=profile_set, material=self.material "material.add_profile", self.file, profile_set=profile_set, material=self.material
) )
ifcopenshell.api.run("material.assign_profile", self.file, material_profile=material_profile, profile=profile) ifcopenshell.api.run("material.assign_profile", self.file, material_profile=material_profile, profile=profile)
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
def create_type(self, ifc_class, name, representations): def create_type(self, ifc_class, name, representations):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
@@ -252,7 +268,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation "geometry.assign_representation", self.file, product=element, representation=representation
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
LibraryGenerator().generate() LibraryGenerator().generate()
@@ -131,7 +131,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation "geometry.assign_representation", self.file, product=element, representation=representation
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
if __name__ == "__main__": if __name__ == "__main__":
@@ -244,7 +244,9 @@ class LibraryGenerator:
polyline = builder.polyline((V(0, 0), V(width, 0))) polyline = builder.polyline((V(0, 0), V(width, 0)))
_, _, first_semicircle = builder.create_transition_arc_ifc(width, depth, create_ifc_curve=True) _, _, first_semicircle = builder.create_transition_arc_ifc(width, depth, create_ifc_curve=True)
_, _, second_semicircle = builder.create_transition_arc_ifc(second_arc_width, second_arc_depth, create_ifc_curve=True) _, _, second_semicircle = builder.create_transition_arc_ifc(
second_arc_width, second_arc_depth, create_ifc_curve=True
)
builder.translate(second_semicircle, V((width - second_arc_width) / 2, 0)) builder.translate(second_semicircle, V((width - second_arc_width) / 2, 0))
builder.translate([polyline, first_semicircle, second_semicircle], shift_to_center) builder.translate([polyline, first_semicircle, second_semicircle], shift_to_center)
@@ -934,34 +936,46 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (900.0, 750.0, 2100.0) overall_width, overall_depth, overall_height = (900.0, 750.0, 2100.0)
representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Shower 75x90", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Shower 75x90", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (800.0, 800.0, 2100.0) overall_width, overall_depth, overall_height = (800.0, 800.0, 2100.0)
representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Shower 80x80", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Shower 80x80", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (900.0, 900.0, 2100.0) overall_width, overall_depth, overall_height = (900.0, 900.0, 2100.0)
representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_shower_or_bathtube(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Shower 90x90", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Shower 90x90", representation_3d, representation_2d
)
# bathtubs # bathtubs
overall_width, overall_depth, overall_height = (1600.0, 700.0, 550.0) overall_width, overall_depth, overall_height = (1600.0, 700.0, 550.0)
representation_3d, representation_2d = create_shower_or_bathtube( representation_3d, representation_2d = create_shower_or_bathtube(
overall_width, overall_depth, overall_height, bathtube=True overall_width, overall_depth, overall_height, bathtube=True
) )
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Small Bathtub", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Small Bathtub", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (1700.0, 750.0, 550.0) overall_width, overall_depth, overall_height = (1700.0, 750.0, 550.0)
representation_3d, representation_2d = create_shower_or_bathtube( representation_3d, representation_2d = create_shower_or_bathtube(
overall_width, overall_depth, overall_height, bathtube=True overall_width, overall_depth, overall_height, bathtube=True
) )
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Medium Bathtub", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Medium Bathtub", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (1800.0, 800.0, 550.0) overall_width, overall_depth, overall_height = (1800.0, 800.0, 550.0)
representation_3d, representation_2d = create_shower_or_bathtube( representation_3d, representation_2d = create_shower_or_bathtube(
overall_width, overall_depth, overall_height, bathtube=True overall_width, overall_depth, overall_height, bathtube=True
) )
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Large Bathtub", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Large Bathtub", representation_3d, representation_2d
)
def create_toilet(width, depth, height, seat_level=0): def create_toilet(width, depth, height, seat_level=0):
shift_to_center = V(-width / 2, 0) shift_to_center = V(-width / 2, 0)
@@ -1130,9 +1144,7 @@ class LibraryGenerator:
back_wall = builder.rectangle(V(width, height)) back_wall = builder.rectangle(V(width, height))
# example of rotating and extruding by Y axis btw # example of rotating and extruding by Y axis btw
back_wall_extruded = builder.extrude( back_wall_extruded = builder.extrude(
back_wall, back_wall, back_wall_depth + back_wall_border_mask_depth, **builder.extrude_kwargs("Y")
back_wall_depth + back_wall_border_mask_depth,
**builder.extrude_kwargs("Y")
) )
items_3d_to_center.append(back_wall_extruded) items_3d_to_center.append(back_wall_extruded)
@@ -1202,15 +1214,21 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (350.0, 350.0, 650.0) overall_width, overall_depth, overall_height = (350.0, 350.0, 650.0)
representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Small Urinal", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Small Urinal", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (400.0, 400.0, 650.0) overall_width, overall_depth, overall_height = (400.0, 400.0, 650.0)
representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Medium Urinal", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Medium Urinal", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (450.0, 450.0, 650.0) overall_width, overall_depth, overall_height = (450.0, 450.0, 650.0)
representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_urinal(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Large Urinal", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Large Urinal", representation_3d, representation_2d
)
def create_basin(width, depth, height): def create_basin(width, depth, height):
second_width = 0.9 * width second_width = 0.9 * width
@@ -1251,19 +1269,27 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (450.0, 400.0, 250.0) overall_width, overall_depth, overall_height = (450.0, 400.0, 250.0)
representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Extra Small Basin", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Extra Small Basin", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (500.0, 450.0, 250.0) overall_width, overall_depth, overall_height = (500.0, 450.0, 250.0)
representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Small Basin", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Small Basin", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (550.0, 500.0, 250.0) overall_width, overall_depth, overall_height = (550.0, 500.0, 250.0)
representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Medium Basin", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Medium Basin", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (600.0, 550.0, 250.0) overall_width, overall_depth, overall_height = (600.0, 550.0, 250.0)
representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_basin(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcSanitaryTerminalType", "Neufert Large Basin", representation_3d, representation_2d) self.create_explicit_type(
"IfcSanitaryTerminalType", "Neufert Large Basin", representation_3d, representation_2d
)
def create_desk(width, depth, height, return_representations=False): def create_desk(width, depth, height, return_representations=False):
leg_width = 50.0 leg_width = 50.0
@@ -1421,7 +1447,9 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (500.0, 570.0, 820.0) overall_width, overall_depth, overall_height = (500.0, 570.0, 820.0)
representation_3d, representation_2d = create_dishwasher(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_dishwasher(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcElectricApplianceType", "Neufert Dishwasher", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Neufert Dishwasher", representation_3d, representation_2d
)
def create_cooktop(width, depth, height): def create_cooktop(width, depth, height):
items_3d, items_2d = create_box_objects(width, depth, height) items_3d, items_2d = create_box_objects(width, depth, height)
@@ -1442,15 +1470,21 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (580.0, 510.0, 50.0) overall_width, overall_depth, overall_height = (580.0, 510.0, 50.0)
representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcElectricApplianceType", "Neufert Cooktop 58x51", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Neufert Cooktop 58x51", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (750.0, 510.0, 50.0) overall_width, overall_depth, overall_height = (750.0, 510.0, 50.0)
representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcElectricApplianceType", "Neufert Cooktop 75x51", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Neufert Cooktop 75x51", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (890.0, 510.0, 50.0) overall_width, overall_depth, overall_height = (890.0, 510.0, 50.0)
representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_cooktop(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcElectricApplianceType", "Neufert Cooktop 89x51", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Neufert Cooktop 89x51", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (1750.0, 600.0, 850.0) overall_width, overall_depth, overall_height = (1750.0, 600.0, 850.0)
representation_3d, representation_2d = create_box_objects( representation_3d, representation_2d = create_box_objects(
@@ -1520,7 +1554,9 @@ class LibraryGenerator:
representation_3d, representation_2d = create_box_objects( representation_3d, representation_2d = create_box_objects(
overall_width, overall_depth, overall_height, return_representations=True overall_width, overall_depth, overall_height, return_representations=True
) )
self.create_explicit_type("IfcElectricApplianceType", "Generic Small Fridge Zone", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Generic Small Fridge Zone", representation_3d, representation_2d
)
overall_width, overall_depth, overall_height = (900.0, 700.0, 1900.0) overall_width, overall_depth, overall_height = (900.0, 700.0, 1900.0)
representation_3d, representation_2d = create_box_objects( representation_3d, representation_2d = create_box_objects(
@@ -1534,7 +1570,9 @@ class LibraryGenerator:
representation_3d, representation_2d = create_box_objects( representation_3d, representation_2d = create_box_objects(
overall_width, overall_depth, overall_height, return_representations=True overall_width, overall_depth, overall_height, return_representations=True
) )
self.create_explicit_type("IfcElectricApplianceType", "Generic Large Fridge Zone", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Generic Large Fridge Zone", representation_3d, representation_2d
)
def create_sink(width, depth, height, add_table): def create_sink(width, depth, height, add_table):
shift_to_center = V(-width / 2, -depth) shift_to_center = V(-width / 2, -depth)
@@ -1670,7 +1708,9 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (595.0, 680.0, 850.0) overall_width, overall_depth, overall_height = (595.0, 680.0, 850.0)
representation_3d, representation_2d = create_washing_machine(overall_width, overall_depth, overall_height) representation_3d, representation_2d = create_washing_machine(overall_width, overall_depth, overall_height)
self.create_explicit_type("IfcElectricApplianceType", "Neufert Washing Machine", representation_3d, representation_2d) self.create_explicit_type(
"IfcElectricApplianceType", "Neufert Washing Machine", representation_3d, representation_2d
)
def create_dryer_machine(width, depth, height): def create_dryer_machine(width, depth, height):
items_3d, items_2d = create_box_objects(width, depth, height) items_3d, items_2d = create_box_objects(width, depth, height)
@@ -1797,13 +1837,17 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation_2d "geometry.assign_representation", self.file, product=element, representation=representation_2d
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
return element return element
def create_layer_set_type(self, name, data): def create_layer_set_type(self, name, data):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name)
element.Description = data["Description"] element.Description = data["Description"]
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") rel = ifcopenshell.api.run(
"material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet"
)
layer_set = rel.RelatingMaterial layer_set = rel.RelatingMaterial
for layer_data in data["Layers"]: for layer_data in data["Layers"]:
layer = ifcopenshell.api.run( layer = ifcopenshell.api.run(
@@ -1811,33 +1855,43 @@ class LibraryGenerator:
) )
layer.Name = layer_data[0] layer.Name = layer_data[0]
layer.LayerThickness = layer_data[2] layer.LayerThickness = layer_data[2]
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
return element return element
def create_layer_type(self, ifc_class, name, thickness): def create_layer_type(self, ifc_class, name, thickness):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") rel = ifcopenshell.api.run(
"material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet"
)
layer_set = rel.RelatingMaterial layer_set = rel.RelatingMaterial
layer = ifcopenshell.api.run( layer = ifcopenshell.api.run(
"material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"] "material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"]
) )
layer.LayerThickness = thickness layer.LayerThickness = thickness
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
return element return element
def create_profile_type(self, ifc_class, name, profile): def create_profile_type(self, ifc_class, name, profile):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") rel = ifcopenshell.api.run(
"material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet"
)
profile_set = rel.RelatingMaterial profile_set = rel.RelatingMaterial
material_profile = ifcopenshell.api.run( material_profile = ifcopenshell.api.run(
"material.add_profile", "material.add_profile",
self.file, self.file,
profile_set=profile_set, profile_set=profile_set,
material=self.material material=self.material,
# material=self.materials["TBD"]["ifc"] # material=self.materials["TBD"]["ifc"]
) )
ifcopenshell.api.run("material.assign_profile", self.file, material_profile=material_profile, profile=profile) ifcopenshell.api.run("material.assign_profile", self.file, material_profile=material_profile, profile=profile)
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
def create_type(self, ifc_class, name, representations): def create_type(self, ifc_class, name, representations):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
@@ -1869,7 +1923,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation "geometry.assign_representation", self.file, product=element, representation=representation
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
if __name__ == "__main__": if __name__ == "__main__":
@@ -394,9 +394,9 @@ class LibraryGenerator:
TreeData("Lollipop Tree (14m)", "simple", (14.0, 7.5, 0.44)), TreeData("Lollipop Tree (14m)", "simple", (14.0, 7.5, 0.44)),
TreeData("Lollipop Tree (18m)", "simple", (18.0, 9.5, 0.44)), TreeData("Lollipop Tree (18m)", "simple", (18.0, 9.5, 0.44)),
TreeData("Lollipop Tree (25m)", "simple", (25.0, 13.5, 0.50)), TreeData("Lollipop Tree (25m)", "simple", (25.0, 13.5, 0.50)),
TreeData("Tree Small (8m)", "low_poly", (8.0, 6.0, 0.0, .8, 1.0, 0.2, 10)), TreeData("Tree Small (8m)", "low_poly", (8.0, 6.0, 0.0, 0.8, 1.0, 0.2, 10)),
TreeData("Tree Medium (12m)", "low_poly", (12.0, 10.0, 0.0, .8, 2.0, 0.4, 20)), TreeData("Tree Medium (12m)", "low_poly", (12.0, 10.0, 0.0, 0.8, 2.0, 0.4, 20)),
TreeData("Tree Big (20m)", "low_poly", (20.0, 15.0, 0.0, .8, 4.0, 0.6, 30)), TreeData("Tree Big (20m)", "low_poly", (20.0, 15.0, 0.0, 0.8, 4.0, 0.6, 30)),
] ]
for tree_data in trees: for tree_data in trees:
@@ -409,7 +409,7 @@ class LibraryGenerator:
# From tree species table # From tree species table
with open(os.path.join(BLEND_DIR, "tree_species.csv"), 'r') as csvfile: with open(os.path.join(BLEND_DIR, "tree_species.csv"), "r") as csvfile:
reader = csv.reader(csvfile) reader = csv.reader(csvfile)
for i, row in enumerate(reader): for i, row in enumerate(reader):
if i == 0: if i == 0:
@@ -418,9 +418,7 @@ class LibraryGenerator:
data = [float(x) for x in row[2:]] data = [float(x) for x in row[2:]]
preset_data = preset.preset_class(*data)._asdict() preset_data = preset.preset_class(*data)._asdict()
tree_geometry = preset.generator(builder, **preset_data) tree_geometry = preset.generator(builder, **preset_data)
self.create_explicit_type( self.create_explicit_type("IfcGeographicElementType", row[1], **self.get_representations(tree_geometry))
"IfcGeographicElementType", row[1], **self.get_representations(tree_geometry)
)
self.file.write(output_filename) self.file.write(output_filename)
@@ -447,7 +445,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation_2d "geometry.assign_representation", self.file, product=element, representation=representation_2d
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
return element return element
def create_type(self, ifc_class, name, representations): def create_type(self, ifc_class, name, representations):
@@ -480,8 +480,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation "geometry.assign_representation", self.file, product=element, representation=representation
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
if __name__ == "__main__": if __name__ == "__main__":
@@ -98,7 +98,9 @@ class LibraryGenerator:
ifcopenshell.api.run( ifcopenshell.api.run(
"geometry.assign_representation", self.file, product=element, representation=representation "geometry.assign_representation", self.file, product=element, representation=representation
) )
ifcopenshell.api.run("project.assign_declaration", self.file, definitions=[element], relating_context=self.library) ifcopenshell.api.run(
"project.assign_declaration", self.file, definitions=[element], relating_context=self.library
)
LibraryGenerator().generate() LibraryGenerator().generate()
+6 -6
View File
@@ -12,12 +12,12 @@ props = bpy.context.scene.BIMGeoreferenceProperties
# georeferencing coordinates in the IFC Georeferencing panel before filling out # georeferencing coordinates in the IFC Georeferencing panel before filling out
# these details. # these details.
#props.blender_eastings = '334134181.0' # props.blender_eastings = '334134181.0'
#props.blender_northings = '6254570511.0' # props.blender_northings = '6254570511.0'
#props.blender_orthogonal_height = '0.0' # props.blender_orthogonal_height = '0.0'
#props.blender_x_axis_abscissa = '0.147487884244522' # props.blender_x_axis_abscissa = '0.147487884244522'
#props.blender_x_axis_ordinate = '0.989063862448262' # props.blender_x_axis_ordinate = '0.989063862448262'
#props.has_blender_offset = True # props.has_blender_offset = True
props = bpy.context.scene.BIMProjectProperties props = bpy.context.scene.BIMProjectProperties
+18 -14
View File
@@ -40,26 +40,30 @@ if not file:
print("No ifc file") print("No ifc file")
sys.exit() sys.exit()
annotations = file.by_type('IfcAnnotation') annotations = file.by_type("IfcAnnotation")
count = 0 count = 0
for annotation in annotations: for annotation in annotations:
if annotation.ObjectType == 'DRAWING': if annotation.ObjectType == "DRAWING":
psets = ifcopenshell.util.element.get_psets(annotation) psets = ifcopenshell.util.element.get_psets(annotation)
pset = psets['EPset_Drawing'] pset = psets["EPset_Drawing"]
pset_ifc = file.by_id(pset['id']) pset_ifc = file.by_id(pset["id"])
wrong_sep = "" wrong_sep = ""
if platform == 'linux' or platform == 'linux2' or platform == 'darwin': if platform == "linux" or platform == "linux2" or platform == "darwin":
wrong_sep = "\\" wrong_sep = "\\"
if platform == 'win32': if platform == "win32":
wrong_sep = "/" wrong_sep = "/"
ifcopenshell.api.run("pset.edit_pset", file, pset = pset_ifc, properties = { ifcopenshell.api.run(
'Stylesheet' : pset['Stylesheet'].replace(wrong_sep, os.path.sep), "pset.edit_pset",
'Markers' : pset['Markers'].replace(wrong_sep, os.path.sep), file,
'Symbols' : pset['Symbols'].replace(wrong_sep, os.path.sep), pset=pset_ifc,
'Patterns' : pset['Patterns'].replace(wrong_sep, os.path.sep), properties={
}) "Stylesheet": pset["Stylesheet"].replace(wrong_sep, os.path.sep),
count+=1 "Markers": pset["Markers"].replace(wrong_sep, os.path.sep),
"Symbols": pset["Symbols"].replace(wrong_sep, os.path.sep),
"Patterns": pset["Patterns"].replace(wrong_sep, os.path.sep),
},
)
count += 1
print(f"DONE! Checked {count} drawings") print(f"DONE! Checked {count} drawings")
@@ -9,7 +9,7 @@ V = lambda *x: Vector([float(i) for i in x])
def simple_uses(): def simple_uses():
ifc_file = ifcopenshell.file() ifc_file = ifcopenshell.file()
builder = ShapeBuilder(ifc_file) builder = ShapeBuilder(ifc_file)
triangle_curve = builder.polyline(( (0., 0.), (1., 2.), (2., 0.) ), closed=True) triangle_curve = builder.polyline(((0.0, 0.0), (1.0, 2.0), (2.0, 0.0)), closed=True)
print(triangle_curve) print(triangle_curve)
rectangle_curve = builder.rectangle() rectangle_curve = builder.rectangle()
@@ -18,26 +18,19 @@ def simple_uses():
circle_curve = builder.circle() circle_curve = builder.circle()
print(circle_curve) print(circle_curve)
translated_rect = builder.translate(rectangle_curve, Vector( (2.5, 2.5) ), create_copy=True) translated_rect = builder.translate(rectangle_curve, Vector((2.5, 2.5)), create_copy=True)
print(translated_rect) print(translated_rect)
rotated_triangle = builder.rotate(triangle_curve, 90, rotated_triangle = builder.rotate(
pivot_point=Vector( (1., 1.) ), triangle_curve, 90, pivot_point=Vector((1.0, 1.0)), counter_clockwise=True, create_copy=True
counter_clockwise=True, )
create_copy=True)
print(rotated_triangle) print(rotated_triangle)
a, b = builder.translate( a, b = builder.translate([rectangle_curve, circle_curve], Vector((5.0, 5.0)), create_copy=True)
[rectangle_curve, circle_curve],
Vector( (5., 5.) ), create_copy=True)
print(f"Multiple translated objects: {a}, {b}") print(f"Multiple translated objects: {a}, {b}")
c, d = builder.rotate( c, d = builder.rotate([a, b], 90, pivot_point=Vector((0.0, 0.0)), counter_clockwise=False, create_copy=True)
[a, b], 90, print(f"Multiple rotated objects: {c}, {d}")
pivot_point=Vector( (0., 0.) ),
counter_clockwise=False,
create_copy=True)
print(f'Multiple rotated objects: {c}, {d}')
mirrored_objects = builder.mirror( mirrored_objects = builder.mirror(
[a, b], [a, b],
@@ -57,8 +50,7 @@ def simple_uses():
print(rotated_circle) print(rotated_circle)
profile = builder.profile( profile = builder.profile(
rectangle_curve, "test_profile", rectangle_curve, "test_profile", inner_curves=[builder.circle(center=Vector((0.5, 0.5)), radius=0.2)]
inner_curves=[builder.circle(center=Vector((0.5, 0.5)), radius=0.2)]
) )
print(profile) print(profile)
@@ -129,20 +121,14 @@ def mirror_placement_test():
rect_profile = builder.profile(rect, inner_curves=rect_small) rect_profile = builder.profile(rect, inner_curves=rect_small)
pl = builder.extrude(rect_profile, pl = builder.extrude(
magnitude=7.0, rect_profile, magnitude=7.0, position_z_axis=V(0, -1, 0), extrusion_vector=V(0, 0, -1), position=V(0, 5, 0)
position_z_axis=V(0, -1, 0),
extrusion_vector=V(0, 0, -1),
position=V(0, 5, 0)
) )
rect = builder.rectangle(size=size) rect = builder.rectangle(size=size)
back_wall = builder.extrude(rect, back_wall = builder.extrude(
magnitude=2.0, rect, magnitude=2.0, position_z_axis=V(0, -1, 0), extrusion_vector=V(0, 0, -1), position=V(0, 1, 0)
position_z_axis=V(0, -1, 0),
extrusion_vector=V(0, 0, -1),
position=V(0, 1, 0)
) )
items_3d = [pl, back_wall] items_3d = [pl, back_wall]
@@ -195,20 +181,18 @@ def curve_between_two_points_test():
width, depth = (200.0, 200.0) width, depth = (200.0, 200.0)
curve_coords = ( curve_coords = (
(V(0, depth), V(-width, 0)), # ccw (V(0, depth), V(-width, 0)), # ccw
(V(0, depth), V(width, 0)), # cw (V(0, depth), V(width, 0)), # cw
(V(0, -depth), V(width, 0)), # ccw (V(0, -depth), V(width, 0)), # ccw
(V(0, -depth), V(-width, 0)), # cw (V(0, -depth), V(-width, 0)), # cw
(V(+width / 2, 0), V(0, depth)), # ccw
(V(+width/2, 0), V(0, depth)), # ccw (V(-width / 2, 0), V(0, depth)), # cw
(V(-width/2, 0), V(0, depth)), # cw (V(-width / 2, 0), V(0, -depth)), # ccw
(V(-width/2, 0), V(0, -depth)), # ccw (V(+width / 2, 0), V(0, -depth)), # cw
(V(+width/2, 0), V(0, -depth)), # cw (V(0, depth / 2), V(+width, 0)), # cw
(V(0, depth / 2), V(-width, 0)), # ccw
(V(0, depth/2), V(+width, 0)), # cw (V(0, -depth / 2), V(+width, 0)), # ccw
(V(0, depth/2), V(-width, 0)), # ccw (V(0, -depth / 2), V(-width, 0)), # cw
(V(0, -depth/2), V(+width, 0)), # ccw
(V(0, -depth/2), V(-width, 0)), # cw
) )
items_2d = [builder.curve_between_two_points(c) for c in curve_coords] items_2d = [builder.curve_between_two_points(c) for c in curve_coords]
@@ -6,7 +6,7 @@ import multiprocessing
class BlenderImporter: class BlenderImporter:
def __init__(self): def __init__(self):
self.file = ifcopenshell.open('/home/dion/untitled.ifc') self.file = ifcopenshell.open("/home/dion/untitled.ifc")
self.cache_path = "cache.h5" self.cache_path = "cache.h5"
self.should_use_cpu_multiprocessing = True self.should_use_cpu_multiprocessing = True
self.deflection_tolerance = 0.001 self.deflection_tolerance = 0.001
@@ -77,9 +77,7 @@ class BlenderImporter:
return results return results
settings = self.settings_2d if is_curve else self.settings settings = self.settings_2d if is_curve else self.settings
if self.should_use_cpu_multiprocessing: if self.should_use_cpu_multiprocessing:
iterator = ifcopenshell.geom.iterator( iterator = ifcopenshell.geom.iterator(settings, self.file, multiprocessing.cpu_count(), include=products)
settings, self.file, multiprocessing.cpu_count(), include=products
)
else: else:
iterator = ifcopenshell.geom.iterator(settings, self.file, include=products) iterator = ifcopenshell.geom.iterator(settings, self.file, include=products)
cache = self.get_cache() cache = self.get_cache()
@@ -120,4 +118,5 @@ class BlenderImporter:
except: except:
return return
BlenderImporter().execute() BlenderImporter().execute()
+37 -11
View File
@@ -159,13 +159,21 @@ class TestAddBrick:
brick.run_assign_brick_reference(element="element", library="library", brick_uri="brick_uri").should_be_called() brick.run_assign_brick_reference(element="element", library="library", brick_uri="brick_uri").should_be_called()
brick.run_refresh_brick_viewer().should_be_called() brick.run_refresh_brick_viewer().should_be_called()
subject.add_brick( subject.add_brick(
ifc, brick, element="element", namespace="namespace", brick_class="brick_class", library="library", label="label" ifc,
brick,
element="element",
namespace="namespace",
brick_class="brick_class",
library="library",
label="label",
) )
def test_adding_a_plain_brick(self, ifc, brick): def test_adding_a_plain_brick(self, ifc, brick):
brick.add_brick("namespace", "brick_class", "label").should_be_called() brick.add_brick("namespace", "brick_class", "label").should_be_called()
brick.run_refresh_brick_viewer().should_be_called() brick.run_refresh_brick_viewer().should_be_called()
subject.add_brick(ifc, brick, element=None, namespace="namespace", brick_class="brick_class", library=None, label="label") subject.add_brick(
ifc, brick, element=None, namespace="namespace", brick_class="brick_class", library=None, label="label"
)
class TestAddBrickRelation: class TestAddBrickRelation:
@@ -197,24 +205,42 @@ class TestConvertIfcToBrick:
brick.get_convertable_brick_elements().should_be_called().will_return({"element", "downstream_element"}) brick.get_convertable_brick_elements().should_be_called().will_return({"element", "downstream_element"})
brick.get_brick_class("element").should_be_called().will_return("element_class") brick.get_brick_class("element").should_be_called().will_return("element_class")
brick.add_brick_from_element("element", "namespace", "element_class").should_be_called().will_return("element_uri") brick.add_brick_from_element("element", "namespace", "element_class").should_be_called().will_return(
"element_uri"
)
brick.get_element_container("element").should_be_called().will_return("space") brick.get_element_container("element").should_be_called().will_return("space")
brick.add_relation("element_uri", "https://brickschema.org/schema/Brick#hasLocation", "space_uri").should_be_called() brick.add_relation(
"element_uri", "https://brickschema.org/schema/Brick#hasLocation", "space_uri"
).should_be_called()
brick.get_element_systems("element").should_be_called().will_return(["system"]) brick.get_element_systems("element").should_be_called().will_return(["system"])
brick.add_relation("system_uri", "https://brickschema.org/schema/Brick#hasPart", "element_uri").should_be_called() brick.add_relation(
brick.run_assign_brick_reference(element="element", library="library", brick_uri="element_uri").should_be_called() "system_uri", "https://brickschema.org/schema/Brick#hasPart", "element_uri"
).should_be_called()
brick.run_assign_brick_reference(
element="element", library="library", brick_uri="element_uri"
).should_be_called()
brick.get_brick_class("downstream_element").should_be_called().will_return("downstream_element_class") brick.get_brick_class("downstream_element").should_be_called().will_return("downstream_element_class")
brick.add_brick_from_element("downstream_element", "namespace", "downstream_element_class").should_be_called().will_return("downstream_element_uri") brick.add_brick_from_element(
"downstream_element", "namespace", "downstream_element_class"
).should_be_called().will_return("downstream_element_uri")
brick.get_element_container("downstream_element").should_be_called().will_return("space") brick.get_element_container("downstream_element").should_be_called().will_return("space")
brick.add_relation("downstream_element_uri", "https://brickschema.org/schema/Brick#hasLocation", "space_uri").should_be_called() brick.add_relation(
"downstream_element_uri", "https://brickschema.org/schema/Brick#hasLocation", "space_uri"
).should_be_called()
brick.get_element_systems("downstream_element").should_be_called().will_return(["system"]) brick.get_element_systems("downstream_element").should_be_called().will_return(["system"])
brick.add_relation("system_uri", "https://brickschema.org/schema/Brick#hasPart", "downstream_element_uri").should_be_called() brick.add_relation(
brick.run_assign_brick_reference(element="downstream_element", library="library", brick_uri="downstream_element_uri").should_be_called() "system_uri", "https://brickschema.org/schema/Brick#hasPart", "downstream_element_uri"
).should_be_called()
brick.run_assign_brick_reference(
element="downstream_element", library="library", brick_uri="downstream_element_uri"
).should_be_called()
brick.get_element_feeds("element").should_be_called().will_return(["downstream_element"]) brick.get_element_feeds("element").should_be_called().will_return(["downstream_element"])
brick.get_element_feeds("downstream_element").should_be_called().will_return([]) brick.get_element_feeds("downstream_element").should_be_called().will_return([])
brick.add_relation("element_uri", "https://brickschema.org/schema/Brick#feeds", "downstream_element_uri").should_be_called() brick.add_relation(
"element_uri", "https://brickschema.org/schema/Brick#feeds", "downstream_element_uri"
).should_be_called()
brick.run_refresh_brick_viewer().should_be_called() brick.run_refresh_brick_viewer().should_be_called()
subject.convert_ifc_to_brick(brick, namespace="namespace", library="library") subject.convert_ifc_to_brick(brick, namespace="namespace", library="library")
+6 -2
View File
@@ -195,7 +195,9 @@ class TestSwitchRepresentation:
geometry.get_object_data("obj").should_be_called().will_return("current_obj_data") geometry.get_object_data("obj").should_be_called().will_return("current_obj_data")
geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
geometry.get_representation_data("representation").should_be_called().will_return(None) geometry.get_representation_data("representation").should_be_called().will_return(None)
geometry.import_representation("obj", "representation", apply_openings=True).should_be_called().will_return("new_data") geometry.import_representation("obj", "representation", apply_openings=True).should_be_called().will_return(
"new_data"
)
geometry.get_representation_name("representation").should_be_called().will_return("name") geometry.get_representation_name("representation").should_be_called().will_return("name")
geometry.rename_object("new_data", "name").should_be_called() geometry.rename_object("new_data", "name").should_be_called()
geometry.link("representation", "new_data").should_be_called() geometry.link("representation", "new_data").should_be_called()
@@ -220,7 +222,9 @@ class TestSwitchRepresentation:
geometry.get_object_data("obj").should_be_called().will_return("current_obj_data") geometry.get_object_data("obj").should_be_called().will_return("current_obj_data")
geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
geometry.get_representation_data("representation").should_be_called().will_return("existing_data") geometry.get_representation_data("representation").should_be_called().will_return("existing_data")
geometry.import_representation("obj", "representation", apply_openings=True).should_be_called().will_return("new_data") geometry.import_representation("obj", "representation", apply_openings=True).should_be_called().will_return(
"new_data"
)
geometry.get_representation_name("representation").should_be_called().will_return("name") geometry.get_representation_name("representation").should_be_called().will_return("name")
geometry.rename_object("new_data", "name").should_be_called() geometry.rename_object("new_data", "name").should_be_called()
geometry.link("representation", "new_data").should_be_called() geometry.link("representation", "new_data").should_be_called()
+3 -1
View File
@@ -30,7 +30,9 @@ class TestReferenceStructure:
class TestDereferenceStructure: class TestDereferenceStructure:
def test_run(self, ifc, spatial): def test_run(self, ifc, spatial):
spatial.can_reference("structure", "element").should_be_called().will_return(True) spatial.can_reference("structure", "element").should_be_called().will_return(True)
ifc.run("spatial.dereference_structure", products=["element"], relating_structure="structure").should_be_called() ifc.run(
"spatial.dereference_structure", products=["element"], relating_structure="structure"
).should_be_called()
subject.dereference_structure(ifc, spatial, structure="structure", element="element") subject.dereference_structure(ifc, spatial, structure="structure", element="element")
+6 -6
View File
@@ -26,15 +26,15 @@ class TestAssignSceneUnits:
unit.get_scene_unit_si_prefix("LENGTHUNIT").should_be_called().will_return("prefix") unit.get_scene_unit_si_prefix("LENGTHUNIT").should_be_called().will_return("prefix")
unit.get_scene_unit_si_prefix("AREAUNIT").should_be_called().will_return("prefix") unit.get_scene_unit_si_prefix("AREAUNIT").should_be_called().will_return("prefix")
unit.get_scene_unit_si_prefix("VOLUMEUNIT").should_be_called().will_return("prefix") unit.get_scene_unit_si_prefix("VOLUMEUNIT").should_be_called().will_return("prefix")
ifc.run( ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix").should_be_called().will_return(
"unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix" "lengthunit"
).should_be_called().will_return("lengthunit") )
ifc.run("unit.add_si_unit", unit_type="AREAUNIT", prefix="prefix").should_be_called().will_return("areaunit") ifc.run("unit.add_si_unit", unit_type="AREAUNIT", prefix="prefix").should_be_called().will_return("areaunit")
ifc.run( ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", prefix="prefix").should_be_called().will_return(
"unit.add_si_unit", unit_type="VOLUMEUNIT", prefix="prefix" "volumeunit"
).should_be_called().will_return("volumeunit") )
ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit") ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit")
@@ -150,4 +150,3 @@ class TestIsMaterialUsedInSets(NewFile):
material_set.MaterialLayers = [material_set_item] material_set.MaterialLayers = [material_set_item]
material_set_item.Material = material material_set_item.Material = material
assert subject.is_material_used_in_sets(material) is True assert subject.is_material_used_in_sets(material) is True
+3 -1
View File
@@ -448,7 +448,9 @@ class TestUsingArrays(NewFile):
class TestApplyIfcMaterialChanges(NewFile): class TestApplyIfcMaterialChanges(NewFile):
def get_used_styles(self, obj: bpy.types.Object) -> set[ifcopenshell.entity_instance]: def get_used_styles(self, obj: bpy.types.Object) -> set[ifcopenshell.entity_instance]:
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
return {ifc_file.by_id(s.material.BIMStyleProperties.ifc_definition_id) for s in obj.material_slots if s.material} return {
ifc_file.by_id(s.material.BIMStyleProperties.ifc_definition_id) for s in obj.material_slots if s.material
}
def get_mesh(self, obj: bpy.types.Object) -> bpy.types.Mesh: def get_mesh(self, obj: bpy.types.Object) -> bpy.types.Mesh:
mesh = obj.data mesh = obj.data
+8 -1
View File
@@ -104,7 +104,14 @@ class TestSetDefaultContext(NewFile):
tool.Ifc.set(ifc) tool.Ifc.set(ifc)
ifc.createIfcProject() ifc.createIfcProject()
model = ifcopenshell.api.run("context.add_context", ifc, context_type="Model") model = ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
body = ifcopenshell.api.run("context.add_context", ifc, parent=model, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW") body = ifcopenshell.api.run(
"context.add_context",
ifc,
parent=model,
context_type="Model",
context_identifier="Body",
target_view="MODEL_VIEW",
)
subject.set_default_context() subject.set_default_context()
assert bpy.context.scene.BIMRootProperties.contexts == str(body.id()) assert bpy.context.scene.BIMRootProperties.contexts == str(body.id())