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]
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]
reportInvalidTypeForm = false
@@ -75,7 +75,7 @@ class AggregateData:
return []
if not element:
return []
product_linked_agg_group = [
r
for r in getattr(aggregate, "HasAssignments", []) or []
@@ -85,7 +85,6 @@ class AggregateData:
if not product_linked_agg_group:
return []
total = len(product_linked_agg_group[0].RelatedObjects)
return total
@@ -99,7 +99,7 @@ class BIM_PT_aggregate(Panel):
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
op.obj = context.active_object.name
class BIM_PT_linked_aggregate(Panel):
bl_label = "Linked Aggregates"
bl_idname = "BIM_PT_linked_aggregate"
@@ -133,9 +133,8 @@ class BIM_PT_linked_aggregate(Panel):
props = obj.BIMObjectAggregateProperties
row = layout.row(align=True)
if element.Decomposes:
Number_Linked_Aggregates = AggregateData.data['total_linked_aggregate']
Number_Linked_Aggregates = AggregateData.data["total_linked_aggregate"]
if not Number_Linked_Aggregates:
row.label(text="Not a Linked Aggregate")
else:
@@ -151,6 +150,3 @@ class BIM_PT_linked_aggregate(Panel):
op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X")
else:
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["value"])
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
# 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"):
print("No project, we will create one for BBIM.")
bcfxml.project_info = bcf.v2.model.ProjectExtension(
project=bcf.v2.model.Project(
name=nameless,
project_id=str(uuid.uuid4())
), extension_schema=""
project=bcf.v2.model.Project(name=nameless, project_id=str(uuid.uuid4())), extension_schema=""
)
if bcfxml.project.name is None:
bcfxml.project.name = nameless
@@ -971,13 +968,14 @@ class ActivateBcfViewpoint(bpy.types.Operator):
self.set_colours(viewpoint)
def set_exceptions(self, viewpoint, context):
if (
not hasattr(viewpoint.visualization_info.components, "visibility")
or not hasattr(viewpoint.visualization_info.components.visibility.exceptions, "component")
if not hasattr(viewpoint.visualization_info.components, "visibility") or not hasattr(
viewpoint.visualization_info.components.visibility.exceptions, "component"
):
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))
if viewpoint.visualization_info.components.visibility.default_visibility:
@@ -1034,7 +1032,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
context.area.type = old
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):
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
if lv == 8:
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:
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]
@@ -603,7 +603,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
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.")
return {"FINISHED"}
@@ -166,9 +166,9 @@ class BrickschemaReferencesData:
results.append(
{
"id": reference.id(),
"identification": reference.ItemReference
if tool.Ifc.get_schema() == "IFC2X3"
else reference.Identification,
"identification": (
reference.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else reference.Identification
),
"name": reference.Name or "Unnamed",
}
)
@@ -34,6 +34,7 @@ import blenderbim.core.brick as core
import blenderbim.tool.brick as tool
from blenderbim.tool.brick import BrickStore
def update_active_brick_index(self, context):
BrickschemaData.is_loaded = False
@@ -53,7 +54,7 @@ def get_brick_entity_classes(self, context):
return [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]]
def get_brick_roots(self, context):
def get_brick_roots(self, context):
return [(root, root, "") for root in BrickStore.root_classes]
@@ -64,13 +65,13 @@ def get_brick_relations(self, context):
return relations
relations.append(("http://www.w3.org/2000/01/rdf-schema#label", "label", ""))
return relations
def update_view(self, context):
root = context.scene.BIMBrickProperties.brick_list_root
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=False)
def split_screen_update_view(self, context):
root = context.scene.BIMBrickProperties.split_screen_brick_list_root
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=True)
@@ -108,7 +109,11 @@ class BIMBrickProperties(PropertyGroup):
# create relations split screen
split_screen_toggled: BoolProperty(name="Split Screen Toggled", default=False)
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_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
)
@@ -46,7 +46,7 @@ class BIM_PT_brickschema_project_info(Panel):
def draw(self, context):
self.props = context.scene.BIMBrickProperties
if not BrickschemaData.data["is_loaded"]:
row = self.layout.row(align=True)
row.operator("bim.new_brick_file", text="Create Project")
@@ -58,7 +58,7 @@ class BIM_PT_brickschema_project_info(Panel):
row.label(text=BrickStore.path, icon="FILEBROWSER")
else:
row.label(text="No file", icon="FILEBROWSER")
row = self.layout.row(align=True)
if BrickStore.last_saved:
row.label(text=BrickStore.last_saved, icon="TIME")
@@ -130,7 +130,7 @@ class BIM_PT_brickschema_create_entity(Panel):
row = self.layout.row(align=True)
prop_with_search(row, self.props, "brick_entity_class", text="Type")
row = self.layout.row(align=True)
active = tool.Ifc.get_entity(context.active_object)
if active and context.selected_objects:
@@ -141,7 +141,7 @@ class BIM_PT_brickschema_create_entity(Panel):
row = self.layout.row(align=True)
row.operator("bim.add_brick", text="Create Entity")
class BIM_PT_brickschema_viewport(Panel):
bl_label = "Viewport"
@@ -194,7 +194,9 @@ class BIM_PT_brickschema_viewport(Panel):
row = grid_right.row()
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"]:
row = self.layout.row(align=True)
@@ -213,7 +215,13 @@ class BIM_PT_brickschema_viewport(Panel):
row.label(text="No selection", icon="INFO")
else:
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")
elif self.props.brick_create_relations_toggled:
@@ -234,7 +242,11 @@ class BIM_PT_brickschema_viewport(Panel):
row.label(text=relation["object_name"])
row = split.row(align=True)
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.predicate = relation["predicate_uri"]
op.object = relation["object_uri"]
@@ -263,6 +275,7 @@ class BIM_UL_bricks(UIList):
row = split.row()
row.label(text=str(item.total_items))
class BIM_PT_ifc_brickschema_references(Panel):
bl_label = "Brickschema References"
bl_idname = "BIM_PT_ifc_brickschema_references"
@@ -291,13 +304,13 @@ class BIM_PT_ifc_brickschema_references(Panel):
row.label(text="No IFC Libraries")
row.operator("bim.convert_brick_project", text="", icon="ADD")
return
elif not BrickschemaReferencesData.data["libraries"]:
row = self.layout.row(align=True)
row.label(text="No IFC Libraries: save the Brick project to create a new library", icon="ERROR")
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
row = self.layout.row(align=True)
@@ -318,4 +331,4 @@ class BIM_PT_ifc_brickschema_references(Panel):
row.label(text=reference["identification"], icon="ASSET_MANAGER")
row.label(text=reference["name"])
row.operator("bim.unassign_library_reference", text="", icon="X").reference = reference["id"]
row.operator("bim.view_brick_item", text="", icon="DISCLOSURE_TRI_RIGHT").item = reference["identification"]
row.operator("bim.view_brick_item", text="", icon="DISCLOSURE_TRI_RIGHT").item = reference["identification"]
@@ -144,7 +144,7 @@ class CadFillet(bpy.types.Operator):
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.radius = self.radius * si_conversion
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
@@ -369,7 +369,7 @@ class CadOffset(bpy.types.Operator):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.distance = self.distance * si_conversion
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="EDIT")
@@ -507,8 +507,6 @@ class CadOffset(bpy.types.Operator):
local_direction = (rotation_i @ direction).normalized()
normals.append(local_direction)
if len(normals) == 2:
# https://stackoverflow.com/a/54042831/9627415
new_normal = (normals[0].lerp(normals[1], 0.5)).normalized()
@@ -638,7 +636,7 @@ class AddIfcArcIndexFillet(bpy.types.Operator):
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.radius = self.radius * si_conversion
if self.has_selected_existing_arc(context):
self.change_radius(context)
else:
@@ -814,8 +812,8 @@ class AddRectangle(bpy.types.Operator):
def execute(self, context):
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
self.x = self.x * si_conversion
self.y = self.y * si_conversion
self.y = self.y * si_conversion
obj = context.active_object
bm = bmesh.from_edit_mesh(obj.data)
cursor = obj.matrix_world.inverted() @ context.scene.cursor.location
@@ -70,7 +70,7 @@ class ClashDecorator:
blf.color(font_id, *color)
if coords_2d:
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.draw(font_id, text) # Set your text here
@@ -496,4 +496,3 @@ class SelectSmartGroup(bpy.types.Operator):
with bpy.context.temp_override(**context_override):
bpy.ops.view3d.view_selected()
return {"FINISHED"}
@@ -105,7 +105,7 @@ class BIM_PT_object_constraints(Panel):
if constraint["type"] == "IfcObjective":
icon = "LIGHT"
else:
continue # Metric not implemented
continue # Metric not implemented
row = self.layout.row(align=True)
row.label(text=constraint["name"])
row.operator("bim.unassign_constraint", text="", icon="X").constraint = constraint["id"]
@@ -164,7 +164,14 @@ class CostSchedulesData:
if unit:
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
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:
data["UnitSymbol"] = "U"
@@ -47,14 +47,14 @@ class BIM_PT_cost_schedules(Panel):
row = self.layout.row(align=True)
if CostSchedulesData.data["total_cost_schedules"]:
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.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT")
else:
row.label(text="No Cost Schedules found.", icon="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"]:
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"
)
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule["id"]
row.operator(
"bim.enable_editing_cost_schedule_attributes", text="", icon="GREASEPENCIL"
).cost_schedule = cost_schedule["id"]
row.operator("bim.enable_editing_cost_schedule_attributes", text="", icon="GREASEPENCIL").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.is_editing == "COST_SCHEDULE_ATTRIBUTES":
@@ -616,9 +616,9 @@ class BIM_UL_cost_items_trait:
def draw_parent_operator(self, row, cost_item_id):
if self.props.active_cost_item_id:
if self.props.active_cost_item_id != cost_item_id:
op = row.operator(
"bim.change_parent_cost_item", text="", icon="LINKED", emboss=False
).new_parent = cost_item_id
op = row.operator("bim.change_parent_cost_item", text="", icon="LINKED", emboss=False).new_parent = (
cost_item_id
)
else:
row.label(text="", icon="BLANK1")
@@ -18,7 +18,8 @@
import bpy
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.props import (
PointerProperty,
@@ -30,10 +31,13 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
#import blenderbim.tool as tool
#import blenderbim.core.geometry
#import ifcopenshell
# import blenderbim.tool as tool
# import blenderbim.core.geometry
# import ifcopenshell
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"
)
@@ -89,7 +89,7 @@ class BIM_PT_ifccsv(Panel):
row = layout.row(align=True)
op = row.operator("bim.search", text="Select", icon="VIEWZOOM")
op.property_group = "CsvProperties"
op.property_group = "CsvProperties"
layout.separator()
row = layout.row(align=True)
@@ -128,6 +128,3 @@ class BIM_PT_ifccsv(Panel):
row = layout.row(align=True)
row.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper())
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.prop(props, "number_of_polygons", text="")
row = layout.split(factor=0.7, align=True)
row.operator(
"bim.select_highest_polygon_meshes"
).percentile = context.scene.BIMDebugProperties.percentile_of_polygons
row.operator("bim.select_highest_polygon_meshes").percentile = (
context.scene.BIMDebugProperties.percentile_of_polygons
)
row.prop(props, "percentile_of_polygons", text="")
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.step_id = attribute.int_value
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
attribute.int_value
)
if props.inverse_attributes:
layout.label(text="Inverse attributes:")
@@ -152,9 +152,9 @@ class BIM_PT_debug(Panel):
row.prop(attribute, "name", text="")
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
attribute.int_value
)
if props.inverse_references:
layout.label(text="Inverse references:")
@@ -163,6 +163,6 @@ class BIM_PT_debug(Panel):
row = layout.row(align=True)
row.prop(attribute, "string_value", text="")
if attribute.int_value:
row.operator(
"bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text=""
).step_id = attribute.int_value
row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = (
attribute.int_value
)
@@ -29,6 +29,7 @@
import bpy
from blenderbim.bim.module.demo.data import DemoData
# 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
# any panel in Blender, and click "Edit Source". This will bring you to a ui.py
@@ -159,7 +159,7 @@ class BaseDecorator:
objecttype = "NOTDEFINED"
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
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
@@ -2020,7 +2020,6 @@ class DecorationsHandler:
for decorator in self.decorators.values():
decorator.font_id = font_id
def get_objects_and_decorators(self, collection):
# TODO: do it in data instead of the handler for performance?
results = []
@@ -41,9 +41,8 @@ def set_active_camera_resolution(scene):
props = scene.camera.data.BIMCameraProperties
ortho_scale = max((props.width, props.height))
aspect_ratio = props.width / props.height
if (
(scene.camera.data.ortho_scale != ortho_scale)
or (scene.render.resolution_x / scene.render.resolution_y != aspect_ratio)
if (scene.camera.data.ortho_scale != ortho_scale) or (
scene.render.resolution_x / scene.render.resolution_y != aspect_ratio
):
scene.camera.data.ortho_scale = ortho_scale
@@ -127,7 +127,7 @@ def format_distance(
precision=None,
decimal_places=None,
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)
@@ -141,9 +141,9 @@ def format_distance(
# Imperial Formatting
if unit_system == "IMPERIAL":
if in_unit_length:
if unit_length == 'INCHES':
if unit_length == "INCHES":
toInches = 1
if unit_length == 'FEET':
if unit_length == "FEET":
toInches = 11.9999
else:
toInches = 39.3700787401574887
@@ -222,11 +222,11 @@ def format_distance(
# METRIC FORMATTING
elif unit_system == "METRIC":
if in_unit_length:
if unit_length == 'CENTIMETERS':
value = value/100
if unit_length == 'MILLIMETERS':
value = value/1000
if unit_length == "CENTIMETERS":
value = value / 100
if unit_length == "MILLIMETERS":
value = value / 1000
if precision:
value = precision * round(float(value) / precision)
@@ -560,7 +560,7 @@ class Scheduler:
text_tag = self.svg.text("", **(text_params | {"font-size": "0"} | box_alignment_params))
# TODO: Should be done without using magic number for self.font_width
# TODO: Should be done without using magic number for self.font_width
if wrap_text:
wrapped_lines = []
for line in text_lines:
@@ -123,18 +123,18 @@ class BIM_PT_element_filters(Panel):
self.layout, props.include_filter_groups, ElementFiltersData, "drawing_include"
)
row = self.layout.row(align=True)
row.operator(
"bim.edit_element_filter", icon="CHECKMARK", text="Save Include Filter"
).filter_mode = "INCLUDE"
row.operator("bim.edit_element_filter", icon="CHECKMARK", text="Save Include Filter").filter_mode = (
"INCLUDE"
)
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
elif props.filter_mode == "EXCLUDE":
blenderbim.bim.helper.draw_filter(
self.layout, props.exclude_filter_groups, ElementFiltersData, "drawing_exclude"
)
row = self.layout.row(align=True)
row.operator(
"bim.edit_element_filter", icon="CHECKMARK", text="Save Exclude Filter"
).filter_mode = "EXCLUDE"
row.operator("bim.edit_element_filter", icon="CHECKMARK", text="Save Exclude Filter").filter_mode = (
"EXCLUDE"
)
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
else:
row = self.layout.row(align=True)
@@ -260,9 +260,9 @@ class BIM_PT_drawings(Panel):
row2 = col.row(align=True)
row2.operator("bim.remove_drawing", icon="X", text="").drawing = active_drawing.ifc_definition_id
row2.operator(
"bim.duplicate_drawing", icon="COPYDOWN", text=""
).drawing = active_drawing.ifc_definition_id
row2.operator("bim.duplicate_drawing", icon="COPYDOWN", text="").drawing = (
active_drawing.ifc_definition_id
)
col = row.column()
col.alignment = "RIGHT"
@@ -339,9 +339,9 @@ class BIM_PT_schedules(Panel):
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.operator("bim.open_schedule", icon="URL", text="").schedule = active_schedule.ifc_definition_id
row.operator(
"bim.build_schedule", icon="LINENUMBERS_ON", text=""
).schedule = active_schedule.ifc_definition_id
row.operator("bim.build_schedule", icon="LINENUMBERS_ON", 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(
@@ -612,13 +612,13 @@ class BIM_UL_sheets(bpy.types.UIList):
row = layout.row(align=True)
if item.is_sheet:
if item.is_expanded:
row.operator(
"bim.contract_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
).sheet = item.ifc_definition_id
row.operator("bim.contract_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").sheet = (
item.ifc_definition_id
)
else:
row.operator(
"bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
).sheet = item.ifc_definition_id
row.operator("bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").sheet = (
item.ifc_definition_id
)
row.label(text=f"{item.identification} - {item.name}")
else:
@@ -39,6 +39,7 @@ class SelectFMIfcFile(MultipleFileSelector):
self.update_props(props, "ifc_file", props.ifc_files)
return {"FINISHED"}
class ExecuteIfcFM(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm"
bl_label = "Execute IfcFM"
@@ -85,15 +85,15 @@ class BIM_MT_object_set_origin(Menu):
bl_label = "IFC Set Origin"
def draw(self, context):
self.layout.operator(
"bim.override_origin_set", icon="PLUGIN", text="IFC Geometry to Origin"
).origin_type = "GEOMETRY_ORIGIN"
self.layout.operator(
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Geometry"
).origin_type = "ORIGIN_GEOMETRY"
self.layout.operator(
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to 3D Cursor"
).origin_type = "ORIGIN_CURSOR"
self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Geometry to Origin").origin_type = (
"GEOMETRY_ORIGIN"
)
self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Geometry").origin_type = (
"ORIGIN_GEOMETRY"
)
self.layout.operator("bim.override_origin_set", icon="PLUGIN", text="IFC Origin to 3D Cursor").origin_type = (
"ORIGIN_CURSOR"
)
self.layout.operator(
"bim.override_origin_set", icon="PLUGIN", text="IFC Origin to Center of Mass (Surface)"
).origin_type = "ORIGIN_CENTER_OF_MASS"
@@ -118,6 +118,7 @@ class ConvertGlobalToLocal(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
core.convert_global_to_local(tool.Georeference)
class ConvertAngleToCoordinates(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.convert_angle_to_coord"
bl_label = "Convert Angle To Y Axis"
@@ -101,9 +101,9 @@ class LibraryReferencesData:
results.append(
{
"id": library.id(),
"identification": library.ItemReference
if tool.Ifc.get_schema() == "IFC2X3"
else library.Identification,
"identification": (
library.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else library.Identification
),
"name": library.Name or "Unnamed",
}
)
@@ -34,10 +34,12 @@ classes = (
ui.BIM_PT_solar,
)
def register():
bpy.types.Scene.radiance_exporter_properties = bpy.props.PointerProperty(type=prop.RadianceExporterProperties)
bpy.types.Scene.BIMSolarProperties = bpy.props.PointerProperty(type=prop.BIMSolarProperties)
def unregister():
del bpy.types.Scene.radiance_exporter_properties
del bpy.types.Scene.BIMSolarProperties
@@ -87,7 +87,6 @@ class SolarDecorator:
blf.position(self.font_id, co[0], co[1], 0)
blf.draw(self.font_id, line)
def draw_geometry(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences()
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)
coords.extend([origin @ v for v in analemma_verts])
for i in range(len(analemma_verts) - 1):
indices.append((coord_offset + i,
coord_offset + i+1))
indices.append((coord_offset + i, coord_offset + i + 1))
coord_offset += len(analemma_verts)
self.draw_batch("LINES", coords, decorator_color_special, indices)
@@ -37,12 +37,13 @@ from blenderbim.bim.module.light.data import SolarData
ifc_materials = []
class ExportOBJ(bpy.types.Operator):
"""Exports the IFC File to OBJ"""
bl_idname = "export_scene.radiance"
bl_label = "Export"
bl_description = "Export the IFC to OBJ"
def execute(self, context):
@@ -52,12 +53,11 @@ class ExportOBJ(bpy.types.Operator):
context.scene.radiance_exporter_properties.is_exporting = True
# Conversion from IFC to OBJ
# Settings for obj
settings = ifcopenshell.geom.settings()
serializer_settings = ifcopenshell.geom.serializer_settings()
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SURFACES_AND_SOLIDS)
settings.set("apply-default-materials", True)
serializer_settings.set("use-element-guids", True)
@@ -65,17 +65,17 @@ class ExportOBJ(bpy.types.Operator):
if should_load_from_memory:
ifc_file = tool.Ifc.get()
else:
ifc_file_path = context.scene.radiance_exporter_properties.ifc_file
ifc_file = ifcopenshell.open(ifc_file_path)
# for material in ifc_file.by_type("IfcMaterial"):
# self.report({'INFO'}, f"Material: {material.Name}, ID: {material.id()}")
obj_file_path = os.path.join(output_dir, "model.obj")
mtl_file_path = os.path.join(output_dir, "model.mtl")
serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, serializer_settings)
serialiser.setFile(ifc_file)
serialiser.setUnitNameAndMagnitude("METER", 1.0)
@@ -84,10 +84,10 @@ class ExportOBJ(bpy.types.Operator):
if ifc_file.schema in ("IFC2X3", "IFC4"):
elements = ifc_file.by_type("IfcElement") + ifc_file.by_type("IfcProxy")
else:
elements = ifc_file.by_type("IfcElement")
elements = ifc_file.by_type("IfcElement")
elements = [e for e in elements if not e.is_a("IfcFeatureElement") or e.is_a("IfcSurfaceFeature")]
elements = [e for e in elements if not e.is_a("IfcFeatureElement") or e.is_a("IfcSurfaceFeature")]
iterator = ifcopenshell.geom.iterator(settings, ifc_file, multiprocessing.cpu_count(), include=elements)
if iterator.initialize():
while True:
@@ -102,30 +102,31 @@ class ExportOBJ(bpy.types.Operator):
# print(material, dir(material))
# print(material.name)
ifc_materials.append(material.name)
serialiser.write(shape)
if not iterator.next():
break
serialiser.finalize()
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):
"""Radiance Rendering"""
bl_idname = "render_scene.radiance"
bl_label = "Render"
bl_description = "Renders the scene using Radiance"
def execute(self, context):
if pr is None:
self.report({'ERROR'}, "PyRadiance is not available. Cannot perform rendering.")
return {'CANCELLED'}
self.report({"ERROR"}, "PyRadiance is not available. Cannot perform rendering.")
return {"CANCELLED"}
# Get the resolution from the user input
props = context.scene.radiance_exporter_properties
resolution_x, resolution_y = props.radiance_resolution_x, props.radiance_resolution_y
@@ -138,31 +139,29 @@ class RadianceRender(bpy.types.Operator):
obj_file_path = os.path.join(output_dir, "model.obj")
camera = self.get_active_camera(context)
if camera is None:
self.report({'ERROR'}, "No active camera found in the scene. Please add a camera and set it as active.")
return {'CANCELLED'}
self.report({"ERROR"}, "No active camera found in the scene. Please add a camera and set it as active.")
return {"CANCELLED"}
# Get camera position and direction
camera_position, camera_direction = self.get_camera_data(camera)
# Material processing
# style = []
# with open(obj_file_path, "r") as obj_file:
# for line in obj_file:
# if line.startswith("usemtl"):
# l = line.strip().split(" ")
# style.append(l[1])
# Check if json file is empty or not
props = context.scene.radiance_exporter_properties
if props.use_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)
else:
# Use in-UI material mappings
@@ -170,7 +169,6 @@ class RadianceRender(bpy.types.Operator):
print(data)
# Create materials.rad file
materials_file = os.path.join(output_dir, "materials.rad")
with open(materials_file, "w") as file:
@@ -190,19 +188,19 @@ class RadianceRender(bpy.types.Operator):
# print(i)
# 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
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])
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")
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')
self.report({'INFO'}, "Exported Scene file to: {}".format(scene_file))
self.report({"INFO"}, "Exported Scene file to: {}".format(scene_file))
# Py Radiance Rendering code
scene = pr.Scene("ascene")
@@ -216,26 +214,31 @@ class RadianceRender(bpy.types.Operator):
aview = pr.View(position=camera_position, direction=camera_direction)
scene.add_view(aview)
image = pr.render(scene, ambbounce=1, resolution=(resolution_x, resolution_y),
quality=quality, detail=detail, variability=variability)
image = pr.render(
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()}")
if output_file_format == 'HDR':
if output_file_format == "HDR":
with open(output_path, "wb") as wtr:
wtr.write(image)
else:
pass
self.report({'INFO'}, "Radiance rendering completed. Output: {}".format(output_path))
return {'FINISHED'}
self.report({"INFO"}, "Radiance rendering completed. Output: {}".format(output_path))
return {"FINISHED"}
def get_active_camera(self, context):
if context.scene.camera:
return context.scene.camera
for obj in context.scene.objects:
if obj.type == 'CAMERA':
if obj.type == "CAMERA":
return obj
return None
@@ -256,10 +259,11 @@ class RadianceRender(bpy.types.Operator):
resolution_y = props.radiance_resolution_y
return resolution_x, resolution_y
def save_obj2mesh_output(inp: Union[bytes, str, Path], output_file: str, **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)
return output_file
@@ -333,6 +337,7 @@ class ViewFromSun(bpy.types.Operator):
props.hour = props.hour # Just to refresh camera position
return {"FINISHED"}
class RefreshIFCMaterials(bpy.types.Operator):
bl_idname = "bim.refresh_ifc_materials"
bl_label = "Refresh IFC Materials"
@@ -341,7 +346,7 @@ class RefreshIFCMaterials(bpy.types.Operator):
def execute(self, context):
props = context.scene.radiance_exporter_properties
ifc_file = tool.Ifc.get() if props.should_load_from_memory else ifcopenshell.open(props.ifc_file)
for style in ifc_file.by_type("IfcSurfaceStyle"):
for render_item in style.Styles:
if render_item.is_a("IfcSurfaceStyleRendering"):
@@ -349,5 +354,5 @@ class RefreshIFCMaterials(bpy.types.Operator):
style_name = style.Name or f"Unnamed Style {render_item.id()}"
if not props.get_material_mapping(style_name):
props.add_material_mapping(style_id, style_name)
return {'FINISHED'}
return {"FINISHED"}
@@ -170,110 +170,88 @@ class RadianceExporterProperties(PropertyGroup):
def get_mappings_dict(self):
return {item["style_id"]: item["radiance_material"] for item in self.material_mappings}
use_json_file: BoolProperty(
name="Upload JSON",
description="Toggle between uploading a JSON file and using in-UI material mapping",
default=False
)
is_exporting: bpy.props.BoolProperty(
name="Is Exporting",
description="Whether the OBJ export is in progress",
default=False
default=False,
)
material_mappings: bpy.props.CollectionProperty(
type= bpy.types.PropertyGroup,
name="Material Mappings"
is_exporting: bpy.props.BoolProperty(
name="Is Exporting", description="Whether the OBJ export is in progress", default=False
)
material_mappings: bpy.props.CollectionProperty(type=bpy.types.PropertyGroup, name="Material Mappings")
should_load_from_memory: BoolProperty(
name="Load from Memory",
default=False,
default=False,
)
radiance_resolution_x: IntProperty(
name="X",
description="Horizontal resolution of the output image",
default=1920,
min=1
name="X", description="Horizontal resolution of the output image", default=1920, min=1
)
radiance_resolution_y: IntProperty(
name="Y",
description="Vertical resolution of the output image",
default=1080,
min=1
name="Y", description="Vertical resolution of the output image", default=1080, min=1
)
output_dir: StringProperty(
name="Output Directory",
description="Directory to output Radiance files",
default="",
subtype="DIR_PATH",
update=lambda self, context: self.update_output_dir(context)
update=lambda self, context: self.update_output_dir(context),
)
ifc_file: StringProperty(
name="IFC File",
description="Path to the IFC file",
default="",
subtype="FILE_PATH",
update=lambda self, context: self.update_ifc_file(context)
update=lambda self, context: self.update_ifc_file(context),
)
json_file: StringProperty(
name="JSON File",
description="Path to the JSON file",
default="",
subtype="FILE_PATH",
update=lambda self, context: self.update_json_file(context)
update=lambda self, context: self.update_json_file(context),
)
radiance_quality: EnumProperty(
name="Quality",
description="Radiance rendering quality",
items=[
('LOW', "Low", "Low quality"),
('MEDIUM', "Medium", "Medium quality"),
('HIGH', "High", "High quality")
],
default='MEDIUM'
items=[("LOW", "Low", "Low quality"), ("MEDIUM", "Medium", "Medium quality"), ("HIGH", "High", "High quality")],
default="MEDIUM",
)
radiance_detail: EnumProperty(
name="Detail",
description="Radiance rendering detail",
items=[
('LOW', "Low", "Low detail"),
('MEDIUM', "Medium", "Medium detail"),
('HIGH', "High", "High detail")
],
default='MEDIUM'
items=[("LOW", "Low", "Low detail"), ("MEDIUM", "Medium", "Medium detail"), ("HIGH", "High", "High detail")],
default="MEDIUM",
)
radiance_variability: EnumProperty(
name="Variability",
description="Radiance rendering variability",
items=[
('LOW', "Low", "Low variability"),
('MEDIUM', "Medium", "Medium variability"),
('HIGH', "High", "High variability")
("LOW", "Low", "Low variability"),
("MEDIUM", "Medium", "Medium variability"),
("HIGH", "High", "High variability"),
],
default="MEDIUM",
)
output_file_name: StringProperty(
name="Output File Name",
description="Name of the output image file (without extension)",
default="render"
name="Output File Name", description="Name of the output image file (without extension)", default="render"
)
output_file_format: EnumProperty(
name="Output File Format",
description="Format of the output image file",
items=[
('HDR', "HDR", "High Dynamic Range"),
("HDR", "HDR", "High Dynamic Range"),
],
default='HDR'
default="HDR",
)
class BIMSolarProperties(PropertyGroup):
sites: EnumProperty(items=get_sites, name="Sites")
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):
"""Creates a Panel in the render properties window"""
bl_label = "Radiance Exporter"
bl_idname = "BIM_PT_radiance_exporter"
bl_options = {'DEFAULT_CLOSED'}
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_lighting"
@@ -43,7 +44,7 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
if tool.Ifc.get():
row = self.layout.row()
row.prop(props, "should_load_from_memory")
if not tool.Ifc.get() or not props.should_load_from_memory:
row = self.layout.row(align=True)
row.prop(props, "ifc_file")
@@ -51,7 +52,6 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
row = layout.row()
row.prop(props, "output_dir")
row = layout.row()
layout.prop(props, "use_json_file")
@@ -69,22 +69,21 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
layout.operator("bim.refresh_ifc_materials")
layout.separator()
row = layout.row()
row.label(text="Resolution")
row.prop(props, "radiance_resolution_x", text="X")
row = layout.row()
row.label(text="")
row.prop(props, "radiance_resolution_y", text="Y")
row = layout.row()
row.prop(props, "radiance_quality")
row = layout.row()
row.prop(props, "radiance_detail")
row = layout.row()
row.prop(props, "radiance_variability")
@@ -92,7 +91,7 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
row = layout.row()
row.prop(props, "output_file_name")
row = layout.row()
row.prop(props, "output_file_format")
layout.separator()
@@ -104,12 +103,14 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
row.operator("render_scene.radiance", text="Radiance Render")
row.enabled = not props.is_exporting
class BIM_PT_solar(bpy.types.Panel):
"""Creates a Panel in the render properties window"""
bl_label = "Solar Access / Shadow"
bl_idname = "BIM_PT_solar"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_solar_analysis"
bl_options = {"HIDE_HEADER"}
@@ -135,7 +136,7 @@ class BIM_PT_solar(bpy.types.Panel):
sun_props = context.scene.sun_pos_properties
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.prop(props, "latitude")
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 = self.layout.row(align=True)
row.prop(props, "month", text={
1: "January",
2: "February",
3: "March",
4: "April",
5: "May",
6: "June",
7: "July",
8: "August",
9: "September",
10: "October",
11: "November",
12: "December",
}[props.month])
row.prop(
props,
"month",
text={
1: "January",
2: "February",
3: "March",
4: "April",
5: "May",
6: "June",
7: "July",
8: "August",
9: "September",
10: "October",
11: "November",
12: "December",
}[props.month],
)
row.prop(props, "day")
row = self.layout.row(align=True)
@@ -258,7 +258,9 @@ class ObjectMaterialData:
precision = bpy.context.scene.DocProperties.imperial_precision
else:
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']}"
if item.is_a("IfcMaterial"):
data["material"] = item.Name or "Unnamed"
@@ -223,7 +223,7 @@ class BIM_PT_object_material(Panel):
row = self.layout.row(align=True)
row.label(text="No Profiles Available")
row.operator("bim.add_profile_def", icon="ADD", text="")
else:
else:
row = self.layout.row(align=True)
if ObjectMaterialData.data["set_item_name"] == "profile":
prop_with_search(row, self.mprops, "profiles", icon="ITALIC", text="")
@@ -235,7 +235,10 @@ class BIM_PT_object_material(Panel):
row = self.layout.row(align=True)
row.label(text="----- Exterior -----")
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)
elif self.props.active_material_set_item_id == set_item["id"]:
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
else:
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.label(text=f"Total Thickness: {formatted_thickness}")
@@ -84,9 +84,9 @@ class EnableEditingArray(bpy.types.Operator, tool.Ifc.Operator):
obj = context.active_object
element = tool.Ifc.get_entity(obj)
props = obj.BIMArrayProperties
relating_obj = props.relating_array_object
if relating_obj:
element = tool.Ifc.get_entity(relating_obj)
parent_globalid = ifcopenshell.util.element.get_pset(element, "BBIM_Array", "Parent")
@@ -102,9 +102,9 @@ class EnableEditingArray(bpy.types.Operator, tool.Ifc.Operator):
props.use_local_space = data.get("use_local_space", False)
props.sync_children = data.get("sync_children", False)
props.method = data.get("method", "OFFSET")
props.is_editing = self.item
return {"FINISHED"}
@@ -149,9 +149,9 @@ class EditArray(bpy.types.Operator, tool.Ifc.Operator):
tool.Blender.Modifier.Array.set_children_lock_state(element, self.item, True)
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
return {"FINISHED"}
@@ -285,8 +285,11 @@ class SelectAllArrayObjects(bpy.types.Operator):
array_objects = tool.Blender.Modifier.Array.get_all_objects(parent_element)
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"}
@@ -53,7 +53,7 @@ class AuthoringData:
cls.data["ifc_element_type"] = cls.ifc_element_type
cls.data["ifc_classes"] = cls.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()
# only after .type_class()
@@ -541,7 +541,9 @@ class MEPGenerator:
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
material_profile = ifcopenshell.api.run(
"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")
class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
relating_type_id: bpy.props.EnumProperty(
@@ -226,8 +223,6 @@ class BIMArrayProperties(PropertyGroup):
)
class BIMStairProperties(PropertyGroup):
def validate_nosing_value(self, context):
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):
self.layout.label(text="No active object. Please select a wall")
def msg_no_active_wall(self, context):
self.layout.label(text="The active object is not a wall. Please select a wall.")
def msg_no_container(self, context):
self.layout.label(text="The wall is not contained. Please the selected wall in a building container")
def msg_no_selected_objects(self, context):
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=[]),
"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
def try_first_element(x):
return x[0] if x else x
@@ -79,7 +79,11 @@ def get_actor_type_enum(self, context):
return [
("IfcPerson", "Person", get_entity_doc(version, "IfcPerson").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)
for mat in bpy.data.materials:
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)
tool.Blender.register_toolbar()
@@ -170,6 +170,7 @@ def get_group_qto_names(self, context):
qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
return qtonames[ifc_class]
def get_profile_pset_names(self, context):
global psetnames
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.label(text=prop["Name"])
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:
row = box.row()
@@ -75,7 +75,9 @@ class PsetTemplatesData:
pset_dir = os.path.join(bpy.context.scene.BIMProperties.data_dir, "pset")
files = os.listdir(pset_dir)
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)
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"
).resource = item.ifc_definition_id
else:
row.operator(
"bim.expand_resource", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
).resource = item.ifc_definition_id
row.operator("bim.expand_resource", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").resource = (
item.ifc_definition_id
)
else:
row.label(text="", icon="DOT")
row.prop(item, "name", emboss=False, text="", icon=icon_map[resource["type"]])
@@ -201,7 +201,10 @@ class IfcClassData:
if element:
if element.is_a("IfcOpeningElement") or element.is_a("IfcOpeningStandardCase"):
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
for product in cls.ifc_products():
if element.is_a(product[0]):
@@ -361,9 +361,7 @@ class SaveColourscheme(Operator, tool.Ifc.Operator):
description["colourscheme_query"] = query
group.Description = json.dumps(description)
else:
description = json.dumps(
{"type": "BBIM_Search", "colourscheme": colourscheme, "colourscheme_query": query}
)
description = json.dumps({"type": "BBIM_Search", "colourscheme": colourscheme, "colourscheme_query": query})
group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), name=self.name, description=description)
def invoke(self, context, event):
@@ -355,6 +355,7 @@ def update_task_bar_list(self, context):
else:
tool.Sequence.remove_task_bar(self.ifc_definition_id)
class Task(PropertyGroup):
name: StringProperty(name="Name", update=updateTaskName)
identification: StringProperty(name="Identification", update=updateTaskIdentification)
@@ -188,9 +188,9 @@ class BIM_PT_work_schedules(Panel):
row1.label(text="Schedule tools")
row1 = col.row(align=True)
row1.alignment = "RIGHT"
row1.operator(
"bim.generate_gantt_chart", text="Generate Gantt", icon="NLA"
).work_schedule = work_schedule_id
row1.operator("bim.generate_gantt_chart", text="Generate Gantt", icon="NLA").work_schedule = (
work_schedule_id
)
row1.operator(
"bim.recalculate_schedule", text="Re-calculate Schedule", icon="FILE_REFRESH"
).work_schedule = work_schedule_id
@@ -226,9 +226,9 @@ class BIM_PT_work_schedules(Panel):
)
col2 = grid.column()
row = col2.row(align=True)
row.operator(
"bim.enable_editing_work_schedule_tasks", text="Tasks", icon="ACTION"
).work_schedule = work_schedule_id
row.operator("bim.enable_editing_work_schedule_tasks", text="Tasks", icon="ACTION").work_schedule = (
work_schedule_id
)
row.operator(
"bim.enable_editing_work_schedule", text="Attributes", icon="GREASEPENCIL"
).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.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_calendar", text="", icon="VIEW_ORTHO"
).task = ifc_definition_id
row2.operator(
"bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL"
).task = ifc_definition_id
row2.operator("bim.enable_editing_task_calendar", text="", icon="VIEW_ORTHO").task = (
ifc_definition_id
)
row2.operator("bim.enable_editing_task_attributes", text="", icon="GREASEPENCIL").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.remove_task", text="Delete", icon="X").task = ifc_definition_id
@@ -876,13 +876,13 @@ class BIM_UL_tasks(UIList):
row.label(text="", icon="BLANK1")
if item.has_children:
if item.is_expanded:
row.operator(
"bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
).task = item.ifc_definition_id
row.operator("bim.contract_task", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN").task = (
item.ifc_definition_id
)
else:
row.operator(
"bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
).task = item.ifc_definition_id
row.operator("bim.expand_task", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT").task = (
item.ifc_definition_id
)
else:
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.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties)
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():
@@ -109,7 +109,7 @@ class BIM_PT_spatial_decomposition(Panel):
SpatialDecompositionData.load()
self.props = context.scene.BIMSpatialDecompositionProperties
if SpatialDecompositionData.data['default_container']:
if SpatialDecompositionData.data["default_container"]:
row = self.layout.row(align=True)
row.label(
text=f"Default: {SpatialDecompositionData.data['default_container']}",
@@ -226,7 +226,7 @@ class StructuralLoadsData:
cls.data = {
"total_loads": cls.total_loads(),
"load_classes": cls.load_classes(),
"structural_load_types": cls.structural_load_types()
"structural_load_types": cls.structural_load_types(),
}
cls.is_loaded = True
@@ -42,9 +42,9 @@ def get_applicable_structural_load_types(self, context):
def updateApplicableStructuralLoadTypes(self, context):
StructuralLoadCasesData.data[
"applicable_structural_load_types"
] = StructuralLoadCasesData.applicable_structural_load_types()
StructuralLoadCasesData.data["applicable_structural_load_types"] = (
StructuralLoadCasesData.applicable_structural_load_types()
)
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:
row.operator("bim.remove_structural_load_case", text="", icon="X").load_case = load_case["id"]
else:
row.operator(
"bim.enable_editing_structural_load_case_groups", text="", icon="GHOST_ENABLED"
).load_case = load_case["id"]
row.operator("bim.enable_editing_structural_load_case_groups", text="", icon="GHOST_ENABLED").load_case = (
load_case["id"]
)
row.operator("bim.enable_editing_structural_load_case", text="", icon="GREASEPENCIL").load_case = load_case[
"id"
]
@@ -547,9 +547,9 @@ class BIM_PT_boundary_conditions(Panel):
row = self.layout.row(align=True)
prop_with_search(row, self.props, "boundary_condition_types", text="")
row.operator(
"bim.add_boundary_condition", text="", icon="ADD"
).ifc_class = self.props.boundary_condition_types
row.operator("bim.add_boundary_condition", text="", icon="ADD").ifc_class = (
self.props.boundary_condition_types
)
else:
row.operator("bim.load_boundary_conditions", text="", icon="GREASEPENCIL")
@@ -191,9 +191,9 @@ class BIM_PT_ports(Panel):
if 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[4].operator(
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF"
).ifc_id = connected_obj.BIMObjectProperties.ifc_definition_id
cols[4].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
connected_obj.BIMObjectProperties.ifc_definition_id
)
cols[5].label(text=connected_obj_name)
else:
cols[3].label(text="", icon="UNLINKED")
@@ -248,9 +248,9 @@ class BIM_PT_port(Panel):
relating_object = bpy.data.objects[relating_object_name]
row.label(text="Port located on:")
row.label(text=relating_object_name)
row.operator(
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF"
).ifc_id = relating_object.BIMObjectProperties.ifc_definition_id
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
relating_object.BIMObjectProperties.ifc_definition_id
)
# object connected to the port
row = layout.row(align=True)
@@ -259,9 +259,9 @@ class BIM_PT_port(Panel):
connected_object = bpy.data.objects[connected_object_name]
row.label(text="Port connected to:")
row.label(text=connected_object_name)
row.operator(
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF"
).ifc_id = connected_object.BIMObjectProperties.ifc_definition_id
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
connected_object.BIMObjectProperties.ifc_definition_id
)
else:
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_element = flow_element_id
op.assign = False
row.operator(
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF"
).ifc_id = displayed_object.BIMObjectProperties.ifc_definition_id
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
displayed_object.BIMObjectProperties.ifc_definition_id
)
row.label(text=f"{displayed_object_name}")
element = tool.Ifc.get_entity(context.active_object)
@@ -32,7 +32,7 @@ classes = (
prop.IfcTesterProperties,
ui.BIM_PT_tester,
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():
del bpy.types.Scene.IfcTesterProperties
@@ -98,7 +98,7 @@ class BIM_PT_tester(Panel):
row = box.row(align=True)
row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL")
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")
op.spec_index = props.active_specification_index
op.req_index = i
@@ -88,7 +88,7 @@ class BIM_PT_type(Panel):
if TypeData.data["relating_type"]:
row.label(text=TypeData.data["relating_type"]["name"])
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.enable_editing_type", icon="GREASEPENCIL", 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)
return {"RUNNING_MODAL"}
class MultipleFileSelector(bpy.types.Operator):
bl_label = "Select Multiple Files"
bl_options = {"REGISTER", "UNDO"}
@@ -156,11 +157,11 @@ class MultipleFileSelector(bpy.types.Operator):
new.name = os.path.join(dirname, f.name)
setattr(props, single_file, self.filepath)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectIfcFile(bpy.types.Operator, IFCFileSelector):
bl_idname = "bim.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)
if aggregator.has_physical_body_representation(relating_object):
raise AggregateRepresentationError
rel = ifc.run(
"aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=relating_object
)
rel = ifc.run("aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=relating_object)
collector.assign(relating_obj)
collector.assign(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:
feeds = brick.get_element_feeds(element)
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()
+1
View File
@@ -40,6 +40,7 @@
# described in regular sentences in under 50 lines. That is the purpose of the
# core.
# 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
# one tool.
+8 -1
View File
@@ -25,7 +25,14 @@ if TYPE_CHECKING:
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():
return
+4 -3
View File
@@ -149,7 +149,10 @@ class Brick(blenderbim.core.tool.Brick):
<{brick_uri}> rdfs:label ?label .
}
LIMIT 1
""".replace("{brick_uri}", brick_uri))
""".replace(
"{brick_uri}", brick_uri
)
)
name = None
for row in query:
name = str(row.get("label"))
@@ -442,8 +445,6 @@ class Brick(blenderbim.core.tool.Brick):
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
class BrickStore:
schema = None # this is now a os path
path = None # file path if the project was loaded in
@@ -30,12 +30,14 @@ from math import pi
from mathutils import Vector, Matrix
from shapely import Polygon, MultiPolygon
class Covering(blenderbim.core.tool.Covering):
@classmethod
def get_z_from_ceiling_height(cls):
props = bpy.context.scene.BIMCoveringProperties
return props.ceiling_height
# def toggle_spaces_visibility_wired_and_textured(cls, spaces):
# first_obj = tool.Ifc.get_object(spaces[0])
# if bpy.data.objects[first_obj.name].display_type == "TEXTURED":
+1
View File
@@ -13,6 +13,7 @@ try:
except ImportError:
print("Warning: GitPython not available.")
class IfcGit:
@classmethod
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"]
class Qto(blenderbim.core.tool.Qto):
@classmethod
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.
#
import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
@@ -103,7 +104,7 @@ html_theme_options = {
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"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": {
"color-brand-primary": "#39b54a",
@@ -118,9 +119,8 @@ html_theme_options = {
"color-link--hover": "#d98014",
"color-link--visited--hover": "#d98014",
"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": [
{
"name": "IfcOpenShell",
@@ -1,5 +1,6 @@
try:
import bpy
# Ensure it's not fake-bpy-module.
if not hasattr(bpy, "context"):
raise ModuleNotFoundError
@@ -1,23 +1,27 @@
import ifcopenshell
from brickschema.graph import Graph
class Generator():
class Generator:
def __init__(self):
self.file = ifcopenshell.file(schema='IFC4')
self.file = ifcopenshell.file(schema="IFC4")
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):
classification = self.file.create_entity('IfcClassification', **{
'Source': 'Brick',
'Edition': 'August-11',
'EditionDate': '2023-08-11',
'Name': 'Brick',
'Description': '',
'Location': 'https://brickschema.org/schema/Brick',
'ReferenceTokens': []
})
classification = self.file.create_entity(
"IfcClassification",
**{
"Source": "Brick",
"Edition": "August-11",
"EditionDate": "2023-08-11",
"Name": "Brick",
"Description": "",
"Location": "https://brickschema.org/schema/Brick",
"ReferenceTokens": [],
}
)
query = self.schema.query(
"""
PREFIX brick: <https://brickschema.org/schema/Brick#>
@@ -54,11 +58,11 @@ class Generator():
for row in query:
# location is the entity URI
location = row.get("entity")
# description is the entity's definition
description = row.get("definition")
if not description:
description = ''
description = ""
# name is the entity's label if it exists, else the name in the URI
name = row.get("label")
@@ -66,13 +70,11 @@ class Generator():
name = location.split("#")[-1].replace("_", " ")
# create the reference
ref = self.file.create_entity('IfcClassificationReference', **{
'Location': location,
'Description': description,
'Identification': name,
'Name': name
})
ref = self.file.create_entity(
"IfcClassificationReference",
**{"Location": location, "Description": description, "Identification": name, "Name": name}
)
# get all parents of the entity
query = self.schema.query(
"""
@@ -88,7 +90,7 @@ class Generator():
# filter parents for the brick entity
for row in query:
parent = row.get("parent").toPython()
if "brickschema.org" in parent and parent in references.keys():
if "brickschema.org" in parent and parent in references.keys():
# some parents are not a brick type, so those should be ignored
# some entities have multiple parents that are a brick type
# since the query traverses down the graph, we can assume at least one parent has been seen, so pick that one
@@ -96,7 +98,7 @@ class Generator():
break
parent = None
# assign reference source
# assign reference source
if parent:
ref.ReferencedSource = references[parent]
else:
@@ -105,7 +107,8 @@ class Generator():
# save this reference for future reference sources
references[location.toPython()] = ref
self.file.write('Brick.ifc')
self.file.write("Brick.ifc")
generator = Generator()
generator.generate()
generator.generate()
+28 -23
View File
@@ -1,30 +1,35 @@
import csv
import os
import json
#import pystache
# import pystache
import subprocess
import ifcopenshell
from pathlib import Path
class Generator():
class Generator:
def __init__(self):
self.file = ifcopenshell.file(schema='IFC4')
self.out_dir = './'
self.file = ifcopenshell.file(schema="IFC4")
self.out_dir = "./"
def generate(self):
classification = self.file.create_entity('IfcClassification', **{
'Source': 'VBIS',
'Edition': 'May-20',
'EditionDate': '2020-05-01',
'Name': 'VBIS',
'Description': '',
'Location': 'https://vbis.com.au/',
'ReferenceTokens': ['-']
})
classification = self.file.create_entity(
"IfcClassification",
**{
"Source": "VBIS",
"Edition": "May-20",
"EditionDate": "2020-05-01",
"Name": "VBIS",
"Description": "",
"Location": "https://vbis.com.au/",
"ReferenceTokens": ["-"],
}
)
# We assume all the Excel spreadsheets are re-exported in CSV format
for filename in Path('./').glob('*.csv'):
with open(filename, newline='') as csvfile:
reader = csv.reader(csvfile, delimiter=',', quotechar='"')
for filename in Path("./").glob("*.csv"):
with open(filename, newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",", quotechar='"')
name = None
levels = [None, None, None, None]
ref = classification
@@ -39,17 +44,17 @@ class Generator():
name = row[2]
elif row[3]:
name = row[3]
ref = self.file.create_entity('IfcClassificationReference', **{
'Identification': row[4],
'Name': name
})
cur_level = len(row[4].split('-')) - 1
ref = self.file.create_entity(
"IfcClassificationReference", **{"Identification": row[4], "Name": name}
)
cur_level = len(row[4].split("-")) - 1
levels[cur_level] = ref
if cur_level == 0:
ref.ReferencedSource = classification
else:
ref.ReferencedSource = levels[cur_level-1]
self.file.write('VBIS.ifc')
ref.ReferencedSource = levels[cur_level - 1]
self.file.write("VBIS.ifc")
generator = Generator()
generator.generate()
@@ -7,86 +7,92 @@ import ifcopenshell
import ifcopenshell.guid
import os
class IFC4Extractor:
def __init__(self, xml_file):
self.xml_file = xml_file
self.tree = ET.parse(self.xml_file)
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.data = {
'BB/SfB (3/4 cijfers)': {'source': 'Regie der Gebouwen', 'tokens': ['.']},
'BIMTypeCode': {'source': 'BIMStockholm', 'tokens': None},
'Common Arrangement of Work Sections (CAWS)': {'source': 'NBS', 'tokens': ['/']},
'CBI Classification - Level 2': {'source': 'Masterspec', 'tokens': None},
'CBI Classification - Level 4': {'source': 'Masterspec', 'tokens': None},
'Rumsfunktionskoder CC001 - 001': {'source': 'BIMAlliance', 'tokens': ['-']},
'CCS': {'source': 'Molio', 'tokens': None},
'CCTB': {'source': 'CCT-Bâtiments', 'tokens': ['.']},
'Funktionskoder Regionservice CD001 - 001': {'source': 'BIMAlliance', 'tokens': None},
'Rumsfunktion Blekinge CD002 - 001': {'source': 'BIMAlliance', 'tokens': None},
'EcoQuaestor Codetabel': {'source': 'EcoQuaestor', 'tokens': ['.', '-']},
'GuBIMclass CA': {'source': 'GuBIMClass', 'tokens': ['.']},
'GuBIMclass ES': {'source': 'GuBIMClass', 'tokens': ['.']},
'MasterFormat': {'source': 'CSI', 'tokens': [' ', '.']},
'NATSPEC Worksections': {'source': 'NATSPEC', 'tokens': None},
'NBS Create': {'source': 'NBS', 'tokens': ['_', '/']},
'NL/SfB (4 cijfers)': {'source': 'BIMLoket', 'tokens': ['.']},
'NS 3451 - Bygningsdelstabell': {'source': 'Standard Norge', 'tokens': None},
'OmniClass': {'source': 'OmniClass', 'tokens': ['-', ' ']},
'ÖNORM 6241-2': {'source': 'freeBIM 2', 'tokens': None},
'RICS NRM1': {'source': 'RICS', 'tokens': ['.']},
'RICS NRM3': {'source': 'RICS', 'tokens': ['.']},
'SFG20': {'source': 'SFG20', 'tokens': ['-']},
'SINAPI': {'source': 'Caixa', 'tokens': ['/']},
'STABU-Element': {'source': 'STABU', 'tokens': ['.']},
'TALO 2000 Building Component Classification': {'source': 'Rakennustieto', 'tokens': ['.']},
'TALO 2000 Hankenimikkeistö': {'source': 'Rakennustieto', 'tokens': ['.']},
'Uniclass': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']},
'Uniclass 2015': {'source': 'RIBA Enterprises Ltd', 'tokens': ['_']},
'UniFormat': {'source': 'UniFormat', 'tokens': ['.']},
'Uniformat': {'source': 'UniFormat', 'tokens': ['.']},
'VMSW': {'source': 'VMSW', 'tokens': ['.']}
"BB/SfB (3/4 cijfers)": {"source": "Regie der Gebouwen", "tokens": ["."]},
"BIMTypeCode": {"source": "BIMStockholm", "tokens": None},
"Common Arrangement of Work Sections (CAWS)": {"source": "NBS", "tokens": ["/"]},
"CBI Classification - Level 2": {"source": "Masterspec", "tokens": None},
"CBI Classification - Level 4": {"source": "Masterspec", "tokens": None},
"Rumsfunktionskoder CC001 - 001": {"source": "BIMAlliance", "tokens": ["-"]},
"CCS": {"source": "Molio", "tokens": None},
"CCTB": {"source": "CCT-Bâtiments", "tokens": ["."]},
"Funktionskoder Regionservice CD001 - 001": {"source": "BIMAlliance", "tokens": None},
"Rumsfunktion Blekinge CD002 - 001": {"source": "BIMAlliance", "tokens": None},
"EcoQuaestor Codetabel": {"source": "EcoQuaestor", "tokens": [".", "-"]},
"GuBIMclass CA": {"source": "GuBIMClass", "tokens": ["."]},
"GuBIMclass ES": {"source": "GuBIMClass", "tokens": ["."]},
"MasterFormat": {"source": "CSI", "tokens": [" ", "."]},
"NATSPEC Worksections": {"source": "NATSPEC", "tokens": None},
"NBS Create": {"source": "NBS", "tokens": ["_", "/"]},
"NL/SfB (4 cijfers)": {"source": "BIMLoket", "tokens": ["."]},
"NS 3451 - Bygningsdelstabell": {"source": "Standard Norge", "tokens": None},
"OmniClass": {"source": "OmniClass", "tokens": ["-", " "]},
"ÖNORM 6241-2": {"source": "freeBIM 2", "tokens": None},
"RICS NRM1": {"source": "RICS", "tokens": ["."]},
"RICS NRM3": {"source": "RICS", "tokens": ["."]},
"SFG20": {"source": "SFG20", "tokens": ["-"]},
"SINAPI": {"source": "Caixa", "tokens": ["/"]},
"STABU-Element": {"source": "STABU", "tokens": ["."]},
"TALO 2000 Building Component Classification": {"source": "Rakennustieto", "tokens": ["."]},
"TALO 2000 Hankenimikkeistö": {"source": "Rakennustieto", "tokens": ["."]},
"Uniclass": {"source": "RIBA Enterprises Ltd", "tokens": ["_"]},
"Uniclass 2015": {"source": "RIBA Enterprises Ltd", "tokens": ["_"]},
"UniFormat": {"source": "UniFormat", "tokens": ["."]},
"Uniformat": {"source": "UniFormat", "tokens": ["."]},
"VMSW": {"source": "VMSW", "tokens": ["."]},
}
def extract(self):
for system in self.tree.findall('Classification/System'):
project = self.file.create_entity('IfcProjectLibrary', Name=system.find('Name').text)
parent = self.file.create_entity('IfcClassification', **{
'Source': self.data[system.find('Name').text]['source'],
'Edition': system.find('EditionVersion').text,
'EditionDate': self.get_edition_date(system),
'Name': system.find('Name').text,
'Description': system.find('Description').text,
'Location': system.find('Source').text,
'ReferenceTokens': self.data[system.find('Name').text]['tokens']
})
self.file.createIfcRelAssociatesClassification(
ifcopenshell.guid.new(), None, None, None, [project], parent)
children = system.findall('Items/Item')
for system in self.tree.findall("Classification/System"):
project = self.file.create_entity("IfcProjectLibrary", Name=system.find("Name").text)
parent = self.file.create_entity(
"IfcClassification",
**{
"Source": self.data[system.find("Name").text]["source"],
"Edition": system.find("EditionVersion").text,
"EditionDate": self.get_edition_date(system),
"Name": system.find("Name").text,
"Description": system.find("Description").text,
"Location": system.find("Source").text,
"ReferenceTokens": self.data[system.find("Name").text]["tokens"],
},
)
self.file.createIfcRelAssociatesClassification(ifcopenshell.guid.new(), None, None, None, [project], parent)
children = system.findall("Items/Item")
self.get_children(children, parent)
def get_children(self, children, parent):
for child in children:
reference = self.file.create_entity('IfcClassificationReference', **{
'Identification': child.find('ID').text,
'Name': child.find('Name').text,
'ReferencedSource': parent,
'Description': child.find('Description').text
})
children = child.find('Children')
reference = self.file.create_entity(
"IfcClassificationReference",
**{
"Identification": child.find("ID").text,
"Name": child.find("Name").text,
"ReferencedSource": parent,
"Description": child.find("Description").text,
},
)
children = child.find("Children")
if children:
self.get_children(children, reference)
def get_edition_date(self, system):
d = system.find('EditionDate')
return '{}-{:02}-{:02}'.format(
d.find('Year').text, int(d.find('Month').text), int(d.find('Day').text))
d = system.find("EditionDate")
return "{}-{:02}-{:02}".format(d.find("Year").text, int(d.find("Month").text), int(d.find("Day").text))
def export(self, 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.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("THICK", "thick")
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("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("TYPE-TAG", "capsule-tag", ["{{type.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((1.0, 0.0, 0.0)),
)
items.append(self.file.createIfcTextLiteralWithExtent(
literal, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), "center"
))
items.append(
self.file.createIfcTextLiteralWithExtent(
literal, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), "center"
)
)
representation = self.file.createIfcShapeRepresentation(
self.representations["model_annotation"],
@@ -205,22 +213,30 @@ class LibraryGenerator:
def create_layer_type(self, ifc_class, name, thickness):
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 = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.material)
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
def create_profile_type(self, ifc_class, name, profile):
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
material_profile = ifcopenshell.api.run(
"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("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):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
@@ -252,7 +268,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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()
@@ -131,7 +131,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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__":
@@ -244,7 +244,9 @@ class LibraryGenerator:
polyline = builder.polyline((V(0, 0), V(width, 0)))
_, _, 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([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)
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)
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)
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
overall_width, overall_depth, overall_height = (1600.0, 700.0, 550.0)
representation_3d, representation_2d = create_shower_or_bathtube(
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)
representation_3d, representation_2d = create_shower_or_bathtube(
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)
representation_3d, representation_2d = create_shower_or_bathtube(
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):
shift_to_center = V(-width / 2, 0)
@@ -1130,9 +1144,7 @@ class LibraryGenerator:
back_wall = builder.rectangle(V(width, height))
# example of rotating and extruding by Y axis btw
back_wall_extruded = builder.extrude(
back_wall,
back_wall_depth + back_wall_border_mask_depth,
**builder.extrude_kwargs("Y")
back_wall, back_wall_depth + back_wall_border_mask_depth, **builder.extrude_kwargs("Y")
)
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)
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)
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)
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):
second_width = 0.9 * width
@@ -1251,19 +1269,27 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (450.0, 400.0, 250.0)
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)
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)
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)
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):
leg_width = 50.0
@@ -1421,7 +1447,9 @@ class LibraryGenerator:
overall_width, overall_depth, overall_height = (500.0, 570.0, 820.0)
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):
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)
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)
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)
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)
representation_3d, representation_2d = create_box_objects(
@@ -1520,7 +1554,9 @@ class LibraryGenerator:
representation_3d, representation_2d = create_box_objects(
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)
representation_3d, representation_2d = create_box_objects(
@@ -1534,7 +1570,9 @@ class LibraryGenerator:
representation_3d, representation_2d = create_box_objects(
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):
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)
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):
items_3d, items_2d = create_box_objects(width, depth, height)
@@ -1797,13 +1837,17 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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
def create_layer_set_type(self, name, data):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name)
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
for layer_data in data["Layers"]:
layer = ifcopenshell.api.run(
@@ -1811,33 +1855,43 @@ class LibraryGenerator:
)
layer.Name = layer_data[0]
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
def create_layer_type(self, ifc_class, name, thickness):
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 = ifcopenshell.api.run(
"material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"]
)
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
def create_profile_type(self, ifc_class, name, profile):
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
material_profile = ifcopenshell.api.run(
"material.add_profile",
self.file,
profile_set=profile_set,
material=self.material
material=self.material,
# material=self.materials["TBD"]["ifc"]
)
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):
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name)
@@ -1869,7 +1923,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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__":
@@ -394,9 +394,9 @@ class LibraryGenerator:
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 (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 Medium (12m)", "low_poly", (12.0, 10.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 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, 0.8, 2.0, 0.4, 20)),
TreeData("Tree Big (20m)", "low_poly", (20.0, 15.0, 0.0, 0.8, 4.0, 0.6, 30)),
]
for tree_data in trees:
@@ -409,7 +409,7 @@ class LibraryGenerator:
# 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)
for i, row in enumerate(reader):
if i == 0:
@@ -418,9 +418,7 @@ class LibraryGenerator:
data = [float(x) for x in row[2:]]
preset_data = preset.preset_class(*data)._asdict()
tree_geometry = preset.generator(builder, **preset_data)
self.create_explicit_type(
"IfcGeographicElementType", row[1], **self.get_representations(tree_geometry)
)
self.create_explicit_type("IfcGeographicElementType", row[1], **self.get_representations(tree_geometry))
self.file.write(output_filename)
@@ -447,7 +445,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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
def create_type(self, ifc_class, name, representations):
@@ -480,8 +480,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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__":
@@ -98,7 +98,9 @@ class LibraryGenerator:
ifcopenshell.api.run(
"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()
+6 -6
View File
@@ -12,12 +12,12 @@ props = bpy.context.scene.BIMGeoreferenceProperties
# georeferencing coordinates in the IFC Georeferencing panel before filling out
# these details.
#props.blender_eastings = '334134181.0'
#props.blender_northings = '6254570511.0'
#props.blender_orthogonal_height = '0.0'
#props.blender_x_axis_abscissa = '0.147487884244522'
#props.blender_x_axis_ordinate = '0.989063862448262'
#props.has_blender_offset = True
# props.blender_eastings = '334134181.0'
# props.blender_northings = '6254570511.0'
# props.blender_orthogonal_height = '0.0'
# props.blender_x_axis_abscissa = '0.147487884244522'
# props.blender_x_axis_ordinate = '0.989063862448262'
# props.has_blender_offset = True
props = bpy.context.scene.BIMProjectProperties
+18 -14
View File
@@ -40,26 +40,30 @@ if not file:
print("No ifc file")
sys.exit()
annotations = file.by_type('IfcAnnotation')
annotations = file.by_type("IfcAnnotation")
count = 0
for annotation in annotations:
if annotation.ObjectType == 'DRAWING':
if annotation.ObjectType == "DRAWING":
psets = ifcopenshell.util.element.get_psets(annotation)
pset = psets['EPset_Drawing']
pset_ifc = file.by_id(pset['id'])
pset = psets["EPset_Drawing"]
pset_ifc = file.by_id(pset["id"])
wrong_sep = ""
if platform == 'linux' or platform == 'linux2' or platform == 'darwin':
if platform == "linux" or platform == "linux2" or platform == "darwin":
wrong_sep = "\\"
if platform == 'win32':
if platform == "win32":
wrong_sep = "/"
ifcopenshell.api.run("pset.edit_pset", file, pset = pset_ifc, properties = {
'Stylesheet' : pset['Stylesheet'].replace(wrong_sep, os.path.sep),
'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
ifcopenshell.api.run(
"pset.edit_pset",
file,
pset=pset_ifc,
properties={
"Stylesheet": pset["Stylesheet"].replace(wrong_sep, os.path.sep),
"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")
@@ -9,7 +9,7 @@ V = lambda *x: Vector([float(i) for i in x])
def simple_uses():
ifc_file = ifcopenshell.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)
rectangle_curve = builder.rectangle()
@@ -18,26 +18,19 @@ def simple_uses():
circle_curve = builder.circle()
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)
rotated_triangle = builder.rotate(triangle_curve, 90,
pivot_point=Vector( (1., 1.) ),
counter_clockwise=True,
create_copy=True)
rotated_triangle = builder.rotate(
triangle_curve, 90, pivot_point=Vector((1.0, 1.0)), counter_clockwise=True, create_copy=True
)
print(rotated_triangle)
a, b = builder.translate(
[rectangle_curve, circle_curve],
Vector( (5., 5.) ), create_copy=True)
a, b = builder.translate([rectangle_curve, circle_curve], Vector((5.0, 5.0)), create_copy=True)
print(f"Multiple translated objects: {a}, {b}")
c, d = builder.rotate(
[a, b], 90,
pivot_point=Vector( (0., 0.) ),
counter_clockwise=False,
create_copy=True)
print(f'Multiple rotated objects: {c}, {d}')
c, d = builder.rotate([a, b], 90, pivot_point=Vector((0.0, 0.0)), counter_clockwise=False, create_copy=True)
print(f"Multiple rotated objects: {c}, {d}")
mirrored_objects = builder.mirror(
[a, b],
@@ -57,8 +50,7 @@ def simple_uses():
print(rotated_circle)
profile = builder.profile(
rectangle_curve, "test_profile",
inner_curves=[builder.circle(center=Vector((0.5, 0.5)), radius=0.2)]
rectangle_curve, "test_profile", inner_curves=[builder.circle(center=Vector((0.5, 0.5)), radius=0.2)]
)
print(profile)
@@ -129,20 +121,14 @@ def mirror_placement_test():
rect_profile = builder.profile(rect, inner_curves=rect_small)
pl = builder.extrude(rect_profile,
magnitude=7.0,
position_z_axis=V(0, -1, 0),
extrusion_vector=V(0, 0, -1),
position=V(0, 5, 0)
pl = builder.extrude(
rect_profile, magnitude=7.0, position_z_axis=V(0, -1, 0), extrusion_vector=V(0, 0, -1), position=V(0, 5, 0)
)
rect = builder.rectangle(size=size)
back_wall = builder.extrude(rect,
magnitude=2.0,
position_z_axis=V(0, -1, 0),
extrusion_vector=V(0, 0, -1),
position=V(0, 1, 0)
back_wall = builder.extrude(
rect, magnitude=2.0, position_z_axis=V(0, -1, 0), extrusion_vector=V(0, 0, -1), position=V(0, 1, 0)
)
items_3d = [pl, back_wall]
@@ -195,20 +181,18 @@ def curve_between_two_points_test():
width, depth = (200.0, 200.0)
curve_coords = (
(V(0, depth), V(-width, 0)), # ccw
(V(0, depth), V(width, 0)), # cw
(V(0, -depth), V(width, 0)), # ccw
(V(0, -depth), V(-width, 0)), # cw
(V(+width/2, 0), V(0, depth)), # ccw
(V(-width/2, 0), V(0, depth)), # cw
(V(-width/2, 0), V(0, -depth)), # ccw
(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)), # ccw
(V(0, -depth/2), V(-width, 0)), # cw
(V(0, depth), V(-width, 0)), # ccw
(V(0, depth), V(width, 0)), # cw
(V(0, -depth), V(width, 0)), # ccw
(V(0, -depth), V(-width, 0)), # cw
(V(+width / 2, 0), V(0, depth)), # ccw
(V(-width / 2, 0), V(0, depth)), # cw
(V(-width / 2, 0), V(0, -depth)), # ccw
(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)), # ccw
(V(0, -depth / 2), V(-width, 0)), # cw
)
items_2d = [builder.curve_between_two_points(c) for c in curve_coords]
@@ -6,7 +6,7 @@ import multiprocessing
class BlenderImporter:
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.should_use_cpu_multiprocessing = True
self.deflection_tolerance = 0.001
@@ -77,9 +77,7 @@ class BlenderImporter:
return results
settings = self.settings_2d if is_curve else self.settings
if self.should_use_cpu_multiprocessing:
iterator = ifcopenshell.geom.iterator(
settings, self.file, multiprocessing.cpu_count(), include=products
)
iterator = ifcopenshell.geom.iterator(settings, self.file, multiprocessing.cpu_count(), include=products)
else:
iterator = ifcopenshell.geom.iterator(settings, self.file, include=products)
cache = self.get_cache()
@@ -120,4 +118,5 @@ class BlenderImporter:
except:
return
BlenderImporter().execute()
+1 -1
View File
@@ -681,7 +681,7 @@ def prop_is_roughly_value(prop, value):
def the_object_name_has_a_cartesian_point_offset_of_offset(name, offset):
offset = replace_variables(offset)
obj = the_object_name_exists(name)
assert obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT"
assert obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT"
obj_offset = np.array(tuple(map(float, obj.BIMObjectProperties.cartesian_point_offset.split(","))))
offset = np.array(tuple(map(float, offset.split(","))))
assert np.allclose(obj_offset, offset)
+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_refresh_brick_viewer().should_be_called()
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):
brick.add_brick("namespace", "brick_class", "label").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:
@@ -197,24 +205,42 @@ class TestConvertIfcToBrick:
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.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.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.add_relation("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.add_relation(
"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.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.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.add_relation("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.add_relation(
"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("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()
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.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
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.rename_object("new_data", "name").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.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation")
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.rename_object("new_data", "name").should_be_called()
geometry.link("representation", "new_data").should_be_called()
+3 -1
View File
@@ -30,7 +30,9 @@ class TestReferenceStructure:
class TestDereferenceStructure:
def test_run(self, ifc, spatial):
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")
+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("AREAUNIT").should_be_called().will_return("prefix")
unit.get_scene_unit_si_prefix("VOLUMEUNIT").should_be_called().will_return("prefix")
ifc.run(
"unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix"
).should_be_called().will_return("lengthunit")
ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", prefix="prefix").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="VOLUMEUNIT", prefix="prefix"
).should_be_called().will_return("volumeunit")
ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", prefix="prefix").should_be_called().will_return(
"volumeunit"
)
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_item.Material = material
assert subject.is_material_used_in_sets(material) is True
+3 -1
View File
@@ -448,7 +448,9 @@ class TestUsingArrays(NewFile):
class TestApplyIfcMaterialChanges(NewFile):
def get_used_styles(self, obj: bpy.types.Object) -> set[ifcopenshell.entity_instance]:
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:
mesh = obj.data
+8 -1
View File
@@ -104,7 +104,14 @@ class TestSetDefaultContext(NewFile):
tool.Ifc.set(ifc)
ifc.createIfcProject()
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()
assert bpy.context.scene.BIMRootProperties.contexts == str(body.id())