Merge branch 'IfcOpenShell:v0.8.0' into fix-5563

This commit is contained in:
sboddy
2025-06-25 23:46:42 +01:00
committed by GitHub
32 changed files with 1215 additions and 1014 deletions
@@ -0,0 +1 @@
SVG [mustache](https://mustache.github.io/) templates that will be used for sheets and fill be filled with infromation from the sheet's IfcDocumentInformation attributes (e.g. Identification, Name, Revision, etc).
@@ -1734,7 +1734,7 @@ class OpenLayout(bpy.types.Operator, tool.Ifc.Operator):
class SelectAllSheets(bpy.types.Operator): class SelectAllSheets(bpy.types.Operator):
bl_idname = "bim.select_all_sheets" bl_idname = "bim.select_all_sheets"
bl_label = "Select All Sheetss" bl_label = "Select All Sheets"
view: bpy.props.StringProperty() view: bpy.props.StringProperty()
bl_description = "Select all sheets in the sheet list.\n\n" + "SHIFT+CLICK to deselect all sheets" bl_description = "Select all sheets in the sheet list.\n\n" + "SHIFT+CLICK to deselect all sheets"
select_all: bpy.props.BoolProperty(name="Open All", default=True, options={"SKIP_SAVE"}) select_all: bpy.props.BoolProperty(name="Open All", default=True, options={"SKIP_SAVE"})
+45 -36
View File
@@ -61,8 +61,8 @@ class SheetBuilder:
shutil.copy(ootb_titleblock_path, titleblock_path) shutil.copy(ootb_titleblock_path, titleblock_path)
view_root = ET.parse(titleblock_path).getroot() view_root = ET.parse(titleblock_path).getroot()
view_width = self.convert_to_mm(view_root.attrib.get("width")) view_width = self.convert_to_mm(view_root.attrib["width"])
view_height = self.convert_to_mm(view_root.attrib.get("height")) view_height = self.convert_to_mm(view_root.attrib["height"])
view = ET.SubElement(root, "g") view = ET.SubElement(root, "g")
view.attrib["data-type"] = "titleblock" view.attrib["data-type"] = "titleblock"
titleblock = ET.SubElement(view, "image") titleblock = ET.SubElement(view, "image")
@@ -87,6 +87,7 @@ class SheetBuilder:
) -> None: ) -> None:
filename = drawing.Name filename = drawing.Name
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
assert layout_path
layout_dir = os.path.dirname(layout_path) layout_dir = os.path.dirname(layout_path)
drawing_path = tool.Drawing.get_document_uri(tool.Drawing.get_drawing_reference(drawing)) drawing_path = tool.Drawing.get_document_uri(tool.Drawing.get_drawing_reference(drawing))
@@ -110,8 +111,8 @@ class SheetBuilder:
view.attrib["data-type"] = "drawing" view.attrib["data-type"] = "drawing"
view.attrib["data-id"] = str(reference.id()) view.attrib["data-id"] = str(reference.id())
view.attrib["data-drawing"] = drawing.GlobalId view.attrib["data-drawing"] = drawing.GlobalId
view_width = self.convert_to_mm(view_root.attrib.get("width")) view_width = self.convert_to_mm(view_root.attrib["width"])
view_height = self.convert_to_mm(view_root.attrib.get("height")) view_height = self.convert_to_mm(view_root.attrib["height"])
x, y = self.next_drawing_location(layout_root, view_width) x, y = self.next_drawing_location(layout_root, view_width)
@@ -134,16 +135,16 @@ class SheetBuilder:
# how wide is the title block frame # how wide is the title block frame
try: try:
titleblock_width = self.convert_to_mm(titleblocks[0][0].attrib.get("width")) titleblock_width = self.convert_to_mm(titleblocks[0][0].attrib["width"])
except (IndexError, AttributeError): except (IndexError, AttributeError):
titleblock_width = 840.0 titleblock_width = 840.0
# where does the last drawing finish # where does the last drawing finish
try: try:
last = drawings[-1][0] last = drawings[-1][0]
last_width = self.convert_to_mm(last.attrib.get("width")) last_width = self.convert_to_mm(last.attrib["width"])
last_x = self.convert_to_mm(last.attrib.get("x")) last_x = self.convert_to_mm(last.attrib["x"])
last_y = self.convert_to_mm(last.attrib.get("y")) last_y = self.convert_to_mm(last.attrib["y"])
except (IndexError, AttributeError): except (IndexError, AttributeError):
return [DEFAULT_POSITION.x, DEFAULT_POSITION.y] return [DEFAULT_POSITION.x, DEFAULT_POSITION.y]
@@ -155,8 +156,8 @@ class SheetBuilder:
for drawing in drawings: for drawing in drawings:
for image in drawing: for image in drawing:
try: try:
image_y = self.convert_to_mm(image.attrib.get("y")) image_y = self.convert_to_mm(image.attrib["y"])
image_height = self.convert_to_mm(image.attrib.get("height")) image_height = self.convert_to_mm(image.attrib["height"])
except AttributeError: except AttributeError:
return [DEFAULT_POSITION.x, DEFAULT_POSITION.y] return [DEFAULT_POSITION.x, DEFAULT_POSITION.y]
if image_y + image_height + DRAWING_PADDING > last_y: if image_y + image_height + DRAWING_PADDING > last_y:
@@ -167,6 +168,7 @@ class SheetBuilder:
ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("", "http://www.w3.org/2000/svg")
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
assert layout_path
layout_tree = ET.parse(layout_path) layout_tree = ET.parse(layout_path)
layout_root = layout_tree.getroot() layout_root = layout_tree.getroot()
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
@@ -210,12 +212,13 @@ class SheetBuilder:
ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("", "http://www.w3.org/2000/svg")
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
assert layout_path
if not os.path.exists(layout_path): if not os.path.exists(layout_path):
return return
layout_tree = ET.parse(layout_path) layout_tree = ET.parse(layout_path)
layout_root = layout_tree.getroot() layout_root = layout_tree.getroot()
for g in layout_root.findall("{http://www.w3.org/2000/svg}g"): for g in layout_root.findall(f"{SVG}g"):
if g.attrib.get("data-id") == str(reference.id()): if g.attrib.get("data-id") == str(reference.id()):
layout_root.remove(g) layout_root.remove(g)
break break
@@ -233,6 +236,7 @@ class SheetBuilder:
tool.Drawing.create_svg_document(document) tool.Drawing.create_svg_document(document)
document_name = os.path.splitext(os.path.basename(view_path))[0] document_name = os.path.splitext(os.path.basename(view_path))[0]
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
assert layout_path
layout_dir = os.path.dirname(layout_path) layout_dir = os.path.dirname(layout_path)
ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("", "http://www.w3.org/2000/svg")
@@ -278,13 +282,14 @@ class SheetBuilder:
title.attrib["xlink:href"] = os.path.relpath(title_path, layout_dir) title.attrib["xlink:href"] = os.path.relpath(title_path, layout_dir)
title.attrib["x"] = str(x) title.attrib["x"] = str(x)
title.attrib["y"] = str(y) title.attrib["y"] = str(y)
title.attrib["width"] = str(self.convert_to_mm(title_root.attrib.get("width"))) title.attrib["width"] = str(self.convert_to_mm(title_root.attrib["width"]))
title.attrib["height"] = str(self.convert_to_mm(title_root.attrib.get("height"))) title.attrib["height"] = str(self.convert_to_mm(title_root.attrib["height"]))
def build(self, sheet: ifcopenshell.entity_instance) -> dict: def build(self, sheet: ifcopenshell.entity_instance) -> dict:
self.references = {"SHEET": None, "RASTER": []} self.references = {"SHEET": None, "RASTER": []}
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT") layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
assert layout_path
self.layout_dir = os.path.dirname(layout_path) self.layout_dir = os.path.dirname(layout_path)
sheet_path = tool.Ifc.resolve_uri(tool.Drawing.get_default_sheet_path(sheet[0], sheet.Name)) sheet_path = tool.Ifc.resolve_uri(tool.Drawing.get_default_sheet_path(sheet[0], sheet.Name))
@@ -313,14 +318,14 @@ class SheetBuilder:
return self.references return self.references
def build_titleblock(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: def build_titleblock(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None:
titleblock = root.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0] titleblock = root.findall(f'{SVG}g[@data-type="titleblock"]')[0]
image = titleblock.findall("{http://www.w3.org/2000/svg}image")[0] image = titleblock.findall(f"{SVG}image")[0]
g = self.parse_embedded_svg(image, sheet.get_info()) g = self.parse_embedded_svg(image, sheet.get_info())
grid_north = ifcopenshell.util.geolocation.get_grid_north(tool.Ifc.get()) * -1 grid_north = ifcopenshell.util.geolocation.get_grid_north(tool.Ifc.get()) * -1
true_north = ifcopenshell.util.geolocation.get_true_north(tool.Ifc.get()) * -1 true_north = ifcopenshell.util.geolocation.get_true_north(tool.Ifc.get()) * -1
for north in g.iterfind('.//{http://www.w3.org/2000/svg}g[@data-type="grid-north"]'): for north in g.iterfind(f'.//{SVG}g[@data-type="grid-north"]'):
north.attrib["transform"] = f"rotate({grid_north})" north.attrib["transform"] = f"rotate({grid_north})"
for north in g.iterfind('.//{http://www.w3.org/2000/svg}g[@data-type="true-north"]'): for north in g.iterfind(f'.//{SVG}g[@data-type="true-north"]'):
north.attrib["transform"] = f"rotate({true_north})" north.attrib["transform"] = f"rotate({true_north})"
titleblock.append(g) titleblock.append(g)
titleblock.remove(image) titleblock.remove(image)
@@ -333,7 +338,9 @@ class SheetBuilder:
# add .prefix class to all css selectors # add .prefix class to all css selectors
style = svg.find(f"{SVG}defs/{SVG}style") style = svg.find(f"{SVG}defs/{SVG}style")
assert style
style_data = style.text style_data = style.text
assert style_data is not None
text = "" text = ""
brackets_level = 0 brackets_level = 0
for l in style_data: for l in style_data:
@@ -374,6 +381,8 @@ class SheetBuilder:
if "filter" in attrib: if "filter" in attrib:
# example use "#fill-background" filter # example use "#fill-background" filter
attrib["filter"] = replace_urls(attrib["filter"]) attrib["filter"] = replace_urls(attrib["filter"])
if "style" in attrib:
attrib["style"] = replace_urls(attrib["style"])
if svg_element.tag == f"{SVG}use": if svg_element.tag == f"{SVG}use":
href_attrib = f"{XLINK}href" href_attrib = f"{XLINK}href"
if href_attrib in attrib: if href_attrib in attrib:
@@ -384,16 +393,16 @@ class SheetBuilder:
return svg return svg
def build_drawings(self, root: ET.Element, sheet: ifcopenshell.entity_instance): def build_drawings(self, root: ET.Element, sheet: ifcopenshell.entity_instance):
for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="drawing"]'): for view in root.findall(f'{SVG}g[@data-type="drawing"]'):
drawing_id = int(view.attrib["data-id"]) drawing_id = int(view.attrib["data-id"])
try: try:
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"])) reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
drawing = tool.Ifc.get().by_id(view.attrib["data-drawing"]) drawing = tool.Ifc.get().by_guid(view.attrib["data-drawing"])
except: except RuntimeError:
# Perhaps the SVG has outdated content or is edited externally which we cannot control. # Perhaps the SVG has outdated content or is edited externally which we cannot control.
continue continue
images = view.findall("{http://www.w3.org/2000/svg}image") images = view.findall(f"{SVG}image")
foreground = None foreground = None
view_title = None view_title = None
@@ -410,6 +419,7 @@ class SheetBuilder:
view.append(svg) view.append(svg)
if view_title is not None: if view_title is not None:
assert foreground
foreground_path = self.get_href(foreground) foreground_path = self.get_href(foreground)
data = reference.get_info() data = reference.get_info()
data.update({"Sheet" + k: v for k, v in sheet.get_info().items()}) data.update({"Sheet" + k: v for k, v in sheet.get_info().items()})
@@ -434,8 +444,8 @@ class SheetBuilder:
view.remove(image) view.remove(image)
def build_documents(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: def build_documents(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None:
schedules = root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]') schedules = root.findall(f'{SVG}g[@data-type="schedule"]')
references = root.findall('{http://www.w3.org/2000/svg}g[@data-type="reference"]') references = root.findall(f'{SVG}g[@data-type="reference"]')
documents = schedules + references documents = schedules + references
for view in documents: for view in documents:
try: try:
@@ -445,7 +455,7 @@ class SheetBuilder:
# Perhaps the SVG has outdated content or is edited externally which we cannot control. # Perhaps the SVG has outdated content or is edited externally which we cannot control.
continue continue
images = view.findall("{http://www.w3.org/2000/svg}image") images = view.findall(f"{SVG}image")
table = None table = None
view_title = None view_title = None
@@ -471,13 +481,12 @@ class SheetBuilder:
view.remove(image) view.remove(image)
def get_href(self, element: ET.Element) -> str: def get_href(self, element: ET.Element) -> str:
return urllib.parse.unquote(element.attrib.get("{http://www.w3.org/1999/xlink}href")).replace("\\", "/") return urllib.parse.unquote(element.attrib[f"{XLINK}href"]).replace("\\", "/")
def parse_embedded_svg(self, image: ET.Element, data: dict) -> ET.Element: def parse_embedded_svg(self, image: ET.Element, data: dict) -> ET.Element:
group = ET.Element("g") group = ET.Element("g")
group.attrib["transform"] = "translate({},{})".format( x, y = self.convert_to_mm(image.attrib["x"]), self.convert_to_mm(image.attrib["y"])
self.convert_to_mm(image.attrib.get("x")), self.convert_to_mm(image.attrib.get("y")) group.attrib["transform"] = f"translate({x},{y})"
)
# Convert viewBox into a clip path # Convert viewBox into a clip path
clip_id = str(uuid.uuid4()) clip_id = str(uuid.uuid4())
@@ -487,8 +496,8 @@ class SheetBuilder:
rect = ET.Element("rect") rect = ET.Element("rect")
rect.attrib["x"] = "0" rect.attrib["x"] = "0"
rect.attrib["y"] = "0" rect.attrib["y"] = "0"
rect.attrib["width"] = str(self.convert_to_mm(image.attrib.get("width"))) rect.attrib["width"] = str(self.convert_to_mm(image.attrib["width"]))
rect.attrib["height"] = str(self.convert_to_mm(image.attrib.get("height"))) rect.attrib["height"] = str(self.convert_to_mm(image.attrib["height"]))
clip_path.append(rect) clip_path.append(rect)
self.defs.append(clip_path) self.defs.append(clip_path)
@@ -499,16 +508,16 @@ class SheetBuilder:
embedded.attrib["viewBox"] = "" embedded.attrib["viewBox"] = ""
# TODO: This should not be in this function # TODO: This should not be in this function
self.scale = embedded.attrib.get("data-scale") self.scale = embedded.attrib.get("data-scale")
images = embedded.findall("{http://www.w3.org/2000/svg}image") images = embedded.findall(f"{SVG}image")
for image in images: for image in images:
old_href = Path(image.attrib.get("{http://www.w3.org/1999/xlink}href")) old_href = Path(image.attrib[f"{XLINK}href"])
if not os.path.isabs(old_href): if not os.path.isabs(old_href):
template_dir = Path(os.path.join(self.layout_dir, svg_path)).resolve().parent template_dir = Path(os.path.join(self.layout_dir, svg_path)).resolve().parent
old_href = Path(os.path.join(template_dir, old_href)) old_href = Path(os.path.join(template_dir, old_href))
old_href = old_href.absolute().resolve().as_posix() old_href = old_href.absolute().resolve().as_posix()
new_href = Path(os.path.join(self.sheets_dir, Path(old_href).name)).absolute().resolve().as_posix() new_href = Path(os.path.join(self.sheets_dir, Path(old_href).name)).absolute().resolve().as_posix()
shutil.copy(old_href, new_href) shutil.copy(old_href, new_href)
image.attrib["{http://www.w3.org/1999/xlink}href"] = Path(old_href).name image.attrib[f"{XLINK}href"] = Path(old_href).name
for child in embedded: for child in embedded:
if "namedview" in child.tag: if "namedview" in child.tag:
continue continue
@@ -539,9 +548,9 @@ class SheetBuilder:
sheet_tree = ET.parse(sheet_path) sheet_tree = ET.parse(sheet_path)
root = sheet_tree.getroot() root = sheet_tree.getroot()
titleblock = sheet_tree.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0] titleblock = sheet_tree.findall(f'{SVG}g[@data-type="titleblock"]')[0]
image = titleblock.findall("{http://www.w3.org/2000/svg}image[@{http://www.w3.org/1999/xlink}href]")[0] image = titleblock.findall(f"{SVG}image[@{XLINK}href]")[0]
image.attrib["{http://www.w3.org/1999/xlink}href"] = os.path.relpath(titleblock_path, sheet_dir) image.attrib[f"{XLINK}href"] = os.path.relpath(titleblock_path, sheet_dir)
image.attrib["width"] = str(view_width) image.attrib["width"] = str(view_width)
image.attrib["height"] = str(view_height) image.attrib["height"] = str(view_height)
+7 -4
View File
@@ -1132,21 +1132,24 @@ class DumbWallJoiner:
relating_element = None relating_element = None
connections = element1.ConnectedTo connections = element1.ConnectedTo
for conn in connections: for conn in connections:
if conn.RelatingConnectionType == "ATEND": if conn.is_a("IfcRelConnectsPathElements") and conn.RelatingConnectionType == "ATEND":
relating_element = conn.RelatedElement relating_element = conn.RelatedElement
relating_connection = conn.RelatedConnectionType
description = conn.Description description = conn.Description
bonsai.core.geometry.remove_connection(tool.Geometry, connection=conn)
connections = element1.ConnectedFrom connections = element1.ConnectedFrom
for conn in connections: for conn in connections:
if conn.RelatedConnectionType == "ATEND": if conn.is_a("IfcRelConnectsPathElements") and conn.RelatedConnectionType == "ATEND":
relating_element = conn.RelatingElement relating_element = conn.RelatingElement
relating_connection = conn.RelatingConnectionType
description = conn.Description description = conn.Description
bonsai.core.geometry.remove_connection(tool.Geometry, connection=conn)
if relating_element: if relating_element:
ifcopenshell.api.geometry.connect_path( ifcopenshell.api.geometry.connect_path(
tool.Ifc.get(), tool.Ifc.get(),
relating_element=relating_element, relating_element=relating_element,
related_element=element2, related_element=element2,
relating_connection="ATSTART", relating_connection=relating_connection,
related_connection="ATEND", related_connection="ATEND",
description=description, description=description,
) )
+1 -1
View File
@@ -82,7 +82,7 @@ class BIMProfileProperties(PropertyGroup):
name="Filter Material Profiles", name="Filter Material Profiles",
default=False, default=False,
description="Check to only show IfcProfileDefs attached to IfcMaterialProfiles", description="Check to only show IfcProfileDefs attached to IfcMaterialProfiles",
update=lambda self, context: bpy.ops.bim.load_profiles(), update=lambda self, context: (None, bpy.ops.bim.load_profiles())[0],
) )
object_to_profile: PointerProperty( object_to_profile: PointerProperty(
name="Object to profile", name="Object to profile",
@@ -63,24 +63,34 @@ from bonsai.bim.module.project.decorator import ProjectDecorator, ClippingPlaneD
from bonsai.bim.module.project.prop import BreadcrumbType from bonsai.bim.module.project.prop import BreadcrumbType
from bonsai.bim.module.model.decorator import PolylineDecorator, FaceAreaDecorator from bonsai.bim.module.model.decorator import PolylineDecorator, FaceAreaDecorator
from bonsai.bim.module.model.polyline import PolylineOperator from bonsai.bim.module.model.polyline import PolylineOperator
from typing import Union, TYPE_CHECKING, get_args from typing import Union, TYPE_CHECKING, get_args, Literal
if TYPE_CHECKING: if TYPE_CHECKING:
import bpy.stub_internal.rna_enums as rna_enums
from bonsai.bim.module.project.prop import Link from bonsai.bim.module.project.prop import Link
PresetType = Literal["metric_m", "metric_mm", "imperial_ft", "demo", "wizard"]
class NewProject(bpy.types.Operator): class NewProject(bpy.types.Operator):
bl_idname = "bim.new_project" bl_idname = "bim.new_project"
bl_label = "New Project" bl_label = "New Project"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Start a new IFC project in a fresh session" bl_description = "Start a new IFC project in a fresh session"
preset: bpy.props.StringProperty() preset: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
items=[(i, i, "") for i in get_args(PresetType)]
)
def execute(self, context): if TYPE_CHECKING:
preset: PresetType
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
bpy.ops.wm.read_homefile() bpy.ops.wm.read_homefile()
pprops = tool.Project.get_project_props() pprops = tool.Project.get_project_props()
bim_props = tool.Blender.get_bim_props() bim_props = tool.Blender.get_bim_props()
assert bpy.context.scene
if self.preset == "metric_m": if self.preset == "metric_m":
pprops.export_schema = "IFC4" pprops.export_schema = "IFC4"
bpy.context.scene.unit_settings.system = "METRIC" bpy.context.scene.unit_settings.system = "METRIC"
+18 -8
View File
@@ -21,15 +21,21 @@ import ifcopenshell.api
import ifcopenshell.util.unit import ifcopenshell.util.unit
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.unit as core import bonsai.core.unit as core
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bpy.stub_internal import rna_enums
class AssignSceneUnits(bpy.types.Operator, tool.Ifc.Operator): class AssignSceneUnits(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_scene_units" bl_idname = "bim.assign_scene_units"
bl_label = "Assign Scene Units" bl_label = "Assign Scene Units"
bl_description = "Add new units based on the current Blender scene units and assign them as project default."
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
core.assign_scene_units(tool.Ifc, tool.Unit) core.assign_scene_units(tool.Ifc, tool.Unit)
core.load_units(tool.Unit)
class AssignUnit(bpy.types.Operator, tool.Ifc.Operator): class AssignUnit(bpy.types.Operator, tool.Ifc.Operator):
@@ -54,24 +60,26 @@ class UnassignUnit(bpy.types.Operator, tool.Ifc.Operator):
core.unassign_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit)) core.unassign_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
class LoadUnits(bpy.types.Operator, tool.Ifc.Operator): class LoadUnits(bpy.types.Operator):
bl_idname = "bim.load_units" bl_idname = "bim.load_units"
bl_label = "Load Units" bl_label = "Load Units"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Open the loaded units" bl_description = "Open the loaded units"
def _execute(self, context): def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
core.load_units(tool.Unit) core.load_units(tool.Unit)
return {"FINISHED"}
class DisableUnitEditingUI(bpy.types.Operator, tool.Ifc.Operator): class DisableUnitEditingUI(bpy.types.Operator):
bl_idname = "bim.disable_unit_editing_ui" bl_idname = "bim.disable_unit_editing_ui"
bl_label = "Disable Unit Editing UI" bl_label = "Disable Unit Editing UI"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
bl_description = "Close the editing units mode" bl_description = "Close the editing units mode"
def _execute(self, context): def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
core.disable_unit_editing_ui(tool.Unit) core.disable_unit_editing_ui(tool.Unit)
return {"FINISHED"}
class RemoveUnit(bpy.types.Operator, tool.Ifc.Operator): class RemoveUnit(bpy.types.Operator, tool.Ifc.Operator):
@@ -124,23 +132,25 @@ class AddContextDependentUnit(bpy.types.Operator, tool.Ifc.Operator):
core.add_context_dependent_unit(tool.Ifc, tool.Unit, unit_type=self.unit_type, name=self.name) core.add_context_dependent_unit(tool.Ifc, tool.Unit, unit_type=self.unit_type, name=self.name)
class EnableEditingUnit(bpy.types.Operator, tool.Ifc.Operator): class EnableEditingUnit(bpy.types.Operator):
bl_idname = "bim.enable_editing_unit" bl_idname = "bim.enable_editing_unit"
bl_label = "Enable Editing Unit" bl_label = "Enable Editing Unit"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
unit: bpy.props.IntProperty() unit: bpy.props.IntProperty()
def _execute(self, context): def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
core.enable_editing_unit(tool.Unit, unit=tool.Ifc.get().by_id(self.unit)) core.enable_editing_unit(tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
return {"FINISHED"}
class DisableEditingUnit(bpy.types.Operator, tool.Ifc.Operator): class DisableEditingUnit(bpy.types.Operator):
bl_idname = "bim.disable_editing_unit" bl_idname = "bim.disable_editing_unit"
bl_label = "Disable Editing Unit" bl_label = "Disable Editing Unit"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
core.disable_editing_unit(tool.Unit) core.disable_editing_unit(tool.Unit)
return {"FINISHED"}
class EditUnit(bpy.types.Operator, tool.Ifc.Operator): class EditUnit(bpy.types.Operator, tool.Ifc.Operator):
+2
View File
@@ -48,10 +48,12 @@ class BIM_PT_units(Panel):
UnitsData.load() UnitsData.load()
self.props = tool.Unit.get_unit_props() self.props = tool.Unit.get_unit_props()
assert self.layout
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="{} Units Found".format(UnitsData.data["total_units"]), icon="SNAP_GRID") row.label(text="{} Units Found".format(UnitsData.data["total_units"]), icon="SNAP_GRID")
if self.props.is_editing: if self.props.is_editing:
row.operator("bim.assign_scene_units", text="", icon="TOOL_SETTINGS")
row.operator("bim.disable_unit_editing_ui", text="", icon="CANCEL") row.operator("bim.disable_unit_editing_ui", text="", icon="CANCEL")
else: else:
row.operator("bim.load_units", text="", icon="GREASEPENCIL") row.operator("bim.load_units", text="", icon="GREASEPENCIL")
+6 -1
View File
@@ -26,7 +26,12 @@ if TYPE_CHECKING:
def copy_attribute_to_selection( def copy_attribute_to_selection(
ifc: tool.Ifc, blender: tool.Blender, root: tool.Root, spatial: tool.Spatial, name: str, value: Union[str, None] ifc: type[tool.Ifc],
blender: type[tool.Blender],
root: type[tool.Root],
spatial: type[tool.Spatial],
name: str,
value: Union[str, None],
) -> int: ) -> int:
total_changed = 0 total_changed = 0
has_edited_spatial_name = False has_edited_spatial_name = False
+23 -19
View File
@@ -25,7 +25,7 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def load_brick_project(brick: tool.Brick, filepath: str, brick_root: str) -> None: def load_brick_project(brick: type[tool.Brick], filepath: str, brick_root: str) -> None:
brick.load_brick_file(filepath) brick.load_brick_file(filepath)
brick.import_brick_classes(brick_root) brick.import_brick_classes(brick_root)
brick.import_brick_classes(brick_root, split_screen=True) brick.import_brick_classes(brick_root, split_screen=True)
@@ -33,7 +33,7 @@ def load_brick_project(brick: tool.Brick, filepath: str, brick_root: str) -> Non
brick.set_active_brick_class(brick_root, split_screen=True) brick.set_active_brick_class(brick_root, split_screen=True)
def new_brick_file(brick: tool.Brick, brick_root: str) -> None: def new_brick_file(brick: type[tool.Brick], brick_root: str) -> None:
brick.new_brick_file() brick.new_brick_file()
brick.import_brick_classes(brick_root) brick.import_brick_classes(brick_root)
brick.import_brick_classes(brick_root, split_screen=True) brick.import_brick_classes(brick_root, split_screen=True)
@@ -41,7 +41,7 @@ def new_brick_file(brick: tool.Brick, brick_root: str) -> None:
brick.set_active_brick_class(brick_root, split_screen=True) brick.set_active_brick_class(brick_root, split_screen=True)
def view_brick_class(brick: tool.Brick, brick_class: str, split_screen: bool = False) -> None: def view_brick_class(brick: type[tool.Brick], brick_class: str, split_screen: bool = False) -> None:
brick.add_brick_breadcrumb(split_screen=split_screen) brick.add_brick_breadcrumb(split_screen=split_screen)
brick.clear_brick_browser(split_screen=split_screen) brick.clear_brick_browser(split_screen=split_screen)
brick.import_brick_classes(brick_class, split_screen=split_screen) brick.import_brick_classes(brick_class, split_screen=split_screen)
@@ -49,13 +49,13 @@ def view_brick_class(brick: tool.Brick, brick_class: str, split_screen: bool = F
brick.set_active_brick_class(brick_class, split_screen=split_screen) brick.set_active_brick_class(brick_class, split_screen=split_screen)
def view_brick_item(brick: tool.Brick, item: str, split_screen: bool = False) -> None: def view_brick_item(brick: type[tool.Brick], item: str, split_screen: bool = False) -> None:
brick_class = brick.get_item_class(item) brick_class = brick.get_item_class(item)
brick.run_view_brick_class(brick_class=brick_class, split_screen=split_screen) brick.run_view_brick_class(brick_class=brick_class, split_screen=split_screen)
brick.select_browser_item(item, split_screen=split_screen) brick.select_browser_item(item, split_screen=split_screen)
def rewind_brick_class(brick: tool.Brick, split_screen: bool = False) -> None: def rewind_brick_class(brick: type[tool.Brick], split_screen: bool = False) -> None:
previous_class = brick.pop_brick_breadcrumb(split_screen=split_screen) previous_class = brick.pop_brick_breadcrumb(split_screen=split_screen)
brick.clear_brick_browser(split_screen=split_screen) brick.clear_brick_browser(split_screen=split_screen)
brick.import_brick_classes(previous_class, split_screen=split_screen) brick.import_brick_classes(previous_class, split_screen=split_screen)
@@ -63,7 +63,7 @@ def rewind_brick_class(brick: tool.Brick, split_screen: bool = False) -> None:
brick.set_active_brick_class(previous_class, split_screen=split_screen) brick.set_active_brick_class(previous_class, split_screen=split_screen)
def close_brick_project(brick: tool.Brick) -> None: def close_brick_project(brick: type[tool.Brick]) -> None:
brick.clear_project() brick.clear_project()
brick.clear_brick_browser() brick.clear_brick_browser()
brick.clear_brick_browser(split_screen=True) brick.clear_brick_browser(split_screen=True)
@@ -71,15 +71,15 @@ def close_brick_project(brick: tool.Brick) -> None:
brick.clear_breadcrumbs(split_screen=True) brick.clear_breadcrumbs(split_screen=True)
def convert_brick_project(ifc: tool.Ifc, brick: tool.Brick) -> None: def convert_brick_project(ifc: type[tool.Ifc], brick: type[tool.Brick]) -> None:
library = ifc.run("library.add_library", name=brick.get_brick_path_name()) library = ifc.run("library.add_library", name=brick.get_brick_path_name())
if ifc.get_schema() != "IFC2X3": if ifc.get_schema() != "IFC2X3":
ifc.run("library.edit_library", library=library, attributes={"Location": brick.get_brick_path()}) ifc.run("library.edit_library", library=library, attributes={"Location": brick.get_brick_path()})
def assign_brick_reference( def assign_brick_reference(
ifc: tool.Ifc, ifc: type[tool.Ifc],
brick: tool.Brick, brick: type[tool.Brick],
element: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance,
library: ifcopenshell.entity_instance, library: ifcopenshell.entity_instance,
brick_uri: str, brick_uri: str,
@@ -96,8 +96,8 @@ def assign_brick_reference(
def add_brick( def add_brick(
ifc: tool.Ifc, ifc: type[tool.Ifc],
brick: tool.Brick, brick: type[tool.Brick],
element: Union[ifcopenshell.entity_instance, None], element: Union[ifcopenshell.entity_instance, None],
namespace: str, namespace: str,
brick_class: str, brick_class: str,
@@ -113,12 +113,14 @@ def add_brick(
brick.run_refresh_brick_viewer() brick.run_refresh_brick_viewer()
def add_brick_relation(brick: tool.Brick, brick_uri: str, predicate: str, object: str) -> None: def add_brick_relation(brick: type[tool.Brick], brick_uri: str, predicate: str, object: str) -> None:
brick.add_relation(brick_uri, predicate, object) brick.add_relation(brick_uri, predicate, object)
brick.run_refresh_brick_viewer() brick.run_refresh_brick_viewer()
def convert_ifc_to_brick(brick: tool.Brick, namespace: str, library: Union[ifcopenshell.entity_instance, None]) -> None: def convert_ifc_to_brick(
brick: type[tool.Brick], namespace: str, library: Union[ifcopenshell.entity_instance, None]
) -> None:
# convert spaces to brick # convert spaces to brick
spaces = brick.get_convertable_brick_spaces() spaces = brick.get_convertable_brick_spaces()
space_uris = {} space_uris = {}
@@ -163,14 +165,16 @@ def convert_ifc_to_brick(brick: tool.Brick, namespace: str, library: Union[ifcop
brick.run_refresh_brick_viewer() brick.run_refresh_brick_viewer()
def refresh_brick_viewer(brick: tool.Brick) -> None: def refresh_brick_viewer(brick: type[tool.Brick]) -> None:
brick.run_view_brick_class(brick_class=brick.get_active_brick_class()) brick.run_view_brick_class(brick_class=brick.get_active_brick_class())
brick.pop_brick_breadcrumb() brick.pop_brick_breadcrumb()
brick.run_view_brick_class(brick_class=brick.get_active_brick_class(split_screen=True), split_screen=True) brick.run_view_brick_class(brick_class=brick.get_active_brick_class(split_screen=True), split_screen=True)
brick.pop_brick_breadcrumb(split_screen=True) brick.pop_brick_breadcrumb(split_screen=True)
def remove_brick(ifc: tool.Ifc, brick: tool.Brick, library: ifcopenshell.entity_instance, brick_uri: str) -> None: def remove_brick(
ifc: type[tool.Ifc], brick: type[tool.Brick], library: ifcopenshell.entity_instance, brick_uri: str
) -> None:
if library: if library:
reference = brick.get_library_brick_reference(library, brick_uri) reference = brick.get_library_brick_reference(library, brick_uri)
if reference: if reference:
@@ -179,18 +183,18 @@ def remove_brick(ifc: tool.Ifc, brick: tool.Brick, library: ifcopenshell.entity_
brick.run_refresh_brick_viewer() brick.run_refresh_brick_viewer()
def serialize_brick(brick: tool.Brick) -> None: def serialize_brick(brick: type[tool.Brick]) -> None:
brick.serialize_brick() brick.serialize_brick()
def add_brick_namespace(brick: tool.Brick, alias: str, uri: str) -> None: def add_brick_namespace(brick: type[tool.Brick], alias: str, uri: str) -> None:
brick.add_namespace(alias, uri) brick.add_namespace(alias, uri)
def set_brick_list_root(brick: tool.Brick, brick_root: str, split_screen: bool = False) -> None: def set_brick_list_root(brick: type[tool.Brick], brick_root: str, split_screen: bool = False) -> None:
brick.run_view_brick_class(brick_class=brick_root, split_screen=split_screen) brick.run_view_brick_class(brick_class=brick_root, split_screen=split_screen)
brick.clear_breadcrumbs(split_screen=split_screen) brick.clear_breadcrumbs(split_screen=split_screen)
def remove_brick_relation(brick: tool.Brick, brick_uri: str, predicate: str, object: str) -> None: def remove_brick_relation(brick: type[tool.Brick], brick_uri: str, predicate: str, object: str) -> None:
brick.remove_relation(brick_uri, predicate, object) brick.remove_relation(brick_uri, predicate, object)
+5 -5
View File
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
def add_context( def add_context(
ifc: tool.Ifc, ifc: type[tool.Ifc],
context_type: Optional[str] = None, context_type: Optional[str] = None,
context_identifier: Optional[str] = None, context_identifier: Optional[str] = None,
target_view: Optional[str] = None, target_view: Optional[str] = None,
@@ -41,19 +41,19 @@ def add_context(
) )
def remove_context(ifc: tool.Ifc, context: ifcopenshell.entity_instance) -> None: def remove_context(ifc: type[tool.Ifc], context: ifcopenshell.entity_instance) -> None:
ifc.run("context.remove_context", context=context) ifc.run("context.remove_context", context=context)
def enable_editing_context(context_tool: tool.Context, context: ifcopenshell.entity_instance) -> None: def enable_editing_context(context_tool: type[tool.Context], context: ifcopenshell.entity_instance) -> None:
context_tool.set_context(context) context_tool.set_context(context)
context_tool.import_attributes() context_tool.import_attributes()
def disable_editing_context(context: tool.Context) -> None: def disable_editing_context(context: type[tool.Context]) -> None:
context.clear_context() context.clear_context()
def edit_context(ifc: tool.Ifc, context: tool.Context) -> None: def edit_context(ifc: type[tool.Ifc], context: type[tool.Context]) -> None:
ifc.run("context.edit_context", context=context.get_context(), attributes=context.export_attributes()) ifc.run("context.edit_context", context=context.get_context(), attributes=context.export_attributes())
disable_editing_context(context) disable_editing_context(context)
+1 -3
View File
@@ -458,7 +458,5 @@ def add_currency(ifc: type[tool.Ifc], cost: type[tool.Cost]) -> ifcopenshell.ent
return unit return unit
def generate_cost_schedule_browser( def generate_cost_schedule_browser(cost: type[tool.Cost], cost_schedule: ifcopenshell.entity_instance) -> None:
cost: type[tool.Cost], cost_schedule: ifcopenshell.entity_instance
) -> bpy.types.Panel:
return cost.generate_cost_schedule_browser(cost_schedule) return cost.generate_cost_schedule_browser(cost_schedule)
+9 -5
View File
@@ -25,7 +25,9 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def add_instance_flooring_covering_from_cursor(ifc: tool.Ifc, root: tool.Root, spatial: tool.Spatial) -> None: def add_instance_flooring_covering_from_cursor(
ifc: type[tool.Ifc], root: type[tool.Root], spatial: type[tool.Spatial]
) -> None:
if not root.get_default_container(): if not root.get_default_container():
raise NoDefaultContainer() raise NoDefaultContainer()
@@ -68,7 +70,7 @@ def add_instance_flooring_covering_from_cursor(ifc: tool.Ifc, root: tool.Root, s
def add_instance_ceiling_covering_from_cursor( def add_instance_ceiling_covering_from_cursor(
ifc: tool.Ifc, root: tool.Root, covering: tool.Covering, spatial: tool.Spatial ifc: type[tool.Ifc], root: type[tool.Root], covering: type[tool.Covering], spatial: type[tool.Spatial]
) -> None: ) -> None:
if not root.get_default_container(): if not root.get_default_container():
raise NoDefaultContainer() raise NoDefaultContainer()
@@ -111,7 +113,7 @@ def add_instance_ceiling_covering_from_cursor(
spatial.regen_obj_representation(obj, body) spatial.regen_obj_representation(obj, body)
def regen_selected_covering_object(root: tool.Root, spatial: tool.Spatial) -> None: def regen_selected_covering_object(root: type[tool.Root], spatial: type[tool.Spatial]) -> None:
if not root.get_default_container(): if not root.get_default_container():
raise NoDefaultContainer() raise NoDefaultContainer()
@@ -142,7 +144,7 @@ def regen_selected_covering_object(root: tool.Root, spatial: tool.Spatial) -> No
# TODO CHECK IF IT IS POSSIBLE TO CREATE ONLY ONE CORE FUNCTION FOR _FROM_WALLS # TODO CHECK IF IT IS POSSIBLE TO CREATE ONLY ONE CORE FUNCTION FOR _FROM_WALLS
def add_instance_flooring_coverings_from_walls(root: tool.Root, spatial: tool.Spatial) -> None: def add_instance_flooring_coverings_from_walls(root: type[tool.Root], spatial: type[tool.Spatial]) -> None:
if not root.get_default_container(): if not root.get_default_container():
raise NoDefaultContainer() raise NoDefaultContainer()
@@ -168,7 +170,9 @@ def add_instance_flooring_coverings_from_walls(root: tool.Root, spatial: tool.Sp
spatial.regen_obj_representation(obj, body) spatial.regen_obj_representation(obj, body)
def add_instance_ceiling_coverings_from_walls(root: tool.Root, spatial: tool.Spatial, covering: tool.Covering) -> None: def add_instance_ceiling_coverings_from_walls(
root: type[tool.Root], spatial: type[tool.Spatial], covering: type[tool.Covering]
) -> None:
if not root.get_default_container(): if not root.get_default_container():
raise NoDefaultContainer() raise NoDefaultContainer()
+14 -14
View File
@@ -25,25 +25,25 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def add_georeferencing(georeference: tool.Georeference) -> None: def add_georeferencing(georeference: type[tool.Georeference]) -> None:
georeference.add_georeferencing() georeference.add_georeferencing()
def enable_editing_georeferencing(georeference: tool.Georeference) -> None: def enable_editing_georeferencing(georeference: type[tool.Georeference]) -> None:
georeference.import_projected_crs() georeference.import_projected_crs()
georeference.import_coordinate_operation() georeference.import_coordinate_operation()
georeference.enable_editing() georeference.enable_editing()
def remove_georeferencing(ifc: tool.Ifc) -> None: def remove_georeferencing(ifc: type[tool.Ifc]) -> None:
ifc.run("georeference.remove_georeferencing") ifc.run("georeference.remove_georeferencing")
def disable_editing_georeferencing(georeference: tool.Georeference) -> None: def disable_editing_georeferencing(georeference: type[tool.Georeference]) -> None:
georeference.disable_editing() georeference.disable_editing()
def edit_georeferencing(ifc: tool.Ifc, georeference: tool.Georeference) -> None: def edit_georeferencing(ifc: type[tool.Ifc], georeference: type[tool.Georeference]) -> None:
ifc.run( ifc.run(
"georeference.edit_georeferencing", "georeference.edit_georeferencing",
projected_crs=georeference.export_projected_crs(), projected_crs=georeference.export_projected_crs(),
@@ -53,7 +53,7 @@ def edit_georeferencing(ifc: tool.Ifc, georeference: tool.Georeference) -> None:
georeference.set_model_origin() georeference.set_model_origin()
def get_cursor_location(georeference: tool.Georeference) -> None: def get_cursor_location(georeference: type[tool.Georeference]) -> None:
location = georeference.get_cursor_location() location = georeference.get_cursor_location()
if georeference.has_blender_offset(): if georeference.has_blender_offset():
georeference.set_coordinates("blender", location) georeference.set_coordinates("blender", location)
@@ -61,39 +61,39 @@ def get_cursor_location(georeference: tool.Georeference) -> None:
georeference.set_coordinates("local", location) georeference.set_coordinates("local", location)
def import_plot(georeference: tool.Georeference, filepath: str) -> None: def import_plot(georeference: type[tool.Georeference], filepath: str) -> None:
georeference.import_plot(filepath) georeference.import_plot(filepath)
def enable_editing_wcs(georeference: tool.Georeference) -> None: def enable_editing_wcs(georeference: type[tool.Georeference]) -> None:
georeference.import_wcs() georeference.import_wcs()
georeference.enable_editing_wcs() georeference.enable_editing_wcs()
def disable_editing_wcs(georeference: tool.Georeference) -> None: def disable_editing_wcs(georeference: type[tool.Georeference]) -> None:
georeference.disable_editing_wcs() georeference.disable_editing_wcs()
def edit_wcs(georeference: tool.Georeference) -> None: def edit_wcs(georeference: type[tool.Georeference]) -> None:
wcs = georeference.export_wcs() wcs = georeference.export_wcs()
georeference.set_wcs(wcs) georeference.set_wcs(wcs)
georeference.disable_editing_wcs() georeference.disable_editing_wcs()
georeference.set_model_origin() georeference.set_model_origin()
def enable_editing_true_north(georeference: tool.Georeference) -> None: def enable_editing_true_north(georeference: type[tool.Georeference]) -> None:
georeference.import_true_north() georeference.import_true_north()
georeference.enable_editing_true_north() georeference.enable_editing_true_north()
def disable_editing_true_north(georeference: tool.Georeference) -> None: def disable_editing_true_north(georeference: type[tool.Georeference]) -> None:
georeference.disable_editing_true_north() georeference.disable_editing_true_north()
def edit_true_north(ifc: tool.Ifc, georeference: tool.Georeference) -> None: def edit_true_north(ifc: type[tool.Ifc], georeference: type[tool.Georeference]) -> None:
ifc.run("georeference.edit_true_north", true_north=georeference.get_true_north_attributes()) ifc.run("georeference.edit_true_north", true_north=georeference.get_true_north_attributes())
georeference.disable_editing_true_north() georeference.disable_editing_true_north()
def remove_true_north(ifc: tool.Ifc) -> None: def remove_true_north(ifc: type[tool.Ifc]) -> None:
ifc.run("georeference.edit_true_north", true_north=None) ifc.run("georeference.edit_true_north", true_north=None)
+20 -14
View File
@@ -25,35 +25,35 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def add_library(ifc: tool.Ifc) -> ifcopenshell.entity_instance: def add_library(ifc: type[tool.Ifc]) -> ifcopenshell.entity_instance:
return ifc.run("library.add_library", name="Unnamed") return ifc.run("library.add_library", name="Unnamed")
def remove_library(ifc: tool.Ifc, library: ifcopenshell.entity_instance) -> None: def remove_library(ifc: type[tool.Ifc], library: ifcopenshell.entity_instance) -> None:
ifc.run("library.remove_library", library=library) ifc.run("library.remove_library", library=library)
def enable_editing_library_references(library_tool: tool.Library, library: ifcopenshell.entity_instance) -> None: def enable_editing_library_references(library_tool: type[tool.Library], library: ifcopenshell.entity_instance) -> None:
library_tool.set_editing_mode("REFERENCES") library_tool.set_editing_mode("REFERENCES")
library_tool.set_active_library(library) library_tool.set_active_library(library)
library_tool.import_references(library) library_tool.import_references(library)
def disable_editing_library_references(library: tool.Library) -> None: def disable_editing_library_references(library: type[tool.Library]) -> None:
library.clear_editing_mode() library.clear_editing_mode()
library.set_active_library(None) library.set_active_library(None)
def enable_editing_library(library: tool.Library) -> None: def enable_editing_library(library: type[tool.Library]) -> None:
library.set_editing_mode("LIBRARY") library.set_editing_mode("LIBRARY")
library.import_library_attributes(library.get_active_library()) library.import_library_attributes(library.get_active_library())
def disable_editing_library(library: tool.Library) -> None: def disable_editing_library(library: type[tool.Library]) -> None:
library.set_editing_mode("REFERENCES") library.set_editing_mode("REFERENCES")
def edit_library(ifc: tool.Ifc, library: tool.Library) -> None: def edit_library(ifc: type[tool.Ifc], library: type[tool.Library]) -> None:
library.set_editing_mode("REFERENCES") library.set_editing_mode("REFERENCES")
active_library = library.get_active_library() active_library = library.get_active_library()
attributes = library.export_library_attributes() attributes = library.export_library_attributes()
@@ -61,29 +61,31 @@ def edit_library(ifc: tool.Ifc, library: tool.Library) -> None:
library.import_references(active_library) library.import_references(active_library)
def add_library_reference(ifc: tool.Ifc, library: tool.Library) -> ifcopenshell.entity_instance: def add_library_reference(ifc: type[tool.Ifc], library: type[tool.Library]) -> ifcopenshell.entity_instance:
active_library = library.get_active_library() active_library = library.get_active_library()
reference = ifc.run("library.add_reference", library=active_library) reference = ifc.run("library.add_reference", library=active_library)
library.import_references(active_library) library.import_references(active_library)
return reference return reference
def remove_library_reference(ifc: tool.Ifc, library: tool.Library, reference: ifcopenshell.entity_instance) -> None: def remove_library_reference(
ifc: type[tool.Ifc], library: type[tool.Library], reference: ifcopenshell.entity_instance
) -> None:
ifc.run("library.remove_reference", reference=reference) ifc.run("library.remove_reference", reference=reference)
library.import_references(library.get_active_library()) library.import_references(library.get_active_library())
def enable_editing_library_reference(library: tool.Library, reference: ifcopenshell.entity_instance) -> None: def enable_editing_library_reference(library: type[tool.Library], reference: ifcopenshell.entity_instance) -> None:
library.set_editing_mode("REFERENCE") library.set_editing_mode("REFERENCE")
library.set_active_reference(reference) library.set_active_reference(reference)
library.import_reference_attributes(reference) library.import_reference_attributes(reference)
def disable_editing_library_reference(library: tool.Library) -> None: def disable_editing_library_reference(library: type[tool.Library]) -> None:
library.set_editing_mode("REFERENCES") library.set_editing_mode("REFERENCES")
def edit_library_reference(ifc: tool.Ifc, library: tool.Library) -> None: def edit_library_reference(ifc: type[tool.Ifc], library: type[tool.Library]) -> None:
library.set_editing_mode("REFERENCES") library.set_editing_mode("REFERENCES")
active_reference = library.get_active_reference() active_reference = library.get_active_reference()
attributes = library.export_reference_attributes() attributes = library.export_reference_attributes()
@@ -91,9 +93,13 @@ def edit_library_reference(ifc: tool.Ifc, library: tool.Library) -> None:
library.import_references(library.get_active_library()) library.import_references(library.get_active_library())
def assign_library_reference(ifc: tool.Ifc, obj: bpy.types.Object, reference: ifcopenshell.entity_instance) -> None: def assign_library_reference(
ifc: type[tool.Ifc], obj: bpy.types.Object, reference: ifcopenshell.entity_instance
) -> None:
ifc.run("library.assign_reference", products=[ifc.get_entity(obj)], reference=reference) ifc.run("library.assign_reference", products=[ifc.get_entity(obj)], reference=reference)
def unassign_library_reference(ifc: tool.Ifc, obj: bpy.types.Object, reference: ifcopenshell.entity_instance) -> None: def unassign_library_reference(
ifc: type[tool.Ifc], obj: bpy.types.Object, reference: ifcopenshell.entity_instance
) -> None:
ifc.run("library.unassign_reference", products=[ifc.get_entity(obj)], reference=reference) ifc.run("library.unassign_reference", products=[ifc.get_entity(obj)], reference=reference)
+14 -14
View File
@@ -25,18 +25,18 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def enable_editing_nest(nest: tool.Nest, obj: bpy.types.Object) -> None: def enable_editing_nest(nest: type[tool.Nest], obj: bpy.types.Object) -> None:
nest.enable_editing(obj) nest.enable_editing(obj)
def disable_editing_nest(nest: tool.Nest, obj: bpy.types.Object) -> None: def disable_editing_nest(nest: type[tool.Nest], obj: bpy.types.Object) -> None:
nest.disable_editing(obj) nest.disable_editing(obj)
def assign_object( def assign_object(
ifc: tool.Ifc, ifc: type[tool.Ifc],
nest: tool.Nest, nest: type[tool.Nest],
collector: tool.Collector, collector: type[tool.Collector],
relating_obj: bpy.types.Object, relating_obj: bpy.types.Object,
related_obj: bpy.types.Object, related_obj: bpy.types.Object,
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
@@ -54,9 +54,9 @@ def assign_object(
def unassign_object( def unassign_object(
ifc: tool.Ifc, ifc: type[tool.Ifc],
nest: tool.Nest, nest: type[tool.Nest],
collector: tool.Collector, collector: type[tool.Collector],
relating_obj: bpy.types.Object, relating_obj: bpy.types.Object,
related_obj: bpy.types.Object, related_obj: bpy.types.Object,
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
@@ -77,10 +77,10 @@ def unassign_object(
def add_part_to_object( def add_part_to_object(
ifc: tool.Ifc, ifc: type[tool.Ifc],
nest: tool.Nest, nest: type[tool.Nest],
collector: tool.Collector, collector: type[tool.Collector],
blender: tool.Blender, blender: type[tool.Blender],
obj: bpy.types.Object, obj: bpy.types.Object,
part_class: str, part_class: str,
part_name: str, part_name: str,
@@ -90,7 +90,7 @@ def add_part_to_object(
def enable_nest_mode( def enable_nest_mode(
nest: tool.Nest, nest: type[tool.Nest],
obj: bpy.types.Object, obj: bpy.types.Object,
) -> None: ) -> None:
if nest.get_nest_mode(): if nest.get_nest_mode():
@@ -99,5 +99,5 @@ def enable_nest_mode(
nest.enable_nest_mode(obj) nest.enable_nest_mode(obj)
def disable_nest_mode(nest: tool.Nest) -> None: def disable_nest_mode(nest: type[tool.Nest]) -> None:
nest.disable_nest_mode() nest.disable_nest_mode()
+1 -1
View File
@@ -26,5 +26,5 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def run_migrate_patch(patch: tool.Patch, infile: str, outfile: str, schema: str) -> None: def run_migrate_patch(patch: type[tool.Patch], infile: str, outfile: str, schema: str) -> None:
patch.run_migrate_patch(infile, outfile, schema) patch.run_migrate_patch(infile, outfile, schema)
+4 -4
View File
@@ -26,10 +26,10 @@ if TYPE_CHECKING:
def create_project( def create_project(
ifc: tool.Ifc, ifc: type[tool.Ifc],
georeference: tool.Georeference, georeference: type[tool.Georeference],
project: tool.Project, project: type[tool.Project],
spatial: tool.Spatial, spatial: type[tool.Spatial],
schema: str, schema: str,
template: Optional[str] = None, template: Optional[str] = None,
) -> None: ) -> None:
+12 -8
View File
@@ -27,8 +27,8 @@ if TYPE_CHECKING:
def copy_property_to_selection( def copy_property_to_selection(
ifc: tool.Ifc, ifc: type[tool.Ifc],
pset: tool.Pset, pset: type[tool.Pset],
obj: bpy.types.Object, obj: bpy.types.Object,
pset_name: str, pset_name: str,
prop_name: str, prop_name: str,
@@ -48,7 +48,11 @@ def copy_property_to_selection(
def add_pset( def add_pset(
ifc: tool.Ifc, pset: tool.Pset, blender: tool.Blender, obj_name: str, obj_type: tool.Ifc.OBJECT_TYPE ifc: type[tool.Ifc],
pset: type[tool.Pset],
blender: type[tool.Blender],
obj_name: str,
obj_type: type[tool.Ifc].OBJECT_TYPE,
) -> None: ) -> None:
pset_name = pset.get_pset_name(obj_name, obj_type, pset_type="PSET") pset_name = pset.get_pset_name(obj_name, obj_type, pset_type="PSET")
if obj_type == "Object": if obj_type == "Object":
@@ -64,12 +68,12 @@ def add_pset(
def enable_pset_editing( def enable_pset_editing(
pset_tool: tool.Pset, pset_tool: type[tool.Pset],
pset: Union[ifcopenshell.entity_instance, None], pset: Union[ifcopenshell.entity_instance, None],
pset_name: str, pset_name: str,
pset_type: tool.Pset.PSET_TYPE, pset_type: type[tool.Pset].PSET_TYPE,
obj_name: str, obj_name: str,
obj_type: tool.Ifc.OBJECT_TYPE, obj_type: type[tool.Ifc].OBJECT_TYPE,
) -> None: ) -> None:
props = pset_tool.get_pset_props(obj_name, obj_type) props = pset_tool.get_pset_props(obj_name, obj_type)
pset_tool.clear_blender_pset_properties(props) pset_tool.clear_blender_pset_properties(props)
@@ -90,7 +94,7 @@ def enable_pset_editing(
def add_proposed_prop( def add_proposed_prop(
pset: tool.Pset, obj_name: str, obj_type: tool.Ifc.OBJECT_TYPE, name: str, value: Any pset: type[tool.Pset], obj_name: str, obj_type: type[tool.Ifc].OBJECT_TYPE, name: str, value: Any
) -> Union[None, str]: ) -> Union[None, str]:
props = pset.get_pset_props(obj_name, obj_type) props = pset.get_pset_props(obj_name, obj_type)
res = pset.add_proposed_property(name, pset.cast_string_to_primitive(value), props) res = pset.add_proposed_property(name, pset.cast_string_to_primitive(value), props)
@@ -99,7 +103,7 @@ def add_proposed_prop(
def unshare_pset( def unshare_pset(
ifc: tool.Ifc, pset_tool: tool.Pset, obj_type: tool.Ifc.OBJECT_TYPE, obj_name: str, pset_id: int ifc: type[tool.Ifc], pset_tool: type[tool.Pset], obj_type: type[tool.Ifc].OBJECT_TYPE, obj_name: str, pset_id: int
) -> None: ) -> None:
elements: list[ifcopenshell.entity_instance] elements: list[ifcopenshell.entity_instance]
pset = ifc.get_entity_by_id(pset_id) pset = ifc.get_entity_by_id(pset_id)
+1 -1
View File
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def calculate_circle_radius(qto: tool.Qto, obj: bpy.types.Object) -> float: def calculate_circle_radius(qto: type[tool.Qto], obj: bpy.types.Object) -> float:
result = qto.get_radius_of_selected_vertices(obj) result = qto.get_radius_of_selected_vertices(obj)
qto.set_qto_result(result) qto.set_qto_result(result)
return result return result
+27 -1
View File
@@ -1,2 +1,28 @@
def show_scene_elements(spatial): # Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import bpy
import bonsai.tool as tool
def show_scene_elements(spatial: type[tool.Spatial]) -> None:
spatial.show_scene_objects() spatial.show_scene_objects()
+143 -102
View File
@@ -25,106 +25,110 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def add_work_plan(ifc: tool.Ifc) -> ifcopenshell.entity_instance: def add_work_plan(ifc: type[tool.Ifc]) -> ifcopenshell.entity_instance:
return ifc.run("sequence.add_work_plan") return ifc.run("sequence.add_work_plan")
def remove_work_plan(ifc: tool.Ifc, work_plan: ifcopenshell.entity_instance) -> None: def remove_work_plan(ifc: type[tool.Ifc], work_plan: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.remove_work_plan", work_plan=work_plan) ifc.run("sequence.remove_work_plan", work_plan=work_plan)
def enable_editing_work_plan(sequence: tool.Sequence, work_plan: ifcopenshell.entity_instance) -> None: def enable_editing_work_plan(sequence: type[tool.Sequence], work_plan: ifcopenshell.entity_instance) -> None:
sequence.load_work_plan_attributes(work_plan) sequence.load_work_plan_attributes(work_plan)
sequence.enable_editing_work_plan(work_plan) sequence.enable_editing_work_plan(work_plan)
def disable_editing_work_plan(sequence: tool.Sequence) -> None: def disable_editing_work_plan(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_work_plan() sequence.disable_editing_work_plan()
def edit_work_plan(ifc: tool.Ifc, sequence: tool.Sequence, work_plan: ifcopenshell.entity_instance) -> None: def edit_work_plan(ifc: type[tool.Ifc], sequence: type[tool.Sequence], work_plan: ifcopenshell.entity_instance) -> None:
attributes = sequence.get_work_plan_attributes() attributes = sequence.get_work_plan_attributes()
ifc.run("sequence.edit_work_plan", work_plan=work_plan, attributes=attributes) ifc.run("sequence.edit_work_plan", work_plan=work_plan, attributes=attributes)
sequence.disable_editing_work_plan() sequence.disable_editing_work_plan()
def edit_work_schedule(ifc: tool.Ifc, sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def edit_work_schedule(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance
) -> None:
attributes = sequence.get_work_schedule_attributes() attributes = sequence.get_work_schedule_attributes()
ifc.run("sequence.edit_work_schedule", work_schedule=work_schedule, attributes=attributes) ifc.run("sequence.edit_work_schedule", work_schedule=work_schedule, attributes=attributes)
sequence.disable_editing_work_schedule() sequence.disable_editing_work_schedule()
def enable_editing_work_plan_schedules( def enable_editing_work_plan_schedules(
sequence: tool.Sequence, work_plan: Optional[ifcopenshell.entity_instance] = None sequence: type[tool.Sequence], work_plan: Optional[ifcopenshell.entity_instance] = None
) -> None: ) -> None:
sequence.enable_editing_work_plan_schedules(work_plan) sequence.enable_editing_work_plan_schedules(work_plan)
def add_work_schedule(ifc: tool.Ifc, sequence: tool.Sequence, name: str) -> ifcopenshell.entity_instance: def add_work_schedule(ifc: type[tool.Ifc], sequence: type[tool.Sequence], name: str) -> ifcopenshell.entity_instance:
predefined_type, object_type = sequence.get_user_predefined_type() predefined_type, object_type = sequence.get_user_predefined_type()
return ifc.run("sequence.add_work_schedule", name=name, predefined_type=predefined_type, object_type=object_type) return ifc.run("sequence.add_work_schedule", name=name, predefined_type=predefined_type, object_type=object_type)
def remove_work_schedule(ifc: tool.Ifc, work_schedule: ifcopenshell.entity_instance) -> None: def remove_work_schedule(ifc: type[tool.Ifc], work_schedule: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.remove_work_schedule", work_schedule=work_schedule) ifc.run("sequence.remove_work_schedule", work_schedule=work_schedule)
def assign_work_schedule( def assign_work_schedule(
ifc: tool.Ifc, work_plan: ifcopenshell.entity_instance, work_schedule: ifcopenshell.entity_instance ifc: type[tool.Ifc], work_plan: ifcopenshell.entity_instance, work_schedule: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
if work_schedule: if work_schedule:
return ifc.run("aggregate.assign_object", relating_object=work_plan, products=[work_schedule]) return ifc.run("aggregate.assign_object", relating_object=work_plan, products=[work_schedule])
def unassign_work_schedule(ifc: tool.Ifc, work_schedule: ifcopenshell.entity_instance) -> None: def unassign_work_schedule(ifc: type[tool.Ifc], work_schedule: ifcopenshell.entity_instance) -> None:
ifc.run("aggregate.unassign_object", products=[work_schedule]) ifc.run("aggregate.unassign_object", products=[work_schedule])
def enable_editing_work_schedule(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def enable_editing_work_schedule(sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance) -> None:
sequence.load_work_schedule_attributes(work_schedule) sequence.load_work_schedule_attributes(work_schedule)
sequence.enable_editing_work_schedule(work_schedule) sequence.enable_editing_work_schedule(work_schedule)
def enable_editing_work_schedule_tasks(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def enable_editing_work_schedule_tasks(
sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance
) -> None:
sequence.enable_editing_work_schedule_tasks(work_schedule) sequence.enable_editing_work_schedule_tasks(work_schedule)
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def load_task_tree(sequence: tool.Sequence, work_schedule) -> None: def load_task_tree(sequence: type[tool.Sequence], work_schedule) -> None:
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def expand_task(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def expand_task(sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
sequence.expand_task(task) sequence.expand_task(task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def expand_all_tasks(sequence: tool.Sequence) -> None: def expand_all_tasks(sequence: type[tool.Sequence]) -> None:
sequence.expand_all_tasks() sequence.expand_all_tasks()
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def contract_task(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def contract_task(sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
sequence.contract_task(task) sequence.contract_task(task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def contract_all_tasks(sequence: tool.Sequence) -> None: def contract_all_tasks(sequence: type[tool.Sequence]) -> None:
sequence.contract_all_tasks() sequence.contract_all_tasks()
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def remove_task(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def remove_task(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.remove_task", task=task) ifc.run("sequence.remove_task", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
@@ -132,22 +136,24 @@ def remove_task(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entit
sequence.disable_selecting_deleted_task() sequence.disable_selecting_deleted_task()
def load_task_properties(sequence: tool.Sequence) -> None: def load_task_properties(sequence: type[tool.Sequence]) -> None:
sequence.load_task_properties() sequence.load_task_properties()
def disable_editing_work_schedule(sequence: tool.Sequence) -> None: def disable_editing_work_schedule(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_work_schedule() sequence.disable_editing_work_schedule()
def add_summary_task(ifc: tool.Ifc, sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def add_summary_task(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance
) -> None:
ifc.run("sequence.add_task", work_schedule=work_schedule) ifc.run("sequence.add_task", work_schedule=work_schedule)
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def add_task( def add_task(
ifc: tool.Ifc, sequence: tool.Sequence, parent_task: Optional[ifcopenshell.entity_instance] = None ifc: type[tool.Ifc], sequence: type[tool.Sequence], parent_task: Optional[ifcopenshell.entity_instance] = None
) -> None: ) -> None:
ifc.run("sequence.add_task", parent_task=parent_task) ifc.run("sequence.add_task", parent_task=parent_task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
@@ -155,19 +161,19 @@ def add_task(
sequence.load_task_properties() sequence.load_task_properties()
def enable_editing_task_attributes(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def enable_editing_task_attributes(sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
sequence.load_task_attributes(task) sequence.load_task_attributes(task)
sequence.enable_editing_task_attributes(task) sequence.enable_editing_task_attributes(task)
def edit_task(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def edit_task(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
attributes = sequence.get_task_attributes() attributes = sequence.get_task_attributes()
ifc.run("sequence.edit_task", task=task, attributes=attributes) ifc.run("sequence.edit_task", task=task, attributes=attributes)
sequence.load_task_properties(task=task) sequence.load_task_properties(task=task)
sequence.disable_editing_task() sequence.disable_editing_task()
def copy_task_attribute(ifc: tool.Ifc, sequence: tool.Sequence, attribute_name: str) -> None: def copy_task_attribute(ifc: type[tool.Ifc], sequence: type[tool.Sequence], attribute_name: str) -> None:
for task in sequence.get_checked_tasks(): for task in sequence.get_checked_tasks():
ifc.run( ifc.run(
"sequence.edit_task", "sequence.edit_task",
@@ -177,18 +183,20 @@ def copy_task_attribute(ifc: tool.Ifc, sequence: tool.Sequence, attribute_name:
sequence.load_task_properties(task) sequence.load_task_properties(task)
def duplicate_task(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def duplicate_task(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.duplicate_task", task=task) ifc.run("sequence.duplicate_task", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
sequence.load_task_tree(work_schedule) sequence.load_task_tree(work_schedule)
sequence.load_task_properties() sequence.load_task_properties()
def disable_editing_task(sequence: tool.Sequence) -> None: def disable_editing_task(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_task() sequence.disable_editing_task()
def enable_editing_task_time(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def enable_editing_task_time(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance
) -> None:
task_time = sequence.get_task_time(task) task_time = sequence.get_task_time(task)
if task_time is None: if task_time is None:
task_time = ifc.run("sequence.add_task_time", task=task) task_time = ifc.run("sequence.add_task_time", task=task)
@@ -196,7 +204,9 @@ def enable_editing_task_time(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcop
sequence.enable_editing_task_time(task) sequence.enable_editing_task_time(task)
def edit_task_time(ifc: tool.Ifc, sequence: tool.Sequence, resource, task_time: ifcopenshell.entity_instance) -> None: def edit_task_time(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], resource, task_time: ifcopenshell.entity_instance
) -> None:
attributes = sequence.get_task_time_attributes() attributes = sequence.get_task_time_attributes()
# TODO: nasty loop goes on when calendar props are messed up # TODO: nasty loop goes on when calendar props are messed up
ifc.run("sequence.edit_task_time", task_time=task_time, attributes=attributes) ifc.run("sequence.edit_task_time", task_time=task_time, attributes=attributes)
@@ -206,34 +216,36 @@ def edit_task_time(ifc: tool.Ifc, sequence: tool.Sequence, resource, task_time:
resource.load_resource_properties() resource.load_resource_properties()
def assign_predecessor(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def assign_predecessor(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
predecessor_task = sequence.get_highlighted_task() predecessor_task = sequence.get_highlighted_task()
ifc.run("sequence.assign_sequence", relating_process=task, related_process=predecessor_task) ifc.run("sequence.assign_sequence", relating_process=task, related_process=predecessor_task)
sequence.load_task_properties() sequence.load_task_properties()
def unassign_predecessor(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def unassign_predecessor(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance
) -> None:
predecessor_task = sequence.get_highlighted_task() predecessor_task = sequence.get_highlighted_task()
ifc.run("sequence.unassign_sequence", relating_process=task, related_process=predecessor_task) ifc.run("sequence.unassign_sequence", relating_process=task, related_process=predecessor_task)
sequence.load_task_properties() sequence.load_task_properties()
def assign_successor(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def assign_successor(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
successor_task = sequence.get_highlighted_task() successor_task = sequence.get_highlighted_task()
ifc.run("sequence.assign_sequence", relating_process=successor_task, related_process=task) ifc.run("sequence.assign_sequence", relating_process=successor_task, related_process=task)
sequence.load_task_properties() sequence.load_task_properties()
def unassign_successor(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def unassign_successor(ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
successor_task = sequence.get_highlighted_task() successor_task = sequence.get_highlighted_task()
ifc.run("sequence.unassign_sequence", relating_process=successor_task, related_process=task) ifc.run("sequence.unassign_sequence", relating_process=successor_task, related_process=task)
sequence.load_task_properties() sequence.load_task_properties()
def assign_products( def assign_products(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
spatial: tool.Spatial, spatial: type[tool.Spatial],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
products: Optional[list[ifcopenshell.entity_instance]] = None, products: Optional[list[ifcopenshell.entity_instance]] = None,
) -> None: ) -> None:
@@ -244,9 +256,9 @@ def assign_products(
def unassign_products( def unassign_products(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
spatial: tool.Spatial, spatial: type[tool.Spatial],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
products: Optional[list[ifcopenshell.entity_instance]] = None, products: Optional[list[ifcopenshell.entity_instance]] = None,
) -> None: ) -> None:
@@ -257,9 +269,9 @@ def unassign_products(
def assign_input_products( def assign_input_products(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
spatial: tool.Spatial, spatial: type[tool.Spatial],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
products: Optional[list[ifcopenshell.entity_instance]] = None, products: Optional[list[ifcopenshell.entity_instance]] = None,
) -> None: ) -> None:
@@ -270,9 +282,9 @@ def assign_input_products(
def unassign_input_products( def unassign_input_products(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
spatial: tool.Spatial, spatial: type[tool.Spatial],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
products: Optional[list[ifcopenshell.entity_instance]] = None, products: Optional[list[ifcopenshell.entity_instance]] = None,
) -> None: ) -> None:
@@ -282,7 +294,9 @@ def unassign_input_products(
sequence.load_task_inputs(inputs) sequence.load_task_inputs(inputs)
def assign_resource(ifc: tool.Ifc, sequence: tool.Sequence, resource_tool, task: ifcopenshell.entity_instance) -> None: def assign_resource(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], resource_tool, task: ifcopenshell.entity_instance
) -> None:
resource = resource_tool.get_highlighted_resource() resource = resource_tool.get_highlighted_resource()
sub_resource = ifc.run( sub_resource = ifc.run(
"resource.add_resource", "resource.add_resource",
@@ -296,8 +310,8 @@ def assign_resource(ifc: tool.Ifc, sequence: tool.Sequence, resource_tool, task:
def unassign_resource( def unassign_resource(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
resource_tool, resource_tool,
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
resource: ifcopenshell.entity_instance, resource: ifcopenshell.entity_instance,
@@ -308,54 +322,58 @@ def unassign_resource(
resource_tool.load_resources() resource_tool.load_resources()
def remove_work_calendar(ifc: tool.Ifc, work_calendar: ifcopenshell.entity_instance) -> None: def remove_work_calendar(ifc: type[tool.Ifc], work_calendar: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.remove_work_calendar", work_calendar=work_calendar) ifc.run("sequence.remove_work_calendar", work_calendar=work_calendar)
def add_work_calendar(ifc: tool.Ifc) -> ifcopenshell.entity_instance: def add_work_calendar(ifc: type[tool.Ifc]) -> ifcopenshell.entity_instance:
return ifc.run("sequence.add_work_calendar") return ifc.run("sequence.add_work_calendar")
def edit_work_calendar(ifc: tool.Ifc, sequence: tool.Sequence, work_calendar: ifcopenshell.entity_instance) -> None: def edit_work_calendar(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], work_calendar: ifcopenshell.entity_instance
) -> None:
attributes = sequence.get_work_calendar_attributes() attributes = sequence.get_work_calendar_attributes()
ifc.run("sequence.edit_work_calendar", work_calendar=work_calendar, attributes=attributes) ifc.run("sequence.edit_work_calendar", work_calendar=work_calendar, attributes=attributes)
sequence.disable_editing_work_calendar() sequence.disable_editing_work_calendar()
sequence.load_task_properties() sequence.load_task_properties()
def enable_editing_work_calendar(sequence: tool.Sequence, work_calendar: ifcopenshell.entity_instance) -> None: def enable_editing_work_calendar(sequence: type[tool.Sequence], work_calendar: ifcopenshell.entity_instance) -> None:
sequence.load_work_calendar_attributes(work_calendar) sequence.load_work_calendar_attributes(work_calendar)
sequence.enable_editing_work_calendar(work_calendar) sequence.enable_editing_work_calendar(work_calendar)
def disable_editing_work_calendar(sequence: tool.Sequence) -> None: def disable_editing_work_calendar(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_work_calendar() sequence.disable_editing_work_calendar()
def enable_editing_work_calendar_times(sequence: tool.Sequence, work_calendar: ifcopenshell.entity_instance) -> None: def enable_editing_work_calendar_times(
sequence: type[tool.Sequence], work_calendar: ifcopenshell.entity_instance
) -> None:
sequence.enable_editing_work_calendar_times(work_calendar) sequence.enable_editing_work_calendar_times(work_calendar)
def add_work_time( def add_work_time(
ifc: tool.Ifc, work_calendar: ifcopenshell.entity_instance, time_type: ifcopenshell.entity_instance ifc: type[tool.Ifc], work_calendar: ifcopenshell.entity_instance, time_type: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance: ) -> ifcopenshell.entity_instance:
return ifc.run("sequence.add_work_time", work_calendar=work_calendar, time_type=time_type) return ifc.run("sequence.add_work_time", work_calendar=work_calendar, time_type=time_type)
def enable_editing_work_time(sequence: tool.Sequence, work_time: ifcopenshell.entity_instance) -> None: def enable_editing_work_time(sequence: type[tool.Sequence], work_time: ifcopenshell.entity_instance) -> None:
sequence.load_work_time_attributes(work_time) sequence.load_work_time_attributes(work_time)
sequence.enable_editing_work_time(work_time) sequence.enable_editing_work_time(work_time)
def disable_editing_work_time(sequence: tool.Sequence) -> None: def disable_editing_work_time(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_work_time() sequence.disable_editing_work_time()
def remove_work_time(ifc: tool.Ifc, work_time=None) -> None: def remove_work_time(ifc: type[tool.Ifc], work_time=None) -> None:
ifc.run("sequence.remove_work_time", work_time=work_time) ifc.run("sequence.remove_work_time", work_time=work_time)
def edit_work_time(ifc: tool.Ifc, sequence: tool.Sequence) -> None: def edit_work_time(ifc: type[tool.Ifc], sequence: type[tool.Sequence]) -> None:
work_time = sequence.get_active_work_time() work_time = sequence.get_active_work_time()
ifc.run("sequence.edit_work_time", work_time=work_time, attributes=sequence.get_work_time_attributes()) ifc.run("sequence.edit_work_time", work_time=work_time, attributes=sequence.get_work_time_attributes())
recurrence_pattern = work_time.RecurrencePattern recurrence_pattern = work_time.RecurrencePattern
@@ -369,32 +387,34 @@ def edit_work_time(ifc: tool.Ifc, sequence: tool.Sequence) -> None:
def assign_recurrence_pattern( def assign_recurrence_pattern(
ifc: tool.Ifc, work_time: ifcopenshell.entity_instance, recurrence_type: ifcopenshell.entity_instance ifc: type[tool.Ifc], work_time: ifcopenshell.entity_instance, recurrence_type: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance: ) -> ifcopenshell.entity_instance:
return ifc.run("sequence.assign_recurrence_pattern", parent=work_time, recurrence_type=recurrence_type) return ifc.run("sequence.assign_recurrence_pattern", parent=work_time, recurrence_type=recurrence_type)
def unassign_recurrence_pattern(ifc: tool.Ifc, recurrence_pattern: ifcopenshell.entity_instance) -> None: def unassign_recurrence_pattern(ifc: type[tool.Ifc], recurrence_pattern: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.unassign_recurrence_pattern", recurrence_pattern=recurrence_pattern) ifc.run("sequence.unassign_recurrence_pattern", recurrence_pattern=recurrence_pattern)
def add_time_period(ifc: tool.Ifc, sequence: tool.Sequence, recurrence_pattern: ifcopenshell.entity_instance) -> None: def add_time_period(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], recurrence_pattern: ifcopenshell.entity_instance
) -> None:
start_time, end_time = sequence.get_recurrence_pattern_times() start_time, end_time = sequence.get_recurrence_pattern_times()
ifc.run("sequence.add_time_period", recurrence_pattern=recurrence_pattern, start_time=start_time, end_time=end_time) ifc.run("sequence.add_time_period", recurrence_pattern=recurrence_pattern, start_time=start_time, end_time=end_time)
sequence.reset_time_period() sequence.reset_time_period()
def remove_time_period(ifc: tool.Ifc, time_period: ifcopenshell.entity_instance) -> None: def remove_time_period(ifc: type[tool.Ifc], time_period: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.remove_time_period", time_period=time_period) ifc.run("sequence.remove_time_period", time_period=time_period)
def enable_editing_task_calendar(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def enable_editing_task_calendar(sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> None:
sequence.enable_editing_task_calendar(task) sequence.enable_editing_task_calendar(task)
def edit_task_calendar( def edit_task_calendar(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
work_calendar: ifcopenshell.entity_instance, work_calendar: ifcopenshell.entity_instance,
) -> None: ) -> None:
@@ -404,8 +424,8 @@ def edit_task_calendar(
def remove_task_calendar( def remove_task_calendar(
ifc: tool.Ifc, ifc: type[tool.Ifc],
sequence: tool.Sequence, sequence: type[tool.Sequence],
task: ifcopenshell.entity_instance, task: ifcopenshell.entity_instance,
work_calendar: ifcopenshell.entity_instance, work_calendar: ifcopenshell.entity_instance,
) -> None: ) -> None:
@@ -414,38 +434,42 @@ def remove_task_calendar(
sequence.load_task_properties() sequence.load_task_properties()
def enable_editing_task_sequence(sequence: tool.Sequence) -> None: def enable_editing_task_sequence(sequence: type[tool.Sequence]) -> None:
sequence.enable_editing_task_sequence() sequence.enable_editing_task_sequence()
sequence.load_task_properties() sequence.load_task_properties()
def disable_editing_task_time(sequence: tool.Sequence) -> None: def disable_editing_task_time(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_task_time() sequence.disable_editing_task_time()
def enable_editing_sequence_attributes(sequence: tool.Sequence, rel_sequence: ifcopenshell.entity_instance) -> None: def enable_editing_sequence_attributes(
sequence: type[tool.Sequence], rel_sequence: ifcopenshell.entity_instance
) -> None:
sequence.enable_editing_rel_sequence_attributes(rel_sequence) sequence.enable_editing_rel_sequence_attributes(rel_sequence)
sequence.load_rel_sequence_attributes(rel_sequence) sequence.load_rel_sequence_attributes(rel_sequence)
def enable_editing_sequence_lag_time( def enable_editing_sequence_lag_time(
sequence: tool.Sequence, rel_sequence: ifcopenshell.entity_instance, lag_time: ifcopenshell.entity_instance sequence: type[tool.Sequence], rel_sequence: ifcopenshell.entity_instance, lag_time: ifcopenshell.entity_instance
) -> None: ) -> None:
sequence.load_lag_time_attributes(lag_time) sequence.load_lag_time_attributes(lag_time)
sequence.enable_editing_sequence_lag_time(rel_sequence) sequence.enable_editing_sequence_lag_time(rel_sequence)
def unassign_lag_time(ifc: tool.Ifc, sequence: tool.Sequence, rel_sequence: ifcopenshell.entity_instance) -> None: def unassign_lag_time(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], rel_sequence: ifcopenshell.entity_instance
) -> None:
ifc.run("sequence.unassign_lag_time", rel_sequence=rel_sequence) ifc.run("sequence.unassign_lag_time", rel_sequence=rel_sequence)
sequence.load_task_properties() sequence.load_task_properties()
def assign_lag_time(ifc: tool.Ifc, rel_sequence: ifcopenshell.entity_instance) -> None: def assign_lag_time(ifc: type[tool.Ifc], rel_sequence: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.assign_lag_time", rel_sequence=rel_sequence, lag_value="P1D") ifc.run("sequence.assign_lag_time", rel_sequence=rel_sequence, lag_value="P1D")
def edit_sequence_attributes( def edit_sequence_attributes(
ifc: tool.Ifc, sequence: tool.Sequence, rel_sequence: ifcopenshell.entity_instance ifc: type[tool.Ifc], sequence: type[tool.Sequence], rel_sequence: ifcopenshell.entity_instance
) -> None: ) -> None:
attributes = sequence.get_rel_sequence_attributes() attributes = sequence.get_rel_sequence_attributes()
ifc.run("sequence.edit_sequence", rel_sequence=rel_sequence, attributes=attributes) ifc.run("sequence.edit_sequence", rel_sequence=rel_sequence, attributes=attributes)
@@ -453,33 +477,41 @@ def edit_sequence_attributes(
sequence.load_task_properties() sequence.load_task_properties()
def edit_sequence_lag_time(ifc: tool.Ifc, sequence: tool.Sequence, lag_time: ifcopenshell.entity_instance) -> None: def edit_sequence_lag_time(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], lag_time: ifcopenshell.entity_instance
) -> None:
attributes = sequence.get_lag_time_attributes() attributes = sequence.get_lag_time_attributes()
ifc.run("sequence.edit_lag_time", lag_time=lag_time, attributes=attributes) ifc.run("sequence.edit_lag_time", lag_time=lag_time, attributes=attributes)
sequence.disable_editing_rel_sequence() sequence.disable_editing_rel_sequence()
sequence.load_task_properties() sequence.load_task_properties()
def disable_editing_rel_sequence(sequence: tool.Sequence) -> None: def disable_editing_rel_sequence(sequence: type[tool.Sequence]) -> None:
sequence.disable_editing_rel_sequence() sequence.disable_editing_rel_sequence()
def select_task_outputs(sequence: tool.Sequence, spatial: tool.Spatial, task: ifcopenshell.entity_instance) -> None: def select_task_outputs(
sequence: type[tool.Sequence], spatial: type[tool.Spatial], task: ifcopenshell.entity_instance
) -> None:
spatial.select_products(products=sequence.get_task_outputs(task)) spatial.select_products(products=sequence.get_task_outputs(task))
def select_task_inputs(sequence: tool.Sequence, spatial: tool.Spatial, task: ifcopenshell.entity_instance) -> None: def select_task_inputs(
sequence: type[tool.Sequence], spatial: type[tool.Spatial], task: ifcopenshell.entity_instance
) -> None:
spatial.select_products(products=sequence.get_task_inputs(task)) spatial.select_products(products=sequence.get_task_inputs(task))
def select_work_schedule_products( def select_work_schedule_products(
sequence: tool.Sequence, spatial: tool.Spatial, work_schedule: ifcopenshell.entity_instance sequence: type[tool.Sequence], spatial: type[tool.Spatial], work_schedule: ifcopenshell.entity_instance
) -> None: ) -> None:
products = sequence.get_work_schedule_products(work_schedule) products = sequence.get_work_schedule_products(work_schedule)
spatial.select_products(products) spatial.select_products(products)
def select_unassigned_work_schedule_products(ifc: tool.Ifc, sequence: tool.Sequence, spatial: tool.Spatial) -> None: def select_unassigned_work_schedule_products(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], spatial: type[tool.Spatial]
) -> None:
spatial.deselect_objects() spatial.deselect_objects()
products = ifc.get().by_type("IfcElement") products = ifc.get().by_type("IfcElement")
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
@@ -488,11 +520,11 @@ def select_unassigned_work_schedule_products(ifc: tool.Ifc, sequence: tool.Seque
spatial.select_products(selection) spatial.select_products(selection)
def recalculate_schedule(ifc: tool.Ifc, work_schedule: ifcopenshell.entity_instance) -> None: def recalculate_schedule(ifc: type[tool.Ifc], work_schedule: ifcopenshell.entity_instance) -> None:
ifc.run("sequence.recalculate_schedule", work_schedule=work_schedule) ifc.run("sequence.recalculate_schedule", work_schedule=work_schedule)
def add_task_column(sequence: tool.Sequence, column_type: str, name: str, data_type: str) -> None: def add_task_column(sequence: type[tool.Sequence], column_type: str, name: str, data_type: str) -> None:
sequence.add_task_column(column_type, name, data_type) sequence.add_task_column(column_type, name, data_type)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
if work_schedule: if work_schedule:
@@ -500,11 +532,11 @@ def add_task_column(sequence: tool.Sequence, column_type: str, name: str, data_t
sequence.load_task_properties() sequence.load_task_properties()
def remove_task_column(sequence: tool.Sequence, name: str) -> None: def remove_task_column(sequence: type[tool.Sequence], name: str) -> None:
sequence.remove_task_column(name) sequence.remove_task_column(name)
def set_task_sort_column(sequence: tool.Sequence, column: str) -> None: def set_task_sort_column(sequence: type[tool.Sequence], column: str) -> None:
sequence.set_task_sort_column(column) sequence.set_task_sort_column(column)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
if work_schedule: if work_schedule:
@@ -512,7 +544,9 @@ def set_task_sort_column(sequence: tool.Sequence, column: str) -> None:
sequence.load_task_properties() sequence.load_task_properties()
def calculate_task_duration(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> None: def calculate_task_duration(
ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance
) -> None:
ifc.run("sequence.calculate_task_duration", task=task) ifc.run("sequence.calculate_task_duration", task=task)
work_schedule = sequence.get_active_work_schedule() work_schedule = sequence.get_active_work_schedule()
if work_schedule: if work_schedule:
@@ -520,11 +554,13 @@ def calculate_task_duration(ifc: tool.Ifc, sequence: tool.Sequence, task: ifcope
sequence.load_task_properties() sequence.load_task_properties()
def load_animation_color_scheme(sequence: tool.Sequence, scheme: Union[ifcopenshell.entity_instance, None]) -> None: def load_animation_color_scheme(
sequence: type[tool.Sequence], scheme: Union[ifcopenshell.entity_instance, None]
) -> None:
sequence.load_animation_color_scheme(scheme) sequence.load_animation_color_scheme(scheme)
def go_to_task(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> Union[None, str]: def go_to_task(sequence: type[tool.Sequence], task: ifcopenshell.entity_instance) -> Union[None, str]:
work_schedule = sequence.get_work_schedule(task) work_schedule = sequence.get_work_schedule(task)
is_work_schedule_active = sequence.is_work_schedule_active(work_schedule) is_work_schedule_active = sequence.is_work_schedule_active(work_schedule)
if is_work_schedule_active: if is_work_schedule_active:
@@ -533,26 +569,28 @@ def go_to_task(sequence: tool.Sequence, task: ifcopenshell.entity_instance) -> U
return "Work schedule is not active" return "Work schedule is not active"
def guess_date_range(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def guess_date_range(sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance) -> None:
start, finish = sequence.guess_date_range(work_schedule) start, finish = sequence.guess_date_range(work_schedule)
sequence.update_visualisation_date(start, finish) sequence.update_visualisation_date(start, finish)
def setup_default_task_columns(sequence: tool.Sequence) -> None: def setup_default_task_columns(sequence: type[tool.Sequence]) -> None:
sequence.setup_default_task_columns() sequence.setup_default_task_columns()
def add_task_bars(sequence: tool.Sequence) -> None: def add_task_bars(sequence: type[tool.Sequence]) -> None:
tasks = sequence.get_animation_bar_tasks() tasks = sequence.get_animation_bar_tasks()
if tasks: if tasks:
sequence.create_bars(tasks) sequence.create_bars(tasks)
def load_default_animation_color_scheme(sequence: tool.Sequence) -> None: def load_default_animation_color_scheme(sequence: type[tool.Sequence]) -> None:
sequence.load_default_animation_color_scheme() sequence.load_default_animation_color_scheme()
def visualise_work_schedule_date_range(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def visualise_work_schedule_date_range(
sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance
) -> None:
sequence.clear_objects_animation(include_blender_objects=False) sequence.clear_objects_animation(include_blender_objects=False)
settings = sequence.get_animation_settings() settings = sequence.get_animation_settings()
if settings: if settings:
@@ -566,7 +604,7 @@ def visualise_work_schedule_date_range(sequence: tool.Sequence, work_schedule: i
sequence.set_object_shading() sequence.set_object_shading()
def visualise_work_schedule_date(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def visualise_work_schedule_date(sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance) -> None:
sequence.clear_objects_animation(include_blender_objects=False) sequence.clear_objects_animation(include_blender_objects=False)
start_date = sequence.get_start_date() start_date = sequence.get_start_date()
product_states = sequence.process_construction_state(work_schedule, start_date) product_states = sequence.process_construction_state(work_schedule, start_date)
@@ -574,13 +612,13 @@ def visualise_work_schedule_date(sequence: tool.Sequence, work_schedule: ifcopen
sequence.set_object_shading() sequence.set_object_shading()
def generate_gantt_chart(sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance) -> None: def generate_gantt_chart(sequence: type[tool.Sequence], work_schedule: ifcopenshell.entity_instance) -> None:
json = sequence.create_tasks_json(work_schedule) json = sequence.create_tasks_json(work_schedule)
sequence.generate_gantt_browser_chart(json, work_schedule) sequence.generate_gantt_browser_chart(json, work_schedule)
def load_product_related_tasks( def load_product_related_tasks(
sequence: tool.Sequence, product: ifcopenshell.entity_instance sequence: type[tool.Sequence], product: ifcopenshell.entity_instance
) -> Union[list[ifcopenshell.entity_instance], str]: ) -> Union[list[ifcopenshell.entity_instance], str]:
filter_by_schedule = sequence.is_filter_by_active_schedule() filter_by_schedule = sequence.is_filter_by_active_schedule()
if filter_by_schedule: if filter_by_schedule:
@@ -596,7 +634,7 @@ def load_product_related_tasks(
def reorder_task_nesting( def reorder_task_nesting(
ifc: tool.Ifc, sequence: tool.Sequence, task: ifcopenshell.entity_instance, new_index: int ifc: type[tool.Ifc], sequence: type[tool.Sequence], task: ifcopenshell.entity_instance, new_index: int
) -> Union[None, str]: ) -> Union[None, str]:
is_sorting_enabled = sequence.is_sorting_enabled() is_sorting_enabled = sequence.is_sorting_enabled()
is_sort_reversed = sequence.is_sort_reversed() is_sort_reversed = sequence.is_sort_reversed()
@@ -610,18 +648,21 @@ def reorder_task_nesting(
def create_baseline( def create_baseline(
ifc: tool.Ifc, sequence: tool.Sequence, work_schedule: ifcopenshell.entity_instance, name: Optional[str] = None ifc: type[tool.Ifc],
sequence: type[tool.Sequence],
work_schedule: ifcopenshell.entity_instance,
name: Optional[str] = None,
) -> None: ) -> None:
ifc.run("sequence.create_baseline", work_schedule=work_schedule, name=name) ifc.run("sequence.create_baseline", work_schedule=work_schedule, name=name)
def clear_previous_animation(sequence: tool.Sequence) -> None: def clear_previous_animation(sequence: type[tool.Sequence]) -> None:
sequence.clear_objects_animation(include_blender_objects=False) sequence.clear_objects_animation(include_blender_objects=False)
def add_animation_camera(sequence: tool.Sequence) -> None: def add_animation_camera(sequence: type[tool.Sequence]) -> None:
sequence.add_animation_camera() sequence.add_animation_camera()
def save_animation_color_scheme(sequence: tool.Sequence, name: str) -> None: def save_animation_color_scheme(sequence: type[tool.Sequence], name: str) -> None:
sequence.save_animation_color_scheme(name) sequence.save_animation_color_scheme(name)
+44 -28
View File
@@ -26,8 +26,8 @@ if TYPE_CHECKING:
def reference_structure( def reference_structure(
ifc: tool.Ifc, ifc: type[tool.Ifc],
spatial: tool.Spatial, spatial: type[tool.Spatial],
structure: Optional[ifcopenshell.entity_instance] = None, structure: Optional[ifcopenshell.entity_instance] = None,
element: Optional[ifcopenshell.entity_instance] = None, element: Optional[ifcopenshell.entity_instance] = None,
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
@@ -36,8 +36,8 @@ def reference_structure(
def dereference_structure( def dereference_structure(
ifc: tool.Ifc, ifc: type[tool.Ifc],
spatial: tool.Spatial, spatial: type[tool.Spatial],
structure: Optional[ifcopenshell.entity_instance] = None, structure: Optional[ifcopenshell.entity_instance] = None,
element: Optional[ifcopenshell.entity_instance] = None, element: Optional[ifcopenshell.entity_instance] = None,
) -> None: ) -> None:
@@ -46,9 +46,9 @@ def dereference_structure(
def assign_container( def assign_container(
ifc: tool.Ifc, ifc: type[tool.Ifc],
collector: tool.Collector, collector: type[tool.Collector],
spatial: tool.Spatial, spatial: type[tool.Spatial],
container: ifcopenshell.entity_instance, container: ifcopenshell.entity_instance,
element_obj: Optional[bpy.types.Object] = None, element_obj: Optional[bpy.types.Object] = None,
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
@@ -61,24 +61,24 @@ def assign_container(
return rel return rel
def enable_editing_container(spatial: tool.Spatial, obj: bpy.types.Object) -> None: def enable_editing_container(spatial: type[tool.Spatial], obj: bpy.types.Object) -> None:
spatial.set_target_container_as_default() spatial.set_target_container_as_default()
spatial.enable_editing(obj) spatial.enable_editing(obj)
def disable_editing_container(spatial: tool.Spatial, obj: bpy.types.Object) -> None: def disable_editing_container(spatial: type[tool.Spatial], obj: bpy.types.Object) -> None:
spatial.disable_editing(obj) spatial.disable_editing(obj)
def remove_container(ifc: tool.Ifc, collector: tool.Collector, obj: bpy.types.Object) -> None: def remove_container(ifc: type[tool.Ifc], collector: type[tool.Collector], obj: bpy.types.Object) -> None:
ifc.run("spatial.unassign_container", products=[ifc.get_entity(obj)]) ifc.run("spatial.unassign_container", products=[ifc.get_entity(obj)])
collector.assign(obj) collector.assign(obj)
def copy_to_container( def copy_to_container(
ifc: tool.Ifc, ifc: type[tool.Ifc],
collector: tool.Collector, collector: type[tool.Collector],
spatial: tool.Spatial, spatial: type[tool.Spatial],
obj: bpy.types.Object, obj: bpy.types.Object,
containers: list[ifcopenshell.entity_instance], containers: list[ifcopenshell.entity_instance],
) -> list[ifcopenshell.entity_instance]: ) -> list[ifcopenshell.entity_instance]:
@@ -102,57 +102,71 @@ def copy_to_container(
def select_container( def select_container(
ifc: tool.Ifc, spatial: tool.Spatial, container: ifcopenshell.entity_instance, selection_mode: str = "ADD" ifc: type[tool.Ifc],
spatial: type[tool.Spatial],
container: ifcopenshell.entity_instance,
selection_mode: str = "ADD",
) -> None: ) -> None:
spatial.set_active_object(ifc.get_object(container), selection_mode=selection_mode) spatial.set_active_object(ifc.get_object(container), selection_mode=selection_mode)
def select_similar_container(ifc: tool.Ifc, spatial: tool.Spatial, obj: bpy.types.Object) -> None: def select_similar_container(ifc: type[tool.Ifc], spatial: type[tool.Spatial], obj: bpy.types.Object) -> None:
element = ifc.get_entity(obj) element = ifc.get_entity(obj)
if element: if element:
spatial.select_products(spatial.get_decomposed_elements(spatial.get_container(element))) spatial.select_products(spatial.get_decomposed_elements(spatial.get_container(element)))
def select_product(spatial: tool.Spatial, product: ifcopenshell.entity_instance) -> None: def select_product(spatial: type[tool.Spatial], product: ifcopenshell.entity_instance) -> None:
spatial.select_products([product]) spatial.select_products([product])
def import_spatial_decomposition(spatial: tool.Spatial) -> None: def import_spatial_decomposition(spatial: type[tool.Spatial]) -> None:
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def set_orientation_slot(spatial: tool.Spatial, container: ifcopenshell.entity_instance) -> None: def set_orientation_slot(spatial: type[tool.Spatial], container: ifcopenshell.entity_instance) -> None:
spatial.create_orientation_slot(container) spatial.create_orientation_slot(container)
def contract_container(spatial: tool.Spatial, container: ifcopenshell.entity_instance, is_recursive: bool) -> None: def contract_container(
spatial: type[tool.Spatial], container: ifcopenshell.entity_instance, is_recursive: bool
) -> None:
spatial.contract_container(container, is_recursive=is_recursive) spatial.contract_container(container, is_recursive=is_recursive)
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def expand_container(spatial: tool.Spatial, container: ifcopenshell.entity_instance, is_recursive: bool) -> None: def expand_container(spatial: type[tool.Spatial], container: ifcopenshell.entity_instance, is_recursive: bool) -> None:
spatial.expand_container(container, is_recursive=is_recursive) spatial.expand_container(container, is_recursive=is_recursive)
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def delete_container( def delete_container(
ifc: tool.Ifc, spatial: tool.Spatial, geometry: tool.Geometry, container: ifcopenshell.entity_instance ifc: type[tool.Ifc],
spatial: type[tool.Spatial],
geometry: type[tool.Geometry],
container: ifcopenshell.entity_instance,
) -> None: ) -> None:
geometry.delete_ifc_object(ifc.get_object(container)) geometry.delete_ifc_object(ifc.get_object(container))
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def toggle_container_element(spatial: tool.Spatial, element_index: int, is_recursive: bool) -> None: def toggle_container_element(spatial: type[tool.Spatial], element_index: int, is_recursive: bool) -> None:
spatial.toggle_container_element(element_index, is_recursive=is_recursive) spatial.toggle_container_element(element_index, is_recursive=is_recursive)
spatial.load_contained_elements() spatial.load_contained_elements()
def select_decomposed_element(ifc: tool.Ifc, spatial: tool.Spatial, element: ifcopenshell.entity_instance) -> None: def select_decomposed_element(
ifc: type[tool.Ifc], spatial: type[tool.Spatial], element: ifcopenshell.entity_instance
) -> None:
spatial.set_active_object(ifc.get_object(element)) spatial.set_active_object(ifc.get_object(element))
def generate_space( def generate_space(
ifc: tool.Ifc, model: tool.Model, root: tool.Root, spatial: tool.Spatial, type: tool.Type ifc: type[tool.Ifc],
model: type[tool.Model],
root: type[tool.Root],
spatial: type[tool.Spatial],
type: type[tool.Type],
) -> Union[None, str]: ) -> Union[None, str]:
""" """
:return: None if successful, error message string if not. :return: None if successful, error message string if not.
@@ -217,7 +231,9 @@ def generate_space(
spatial.import_spatial_decomposition() spatial.import_spatial_decomposition()
def generate_spaces_from_walls(ifc: tool.Ifc, spatial: tool.Spatial, collector: tool.Collector) -> None: def generate_spaces_from_walls(
ifc: type[tool.Ifc], spatial: type[tool.Spatial], collector: type[tool.Collector]
) -> None:
z = spatial.get_active_obj_z() z = spatial.get_active_obj_z()
h = spatial.get_active_obj_height() h = spatial.get_active_obj_height()
@@ -237,7 +253,7 @@ def generate_spaces_from_walls(ifc: tool.Ifc, spatial: tool.Spatial, collector:
spatial.assign_ifcspace_class_to_obj(obj) spatial.assign_ifcspace_class_to_obj(obj)
def toggle_space_visibility(ifc: tool.Ifc, spatial: tool.Spatial) -> None: def toggle_space_visibility(ifc: type[tool.Ifc], spatial: type[tool.Spatial]) -> None:
model = ifc.get() model = ifc.get()
spaces = model.by_type("IfcSpace") spaces = model.by_type("IfcSpace")
if not spaces: if not spaces:
@@ -245,7 +261,7 @@ def toggle_space_visibility(ifc: tool.Ifc, spatial: tool.Spatial) -> None:
spatial.toggle_spaces_visibility_wired_and_textured(spaces) spatial.toggle_spaces_visibility_wired_and_textured(spaces)
def toggle_hide_spaces(ifc: tool.Ifc, spatial: tool.Spatial) -> None: def toggle_hide_spaces(ifc: type[tool.Ifc], spatial: type[tool.Spatial]) -> None:
model = ifc.get() model = ifc.get()
spaces = model.by_type("IfcSpace") spaces = model.by_type("IfcSpace")
if not spaces: if not spaces:
@@ -253,7 +269,7 @@ def toggle_hide_spaces(ifc: tool.Ifc, spatial: tool.Spatial) -> None:
spatial.toggle_hide_spaces(spaces) spatial.toggle_hide_spaces(spaces)
def set_default_container(spatial: tool.Spatial, container: ifcopenshell.entity_instance) -> None: def set_default_container(spatial: type[tool.Spatial], container: ifcopenshell.entity_instance) -> None:
spatial.set_default_container(container) spatial.set_default_container(container)
+13 -11
View File
@@ -25,7 +25,9 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def add_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) -> ifcopenshell.entity_instance: def add_structural_analysis_model(
ifc: type[tool.Ifc], structural: type[tool.Structural]
) -> ifcopenshell.entity_instance:
result = ifc.run("structural.add_structural_analysis_model") result = ifc.run("structural.add_structural_analysis_model")
structural.load_structural_analysis_models() structural.load_structural_analysis_models()
structural.ensure_representation_contexts() structural.ensure_representation_contexts()
@@ -33,7 +35,7 @@ def add_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) ->
def assign_structural_analysis_model( def assign_structural_analysis_model(
ifc: tool.Ifc, ifc: type[tool.Ifc],
products: list[ifcopenshell.entity_instance], products: list[ifcopenshell.entity_instance],
structural_analysis_model: ifcopenshell.entity_instance, structural_analysis_model: ifcopenshell.entity_instance,
) -> None: ) -> None:
@@ -44,15 +46,15 @@ def assign_structural_analysis_model(
) )
def disable_editing_structural_analysis_model(structural: tool.Structural) -> None: def disable_editing_structural_analysis_model(structural: type[tool.Structural]) -> None:
structural.disable_editing_structural_analysis_model() structural.disable_editing_structural_analysis_model()
def disable_structural_analysis_model_editing_ui(structural: tool.Structural) -> None: def disable_structural_analysis_model_editing_ui(structural: type[tool.Structural]) -> None:
structural.disable_structural_analysis_model_editing_ui() structural.disable_structural_analysis_model_editing_ui()
def edit_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) -> None: def edit_structural_analysis_model(ifc: type[tool.Ifc], structural: type[tool.Structural]) -> None:
attributes = structural.get_structural_analysis_model_attributes() attributes = structural.get_structural_analysis_model_attributes()
ifc.run( ifc.run(
"structural.edit_structural_analysis_model", "structural.edit_structural_analysis_model",
@@ -63,28 +65,28 @@ def edit_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural) -
structural.disable_editing_structural_analysis_model() structural.disable_editing_structural_analysis_model()
def enable_editing_structural_analysis_model(structural: tool.Structural, model: Union[int, None]) -> None: def enable_editing_structural_analysis_model(structural: type[tool.Structural], model: Union[int, None]) -> None:
structural.enable_editing_structural_analysis_model(model) structural.enable_editing_structural_analysis_model(model)
def enable_structural_analysis_model_editing_ui(structural: tool.Structural) -> None: def enable_structural_analysis_model_editing_ui(structural: type[tool.Structural]) -> None:
structural.enable_structural_analysis_model_editing_ui() structural.enable_structural_analysis_model_editing_ui()
def load_structural_analysis_model_attributes(structural: tool.Structural, model: Union[int, None]) -> None: def load_structural_analysis_model_attributes(structural: type[tool.Structural], model: Union[int, None]) -> None:
data = structural.get_ifc_structural_analysis_model_attributes(model) data = structural.get_ifc_structural_analysis_model_attributes(model)
if data is None: if data is None:
return return
structural.load_structural_analysis_model_attributes(data) structural.load_structural_analysis_model_attributes(data)
def load_structural_analysis_models(structural: tool.Structural) -> None: def load_structural_analysis_models(structural: type[tool.Structural]) -> None:
structural.load_structural_analysis_models() structural.load_structural_analysis_models()
structural.enable_structural_analysis_model_editing_ui() structural.enable_structural_analysis_model_editing_ui()
# structural.disable_editing_structural_analysis_model() # structural.disable_editing_structural_analysis_model()
def remove_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural, model: int) -> None: def remove_structural_analysis_model(ifc: type[tool.Ifc], structural: type[tool.Structural], model: int) -> None:
ifc.run( ifc.run(
"structural.remove_structural_analysis_model", "structural.remove_structural_analysis_model",
structural_analysis_model=ifc.get().by_id(model), structural_analysis_model=ifc.get().by_id(model),
@@ -93,7 +95,7 @@ def remove_structural_analysis_model(ifc: tool.Ifc, structural: tool.Structural,
def unassign_structural_analysis_model( def unassign_structural_analysis_model(
ifc: tool.Ifc, ifc: type[tool.Ifc],
products: list[ifcopenshell.entity_instance], products: list[ifcopenshell.entity_instance],
structural_analysis_model: ifcopenshell.entity_instance, structural_analysis_model: ifcopenshell.entity_instance,
) -> None: ) -> None:
+19 -17
View File
@@ -25,62 +25,62 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def load_systems(system: tool.System) -> None: def load_systems(system: type[tool.System]) -> None:
system.import_systems() system.import_systems()
system.enable_system_editing_ui() system.enable_system_editing_ui()
system.disable_editing_system() system.disable_editing_system()
def disable_system_editing_ui(system: tool.System) -> None: def disable_system_editing_ui(system: type[tool.System]) -> None:
system.disable_editing_system() system.disable_editing_system()
system.disable_system_editing_ui() system.disable_system_editing_ui()
def add_system(ifc: tool.Ifc, system: tool.System, ifc_class: str) -> None: def add_system(ifc: type[tool.Ifc], system: type[tool.System], ifc_class: str) -> None:
ifc.run("system.add_system", ifc_class=ifc_class) ifc.run("system.add_system", ifc_class=ifc_class)
system.import_systems() system.import_systems()
def edit_system(ifc: tool.Ifc, system_tool: tool.System, system: ifcopenshell.entity_instance) -> None: def edit_system(ifc: type[tool.Ifc], system_tool: type[tool.System], system: ifcopenshell.entity_instance) -> None:
attributes = system_tool.export_system_attributes() attributes = system_tool.export_system_attributes()
ifc.run("system.edit_system", system=system, attributes=attributes) ifc.run("system.edit_system", system=system, attributes=attributes)
system_tool.disable_editing_system() system_tool.disable_editing_system()
system_tool.import_systems() system_tool.import_systems()
def remove_system(ifc: tool.Ifc, system_tool: tool.System, system: ifcopenshell.entity_instance) -> None: def remove_system(ifc: type[tool.Ifc], system_tool: type[tool.System], system: ifcopenshell.entity_instance) -> None:
ifc.run("system.remove_system", system=system) ifc.run("system.remove_system", system=system)
system_tool.import_systems() system_tool.import_systems()
def enable_editing_system(system_tool: tool.System, system: ifcopenshell.entity_instance) -> None: def enable_editing_system(system_tool: type[tool.System], system: ifcopenshell.entity_instance) -> None:
system_tool.import_system_attributes(system) system_tool.import_system_attributes(system)
system_tool.set_active_edited_system(system) system_tool.set_active_edited_system(system)
def disable_editing_system(system: tool.System) -> None: def disable_editing_system(system: type[tool.System]) -> None:
system.disable_editing_system() system.disable_editing_system()
def assign_system( def assign_system(
ifc: tool.Ifc, system: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance] ifc: type[tool.Ifc], system: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance]
) -> None: ) -> None:
ifc.run("system.assign_system", products=products, system=system) ifc.run("system.assign_system", products=products, system=system)
def unassign_system( def unassign_system(
ifc: tool.Ifc, system: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance] ifc: type[tool.Ifc], system: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance]
) -> None: ) -> None:
ifc.run("system.unassign_system", products=products, system=system) ifc.run("system.unassign_system", products=products, system=system)
def select_system_products(system_tool: tool.System, system: ifcopenshell.entity_instance) -> None: def select_system_products(system_tool: type[tool.System], system: ifcopenshell.entity_instance) -> None:
system_tool.select_system_products(system) system_tool.select_system_products(system)
system_tool.set_active_system(system) system_tool.set_active_system(system)
def show_ports( def show_ports(
ifc: tool.Ifc, system: tool.System, spatial: tool.Spatial, element: ifcopenshell.entity_instance ifc: type[tool.Ifc], system: type[tool.System], spatial: type[tool.Spatial], element: ifcopenshell.entity_instance
) -> None: ) -> None:
obj = ifc.get_object(element) obj = ifc.get_object(element)
if obj and ifc.is_moved(obj): if obj and ifc.is_moved(obj):
@@ -91,7 +91,7 @@ def show_ports(
spatial.select_products(ports) spatial.select_products(ports)
def hide_ports(ifc: tool.Ifc, system: tool.System, element: ifcopenshell.entity_instance) -> None: def hide_ports(ifc: type[tool.Ifc], system: type[tool.System], element: ifcopenshell.entity_instance) -> None:
obj = ifc.get_object(element) obj = ifc.get_object(element)
if obj and ifc.is_moved(obj): if obj and ifc.is_moved(obj):
system.run_geometry_edit_object_placement(obj=obj) system.run_geometry_edit_object_placement(obj=obj)
@@ -105,27 +105,29 @@ def hide_ports(ifc: tool.Ifc, system: tool.System, element: ifcopenshell.entity_
system.delete_element_objects(ports) system.delete_element_objects(ports)
def add_port(ifc: tool.Ifc, system: tool.System, element: ifcopenshell.entity_instance) -> None: def add_port(ifc: type[tool.Ifc], system: type[tool.System], element: ifcopenshell.entity_instance) -> None:
system.load_ports(element, system.get_ports(element)) system.load_ports(element, system.get_ports(element))
obj = system.create_empty_at_cursor_with_element_orientation(element) obj = system.create_empty_at_cursor_with_element_orientation(element)
port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort", should_add_representation=False) port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort", should_add_representation=False)
ifc.run("system.assign_port", element=element, port=port) ifc.run("system.assign_port", element=element, port=port)
def remove_port(ifc: tool.Ifc, system: tool.System, port: ifcopenshell.entity_instance) -> None: def remove_port(ifc: type[tool.Ifc], system: type[tool.System], port: ifcopenshell.entity_instance) -> None:
system.delete_element_objects([port]) system.delete_element_objects([port])
ifc.run("root.remove_product", product=port) ifc.run("root.remove_product", product=port)
def connect_port(ifc: tool.Ifc, port1: ifcopenshell.entity_instance, port2: ifcopenshell.entity_instance) -> None: def connect_port(ifc: type[tool.Ifc], port1: ifcopenshell.entity_instance, port2: ifcopenshell.entity_instance) -> None:
ifc.run("system.connect_port", port1=port1, port2=port2) ifc.run("system.connect_port", port1=port1, port2=port2)
def disconnect_port(ifc: tool.Ifc, port: ifcopenshell.entity_instance) -> None: def disconnect_port(ifc: type[tool.Ifc], port: ifcopenshell.entity_instance) -> None:
ifc.run("system.disconnect_port", port=port) ifc.run("system.disconnect_port", port=port)
def set_flow_direction(ifc: tool.Ifc, system: tool.System, port: ifcopenshell.entity_instance, direction: str) -> None: def set_flow_direction(
ifc: type[tool.Ifc], system: type[tool.System], port: ifcopenshell.entity_instance, direction: str
) -> None:
port2 = system.get_connected_port(port) port2 = system.get_connected_port(port)
if not port2: if not port2:
return return
+32 -5
View File
@@ -1,8 +1,35 @@
def generate_port_number(web): # Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Union
if TYPE_CHECKING:
import bpy
import ifcopenshell
import bonsai.tool as tool
def generate_port_number(web: type[tool.Web]) -> int:
return web.generate_port_number() return web.generate_port_number()
def connect_websocket_server(web, port, page): def connect_websocket_server(web: type[tool.Web], port: int, page: str) -> None:
# check if port already has a server listening to it # check if port already has a server listening to it
if web.is_port_available(port): if web.is_port_available(port):
web.start_websocket_server(port) web.start_websocket_server(port)
@@ -15,13 +42,13 @@ def connect_websocket_server(web, port, page):
web.connect_websocket_server(port) web.connect_websocket_server(port)
def disconnect_websocket_server(web): def disconnect_websocket_server(web: type[tool.Web]) -> None:
web.disconnect_websocket_server() web.disconnect_websocket_server()
def kill_websocket_server(web): def kill_websocket_server(web: type[tool.Web]) -> None:
web.kill_websocket_server() web.kill_websocket_server()
def open_web_browser(web, port, page): def open_web_browser(web: type[tool.Web], port: int, page: str) -> None:
web.open_web_browser(port, page) web.open_web_browser(port, page)
-1
View File
@@ -159,7 +159,6 @@ class Project(bonsai.core.tool.Project):
@classmethod @classmethod
def set_default_modeling_dimensions(cls) -> None: def set_default_modeling_dimensions(cls) -> None:
props = tool.Model.get_model_props() props = tool.Model.get_model_props()
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
props.extrusion_depth = 3 props.extrusion_depth = 3
props.length = 1 props.length = 1
props.rl1 = 0 props.rl1 = 0
+11 -6
View File
@@ -355,6 +355,16 @@ class Snap(bonsai.core.tool.Snap):
# Objects # Objects
objs_to_raycast = tool.Raycast.filter_objects_to_raycast(context, event, objs_2d_bbox) objs_to_raycast = tool.Raycast.filter_objects_to_raycast(context, event, objs_2d_bbox)
# Wireframes
# For wireframe we have to get all the objects so we can further calculate edge intersection
for snap_obj in objs_to_raycast:
if snap_obj.type in {"EMPTY", "CURVE"} or (snap_obj.type == "MESH" and len(snap_obj.data.polygons) == 0):
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, snap_obj)
if snap_points:
for point in snap_points:
point["group"] = "Wireframe"
detected_snaps.append(point)
if (space.shading.type == "SOLID" and space.shading.show_xray) or ( if (space.shading.type == "SOLID" and space.shading.show_xray) or (
space.shading.type == "WIREFRAME" and space.shading.show_xray_wireframe space.shading.type == "WIREFRAME" and space.shading.show_xray_wireframe
): ):
@@ -374,12 +384,7 @@ class Snap(bonsai.core.tool.Snap):
if snap_obj.type in {"EMPTY", "CURVE"} or ( if snap_obj.type in {"EMPTY", "CURVE"} or (
snap_obj.type == "MESH" and len(snap_obj.data.polygons) == 0 snap_obj.type == "MESH" and len(snap_obj.data.polygons) == 0
): ):
snap_points = tool.Raycast.ray_cast_by_proximity(context, event, snap_obj) continue
if snap_points:
for point in snap_points:
point["group"] = "Wireframe"
detected_snaps.append(point)
# Meshes # Meshes
else: else:
# Add face snap # Add face snap
+5 -1
View File
@@ -69,6 +69,7 @@ class Unit(bonsai.core.tool.Unit):
def get_scene_unit_name(cls, unit_type: UNIT_TYPE) -> str: def get_scene_unit_name(cls, unit_type: UNIT_TYPE) -> str:
bim_props = tool.Blender.get_bim_props() bim_props = tool.Blender.get_bim_props()
if unit_type == "LENGTHUNIT": if unit_type == "LENGTHUNIT":
assert bpy.context.scene
props = bpy.context.scene.unit_settings props = bpy.context.scene.unit_settings
if props.length_unit == "MILES": if props.length_unit == "MILES":
return "mile" return "mile"
@@ -84,12 +85,13 @@ class Unit(bonsai.core.tool.Unit):
elif unit_type == "VOLUMEUNIT": elif unit_type == "VOLUMEUNIT":
return bim_props.volume_unit return bim_props.volume_unit
else: else:
assert_never() assert_never(unit_type)
@classmethod @classmethod
def get_scene_unit_si_prefix(cls, unit_type: UNIT_TYPE) -> Union[str, None]: def get_scene_unit_si_prefix(cls, unit_type: UNIT_TYPE) -> Union[str, None]:
bim_props = tool.Blender.get_bim_props() bim_props = tool.Blender.get_bim_props()
if unit_type == "LENGTHUNIT": if unit_type == "LENGTHUNIT":
assert bpy.context.scene
props = bpy.context.scene.unit_settings props = bpy.context.scene.unit_settings
if props.length_unit == "ADAPTIVE" or props.length_unit == "METERS": if props.length_unit == "ADAPTIVE" or props.length_unit == "METERS":
return return
@@ -163,6 +165,7 @@ class Unit(bonsai.core.tool.Unit):
@classmethod @classmethod
def is_scene_unit_metric(cls) -> bool: def is_scene_unit_metric(cls) -> bool:
assert bpy.context.scene
return bpy.context.scene.unit_settings.system in ["METRIC", "NONE"] return bpy.context.scene.unit_settings.system in ["METRIC", "NONE"]
@classmethod @classmethod
@@ -189,6 +192,7 @@ class Unit(bonsai.core.tool.Unit):
@classmethod @classmethod
def blender_format_unit(cls, value: float) -> str: def blender_format_unit(cls, value: float) -> str:
assert bpy.context.scene
return bpy.utils.units.to_string( return bpy.utils.units.to_string(
bpy.context.scene.unit_settings.system, bpy.context.scene.unit_settings.system,
"LENGTH", "LENGTH",
+652
View File
@@ -0,0 +1,652 @@
#include "Iterator.h"
/**
* @return Returns true if the iterator is initialized with any elements, false otherwise.
*
* @note
* - A true return value does not guarantee successful initialization of all elements.
* Some elements may have failed to initialize. Check had_error_processing_elements()
* to see whether there were errors during the initialization.
*
* - For non-concurrent iterators, a false return may occur if initialization of the first
* element fails, even if subsequent elements could be initialized successfully.
*/
bool IfcGeom::Iterator::initialize() {
using std::chrono::high_resolution_clock;
if (initialization_outcome_) {
return *initialization_outcome_;
}
time_points[0] = high_resolution_clock::now();
std::vector<ifcopenshell::geometry::geometry_conversion_task> reps;
if (num_threads_ != 1) {
// @todo this shouldn't be necessary with properly immutable taxonomy items
converter_->mapping()->use_caching() = false;
}
try {
converter_->mapping()->get_representations(reps, filters_);
} catch (const std::exception& e) {
Logger::Error(e);
}
time_points[1] = high_resolution_clock::now();
for (auto& task : reps) {
geometry_conversion_result res;
res.index = task.index;
if (!settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get()) {
res.representation = task.representation;
res.products_2 = task.products;
} else {
res.item = converter_->mapping()->map(task.representation);
if (!res.item) {
continue;
}
std::transform(task.products->begin(), task.products->end(), std::back_inserter(res.products), [this, &res](IfcUtil::IfcBaseClass* prod) {
auto prod_item = converter_->mapping()->map(prod);
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
});
}
tasks_.push_back(res);
}
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() && settings_.get<ifcopenshell::geometry::settings::PermissiveShapeReuse>().get()) {
std::unordered_map<
ifcopenshell::geometry::taxonomy::item::ptr,
std::vector<std::pair<const IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
for (auto& r : tasks_) {
auto i = r.item;
Eigen::Matrix4d m4 = Eigen::Matrix4d::Identity();
while (auto col = std::dynamic_pointer_cast<ifcopenshell::geometry::taxonomy::collection>(i)) {
if (col->children.size() == 1) {
if (col->matrix) {
m4 *= col->matrix->ccomponents();
}
i = col->children[0];
} else {
break;
}
}
for (auto& p : r.products) {
auto pl = ifcopenshell::geometry::taxonomy::matrix4::ptr(p.second->clone_());
pl->components() *= m4;
folded[i].push_back(
{ p.first, pl }
);
}
}
if (folded.size() < tasks_.size()) {
auto old_size = tasks_.size();
tasks_.clear();
size_t i = 0;
for (auto& p : folded) {
tasks_.emplace_back();
tasks_.back().index = i++;
tasks_.back().item = p.first;
tasks_.back().products = p.second;
}
Logger::Notice("Merged " + std::to_string(old_size) + " tasks into " + std::to_string(tasks_.size()) + " tasks due to permissive shape reuse");
}
}
size_t num_products = 0;
for (auto& r : tasks_) {
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2->size() : r.products.size();
}
time_points[2] = high_resolution_clock::now();
/*
// What to do, map representation and product individually?
// There needs to be two options, mapped item respecting (does that still work?), and optimized based on topology sorting.
// Or is the sorting not necessary if we just cache?
std::vector<taxonomy::ptr> items;
std::map<taxonomy::ptr, taxonomy::matrix4> placements;
std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](IfcUtil::IfcBaseClass* p) {
auto item = converter_->mapping()->map(p);
// Product placements do not affect item reuse and should temporarily be swapped to identity
if (item) {
std::swap(placements[item], ((taxonomy::geom_ptr)item)->matrix);
}
return item;
});
items.erase(std::remove(items.begin(), items.end(), nullptr), items.end());
std::sort(items.begin(), items.end(), taxonomy::less);
auto it = items.begin();
while (it < items.end()) {
auto jt = std::upper_bound(it, items.end(), *it, taxonomy::less);
geometry_conversion_result r;
r.item = *it;
std::transform(it, jt, std::back_inserter(r.products), [&r, &placements](taxonomy::ptr product_node) {
return std::make_pair((IfcUtil::IfcBaseEntity*) product_node->instance, placements[product_node]);
});
tasks_.push_back(r);
it = jt;
}
*/
Logger::Notice("Created " + boost::lexical_cast<std::string>(tasks_.size()) + " tasks for " + boost::lexical_cast<std::string>(num_products) + " products");
if (tasks_.size() == 0) {
Logger::Warning("No representations encountered, aborting");
initialization_outcome_.reset(false);
} else {
task_iterator_ = tasks_.begin();
task_result_index_ = 0;
done = 0;
total = (int)tasks_.size();
if (num_threads_ != 1) {
init_future_ = std::async(std::launch::async, [this]() { process_concurrently(); });
// wait for the first element, because after init(), get() can be called.
// so the element conversion must succeed
initialization_outcome_ = wait_for_element();
} else {
initialization_outcome_ = create();
}
}
return *initialization_outcome_;
}
void IfcGeom::Iterator::process_finished_rep(geometry_conversion_result* rep) {
if (rep->elements.empty()) {
return;
}
std::lock_guard<std::mutex> lk(element_ready_mutex_);
all_processed_elements_.insert(all_processed_elements_.end(), rep->elements.begin(), rep->elements.end());
all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep->breps.begin(), rep->breps.end());
if (!task_result_ptr_initialized) {
task_result_iterator_ = all_processed_elements_.begin();
native_task_result_iterator_ = all_processed_native_elements_.begin();
task_result_ptr_initialized = true;
}
progress_ = (int)(++processed_ * 100 / tasks_.size());
}
void IfcGeom::Iterator::process_concurrently() {
size_t conc_threads = num_threads_;
if (conc_threads > tasks_.size()) {
conc_threads = tasks_.size();
}
kernel_pool.reserve(conc_threads);
for (unsigned i = 0; i < conc_threads; ++i) {
kernel_pool.push_back(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_));
}
std::vector<std::future<geometry_conversion_result*>> threadpool;
for (auto& rep : tasks_) {
ifcopenshell::geometry::Converter* K = nullptr;
if (threadpool.size() < kernel_pool.size()) {
K = kernel_pool[threadpool.size()];
}
while (threadpool.size() == conc_threads) {
for (int i = 0; i < (int)threadpool.size(); i++) {
auto& fu = threadpool[i];
std::future_status status;
status = fu.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
process_finished_rep(fu.get());
std::swap(threadpool[i], threadpool.back());
threadpool.pop_back();
std::swap(kernel_pool[i], kernel_pool.back());
K = kernel_pool.back();
break;
} // if
} // for
} // while
std::future<geometry_conversion_result*> fu = std::async(
std::launch::async, [this](
ifcopenshell::geometry::Converter* kernel,
ifcopenshell::geometry::Settings settings,
geometry_conversion_result* rep) {
// Catch exceptions to be safe from freezing the iterator.
try {
this->create_element_(kernel, settings, rep);
} catch (const std::exception& e) {
Logger::Error(
std::string("Exception '") + e.what() +
std::string("' occurred while iterator was creating a shape: "),
rep->item->instance
);
had_error_processing_elements_ = true;
} catch (...) {
Logger::Error(
"Unknown exception occurred while iteartor was creating a shape: ",
rep->item->instance
);
had_error_processing_elements_ = true;
}
return rep;
},
K,
std::ref(settings_),
&rep);
if (terminating_) {
break;
}
threadpool.emplace_back(std::move(fu));
}
for (auto& fu : threadpool) {
process_finished_rep(fu.get());
}
finished_ = true;
Logger::SetProduct(boost::none);
if (!terminating_) {
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
" objects) ");
}
}
/// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files.
void IfcGeom::Iterator::compute_bounds(bool with_geometry)
{
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::numeric_limits<double>::infinity();
bounds_max_.components()(i) = -std::numeric_limits<double>::infinity();
}
if (with_geometry) {
size_t num_created = 0;
do {
IfcGeom::Element* geom_object = get();
const IfcGeom::TriangulationElement* o = static_cast<const IfcGeom::TriangulationElement*>(geom_object);
const IfcGeom::Representation::Triangulation& mesh = o->geometry();
auto mat = o->transformation().data()->ccomponents();
Eigen::Vector4d vec, transformed;
for (typename std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end();) {
const double& x = *(it++);
const double& y = *(it++);
const double& z = *(it++);
vec << x, y, z, 1.;
transformed = mat * vec;
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::min(bounds_min_.components()(i), transformed(i));
bounds_max_.components()(i) = std::max(bounds_max_.components()(i), transformed(i));
}
}
} while (++num_created, next());
} else {
std::vector<ifcopenshell::geometry::geometry_conversion_task> reps;
converter_->mapping()->get_representations(reps, filters_);
std::vector<IfcUtil::IfcBaseClass*> products;
for (auto& r : reps) {
std::copy(r.products->begin(), r.products->end(), std::back_inserter(products));
}
for (auto& product : products) {
auto prod_item = converter_->mapping()->map(product);
auto vec = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix->translation_part();
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::min(bounds_min_.components()(i), vec(i));
bounds_max_.components()(i) = std::max(bounds_max_.components()(i), vec(i));
}
}
}
}
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create_shape_model_for_next_entity() {
geometry_conversion_result* task = nullptr;
for (; task_iterator_ < tasks_.end();) {
task = &*task_iterator_++;
create_element_(converter_, settings_, task);
if (task->elements.empty()) {
task = nullptr;
} else {
break;
}
}
if (task) {
process_finished_rep(task);
return task->item->instance->as<IfcUtil::IfcBaseClass>();
} else {
return nullptr;
}
}
void IfcGeom::Iterator::create_element_(ifcopenshell::geometry::Converter* kernel, ifcopenshell::geometry::Settings settings, geometry_conversion_result* rep)
{
if (!settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get()) {
rep->item = kernel->mapping()->map(rep->representation);
if (!rep->item) {
return;
}
std::transform(rep->products_2->begin(), rep->products_2->end(), std::back_inserter(rep->products), [this, &rep, kernel](IfcUtil::IfcBaseClass* prod) {
auto prod_item = kernel->mapping()->map(prod);
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
});
} else {
}
auto product_node = rep->products.front();
const IfcUtil::IfcBaseEntity* product = product_node.first;
const auto& place = product_node.second;
Logger::SetProduct(product);
IfcGeom::BRepElement* brep = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product, place, rep]() {
return kernel->create_brep_for_representation_and_product(rep->item, product, place);
}));
if (!brep) {
return;
}
auto elem = process_based_on_settings(settings, brep);
if (!elem) {
return;
}
rep->breps = { brep };
rep->elements = { elem };
for (auto it = rep->products.begin() + 1; it != rep->products.end(); ++it) {
const auto& p = *it;
const IfcUtil::IfcBaseEntity* product2 = p.first;
const auto& place2 = p.second;
IfcGeom::BRepElement* brep2 = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product2->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product2, place2, brep]() {
return kernel->create_brep_for_processed_representation(product2, place2, brep);
}));
if (brep2) {
auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast<IfcGeom::TriangulationElement*>(elem));
if (elem2) {
rep->breps.push_back(brep2);
rep->elements.push_back(elem2);
}
}
}
}
IfcGeom::Element* IfcGeom::Iterator::process_based_on_settings(ifcopenshell::geometry::Settings settings, IfcGeom::BRepElement* elem, IfcGeom::TriangulationElement* previous)
{
if (settings.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::SERIALIZED) {
try {
return new IfcGeom::SerializedElement(*elem);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
return nullptr;
}
} else if (settings.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::TRIANGULATED) {
// the part before the hyphen is the representation id
auto gid2 = elem->geometry().id();
auto hyphen = gid2.find("-");
if (hyphen != std::string::npos) {
gid2 = gid2.substr(0, hyphen);
}
return decorate_with_cache_(GeometrySerializer::READ_TRIANGULATION, elem->guid(), gid2, [elem, previous]() {
try {
if (!previous) {
return new TriangulationElement(*elem);
} else {
return new TriangulationElement(*elem, previous->geometry_pointer());
}
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
}
return (TriangulationElement*)nullptr;
});
} else {
return elem;
}
}
bool IfcGeom::Iterator::wait_for_element() {
while (true) {
size_t s;
{
std::lock_guard<std::mutex> lk(element_ready_mutex_);
s = all_processed_elements_.size();
}
if (s > async_elements_returned_) {
++async_elements_returned_;
return true;
} else if (finished_) {
return false;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}
void IfcGeom::Iterator::log_timepoints() const {
using std::chrono::high_resolution_clock;
using std::chrono::duration;
using namespace std::string_literals;
std::array<std::string, 3> labels = {
"Initializing mapping"s,
"Performing mapping"s,
"Geometry interpretation"s
};
for (auto it = time_points.begin() + 1; it != time_points.end(); ++it) {
auto jt = it - 1;
duration<double, std::milli> ms_double = (*it) - (*jt);
Logger::Notice(labels[std::distance(time_points.begin(), jt)] + " took " + std::to_string(ms_double.count()) + "ms");
}
}
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::next() {
using std::chrono::high_resolution_clock;
if (*native_task_result_iterator_ != *task_result_iterator_) {
delete* native_task_result_iterator_;
}
delete* task_result_iterator_;
if (num_threads_ != 1) {
if (!wait_for_element()) {
Logger::SetProduct(boost::none);
time_points[3] = high_resolution_clock::now();
log_timepoints();
return nullptr;
}
task_result_iterator_++;
native_task_result_iterator_++;
return (*task_result_iterator_)->product();
} else {
// Increment the iterator over the list of products using the current
// shape representation
if (task_result_iterator_ == --all_processed_elements_.end()) {
if (!create()) {
Logger::SetProduct(boost::none);
time_points[3] = high_resolution_clock::now();
log_timepoints();
return nullptr;
}
}
task_result_iterator_++;
native_task_result_iterator_++;
return (*task_result_iterator_)->product();
}
}
/// Gets the representation of the current geometrical entity.
IfcGeom::Element* IfcGeom::Iterator::get()
{
if (!initialization_outcome_) {
throw std::runtime_error("Iterator not initialized");
}
auto ret = *task_result_iterator_;
// If we want to organize the element considering their hierarchy
if (settings_.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get()) {
// We are going to build a vector with the element parents.
// First, create the parent vector
std::vector<const IfcGeom::Element*> parents;
// if the element has a parent
if (ret->parent_id() != -1) {
const IfcGeom::Element* parent_object = NULL;
bool hasParent = true;
// get the parent
try {
parent_object = get_object(ret->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
// We need to find all the parents
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1) {
// Find the next parent
try {
parent_object = get_object(parent_object->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
hasParent = hasParent && parent_object->parent_id() != -1;
}
// when done push the parent list in the Element object
ret->SetParents(parents);
}
}
return ret;
}
const IfcGeom::Element* IfcGeom::Iterator::get_object(int id) {
ifcopenshell::geometry::taxonomy::matrix4::ptr m4;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
IfcUtil::IfcBaseEntity* ifc_product = 0;
try {
ifc_product = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
instance_type = ifc_product->declaration().name();
if (ifc_product->declaration().is("IfcRoot")) {
product_guid = (std::string)ifc_product->get("GlobalId");
product_name = ifc_product->get_value<std::string>("Name", "");
}
auto parent_object = converter_->mapping()->get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->id();
}
// fails in case of IfcProject
auto mapped = converter_->mapping()->map(ifc_product);
auto casted = mapped ? ifcopenshell::geometry::taxonomy::dcast<ifcopenshell::geometry::taxonomy::geom_item>(mapped) : nullptr;
if (casted) {
m4 = casted->matrix;
}
} catch (const std::exception& e) {
Logger::Error(e);
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error returning product");
}
}
#endif
catch (...) {
Logger::Error("Unknown error returning product");
}
Element* ifc_object = new Element(settings_, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product);
return ifc_object;
}
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create() {
const IfcUtil::IfcBaseClass* product = nullptr;
try {
product = create_shape_model_for_next_entity();
} catch (const std::exception& e) {
Logger::Error(e);
had_error_processing_elements_ = true;
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error creating geometry");
}
had_error_processing_elements_ = true;
}
#endif
catch (...) {
Logger::Error("Unknown error creating geometry");
had_error_processing_elements_ = true;
}
return product;
}
IfcGeom::Iterator::~Iterator() {
if (num_threads_ != 1) {
terminating_ = true;
if (init_future_.valid()) {
init_future_.wait();
}
}
for (auto& k : kernel_pool) {
delete k;
}
if (task_result_ptr_initialized) {
while (task_result_iterator_ != --all_processed_elements_.end()) {
if (*native_task_result_iterator_ != *task_result_iterator_) {
delete* native_task_result_iterator_;
}
delete* task_result_iterator_++;
native_task_result_iterator_++;
}
}
delete converter_;
}
+67 -696
View File
@@ -123,7 +123,6 @@ namespace IfcGeom {
std::mutex element_ready_mutex_; std::mutex element_ready_mutex_;
bool task_result_ptr_initialized = false; bool task_result_ptr_initialized = false;
// ?
size_t async_elements_returned_ = 0; size_t async_elements_returned_ = 0;
size_t task_result_index_ = 0; size_t task_result_index_ = 0;
@@ -155,354 +154,10 @@ namespace IfcGeom {
// Should not be destructed because, destructor is blocking // Should not be destructed because, destructor is blocking
std::future<void> init_future_; std::future<void> init_future_;
std::mutex caching_mutex_;
std::array<std::chrono::high_resolution_clock::time_point, 4> time_points; std::array<std::chrono::high_resolution_clock::time_point, 4> time_points;
/// @todo public/private sections all over the place: move all public to the beginning of the class
public:
void set_cache(GeometrySerializer* cache) { cache_ = cache; }
const std::string& unit_name() const { return converter_->mapping()->get_length_unit_name(); }
double unit_magnitude() const { return converter_->mapping()->get_length_unit(); }
// Check if error occurred during iterator initialization or iteration over elements.
bool had_error_processing_elements() const { return had_error_processing_elements_; }
boost::optional<bool> initialization_outcome_;
/**
* @return Returns true if the iterator is initialized with any elements, false otherwise.
*
* @note
* - A true return value does not guarantee successful initialization of all elements.
* Some elements may have failed to initialize. Check had_error_processing_elements()
* to see whether there were errors during the initialization.
*
* - For non-concurrent iterators, a false return may occur if initialization of the first
* element fails, even if subsequent elements could be initialized successfully.
*/
bool initialize() {
using std::chrono::high_resolution_clock;
if (initialization_outcome_) {
return *initialization_outcome_;
}
time_points[0] = high_resolution_clock::now();
std::vector<ifcopenshell::geometry::geometry_conversion_task> reps;
if (num_threads_ != 1) {
// @todo this shouldn't be necessary with properly immutable taxonomy items
converter_->mapping()->use_caching() = false;
}
try {
converter_->mapping()->get_representations(reps, filters_);
} catch (const std::exception& e) {
Logger::Error(e);
}
time_points[1] = high_resolution_clock::now();
for (auto& task : reps) {
geometry_conversion_result res;
res.index = task.index;
if (!settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get()) {
res.representation = task.representation;
res.products_2 = task.products;
} else {
res.item = converter_->mapping()->map(task.representation);
if (!res.item) {
continue;
}
std::transform(task.products->begin(), task.products->end(), std::back_inserter(res.products), [this, &res](IfcUtil::IfcBaseClass* prod) {
auto prod_item = converter_->mapping()->map(prod);
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
});
}
tasks_.push_back(res);
}
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() && settings_.get<ifcopenshell::geometry::settings::PermissiveShapeReuse>().get()) {
std::unordered_map<
ifcopenshell::geometry::taxonomy::item::ptr,
std::vector<std::pair<const IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
for (auto& r : tasks_) {
auto i = r.item;
Eigen::Matrix4d m4 = Eigen::Matrix4d::Identity();
while (auto col = std::dynamic_pointer_cast<ifcopenshell::geometry::taxonomy::collection>(i)) {
if (col->children.size() == 1) {
if (col->matrix) {
m4 *= col->matrix->ccomponents();
}
i = col->children[0];
} else {
break;
}
}
for (auto& p : r.products) {
auto pl = ifcopenshell::geometry::taxonomy::matrix4::ptr(p.second->clone_());
pl->components() *= m4;
folded[i].push_back(
{ p.first, pl }
);
}
}
if (folded.size() < tasks_.size()) {
auto old_size = tasks_.size();
tasks_.clear();
size_t i = 0;
for (auto& p : folded) {
tasks_.emplace_back();
tasks_.back().index = i++;
tasks_.back().item = p.first;
tasks_.back().products = p.second;
}
Logger::Notice("Merged " + std::to_string(old_size) + " tasks into " + std::to_string(tasks_.size()) + " tasks due to permissive shape reuse");
}
}
size_t num_products = 0;
for (auto& r : tasks_) {
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2->size() : r.products.size();
}
time_points[2] = high_resolution_clock::now();
/*
// What to do, map representation and product individually?
// There needs to be two options, mapped item respecting (does that still work?), and optimized based on topology sorting.
// Or is the sorting not necessary if we just cache?
std::vector<taxonomy::ptr> items;
std::map<taxonomy::ptr, taxonomy::matrix4> placements;
std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](IfcUtil::IfcBaseClass* p) {
auto item = converter_->mapping()->map(p);
// Product placements do not affect item reuse and should temporarily be swapped to identity
if (item) {
std::swap(placements[item], ((taxonomy::geom_ptr)item)->matrix);
}
return item;
});
items.erase(std::remove(items.begin(), items.end(), nullptr), items.end());
std::sort(items.begin(), items.end(), taxonomy::less);
auto it = items.begin();
while (it < items.end()) {
auto jt = std::upper_bound(it, items.end(), *it, taxonomy::less);
geometry_conversion_result r;
r.item = *it;
std::transform(it, jt, std::back_inserter(r.products), [&r, &placements](taxonomy::ptr product_node) {
return std::make_pair((IfcUtil::IfcBaseEntity*) product_node->instance, placements[product_node]);
});
tasks_.push_back(r);
it = jt;
}
*/
Logger::Notice("Created " + boost::lexical_cast<std::string>(tasks_.size()) + " tasks for " + boost::lexical_cast<std::string>(num_products) + " products");
if (tasks_.size() == 0) {
Logger::Warning("No representations encountered, aborting");
initialization_outcome_.reset(false);
} else {
task_iterator_ = tasks_.begin();
task_result_index_ = 0;
done = 0;
total = (int) tasks_.size();
if (num_threads_ != 1) {
init_future_ = std::async(std::launch::async, [this]() { process_concurrently(); });
// wait for the first element, because after init(), get() can be called.
// so the element conversion must succeed
initialization_outcome_ = wait_for_element();
} else {
initialization_outcome_ = create();
}
}
return *initialization_outcome_;
}
size_t processed_ = 0;
void process_finished_rep(geometry_conversion_result* rep) {
if (rep->elements.empty()) {
return;
}
std::lock_guard<std::mutex> lk(element_ready_mutex_);
all_processed_elements_.insert(all_processed_elements_.end(), rep->elements.begin(), rep->elements.end());
all_processed_native_elements_.insert(all_processed_native_elements_.end(), rep->breps.begin(), rep->breps.end());
if (!task_result_ptr_initialized) {
task_result_iterator_ = all_processed_elements_.begin();
native_task_result_iterator_ = all_processed_native_elements_.begin();
task_result_ptr_initialized = true;
}
progress_ = (int) (++processed_ * 100 / tasks_.size());
}
void process_concurrently() {
size_t conc_threads = num_threads_;
if (conc_threads > tasks_.size()) {
conc_threads = tasks_.size();
}
kernel_pool.reserve(conc_threads);
for (unsigned i = 0; i < conc_threads; ++i) {
kernel_pool.push_back(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_));
}
std::vector<std::future<geometry_conversion_result*>> threadpool;
for (auto& rep : tasks_) {
ifcopenshell::geometry::Converter* K = nullptr;
if (threadpool.size() < kernel_pool.size()) {
K = kernel_pool[threadpool.size()];
}
while (threadpool.size() == conc_threads) {
for (int i = 0; i < (int)threadpool.size(); i++) {
auto& fu = threadpool[i];
std::future_status status;
status = fu.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
process_finished_rep(fu.get());
std::swap(threadpool[i], threadpool.back());
threadpool.pop_back();
std::swap(kernel_pool[i], kernel_pool.back());
K = kernel_pool.back();
break;
} // if
} // for
} // while
std::future<geometry_conversion_result*> fu = std::async(
std::launch::async, [this](
ifcopenshell::geometry::Converter* kernel,
ifcopenshell::geometry::Settings settings,
geometry_conversion_result* rep) {
// Catch exceptions to be safe from freezing the iterator.
try {
this->create_element_(kernel, settings, rep);
} catch (const std::exception& e) {
Logger::Error(
std::string("Exception '") + e.what() +
std::string("' occurred while iterator was creating a shape: "),
rep->item->instance
);
had_error_processing_elements_ = true;
} catch (...) {
Logger::Error(
"Unknown exception occurred while iteartor was creating a shape: ",
rep->item->instance
);
had_error_processing_elements_ = true;
}
return rep;
},
K,
std::ref(settings_),
&rep);
if (terminating_) {
break;
}
threadpool.emplace_back(std::move(fu));
}
for (auto& fu : threadpool) {
process_finished_rep(fu.get());
}
finished_ = true;
Logger::SetProduct(boost::none);
if (!terminating_) {
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
" objects) ");
}
}
/// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files.
void compute_bounds(bool with_geometry)
{
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::numeric_limits<double>::infinity();
bounds_max_.components()(i) = -std::numeric_limits<double>::infinity();
}
if (with_geometry) {
size_t num_created = 0;
do {
IfcGeom::Element* geom_object = get();
const IfcGeom::TriangulationElement* o = static_cast<const IfcGeom::TriangulationElement*>(geom_object);
const IfcGeom::Representation::Triangulation& mesh = o->geometry();
auto mat = o->transformation().data()->ccomponents();
Eigen::Vector4d vec, transformed;
for (typename std::vector<double>::const_iterator it = mesh.verts().begin(); it != mesh.verts().end();) {
const double& x = *(it++);
const double& y = *(it++);
const double& z = *(it++);
vec << x, y, z, 1.;
transformed = mat * vec;
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::min(bounds_min_.components()(i), transformed(i));
bounds_max_.components()(i) = std::max(bounds_max_.components()(i), transformed(i));
}
}
} while (++num_created, next());
} else {
std::vector<ifcopenshell::geometry::geometry_conversion_task> reps;
converter_->mapping()->get_representations(reps, filters_);
std::vector<IfcUtil::IfcBaseClass*> products;
for (auto& r : reps) {
std::copy(r.products->begin(), r.products->end(), std::back_inserter(products));
}
for (auto& product : products) {
auto prod_item = converter_->mapping()->map(product);
auto vec = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix->translation_part();
for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::min(bounds_min_.components()(i), vec(i));
bounds_max_.components()(i) = std::max(bounds_max_.components()(i), vec(i));
}
}
}
}
int progress() const {
return progress_;
}
std::string getLog() const { return Logger::GetLog(); }
IfcParse::IfcFile* file() const { return ifc_file; }
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; }
private:
std::mutex caching_mutex_;
template <typename Fn> template <typename Fn>
Element* decorate_with_cache_(GeometrySerializer::read_type rt, const std::string& product_guid, const std::string& representation_id, Fn f) { Element* decorate_with_cache_(GeometrySerializer::read_type rt, const std::string& product_guid, const std::string& representation_id, Fn f) {
@@ -529,7 +184,7 @@ namespace IfcGeom {
std::lock_guard<std::mutex> lk(caching_mutex_); std::lock_guard<std::mutex> lk(caching_mutex_);
if (rt == GeometrySerializer::READ_TRIANGULATION) { if (rt == GeometrySerializer::READ_TRIANGULATION) {
cache_->write((IfcGeom::TriangulationElement*) element); cache_->write((IfcGeom::TriangulationElement*)element);
} else { } else {
cache_->write((IfcGeom::BRepElement*)element); cache_->write((IfcGeom::BRepElement*)element);
} }
@@ -539,347 +194,24 @@ namespace IfcGeom {
return element; return element;
} }
const IfcUtil::IfcBaseClass* create_shape_model_for_next_entity() { const IfcUtil::IfcBaseClass* create_shape_model_for_next_entity();
geometry_conversion_result* task = nullptr;
for (; task_iterator_ < tasks_.end();) {
task = &*task_iterator_++;
create_element_(converter_, settings_, task);
if (task->elements.empty()) {
task = nullptr;
} else {
break;
}
}
if (task) {
process_finished_rep(task);
return task->item->instance->as<IfcUtil::IfcBaseClass>();
} else {
return nullptr;
}
}
void create_element_( void create_element_(
ifcopenshell::geometry::Converter* kernel, ifcopenshell::geometry::Converter* kernel,
ifcopenshell::geometry::Settings settings, ifcopenshell::geometry::Settings settings,
geometry_conversion_result* rep) geometry_conversion_result* rep);
{
if (!settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get()) {
rep->item = kernel->mapping()->map(rep->representation);
if (!rep->item) {
return;
}
std::transform(rep->products_2->begin(), rep->products_2->end(), std::back_inserter(rep->products), [this, &rep, kernel](IfcUtil::IfcBaseClass* prod) {
auto prod_item = kernel->mapping()->map(prod);
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
});
} else {
}
auto product_node = rep->products.front();
const IfcUtil::IfcBaseEntity* product = product_node.first;
const auto& place = product_node.second;
Logger::SetProduct(product);
IfcGeom::BRepElement* brep = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product, place, rep]() {
return kernel->create_brep_for_representation_and_product(rep->item, product, place);
}));
if (!brep) {
return;
}
auto elem = process_based_on_settings(settings, brep);
if (!elem) {
return;
}
rep->breps = { brep };
rep->elements = { elem };
for (auto it = rep->products.begin() + 1; it != rep->products.end(); ++it) {
const auto& p = *it;
const IfcUtil::IfcBaseEntity* product2 = p.first;
const auto& place2 = p.second;
IfcGeom::BRepElement* brep2 = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product2->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product2, place2, brep]() {
return kernel->create_brep_for_processed_representation(product2, place2, brep);
}));
if (brep2) {
auto elem2 = process_based_on_settings(settings, brep2, dynamic_cast<IfcGeom::TriangulationElement*>(elem));
if (elem2) {
rep->breps.push_back(brep2);
rep->elements.push_back(elem2);
}
}
}
}
IfcGeom::Element* process_based_on_settings( IfcGeom::Element* process_based_on_settings(
ifcopenshell::geometry::Settings settings, ifcopenshell::geometry::Settings settings,
IfcGeom::BRepElement* elem, IfcGeom::BRepElement* elem,
IfcGeom::TriangulationElement* previous = nullptr) IfcGeom::TriangulationElement* previous = nullptr);
{
if (settings.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::SERIALIZED) {
try {
return new IfcGeom::SerializedElement(*elem);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
return nullptr;
}
} else if (settings.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::TRIANGULATED) {
// the part before the hyphen is the representation id
auto gid2 = elem->geometry().id();
auto hyphen = gid2.find("-");
if (hyphen != std::string::npos) {
gid2 = gid2.substr(0, hyphen);
}
return decorate_with_cache_(GeometrySerializer::READ_TRIANGULATION, elem->guid(), gid2, [elem, previous]() { bool wait_for_element();
try {
if (!previous) {
return new TriangulationElement(*elem);
} else {
return new TriangulationElement(*elem, previous->geometry_pointer());
}
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
}
return (TriangulationElement*)nullptr;
});
} else {
return elem;
}
}
bool wait_for_element() { void log_timepoints() const;
while (true) {
size_t s;
{
std::lock_guard<std::mutex> lk(element_ready_mutex_);
s = all_processed_elements_.size();
}
if (s > async_elements_returned_) {
++async_elements_returned_;
return true;
} else if (finished_) {
return false;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}
void log_timepoints() const {
using std::chrono::high_resolution_clock;
using std::chrono::duration;
using namespace std::string_literals;
std::array<std::string, 3> labels = {
"Initializing mapping"s,
"Performing mapping"s,
"Geometry interpretation"s
};
for (auto it = time_points.begin() + 1; it != time_points.end(); ++it) {
auto jt = it - 1;
duration<double, std::milli> ms_double = (*it) - (*jt);
Logger::Notice(labels[std::distance(time_points.begin(), jt)] + " took " + std::to_string(ms_double.count()) + "ms");
}
}
/// @todo public/private sections all over the place: move all public to the beginning of the class
public: public:
/// Returns what would be the product for the next shape representation
/// @todo Double-check and test the impl.
//IfcSchema::IfcProduct* peek_next() const
//{
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
// return *(ifcproduct_iterator + 1);
// } else {
// return 0;
// }
//}
/// @todo Would this be as simple as the following code?
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
const IfcUtil::IfcBaseClass* next() {
using std::chrono::high_resolution_clock;
if (*native_task_result_iterator_ != *task_result_iterator_) {
delete* native_task_result_iterator_;
}
delete *task_result_iterator_;
if (num_threads_ != 1) {
if (!wait_for_element()) {
Logger::SetProduct(boost::none);
time_points[3] = high_resolution_clock::now();
log_timepoints();
return nullptr;
}
task_result_iterator_++;
native_task_result_iterator_++;
return (*task_result_iterator_)->product();
} else {
// Increment the iterator over the list of products using the current
// shape representation
if (task_result_iterator_ == --all_processed_elements_.end()) {
if (!create()) {
Logger::SetProduct(boost::none);
time_points[3] = high_resolution_clock::now();
log_timepoints();
return nullptr;
}
}
task_result_iterator_++;
native_task_result_iterator_++;
return (*task_result_iterator_)->product();
}
}
/// Gets the representation of the current geometrical entity.
Element* get()
{
if (!initialization_outcome_) {
throw std::runtime_error("Iterator not initialized");
}
auto ret = *task_result_iterator_;
// If we want to organize the element considering their hierarchy
if (settings_.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get())
{
// We are going to build a vector with the element parents.
// First, create the parent vector
std::vector<const IfcGeom::Element*> parents;
// if the element has a parent
if (ret->parent_id() != -1)
{
const IfcGeom::Element* parent_object = NULL;
bool hasParent = true;
// get the parent
try {
parent_object = get_object(ret->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
// We need to find all the parents
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1)
{
// Find the next parent
try {
parent_object = get_object(parent_object->parent_id());
} catch (const std::exception& e) {
Logger::Error(e);
hasParent = false;
}
// Add the previously found parent to the vector
if (hasParent) parents.insert(parents.begin(), parent_object);
hasParent = hasParent && parent_object->parent_id() != -1;
}
// when done push the parent list in the Element object
ret->SetParents(parents);
}
}
return ret;
}
/// Gets the native (Open Cascade or CGAL) representation of the current geometrical entity.
BRepElement* get_native()
{
return *native_task_result_iterator_;
}
const Element* get_object(int id) {
ifcopenshell::geometry::taxonomy::matrix4::ptr m4;
int parent_id = -1;
std::string instance_type, product_name, product_guid;
IfcUtil::IfcBaseEntity* ifc_product = 0;
try {
ifc_product = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
instance_type = ifc_product->declaration().name();
if (ifc_product->declaration().is("IfcRoot")) {
product_guid = (std::string) ifc_product->get("GlobalId");
product_name = ifc_product->get_value<std::string>("Name", "");
}
auto parent_object = converter_->mapping()->get_decomposing_entity(ifc_product);
if (parent_object) {
parent_id = parent_object->id();
}
// fails in case of IfcProject
auto mapped = converter_->mapping()->map(ifc_product);
auto casted = mapped ? ifcopenshell::geometry::taxonomy::dcast<ifcopenshell::geometry::taxonomy::geom_item>(mapped) : nullptr;
if (casted) {
m4 = casted->matrix;
}
} catch (const std::exception& e) {
Logger::Error(e);
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error returning product");
}
}
#endif
catch (...) {
Logger::Error("Unknown error returning product");
}
Element* ifc_object = new Element(settings_, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product);
return ifc_object;
}
const IfcUtil::IfcBaseClass* create() {
const IfcUtil::IfcBaseClass* product = nullptr;
try {
product = create_shape_model_for_next_entity();
} catch (const std::exception& e) {
Logger::Error(e);
had_error_processing_elements_ = true;
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error creating geometry");
}
had_error_processing_elements_ = true;
}
#endif
catch (...) {
Logger::Error("Unknown error creating geometry");
had_error_processing_elements_ = true;
}
return product;
}
Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads) Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
: settings_(settings) : settings_(settings)
, ifc_file(file) , ifc_file(file)
@@ -927,31 +259,70 @@ namespace IfcGeom {
{ {
} }
~Iterator() { ~Iterator();
if (num_threads_ != 1) {
terminating_ = true;
if (init_future_.valid()) { void set_cache(GeometrySerializer* cache) { cache_ = cache; }
init_future_.wait();
}
}
for (auto& k : kernel_pool) { const std::string& unit_name() const { return converter_->mapping()->get_length_unit_name(); }
delete k; double unit_magnitude() const { return converter_->mapping()->get_length_unit(); }
} // Check if error occurred during iterator initialization or iteration over elements.
bool had_error_processing_elements() const { return had_error_processing_elements_; }
if (task_result_ptr_initialized) { boost::optional<bool> initialization_outcome_;
while (task_result_iterator_ != --all_processed_elements_.end()) {
if (*native_task_result_iterator_ != *task_result_iterator_) {
delete* native_task_result_iterator_;
}
delete *task_result_iterator_++;
native_task_result_iterator_++;
}
}
delete converter_; /**
* @return Returns true if the iterator is initialized with any elements, false otherwise.
*
* @note
* - A true return value does not guarantee successful initialization of all elements.
* Some elements may have failed to initialize. Check had_error_processing_elements()
* to see whether there were errors during the initialization.
*
* - For non-concurrent iterators, a false return may occur if initialization of the first
* element fails, even if subsequent elements could be initialized successfully.
*/
bool initialize();
size_t processed_ = 0;
void process_finished_rep(geometry_conversion_result* rep);
void process_concurrently();
/// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files.
void compute_bounds(bool with_geometry);
int progress() const {
return progress_;
} }
std::string getLog() const { return Logger::GetLog(); }
IfcParse::IfcFile* file() const { return ifc_file; }
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; }
/// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry.
const IfcUtil::IfcBaseClass* next();
/// Gets the representation of the current geometrical entity.
Element* get();
/// Gets the native (Open Cascade or CGAL) representation of the current geometrical entity.
BRepElement* get_native()
{
return *native_task_result_iterator_;
}
const Element* get_object(int id);
const IfcUtil::IfcBaseClass* create();
}; };
} }