mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
project.operator - use pathlib
This commit is contained in:
@@ -54,7 +54,7 @@ from bonsai.bim.module.project.data import LinksData
|
|||||||
from bonsai.bim.module.project.decorator import ProjectDecorator, ClippingPlaneDecorator, MeasureDecorator
|
from bonsai.bim.module.project.decorator import ProjectDecorator, ClippingPlaneDecorator, MeasureDecorator
|
||||||
from bonsai.bim.module.model.decorator import PolylineDecorator
|
from bonsai.bim.module.model.decorator import PolylineDecorator
|
||||||
from bonsai.bim.module.model.polyline import PolylineOperator
|
from bonsai.bim.module.model.polyline import PolylineOperator
|
||||||
from typing import Union
|
from typing import Union, TYPE_CHECKING
|
||||||
|
|
||||||
|
|
||||||
class NewProject(bpy.types.Operator):
|
class NewProject(bpy.types.Operator):
|
||||||
@@ -933,6 +933,11 @@ class LinkIfc(bpy.types.Operator):
|
|||||||
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
|
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
|
||||||
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
|
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
filepath: str
|
||||||
|
files: list[bpy.types.OperatorFileListElement]
|
||||||
|
directory: str
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
pprops = context.scene.BIMProjectProperties
|
pprops = context.scene.BIMProjectProperties
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
@@ -949,20 +954,20 @@ class LinkIfc(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
files = [f.name.replace("\\", "/") for f in self.files] if self.files else [self.filepath.replace("\\", "/")]
|
files = [f.name for f in self.files] if self.files else [self.filepath]
|
||||||
for filename in files:
|
for filename in files:
|
||||||
filepath = os.path.join(self.directory, filename).replace("\\", "/")
|
filepath = Path(self.directory) / filename
|
||||||
if bpy.data.filepath and Path(filepath).samefile(bpy.data.filepath):
|
if bpy.data.filepath and filepath.samefile(bpy.data.filepath):
|
||||||
self.report({"INFO"}, "Can't link the current .blend file")
|
self.report({"INFO"}, "Can't link the current .blend file")
|
||||||
continue
|
continue
|
||||||
new = context.scene.BIMProjectProperties.links.add()
|
new = context.scene.BIMProjectProperties.links.add()
|
||||||
if self.use_relative_path:
|
if self.use_relative_path:
|
||||||
try:
|
try:
|
||||||
filepath = os.path.relpath(filepath, bpy.path.abspath("//")).replace("\\", "/")
|
filepath = filepath.relative_to(bpy.path.abspath("//"))
|
||||||
except:
|
except:
|
||||||
pass # Perhaps on another drive or something
|
pass # Perhaps on another drive or something
|
||||||
new.name = filepath
|
new.name = filepath.as_posix()
|
||||||
status = bpy.ops.bim.load_link(filepath=filepath, use_cache=self.use_cache)
|
status = bpy.ops.bim.load_link(filepath=filepath.as_posix(), use_cache=self.use_cache)
|
||||||
if status == {"CANCELLED"}:
|
if status == {"CANCELLED"}:
|
||||||
error_msg = (
|
error_msg = (
|
||||||
f'Error processing IFC file "{self.filepath}" '
|
f'Error processing IFC file "{self.filepath}" '
|
||||||
@@ -988,9 +993,9 @@ class UnlinkIfc(bpy.types.Operator):
|
|||||||
filepath: bpy.props.StringProperty()
|
filepath: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.filepath = self.filepath.replace("\\", "/")
|
filepath = Path(self.filepath).as_posix()
|
||||||
bpy.ops.bim.unload_link(filepath=self.filepath)
|
bpy.ops.bim.unload_link(filepath=filepath)
|
||||||
index = context.scene.BIMProjectProperties.links.find(self.filepath)
|
index = context.scene.BIMProjectProperties.links.find(filepath)
|
||||||
if index != -1:
|
if index != -1:
|
||||||
context.scene.BIMProjectProperties.links.remove(index)
|
context.scene.BIMProjectProperties.links.remove(index)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -1004,11 +1009,7 @@ class UnloadLink(bpy.types.Operator):
|
|||||||
filepath: bpy.props.StringProperty()
|
filepath: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.filepath = self.filepath.replace("\\", "/")
|
filepath = tool.Blender.ensure_blender_path_is_abs(Path(self.filepath))
|
||||||
filepath = self.filepath
|
|
||||||
if not os.path.isabs(filepath):
|
|
||||||
filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), filepath))
|
|
||||||
filepath = Path(filepath)
|
|
||||||
if filepath.suffix.lower() == ".ifc":
|
if filepath.suffix.lower() == ".ifc":
|
||||||
filepath = filepath.with_suffix(".ifc.cache.blend")
|
filepath = filepath.with_suffix(".ifc.cache.blend")
|
||||||
|
|
||||||
@@ -1046,25 +1047,25 @@ class LoadLink(bpy.types.Operator):
|
|||||||
filepath: bpy.props.StringProperty()
|
filepath: bpy.props.StringProperty()
|
||||||
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
|
use_cache: bpy.props.BoolProperty(name="Use Cache", default=True)
|
||||||
|
|
||||||
|
filepath_: Path
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.filepath = self.filepath.replace("\\", "/")
|
filepath = tool.Blender.ensure_blender_path_is_abs(Path(self.filepath))
|
||||||
filepath = self.filepath
|
self.filepath_ = filepath
|
||||||
if not os.path.isabs(filepath):
|
if filepath.suffix.lower().endswith(".blend"):
|
||||||
filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), filepath)).replace("\\", "/")
|
|
||||||
if self.filepath.lower().endswith(".blend"):
|
|
||||||
self.link_blend(filepath)
|
self.link_blend(filepath)
|
||||||
elif self.filepath.lower().endswith(".ifc"):
|
elif filepath.suffix.lower().endswith(".ifc"):
|
||||||
status = self.link_ifc()
|
status = self.link_ifc()
|
||||||
if status:
|
if status:
|
||||||
return status
|
return status
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def link_blend(self, filepath: str) -> None:
|
def link_blend(self, filepath: Path) -> None:
|
||||||
with bpy.data.libraries.load(filepath, link=True) as (data_from, data_to):
|
with bpy.data.libraries.load(str(filepath), link=True) as (data_from, data_to):
|
||||||
data_to.scenes = data_from.scenes
|
data_to.scenes = data_from.scenes
|
||||||
link = bpy.context.scene.BIMProjectProperties.links.get(self.filepath)
|
link = bpy.context.scene.BIMProjectProperties.links.get(self.filepath_.as_posix())
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
if not scene.library or scene.library.filepath.replace("\\", "/") != filepath:
|
if not scene.library or Path(scene.library.filepath) != filepath:
|
||||||
continue
|
continue
|
||||||
for child in scene.collection.children:
|
for child in scene.collection.children:
|
||||||
if "IfcProject" not in child.name:
|
if "IfcProject" not in child.name:
|
||||||
@@ -1080,13 +1081,13 @@ class LoadLink(bpy.types.Operator):
|
|||||||
tool.Blender.select_and_activate_single_object(bpy.context, empty)
|
tool.Blender.select_and_activate_single_object(bpy.context, empty)
|
||||||
|
|
||||||
def link_ifc(self) -> Union[set[str], None]:
|
def link_ifc(self) -> Union[set[str], None]:
|
||||||
blend_filepath = self.filepath + ".cache.blend"
|
blend_filepath = self.filepath_.with_suffix(".ifc.cache.blend")
|
||||||
h5_filepath = self.filepath + ".cache.h5"
|
h5_filepath = self.filepath_.with_suffix(".ifc.cache.h5")
|
||||||
|
|
||||||
if not self.use_cache and os.path.exists(blend_filepath):
|
if not self.use_cache and blend_filepath.exists():
|
||||||
os.remove(blend_filepath)
|
os.remove(blend_filepath)
|
||||||
|
|
||||||
if not os.path.exists(blend_filepath):
|
if not blend_filepath.exists():
|
||||||
pprops = bpy.context.scene.BIMProjectProperties
|
pprops = bpy.context.scene.BIMProjectProperties
|
||||||
gprops = bpy.context.scene.BIMGeoreferenceProperties
|
gprops = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
|
|
||||||
@@ -1111,7 +1112,7 @@ def run():
|
|||||||
pprops.false_origin = "{pprops.false_origin}"
|
pprops.false_origin = "{pprops.false_origin}"
|
||||||
pprops.project_north = "{pprops.project_north}"
|
pprops.project_north = "{pprops.project_north}"
|
||||||
bpy.ops.bim.load_linked_project(filepath="{self.filepath}")
|
bpy.ops.bim.load_linked_project(filepath="{self.filepath}")
|
||||||
bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath}")
|
bpy.ops.wm.save_as_mainfile(filepath="{blend_filepath.as_posix()}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
run()
|
run()
|
||||||
@@ -1127,19 +1128,19 @@ except Exception as e:
|
|||||||
run = subprocess.run([bpy.app.binary_path, "-b", "--python", temp_file.name, "--python-exit-code", "1"])
|
run = subprocess.run([bpy.app.binary_path, "-b", "--python", temp_file.name, "--python-exit-code", "1"])
|
||||||
if run.returncode == 1:
|
if run.returncode == 1:
|
||||||
print("An error occurred while processing your IFC.")
|
print("An error occurred while processing your IFC.")
|
||||||
if not os.path.exists(blend_filepath) or os.stat(blend_filepath).st_mtime < t:
|
if not blend_filepath.exists() or blend_filepath.stat().st_mtime < t:
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
self.set_model_origin_from_link()
|
self.set_model_origin_from_link()
|
||||||
|
|
||||||
self.link_blend(blend_filepath)
|
self.link_blend(blend_filepath)
|
||||||
|
|
||||||
def set_model_origin_from_link(self):
|
def set_model_origin_from_link(self) -> None:
|
||||||
if tool.Ifc.get():
|
if tool.Ifc.get():
|
||||||
return # The current model's coordinates always take priority.
|
return # The current model's coordinates always take priority.
|
||||||
|
|
||||||
json_filepath = self.filepath + ".cache.json"
|
json_filepath = self.filepath_.with_suffix(".ifc.cache.json")
|
||||||
if not os.path.exists(json_filepath):
|
if not json_filepath.exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(json_filepath, "r") as f:
|
with open(json_filepath, "r") as f:
|
||||||
@@ -1159,15 +1160,16 @@ class ReloadLink(bpy.types.Operator):
|
|||||||
filepath: bpy.props.StringProperty()
|
filepath: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
def get_linked_ifcs():
|
filepath = Path(self.filepath)
|
||||||
selected_filename = os.path.basename(self.filepath.replace("\\", "/"))
|
|
||||||
return [
|
def get_linked_ifcs() -> set[bpy.types.Library]:
|
||||||
|
return {
|
||||||
c.library
|
c.library
|
||||||
for c in bpy.data.collections
|
for c in bpy.data.collections
|
||||||
if "IfcProject" in c.name and c.library and os.path.basename(c.library.filepath) == selected_filename
|
if "IfcProject" in c.name and c.library and Path(c.library.filepath) == filepath
|
||||||
]
|
}
|
||||||
|
|
||||||
for library in get_linked_ifcs() or []:
|
for library in get_linked_ifcs():
|
||||||
library.reload()
|
library.reload()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -1182,9 +1184,7 @@ class ToggleLinkSelectability(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMProjectProperties
|
props = context.scene.BIMProjectProperties
|
||||||
link = props.links.get(self.link)
|
link = props.links.get(self.link)
|
||||||
if not os.path.isabs(self.link):
|
self.library_filepath = tool.Blender.ensure_blender_path_is_abs(Path(self.link).with_suffix(".ifc.cache.blend"))
|
||||||
self.link = os.path.abspath(os.path.join(bpy.path.abspath("//"), self.link))
|
|
||||||
self.library_filepath = Path(self.link).with_suffix(".ifc.cache.blend")
|
|
||||||
for collection in self.get_linked_collections():
|
for collection in self.get_linked_collections():
|
||||||
collection.hide_select = not collection.hide_select
|
collection.hide_select = not collection.hide_select
|
||||||
link.is_selectable = not collection.hide_select
|
link.is_selectable = not collection.hide_select
|
||||||
@@ -1209,9 +1209,7 @@ class ToggleLinkVisibility(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMProjectProperties
|
props = context.scene.BIMProjectProperties
|
||||||
link = props.links.get(self.link)
|
link = props.links.get(self.link)
|
||||||
if not os.path.isabs(self.link):
|
self.library_filepath = tool.Blender.ensure_blender_path_is_abs(Path(self.link).with_suffix(".ifc.cache.blend"))
|
||||||
self.link = os.path.abspath(os.path.join(bpy.path.abspath("//"), self.link))
|
|
||||||
self.library_filepath = Path(self.link).with_suffix(".ifc.cache.blend")
|
|
||||||
if self.mode == "WIREFRAME":
|
if self.mode == "WIREFRAME":
|
||||||
self.toggle_wireframe(link)
|
self.toggle_wireframe(link)
|
||||||
elif self.mode == "VISIBLE":
|
elif self.mode == "VISIBLE":
|
||||||
@@ -1298,10 +1296,8 @@ class ExportIFCBase:
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
self.save_as_invoked = False
|
self.save_as_invoked = False
|
||||||
if context.scene.BIMProperties.ifc_file and not self.should_save_as:
|
if (filepath := context.scene.BIMProperties.ifc_file) and not self.should_save_as:
|
||||||
self.filepath = context.scene.BIMProperties.ifc_file
|
self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(filepath)))
|
||||||
if not os.path.isabs(self.filepath):
|
|
||||||
self.filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), self.filepath))
|
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
if not self.filepath:
|
if not self.filepath:
|
||||||
if bpy.data.is_saved:
|
if bpy.data.is_saved:
|
||||||
@@ -1408,7 +1404,7 @@ class LoadLinkedProject(bpy.types.Operator):
|
|||||||
pprops = bpy.context.scene.BIMProjectProperties
|
pprops = bpy.context.scene.BIMProjectProperties
|
||||||
gprops = bpy.context.scene.BIMGeoreferenceProperties
|
gprops = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
|
|
||||||
self.filepath = self.filepath.replace("\\", "/")
|
self.filepath = Path(self.filepath).as_posix()
|
||||||
print("Processing", self.filepath)
|
print("Processing", self.filepath)
|
||||||
|
|
||||||
self.collection = bpy.data.collections.new("IfcProject/" + os.path.basename(self.filepath))
|
self.collection = bpy.data.collections.new("IfcProject/" + os.path.basename(self.filepath))
|
||||||
|
|||||||
@@ -106,7 +106,10 @@ class FilterCategory(PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
class Link(PropertyGroup):
|
class Link(PropertyGroup):
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(
|
||||||
|
name="Name",
|
||||||
|
description="Filepath to linked .ifc file, stored in posix format (could be relative to .blend file, not to .ifc)",
|
||||||
|
)
|
||||||
is_loaded: BoolProperty(name="Is Loaded", default=False)
|
is_loaded: BoolProperty(name="Is Loaded", default=False)
|
||||||
is_selectable: BoolProperty(name="Is Selectable", default=True)
|
is_selectable: BoolProperty(name="Is Selectable", default=True)
|
||||||
is_wireframe: BoolProperty(name="Is Wireframe", default=False)
|
is_wireframe: BoolProperty(name="Is Wireframe", default=False)
|
||||||
|
|||||||
@@ -414,6 +414,12 @@ class Blender(bonsai.core.tool.Blender):
|
|||||||
|
|
||||||
return path.as_posix()
|
return path.as_posix()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ensure_blender_path_is_abs(cls, blender_path: Path) -> Path:
|
||||||
|
if blender_path.is_absolute():
|
||||||
|
return blender_path
|
||||||
|
return bpy.path.abspath("//") / blender_path
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_default_selection_keypmap(cls) -> tuple:
|
def get_default_selection_keypmap(cls) -> tuple:
|
||||||
"""keymap to replicate default blender selection behaviour with click and box selection"""
|
"""keymap to replicate default blender selection behaviour with click and box selection"""
|
||||||
|
|||||||
Reference in New Issue
Block a user