Fix failing drawing tool tests. Also consolidate relative paths using tool.Ifc.get_uri.

The same issue of handling relative paths, doing as_posix, checking
drives, etc was solved again and again in slightly different ways. This
centralises it.
This commit is contained in:
Dion Moult
2025-02-05 17:17:09 +11:00
parent 13746eb55e
commit 590c2e120c
7 changed files with 40 additions and 79 deletions
@@ -694,8 +694,8 @@ class CreateDrawing(bpy.types.Operator):
invalidated_elements = exporter.sync_all_objects()
invalidated_elements += exporter.sync_edited_objects()
invalidated_guids = [e.GlobalId for e in invalidated_elements if hasattr(e, "GlobalId")]
cache = IfcStore.get_cache()
[cache.remove(guid) for guid in invalidated_guids]
if cache := IfcStore.get_cache():
[cache.remove(guid) for guid in invalidated_guids]
# If we have already calculated it in the SVG in the past, don't recalculate
edited_guids = set()
@@ -1752,7 +1752,7 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
sheet_builder = sheeter.SheetBuilder()
references = sheet_builder.build(sheet)
raster_references = [tool.Ifc.get_relative_uri(r) for r in references["RASTER"]]
raster_references = [tool.Ifc.get_uri(r, use_relative_path=True) for r in references["RASTER"]]
# These variables will be made available to the evaluated commands
svg = references["SHEET"]
@@ -1783,7 +1783,7 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
"document.edit_reference",
reference=reference,
attributes=tool.Drawing.generate_reference_attributes(
reference, Location=tool.Ifc.get_relative_uri(svg), Description="SHEET"
reference, Location=tool.Ifc.get_uri(svg, use_relative_path=True), Description="SHEET"
),
)
@@ -1793,7 +1793,9 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
"document.edit_reference",
reference=reference,
attributes=tool.Drawing.generate_reference_attributes(
reference, Location=tool.Ifc.get_relative_uri(raster_reference), Description="RASTER"
reference,
Location=tool.Ifc.get_uri(raster_reference, use_relative_path=True),
Description="RASTER",
),
)
@@ -2455,21 +2457,8 @@ class AddSchedule(bpy.types.Operator, tool.Ifc.Operator):
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
def _execute(self, context):
filepath = self.filepath
if self.use_relative_path:
ifc_path = tool.Ifc.get_path()
if os.path.isfile(ifc_path):
ifc_path = os.path.dirname(ifc_path)
# taking into account different drives on windows
if Path(filepath).drive == Path(ifc_path).drive:
filepath = os.path.relpath(filepath, ifc_path)
core.add_document(
tool.Ifc,
tool.Drawing,
"SCHEDULE",
uri=filepath,
)
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
core.add_document(tool.Ifc, tool.Drawing, "SCHEDULE", uri=filepath)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
@@ -2653,21 +2642,8 @@ class AddReference(bpy.types.Operator, tool.Ifc.Operator):
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
def _execute(self, context):
filepath = self.filepath
if self.use_relative_path:
ifc_path = tool.Ifc.get_path()
if os.path.isfile(ifc_path):
ifc_path = os.path.dirname(ifc_path)
# taking into account different drives on windows
if Path(filepath).drive == Path(ifc_path).drive:
filepath = os.path.relpath(filepath, ifc_path)
core.add_document(
tool.Ifc,
tool.Drawing,
"REFERENCE",
uri=filepath,
)
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
core.add_document(tool.Ifc, tool.Drawing, "REFERENCE", uri=filepath)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
@@ -3301,11 +3277,8 @@ class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
return {"RUNNING_MODAL"}
def _execute(self, context):
abs_path = Path(self.filepath)
if self.use_relative_path:
image_filepath = abs_path.relative_to(Path(tool.Ifc.get_path()).parent)
else:
image_filepath = abs_path
abs_path = Path(self.filepath).absolute().resolve()
image_filepath = Path(tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path))
ifc_file = tool.Ifc.get()
if self.override_existing_image:
@@ -1135,17 +1135,12 @@ class LinkIfc(bpy.types.Operator):
self.report({"INFO"}, "Can't link the current .blend file")
continue
new = context.scene.BIMProjectProperties.links.add()
if self.use_relative_path and (ifc_filepath := tool.Ifc.get_path()):
try:
filepath = filepath.relative_to(Path(ifc_filepath).parent)
except:
pass # Perhaps on another drive or something
# Store link paths as posix for cross-platform.
new.name = filepath.as_posix()
status = bpy.ops.bim.load_link(filepath=filepath.as_posix(), use_cache=self.use_cache)
filepath = tool.Ifc.get_uri(filepath, use_relative_path=self.use_relative_path)
new.name = filepath
status = bpy.ops.bim.load_link(filepath=filepath, use_cache=self.use_cache)
if status == {"CANCELLED"}:
error_msg = (
f'Error processing IFC file "{filepath.as_posix()}" '
f'Error processing IFC file "{filepath}" '
"was critical and blend file either wasn't saved or wasn't updated. "
"See logs above in system console for details."
)
+3 -18
View File
@@ -387,12 +387,7 @@ class BrowseExternalStyle(bpy.types.Operator):
bpy.data.materials.remove(db["data_block"])
if self.use_relative_path:
filepath = os.path.relpath(self.filepath, Path(tool.Ifc.get_path()).parent)
else:
filepath = self.filepath
filepath = Path(filepath).as_posix()
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
attributes = context.scene.BIMStylesProperties.external_style_attributes
attributes["Location"].string_value = filepath
attributes["Identification"].string_value = f"{self.data_block_type}/{self.data_block}"
@@ -565,19 +560,9 @@ class ChooseTextureMapPath(bpy.types.Operator):
self.report({"ERROR"}, "Provide a texture map index")
return {"CANCELLED"}
abs_path = Path(self.filepath)
if self.use_relative_path:
parent = Path(tool.Ifc.get_path()).parent
if abs_path.is_relative_to(parent):
image_filepath = abs_path.relative_to(parent)
else:
self.report({"INFO"}, "Path is not relative to the .ifc file, it will be saved as absolute.")
image_filepath = abs_path
else:
image_filepath = abs_path
filepath = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
texture = context.scene.BIMStylesProperties.textures[self.texture_map_index]
texture.path = image_filepath.as_posix()
texture.path = filepath
return {"FINISHED"}
+1 -4
View File
@@ -166,10 +166,7 @@ class SelectURIAttribute(bpy.types.Operator):
# Do you know a better way?
pass
if attribute:
filepath = self.filepath
if self.use_relative_path:
filepath = os.path.relpath(filepath, os.path.dirname(tool.Ifc.get_path()))
attribute.string_value = filepath
attribute.string_value = tool.Ifc.get_uri(self.filepath, use_relative_path=self.use_relative_path)
return {"FINISHED"}
def invoke(self, context, event):
+10 -5
View File
@@ -26,6 +26,7 @@ import ifcopenshell.util.schema
import bonsai.core.tool
import bonsai.bim.handler
import bonsai.tool as tool
from pathlib import Path
from bonsai.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
from typing import Optional, Union, Any, final, Literal
@@ -247,13 +248,17 @@ class Ifc(bonsai.core.tool.Ifc):
return (uri if not uri else os.path.join(ifc_path, uri)).replace("\\", "/")
@classmethod
def get_relative_uri(cls, uri: str) -> str:
if not os.path.isabs(uri):
return uri
ifc_path = cls.get_path()
def get_uri(cls, uri: str | Path, use_relative_path: bool = False) -> str:
if not use_relative_path:
return Path(uri).absolute().resolve().as_posix()
uri = Path(uri)
if not os.path.isabs(uri) or not (ifc_path := cls.get_path()):
return uri.as_posix().replace("\\", "/")
if Path(uri).drive != Path(ifc_path).drive:
return uri.as_posix().replace("\\", "/")
if os.path.isfile(ifc_path):
ifc_path = os.path.dirname(ifc_path)
return os.path.relpath(uri, ifc_path).replace("\\", "/")
return Path(os.path.relpath(uri, ifc_path)).as_posix().replace("\\", "/")
@classmethod
def unlink(
+1
View File
@@ -298,6 +298,7 @@ class Loader(bonsai.core.tool.Loader):
if is_relative:
ifc_path = Path(tool.Ifc.get_path())
image_url = ifc_path.parent / image_url
image_url = image_url.absolute().resolve()
if not image_url.exists():
print(f"WARNING. Couldn't find texture by path {image_url}, it will be skipped.")
+8 -3
View File
@@ -724,8 +724,8 @@ class TestDrawingMaintainingSheetPosition(NewFile):
# check drawing position on the sheet
drawing_data = self.get_sheet_drawing_data(sheet_path)
assert drawing_data["foreground"] == (155.0, 155.0, 250.0, 250.0)
assert drawing_data["view-title"] == (155.0, 410.0, 50.22, 10.0)
assert drawing_data["foreground"] == (30.0, 30.0, 500.0, 500.0)
assert drawing_data["view-title"] == (30.0, 535.0, 50.22, 10.0)
class TestUpdateTextValue(NewFile):
@@ -835,6 +835,9 @@ class TestDrawingStyles(NewFile):
bpy.ops.bim.add_drawing()
ifc = tool.Ifc.get()
drawing = ifc.by_type("IfcAnnotation")[0]
bpy.ops.bim.expand_target_view(target_view="PLAN_VIEW")
props = bpy.context.scene.DocProperties
props.active_drawing_index = 2
bpy.ops.bim.activate_drawing(drawing=drawing.id())
self.drawing_styles = bpy.context.scene.DocProperties.drawing_styles
@@ -857,7 +860,8 @@ class TestAddReferenceImage(NewFile):
def test_run(self):
bpy.context.scene.BIMProjectProperties.template_file = "0"
bpy.ops.bim.create_project()
ifc_file = tool.Ifc.get()
ifc_path = Path("test/files/temp/test.ifc").absolute()
bpy.ops.bim.save_project(filepath=str(ifc_path), should_save_as=True)
filepath = Path("test/files/image.jpg").absolute()
bpy.ops.bim.add_reference_image(filepath=str(filepath))
@@ -870,6 +874,7 @@ class TestAddReferenceImage(NewFile):
assert material.name == "image"
assert material.BIMStyleProperties.ifc_definition_id != 0
ifc_file = tool.Ifc.get()
style = ifc_file.by_id(material.BIMStyleProperties.ifc_definition_id)
styled_items = set(tool.Style.get_styled_items(style))
representation_items = set(tool.Geometry.get_active_representation(obj).Items)