SplitByBuildingStorey - fix errors, fix Bonsai UI #4721

- The patch was failed when executed from Bonsai since self.src wasn't provided, fixed now.
- Added a temporary hack to diplsay file selector for this patch.
- small refactor.
This commit is contained in:
Andrej730
2024-12-05 17:16:21 +05:00
parent 13106d255c
commit 939cc63cae
3 changed files with 53 additions and 16 deletions
+12 -2
View File
@@ -79,7 +79,12 @@ class ExecuteIfcPatch(bpy.types.Operator):
props = context.scene.BIMPatchProperties props = context.scene.BIMPatchProperties
arguments = [] arguments = []
if props.ifc_patch_args_attr: if props.ifc_patch_args_attr:
arguments = [arg.get_value() for arg in props.ifc_patch_args_attr] arguments = []
for arg in props.ifc_patch_args_attr:
value = arg.get_value()
if arg.data_type == "file" and arg.metadata == "single_file":
value = value[0]
arguments.append(value)
if props.should_load_from_memory and tool.Ifc.get(): if props.should_load_from_memory and tool.Ifc.get():
input_file = props.ifc_patch_input input_file = props.ifc_patch_input
@@ -123,8 +128,13 @@ class UpdateIfcPatchArguments(bpy.types.Operator):
arg_info = inputs[arg_name] arg_info = inputs[arg_name]
new_attr = patch_args.add() new_attr = patch_args.add()
data_type = arg_info.get("type", "str") data_type = arg_info.get("type", "str")
if tool.Patch.is_filepath_argument(self.recipe, arg_name):
data_type = "file"
new_attr.metadata = "single_file"
if isinstance(data_type, list): if isinstance(data_type, list):
if "file" in data_type: if "file" in data_type or tool.Patch.is_filepath_argument(self.recipe, arg_name):
data_type = ["file"] data_type = ["file"]
data_type = [dt for dt in data_type if dt != "NoneType"][0] data_type = [dt for dt in data_type if dt != "NoneType"][0]
+7
View File
@@ -29,3 +29,10 @@ class Patch(bonsai.core.tool.Patch):
{"input": infile, "file": ifcopenshell.open(infile), "recipe": "Migrate", "arguments": [schema]} {"input": infile, "file": ifcopenshell.open(infile), "recipe": "Migrate", "arguments": [schema]}
) )
ifcpatch.write(output, outfile) ifcpatch.write(output, outfile)
@classmethod
def is_filepath_argument(cls, recipe: str, arg_name: str) -> bool:
# TODO: Temporary hack to identify filepath arguments.
# Should mark them as such in the patches documentation
# and process it later.
return recipe == "SplitByBuildingStorey" and arg_name == "output_dir"
@@ -16,9 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>. # along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
import ifcopenshell
from pathlib import Path
from typing import Union
class Patcher: class Patcher:
def __init__(self, src, file, logger, output_dir=None): def __init__(self, src: str, file: ifcopenshell.file, logger: logging.Logger, output_dir: Union[str, None] = None):
"""Split an IFC model into multiple models based on building storey """Split an IFC model into multiple models based on building storey
The new IFC model names will be named after the storey name in the The new IFC model names will be named after the storey name in the
@@ -26,7 +32,6 @@ class Patcher:
0 and {name} is the name of the storey. 0 and {name} is the name of the storey.
:param output_dir: Specifies an output directory where the new IFC models will be saved. :param output_dir: Specifies an output directory where the new IFC models will be saved.
:type output_dir: str
Example: Example:
@@ -39,25 +44,37 @@ class Patcher:
self.logger = logger self.logger = logger
self.output_dir = output_dir self.output_dir = output_dir
def patch(self): def patch(self) -> None:
import ifcopenshell import ifcopenshell
import tempfile
from shutil import copyfile from shutil import copyfile
if self.output_dir is None:
output_dir = None
else:
output_dir = Path(self.output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
temp_file = None
if not self.src:
temp_file = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False)
self.src = temp_file.name
self.file.write(self.src)
storeys = self.file.by_type("IfcBuildingStorey") storeys = self.file.by_type("IfcBuildingStorey")
for i, storey in enumerate(storeys): for i, storey in enumerate(storeys):
dest = ( filename = f"{i}-{storey.Name}.ifc"
"{}-{}.ifc".format(i, storey.Name) dest = filename if output_dir == None else output_dir / filename
if self.output_dir == None
else "{}/{}-{}.ifc".format(self.output_dir, i, storey.Name)
)
copyfile(self.src, dest) copyfile(self.src, dest)
old_ifc = ifcopenshell.open(dest) old_ifc: ifcopenshell.file = ifcopenshell.open(dest)
new_ifc = ifcopenshell.file(schema=self.file.schema) new_ifc = ifcopenshell.file(schema=self.file.schema)
if self.file.schema == "IFC2X3": if self.file.schema == "IFC2X3":
elements = old_ifc.by_type("IfcProject") + old_ifc.by_type("IfcProduct") elements = old_ifc.by_type("IfcProject") + old_ifc.by_type("IfcProduct")
else: else:
elements = old_ifc.by_type("IfcContext") + old_ifc.by_type("IfcProduct") elements = old_ifc.by_type("IfcContext") + old_ifc.by_type("IfcProduct")
inverse_elements = []
inverse_elements: list[ifcopenshell.entity_instance] = []
for element in elements: for element in elements:
if element.is_a("IfcElement") and not self.is_in_storey(element, storey): if element.is_a("IfcElement") and not self.is_in_storey(element, storey):
element.Representation = None element.Representation = None
@@ -76,9 +93,12 @@ class Patcher:
new_ifc.remove(element) new_ifc.remove(element)
new_ifc.write(dest) new_ifc.write(dest)
def is_in_storey(self, element, storey): if temp_file is not None:
os.unlink(temp_file.name)
def is_in_storey(self, element: ifcopenshell.entity_instance, storey: ifcopenshell.entity_instance) -> bool:
return ( return (
element.ContainedInStructure (contained_in_structure := element.ContainedInStructure)
and element.ContainedInStructure[0].RelatingStructure.is_a("IfcBuildingStorey") and (relating_structure := contained_in_structure[0].RelatingStructure).is_a("IfcBuildingStorey")
and element.ContainedInStructure[0].RelatingStructure.GlobalId == storey.GlobalId and relating_structure.GlobalId == storey.GlobalId
) )