mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Run black on IOS-Python
This commit is contained in:
@@ -74,7 +74,5 @@ def add_cost_item(
|
||||
},
|
||||
)
|
||||
elif settings["cost_item"]:
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file, related_objects=[cost_item], relating_object=settings["cost_item"]
|
||||
)
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[cost_item], relating_object=settings["cost_item"])
|
||||
return cost_item
|
||||
|
||||
@@ -26,6 +26,7 @@ geometry extrusions).
|
||||
from .. import wrap_usecases
|
||||
from .add_axis_representation import add_axis_representation
|
||||
from .add_boolean import add_boolean
|
||||
|
||||
try:
|
||||
from .add_door_representation import add_door_representation
|
||||
except ModuleNotFoundError as e:
|
||||
@@ -33,6 +34,7 @@ except ModuleNotFoundError as e:
|
||||
from .add_footprint_representation import add_footprint_representation
|
||||
from .add_mesh_representation import add_mesh_representation
|
||||
from .add_profile_representation import add_profile_representation
|
||||
|
||||
try:
|
||||
from .add_railing_representation import add_railing_representation
|
||||
except ModuleNotFoundError as e:
|
||||
@@ -44,6 +46,7 @@ except ModuleNotFoundError as e:
|
||||
print(f"Note: API not available due to missing dependencies: geometry.add_representation - {e}")
|
||||
from .add_slab_representation import add_slab_representation
|
||||
from .add_wall_representation import add_wall_representation
|
||||
|
||||
try:
|
||||
from .add_window_representation import add_window_representation
|
||||
except ModuleNotFoundError as e:
|
||||
|
||||
@@ -857,13 +857,19 @@ class Usecase:
|
||||
z = self.convert_si_to_unit(z)
|
||||
return self.file.createIfcCartesianPoint((x, y, z))
|
||||
|
||||
def create_cartesian_point_list_from_vertices(self, vertices: list[bpy.types.MeshVertex], is_2d=False, is_model_coords=True):
|
||||
def create_cartesian_point_list_from_vertices(
|
||||
self, vertices: list[bpy.types.MeshVertex], is_2d=False, is_model_coords=True
|
||||
):
|
||||
if is_model_coords and self.settings["coordinate_offset"]:
|
||||
if is_2d:
|
||||
xy_offset = Vector((self.settings["coordinate_offset"][0:2]))
|
||||
return self.file.createIfcCartesianPointList2D([self.convert_si_to_unit(v.co.xy + xy_offset) for v in vertices])
|
||||
return self.file.createIfcCartesianPointList2D(
|
||||
[self.convert_si_to_unit(v.co.xy + xy_offset) for v in vertices]
|
||||
)
|
||||
xyz_offset = Vector((self.settings["coordinate_offset"][0:3]))
|
||||
return self.file.createIfcCartesianPointList3D([self.convert_si_to_unit(v.co.xyz + xyz_offset) for v in vertices])
|
||||
return self.file.createIfcCartesianPointList3D(
|
||||
[self.convert_si_to_unit(v.co.xyz + xyz_offset) for v in vertices]
|
||||
)
|
||||
if is_2d:
|
||||
return self.file.createIfcCartesianPointList2D([self.convert_si_to_unit(v.co.xy) for v in vertices])
|
||||
return self.file.createIfcCartesianPointList3D([self.convert_si_to_unit(v.co) for v in vertices])
|
||||
|
||||
@@ -57,7 +57,7 @@ def edit_true_north(file: ifcopenshell.file, true_north: Optional[Union[tuple[fl
|
||||
|
||||
for context in file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
if context.TrueNorth and true_north is None:
|
||||
old_true_north = context.TrueNorth
|
||||
old_true_north = context.TrueNorth
|
||||
context.TrueNorth = None
|
||||
if not file.get_total_inverses(old_true_north):
|
||||
ifcopenshell.util.element.remove_deep2(file, old_true_north)
|
||||
|
||||
@@ -22,6 +22,7 @@ A grid in IFC may contain two or more axes running in two or more directions.
|
||||
"""
|
||||
|
||||
from .. import wrap_usecases
|
||||
|
||||
try:
|
||||
from .create_axis_curve import create_axis_curve
|
||||
except ModuleNotFoundError as e:
|
||||
|
||||
@@ -20,7 +20,10 @@ from typing import Optional
|
||||
|
||||
|
||||
def add_material(
|
||||
file: ifcopenshell.file, name: Optional[str] = None, category: Optional[str] = None, description: Optional[str] = None
|
||||
file: ifcopenshell.file,
|
||||
name: Optional[str] = None,
|
||||
category: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new material
|
||||
|
||||
@@ -50,8 +53,8 @@ def add_material(
|
||||
Note that categories are not available in IFC2X3. This shortcoming is
|
||||
one of the big reasons projects should upgrade to IFC4.
|
||||
|
||||
Additionally, a material's description provides more information beyond
|
||||
its name or category.
|
||||
Additionally, a material's description provides more information beyond
|
||||
its name or category.
|
||||
|
||||
:param name: The name of the material, typically tagged in a finishes
|
||||
drawing or schedule.
|
||||
@@ -78,7 +81,7 @@ def add_material(
|
||||
# "Style" has been specified.
|
||||
ifcopenshell.api.material.assign_material(model, products=[concrete_bench], material=concrete)
|
||||
"""
|
||||
settings = {"name": name or "Unnamed", "category": category, "description": description }
|
||||
settings = {"name": name or "Unnamed", "category": category, "description": description}
|
||||
|
||||
material = file.create_entity("IfcMaterial", **{"Name": settings["name"] or "Unnamed"})
|
||||
if settings["category"]:
|
||||
|
||||
@@ -97,6 +97,7 @@ def assign_profile(
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self) -> None:
|
||||
# TODO: handle composite profiles
|
||||
old_profile = self.settings["material_profile"].Profile
|
||||
|
||||
@@ -19,7 +19,9 @@ import ifcopenshell
|
||||
from typing import Any
|
||||
|
||||
|
||||
def edit_assigned_material(file: ifcopenshell.file, element: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
def edit_assigned_material(
|
||||
file: ifcopenshell.file, element: ifcopenshell.entity_instance, attributes: dict[str, Any]
|
||||
) -> None:
|
||||
"""Edits the attributes of an IfcMaterial
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
def add_role(file: ifcopenshell.file, assigned_object: ifcopenshell.entity_instance, role: str = "ARCHITECT") -> ifcopenshell.entity_instance:
|
||||
def add_role(
|
||||
file: ifcopenshell.file, assigned_object: ifcopenshell.entity_instance, role: str = "ARCHITECT"
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds and assigns a new role
|
||||
|
||||
People and organisations must play one or more roles on a project. Roles
|
||||
|
||||
@@ -19,7 +19,9 @@ import ifcopenshell
|
||||
from typing import Any
|
||||
|
||||
|
||||
def edit_organisation(file: ifcopenshell.file, organisation: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
def edit_organisation(
|
||||
file: ifcopenshell.file, organisation: ifcopenshell.entity_instance, attributes: dict[str, Any]
|
||||
) -> None:
|
||||
"""Edits the attributes of an IfcOrganization
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
|
||||
@@ -95,7 +95,7 @@ def add_pset(file: ifcopenshell.file, product: ifcopenshell.entity_instance, nam
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"Name": settings["name"],
|
||||
}
|
||||
},
|
||||
)
|
||||
file.create_entity(
|
||||
"IfcRelDefinesByProperties",
|
||||
@@ -104,7 +104,7 @@ def add_pset(file: ifcopenshell.file, product: ifcopenshell.entity_instance, nam
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"RelatedObjects": [settings["product"]],
|
||||
"RelatingPropertyDefinition": pset,
|
||||
}
|
||||
},
|
||||
)
|
||||
return pset
|
||||
elif settings["product"].is_a("IfcTypeObject"):
|
||||
@@ -118,7 +118,7 @@ def add_pset(file: ifcopenshell.file, product: ifcopenshell.entity_instance, nam
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"Name": settings["name"],
|
||||
}
|
||||
},
|
||||
)
|
||||
has_property_sets = list(settings["product"].HasPropertySets or [])
|
||||
has_property_sets.append(pset)
|
||||
@@ -142,7 +142,7 @@ def add_pset(file: ifcopenshell.file, product: ifcopenshell.entity_instance, nam
|
||||
**{
|
||||
"Name": settings["name"],
|
||||
"Material": settings["product"],
|
||||
}
|
||||
},
|
||||
)
|
||||
elif settings["product"].is_a("IfcProfileDef"):
|
||||
# in IFC2X3 IfcProfileProperties doesn't have Name and we cannot identify them
|
||||
|
||||
@@ -50,7 +50,9 @@ def edit_prop_template(
|
||||
if enum_values := attributes.get("Enumerators", None):
|
||||
prop_name = attributes.get("Name", None) or getattr(prop_template, "Name", None) or "Unnamed"
|
||||
primary_measure_type = (
|
||||
attributes.get("PrimaryMeasureType", None) or getattr(prop_template, "PrimaryMeasureType", None) or "IfcLabel"
|
||||
attributes.get("PrimaryMeasureType", None)
|
||||
or getattr(prop_template, "PrimaryMeasureType", None)
|
||||
or "IfcLabel"
|
||||
)
|
||||
enum_values = [file.create_entity(primary_measure_type, v) for v in enum_values]
|
||||
if enumerators := prop_template.Enumerators:
|
||||
|
||||
@@ -38,10 +38,7 @@ def add_structural_load_case(
|
||||
"""
|
||||
|
||||
load_case = ifcopenshell.api.root.create_entity(
|
||||
file,
|
||||
ifc_class="IfcStructuralLoadCase",
|
||||
predefined_type="LOAD_CASE",
|
||||
name=name
|
||||
file, ifc_class="IfcStructuralLoadCase", predefined_type="LOAD_CASE", name=name
|
||||
)
|
||||
load_case.ActionType = action_type
|
||||
load_case.ActionSource = action_source
|
||||
|
||||
@@ -83,11 +83,15 @@ def register_schema_attributes(schema: ifcopenshell_wrapper.schema_definition) -
|
||||
|
||||
# resolve to actual functions in wrapper
|
||||
functions = [
|
||||
set_derived_attribute
|
||||
if mname == "setArgumentAsDerived"
|
||||
else set_unsupported_attribute
|
||||
if mname == "setArgumentAsUnknown"
|
||||
else getattr(ifcopenshell_wrapper.entity_instance, mname)
|
||||
(
|
||||
set_derived_attribute
|
||||
if mname == "setArgumentAsDerived"
|
||||
else (
|
||||
set_unsupported_attribute
|
||||
if mname == "setArgumentAsUnknown"
|
||||
else getattr(ifcopenshell_wrapper.entity_instance, mname)
|
||||
)
|
||||
)
|
||||
for mname in fn_names
|
||||
]
|
||||
|
||||
@@ -203,15 +207,20 @@ class entity_instance:
|
||||
rules = importlib.import_module(f"ifcopenshell.express.rules.{schema_name}")
|
||||
except:
|
||||
import os
|
||||
current_dir_files = {fn.lower(): fn for fn in os.listdir('.')}
|
||||
exp_filename = schema_name.lower() + '.exp'
|
||||
|
||||
current_dir_files = {fn.lower(): fn for fn in os.listdir(".")}
|
||||
exp_filename = schema_name.lower() + ".exp"
|
||||
schema_path = current_dir_files.get(exp_filename)
|
||||
if schema_path is None:
|
||||
raise Exception(f"Couldn't find express file '{schema_name.lower()}.exp' in the current folder: '{os.getcwd()}'.")
|
||||
fn = schema_path[:-4] + '.py'
|
||||
raise Exception(
|
||||
f"Couldn't find express file '{schema_name.lower()}.exp' in the current folder: '{os.getcwd()}'."
|
||||
)
|
||||
fn = schema_path[:-4] + ".py"
|
||||
if not os.path.exists(fn):
|
||||
subprocess.run([sys.executable, "-m", "ifcopenshell.express.rule_compiler", schema_path, fn], check=True)
|
||||
time.sleep(1.)
|
||||
subprocess.run(
|
||||
[sys.executable, "-m", "ifcopenshell.express.rule_compiler", schema_path, fn], check=True
|
||||
)
|
||||
time.sleep(1.0)
|
||||
rules = importlib.import_module(schema_name)
|
||||
|
||||
def yield_supertypes():
|
||||
@@ -255,7 +264,7 @@ class entity_instance:
|
||||
# Define condition and transformation functions
|
||||
condition = lambda v: v == old
|
||||
transform = lambda v: new
|
||||
|
||||
|
||||
# Usage example
|
||||
attribute_value = element.RelatedElements
|
||||
print(old in attribute_value, new in attribute_value) # True, False
|
||||
|
||||
@@ -204,7 +204,6 @@ class application(QtWidgets.QApplication):
|
||||
with two tree views and a graphical 3d view"""
|
||||
|
||||
class abstract_treeview(QtWidgets.QTreeWidget):
|
||||
|
||||
"""Base class for the two treeview controls"""
|
||||
|
||||
instanceSelected = QtCore.pyqtSignal([object])
|
||||
@@ -255,7 +254,6 @@ class application(QtWidgets.QApplication):
|
||||
)
|
||||
|
||||
class decomposition_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ["Entity", "GlobalId", "Name"]
|
||||
@@ -301,7 +299,6 @@ class application(QtWidgets.QApplication):
|
||||
self.expandAll()
|
||||
|
||||
class type_treeview(abstract_treeview):
|
||||
|
||||
"""Treeview with typical IFC decomposition relationships"""
|
||||
|
||||
ATTRIBUTES = ["Name"]
|
||||
|
||||
@@ -37,7 +37,7 @@ def compress(g):
|
||||
bs = [int(g[i : i + 2], 16) for i in range(0, len(g), 2)]
|
||||
|
||||
def b64(v, l=4):
|
||||
return "".join([chars[(v // (64 ** i)) % 64] for i in range(l)][::-1])
|
||||
return "".join([chars[(v // (64**i)) % 64] for i in range(l)][::-1])
|
||||
|
||||
return "".join([b64(bs[0], 2)] + [b64((bs[i] << 16) + (bs[i + 1] << 8) + bs[i + 2]) for i in range(1, 16, 3)])
|
||||
|
||||
|
||||
@@ -33,4 +33,4 @@ element or None. Example:
|
||||
#2=IfcRelAssignsToGroup($,$,$,$,$,$,#1)
|
||||
"""
|
||||
|
||||
unpack_non_aggregate_inverses = False
|
||||
unpack_non_aggregate_inverses = False
|
||||
|
||||
@@ -11,19 +11,19 @@ try:
|
||||
class StreamTransformer(Transformer):
|
||||
def string(self, items):
|
||||
return str(items[0])[1:-1]
|
||||
|
||||
|
||||
def float(self, items):
|
||||
return float(items[0])
|
||||
|
||||
|
||||
def ifcint(self, items):
|
||||
return int(items[0])
|
||||
|
||||
|
||||
def null(self, items):
|
||||
return None
|
||||
|
||||
|
||||
def derived(self, items):
|
||||
return None
|
||||
|
||||
|
||||
def enum(self, items):
|
||||
if items[0] == ".T.":
|
||||
return True
|
||||
@@ -32,7 +32,7 @@ try:
|
||||
elif items[0] == ".U.":
|
||||
return "UNKNOWN"
|
||||
return str(items[0])[1:-1]
|
||||
|
||||
|
||||
def list(self, items):
|
||||
# List is always called twice, I think due to an ambiguity in the Lark
|
||||
# definition between a list and an arg, but I'm not quite sure.
|
||||
@@ -40,7 +40,7 @@ try:
|
||||
if items and isinstance(items[0], dict):
|
||||
return tuple(items[0]["list"])
|
||||
return {"list": items}
|
||||
|
||||
|
||||
def inline_type(self, items):
|
||||
# inline_type is also always called twice. Why?
|
||||
if items and isinstance(items[0], dict):
|
||||
@@ -48,20 +48,19 @@ try:
|
||||
entity = ifcopenshell.create_entity(items[0])
|
||||
entity[0] = items[1]
|
||||
return {"inline_type": entity}
|
||||
|
||||
|
||||
def reference(self, items):
|
||||
return self.file.by_id(int(items[0][1:]))
|
||||
|
||||
|
||||
def arg(self, items):
|
||||
return items[0]
|
||||
|
||||
|
||||
def args(self, items):
|
||||
return items
|
||||
|
||||
|
||||
def start(self, items):
|
||||
return (int(items[0]), str(items[1]), items[2])
|
||||
|
||||
|
||||
|
||||
class stream(file):
|
||||
def __init__(self, filepath):
|
||||
self.wrapped_data = None
|
||||
@@ -69,9 +68,9 @@ try:
|
||||
self.history = []
|
||||
self.future = []
|
||||
self.transaction = None
|
||||
|
||||
|
||||
self.filepath = filepath
|
||||
|
||||
|
||||
self.file = open(filepath, "r")
|
||||
self.id_map = {}
|
||||
self.class_map = {}
|
||||
@@ -80,7 +79,7 @@ try:
|
||||
self.reference_pattern = re.compile(r"#(\d+)")
|
||||
self.entity_cache = {}
|
||||
self.inverses = {}
|
||||
|
||||
|
||||
# common.INT doesn't support negative integers.
|
||||
grammar = r"""
|
||||
start: "#" NUMBER "=" TYPE "(" args ")" ";"
|
||||
@@ -114,11 +113,11 @@ try:
|
||||
%import common.INT
|
||||
%import common.CNAME
|
||||
"""
|
||||
|
||||
|
||||
transformer = StreamTransformer()
|
||||
transformer.file = self
|
||||
self.parser = Lark(grammar, parser="lalr", transformer=transformer)
|
||||
|
||||
|
||||
exclude_classes = [
|
||||
"IfcObjectPlacement",
|
||||
"IfcPresentationItem",
|
||||
@@ -128,9 +127,9 @@ try:
|
||||
"IfcRepresentationItem",
|
||||
]
|
||||
exclude_classes = []
|
||||
|
||||
|
||||
exclude = set()
|
||||
|
||||
|
||||
offset = 0
|
||||
for line in self.file:
|
||||
line = line.strip()
|
||||
@@ -138,14 +137,14 @@ try:
|
||||
step_id, ifc_class = line.split("(")[0].split("=")
|
||||
step_id = int(step_id.strip()[1:])
|
||||
ifc_class = ifc_class.strip()
|
||||
|
||||
|
||||
if ifc_class in exclude:
|
||||
offset += len(line) + 1 # +1 for the newline character
|
||||
continue
|
||||
|
||||
|
||||
for reference_id in self.reference_pattern.findall(line[1:]):
|
||||
self.inverses.setdefault(int(reference_id), []).append(step_id)
|
||||
|
||||
|
||||
self.id_map[step_id] = ifc_class
|
||||
self.class_map.setdefault(ifc_class, []).append(step_id)
|
||||
self.id_offset[step_id] = offset
|
||||
@@ -156,9 +155,9 @@ try:
|
||||
declaration = self.ifc_schema.declaration_by_name(ifc_class)
|
||||
exclude.update([st.name().upper() for st in ifcopenshell.util.schema.get_subtypes(declaration)])
|
||||
offset += len(line) + 1 # +1 for the newline character
|
||||
|
||||
|
||||
self.preprocess_schema()
|
||||
|
||||
|
||||
def preprocess_schema(self):
|
||||
self.ifc_class_names = {}
|
||||
self.ifc_class_subtypes = {}
|
||||
@@ -166,32 +165,32 @@ try:
|
||||
self.ifc_class_inverse_attributes = {}
|
||||
self.ifc_class_references = {}
|
||||
self.ifc_class_inverses = {}
|
||||
|
||||
|
||||
for declaration in self.ifc_schema.entities():
|
||||
self.ifc_class_names[declaration.name().upper()] = declaration.name()
|
||||
|
||||
|
||||
self.ifc_class_subtypes[declaration.name()] = ifcopenshell.util.schema.get_subtypes(declaration)
|
||||
self.ifc_class_attributes[declaration.name()] = {a.name(): a for a in declaration.all_attributes()}
|
||||
self.ifc_class_inverse_attributes[declaration.name()] = {
|
||||
a.name(): a for a in declaration.all_inverse_attributes()
|
||||
}
|
||||
|
||||
|
||||
entity = []
|
||||
entity_list = []
|
||||
for attribute in declaration.all_attributes():
|
||||
primitive = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if primitive == "entity":
|
||||
entity.append(attribute.name())
|
||||
|
||||
|
||||
attribute_entity = attribute.type_of_attribute().declared_type()
|
||||
for subtype in ifcopenshell.util.schema.get_subtypes(attribute_entity):
|
||||
self.ifc_class_inverses.setdefault(subtype.name(), {})
|
||||
self.ifc_class_inverses[subtype.name()].setdefault(declaration.name(), [])
|
||||
self.ifc_class_inverses[subtype.name()][declaration.name()].append(attribute.name())
|
||||
|
||||
|
||||
elif self.is_entity_list(attribute):
|
||||
entity_list.append(attribute.name())
|
||||
|
||||
|
||||
for entity_name in re.findall("<entity (.*?)>", str(attribute)):
|
||||
attribute_entity = self.ifc_schema.declaration_by_name(entity_name)
|
||||
for subtype in ifcopenshell.util.schema.get_subtypes(attribute_entity):
|
||||
@@ -199,15 +198,15 @@ try:
|
||||
self.ifc_class_inverses.setdefault(subtype.name(), {})
|
||||
self.ifc_class_inverses[subtype.name()].setdefault(declaration.name(), [])
|
||||
self.ifc_class_inverses[subtype.name()][declaration.name()].append(attribute.name())
|
||||
|
||||
|
||||
self.ifc_class_references[declaration.name()] = {"entity": entity, "entity_list": entity_list}
|
||||
|
||||
|
||||
def clear_cache(self):
|
||||
self.entity_cache = {}
|
||||
|
||||
|
||||
def create_entity(self, type, *args, **kawrgs):
|
||||
assert False
|
||||
|
||||
|
||||
def by_id(self, id):
|
||||
entity = self.entity_cache.get(id, None)
|
||||
if entity:
|
||||
@@ -217,35 +216,35 @@ try:
|
||||
entity = stream_entity(id, self.ifc_class_names[ifc_class], self)
|
||||
self.entity_cache[id] = entity
|
||||
return entity
|
||||
|
||||
|
||||
def by_type(self, type, include_subtypes=True):
|
||||
results = []
|
||||
subtypes = self.ifc_class_subtypes[type] if include_subtypes else self.ifc_class_subtypes[type][0:1]
|
||||
for subtype in subtypes:
|
||||
results.extend([self.by_id(i) for i in self.class_map.get(subtype.name().upper(), [])])
|
||||
return results
|
||||
|
||||
|
||||
def traverse(self, inst, max_levels=None, breadth_first=False):
|
||||
results = [inst]
|
||||
queue = [inst]
|
||||
while queue:
|
||||
if max_levels is not None:
|
||||
max_levels -= 1
|
||||
|
||||
|
||||
cur = queue.pop()
|
||||
level_results = set()
|
||||
|
||||
|
||||
for reference_id in self.reference_pattern.findall(str(cur)[1:]):
|
||||
result = self.by_id(int(reference_id))
|
||||
results.append(result)
|
||||
if max_levels is None or max_levels:
|
||||
queue.append(result)
|
||||
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def get_inverse(self, inst, allow_duplicate=False, with_attribute_indices=False):
|
||||
return {self.by_id(e) for e in self.inverses.get(inst.stream_wrapper.id, [])}
|
||||
|
||||
|
||||
def is_entity_list(self, attribute):
|
||||
attribute = str(attribute.type_of_attribute())
|
||||
if (attribute.startswith("<list") or attribute.startswith("<set")) and "<entity" in attribute:
|
||||
@@ -254,8 +253,7 @@ try:
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
class stream_entity(entity_instance):
|
||||
def __init__(self, id, ifc_class, file=None):
|
||||
if not ifc_class:
|
||||
@@ -265,39 +263,39 @@ try:
|
||||
s = stream_wrapper(id, ifc_class, file)
|
||||
super(entity_instance, self).__setattr__("wrapped_data", e)
|
||||
super(entity_instance, self).__setattr__("stream_wrapper", s)
|
||||
|
||||
|
||||
def id(self):
|
||||
return self.stream_wrapper.id
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
offset = self.stream_wrapper.file.id_offset[self.stream_wrapper.id]
|
||||
self.stream_wrapper.file.file.seek(offset)
|
||||
return self.stream_wrapper.file.file.readline().strip()
|
||||
|
||||
|
||||
def __del__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.__getattr__(list(self.stream_wrapper.attributes.keys())[key])
|
||||
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
query = f"UPDATE `{self.stream_wrapper.ifc_class}` SET `{key}` = ? WHERE ifc_id = {self.stream_wrapper.id}"
|
||||
self.stream_wrapper.file.cursor.execute(query, (value,))
|
||||
self.stream_wrapper.file.db.commit()
|
||||
self.stream_wrapper.attribute_cache = {}
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
INVALID, FORWARD, INVERSE = range(3)
|
||||
attr_cat = self.wrapped_data.get_attribute_category(name)
|
||||
if attr_cat == FORWARD:
|
||||
if self.stream_wrapper.attribute_cache:
|
||||
return self.stream_wrapper.attribute_cache[name]
|
||||
|
||||
|
||||
offset = self.stream_wrapper.file.id_offset[self.stream_wrapper.id]
|
||||
self.stream_wrapper.file.file.seek(offset)
|
||||
line = self.stream_wrapper.file.file.readline()
|
||||
attributes = self.stream_wrapper.file.parser.parse(line.strip())[2]
|
||||
|
||||
|
||||
for i, attribute in enumerate(self.stream_wrapper.attributes.values()):
|
||||
self.stream_wrapper.attribute_cache[attribute.name()] = attributes[i]
|
||||
return self.stream_wrapper.attribute_cache[name]
|
||||
@@ -306,19 +304,19 @@ try:
|
||||
results = self.stream_wrapper.inverse_attribute_cache.get(name, None)
|
||||
if results is not None:
|
||||
return results
|
||||
|
||||
|
||||
results = []
|
||||
|
||||
|
||||
element_ids = self.stream_wrapper.file.inverses.get(self.stream_wrapper.id, [])
|
||||
if not element_ids:
|
||||
self.stream_wrapper.inverse_attribute_cache[name] = tuple()
|
||||
return self.stream_wrapper.inverse_attribute_cache[name]
|
||||
|
||||
|
||||
attribute = self.stream_wrapper.inverse_attributes[name]
|
||||
entity_class = attribute.entity_reference().name()
|
||||
declaration = self.stream_wrapper.file.ifc_schema.declaration_by_name(entity_class)
|
||||
forward_name = attribute.attribute_reference().name()
|
||||
|
||||
|
||||
subtypes = [st.name() for st in ifcopenshell.util.schema.get_subtypes(declaration)]
|
||||
for element_id in element_ids:
|
||||
ifc_class = self.stream_wrapper.file.ifc_class_names[self.stream_wrapper.file.id_map[element_id]]
|
||||
@@ -332,14 +330,14 @@ try:
|
||||
results.append(potential_result)
|
||||
elif forward_value.id() == self.stream_wrapper.id:
|
||||
results.append(potential_result)
|
||||
|
||||
|
||||
self.stream_wrapper.inverse_attribute_cache[name] = tuple(results)
|
||||
return self.stream_wrapper.inverse_attribute_cache[name]
|
||||
|
||||
|
||||
raise AttributeError(
|
||||
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(True), name)
|
||||
)
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(self, type(other)):
|
||||
return False
|
||||
@@ -348,19 +346,18 @@ try:
|
||||
if self.stream_wrapper.id:
|
||||
return self.stream_wrapper.id == other.stream_wrapper.id
|
||||
assert False # not implemented
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
if self.stream_wrapper.id:
|
||||
return hash((self.stream_wrapper.id, self.stream_wrapper.file.filepath))
|
||||
|
||||
|
||||
def get_info(self, include_identifier=True, recursive=False, return_type=dict, ignore=(), scalar_only=False):
|
||||
info = {"id": self.stream_wrapper.id, "type": self.stream_wrapper.ifc_class}
|
||||
if not self.stream_wrapper.attribute_cache:
|
||||
self.__getitem__(0) # This will get all attributes
|
||||
info.update(self.stream_wrapper.attribute_cache)
|
||||
return info
|
||||
|
||||
|
||||
|
||||
class stream_wrapper:
|
||||
def __init__(self, id, ifc_class, file):
|
||||
self.id = id
|
||||
@@ -370,10 +367,11 @@ try:
|
||||
self.inverse_attributes = self.file.ifc_class_inverse_attributes[self.ifc_class]
|
||||
self.attribute_cache = {}
|
||||
self.inverse_attribute_cache = {}
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "todo"
|
||||
|
||||
except ImportError as e:
|
||||
import sys
|
||||
|
||||
print(f"No stream support: {e}", file=sys.stderr)
|
||||
|
||||
@@ -60,14 +60,14 @@ class TransitionCurve:
|
||||
def _calc_biquadratic_parabola_point(self, lpt, L, R, ccw):
|
||||
x = lpt
|
||||
if x <= (L / 2):
|
||||
y = x ** 4 / (6 * R * L ** 2)
|
||||
y = x**4 / (6 * R * L**2)
|
||||
else:
|
||||
|
||||
yterm_1 = (-1 * x ** 4) / (6 * R * L ** 2)
|
||||
yterm_2 = (2 * x ** 3) / (3 * R * L)
|
||||
yterm_3 = x ** 2 / (2 * R)
|
||||
yterm_1 = (-1 * x**4) / (6 * R * L**2)
|
||||
yterm_2 = (2 * x**3) / (3 * R * L)
|
||||
yterm_3 = x**2 / (2 * R)
|
||||
yterm_4 = (L * x) / (6 * R)
|
||||
yterm_5 = L ** 2 / (48 * R)
|
||||
yterm_5 = L**2 / (48 * R)
|
||||
|
||||
y = yterm_1 + yterm_2 - yterm_3 + yterm_4 - yterm_5
|
||||
|
||||
@@ -82,16 +82,16 @@ class TransitionCurve:
|
||||
def _calc_clothoid_curve_point(self, lpt, L, R, ccw):
|
||||
RL = R * L
|
||||
xterm_1 = 1
|
||||
xterm_2 = lpt ** 4 / (40 * RL ** 2)
|
||||
xterm_3 = lpt ** 8 / (3456 * RL ** 4)
|
||||
xterm_4 = lpt ** 12 / (599040 * RL ** 6)
|
||||
xterm_2 = lpt**4 / (40 * RL**2)
|
||||
xterm_3 = lpt**8 / (3456 * RL**4)
|
||||
xterm_4 = lpt**12 / (599040 * RL**6)
|
||||
x = lpt * (xterm_1 - xterm_2 + xterm_3 - xterm_4)
|
||||
|
||||
factor = lpt ** 3 / (6 * RL)
|
||||
factor = lpt**3 / (6 * RL)
|
||||
yterm_1 = 1
|
||||
yterm_2 = lpt ** 4 / (56 * RL ** 2)
|
||||
yterm_3 = lpt ** 8 / (7040 * RL ** 4)
|
||||
yterm_4 = lpt ** 12 / (1612800 * RL ** 6)
|
||||
yterm_2 = lpt**4 / (56 * RL**2)
|
||||
yterm_3 = lpt**8 / (7040 * RL**4)
|
||||
yterm_4 = lpt**12 / (1612800 * RL**6)
|
||||
|
||||
y = factor * (yterm_1 - yterm_2 + yterm_3 - yterm_4)
|
||||
|
||||
@@ -104,9 +104,9 @@ class TransitionCurve:
|
||||
pi = math.pi
|
||||
psi_x = (pi * lpt) / L
|
||||
|
||||
xterm_1 = (L ** 2) / (8.0 * pi ** 2 * R ** 2)
|
||||
xterm_1 = (L**2) / (8.0 * pi**2 * R**2)
|
||||
xterm_2 = L / pi
|
||||
xterm_3 = psi_x ** 3 / (3.0)
|
||||
xterm_3 = psi_x**3 / (3.0)
|
||||
xterm_4 = psi_x / (2.0)
|
||||
xterm_5 = (math.sin(psi_x) * math.cos(psi_x)) / (2.0)
|
||||
xterm_6 = psi_x * math.cos(psi_x)
|
||||
|
||||
@@ -130,6 +130,8 @@ def get_attributes_keep_md(resource, builder):
|
||||
|
||||
# Temporary fix for https://github.com/buildingSMART/IFC4.3.x-development/issues/754.
|
||||
_original_get_resource_path = get_resource_path
|
||||
|
||||
|
||||
def get_resource_path(resource: str, abort_on_error=False) -> Union[str, None]:
|
||||
md = _original_get_resource_path(resource, abort_on_error)
|
||||
if md and resource == "IfcURIReference":
|
||||
|
||||
@@ -74,8 +74,7 @@ def get_calendar(task: ifcopenshell.entity_instance) -> Union[ifcopenshell.entit
|
||||
calendar = [
|
||||
rel.RelatingControl
|
||||
for rel in task.HasAssignments or []
|
||||
if rel.is_a("IfcRelAssignsToControl")
|
||||
and rel.RelatingControl.is_a("IfcWorkCalendar")
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkCalendar")
|
||||
]
|
||||
if calendar:
|
||||
return calendar[0]
|
||||
@@ -88,11 +87,7 @@ def count_working_days(start, finish, calendar: ifcopenshell.entity_instance) ->
|
||||
current_date = datetime.date(start.year, start.month, start.day)
|
||||
finish_date = datetime.date(finish.year, finish.month, finish.day)
|
||||
while current_date <= finish_date:
|
||||
if (
|
||||
calendar
|
||||
and calendar.WorkingTimes
|
||||
and is_working_day(current_date, calendar)
|
||||
):
|
||||
if calendar and calendar.WorkingTimes and is_working_day(current_date, calendar):
|
||||
result += 1
|
||||
elif not calendar or not is_calendar_applicable(current_date, calendar):
|
||||
result += 1
|
||||
@@ -132,9 +127,7 @@ def offset_date(start, duration, duration_type: DURATION_TYPE, calendar: ifcopen
|
||||
abs_duration = abs((duration.days + months * 30 + years * 12 * 30))
|
||||
date_offset = datetime.timedelta(days=1 if duration.days > 0 else -1)
|
||||
while abs_duration > 0:
|
||||
if duration_type == "ELAPSEDTIME" or not is_calendar_applicable(
|
||||
current_date, calendar
|
||||
):
|
||||
if duration_type == "ELAPSEDTIME" or not is_calendar_applicable(current_date, calendar):
|
||||
abs_duration -= 1
|
||||
elif is_working_day(current_date, calendar):
|
||||
abs_duration -= 1
|
||||
@@ -245,16 +238,13 @@ def is_work_time_applicable_to_day(work_time: ifcopenshell.entity_instance, day)
|
||||
return False # TODO
|
||||
elif recurrence_type == "MONTHLY_BY_POSITION":
|
||||
if not recurrence.Interval and not recurrence.Occurrences:
|
||||
return (day.weekday() + 1) in recurrence.WeekdayComponent and floor(
|
||||
day.day / 7
|
||||
) + 1 == recurrence["Position"]
|
||||
return (day.weekday() + 1) in recurrence.WeekdayComponent and floor(day.day / 7) + 1 == recurrence[
|
||||
"Position"
|
||||
]
|
||||
return False # TODO
|
||||
elif recurrence_type == "YEARLY_BY_DAY_OF_MONTH":
|
||||
if not recurrence.Interval and not recurrence.Occurrences:
|
||||
return (
|
||||
day.month in recurrence.MonthComponent
|
||||
and day.day in recurrence.DayComponent
|
||||
)
|
||||
return day.month in recurrence.MonthComponent and day.day in recurrence.DayComponent
|
||||
return False # TODO
|
||||
elif recurrence_type == "YEARLY_BY_POSITION":
|
||||
if not recurrence.Interval and not recurrence.Occurrences:
|
||||
@@ -272,9 +262,7 @@ def get_task_work_schedule(task: ifcopenshell.entity_instance) -> Union[ifcopens
|
||||
return get_task_work_schedule(parent_task) or get_task_work_schedule(task)
|
||||
else:
|
||||
for rel in task.HasAssignments:
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a(
|
||||
"IfcWorkSchedule"
|
||||
):
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
|
||||
return rel.RelatingControl
|
||||
return None
|
||||
|
||||
@@ -304,21 +292,11 @@ def get_work_schedule_tasks(work_schedule: ifcopenshell.entity_instance) -> list
|
||||
|
||||
|
||||
def get_root_tasks(work_schedule: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
return [
|
||||
obj
|
||||
for rel in work_schedule.Controls
|
||||
for obj in rel.RelatedObjects
|
||||
if obj.is_a("IfcTask")
|
||||
]
|
||||
return [obj for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
|
||||
|
||||
|
||||
def get_root_tasks_ids(work_schedule: ifcopenshell.entity_instance) -> list[int]:
|
||||
return [
|
||||
obj.id()
|
||||
for rel in work_schedule.Controls
|
||||
for obj in rel.RelatedObjects
|
||||
if obj.is_a("IfcTask")
|
||||
]
|
||||
return [obj.id() for rel in work_schedule.Controls for obj in rel.RelatedObjects if obj.is_a("IfcTask")]
|
||||
|
||||
|
||||
def guess_date_range(work_schedule: ifcopenshell.entity_instance):
|
||||
@@ -344,22 +322,14 @@ def guess_date_range(work_schedule: ifcopenshell.entity_instance):
|
||||
|
||||
|
||||
def get_direct_task_outputs(task: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
return [
|
||||
rel.RelatingProduct
|
||||
for rel in task.HasAssignments
|
||||
if rel.is_a("IfcRelAssignsToProduct")
|
||||
]
|
||||
return [rel.RelatingProduct for rel in task.HasAssignments if rel.is_a("IfcRelAssignsToProduct")]
|
||||
|
||||
|
||||
def get_task_outputs(task: ifcopenshell.entity_instance, is_deep: bool = False) -> list[ifcopenshell.entity_instance]:
|
||||
if not is_deep:
|
||||
return get_direct_task_outputs(task)
|
||||
else:
|
||||
return [
|
||||
output
|
||||
for nested_task in get_all_nested_tasks(task)
|
||||
for output in get_direct_task_outputs(nested_task)
|
||||
]
|
||||
return [output for nested_task in get_all_nested_tasks(task) for output in get_direct_task_outputs(nested_task)]
|
||||
|
||||
|
||||
def get_task_inputs(task: ifcopenshell.entity_instance, is_deep: bool = False) -> list[ifcopenshell.entity_instance]:
|
||||
@@ -434,8 +404,7 @@ def get_tasks_for_product(
|
||||
inputs = [
|
||||
assignement.RelatingProcess
|
||||
for assignement in product.HasAssignments
|
||||
if assignement.is_a("IfcRelAssignsToProcess")
|
||||
and assignement.RelatingProcess.is_a("IfcTask")
|
||||
if assignement.is_a("IfcRelAssignsToProcess") and assignement.RelatingProcess.is_a("IfcTask")
|
||||
]
|
||||
outputs = [
|
||||
obj
|
||||
@@ -446,16 +415,8 @@ def get_tasks_for_product(
|
||||
]
|
||||
|
||||
if schedule:
|
||||
inputs = [
|
||||
task
|
||||
for task in inputs
|
||||
if get_task_work_schedule(task).id() == schedule.id()
|
||||
]
|
||||
outputs = [
|
||||
task
|
||||
for task in outputs
|
||||
if get_task_work_schedule(task).id() == schedule.id()
|
||||
]
|
||||
inputs = [task for task in inputs if get_task_work_schedule(task).id() == schedule.id()]
|
||||
outputs = [task for task in outputs if get_task_work_schedule(task).id() == schedule.id()]
|
||||
|
||||
return inputs, outputs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user