Run black on IOS-Python

This commit is contained in:
Dion Moult
2024-07-26 12:00:28 +10:00
parent d51fa2c5f7
commit a6286293d8
83 changed files with 603 additions and 637 deletions
@@ -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"]
+1 -1
View File
@@ -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
+62 -64
View File
@@ -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