From ff8128687425580d7b0c32327dfcc6fdfc83ab4d Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Wed, 17 May 2023 18:00:25 +0200 Subject: [PATCH 1/4] Now it's possible to fix drawing reference path problem saved in Windows and opened in Linux --- .../ifcpatch/recipes/ReplaceDrawingPath.py | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py diff --git a/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py b/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py new file mode 100644 index 0000000000..e65a41acbd --- /dev/null +++ b/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py @@ -0,0 +1,123 @@ +# IfcPatch - IFC patching utiliy +# Copyright (C) 2023 Dion Moult , Massimo Fabbro +# +# This file is part of IfcPatch. +# +# IfcPatch is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcPatch 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcPatch. If not, see . + + +class Patcher: + def __init__(self, src, file, logger): + """ Regenerate all drawings path in case they have been created in a different operating system. + + It is useful when an annotation drawing has been created on windows and you want to recreate the + drawig in linux. + In this case, blenderbim would tell you that can't load "stylesheet" or "markers" or "symbols" or "patterns" folder. + If this happens, this recipie comes in rescue! + Basically, as the path is stored in a strig, the recipie replace the existing sep char with the right one. + + Example: + + .. code:: python + + ifcpatch.execute({"input": model, "recipe": "ReplaceDrawingPath"}) + """ + self.src = src + self.file = file + self.logger = logger + + def patch(self): + import blenderbim.tool as tool + import ifcopenshell + + annotations = self.file.by_type('IfcAnnotation') + + for annotation in annotations: + if annotation.ObjectType == 'DRAWING': + psets = ifcopenshell.util.element.get_psets(annotation) + pset = psets['EPset_Drawing'] + pset_ifc = self.file.by_id(pset['id']) + ifcopenshell.api.run("pset.edit_pset", self.file, pset = pset_ifc, properties = { + 'Stylesheet' : pset['Stylesheet'].replace('\\', '/'), + 'Markers' : pset['Markers'].replace('\\', '/'), + 'Symbols' : pset['Symbols'].replace('\\', '/'), + 'Patterns' : pset['Patterns'].replace('\\', '/'), + }) + + + +#class Patcher: +# def __init__(self, src, file, logger, output_dir=None): +# """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 +# format of {i}-{name}.ifc, where {i} is an ascending number starting from +# 0 and {name} is the name of the storey. +# +# :param output_dir: Specifies an output directory where the new IFC models will be saved. +# :type output_dir: str +# +# Example: +# +# .. code:: python +# +# ifcpatch.execute({"input": model, "recipe": "SplitByBuildingStorey", "arguments": ["C:/.../output_files"]}) +# """ +# self.src = src +# self.file = file +# self.logger = logger +# self.output_dir = output_dir +# +# +# def patch(self): +# import ifcopenshell +# from shutil import copyfile +# +# storeys = self.file.by_type("IfcBuildingStorey") +# for i, storey in enumerate(storeys): +# dest = "{}-{}.ifc".format(i, storey.Name) if self.output_dir == None else "{}/{}-{}.ifc".format(self.output_dir,i, storey.Name) +# copyfile(self.src, dest) +# old_ifc = ifcopenshell.open(dest) +# new_ifc = ifcopenshell.file(schema=self.file.schema) +# if self.file.schema == "IFC2X3": +# elements = old_ifc.by_type("IfcProject") + old_ifc.by_type("IfcProduct") +# else: +# elements = old_ifc.by_type("IfcContext") + old_ifc.by_type("IfcProduct") +# inverse_elements = [] +# for element in elements: +# if element.is_a("IfcElement") and not self.is_in_storey(element, storey): +# element.Representation = None +# continue +# if element.is_a("IfcElement"): +# styled_rep_items = [ +# i for i in old_ifc.traverse(element) if i.is_a("IfcRepresentationItem") and i.StyledByItem +# ] +# [new_ifc.add(i.StyledByItem[0]) for i in styled_rep_items] +# new_ifc.add(element) +# inverse_elements.extend(old_ifc.get_inverse(element)) +# for inverse_element in inverse_elements: +# new_ifc.add(inverse_element) +# for element in new_ifc.by_type("IfcElement"): +# if not self.is_in_storey(element, storey): +# new_ifc.remove(element) +# new_ifc.write(dest) +# +# def is_in_storey(self, element, storey): +# return ( +# element.ContainedInStructure +# and element.ContainedInStructure[0].RelatingStructure.is_a("IfcBuildingStorey") +# and element.ContainedInStructure[0].RelatingStructure.GlobalId == storey.GlobalId +# ) + + From 7ab92dfa0b72ff572693a2f4400a696085d7641a Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Mon, 29 May 2023 20:01:45 +0200 Subject: [PATCH 2/4] IfcPatch ReplaceDrawingPath recipie improved: now it's possible to use it on Linux and on Windows --- .../ifcpatch/recipes/ReplaceDrawingPath.py | 85 +++---------------- 1 file changed, 14 insertions(+), 71 deletions(-) diff --git a/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py b/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py index e65a41acbd..b9cc90b9c6 100644 --- a/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py +++ b/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcPatch. If not, see . +import os +from sys import platform class Patcher: def __init__(self, src, file, logger): @@ -25,7 +27,9 @@ class Patcher: drawig in linux. In this case, blenderbim would tell you that can't load "stylesheet" or "markers" or "symbols" or "patterns" folder. If this happens, this recipie comes in rescue! - Basically, as the path is stored in a strig, the recipie replace the existing sep char with the right one. + Basically, as the path is stored in a string, the recipie replace the existing sep char with the right one. + It doesn't need to specify the ifc output file or any arguments. + If ifc ouput file is specified, it saves the patched file in the new file. Example: @@ -48,76 +52,15 @@ class Patcher: psets = ifcopenshell.util.element.get_psets(annotation) pset = psets['EPset_Drawing'] pset_ifc = self.file.by_id(pset['id']) + wrong_sep = "" + if platform == 'linux' or platform == 'linux2' or platform == 'darwin': + wrong_sep = "\\" + if platform == 'win32': + wrong_sep = "/" ifcopenshell.api.run("pset.edit_pset", self.file, pset = pset_ifc, properties = { - 'Stylesheet' : pset['Stylesheet'].replace('\\', '/'), - 'Markers' : pset['Markers'].replace('\\', '/'), - 'Symbols' : pset['Symbols'].replace('\\', '/'), - 'Patterns' : pset['Patterns'].replace('\\', '/'), + 'Stylesheet' : pset['Stylesheet'].replace(wrong_sep, os.path.sep), + 'Markers' : pset['Markers'].replace(wrong_sep, os.path.sep), + 'Symbols' : pset['Symbols'].replace(wrong_sep, os.path.sep), + 'Patterns' : pset['Patterns'].replace(wrong_sep, os.path.sep), }) - - -#class Patcher: -# def __init__(self, src, file, logger, output_dir=None): -# """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 -# format of {i}-{name}.ifc, where {i} is an ascending number starting from -# 0 and {name} is the name of the storey. -# -# :param output_dir: Specifies an output directory where the new IFC models will be saved. -# :type output_dir: str -# -# Example: -# -# .. code:: python -# -# ifcpatch.execute({"input": model, "recipe": "SplitByBuildingStorey", "arguments": ["C:/.../output_files"]}) -# """ -# self.src = src -# self.file = file -# self.logger = logger -# self.output_dir = output_dir -# -# -# def patch(self): -# import ifcopenshell -# from shutil import copyfile -# -# storeys = self.file.by_type("IfcBuildingStorey") -# for i, storey in enumerate(storeys): -# dest = "{}-{}.ifc".format(i, storey.Name) if self.output_dir == None else "{}/{}-{}.ifc".format(self.output_dir,i, storey.Name) -# copyfile(self.src, dest) -# old_ifc = ifcopenshell.open(dest) -# new_ifc = ifcopenshell.file(schema=self.file.schema) -# if self.file.schema == "IFC2X3": -# elements = old_ifc.by_type("IfcProject") + old_ifc.by_type("IfcProduct") -# else: -# elements = old_ifc.by_type("IfcContext") + old_ifc.by_type("IfcProduct") -# inverse_elements = [] -# for element in elements: -# if element.is_a("IfcElement") and not self.is_in_storey(element, storey): -# element.Representation = None -# continue -# if element.is_a("IfcElement"): -# styled_rep_items = [ -# i for i in old_ifc.traverse(element) if i.is_a("IfcRepresentationItem") and i.StyledByItem -# ] -# [new_ifc.add(i.StyledByItem[0]) for i in styled_rep_items] -# new_ifc.add(element) -# inverse_elements.extend(old_ifc.get_inverse(element)) -# for inverse_element in inverse_elements: -# new_ifc.add(inverse_element) -# for element in new_ifc.by_type("IfcElement"): -# if not self.is_in_storey(element, storey): -# new_ifc.remove(element) -# new_ifc.write(dest) -# -# def is_in_storey(self, element, storey): -# return ( -# element.ContainedInStructure -# and element.ContainedInStructure[0].RelatingStructure.is_a("IfcBuildingStorey") -# and element.ContainedInStructure[0].RelatingStructure.GlobalId == storey.GlobalId -# ) - - From 663402534619b96d88568d5a6c30fd059efc9eda Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Wed, 31 May 2023 21:02:29 +0200 Subject: [PATCH 3/4] Move the recipe into the blenderbim script folder and rewrite it as a script --- .../scripts/replace_drawing_path.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/blenderbim/scripts/replace_drawing_path.py diff --git a/src/blenderbim/scripts/replace_drawing_path.py b/src/blenderbim/scripts/replace_drawing_path.py new file mode 100644 index 0000000000..3a9205305a --- /dev/null +++ b/src/blenderbim/scripts/replace_drawing_path.py @@ -0,0 +1,65 @@ +# IfcPatch - IFC patching utiliy +# Copyright (C) 2023 Dion Moult , Massimo Fabbro +# +# This file is part of IfcPatch. +# +# IfcPatch is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcPatch 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcPatch. If not, see . + +""" This script regenerates all drawing paths in case they have been created in a different operating system. + +It is useful when an annotation drawing has been created on windows and you want to recreate the +drawig in linux. +In this case, blenderbim would tell you that can't load "stylesheet" or "markers" or "symbols" or "patterns" folder. +If this happens, this script comes in rescue! +Basically, as the path is stored in a string, the script replaces the existing sep char with the right one. +It works on the active ifc file (if exists). + +""" + +import blenderbim.tool as tool +import ifcopenshell +import sys + + +import os +from sys import platform + +file = tool.Ifc.get() +if not file: + print("No ifc file") + sys.exit() + +annotations = file.by_type('IfcAnnotation') +count = 0 + +for annotation in annotations: + if annotation.ObjectType == 'DRAWING': + psets = ifcopenshell.util.element.get_psets(annotation) + pset = psets['EPset_Drawing'] + pset_ifc = file.by_id(pset['id']) + wrong_sep = "" + if platform == 'linux' or platform == 'linux2' or platform == 'darwin': + wrong_sep = "\\" + if platform == 'win32': + wrong_sep = "/" + ifcopenshell.api.run("pset.edit_pset", file, pset = pset_ifc, properties = { + 'Stylesheet' : pset['Stylesheet'].replace(wrong_sep, os.path.sep), + 'Markers' : pset['Markers'].replace(wrong_sep, os.path.sep), + 'Symbols' : pset['Symbols'].replace(wrong_sep, os.path.sep), + 'Patterns' : pset['Patterns'].replace(wrong_sep, os.path.sep), + }) + count+=1 + +print(f"DONE! Checked {count} drawings") + From 91176349f731b095794926674a83ae719d74d5f0 Mon Sep 17 00:00:00 2001 From: Massimo Fabbro Date: Wed, 31 May 2023 21:07:34 +0200 Subject: [PATCH 4/4] Remove old patch file --- .../ifcpatch/recipes/ReplaceDrawingPath.py | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py diff --git a/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py b/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py deleted file mode 100644 index b9cc90b9c6..0000000000 --- a/src/ifcpatch/ifcpatch/recipes/ReplaceDrawingPath.py +++ /dev/null @@ -1,66 +0,0 @@ -# IfcPatch - IFC patching utiliy -# Copyright (C) 2023 Dion Moult , Massimo Fabbro -# -# This file is part of IfcPatch. -# -# IfcPatch is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# IfcPatch 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 Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with IfcPatch. If not, see . - -import os -from sys import platform - -class Patcher: - def __init__(self, src, file, logger): - """ Regenerate all drawings path in case they have been created in a different operating system. - - It is useful when an annotation drawing has been created on windows and you want to recreate the - drawig in linux. - In this case, blenderbim would tell you that can't load "stylesheet" or "markers" or "symbols" or "patterns" folder. - If this happens, this recipie comes in rescue! - Basically, as the path is stored in a string, the recipie replace the existing sep char with the right one. - It doesn't need to specify the ifc output file or any arguments. - If ifc ouput file is specified, it saves the patched file in the new file. - - Example: - - .. code:: python - - ifcpatch.execute({"input": model, "recipe": "ReplaceDrawingPath"}) - """ - self.src = src - self.file = file - self.logger = logger - - def patch(self): - import blenderbim.tool as tool - import ifcopenshell - - annotations = self.file.by_type('IfcAnnotation') - - for annotation in annotations: - if annotation.ObjectType == 'DRAWING': - psets = ifcopenshell.util.element.get_psets(annotation) - pset = psets['EPset_Drawing'] - pset_ifc = self.file.by_id(pset['id']) - wrong_sep = "" - if platform == 'linux' or platform == 'linux2' or platform == 'darwin': - wrong_sep = "\\" - if platform == 'win32': - wrong_sep = "/" - ifcopenshell.api.run("pset.edit_pset", self.file, pset = pset_ifc, properties = { - 'Stylesheet' : pset['Stylesheet'].replace(wrong_sep, os.path.sep), - 'Markers' : pset['Markers'].replace(wrong_sep, os.path.sep), - 'Symbols' : pset['Symbols'].replace(wrong_sep, os.path.sep), - 'Patterns' : pset['Patterns'].replace(wrong_sep, os.path.sep), - }) -