mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
This commit is contained in:
@@ -98,12 +98,6 @@ class ExecuteIfcPatch(bpy.types.Operator):
|
|||||||
|
|
||||||
if props.should_load_from_memory and tool.Ifc.get():
|
if props.should_load_from_memory and tool.Ifc.get():
|
||||||
args["file"] = tool.Ifc.get()
|
args["file"] = tool.Ifc.get()
|
||||||
if ifcpatch.get_patch_input_argument_use(recipe_name) == "REQUIRED":
|
|
||||||
self.report(
|
|
||||||
{"ERROR"},
|
|
||||||
f"The recipe '{recipe_name}' is not currently supported if file is loaded from memory.",
|
|
||||||
)
|
|
||||||
return {"CANCELLED"}
|
|
||||||
else:
|
else:
|
||||||
args["input"] = cast(str, props.ifc_patch_input)
|
args["input"] = cast(str, props.ifc_patch_input)
|
||||||
args["file"] = cast(ifcopenshell.file, ifcopenshell.open(props.ifc_patch_input))
|
args["file"] = cast(ifcopenshell.file, ifcopenshell.open(props.ifc_patch_input))
|
||||||
|
|||||||
@@ -33,10 +33,8 @@ class Patch(bonsai.core.tool.Patch):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_filepath_argument(cls, recipe: str, arg_name: str) -> bool:
|
def is_filepath_argument(cls, recipe: str, arg_name: str) -> bool:
|
||||||
# TODO: Temporary hack to identify filepath arguments.
|
# There is probably a more explicit way to do this
|
||||||
# Should mark them as such in the patches documentation
|
return "filepath" in arg_name
|
||||||
# and process it later.
|
|
||||||
return recipe == "SplitByBuildingStorey" and arg_name == "output_dir"
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def does_patch_has_output(cls, recipe: str) -> bool:
|
def does_patch_has_output(cls, recipe: str) -> bool:
|
||||||
|
|||||||
@@ -95,30 +95,16 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]:
|
|||||||
else:
|
else:
|
||||||
recipe = importlib.import_module(f"ifcpatch.recipes.{args['recipe']}")
|
recipe = importlib.import_module(f"ifcpatch.recipes.{args['recipe']}")
|
||||||
|
|
||||||
# Ensure file or input is provided.
|
|
||||||
input_argument = get_patch_input_argument_use(args["recipe"])
|
|
||||||
if input_argument == "REQUIRED":
|
|
||||||
if not args.get("input"):
|
|
||||||
raise ValueError(f"Recipe {args['recipe']} is requiring 'input' argument to be provided.")
|
|
||||||
elif "file" not in args: # SUPPORTED, IGNORED.
|
|
||||||
raise ValueError(f"Recipe {args['recipe']} is requiring 'file' argument to be provided.")
|
|
||||||
|
|
||||||
arguments = args.get("arguments", None) or []
|
arguments = args.get("arguments", None) or []
|
||||||
if recipe.Patcher.__init__.__doc__ is not None:
|
if recipe.Patcher.__init__.__doc__ is not None:
|
||||||
patcher = recipe.Patcher(args.get("input"), args.get("file"), logger, *arguments)
|
patcher = recipe.Patcher(args.get("file"), logger, *arguments)
|
||||||
else:
|
else:
|
||||||
patcher = recipe.Patcher(args.get("input"), args.get("file"), logger, arguments)
|
patcher = recipe.Patcher(args.get("file"), logger, arguments)
|
||||||
patcher.patch()
|
patcher.patch()
|
||||||
output = getattr(patcher, "file_patched", patcher.file)
|
output = getattr(patcher, "file_patched", patcher.file)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def get_patch_input_argument_use(recipe: str) -> Literal["REQUIRED", "SUPPORTED", "IGNORED"]:
|
|
||||||
# try out of tree and subpackage imports
|
|
||||||
recipe_module = sys.modules.get(f"ifcpatch.recipes.{recipe}") or sys.modules.get(recipe)
|
|
||||||
return getattr(recipe_module.Patcher, "input_argument", "IGNORED")
|
|
||||||
|
|
||||||
|
|
||||||
def write(output: Union[ifcopenshell.file, str], filepath: str) -> None:
|
def write(output: Union[ifcopenshell.file, str], filepath: str) -> None:
|
||||||
"""Write the output of an IFC patch to a file
|
"""Write the output of an IFC patch to a file
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ LengthUnit = typing.Literal[
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src: str,
|
|
||||||
file: ifcopenshell.file,
|
file: ifcopenshell.file,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
unit: LengthUnit = "METER",
|
unit: LengthUnit = "METER",
|
||||||
@@ -76,7 +75,6 @@ class Patcher:
|
|||||||
# Convert to feet
|
# Convert to feet
|
||||||
model = ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertLengthUnit", "arguments": ["FOOT"]})
|
model = ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertLengthUnit", "arguments": ["FOOT"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.unit = unit
|
self.unit = unit
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ifcopenshell.guid
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Convert nesting relationships to aggregate relationships
|
"""Convert nesting relationships to aggregate relationships
|
||||||
|
|
||||||
Some software like Revit won't load nested children elements because
|
Some software like Revit won't load nested children elements because
|
||||||
@@ -39,7 +39,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertNestToAggregate", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertNestToAggregate", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from typing import Union
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, property_name: str, quantity_name: str):
|
def __init__(self, file: ifcopenshell.file, logger: Logger, property_name: str, quantity_name: str):
|
||||||
"""Converts a property to a standardised quantity
|
"""Converts a property to a standardised quantity
|
||||||
|
|
||||||
IFC can store arbitrary key value metadata associated with a elements
|
IFC can store arbitrary key value metadata associated with a elements
|
||||||
@@ -59,7 +59,6 @@ class Patcher:
|
|||||||
# "NetSideArea", if that standardised quantity exists.
|
# "NetSideArea", if that standardised quantity exists.
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertPropertiesToQuantities", "arguments": ["Area", "NetSideArea"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertPropertiesToQuantities", "arguments": ["Area", "NetSideArea"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.source_property_name = property_name
|
self.source_property_name = property_name
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ifcopenshell.util.element
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Downgrade indexed polycurves to simple polylines
|
"""Downgrade indexed polycurves to simple polylines
|
||||||
|
|
||||||
Low quality IFC viewers like Navisworks do not support various IFC4
|
Low quality IFC viewers like Navisworks do not support various IFC4
|
||||||
@@ -39,7 +39,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "DowngradeIndexedPolyCurve", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "DowngradeIndexedPolyCurve", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, query: str = "IfcWall"):
|
def __init__(self, file: ifcopenshell.file, logger: Logger, query: str = "IfcWall"):
|
||||||
"""Extract certain elements into a new model
|
"""Extract certain elements into a new model
|
||||||
|
|
||||||
Extract a subset of elements from an existing IFC data set and save it
|
Extract a subset of elements from an existing IFC data set and save it
|
||||||
@@ -48,7 +48,6 @@ class Patcher:
|
|||||||
# Extract all walls and slabs
|
# Extract all walls and slabs
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcWall, IfcSlab"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcWall, IfcSlab"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.query = query
|
self.query = query
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ except:
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src,
|
|
||||||
file,
|
file,
|
||||||
logger,
|
logger,
|
||||||
):
|
):
|
||||||
@@ -50,7 +49,6 @@ class Patcher:
|
|||||||
result = ifcpatch.execute({"input": fn, "file": model, "recipe": "ExtractPropertiesToSQLite"})
|
result = ifcpatch.execute({"input": fn, "file": model, "recipe": "ExtractPropertiesToSQLite"})
|
||||||
ifcpatch.write(result, "output.sqlite")
|
ifcpatch.write(result, "output.sqlite")
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import ifcopenshell.util.element
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Fix missing door swings in Revit when viewing ArchiCAD IFCs
|
"""Fix missing door swings in Revit when viewing ArchiCAD IFCs
|
||||||
|
|
||||||
ArchiCAD has the ability to store 2D data with objects like doors for
|
ArchiCAD has the ability to store 2D data with objects like doors for
|
||||||
@@ -56,7 +56,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixArchiCADToRevitDoorSwings", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixArchiCADToRevitDoorSwings", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ import ifcopenshell
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
input_argument = "REQUIRED"
|
def __init__(self, file: None, logger: logging.Logger, filepath: str):
|
||||||
|
|
||||||
def __init__(self, src: str, file: None, logger: logging.Logger):
|
|
||||||
"""Allow ArchiCAD IFC spaces to open as Revit rooms
|
"""Allow ArchiCAD IFC spaces to open as Revit rooms
|
||||||
|
|
||||||
The underlying problem is that Revit does not bring in IFC spaces as
|
The underlying problem is that Revit does not bring in IFC spaces as
|
||||||
@@ -51,16 +49,21 @@ class Patcher:
|
|||||||
requires you to run it using Blender, as the geometric modification
|
requires you to run it using Blender, as the geometric modification
|
||||||
uses the Blender geometry engine.
|
uses the Blender geometry engine.
|
||||||
|
|
||||||
`input` argument is required for this recipe, `file` argument is ignored.
|
`filepath` argument is required for this recipe, `file` argument is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
:param filepath: The filepath of the IFC model. This is required to
|
||||||
|
load into Bonsai.
|
||||||
|
:filter_glob filepath: *.ifc;*.ifczip;*.ifcxml
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
ifcpatch.execute({"input": "input.ifc", "recipe": "FixArchiCADToRevitSpaces", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "recipe": "FixArchiCADToRevitSpaces", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
self.filepath = filepath
|
||||||
|
|
||||||
def patch(self) -> None:
|
def patch(self) -> None:
|
||||||
import bpy
|
import bpy
|
||||||
@@ -74,7 +77,7 @@ class Patcher:
|
|||||||
bpy.data.batch_remove(bpy.data.objects)
|
bpy.data.batch_remove(bpy.data.objects)
|
||||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||||
|
|
||||||
bpy.ops.bim.load_project(filepath=self.src)
|
bpy.ops.bim.load_project(filepath=self.filepath)
|
||||||
|
|
||||||
def recalculate_origin(wall: bpy.types.Object) -> None:
|
def recalculate_origin(wall: bpy.types.Object) -> None:
|
||||||
new_origin = wall.matrix_world @ Vector(wall.bound_box[0])
|
new_origin = wall.matrix_world @ Vector(wall.bound_box[0])
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ifcopenshell.util.element
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Reassigns occurrence classifications to types
|
"""Reassigns occurrence classifications to types
|
||||||
|
|
||||||
Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/691)
|
Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/691)
|
||||||
@@ -35,7 +35,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixRevitClassificationCodeTypes"})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixRevitClassificationCodeTypes"})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ import logging
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
input_argument = "REQUIRED"
|
def __init__(self, file: None, logger: logging.Logger, filepath: str, is_solid: bool = True):
|
||||||
|
|
||||||
def __init__(self, src: str, file: None, logger: logging.Logger, is_solid: bool = True):
|
|
||||||
"""Fix missing or spot-coordinate bugged TINs loading in Revit
|
"""Fix missing or spot-coordinate bugged TINs loading in Revit
|
||||||
|
|
||||||
TINs exported from 12D or Civil 3D may contain dense or highly obtuse
|
TINs exported from 12D or Civil 3D may contain dense or highly obtuse
|
||||||
@@ -62,7 +60,12 @@ class Patcher:
|
|||||||
from civil software. It also requires you to run it using Blender, as
|
from civil software. It also requires you to run it using Blender, as
|
||||||
the geometric modification uses the Blender geometry engine.
|
the geometric modification uses the Blender geometry engine.
|
||||||
|
|
||||||
`input` argument is required for this recipe, `file` argument is ignored.
|
`filepath` argument is required for this recipe, `file` argument is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
:param filepath: The filepath of the IFC model. This is required to
|
||||||
|
load into Bonsai.
|
||||||
|
:filter_glob filepath: *.ifc;*.ifczip;*.ifcxml
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -70,8 +73,8 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "recipe": "FixRevitTINs", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "recipe": "FixRevitTINs", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
|
self.filepath = filepath
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.is_solid = is_solid
|
self.is_solid = is_solid
|
||||||
|
|
||||||
@@ -82,7 +85,7 @@ class Patcher:
|
|||||||
from math import degrees
|
from math import degrees
|
||||||
|
|
||||||
bpy.context.scene.BIMProjectProperties.should_use_native_meshes = True
|
bpy.context.scene.BIMProjectProperties.should_use_native_meshes = True
|
||||||
bpy.ops.bim.load_project(filepath=self.src)
|
bpy.ops.bim.load_project(filepath=self.filepath)
|
||||||
|
|
||||||
old_history_size = tool.Ifc.get().history_size
|
old_history_size = tool.Ifc.get().history_size
|
||||||
old_undo_steps = bpy.context.preferences.edit.undo_steps
|
old_undo_steps = bpy.context.preferences.edit.undo_steps
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ except:
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src,
|
|
||||||
file,
|
file,
|
||||||
logger,
|
logger,
|
||||||
sql_type: SQLTypes = "SQLite",
|
sql_type: SQLTypes = "SQLite",
|
||||||
@@ -98,7 +97,6 @@ class Patcher:
|
|||||||
{"input": "input.ifc", "file": model, "recipe": "Ifc2Sql", "arguments": ["sqlite"]}
|
{"input": "input.ifc", "file": model, "recipe": "Ifc2Sql", "arguments": ["sqlite"]}
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.sql_type = sql_type.lower()
|
self.sql_type = sql_type.lower()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, attribute: str = "Tag"):
|
def __init__(self, file: ifcopenshell.file, logger: Logger, attribute: str = "Tag"):
|
||||||
"""Merge duplicate element types via the Tag or another attribute
|
"""Merge duplicate element types via the Tag or another attribute
|
||||||
|
|
||||||
Revit is notorious for creating many duplicate element types. Element
|
Revit is notorious for creating many duplicate element types. Element
|
||||||
@@ -60,7 +60,6 @@ class Patcher:
|
|||||||
# Explicitly say we want to merge based on the Name attribute
|
# Explicitly say we want to merge based on the Name attribute
|
||||||
ifcpatch.execute({"file": model, "recipe": "MergeDuplicateTypes", "arguments": ["Name"]})
|
ifcpatch.execute({"file": model, "recipe": "MergeDuplicateTypes", "arguments": ["Name"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(self, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]]):
|
||||||
self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]]
|
|
||||||
):
|
|
||||||
"""Merge two or more IFC models into one
|
"""Merge two or more IFC models into one
|
||||||
|
|
||||||
Note that other than combining the two (or more) IfcProject elements into
|
Note that other than combining the two (or more) IfcProject elements into
|
||||||
@@ -50,7 +48,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "MergeProjects", "arguments": ["/path/to/model2.ifc"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "MergeProjects", "arguments": ["/path/to/model2.ifc"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.filepaths = filepaths
|
self.filepaths = filepaths
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from logging import Logger
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src: str,
|
|
||||||
file: ifcopenshell.file,
|
file: ifcopenshell.file,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
schema: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4",
|
schema: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4",
|
||||||
@@ -45,7 +44,6 @@ class Patcher:
|
|||||||
# Upgrade an IFC2X3 model to IFC4
|
# Upgrade an IFC2X3 model to IFC4
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Migrate", "arguments": ["IFC4"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Migrate", "arguments": ["IFC4"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.schema = schema
|
self.schema = schema
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import typing
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src,
|
|
||||||
file,
|
file,
|
||||||
logger,
|
logger,
|
||||||
x: typing.Union[str, float] = "0",
|
x: typing.Union[str, float] = "0",
|
||||||
@@ -89,7 +88,6 @@ class Patcher:
|
|||||||
# Some crazy 3D rotation and offset
|
# Some crazy 3D rotation and offset
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetObjectPlacements", "arguments": [12.5,5,2,False,90,90,45]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetObjectPlacements", "arguments": [12.5,5,2,False,90,90,45]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.x = float(x)
|
self.x = float(x)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import typing
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger, z: typing.Union[str, float] = "0"):
|
def __init__(self, file, logger, z: typing.Union[str, float] = "0"):
|
||||||
"""Offset building storeys by a particular Z value
|
"""Offset building storeys by a particular Z value
|
||||||
|
|
||||||
All objects placed relative to the storeys will also be shifted.
|
All objects placed relative to the storeys will also be shifted.
|
||||||
@@ -35,7 +35,6 @@ class Patcher:
|
|||||||
# Shift all storeys up by 42 units
|
# Shift all storeys up by 42 units
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetStoreyElevations", "arguments": [42]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetStoreyElevations", "arguments": [42]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.z = float(z)
|
self.z = float(z)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import ifcopenshell.util.element
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Optimise the filesize of an IFC model
|
"""Optimise the filesize of an IFC model
|
||||||
|
|
||||||
It is possible to non-losslessly optimise the filesize of an IFC model.
|
It is possible to non-losslessly optimise the filesize of an IFC model.
|
||||||
@@ -46,7 +46,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Optimise", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Optimise", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.optimized_file = ifcopenshell.file(schema=self.file.schema)
|
self.optimized_file = ifcopenshell.file(schema=self.file.schema)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger):
|
def __init__(self, file: ifcopenshell.file, logger: Logger):
|
||||||
"""Purge IFC properties, relationships, and other data
|
"""Purge IFC properties, relationships, and other data
|
||||||
|
|
||||||
In some rare cases (i.e. "resetting" a model or for security purposes)
|
In some rare cases (i.e. "resetting" a model or for security purposes)
|
||||||
@@ -51,7 +51,6 @@ class Patcher:
|
|||||||
# Watch the world burn
|
# Watch the world burn
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "PurgeData", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "PurgeData", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import ifcopenshell.util.element
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: logging.Logger):
|
def __init__(self, file: ifcopenshell.file, logger: logging.Logger):
|
||||||
"""Optimise the filesize of an IFC model by reusing non-rooted elements
|
"""Optimise the filesize of an IFC model by reusing non-rooted elements
|
||||||
|
|
||||||
It is possible to non-losslessly optimise the filesize of an IFC model.
|
It is possible to non-losslessly optimise the filesize of an IFC model.
|
||||||
@@ -46,7 +46,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RecycleNonRootedElements", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RecycleNonRootedElements", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, only_duplicates=False):
|
def __init__(self, file: ifcopenshell.file, logger: Logger, only_duplicates=False):
|
||||||
"""Regenerate GlobalIds in an IFC model
|
"""Regenerate GlobalIds in an IFC model
|
||||||
|
|
||||||
All root elements in an IFC model must be identified by a unique Global
|
All root elements in an IFC model must be identified by a unique Global
|
||||||
@@ -48,7 +48,6 @@ class Patcher:
|
|||||||
# Regenerate only duplicate GlobalIds
|
# Regenerate only duplicate GlobalIds
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RegenerateGlobalIds", "arguments": [True]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RegenerateGlobalIds", "arguments": [True]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.only_duplicates = only_duplicates
|
self.only_duplicates = only_duplicates
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Removes the built-in Revit Uniformat classification.
|
"""Removes the built-in Revit Uniformat classification.
|
||||||
|
|
||||||
Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/486)
|
Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/486)
|
||||||
@@ -31,7 +31,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveRevitUniformatClassification"})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveRevitUniformatClassification"})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger):
|
def __init__(self, file, logger):
|
||||||
"""Removes any 3D geometry associated with a site or multiple sites
|
"""Removes any 3D geometry associated with a site or multiple sites
|
||||||
|
|
||||||
If no sites or no site geometry is present, nothing happens.
|
If no sites or no site geometry is present, nothing happens.
|
||||||
@@ -29,7 +29,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveSiteRepresentation", "arguments": []})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveSiteRepresentation", "arguments": []})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ from typing import Literal, Optional, Union
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src: str,
|
|
||||||
file: ifcopenshell.file,
|
file: ifcopenshell.file,
|
||||||
logger: logging.Logger,
|
logger: logging.Logger,
|
||||||
mode: Literal[
|
mode: Literal[
|
||||||
@@ -99,7 +98,6 @@ class Patcher:
|
|||||||
# Reset all coordinates with an ordinate larger than 1000 by -500,-200,0
|
# Reset all coordinates with an ordinate larger than 1000 by -500,-200,0
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetAbsoluteCoordinates", "arguments": [False, 1000, -500,-200,0]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetAbsoluteCoordinates", "arguments": [False, 1000, -500,-200,0]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.mode = mode.lower()
|
self.mode = mode.lower()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger, ifc_class="IfcSite"):
|
def __init__(self, file, logger, ifc_class="IfcSite"):
|
||||||
"""Resets the location of a spatial element to 0,0,0
|
"""Resets the location of a spatial element to 0,0,0
|
||||||
|
|
||||||
Another more specialised patch to fix incorrect coordinate usage is to
|
Another more specialised patch to fix incorrect coordinate usage is to
|
||||||
@@ -35,7 +35,6 @@ class Patcher:
|
|||||||
# All IfcSites will shift back to 0,0,0.
|
# All IfcSites will shift back to 0,0,0.
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetSpatialElementLocations", "arguments": ["IfcSite"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetSpatialElementLocations", "arguments": ["IfcSite"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.ifc_class = ifc_class
|
self.ifc_class = ifc_class
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import typing
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src,
|
|
||||||
file,
|
file,
|
||||||
logger,
|
logger,
|
||||||
name: str = "EPSG:1234",
|
name: str = "EPSG:1234",
|
||||||
@@ -59,7 +58,6 @@ class Patcher:
|
|||||||
# Set the current origin 0,0,0 to correlate to map coordinates 1000,1000,0 and a grid north of 15.
|
# Set the current origin 0,0,0 to correlate to map coordinates 1000,1000,0 and a grid north of 15.
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetFalseOrigin", "arguments": ["EPSG:1234", 0, 0, 0, 1000, 1000, 0, 15, 0]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetFalseOrigin", "arguments": ["EPSG:1234", 0, 0, 0, 1000, 1000, 0, 15, 0]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -73,7 +71,7 @@ class Patcher:
|
|||||||
self.rotate_angle = float(rotate_angle)
|
self.rotate_angle = float(rotate_angle)
|
||||||
|
|
||||||
def patch(self):
|
def patch(self):
|
||||||
SetWorldCoordinateSystem.Patcher(self.src, self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch()
|
SetWorldCoordinateSystem.Patcher(self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch()
|
||||||
coordinate_operation = {
|
coordinate_operation = {
|
||||||
"Eastings": self.e,
|
"Eastings": self.e,
|
||||||
"Northings": self.n,
|
"Northings": self.n,
|
||||||
@@ -90,7 +88,6 @@ class Patcher:
|
|||||||
self.file, projected_crs={"Name": self.name}, coordinate_operation=coordinate_operation
|
self.file, projected_crs={"Name": self.name}, coordinate_operation=coordinate_operation
|
||||||
)
|
)
|
||||||
OffsetObjectPlacements.Patcher(
|
OffsetObjectPlacements.Patcher(
|
||||||
self.src,
|
|
||||||
self.file,
|
self.file,
|
||||||
self.logger,
|
self.logger,
|
||||||
x=-self.x,
|
x=-self.x,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import typing
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src, file, logger, elevation: typing.Union[str, float] = "0"):
|
def __init__(self, file, logger, elevation: typing.Union[str, float] = "0"):
|
||||||
"""Sets the reference elevation of all IfcSites
|
"""Sets the reference elevation of all IfcSites
|
||||||
|
|
||||||
To completely reference model coordinates, a reference elevation should
|
To completely reference model coordinates, a reference elevation should
|
||||||
@@ -41,7 +41,6 @@ class Patcher:
|
|||||||
# All IfcSites will have their reference elevation set to 42.
|
# All IfcSites will have their reference elevation set to 42.
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetRefElevation", "arguments": [42]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetRefElevation", "arguments": [42]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.elevation = float(elevation)
|
self.elevation = float(elevation)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import typing
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src,
|
|
||||||
file,
|
file,
|
||||||
logger,
|
logger,
|
||||||
x: typing.Union[str, float] = "0",
|
x: typing.Union[str, float] = "0",
|
||||||
@@ -61,7 +60,6 @@ class Patcher:
|
|||||||
# Set the world coordinate system back to 0, 0, 0
|
# Set the world coordinate system back to 0, 0, 0
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetWorldCoordinateSystem", "arguments": [0,0,0,0,0,0]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetWorldCoordinateSystem", "arguments": [0,0,0,0,0,0]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.x = float(x)
|
self.x = float(x)
|
||||||
|
|||||||
@@ -24,18 +24,13 @@ from typing import Union
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
input_argument = "SUPPORTED"
|
def __init__(self, file: ifcopenshell.file, logger: logging.Logger, output_dir: Union[str, None] = 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
|
||||||
format of {i}-{name}.ifc, where {i} is an ascending number starting from
|
format of {i}-{name}.ifc, where {i} is an ascending number starting from
|
||||||
0 and {name} is the name of the storey.
|
0 and {name} is the name of the storey.
|
||||||
|
|
||||||
`input` argument might be provided to ifcpatch - it will be used load file from disk
|
|
||||||
(otherwise `file` will be saved to a temporary file).
|
|
||||||
|
|
||||||
: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.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@@ -44,7 +39,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SplitByBuildingStorey", "arguments": ["C:/.../output_files"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SplitByBuildingStorey", "arguments": ["C:/.../output_files"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.output_dir = output_dir
|
self.output_dir = output_dir
|
||||||
@@ -60,17 +54,14 @@ class Patcher:
|
|||||||
output_dir = Path(self.output_dir)
|
output_dir = Path(self.output_dir)
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
temp_file = None
|
temp_file = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False)
|
||||||
if not self.src:
|
self.file.write(temp_file.name)
|
||||||
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):
|
||||||
filename = f"{i}-{storey.Name}.ifc"
|
filename = f"{i}-{storey.Name}.ifc"
|
||||||
dest = filename if output_dir == None else output_dir / filename
|
dest = filename if output_dir == None else output_dir / filename
|
||||||
copyfile(self.src, dest)
|
copyfile(temp_file.name, dest)
|
||||||
old_ifc: ifcopenshell.file = 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)
|
||||||
|
|
||||||
@@ -98,9 +89,8 @@ class Patcher:
|
|||||||
new_ifc.remove(element)
|
new_ifc.remove(element)
|
||||||
new_ifc.write(dest)
|
new_ifc.write(dest)
|
||||||
|
|
||||||
if temp_file is not None:
|
temp_file.close()
|
||||||
temp_file.close()
|
os.unlink(temp_file.name)
|
||||||
os.unlink(temp_file.name)
|
|
||||||
|
|
||||||
def is_in_storey(self, element: ifcopenshell.entity_instance, storey: ifcopenshell.entity_instance) -> bool:
|
def is_in_storey(self, element: ifcopenshell.entity_instance, storey: ifcopenshell.entity_instance) -> bool:
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ from typing import Union
|
|||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
src: str,
|
|
||||||
file: ifcopenshell.file,
|
file: ifcopenshell.file,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
query: str = "IfcBeam",
|
query: str = "IfcBeam",
|
||||||
@@ -58,7 +57,6 @@ class Patcher:
|
|||||||
|
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "TessellateElements", "arguments": ["IfcBeam", False]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "TessellateElements", "arguments": ["IfcBeam", False]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.query = query
|
self.query = query
|
||||||
|
|||||||
@@ -25,18 +25,22 @@ from logging import Logger
|
|||||||
|
|
||||||
|
|
||||||
class Patcher:
|
class Patcher:
|
||||||
def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, query: str = ""):
|
def __init__(self, file: ifcopenshell.file, logger: Logger, query: str = ""):
|
||||||
"""Create independent copies for shared psets in IFC file.
|
"""Create independent copies for shared psets in IFC file.
|
||||||
|
|
||||||
In IFC it's possible that same property set is shared by multiple elements,
|
In IFC it's possible that same property set is shared by multiple
|
||||||
so editing it's properties will automatically change their values for all those elements.
|
elements, so editing it's properties will automatically change their
|
||||||
|
values for all those elements.
|
||||||
|
|
||||||
Sometimes it's intended but sometimes it's not and it's just the way some other
|
Sometimes it's intended but sometimes it's not and it's just the way
|
||||||
software exports IFC (e.g. there is a known case when Tekla exports shared psets for all the occurrences).
|
some other software exports IFC (e.g. there is a known case when Tekla
|
||||||
While it is more optimized way to store data, it may lead to unexpected results when editing properties.
|
exports shared psets for all the occurrences). While it is more
|
||||||
|
optimized way to store data, it may lead to unexpected results when
|
||||||
|
editing properties.
|
||||||
|
|
||||||
This recipe creates independent copies of all shared psets (may be limited by the query)
|
This recipe creates independent copies of all shared psets (may be
|
||||||
and assigns them to the elements, so they can be edited without affecting any other elements.
|
limited by the query) and assigns them to the elements, so they can be
|
||||||
|
edited without affecting any other elements.
|
||||||
|
|
||||||
:param query: A query to select the subset of IFC elements, optional.
|
:param query: A query to select the subset of IFC elements, optional.
|
||||||
If not provided, patch will be applied to all shared property sets in the model.
|
If not provided, patch will be applied to all shared property sets in the model.
|
||||||
@@ -51,7 +55,6 @@ class Patcher:
|
|||||||
# Unshare psets on all IfcWalls.
|
# Unshare psets on all IfcWalls.
|
||||||
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "UnsharePsets", "arguments": ["IfcWall"]})
|
ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "UnsharePsets", "arguments": ["IfcWall"]})
|
||||||
"""
|
"""
|
||||||
self.src = src
|
|
||||||
self.file = file
|
self.file = file
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.query = query
|
self.query = query
|
||||||
|
|||||||
Reference in New Issue
Block a user