diff --git a/src/ifcopenshell-python/docs/ifcpatch.rst b/src/ifcopenshell-python/docs/ifcpatch.rst
index 7407c2c3ab..171e2ed063 100644
--- a/src/ifcopenshell-python/docs/ifcpatch.rst
+++ b/src/ifcopenshell-python/docs/ifcpatch.rst
@@ -57,10 +57,8 @@ Here is a minimal example of how to use IfcDiff as a library:
import ifcpatch
ifcpatch.execute({
- "input": "input.ifc",
- "output": "output.ifc",
+ "input": ifcopenshell.open("input.ifc"),
"recipe": "ExtractElements",
- "log": "ifcpatch.log",
"arguments": [".IfcWall"],
})
diff --git a/src/ifcpatch/ifcpatch/__init__.py b/src/ifcpatch/ifcpatch/__init__.py
index 74f38c36dd..7b163f6c42 100644
--- a/src/ifcpatch/ifcpatch/__init__.py
+++ b/src/ifcpatch/ifcpatch/__init__.py
@@ -18,8 +18,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcPatch. If not, see .
-# This can be packaged into one executable with ./make.py
-
import ifcopenshell
import logging
import os
@@ -29,39 +27,24 @@ import collections
import importlib
-def execute(args, is_library=None):
- logging.basicConfig(filename=args["log"], filemode="a", level=logging.DEBUG)
+def execute(args):
+ if "log" in args:
+ logging.basicConfig(filename=args["log"], filemode="a", level=logging.DEBUG)
logger = logging.getLogger("IFCPatch")
- print("# Loading IFC file ...")
- ifc_file = ifcopenshell.open(args["input"])
- print("# Loading patch recipe ...")
+ ifc_file = args["input"]
recipes = getattr(__import__("ifcpatch.recipes.{}".format(args["recipe"])), "recipes")
recipe = getattr(recipes, args["recipe"])
if recipe.Patcher.__init__.__doc__ is not None:
patcher = recipe.Patcher(args["input"], ifc_file, logger, *args["arguments"])
else:
patcher = recipe.Patcher(args["input"], ifc_file, logger, args["arguments"])
- print("# Patching ...")
patcher.patch()
- ifc_file = getattr(patcher, "file_patched", patcher.file)
- if is_library is True:
- return ifc_file
- print("# Writing patched file ...")
- if not args["output"]:
- args["output"] = args["input"]
- if isinstance(ifc_file, str):
- with open(args["output"], "w") as text_file:
- text_file.write(ifc_file)
- else:
- ifc_file.write(args["output"])
- print("# All tasks are complete :-)")
+ return getattr(patcher, "file_patched", patcher.file)
def extract_docs(
- submodule_name: str,
- cls_name: str,
- method_name: str="__init__",
- boilerplate_args : typing.Iterable[str]=None):
+ submodule_name: str, cls_name: str, method_name: str = "__init__", boilerplate_args: typing.Iterable[str] = None
+):
"""Extract class docstrings and method arguments
:param submodule_name: Submodule from which to extract the class
@@ -70,8 +53,8 @@ def extract_docs(
:param boilerplate_args: String iterable containing arguments that shall not be parsed
"""
spec = importlib.util.spec_from_file_location(
- submodule_name,
- f"{os.path.dirname(inspect.getabsfile(inspect.currentframe()))}/recipes/{submodule_name}.py")
+ submodule_name, f"{os.path.dirname(inspect.getabsfile(inspect.currentframe()))}/recipes/{submodule_name}.py"
+ )
submodule = importlib.util.module_from_spec(spec)
try:
spec.loader.exec_module(submodule)
@@ -101,7 +84,7 @@ def _extract_docs(cls, method_name, boilerplate_args):
type_hints = typing.get_type_hints(method)
for input_name in inputs.keys():
type_hint = type_hints.get(input_name, None)
- if type_hint is None: # The argument is not type-hinted. (Or hinted to None ??)
+ if type_hint is None: # The argument is not type-hinted. (Or hinted to None ??)
continue
if isinstance(type_hint, typing._UnionGenericAlias):
inputs[input_name]["type"] = [t.__name__ for t in typing.get_args(type_hint)]
@@ -125,7 +108,7 @@ def _extract_docs(cls, method_name, boilerplate_args):
description += line
elif i > 2:
description += "\n" + line
-
+
docs["description"] = description.strip()
docs["inputs"] = inputs
return docs
diff --git a/src/ifcpatch/ifcpatch/__main__.py b/src/ifcpatch/ifcpatch/__main__.py
index 115326b2c0..c95a05ed8f 100644
--- a/src/ifcpatch/ifcpatch/__main__.py
+++ b/src/ifcpatch/ifcpatch/__main__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# IfcPatch - IFC patching utiliy
-# Copyright (C) 2020, 2021 Dion Moult
+# Copyright (C) 2020, 2021, 2022 Dion Moult
#
# This file is part of IfcPatch.
#
@@ -20,6 +20,7 @@
import argparse
import ifcpatch
+import ifcopenshell
parser = argparse.ArgumentParser(description="Patches IFC files to fix badly formatted data")
parser.add_argument("-i", "--input", type=str, required=True, help="The IFC file to patch")
@@ -28,4 +29,20 @@ parser.add_argument("-r", "--recipe", type=str, required=True, help="Name of the
parser.add_argument("-l", "--log", type=str, help="Specify a log file", default="ifcpatch.log")
parser.add_argument("-a", "--arguments", nargs="+", help="Specify custom arguments to the patch recipe")
args = vars(parser.parse_args())
-ifcpatch.execute(args)
+
+print("# Loading IFC file ...")
+args["input"] = ifcopenshell.open(args["input"])
+
+print("# Patching ...")
+ifc_file = ifcpatch.execute(args)
+
+print("# Writing patched file ...")
+if not args["output"]:
+ args["output"] = args["input"]
+if isinstance(ifc_file, str):
+ with open(args["output"], "w") as text_file:
+ text_file.write(ifc_file)
+else:
+ ifc_file.write(args["output"])
+
+print("# All tasks are complete :-)")
diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py
index 11151fdd22..9192e977c7 100644
--- a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py
+++ b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -37,13 +36,13 @@ class Patcher:
if self.file.schema == "IFC2X3":
user = self.file_patched.add(self.file.by_type("IfcProject")[0].OwnerHistory.OwningUser)
old_get_user = ifcopenshell.api.owner.settings.get_user
- ifcopenshell.api.owner.settings.get_user = lambda ifc : user
+ ifcopenshell.api.owner.settings.get_user = lambda ifc: user
project = ifcopenshell.api.run("root.create_entity", self.file_patched, ifc_class="IfcProject")
unit_assignment = ifcopenshell.api.run("unit.assign_unit", self.file_patched, **{"length": unit})
# Is there a better way?
for element in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
- element.Precision = 1E-8
+ element.Precision = 1e-8
# If we don't add openings first, they don't get converted
for element in self.file.by_type("IfcOpeningElement"):
diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py b/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py
index 102639ef46..36db19f82b 100644
--- a/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py
+++ b/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
diff --git a/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py b/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py
index ac358347e2..ea10b67ce2 100644
--- a/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py
+++ b/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
diff --git a/src/ifcpatch/ifcpatch/recipes/Fix12DToRevitTINs.py b/src/ifcpatch/ifcpatch/recipes/Fix12DToRevitTINs.py
index f4b88c8b9b..0126ece36a 100644
--- a/src/ifcpatch/ifcpatch/recipes/Fix12DToRevitTINs.py
+++ b/src/ifcpatch/ifcpatch/recipes/Fix12DToRevitTINs.py
@@ -44,13 +44,13 @@ class Patcher:
bm = bmesh.new()
bm.from_mesh(data)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.01)
- bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method='BEAUTY', ngon_method='BEAUTY')
+ bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method="BEAUTY", ngon_method="BEAUTY")
bm.faces.ensure_lookup_table()
for polygon in bm.faces:
v1, v2, v3 = [v.co.to_2d() for v in polygon.verts]
- d1 = degrees((v2-v1).angle(v3-v1))
- d2 = degrees((v3-v2).angle(v1-v2))
- d3 = degrees((v1-v3).angle(v2-v3))
+ d1 = degrees((v2 - v1).angle(v3 - v1))
+ d2 = degrees((v3 - v2).angle(v1 - v2))
+ d3 = degrees((v1 - v3).angle(v2 - v3))
if d1 < angle_threshold or d2 < angle_threshold or d3 < angle_threshold:
bm.faces.remove(polygon)
bm.to_mesh(data)
diff --git a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py
index 8f1c941198..7a509a2862 100644
--- a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py
+++ b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py
@@ -45,7 +45,7 @@ class Patcher:
#
# See bug https://github.com/Autodesk/revit-ifc/issues/187
- #for context in self.file.by_type("IfcGeometricRepresentationSubContext"):
+ # for context in self.file.by_type("IfcGeometricRepresentationSubContext"):
# if context.ContextIdentifier == "FootPrint":
# context.ContextIdentifier = None
# context.ContextType = "Annotation"
diff --git a/src/ifcpatch/ifcpatch/recipes/MergeProject.py b/src/ifcpatch/ifcpatch/recipes/MergeProject.py
index c413ce013b..819791b635 100644
--- a/src/ifcpatch/ifcpatch/recipes/MergeProject.py
+++ b/src/ifcpatch/ifcpatch/recipes/MergeProject.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -20,6 +19,7 @@
import ifcopenshell
import ifcopenshell.util.element
+
class Patcher:
def __init__(self, src, file, logger, args=None):
self.src = src
@@ -29,9 +29,9 @@ class Patcher:
def patch(self):
source = ifcopenshell.open(self.args[0])
- original_project = self.file.by_type('IfcProject')[0]
- merged_project = self.file.add(source.by_type('IfcProject')[0])
- for element in source.by_type('IfcRoot'):
+ original_project = self.file.by_type("IfcProject")[0]
+ merged_project = self.file.add(source.by_type("IfcProject")[0])
+ for element in source.by_type("IfcRoot"):
self.file.add(element)
for inverse in self.file.get_inverse(merged_project):
ifcopenshell.util.element.replace_attribute(inverse, merged_project, original_project)
diff --git a/src/ifcpatch/ifcpatch/recipes/Migrate.py b/src/ifcpatch/ifcpatch/recipes/Migrate.py
index bc31388e2b..e94652b567 100644
--- a/src/ifcpatch/ifcpatch/recipes/Migrate.py
+++ b/src/ifcpatch/ifcpatch/recipes/Migrate.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
diff --git a/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py b/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py
index 79a35fb66d..a92389732e 100644
--- a/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py
+++ b/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -25,11 +25,11 @@ class Patcher:
self.args = args
def patch(self):
- project = self.file.by_type('IfcProject')[0]
- storeys = self.find_decomposed_ifc_class(project, 'IfcBuildingStorey')
+ project = self.file.by_type("IfcProject")[0]
+ storeys = self.find_decomposed_ifc_class(project, "IfcBuildingStorey")
for storey in storeys:
co = storey.ObjectPlacement.RelativePlacement.Location.Coordinates
- storey.ObjectPlacement.RelativePlacement.Location.Coordinates = (co[0], co[1], co[2]+float(self.args[0]))
+ storey.ObjectPlacement.RelativePlacement.Location.Coordinates = (co[0], co[1], co[2] + float(self.args[0]))
co = storey.ObjectPlacement.RelativePlacement.Location.Coordinates
# NOTE If the geometric data is provided (ObjectPlacement is
# specified), the Elevation value shall either not be included, or
diff --git a/src/ifcpatch/ifcpatch/recipes/Optimise.py b/src/ifcpatch/ifcpatch/recipes/Optimise.py
index 99272ee1af..f85f585c12 100644
--- a/src/ifcpatch/ifcpatch/recipes/Optimise.py
+++ b/src/ifcpatch/ifcpatch/recipes/Optimise.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -22,7 +21,6 @@ import ifcopenshell.util.element
from toposort import toposort_flatten as toposort
-
class Patcher:
def __init__(self, src, file, logger, args=None):
self.src = src
@@ -31,24 +29,22 @@ class Patcher:
self.args = args
self.optimized_file = ifcopenshell.file(schema=self.file.schema)
-
def patch(self):
def generate_instances_and_references():
"""
- Generator which yields an entity id and
- the set of all of its references contained in its attributes.
+ Generator which yields an entity id and
+ the set of all of its references contained in its attributes.
"""
for inst in self.file:
yield inst.id(), set(i.id() for i in self.file.traverse(inst)[1:] if i.id())
instance_mapping = {}
-
def map_value(v):
"""
- Recursive function which replicates an entity instance, with
+ Recursive function which replicates an entity instance, with
its attributes, mapping references to already registered
- instances. Indeed, because of the toposort we know that
+ instances. Indeed, because of the toposort we know that
forward attribute value instances are mapped before the instances
that reference them.
"""
@@ -59,15 +55,14 @@ class Patcher:
if v.id() == 0:
# express simple types are not part of the toposort and just copied
return self.optimized_file.create_entity(v.is_a(), v[0])
-
-
+
return instance_mapping[v]
else:
# a plain python value can just be returned
return v
info_to_id = {}
-
+
for id in toposort(dict(generate_instances_and_references())):
inst = self.file[id]
info = inst.get_info(include_identifier=False, recursive=True, return_type=frozenset)
@@ -76,10 +71,6 @@ class Patcher:
else:
info_to_id[info] = id
- instance_mapping[inst] = self.optimized_file.create_entity(
- inst.is_a(),
- *map(map_value, inst)
- )
+ instance_mapping[inst] = self.optimized_file.create_entity(inst.is_a(), *map(map_value, inst))
self.file = self.optimized_file
-
\ No newline at end of file
diff --git a/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py b/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py
index ac3160837f..cba3482c5d 100644
--- a/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py
+++ b/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -20,6 +19,7 @@
from collections import deque
import ifcopenshell.util.element
+
class Patcher:
def __init__(self, src, file, logger, args=None):
self.src = src
@@ -31,7 +31,7 @@ class Patcher:
deleted = []
hashes = {}
for element in self.file:
- if element.is_a('IfcRoot'):
+ if element.is_a("IfcRoot"):
continue
h = hash(tuple(element))
if h in hashes:
@@ -42,13 +42,13 @@ class Patcher:
hashes[h] = element
deleted.sort()
deleted_q = deque(deleted)
- new = ''
- for line in self.file.wrapped_data.to_string().split('\n'):
+ new = ""
+ for line in self.file.wrapped_data.to_string().split("\n"):
try:
- if int(line.split('=')[0][1:]) != deleted_q[0]:
- new += (line + '\n')
+ if int(line.split("=")[0][1:]) != deleted_q[0]:
+ new += line + "\n"
else:
deleted_q.popleft()
except:
- new += (line + '\n')
+ new += line + "\n"
self.file = new
diff --git a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py
index a921a08dbf..85f09bb557 100644
--- a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py
+++ b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
diff --git a/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py b/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py
index 6498fe135a..356673e904 100644
--- a/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py
+++ b/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -25,8 +25,8 @@ class Patcher:
self.args = args
def patch(self):
- project = self.file.by_type('IfcProject')[0]
- sites = self.find_decomposed_ifc_class(project, 'IfcSite')
+ project = self.file.by_type("IfcProject")[0]
+ sites = self.find_decomposed_ifc_class(project, "IfcSite")
for site in sites:
site.Representation = None
diff --git a/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py b/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py
index 9cb10cdf65..58c5462438 100644
--- a/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py
+++ b/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -26,8 +26,8 @@ class Patcher:
def patch(self):
placement_coord_ids = set()
- for placement in self.file.by_type('IfcObjectPlacement'):
- [placement_coord_ids.add(e.id()) for e in self.file.traverse(placement) if e.is_a('IfcCartesianPoint')]
+ for placement in self.file.by_type("IfcObjectPlacement"):
+ [placement_coord_ids.add(e.id()) for e in self.file.traverse(placement) if e.is_a("IfcCartesianPoint")]
# Arbitrary threshold based on experience
self.threshold = 1000000
@@ -42,9 +42,9 @@ class Patcher:
# the case, but is very fast to run, and works for most cases.
offset_point = None
if self.args and len(self.args) >= 3:
- offset_point = (float(self.args[0]),float(self.args[1]),float(self.args[2]))
+ offset_point = (float(self.args[0]), float(self.args[1]), float(self.args[2]))
try:
- point_lists = self.file.by_type('IfcCartesianPointList3D')
+ point_lists = self.file.by_type("IfcCartesianPointList3D")
except:
# IFC2X3 does not have IfcCartesianPointList3D
point_lists = []
@@ -56,33 +56,29 @@ class Patcher:
continue
if not offset_point:
offset_point = (-point[0], -point[1], -point[2])
- self.logger.info(f'Resetting absolute coordinates by {point}')
- point = (
- point[0] + offset_point[0],
- point[1] + offset_point[1],
- point[2] + offset_point[2]
- )
+ self.logger.info(f"Resetting absolute coordinates by {point}")
+ point = (point[0] + offset_point[0], point[1] + offset_point[1], point[2] + offset_point[2])
coord_list[i] = point
point_list.CoordList = coord_list
- for point in self.file.by_type('IfcCartesianPoint'):
+ for point in self.file.by_type("IfcCartesianPoint"):
if len(point.Coordinates) == 2 or not self.is_point_far_away(point):
continue
if point.id() in placement_coord_ids:
continue
if not offset_point:
offset_point = (-point.Coordinates[0], -point.Coordinates[1], -point.Coordinates[2])
- self.logger.info(f'Resetting absolute coordinates by {point}')
+ self.logger.info(f"Resetting absolute coordinates by {point}")
point.Coordinates = (
point.Coordinates[0] + offset_point[0],
point.Coordinates[1] + offset_point[1],
- point.Coordinates[2] + offset_point[2]
+ point.Coordinates[2] + offset_point[2],
)
def is_point_far_away(self, point):
- if hasattr(point, 'Coordinates'):
- return abs(point.Coordinates[0]) > self.threshold \
- or abs(point.Coordinates[1]) > self.threshold \
+ if hasattr(point, "Coordinates"):
+ return (
+ abs(point.Coordinates[0]) > self.threshold
+ or abs(point.Coordinates[1]) > self.threshold
or abs(point.Coordinates[2]) > self.threshold
- return abs(point[0]) > self.threshold \
- or abs(point[1]) > self.threshold \
- or abs(point[2]) > self.threshold
+ )
+ return abs(point[0]) > self.threshold or abs(point[1]) > self.threshold or abs(point[2]) > self.threshold
diff --git a/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py b/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py
index 2747e785c7..680a9fa3f6 100644
--- a/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py
+++ b/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -25,7 +25,7 @@ class Patcher:
self.args = args
def patch(self):
- project = self.file.by_type('IfcProject')[0]
+ project = self.file.by_type("IfcProject")[0]
spatial_elements = self.find_decomposed_ifc_class(project, self.args[0])
for spatial_element in spatial_elements:
self.patch_placement_to_origin(spatial_element)
@@ -43,8 +43,8 @@ class Patcher:
return results
def patch_placement_to_origin(self, element):
- element.ObjectPlacement.RelativePlacement.Location.Coordinates = (0., 0., 0.)
+ element.ObjectPlacement.RelativePlacement.Location.Coordinates = (0.0, 0.0, 0.0)
if element.ObjectPlacement.RelativePlacement.Axis:
- element.ObjectPlacement.RelativePlacement.Axis.DirectionRatios = (0., 0., 1.)
+ element.ObjectPlacement.RelativePlacement.Axis.DirectionRatios = (0.0, 0.0, 1.0)
if element.ObjectPlacement.RelativePlacement.RefDirection:
- element.ObjectPlacement.RelativePlacement.RefDirection.DirectionRatios = (1., 0., 0.)
+ element.ObjectPlacement.RelativePlacement.RefDirection.DirectionRatios = (1.0, 0.0, 0.0)
diff --git a/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py b/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py
index 0f330b64f7..a7b555279e 100644
--- a/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py
+++ b/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -25,8 +25,8 @@ class Patcher:
self.args = args
def patch(self):
- project = self.file.by_type('IfcProject')[0]
- sites = self.find_decomposed_ifc_class(project, 'IfcSite')
+ project = self.file.by_type("IfcProject")[0]
+ sites = self.find_decomposed_ifc_class(project, "IfcSite")
for site in sites:
site.RefElevation = float(self.args[0])
diff --git a/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py b/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py
index f4346fa806..5b6af064be 100644
--- a/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py
+++ b/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -17,6 +16,7 @@
# 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, args=None):
self.src = src
@@ -27,35 +27,39 @@ class Patcher:
def patch(self):
import ifcopenshell
from shutil import copyfile
- storeys = self.file.by_type('IfcBuildingStorey')
+
+ storeys = self.file.by_type("IfcBuildingStorey")
for i, storey in enumerate(storeys):
- dest = '{}-{}.ifc'.format(i, storey.Name)
+ dest = "{}-{}.ifc".format(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')
+ 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')
+ 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):
+ 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]
+ 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'):
+ 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') \
+ return (
+ element.ContainedInStructure
+ and element.ContainedInStructure[0].RelatingStructure.is_a("IfcBuildingStorey")
and element.ContainedInStructure[0].RelatingStructure.GlobalId == storey.GlobalId
+ )
diff --git a/src/ifcpatch/ifcpatch/recipes/__init__.py b/src/ifcpatch/ifcpatch/recipes/__init__.py
index e38f65e07e..f703e25969 100644
--- a/src/ifcpatch/ifcpatch/recipes/__init__.py
+++ b/src/ifcpatch/ifcpatch/recipes/__init__.py
@@ -1,4 +1,3 @@
-
# IfcPatch - IFC patching utiliy
# Copyright (C) 2020, 2021 Dion Moult
#
@@ -16,4 +15,3 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcPatch. If not, see .
-
diff --git a/src/ifcpatch/make.py b/src/ifcpatch/make.py
index 21de52de8e..de689038df 100644
--- a/src/ifcpatch/make.py
+++ b/src/ifcpatch/make.py
@@ -23,4 +23,3 @@ import subprocess
cmd = f'pyinstaller ./bootstrap.py --name ifcpatch --onefile --clean --add-data "ifcpatch{os.pathsep}ifcpatch"'
subprocess.check_output(cmd, shell=True)
-