mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
typing
This commit is contained in:
@@ -25,6 +25,7 @@ import mathutils
|
||||
import numpy as np
|
||||
import multiprocessing
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.boundary
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.shape
|
||||
@@ -416,7 +417,7 @@ class UpdateBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
tool.Boundary.move_origin_to_space_origin(context.active_object)
|
||||
settings = tool.Boundary.get_assign_connection_geometry_settings(context.active_object)
|
||||
ifcopenshell.api.run("boundary.assign_connection_geometry", tool.Ifc.get(), **settings)
|
||||
ifcopenshell.api.boundary.assign_connection_geometry(tool.Ifc.get(), **settings)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.shape_builder
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.boundary
|
||||
import ifcopenshell.api.grid
|
||||
import bonsai.core.geometry
|
||||
import bonsai.core.geometry as core
|
||||
@@ -479,7 +480,7 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
elif product.is_a("IfcRelSpaceBoundary"):
|
||||
# TODO refactor
|
||||
settings = tool.Boundary.get_assign_connection_geometry_settings(obj)
|
||||
ifcopenshell.api.run("boundary.assign_connection_geometry", tool.Ifc.get(), **settings)
|
||||
ifcopenshell.api.boundary.assign_connection_geometry(tool.Ifc.get(), **settings)
|
||||
return
|
||||
|
||||
if tool.Ifc.is_moved(obj) or tool.Geometry.is_scaled(obj):
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.profile
|
||||
import ifcopenshell.util.element
|
||||
import bonsai.bim.helper
|
||||
import bonsai.tool as tool
|
||||
@@ -174,12 +175,12 @@ class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
||||
props.object_to_profile = None
|
||||
if not indices:
|
||||
points = [(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]
|
||||
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
||||
profile = ifcopenshell.api.profile.add_arbitrary_profile(tool.Ifc.get(), profile=points)
|
||||
else:
|
||||
if "inner_curves" not in indices:
|
||||
points = [(obj.data.vertices[i].co.x, obj.data.vertices[i].co.y) for i in indices["profile"]]
|
||||
points.append(points[0])
|
||||
profile = ifcopenshell.api.run("profile.add_arbitrary_profile", tool.Ifc.get(), profile=points)
|
||||
profile = ifcopenshell.api.profile.add_arbitrary_profile(tool.Ifc.get(), profile=points)
|
||||
else:
|
||||
outer_points = [(obj.data.vertices[i].co.x, obj.data.vertices[i].co.y) for i in indices["profile"]]
|
||||
outer_points.append(outer_points[0])
|
||||
@@ -189,8 +190,7 @@ class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
|
||||
]
|
||||
for curve in inner_points:
|
||||
curve.append(curve[0])
|
||||
profile = ifcopenshell.api.run(
|
||||
"profile.add_arbitrary_profile_with_voids",
|
||||
profile = ifcopenshell.api.profile.add_arbitrary_profile_with_voids(
|
||||
tool.Ifc.get(),
|
||||
outer_profile=outer_points,
|
||||
inner_profiles=inner_points,
|
||||
|
||||
@@ -39,11 +39,8 @@ def edit_attributes(file: ifcopenshell.file, product: ifcopenshell.entity_instan
|
||||
|
||||
:param product: The product you want to edit. This may be any rooted IFC
|
||||
entity.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -17,17 +17,20 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from typing import Optional
|
||||
from ifcopenshell.util.shape_builder import SequenceOfVectors, V, ifc_safe_vector_type
|
||||
|
||||
|
||||
def assign_connection_geometry(
|
||||
file: ifcopenshell.file,
|
||||
rel_space_boundary: ifcopenshell.entity_instance,
|
||||
outer_boundary: list[tuple[float, float]],
|
||||
outer_boundary: SequenceOfVectors,
|
||||
location: tuple[float, float, float],
|
||||
axis: tuple[float, float, float],
|
||||
ref_direction: tuple[float, float, float],
|
||||
inner_boundaries: Optional[list[list[tuple[float, float]]]] = None,
|
||||
inner_boundaries: Optional[SequenceOfVectors] = None,
|
||||
unit_scale: Optional[float] = None,
|
||||
) -> None:
|
||||
"""Create and assign a connection geometry to a space boundary relationship
|
||||
@@ -40,35 +43,28 @@ def assign_connection_geometry(
|
||||
|
||||
:param rel_space_boundary: The space boundary relationship to assign the
|
||||
connection geometry to.
|
||||
:type rel_space_boundary: ifcopenshell.entity_instance
|
||||
:param outer_boundary: A list of 2D points representing an open
|
||||
polyline. The last point will connect to the first point. Each
|
||||
point is represented by an interable of 2 floats. The coordinates of
|
||||
the points are relative to the positional matrix arguments.
|
||||
:type outer_boundary: list[tuple[float, float]]
|
||||
:param inner_boundaries: A list of zero or more inner boundaries to use
|
||||
for the plane. Each boundary is represented by an open polyline, as
|
||||
defined by the outer_boundary argument.
|
||||
:type inner_boundaries: list[list[tuple[float, float]]], optional
|
||||
:param location: The local origin of the connection geometry, defined as
|
||||
an XYZ coordinate relative to the placement of the space that is
|
||||
being bounded.
|
||||
:type location: tuple[float, float, float]
|
||||
:param axis: The local X axis of the connection geometry, defined as an
|
||||
XYZ vector relative to the placement of the space that is being
|
||||
bounded.
|
||||
:type axis: tuple[float, float, float]
|
||||
:param ref_direction: The local Z axis of the connection geometry,
|
||||
defined as an XYZ vector relative to the placement of the space that
|
||||
is being bounded. The Y vector is automatically derived using the
|
||||
right hand rule.
|
||||
:type ref_direction: tuple[float, float, float]
|
||||
:param unit_scale: The unit scale as calculated by
|
||||
ifcopenshell.util.unit.calculate_unit_scale. If not provided, it
|
||||
will be automatically calculated for you.
|
||||
:type unit_scale: float, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -83,19 +79,26 @@ def assign_connection_geometry(
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.rel_space_boundary = rel_space_boundary
|
||||
usecase.outer_boundary = outer_boundary
|
||||
usecase.inner_boundaries = inner_boundaries or ()
|
||||
usecase.location = location
|
||||
usecase.axis = axis
|
||||
usecase.ref_direction = ref_direction
|
||||
usecase.unit_scale = unit_scale
|
||||
usecase.outer_boundary = V(outer_boundary)
|
||||
usecase.inner_boundaries = V(inner_boundaries or [])
|
||||
usecase.location = V(location)
|
||||
usecase.axis = V(axis)
|
||||
usecase.ref_direction = V(ref_direction)
|
||||
usecase.unit_scale = unit_scale if unit_scale is not None else ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
return usecase.execute()
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
rel_space_boundary: ifcopenshell.entity_instance
|
||||
outer_boundary: npt.NDArray
|
||||
inner_boundaries: npt.NDArray
|
||||
location: npt.NDArray
|
||||
axis: npt.NDArray
|
||||
ref_direction: npt.NDArray
|
||||
unit_scale: float
|
||||
|
||||
def execute(self):
|
||||
if self.unit_scale is None:
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
outer_boundary = self.create_polyline(self.outer_boundary)
|
||||
inner_boundaries = tuple(self.create_polyline(boundary) for boundary in self.inner_boundaries)
|
||||
plane = self.create_plane(self.location, self.axis, self.ref_direction)
|
||||
@@ -103,18 +106,23 @@ class Usecase:
|
||||
connection_geometry = self.file.createIfcConnectionSurfaceGeometry(curve_bounded_plane)
|
||||
self.rel_space_boundary.ConnectionGeometry = connection_geometry
|
||||
|
||||
def create_point(self, point):
|
||||
return self.file.createIfcCartesianPoint(point / self.unit_scale)
|
||||
def create_point(self, point: npt.NDArray) -> ifcopenshell.entity_instance:
|
||||
return self.file.create_enitty("IfcCartesianPoint", ifc_safe_vector_type(point / self.unit_scale))
|
||||
|
||||
def close_polyline(self, points):
|
||||
def close_polyline(
|
||||
self, points: tuple[ifcopenshell.entity_instance, ...]
|
||||
) -> tuple[ifcopenshell.entity_instance, ...]:
|
||||
return points + (points[0],)
|
||||
|
||||
def create_polyline(self, points):
|
||||
if points[0] == points[-1]:
|
||||
def create_polyline(self, points: npt.NDArray) -> ifcopenshell.entity_instance:
|
||||
if np.allclose(points[0], points[-1]):
|
||||
points = points[0 : len(points) - 1]
|
||||
return self.file.createIfcPolyline(self.close_polyline(tuple(self.create_point(point) for point in points)))
|
||||
ifc_points = tuple(self.create_point(point) for point in points)
|
||||
return self.file.createIfcPolyline(self.close_polyline(ifc_points))
|
||||
|
||||
def create_plane(self, location, axis, ref_direction):
|
||||
def create_plane(
|
||||
self, location: npt.NDArray, axis: npt.NDArray, ref_direction: npt.NDArray
|
||||
) -> ifcopenshell.entity_instance:
|
||||
return self.file.createIfcPlane(
|
||||
self.file.createIfcAxis2Placement3D(
|
||||
self.create_point(location),
|
||||
|
||||
@@ -20,7 +20,7 @@ import ifcopenshell
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.date
|
||||
from typing import Union
|
||||
from typing import Union, Any
|
||||
|
||||
|
||||
def add_classification(
|
||||
@@ -61,9 +61,7 @@ def add_classification(
|
||||
classification library. The latter approach is preferred if you are
|
||||
using a commonly known system such as Uniclass, as this will ensure
|
||||
all metadata is added correctly.
|
||||
:type classification: str,ifcopenshell.entity_instance
|
||||
:return: The added IfcClassification element
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -81,28 +79,28 @@ def add_classification(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"classification": classification,
|
||||
}
|
||||
return usecase.execute()
|
||||
return usecase.execute(classification)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if isinstance(self.settings["classification"], str):
|
||||
classification = self.file.createIfcClassification(Name=self.settings["classification"])
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, classification: Union[str, ifcopenshell.entity_instance]) -> ifcopenshell.entity_instance:
|
||||
self.classification = classification
|
||||
if isinstance(self.classification, str):
|
||||
classification = self.file.create_entity("IfcClassification", Name=self.classification)
|
||||
self.relate_to_project(classification)
|
||||
return classification
|
||||
return self.add_from_library()
|
||||
|
||||
def add_from_library(self):
|
||||
def add_from_library(self) -> ifcopenshell.entity_instance:
|
||||
edition_date = None
|
||||
if self.settings["classification"].EditionDate:
|
||||
edition_date = ifcopenshell.util.date.ifc2datetime(self.settings["classification"].EditionDate)
|
||||
self.settings["classification"].EditionDate = None
|
||||
if self.classification.EditionDate:
|
||||
edition_date = ifcopenshell.util.date.ifc2datetime(self.classification.EditionDate)
|
||||
self.classification.EditionDate = None
|
||||
|
||||
migrator = ifcopenshell.util.schema.Migrator()
|
||||
result = migrator.migrate(self.settings["classification"], self.file)
|
||||
result = migrator.migrate(self.classification, self.file)
|
||||
|
||||
# TODO: should auto date migration be part of the migrator?
|
||||
if self.file.schema == "IFC2X3" and edition_date:
|
||||
@@ -118,7 +116,7 @@ class Usecase:
|
||||
|
||||
return result
|
||||
|
||||
def relate_to_project(self, classification):
|
||||
def relate_to_project(self, classification: ifcopenshell.entity_instance) -> None:
|
||||
self.file.create_entity(
|
||||
"IfcRelAssociatesClassification",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
|
||||
@@ -21,7 +21,7 @@ import ifcopenshell.api.owner
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Any
|
||||
|
||||
|
||||
def add_reference(
|
||||
@@ -65,23 +65,18 @@ def add_reference(
|
||||
|
||||
:param product: The list of IFC objects, properties, or resources you want to
|
||||
associate the classification reference to.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
:param reference: The classification reference entity taken from an
|
||||
IFC classification library. If you supply this parameter, you will
|
||||
use option 2.
|
||||
:type reference: ifcopenshell.entity_instance, optional
|
||||
:param identification: If you choose option 1 and do not specify a
|
||||
reference, you may manually specify an identification code. The code
|
||||
is typically a short identifier and may have punctuation to separate
|
||||
the levels of hierarchy in the classificaion (e.g. Pr_12_23_34).
|
||||
:type identification: str, optional
|
||||
:param name: If you choose option 1 and do not specify a reference, you
|
||||
may manually specify a name. The name is typically human readable.
|
||||
:type name: str, optional
|
||||
:param classification: The IfcClassification entity in your IFC model
|
||||
(not the library, if you are doing option 2) that the reference is
|
||||
part of.
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param is_lightweight: If you are doing option 2, choose whether or not
|
||||
to only add that particular reference (lighweight) or also add all
|
||||
of its parent references in the classification hierarchy (not
|
||||
@@ -91,13 +86,11 @@ def add_reference(
|
||||
references merely help describe the "tree" of classifications, but
|
||||
is generally unnecessary. Using lightweight classifications are
|
||||
recommended and is the default.
|
||||
:type is_lightweight: bool, optional
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: The newly added IfcClassificationReference
|
||||
or `None` if `products` was empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -136,6 +129,9 @@ def add_reference(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
if not self.settings["products"]:
|
||||
return
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_classification(
|
||||
IfcClassification, consult the IFC documentation.
|
||||
|
||||
:param classification: The IfcClassification entity you want to edit
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -43,7 +40,5 @@ def edit_classification(
|
||||
ifcopenshell.api.classification.edit_classification(model,
|
||||
classification=classification, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"classification": classification, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["classification"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(classification, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_reference(
|
||||
IfcClassificationReference, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcClassificationReference entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -43,7 +40,5 @@ def edit_reference(
|
||||
ifcopenshell.api.classification.edit_reference(model,
|
||||
reference=reference, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"reference": reference, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["reference"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(reference, name, value)
|
||||
|
||||
@@ -28,9 +28,7 @@ def remove_classification(file: ifcopenshell.file, classification: ifcopenshell.
|
||||
removed from a project.
|
||||
|
||||
:param classification: The IfcClassification entity you want to remove
|
||||
:type classification: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,16 +40,17 @@ def remove_classification(file: ifcopenshell.file, classification: ifcopenshell.
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"classification": classification}
|
||||
return usecase.execute()
|
||||
return usecase.execute(classification)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
references = self.get_references(self.settings["classification"])
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, classification: ifcopenshell.entity_instance) -> None:
|
||||
references = self.get_references(classification)
|
||||
for reference in references:
|
||||
self.file.remove(reference)
|
||||
self.file.remove(self.settings["classification"])
|
||||
self.file.remove(classification)
|
||||
for rel in self.file.by_type("IfcRelAssociatesClassification"):
|
||||
if not rel.RelatingClassification:
|
||||
history = rel.OwnerHistory
|
||||
|
||||
@@ -33,15 +33,12 @@ def remove_reference(
|
||||
|
||||
:param reference: The IfcClassificationReference entity of the
|
||||
relationship you want to remove.
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param product: The list fo object entities of the relationship you want to
|
||||
remove.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
|
||||
:raises TypeError: If file is IFC2X3 and `products` has non-IfcRoot elements.
|
||||
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -56,20 +53,18 @@ def remove_reference(
|
||||
ifcopenshell.api.classification.remove_reference(model,
|
||||
reference=reference, products=[wall_type])
|
||||
"""
|
||||
settings = {"reference": reference, "products": products}
|
||||
|
||||
is_ifc2x3 = file.schema == "IFC2X3"
|
||||
products = set(settings["products"])
|
||||
referenced = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
|
||||
products -= products.difference(referenced)
|
||||
products_set = set(products)
|
||||
referenced = ifcopenshell.util.element.get_referenced_elements(reference)
|
||||
products_set -= products_set.difference(referenced)
|
||||
|
||||
# all products are already unassigned from a reference
|
||||
if not products:
|
||||
if not products_set:
|
||||
return
|
||||
|
||||
rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
non_rooted_products: set[ifcopenshell.entity_instance] = set()
|
||||
for product in settings["products"]:
|
||||
for product in products:
|
||||
if product.is_a("IfcRoot"):
|
||||
rooted_products.add(product)
|
||||
else:
|
||||
@@ -86,7 +81,7 @@ def remove_reference(
|
||||
reference_rels = {
|
||||
rel
|
||||
for rel in reference_rels
|
||||
if rel.is_a("IfcRelAssociatesClassification") and rel.RelatingClassification == settings["reference"]
|
||||
if rel.is_a("IfcRelAssociatesClassification") and rel.RelatingClassification == reference
|
||||
}
|
||||
|
||||
for rel in reference_rels:
|
||||
@@ -108,7 +103,7 @@ def remove_reference(
|
||||
rels = getattr(product, "HasExternalReference", [])
|
||||
reference_rels.update(rels)
|
||||
|
||||
reference_rels = {rel for rel in reference_rels if rel.RelatingReference == settings["reference"]}
|
||||
reference_rels = {rel for rel in reference_rels if rel.RelatingReference == reference}
|
||||
for rel in reference_rels:
|
||||
related_objects = set(rel.RelatedResourceObjects) - non_rooted_products
|
||||
if related_objects:
|
||||
@@ -117,6 +112,6 @@ def remove_reference(
|
||||
file.remove(rel)
|
||||
|
||||
# TODO: we only handle lightweight classifications here
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(settings["reference"])
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(reference)
|
||||
if not referenced_elements:
|
||||
file.remove(settings["reference"])
|
||||
file.remove(reference)
|
||||
|
||||
@@ -26,16 +26,14 @@ def add_metric_reference(
|
||||
Adds a chain of references to a metric. The reference path is a string of the form "attribute.attribute.attribute"
|
||||
Used to reference a value of an attribute of an instance through a metric objective entity.
|
||||
"""
|
||||
settings = {"metric": metric, "reference_path": reference_path}
|
||||
|
||||
references_created = []
|
||||
if settings["reference_path"]:
|
||||
attributes = settings["reference_path"].split(".")
|
||||
if reference_path:
|
||||
attributes = reference_path.split(".")
|
||||
for i in range(len(attributes)):
|
||||
if i == 0:
|
||||
reference = file.create_entity("IfcReference")
|
||||
reference.AttributeIdentifier = attributes[i]
|
||||
settings["metric"].ReferencePath = reference
|
||||
metric.ReferencePath = reference
|
||||
references_created.append(reference)
|
||||
else:
|
||||
reference = file.create_entity("IfcReference")
|
||||
|
||||
@@ -39,36 +39,29 @@ def assign_constraint(
|
||||
|
||||
:param products: The list of products the constraint applies to. This is anything
|
||||
which can have properties or quantities.
|
||||
:type products: list[ifcopenshell.entity_instance]
|
||||
:param constraint: The IfcObjective constraint
|
||||
:type constraint: ifcopenshell.entity_instance
|
||||
:return: The new or updated IfcRelAssociatesConstraint relationship
|
||||
or `None` if `products` was an empty list.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"products": products,
|
||||
"constraint": constraint,
|
||||
}
|
||||
return usecase.execute()
|
||||
return usecase.execute(products, constraint)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
products = set(self.settings["products"])
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, products: list[ifcopenshell.entity_instance], constraint: ifcopenshell.entity_instance):
|
||||
if not products:
|
||||
return
|
||||
products_set = set(products)
|
||||
|
||||
self.constraint = self.settings["constraint"]
|
||||
|
||||
rels = self.get_constraint_rels()
|
||||
rels = self.get_constraint_rels(constraint)
|
||||
related_objects = set()
|
||||
for rel in rels:
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
products_to_assign = products - related_objects
|
||||
products_to_assign = products_set - related_objects
|
||||
if not products_to_assign:
|
||||
return rels[0]
|
||||
|
||||
@@ -85,14 +78,14 @@ class Usecase:
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(self.file),
|
||||
"RelatingConstraint": self.constraint,
|
||||
"RelatingConstraint": constraint,
|
||||
"RelatedObjects": list(products_to_assign),
|
||||
}
|
||||
)
|
||||
|
||||
def get_constraint_rels(self) -> list[ifcopenshell.entity_instance]:
|
||||
def get_constraint_rels(self, constraint: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
rels = []
|
||||
for rel in self.file.get_inverse(self.constraint):
|
||||
for rel in self.file.get_inverse(constraint):
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
rels.append(rel)
|
||||
return rels
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_metric(file: ifcopenshell.file, metric: ifcopenshell.entity_instance, a
|
||||
IfcMetric, consult the IFC documentation.
|
||||
|
||||
:param metric: The IfcMetric you want to edit.
|
||||
:type metric: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_metric(file: ifcopenshell.file, metric: ifcopenshell.entity_instance, a
|
||||
ifcopenshell.api.constraint.edit_metric(model,
|
||||
metric=metric, attributes={"ConstraintGrade": "HARD"})
|
||||
"""
|
||||
settings = {"metric": metric, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["metric"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(metric, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_objective(
|
||||
IfcObjective, consult the IFC documentation.
|
||||
|
||||
:param objective: The IfcObjective you want to edit.
|
||||
:type objective: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_objective(
|
||||
ifcopenshell.api.constraint.edit_objective(model,
|
||||
objective=objective, attributes={"ConstraintGrade": "HARD"})
|
||||
"""
|
||||
settings = {"objective": objective, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["objective"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(objective, name, value)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def remove_metric(file: ifcopenshell.file, metric: ifcopenshell.entity_instance) -> None:
|
||||
@@ -41,17 +42,18 @@ def remove_metric(file: ifcopenshell.file, metric: ifcopenshell.entity_instance)
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"metric": metric}
|
||||
return usecase.execute()
|
||||
return usecase.execute(metric)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
if self.settings["metric"].ReferencePath:
|
||||
reference = self.settings["metric"].ReferencePath
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, metric: ifcopenshell.entity_instance) -> None:
|
||||
if metric.ReferencePath:
|
||||
reference = metric.ReferencePath
|
||||
self.delete_reference(reference)
|
||||
|
||||
self.file.remove(self.settings["metric"])
|
||||
self.file.remove(metric)
|
||||
for rel in self.file.by_type("IfcRelAssociatesConstraint"):
|
||||
if not rel.RelatingConstraint:
|
||||
history = rel.OwnerHistory
|
||||
@@ -62,7 +64,7 @@ class Usecase:
|
||||
if not resource_rel.RelatingConstraint:
|
||||
self.file.remove(resource_rel)
|
||||
|
||||
def delete_reference(self, reference):
|
||||
def delete_reference(self, reference: ifcopenshell.entity_instance) -> None:
|
||||
if reference.InnerReference:
|
||||
self.delete_reference(reference.InnerReference)
|
||||
self.file.remove(reference)
|
||||
|
||||
@@ -32,41 +32,35 @@ def unassign_constraint(
|
||||
other products.
|
||||
|
||||
:param products: The list of products the constraint applies to.
|
||||
:type products: list[ifcopenshell.entity_instance]
|
||||
:param constraint: The IfcObjective constraint
|
||||
:type constraint: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"products": products,
|
||||
"constraint": constraint,
|
||||
}
|
||||
return usecase.execute()
|
||||
return usecase.execute(products, constraint)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
products = set(self.settings["products"])
|
||||
if not products:
|
||||
return
|
||||
file: ifcopenshell.file
|
||||
|
||||
self.constraint = self.settings["constraint"]
|
||||
rels = self.get_constraint_rels()
|
||||
def execute(self, products_: list[ifcopenshell.entity_instance], constraint: ifcopenshell.entity_instance):
|
||||
if not products_:
|
||||
return
|
||||
products_set = set(products_)
|
||||
|
||||
rels = self.get_constraint_rels(constraint)
|
||||
related_objects = set()
|
||||
for rel in rels:
|
||||
related_objects.update(rel.RelatedObjects)
|
||||
|
||||
if not related_objects.intersection(products):
|
||||
if not related_objects.intersection(products_set):
|
||||
return
|
||||
|
||||
for rel in rels:
|
||||
related_objects = set(rel.RelatedObjects)
|
||||
if not related_objects.intersection(products):
|
||||
if not related_objects.intersection(products_set):
|
||||
continue
|
||||
related_objects -= products
|
||||
related_objects -= products_set
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.owner.update_owner_history(self.file, **{"element": rel})
|
||||
@@ -77,9 +71,9 @@ class Usecase:
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(self.file, history)
|
||||
|
||||
def get_constraint_rels(self) -> list[ifcopenshell.entity_instance]:
|
||||
def get_constraint_rels(self, cosntraint: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
rels = []
|
||||
for rel in self.file.get_inverse(self.constraint):
|
||||
for rel in self.file.get_inverse(cosntraint):
|
||||
if rel.is_a("IfcRelAssociatesConstraint"):
|
||||
rels.append(rel)
|
||||
return rels
|
||||
|
||||
@@ -27,11 +27,8 @@ def edit_context(file: ifcopenshell.file, context: ifcopenshell.entity_instance,
|
||||
IfcGeometricRepresentationContext, consult the IFC documentation.
|
||||
|
||||
:param context: The IfcGeometricRepresentationContext entity you want to edit
|
||||
:type context: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -47,7 +44,5 @@ def edit_context(file: ifcopenshell.file, context: ifcopenshell.entity_instance,
|
||||
ifcopenshell.api.context.edit_context(model,
|
||||
context=body, attributes={"ContextIdentifier": "Body"})
|
||||
"""
|
||||
settings = {"context": context, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["context"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(context, name, value)
|
||||
|
||||
@@ -25,8 +25,6 @@ from typing import Union
|
||||
def copy_cost_item(
|
||||
file: ifcopenshell.file, cost_item: ifcopenshell.entity_instance
|
||||
) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]]:
|
||||
# TODO: currently it never returns list of duplicated cost items
|
||||
# though it is stated in the docs
|
||||
"""Copies all cost items and related relationships
|
||||
|
||||
The following relationships are also duplicated:
|
||||
@@ -36,9 +34,7 @@ def copy_cost_item(
|
||||
* The copy will have duplicated nested cost items
|
||||
|
||||
:param cost_item: The cost item to be duplicated
|
||||
:type cost_item: ifcopenshell.entity_instance
|
||||
:return: The duplicated cost item or the list of duplicated cost items if the latter has children
|
||||
:rtype: ifcopenshell.entity_instance or list[ifcopenshell.entity_instance]
|
||||
|
||||
Example:
|
||||
.. code:: python
|
||||
@@ -53,22 +49,29 @@ def copy_cost_item(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"cost_item": cost_item}
|
||||
return usecase.execute()
|
||||
return usecase.execute(cost_item)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.new_cost_items = []
|
||||
return self.duplicate_cost_item(self.settings["cost_item"])
|
||||
file: ifcopenshell.file
|
||||
new_cost_items: list[ifcopenshell.entity_instance]
|
||||
|
||||
def duplicate_cost_item(self, cost_item):
|
||||
def execute(
|
||||
self, cost_item: ifcopenshell.entity_instance
|
||||
) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]]:
|
||||
self.new_cost_items = []
|
||||
self.duplicate_cost_item(cost_item)
|
||||
return self.new_cost_items[0] if len(self.new_cost_items) == 1 else self.new_cost_items
|
||||
|
||||
def duplicate_cost_item(self, cost_item: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
new_cost_item = ifcopenshell.util.element.copy_deep(self.file, cost_item)
|
||||
self.new_cost_items.append(new_cost_item)
|
||||
self.copy_indirect_attributes(cost_item, new_cost_item)
|
||||
return new_cost_item
|
||||
|
||||
def copy_indirect_attributes(self, from_element, to_element):
|
||||
def copy_indirect_attributes(
|
||||
self, from_element: ifcopenshell.entity_instance, to_element: ifcopenshell.entity_instance
|
||||
) -> None:
|
||||
for inverse in self.file.get_inverse(from_element):
|
||||
if inverse.is_a("IfcRelDefinesByProperties"):
|
||||
inverse = ifcopenshell.util.element.copy(self.file, inverse)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_cost_item(
|
||||
IfcCostItem, consult the IFC documentation.
|
||||
|
||||
:param cost_item: The IfcCostItem entity you want to edit
|
||||
:type cost_item: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_cost_item(
|
||||
item = ifcopenshell.api.cost.add_cost_item(model, cost_schedule=schedule)
|
||||
ifcopenshell.api.cost.edit_cost_item(model, cost_item=item, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"cost_item": cost_item, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["cost_item"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(cost_item, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_cost_item_quantity(
|
||||
IfcPhysicalQuantity, consult the IFC documentation.
|
||||
|
||||
:param physical_quantity: The IfcPhysicalQuantity entity you want to edit
|
||||
:type physical_quantity: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -50,7 +47,5 @@ def edit_cost_item_quantity(
|
||||
ifcopenshell.api.cost.edit_cost_item_quantity(model,
|
||||
physical_quantity=quantity, "attributes": {"VolumeValue": 3.0})
|
||||
"""
|
||||
settings = {"physical_quantity": physical_quantity, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["physical_quantity"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(physical_quantity, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_cost_schedule(
|
||||
IfcCostSchedule, consult the IFC documentation.
|
||||
|
||||
:param cost_schedule: The IfcCostSchedule entity you want to edit
|
||||
:type cost_schedule: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,8 +39,5 @@ def edit_cost_schedule(
|
||||
ifcopenshell.api.cost.edit_cost_schedule(model,
|
||||
cost_schedule=schedule, attributes={"Name": "Foo"})
|
||||
"""
|
||||
|
||||
settings = {"cost_schedule": cost_schedule, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["cost_schedule"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(cost_schedule, name, value)
|
||||
|
||||
@@ -31,11 +31,8 @@ def edit_cost_value(
|
||||
IfcCostValue, consult the IFC documentation.
|
||||
|
||||
:param cost_value: The IfcCostValue entity you want to edit
|
||||
:type cost_value: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -49,14 +46,12 @@ def edit_cost_value(
|
||||
ifcopenshell.api.cost.edit_cost_value(model, cost_value=value,
|
||||
attributes={"AppliedValue": 42.0})
|
||||
"""
|
||||
settings = {"cost_value": cost_value, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if name == "AppliedValue" and value is not None:
|
||||
# TODO: support all applied value select types
|
||||
value = file.createIfcMonetaryMeasure(value)
|
||||
elif name == "UnitBasis":
|
||||
old_unit_basis = settings["cost_value"].UnitBasis
|
||||
old_unit_basis = cost_value.UnitBasis
|
||||
if value:
|
||||
value_component = file.create_entity(
|
||||
ifcopenshell.util.unit.get_unit_measure_class(value["UnitComponent"].UnitType),
|
||||
@@ -65,4 +60,4 @@ def edit_cost_value(
|
||||
value = file.create_entity("IfcMeasureWithUnit", value_component, value["UnitComponent"])
|
||||
if old_unit_basis and len(file.get_inverse(old_unit_basis)) == 0:
|
||||
ifcopenshell.util.element.remove_deep(file, old_unit_basis)
|
||||
setattr(settings["cost_value"], name, value)
|
||||
setattr(cost_value, name, value)
|
||||
|
||||
@@ -30,12 +30,9 @@ def unassign_cost_item_quantity(
|
||||
have any impact on the cost item.
|
||||
|
||||
:param cost_item: The IfcCostItem to remove quantities from
|
||||
:type cost_item: ifcopenshell.entity_instance
|
||||
:param products: A list of IfcProducts that may have parametrically
|
||||
connected quantities to the cost item
|
||||
:type products: list[ifcopenshell.entity_instance]
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -69,38 +66,39 @@ def unassign_cost_item_quantity(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"cost_item": cost_item, "products": products or []}
|
||||
return usecase.execute()
|
||||
return usecase.execute(cost_item, products or [])
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.quantities = set(self.settings["cost_item"].CostQuantities or [])
|
||||
for quantity in self.settings["cost_item"].CostQuantities or []:
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, cost_item: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance]) -> None:
|
||||
quantities = set(cost_item.CostQuantities or [])
|
||||
for quantity in cost_item.CostQuantities or []:
|
||||
for inverse in self.file.get_inverse(quantity):
|
||||
if not inverse.is_a("IfcElementQuantity"):
|
||||
continue
|
||||
for rel in inverse.DefinesOccurrence or []:
|
||||
for related_object in rel.RelatedObjects:
|
||||
if related_object in self.settings["products"]:
|
||||
self.quantities.remove(quantity)
|
||||
self.settings["cost_item"].CostQuantities = list(self.quantities)
|
||||
for product in self.settings["products"]:
|
||||
if related_object in products:
|
||||
quantities.remove(quantity)
|
||||
cost_item.CostQuantities = list(quantities)
|
||||
for product in products:
|
||||
ifcopenshell.api.control.unassign_control(
|
||||
self.file,
|
||||
related_object=product,
|
||||
relating_control=self.settings["cost_item"],
|
||||
relating_control=cost_item,
|
||||
)
|
||||
self.update_cost_item_count()
|
||||
self.update_cost_item_count(cost_item)
|
||||
|
||||
def update_cost_item_count(self):
|
||||
def update_cost_item_count(self, cost_item: ifcopenshell.entity_instance) -> None:
|
||||
# This is a bold assumption
|
||||
# https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564
|
||||
if len(self.settings["cost_item"].CostQuantities) == 1:
|
||||
quantity = self.settings["cost_item"].CostQuantities[0]
|
||||
if len(cost_item.CostQuantities) == 1:
|
||||
quantity = cost_item.CostQuantities[0]
|
||||
if quantity.is_a("IfcQuantityCount"):
|
||||
count = 0
|
||||
for rel in self.settings["cost_item"].Controls:
|
||||
for rel in cost_item.Controls:
|
||||
count += len(rel.RelatedObjects)
|
||||
if count:
|
||||
quantity[3] = count
|
||||
|
||||
@@ -41,15 +41,12 @@ def assign_document(
|
||||
|
||||
:param product: The list of objects to associate the document to. This could be
|
||||
almost any sensible object in IFC.
|
||||
:type product: list[ifcopenshell.entity_instance]
|
||||
:param document: The IfcDocumentReference to associate to, or
|
||||
alternatively an IfcDocumentInformation, though this is not
|
||||
recommended.
|
||||
:type document: ifcopenshell.entity_instance
|
||||
:return: The IfcRelAssociatesDocument relationship
|
||||
or `None` if `products` was an empty list or all products were
|
||||
already assigned to the `document`.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -65,43 +62,41 @@ def assign_document(
|
||||
# Let's imagine storey represents an IfcBuildingStorey for the ground floor
|
||||
ifcopenshell.api.document.assign_document(model, products=[storey], document=reference)
|
||||
"""
|
||||
settings = {
|
||||
"products": products,
|
||||
"document": document,
|
||||
}
|
||||
|
||||
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||
# NOTE: reuses code from `library.assign_reference`
|
||||
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(settings["document"])
|
||||
products: set[ifcopenshell.entity_instance] = set(settings["products"])
|
||||
products = products - referenced_elements
|
||||
referenced_elements = ifcopenshell.util.element.get_referenced_elements(document)
|
||||
products_set: set[ifcopenshell.entity_instance] = set(products)
|
||||
products_set = products_set - referenced_elements
|
||||
|
||||
if not products:
|
||||
if not products_set:
|
||||
return
|
||||
|
||||
if file.schema == "IFC2X3":
|
||||
rel = next(
|
||||
(r for r in file.by_type("IfcRelAssociatesDocument") if r.RelatingDocument == settings["document"]),
|
||||
(r for r in file.by_type("IfcRelAssociatesDocument") if r.RelatingDocument == document),
|
||||
None,
|
||||
)
|
||||
else:
|
||||
ifc_class = settings["document"].is_a()
|
||||
ifc_class = document.is_a()
|
||||
if ifc_class == "IfcDocumentReference":
|
||||
rel = next(iter(settings["document"].DocumentRefForObjects), None)
|
||||
rel = next(iter(document.DocumentRefForObjects), None)
|
||||
elif ifc_class == "IfcDocumentInformation":
|
||||
rel = next(iter(settings["document"].DocumentInfoForObjects), None)
|
||||
rel = next(iter(document.DocumentInfoForObjects), None)
|
||||
else:
|
||||
assert False, f"Unexpected document type: {ifc_class}"
|
||||
|
||||
if not rel:
|
||||
return file.create_entity(
|
||||
"IfcRelAssociatesDocument",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.owner.create_owner_history(file),
|
||||
RelatedObjects=list(products),
|
||||
RelatingDocument=settings["document"],
|
||||
RelatedObjects=list(products_set),
|
||||
RelatingDocument=document,
|
||||
)
|
||||
|
||||
related_objects = set(rel.RelatedObjects) | products
|
||||
related_objects = set(rel.RelatedObjects) | products_set
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.owner.update_owner_history(file, element=rel)
|
||||
return rel
|
||||
|
||||
@@ -30,11 +30,8 @@ def edit_information(
|
||||
IfcDocumentInformation, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcDocumentInformation entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -46,7 +43,5 @@ def edit_information(
|
||||
attributes={"Identification": "A-GA-6100", "Name": "Overall Plan",
|
||||
"Location": "A-GA-6100 - Overall Plan.pdf"})
|
||||
"""
|
||||
settings = {"information": information, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["information"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(information, name, value)
|
||||
|
||||
@@ -30,11 +30,8 @@ def edit_reference(
|
||||
IfcDocumentReference, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcDocumentReference entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -49,7 +46,5 @@ def edit_reference(
|
||||
ifcopenshell.api.document.edit_reference(model,
|
||||
reference=reference, attributes={"Identification": "2.1.15"})
|
||||
"""
|
||||
settings = {"reference": reference, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["reference"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(reference, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_text_literal(
|
||||
IfcTextLiteral, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcTextLiteral entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_text_literal(
|
||||
ifcopenshell.api.drawing.edit_text_literal(model,
|
||||
text_literal=text, attributes={"Literal": "MY ANNOTATION"})
|
||||
"""
|
||||
settings = {"text_literal": text_literal, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["text_literal"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(text_literal, name, value)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
from typing import Union
|
||||
from typing import Union, Any
|
||||
|
||||
COORD = Union[tuple[float, float], tuple[float, float, float]]
|
||||
|
||||
@@ -82,6 +82,9 @@ def add_axis_representation(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
is_2d = len(self.settings["axis"][0]) == 2
|
||||
|
||||
@@ -26,14 +26,9 @@ def add_footprint_representation(
|
||||
# A list of IFC curves to include in the curve set
|
||||
curves: list[ifcopenshell.entity_instance],
|
||||
) -> ifcopenshell.entity_instance:
|
||||
settings = {
|
||||
"context": context,
|
||||
"curves": curves,
|
||||
}
|
||||
|
||||
return file.createIfcShapeRepresentation(
|
||||
settings["context"],
|
||||
settings["context"].ContextIdentifier,
|
||||
context,
|
||||
context.ContextIdentifier,
|
||||
"GeometricCurveSet",
|
||||
[file.createIfcGeometricCurveSet(settings["curves"])],
|
||||
[file.createIfcGeometricCurveSet(curves)],
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
COORD_3D = tuple[float, float, float]
|
||||
|
||||
@@ -60,6 +60,9 @@ def add_mesh_representation(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
if self.settings["unit_scale"] is None:
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
|
||||
@@ -52,6 +52,9 @@ def add_profile_representation(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
self.settings["clippings"] = [Clipping.parse(c) for c in self.settings["clippings"]]
|
||||
|
||||
@@ -426,6 +426,9 @@ def add_window_representation(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
builder = ShapeBuilder(self.file)
|
||||
np_X, np_Y, np_Z = 0, 1, 2
|
||||
|
||||
@@ -31,53 +31,33 @@ def connect_path(
|
||||
related_connection: str = "NOTDEFINED",
|
||||
description: Optional[str] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
settings = {
|
||||
"relating_element": relating_element,
|
||||
"related_element": related_element,
|
||||
"relating_connection": relating_connection,
|
||||
"related_connection": related_connection,
|
||||
"description": description,
|
||||
}
|
||||
|
||||
incompatible_connections = []
|
||||
for rel in settings["relating_element"].ConnectedTo:
|
||||
incompatible_connections: list[ifcopenshell.entity_instance] = []
|
||||
for rel in relating_element.ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == settings["related_element"]:
|
||||
if rel.RelatedElement == related_element:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == settings["relating_connection"]
|
||||
):
|
||||
elif rel.RelatingConnectionType in ["ATSTART", "ATEND"] and rel.RelatingConnectionType == relating_connection:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in settings["relating_element"].ConnectedFrom:
|
||||
for rel in relating_element.ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == settings["relating_connection"]
|
||||
):
|
||||
if rel.RelatedConnectionType in ["ATSTART", "ATEND"] and rel.RelatedConnectionType == relating_connection:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in settings["related_element"].ConnectedFrom:
|
||||
for rel in related_element.ConnectedFrom:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if (
|
||||
rel.RelatedConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatedConnectionType == settings["related_connection"]
|
||||
):
|
||||
if rel.RelatedConnectionType in ["ATSTART", "ATEND"] and rel.RelatedConnectionType == related_connection:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
for rel in settings["related_element"].ConnectedTo:
|
||||
for rel in related_element.ConnectedTo:
|
||||
if not rel.is_a("IfcRelConnectsPathElements"):
|
||||
continue
|
||||
if rel.RelatedElement == settings["relating_element"]:
|
||||
if rel.RelatedElement == relating_element:
|
||||
incompatible_connections.append(rel)
|
||||
elif (
|
||||
rel.RelatingConnectionType in ["ATSTART", "ATEND"]
|
||||
and rel.RelatingConnectionType == settings["related_connection"]
|
||||
):
|
||||
elif rel.RelatingConnectionType in ["ATSTART", "ATEND"] and rel.RelatingConnectionType == related_connection:
|
||||
incompatible_connections.append(rel)
|
||||
|
||||
if incompatible_connections:
|
||||
@@ -87,14 +67,15 @@ def connect_path(
|
||||
if history:
|
||||
ifcopenshell.util.element.remove_deep2(file, history)
|
||||
|
||||
return file.createIfcRelConnectsPathElements(
|
||||
return file.create_entity(
|
||||
"IfcRelConnectsPathElements",
|
||||
ifcopenshell.guid.new(),
|
||||
OwnerHistory=ifcopenshell.api.owner.create_owner_history(file),
|
||||
Description=settings["description"],
|
||||
RelatingElement=settings["relating_element"],
|
||||
RelatedElement=settings["related_element"],
|
||||
RelatingConnectionType=settings["relating_connection"],
|
||||
RelatedConnectionType=settings["related_connection"],
|
||||
Description=description,
|
||||
RelatingElement=relating_element,
|
||||
RelatedElement=related_element,
|
||||
RelatingConnectionType=relating_connection,
|
||||
RelatedConnectionType=related_connection,
|
||||
RelatingPriorities=[],
|
||||
RelatedPriorities=[],
|
||||
)
|
||||
|
||||
@@ -46,29 +46,25 @@ def assign_group(
|
||||
ifcopenshell.api.group.assign_group(model,
|
||||
products=model.by_type("IfcFurniture"), group=group)
|
||||
"""
|
||||
settings = {
|
||||
"products": products,
|
||||
"group": group,
|
||||
}
|
||||
|
||||
if not settings["products"]:
|
||||
if not products:
|
||||
return
|
||||
|
||||
if not settings["group"].IsGroupedBy:
|
||||
is_grouped_by: tuple[ifcopenshell.entity_instance, ...]
|
||||
if not (is_grouped_by := group.IsGroupedBy):
|
||||
return file.create_entity(
|
||||
"IfcRelAssignsToGroup",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"RelatedObjects": settings["products"],
|
||||
"RelatingGroup": settings["group"],
|
||||
}
|
||||
"RelatedObjects": products,
|
||||
"RelatingGroup": group,
|
||||
},
|
||||
)
|
||||
rel = settings["group"].IsGroupedBy[0]
|
||||
rel = is_grouped_by[0]
|
||||
related_objects = set(rel.RelatedObjects) or set()
|
||||
products = set(settings["products"])
|
||||
if products.issubset(related_objects):
|
||||
products_set = set(products)
|
||||
if products_set.issubset(related_objects):
|
||||
return rel
|
||||
rel.RelatedObjects = list(related_objects | products)
|
||||
rel.RelatedObjects = list(related_objects | products_set)
|
||||
ifcopenshell.api.owner.update_owner_history(file, **{"element": rel})
|
||||
return rel
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_group(file: ifcopenshell.file, group: ifcopenshell.entity_instance, att
|
||||
IfcGroup, consult the IFC documentation.
|
||||
|
||||
:param group: The IfcGroup entity you want to edit
|
||||
:type group: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -40,7 +37,5 @@ def edit_group(file: ifcopenshell.file, group: ifcopenshell.entity_instance, att
|
||||
ifcopenshell.api.group.edit_group(model,
|
||||
group=group, attributes={"Description": "All furniture and joinery included in the unit"})
|
||||
"""
|
||||
settings = {"group": group, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["group"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(group, name, value)
|
||||
|
||||
@@ -46,17 +46,12 @@ def unassign_group(
|
||||
bad_furniture = furniture[0]
|
||||
ifcopenshell.api.group.unassign_group(model, products=[bad_furniture], group=group)
|
||||
"""
|
||||
settings = {
|
||||
"products": products,
|
||||
"group": group,
|
||||
}
|
||||
|
||||
if not settings["group"].IsGroupedBy:
|
||||
if not group.IsGroupedBy:
|
||||
return
|
||||
rel = settings["group"].IsGroupedBy[0]
|
||||
rel = group.IsGroupedBy[0]
|
||||
related_objects = set(rel.RelatedObjects) or set()
|
||||
products = set(settings["products"])
|
||||
related_objects -= products
|
||||
products_set = set(products)
|
||||
related_objects -= products_set
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
ifcopenshell.api.owner.update_owner_history(file, **{"element": rel})
|
||||
|
||||
@@ -45,24 +45,19 @@ def update_group_products(
|
||||
ifcopenshell.api.group.update_group_products(model,
|
||||
products=model.by_type("IfcFurniture"), group=group)
|
||||
"""
|
||||
settings = {
|
||||
"group": group,
|
||||
"products": products,
|
||||
}
|
||||
|
||||
if not settings["group"].IsGroupedBy:
|
||||
if not group.IsGroupedBy:
|
||||
return file.create_entity(
|
||||
"IfcRelAssignsToGroup",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"RelatedObjects": settings["products"],
|
||||
"RelatingGroup": settings["group"],
|
||||
"RelatedObjects": products,
|
||||
"RelatingGroup": group,
|
||||
}
|
||||
)
|
||||
else:
|
||||
rels = settings["group"].IsGroupedBy
|
||||
objects = set(settings["products"])
|
||||
rels = group.IsGroupedBy
|
||||
objects = set(products)
|
||||
for rel in rels:
|
||||
objects.update([g for g in rel.RelatedObjects if g.is_a("IfcGroup")])
|
||||
to_purge = rels[1:]
|
||||
|
||||
@@ -37,7 +37,5 @@ def edit_layer(file: ifcopenshell.file, layer: ifcopenshell.entity_instance, att
|
||||
ifcopenshell.api.layer.edit_layer(model,
|
||||
layer=layer, attributes={"Description": "All walls, based on the AIA standard."})
|
||||
"""
|
||||
settings = {"layer": layer, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["layer"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(layer, name, value)
|
||||
|
||||
@@ -61,17 +61,11 @@ def unassign_layer(
|
||||
# Let's undo it!
|
||||
ifcopenshell.api.layer.unassign_layer(model, items=[representation.Items[0]], layer=layer)
|
||||
"""
|
||||
settings = {
|
||||
"items": items,
|
||||
"layer": layer,
|
||||
}
|
||||
|
||||
layer = settings["layer"]
|
||||
assigned_items = set(layer.AssignedItems) or set()
|
||||
items = set(settings["items"])
|
||||
if not items.issubset(assigned_items):
|
||||
items_set = set(items)
|
||||
if not items_set.issubset(assigned_items):
|
||||
return
|
||||
assigned_items = list(assigned_items - items)
|
||||
assigned_items = list(assigned_items - items_set)
|
||||
|
||||
# keep IFC valid in case if there are no items left
|
||||
if assigned_items:
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_library(file: ifcopenshell.file, library: ifcopenshell.entity_instance,
|
||||
IfcLibraryInformation, consult the IFC documentation.
|
||||
|
||||
:param library: The IfcLibraryInformation entity you want to edit
|
||||
:type library: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_reference(
|
||||
IfcLibraryReference, consult the IFC documentation.
|
||||
|
||||
:param reference: The IfcLibraryReference entity you want to edit
|
||||
:type reference: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -44,7 +41,5 @@ def edit_reference(
|
||||
ifcopenshell.api.library.edit_reference(model,
|
||||
reference=reference, attributes={"Identification": "http://example.org/digitaltwin#AHU01"})
|
||||
"""
|
||||
settings = {"reference": reference, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["reference"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(reference, name, value)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.representation
|
||||
from typing import Any
|
||||
|
||||
|
||||
def assign_profile(
|
||||
@@ -97,6 +98,7 @@ def assign_profile(
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self) -> None:
|
||||
# TODO: handle composite profiles
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_assigned_material(
|
||||
IfcMaterial, consult the IFC documentation.
|
||||
|
||||
:param element: The IfcMaterial entity you want to edit
|
||||
:type element: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_assigned_material(
|
||||
ifcopenshell.api.material.edit_assigned_material(model,
|
||||
element=concrete, attributes={"Description": "40MPA concrete with broom finish"})
|
||||
"""
|
||||
settings = {"element": element, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["element"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(element, name, value)
|
||||
|
||||
@@ -31,13 +31,9 @@ def edit_constituent(
|
||||
IfcMaterialConstituent, consult the IFC documentation.
|
||||
|
||||
:param constituent: The IfcMaterialConstituent entity you want to edit
|
||||
:type constituent: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:param material: The IfcMaterial entity you want to change the constituent to
|
||||
:type material: ifcopenshell.entity_instance, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -65,8 +61,6 @@ def edit_constituent(
|
||||
ifcopenshell.api.material.edit_constituent(model,
|
||||
constituent=constituent, attributes={"Name": "Glazing"})
|
||||
"""
|
||||
settings = {"constituent": constituent, "attributes": attributes or {}, "material": material}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["constituent"], name, value)
|
||||
settings["constituent"].Material = settings["material"]
|
||||
for name, value in (attributes or {}).items():
|
||||
setattr(constituent, name, value)
|
||||
constituent.Material = material
|
||||
|
||||
@@ -31,14 +31,10 @@ def edit_layer(
|
||||
IfcMaterialLayer, consult the IFC documentation.
|
||||
|
||||
:param layer: The IfcMaterialLayer entity you want to edit
|
||||
:type layer: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:param material: The IfcMaterial entity you want the layer to be made
|
||||
from.
|
||||
:type material: ifcopenshell.entity_instance, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -63,9 +59,7 @@ def edit_layer(
|
||||
layer = ifcopenshell.api.material.add_layer(model, layer_set=material_set, material=gypsum)
|
||||
ifcopenshell.api.material.edit_layer(model, layer=layer, attributes={"LayerThickness": 13})
|
||||
"""
|
||||
settings = {"layer": layer, "attributes": attributes or {}, "material": material}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["layer"], name, value)
|
||||
if settings["material"]:
|
||||
settings["layer"].Material = settings["material"]
|
||||
for name, value in (attributes or {}).items():
|
||||
setattr(layer, name, value)
|
||||
if material:
|
||||
layer.Material = material
|
||||
|
||||
@@ -29,11 +29,8 @@ def edit_layer_usage(file: ifcopenshell.file, usage: ifcopenshell.entity_instanc
|
||||
IfcMaterialLayerSetUsage, consult the IFC documentation.
|
||||
|
||||
:param usage: The IfcMaterialLayerSetUsage entity you want to edit
|
||||
:type usage: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -75,7 +72,5 @@ def edit_layer_usage(file: ifcopenshell.file, usage: ifcopenshell.entity_instanc
|
||||
ifcopenshell.api.material.edit_layer_usage(model,
|
||||
usage=rel.RelatingMaterial, attributes={"OffsetFromReferenceLine": 200})
|
||||
"""
|
||||
settings = {"usage": usage, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["usage"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(usage, name, value)
|
||||
|
||||
@@ -34,17 +34,12 @@ def edit_profile(
|
||||
IfcMaterialProfile, consult the IFC documentation.
|
||||
|
||||
:param profile: The IfcMaterialProfile entity you want to edit
|
||||
:type profile: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:param profile_def: The IfcProfileDef entity the profile curve should be
|
||||
extruded from.
|
||||
:type profile_def: ifcopenshell.entity_instance, optional
|
||||
:param material: The IfcMaterial entity you want to change the profile
|
||||
to be made from.
|
||||
:type material: ifcopenshell.entity_instance, optional
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -80,16 +75,9 @@ def edit_profile(
|
||||
ifcopenshell.api.material.edit_profile(model,
|
||||
profile=profile_item, profile_def=hea200, material=steel2)
|
||||
"""
|
||||
settings = {
|
||||
"profile": profile,
|
||||
"attributes": attributes or {},
|
||||
"profile_def": profile_def,
|
||||
"material": material,
|
||||
}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["profile"], name, value)
|
||||
if settings["material"]:
|
||||
settings["profile"].Material = settings["material"]
|
||||
if settings["profile_def"]:
|
||||
settings["profile"].Profile = settings["profile_def"]
|
||||
for name, value in (attributes or {}).items():
|
||||
setattr(profile, name, value)
|
||||
if material:
|
||||
profile.Material = material
|
||||
if profile_def:
|
||||
profile.Profile = profile_def
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.representation
|
||||
from ifcopenshell.geom import ShapeType
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -34,11 +35,8 @@ def edit_profile_usage(
|
||||
IfcMaterialProfileSetUsage, consult the IFC documentation.
|
||||
|
||||
:param usage: The IfcMaterialProfileSetUsage entity you want to edit
|
||||
:type usage: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -98,16 +96,19 @@ def edit_profile_usage(
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.cardinal_point = self.settings["attributes"].get("CardinalPoint")
|
||||
if self.cardinal_point and self.cardinal_point != self.settings["usage"].CardinalPoint:
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, usage: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
self.attributes = attributes
|
||||
self.cardinal_point = attributes.get("CardinalPoint")
|
||||
if self.cardinal_point and self.cardinal_point != usage.CardinalPoint:
|
||||
self.update_cardinal_point()
|
||||
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["usage"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(usage, name, value)
|
||||
|
||||
def update_cardinal_point(self):
|
||||
material_set = self.settings["usage"].ForProfileSet
|
||||
material_set = self.attributes["usage"].ForProfileSet
|
||||
self.profile = material_set.CompositeProfile
|
||||
if not self.profile and material_set.MaterialProfiles:
|
||||
self.profile = material_set.MaterialProfiles[0].Profile
|
||||
@@ -117,13 +118,13 @@ class Usecase:
|
||||
self.position = self.calculate_position()
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
for rel in self.file.get_inverse(self.settings["usage"]):
|
||||
for rel in self.file.get_inverse(self.attributes["usage"]):
|
||||
if not rel.is_a("IfcRelAssociatesMaterial"):
|
||||
continue
|
||||
for element in rel.RelatedObjects:
|
||||
self.update_representation(element)
|
||||
else:
|
||||
for rel in self.settings["usage"].AssociatedTo:
|
||||
for rel in self.attributes["usage"].AssociatedTo:
|
||||
for element in rel.RelatedObjects:
|
||||
self.update_representation(element)
|
||||
|
||||
@@ -166,7 +167,7 @@ class Usecase:
|
||||
elif self.cardinal_point == 9:
|
||||
return self.get_top_right(shape)
|
||||
|
||||
def get_bottom_left(self, shape):
|
||||
def get_bottom_left(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
@@ -174,13 +175,13 @@ class Usecase:
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((-width / 2, height / 2, 0.0)))
|
||||
|
||||
def get_bottom_centre(self, shape):
|
||||
def get_bottom_centre(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((0.0, height / 2, 0.0)))
|
||||
|
||||
def get_bottom_right(self, shape):
|
||||
def get_bottom_right(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
@@ -188,22 +189,22 @@ class Usecase:
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((width / 2, height / 2, 0.0)))
|
||||
|
||||
def get_mid_depth_left(self, shape):
|
||||
def get_mid_depth_left(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
width = max(x) - min(x)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((-width / 2, 0.0, 0.0)))
|
||||
|
||||
def get_mid_depth_centre(self, shape):
|
||||
def get_mid_depth_centre(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)))
|
||||
|
||||
def get_mid_depth_right(self, shape):
|
||||
def get_mid_depth_right(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
width = max(x) - min(x)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((width / 2, 0.0, 0.0)))
|
||||
|
||||
def get_top_left(self, shape):
|
||||
def get_top_left(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
@@ -211,13 +212,13 @@ class Usecase:
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((-width / 2, -height / 2, 0.0)))
|
||||
|
||||
def get_top_centre(self, shape):
|
||||
def get_top_centre(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((0.0, -height / 2, 0.0)))
|
||||
|
||||
def get_top_right(self, shape):
|
||||
def get_top_right(self, shape: ShapeType) -> ifcopenshell.entity_instance:
|
||||
v = shape.verts
|
||||
x = [v[i] for i in range(0, len(v), 3)]
|
||||
y = [v[i + 1] for i in range(0, len(v), 3)]
|
||||
@@ -225,7 +226,7 @@ class Usecase:
|
||||
height = max(y) - min(y)
|
||||
return self.file.createIfcAxis2Placement3D(self.file.createIfcCartesianPoint((width / 2, -height / 2, 0.0)))
|
||||
|
||||
def update_representation(self, element):
|
||||
def update_representation(self, element: ifcopenshell.entity_instance) -> None:
|
||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
if not representation:
|
||||
return
|
||||
@@ -234,5 +235,5 @@ class Usecase:
|
||||
if subelement.is_a("IfcSweptAreaSolid") and subelement.SweptArea == self.profile:
|
||||
self.update_swept_area_solid(subelement)
|
||||
|
||||
def update_swept_area_solid(self, element):
|
||||
def update_swept_area_solid(self, element: ifcopenshell.entity_instance) -> None:
|
||||
element.Position = self.position
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def remove_constituent(
|
||||
|
||||
@@ -54,8 +54,6 @@ def remove_list_item(
|
||||
# Let's remove the glass
|
||||
ifcopenshell.api.material.remove_list_item(model, material_list=material_set, material_index=1)
|
||||
"""
|
||||
settings = {"material_list": material_list, "material_index": material_index}
|
||||
|
||||
materials = list(settings["material_list"].Materials)
|
||||
materials.pop(settings["material_index"])
|
||||
settings["material_list"].Materials = materials
|
||||
materials = list(material_list.Materials)
|
||||
materials.pop(material_index)
|
||||
material_list.Materials = materials
|
||||
|
||||
@@ -57,16 +57,17 @@ def reorder_set_item(
|
||||
ifcopenshell.api.material.reorder_set_item(model,
|
||||
material_set=material_set, old_index=0, new_index=1)
|
||||
"""
|
||||
settings = {"material_set": material_set, "old_index": old_index, "new_index": new_index}
|
||||
|
||||
if settings["material_set"].is_a("IfcMaterialConstituentSet"):
|
||||
if material_set.is_a("IfcMaterialConstituentSet"):
|
||||
set_name = "MaterialConstituents"
|
||||
elif settings["material_set"].is_a("IfcMaterialLayerSet"):
|
||||
elif material_set.is_a("IfcMaterialLayerSet"):
|
||||
set_name = "MaterialLayers"
|
||||
elif settings["material_set"].is_a("IfcMaterialProfileSet"):
|
||||
elif material_set.is_a("IfcMaterialProfileSet"):
|
||||
set_name = "MaterialProfiles"
|
||||
elif settings["material_set"].is_a("IfcMaterialList"):
|
||||
elif material_set.is_a("IfcMaterialList"):
|
||||
set_name = "Materials"
|
||||
items = list(getattr(settings["material_set"], set_name) or [])
|
||||
items.insert(settings["new_index"], items.pop(settings["old_index"]))
|
||||
setattr(settings["material_set"], set_name, items)
|
||||
else:
|
||||
raise ValueError(f"Unexpected material set type: '{material_set.is_a()}'.")
|
||||
|
||||
items = list(getattr(material_set, set_name) or [])
|
||||
items.insert(new_index, items.pop(old_index))
|
||||
setattr(material_set, set_name, items)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.owner
|
||||
import ifcopenshell.util.element
|
||||
from typing import Any
|
||||
|
||||
|
||||
def unassign_material(file: ifcopenshell.file, products: list[ifcopenshell.entity_instance]) -> None:
|
||||
@@ -58,6 +59,9 @@ def unassign_material(file: ifcopenshell.file, products: list[ifcopenshell.entit
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
self.products = set(self.settings["products"])
|
||||
if not self.products:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.api
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
|
||||
def add_application(
|
||||
@@ -68,6 +68,9 @@ def add_application(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
if not self.settings["application_developer"]:
|
||||
self.settings["application_developer"] = self.create_application_organisation()
|
||||
|
||||
@@ -48,16 +48,14 @@ def add_role(
|
||||
identification="AWB", name="Architects Without Ballpens")
|
||||
ifcopenshell.api.owner.add_role(model, assigned_object=organisation, role="ARCHITECT")
|
||||
"""
|
||||
settings = {"assigned_object": assigned_object, "role": role}
|
||||
|
||||
element = file.createIfcActorRole("ARCHITECT")
|
||||
if settings["role"]:
|
||||
element = file.create_entity("IfcActorRole", Role="ARCHITECT")
|
||||
if role:
|
||||
try:
|
||||
element.Role = settings["role"]
|
||||
element.Role = role
|
||||
except:
|
||||
element.Role = "USERDEFINED"
|
||||
element.UserDefinedRole = settings["role"]
|
||||
roles = list(settings["assigned_object"].Roles) if settings["assigned_object"].Roles else []
|
||||
element.UserDefinedRole = role
|
||||
roles = list(assigned_object.Roles) if assigned_object.Roles else []
|
||||
roles.append(element)
|
||||
settings["assigned_object"].Roles = roles
|
||||
assigned_object.Roles = roles
|
||||
return element
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance, att
|
||||
IfcActor, consult the IFC documentation.
|
||||
|
||||
:param actor: The IfcActor entity you want to edit
|
||||
:type actor: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -49,7 +46,5 @@ def edit_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance, att
|
||||
ifcopenshell.api.actor.edit_actor(model,
|
||||
actor=actor, attributes={"Description": "Responsible for buildings A, B, and C."})
|
||||
"""
|
||||
settings = {"actor": actor, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["actor"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(actor, name, value)
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_address(file: ifcopenshell.file, address: ifcopenshell.entity_instance,
|
||||
IfcAddress, consult the IFC documentation.
|
||||
|
||||
:param address: The IfcAddress entity you want to edit
|
||||
:type address: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -51,7 +48,5 @@ def edit_address(file: ifcopenshell.file, address: ifcopenshell.entity_instance,
|
||||
"ElectronicMailAddresses": ["bobthebuilder@example.com"],
|
||||
"WWWHomePageURL": "https://thinkmoult.com"})
|
||||
"""
|
||||
settings = {"address": address, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["address"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(address, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_organisation(
|
||||
IfcOrganization, consult the IFC documentation.
|
||||
|
||||
:param organisation: The IfcOrganization entity you want to edit
|
||||
:type organisation: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -43,7 +40,5 @@ def edit_organisation(
|
||||
ifcopenshell.api.owner.edit_organisation(model, organisation=organisation,
|
||||
attributes={"name": "Architects Without Ballpens"})
|
||||
"""
|
||||
settings = {"organisation": organisation, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["organisation"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(organisation, name, value)
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance, a
|
||||
IfcPerson, consult the IFC documentation.
|
||||
|
||||
:param person: The IfcPerson entity you want to edit
|
||||
:type person: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -41,7 +38,5 @@ def edit_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance, a
|
||||
ifcopenshell.api.owner.edit_person(model, person=person,
|
||||
attributes={"MiddleNames": ["The"], "FamilyName": "Builder"})
|
||||
"""
|
||||
settings = {"person": person, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["person"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(person, name, value)
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance, attri
|
||||
IfcActorRole, consult the IFC documentation.
|
||||
|
||||
:param role: The IfcActorRole entity you want to edit
|
||||
:type role: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -45,7 +42,5 @@ def edit_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance, attri
|
||||
# But Bob is not an architect
|
||||
ifcopenshell.api.owner.edit_role(model, role=role, attributes={"Role": "CONSTRUCTIONMANAGER"})
|
||||
"""
|
||||
settings = {"role": role, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["role"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(role, name, value)
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import numpy.typing as npt
|
||||
import ifcopenshell.util.unit
|
||||
from typing import Optional
|
||||
from ifcopenshell.util.shape_builder import V, SequenceOfVectors, ifc_safe_vector_type
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def add_arbitrary_profile(
|
||||
file: ifcopenshell.file, profile: list[tuple[float, float]], name: Optional[str] = None
|
||||
file: ifcopenshell.file, profile: SequenceOfVectors, name: Optional[str] = None
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new arbitrary polyline-based profile
|
||||
|
||||
@@ -33,13 +35,10 @@ def add_arbitrary_profile(
|
||||
identical.
|
||||
|
||||
:param profile: A list of coordinates
|
||||
:type profile: list[tuple[float, float]]
|
||||
:param name: If the profile is semantically significant (i.e. to be
|
||||
managed and reused by the user) then it must be named. Otherwise,
|
||||
this may be left as none.
|
||||
:type name: str, optional
|
||||
:return: The newly created IfcArbitraryClosedProfileDef
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -53,26 +52,30 @@ def add_arbitrary_profile(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"profile": profile, "name": name}
|
||||
return usecase.execute()
|
||||
return usecase.execute(V(profile), name)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
points = [self.convert_si_to_unit(p) for p in self.settings["profile"]]
|
||||
if self.file.schema == "IFC2X3":
|
||||
curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in points])
|
||||
else:
|
||||
dimensions = len(points[0])
|
||||
if dimensions == 2:
|
||||
ifc_points = self.file.createIfcCartesianPointList2D(points)
|
||||
elif dimensions == 3:
|
||||
ifc_points = self.file.createIfcCartesianPointList3D(points)
|
||||
curve = self.file.createIfcIndexedPolyCurve(ifc_points)
|
||||
return self.file.createIfcArbitraryClosedProfileDef("AREA", self.settings["name"], curve)
|
||||
file: ifcopenshell.file
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
if isinstance(co, (tuple, list)):
|
||||
return [self.convert_si_to_unit(o) for o in co]
|
||||
return co / self.settings["unit_scale"]
|
||||
def execute(self, profile: npt.NDArray, name: Union[str, None]):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
points = self.convert_si_to_unit(profile)
|
||||
if self.file.schema == "IFC2X3":
|
||||
curve = self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in points],
|
||||
)
|
||||
else:
|
||||
dimensions = points.shape[1]
|
||||
if dimensions == 2:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList2D", ifc_safe_vector_type(points))
|
||||
elif dimensions == 3:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(points))
|
||||
else:
|
||||
assert False, f"Invalid dimensions: {dimensions}."
|
||||
curve = self.file.create_entity("IfcIndexedPolyCurve", ifc_points)
|
||||
return self.file.create_entity("IfcArbitraryClosedProfileDef", "AREA", name, curve)
|
||||
|
||||
def convert_si_to_unit(self, co: npt.NDArray) -> npt.NDArray:
|
||||
return co / self.unit_scale
|
||||
|
||||
+42
-29
@@ -17,13 +17,15 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
from typing import Optional
|
||||
import numpy.typing as npt
|
||||
from ifcopenshell.util.shape_builder import SequenceOfVectors, ifc_safe_vector_type, V
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def add_arbitrary_profile_with_voids(
|
||||
file: ifcopenshell.file,
|
||||
outer_profile: list[tuple[float, float]],
|
||||
inner_profiles: list[list[tuple[float, float]]],
|
||||
outer_profile: SequenceOfVectors,
|
||||
inner_profiles: list[SequenceOfVectors],
|
||||
name: Optional[str] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new arbitrary polyline-based profile with voids
|
||||
@@ -41,15 +43,11 @@ def add_arbitrary_profile_with_voids(
|
||||
provided in SI meters.
|
||||
|
||||
:param outer_profile: A list of coordinates
|
||||
:type profile: list[tuple[float, float]]
|
||||
:param inner_profiles: A list of polylines
|
||||
:type profile: list[list[tuple[float, float]]]
|
||||
:param name: If the profile is semantically significant (i.e. to be
|
||||
managed and reused by the user) then it must be named. Otherwise,
|
||||
this may be left as none.
|
||||
:type name: str, optional
|
||||
:return: The newly created IfcArbitraryProfileDefWithVoids
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -63,37 +61,52 @@ def add_arbitrary_profile_with_voids(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"outer_profile": outer_profile, "inner_profiles": inner_profiles, "name": name}
|
||||
return usecase.execute()
|
||||
return usecase.execute(V(outer_profile), [V(p) for p in inner_profiles], name)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.settings["unit_scale"] = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
outer_points = [self.convert_si_to_unit(p) for p in self.settings["outer_profile"]]
|
||||
inner_points = []
|
||||
for inner_profile in self.settings["inner_profiles"]:
|
||||
inner_points.append([self.convert_si_to_unit(p) for p in inner_profile])
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(
|
||||
self,
|
||||
outer_profile: npt.NDArray,
|
||||
inner_profiles: list[npt.NDArray],
|
||||
name: Union[str, None],
|
||||
):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
outer_points = self.convert_si_to_unit(outer_profile)
|
||||
inner_points: list[npt.NDArray] = []
|
||||
for inner_profile in inner_profiles:
|
||||
inner_points.append(self.convert_si_to_unit(inner_profile))
|
||||
|
||||
inner_curves: list[ifcopenshell.entity_instance] = []
|
||||
if self.file.schema == "IFC2X3":
|
||||
outer_curve = self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in outer_points])
|
||||
inner_curves = []
|
||||
outer_curve = self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in outer_points],
|
||||
)
|
||||
for inner_point in inner_points:
|
||||
inner_curves.append(
|
||||
self.file.createIfcPolyline([self.file.createIfcCartesianPoint(p) for p in inner_point])
|
||||
self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in inner_point],
|
||||
)
|
||||
)
|
||||
else:
|
||||
outer_curve = self.file.createIfcIndexedPolyCurve(self.file.createIfcCartesianPointList3D(outer_points))
|
||||
inner_curves = []
|
||||
outer_curve = self.file.create_entity(
|
||||
"IfcIndexedPolyCurve",
|
||||
(self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(outer_points))),
|
||||
)
|
||||
for inner_point in inner_points:
|
||||
dimensions = len(inner_point[0])
|
||||
dimensions = inner_point.shape[1]
|
||||
if dimensions == 2:
|
||||
ifc_points = self.file.createIfcCartesianPointList2D(inner_point)
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList2D", ifc_safe_vector_type(inner_point))
|
||||
elif dimensions == 3:
|
||||
ifc_points = self.file.createIfcCartesianPointList3D(inner_point)
|
||||
inner_curves.append(self.file.createIfcIndexedPolyCurve(ifc_points))
|
||||
return self.file.createIfcArbitraryProfileDefWithVoids("AREA", self.settings["name"], outer_curve, inner_curves)
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(inner_point))
|
||||
else:
|
||||
assert False, f"Invalid dimensions: {dimensions}."
|
||||
inner_curves.append(self.file.create_entity("IfcIndexedPolyCurve", ifc_points))
|
||||
return self.file.create_entity("IfcArbitraryProfileDefWithVoids", "AREA", name, outer_curve, inner_curves)
|
||||
|
||||
def convert_si_to_unit(self, co):
|
||||
if isinstance(co, (tuple, list)):
|
||||
return [self.convert_si_to_unit(o) for o in co]
|
||||
return co / self.settings["unit_scale"]
|
||||
def convert_si_to_unit(self, co: npt.NDArray) -> npt.NDArray:
|
||||
return co / self.unit_scale
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instance,
|
||||
IfcProfileDef, consult the IFC documentation.
|
||||
|
||||
:param profile: The IfcProfileDef entity you want to edit
|
||||
:type profile: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -43,7 +40,5 @@ def edit_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instance,
|
||||
ifcopenshell.api.profile.edit_profile(model,
|
||||
profile=circle, attributes={"ProfileName": "1000mm Dia"})
|
||||
"""
|
||||
settings = {"profile": profile, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["profile"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(profile, name, value)
|
||||
|
||||
@@ -20,7 +20,7 @@ import ifcopenshell
|
||||
import ifcopenshell.api.owner
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.guid
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
|
||||
def add_pset(
|
||||
@@ -92,12 +92,11 @@ def add_pset(
|
||||
# Add a fire rating property standardised by buildingSMART.
|
||||
ifcopenshell.api.pset.edit_pset(model, pset=pset, properties={"FireRating": "2HR"})
|
||||
"""
|
||||
settings = {"product": product, "name": name}
|
||||
is_ifc2x3 = file.schema == "IFC2X3"
|
||||
|
||||
if settings["product"].is_a("IfcObject") or settings["product"].is_a("IfcContext"):
|
||||
for rel in settings["product"].IsDefinedBy or []:
|
||||
if rel.is_a("IfcRelDefinesByProperties") and rel.RelatingPropertyDefinition.Name == settings["name"]:
|
||||
if product.is_a("IfcObject") or product.is_a("IfcContext"):
|
||||
for rel in product.IsDefinedBy or []:
|
||||
if rel.is_a("IfcRelDefinesByProperties") and rel.RelatingPropertyDefinition.Name == name:
|
||||
return rel.RelatingPropertyDefinition
|
||||
|
||||
pset = file.create_entity(
|
||||
@@ -105,15 +104,15 @@ def add_pset(
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"Name": settings["name"],
|
||||
"Name": name,
|
||||
},
|
||||
)
|
||||
ifcopenshell.api.pset.assign_pset(file, [settings["product"]], pset)
|
||||
ifcopenshell.api.pset.assign_pset(file, [product], pset)
|
||||
return pset
|
||||
|
||||
elif settings["product"].is_a("IfcTypeObject"):
|
||||
for definition in settings["product"].HasPropertySets or []:
|
||||
if definition.Name == settings["name"]:
|
||||
elif product.is_a("IfcTypeObject"):
|
||||
for definition in product.HasPropertySets or []:
|
||||
if definition.Name == name:
|
||||
return definition
|
||||
|
||||
pset = file.create_entity(
|
||||
@@ -121,42 +120,43 @@ def add_pset(
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"Name": settings["name"],
|
||||
"Name": name,
|
||||
},
|
||||
)
|
||||
ifcopenshell.api.pset.assign_pset(file, [settings["product"]], pset)
|
||||
ifcopenshell.api.pset.assign_pset(file, [product], pset)
|
||||
return pset
|
||||
|
||||
# in IFC2X3 IfcMaterialDefinition not yet existed
|
||||
elif settings["product"].is_a("IfcMaterialDefinition") or settings["product"].is_a("IfcMaterial"):
|
||||
kwargs = {"Material": settings["product"]}
|
||||
elif product.is_a("IfcMaterialDefinition") or product.is_a("IfcMaterial"):
|
||||
kwargs: dict[str, Any]
|
||||
kwargs = {"Material": product}
|
||||
if file.schema == "IFC2X3":
|
||||
ifc_class = ifc2x3_subclass or "IfcExtendedMaterialProperties"
|
||||
definitions = (d for d in file.by_type("IfcMaterialProperties") if d.Material == settings["product"])
|
||||
definitions = (d for d in file.by_type("IfcMaterialProperties") if d.Material == product)
|
||||
if ifc_class == "IfcExtendedMaterialProperties":
|
||||
kwargs["Name"] = settings["name"]
|
||||
kwargs["Name"] = name
|
||||
else:
|
||||
ifc_class = "IfcMaterialProperties"
|
||||
definitions = settings["product"].HasProperties
|
||||
kwargs["Name"] = settings["name"]
|
||||
definitions = product.HasProperties
|
||||
kwargs["Name"] = name
|
||||
for definition in definitions:
|
||||
# In IFC2X3 not all IfcMaterialProperties has Name
|
||||
if getattr(definition, "Name", None) == settings["name"]:
|
||||
if getattr(definition, "Name", None) == name:
|
||||
return definition
|
||||
|
||||
return file.create_entity(ifc_class, **kwargs)
|
||||
|
||||
elif settings["product"].is_a("IfcProfileDef"):
|
||||
elif product.is_a("IfcProfileDef"):
|
||||
# in IFC2X3 IfcProfileProperties doesn't have Name and we cannot identify them
|
||||
if file.schema != "IFC2X3":
|
||||
for definition in settings["product"].HasProperties or []:
|
||||
if definition.Name == settings["name"]:
|
||||
for definition in product.HasProperties or []:
|
||||
if definition.Name == name:
|
||||
return definition
|
||||
|
||||
kwargs = {}
|
||||
kwargs["ProfileDefinition"] = settings["product"]
|
||||
kwargs["ProfileDefinition"] = product
|
||||
if file.schema != "IFC2X3":
|
||||
kwargs["Name"] = settings["name"]
|
||||
kwargs["Name"] = name
|
||||
|
||||
if is_ifc2x3:
|
||||
ifc_class = ifc2x3_subclass or "IfcGeneralProfileProperties"
|
||||
@@ -164,4 +164,4 @@ def add_pset(
|
||||
ifc_class = "IfcProfileProperties"
|
||||
return file.create_entity(ifc_class, **kwargs)
|
||||
|
||||
raise TypeError(f"Class '{settings['product'].is_a(True)}' doesn't support adding a property set.")
|
||||
raise TypeError(f"Class '{product.is_a(True)}' doesn't support adding a property set.")
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.owner
|
||||
import ifcopenshell.guid
|
||||
from typing import Any
|
||||
|
||||
|
||||
def add_qto(file: ifcopenshell.file, product: ifcopenshell.entity_instance, name: str) -> ifcopenshell.entity_instance:
|
||||
@@ -83,9 +84,15 @@ def add_qto(file: ifcopenshell.file, product: ifcopenshell.entity_instance, name
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
if self.settings["product"].is_a("IfcObject") or self.settings["product"].is_a("IfcContext"):
|
||||
for rel in self.settings["product"].IsDefinedBy or []:
|
||||
product: ifcopenshell.entity_instance = self.settings["product"]
|
||||
name: str = self.settings["name"]
|
||||
|
||||
if product.is_a("IfcObject") or product.is_a("IfcContext"):
|
||||
for rel in product.IsDefinedBy or []:
|
||||
if (
|
||||
rel.is_a("IfcRelDefinesByProperties")
|
||||
and rel.RelatingPropertyDefinition.Name == self.settings["name"]
|
||||
@@ -103,14 +110,14 @@ class Usecase:
|
||||
}
|
||||
)
|
||||
return qto
|
||||
elif self.settings["product"].is_a("IfcTypeObject"):
|
||||
for definition in self.settings["product"].HasPropertySets or []:
|
||||
if definition.Name == self.settings["name"]:
|
||||
elif product.is_a("IfcTypeObject"):
|
||||
for definition in product.HasPropertySets or []:
|
||||
if definition.Name == name:
|
||||
return definition
|
||||
qto = self.create_qto()
|
||||
has_property_sets = list(self.settings["product"].HasPropertySets or [])
|
||||
has_property_sets = list(product.HasPropertySets or [])
|
||||
has_property_sets.append(qto)
|
||||
self.settings["product"].HasPropertySets = has_property_sets
|
||||
product.HasPropertySets = has_property_sets
|
||||
return qto
|
||||
|
||||
def create_qto(self):
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_prop_template(
|
||||
IfcSimplePropertyTemplate, consult the IFC documentation.
|
||||
|
||||
:param prop_template: The IfcSimplePropertyTemplate entity you want to edit
|
||||
:type prop_template: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_pset_template(
|
||||
IfcPropertySetTemplate, consult the IFC documentation.
|
||||
|
||||
:param pset_template: The IfcPropertySetTemplate entity you want to edit
|
||||
:type pset_template: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -45,7 +42,5 @@ def edit_pset_template(
|
||||
ifcopenshell.api.pset_template.edit_pset_template(model,
|
||||
pset_template=template, attributes={"Name": "ABC_RiskFactors"})
|
||||
"""
|
||||
settings = {"pset_template": pset_template, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["pset_template"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(pset_template, name, value)
|
||||
|
||||
@@ -36,15 +36,12 @@ def add_resource_quantity(
|
||||
This base quantity is then used in other calculations.
|
||||
|
||||
:param resource: The IfcConstructionResource to add a quantity to.
|
||||
:type resource: ifcopenshell.entity_instance
|
||||
:param ifc_class: The type of quantity to add, chosen from
|
||||
IfcQuantityArea (for material), IfcQuantityCount (for products),
|
||||
IfcQuantityLength (for material), IfcQuantityTime (for equipment or
|
||||
labour), IfcQuantityVolume (for material), and IfcQuantityWeight
|
||||
(for material).
|
||||
:type ifc_class: str,optional
|
||||
:return: The newly created quantity depending on the IFC class
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -65,8 +62,6 @@ def add_resource_quantity(
|
||||
ifcopenshell.api.resource.edit_resource_quantity(model,
|
||||
physical_quantity=quantity, attributes={"TimeValue": 8.0})
|
||||
"""
|
||||
settings = {"resource": resource, "ifc_class": ifc_class}
|
||||
|
||||
resource_type = resource.is_a()
|
||||
supported_quantities = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES[resource_type]
|
||||
if ifc_class not in supported_quantities:
|
||||
@@ -75,14 +70,14 @@ def add_resource_quantity(
|
||||
f"Supported quantities: {','.join(supported_quantities)}"
|
||||
)
|
||||
|
||||
quantity = file.create_entity(settings["ifc_class"], Name="Unnamed")
|
||||
quantity = file.create_entity(ifc_class, Name="Unnamed")
|
||||
# 3 IfcPhysicalSimpleQuantity Value
|
||||
if settings["ifc_class"] == "IfcQuantityCount":
|
||||
if ifc_class == "IfcQuantityCount":
|
||||
quantity[3] = 0
|
||||
else:
|
||||
quantity[3] = 0.0
|
||||
old_quantity = settings["resource"].BaseQuantity
|
||||
settings["resource"].BaseQuantity = quantity
|
||||
old_quantity = resource.BaseQuantity
|
||||
resource.BaseQuantity = quantity
|
||||
if old_quantity:
|
||||
ifcopenshell.util.element.remove_deep(file, old_quantity)
|
||||
return quantity
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_instanc
|
||||
IfcResource, consult the IFC documentation.
|
||||
|
||||
:param resource: The IfcResource entity you want to edit
|
||||
:type resource: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -42,7 +39,5 @@ def edit_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_instanc
|
||||
# Change the name of the resource to "Zone A Crew"
|
||||
ifcopenshell.api.resource.edit_resource(model, resource=resource, attributes={"Name": "Foo"})
|
||||
"""
|
||||
settings = {"resource": resource, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["resource"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(resource, name, value)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_resource_quantity(
|
||||
IfC quantity, consult the IFC documentation.
|
||||
|
||||
:param physical_quantity: The IfC quantity entity you want to edit
|
||||
:type physical_quantity: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -53,10 +50,5 @@ def edit_resource_quantity(
|
||||
ifcopenshell.api.resource.edit_resource_quantity(model,
|
||||
physical_quantity=time, attributes={"TimeValue": 8.0})
|
||||
"""
|
||||
settings = {
|
||||
"physical_quantity": physical_quantity,
|
||||
"attributes": attributes,
|
||||
}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["physical_quantity"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(physical_quantity, name, value)
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.sequence
|
||||
import ifcopenshell.util.constraint
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.resource
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -30,11 +33,8 @@ def edit_resource_time(
|
||||
IfcResourceTime, consult the IFC documentation.
|
||||
|
||||
:param resource_time: The IfcResourceTime entity you want to edit
|
||||
:type resource_time: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -62,25 +62,23 @@ def edit_resource_time(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"resource_time": resource_time, "attributes": attributes}
|
||||
return usecase.execute()
|
||||
return usecase.execute(resource_time, attributes)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
self.resource = self.get_resource()
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, resource_time: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
resource = self.get_resource(resource_time)
|
||||
|
||||
# If the user specifies both an end date and a duration, the duration takes priority
|
||||
if (
|
||||
self.settings["attributes"].get("ScheduleWork", None)
|
||||
and "ScheduleFinish" in self.settings["attributes"].keys()
|
||||
):
|
||||
del self.settings["attributes"]["ScheduleFinish"]
|
||||
if self.settings["attributes"].get("ActualWork", None) and "ActualFinish" in self.settings["attributes"].keys():
|
||||
del self.settings["attributes"]["ActualFinish"]
|
||||
if attributes.get("ScheduleWork", None) and "ScheduleFinish" in attributes.keys():
|
||||
del attributes["ScheduleFinish"]
|
||||
if attributes.get("ActualWork", None) and "ActualFinish" in attributes.keys():
|
||||
del attributes["ActualFinish"]
|
||||
|
||||
for name, value in self.settings["attributes"].items():
|
||||
metrics = ifcopenshell.util.constraint.get_metric_constraints(self.resource, "Usage." + name)
|
||||
for name, value in attributes.items():
|
||||
metrics = ifcopenshell.util.constraint.get_metric_constraints(resource, "Usage." + name)
|
||||
if metrics and ifcopenshell.util.constraint.is_hard_constraint(metrics[0]):
|
||||
continue
|
||||
if value:
|
||||
@@ -88,13 +86,13 @@ class Usecase:
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||
elif name == "ScheduleWork" or name == "ActualWork" or name == "RemainingTime":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||
setattr(self.settings["resource_time"], name, value)
|
||||
setattr(resource_time, name, value)
|
||||
if name == "ScheduleUsage" and ifcopenshell.util.constraint.get_metric_constraints(
|
||||
self.resource, "Usage.ScheduleWork"
|
||||
resource, "Usage.ScheduleWork"
|
||||
):
|
||||
task = ifcopenshell.util.resource.get_task_assignments(self.resource)
|
||||
task = ifcopenshell.util.resource.get_task_assignments(resource)
|
||||
if task:
|
||||
ifcopenshell.api.sequence.calculate_task_duration(self.file, task=task)
|
||||
|
||||
def get_resource(self):
|
||||
return [e for e in self.file.get_inverse(self.settings["resource_time"]) if e.is_a("IfcResource")][0]
|
||||
def get_resource(self, resource_time: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
return next(e for e in self.file.get_inverse(resource_time) if e.is_a("IfcResource"))
|
||||
|
||||
@@ -23,6 +23,7 @@ import ifcopenshell.api.geometry
|
||||
import ifcopenshell.util.system
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
from typing import Any
|
||||
|
||||
|
||||
def copy_class(file: ifcopenshell.file, product: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
@@ -74,6 +75,9 @@ def copy_class(file: ifcopenshell.file, product: ifcopenshell.entity_instance) -
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
result = ifcopenshell.util.element.copy(self.file, self.settings["product"])
|
||||
self.copy_direct_attributes(result)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.owner
|
||||
import ifcopenshell.guid
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
|
||||
def create_entity(
|
||||
@@ -80,6 +80,9 @@ def create_entity(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
element = self.file.create_entity(
|
||||
self.settings["ifc_class"],
|
||||
|
||||
@@ -27,7 +27,7 @@ import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.type
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.element
|
||||
from typing import Optional, Union, Literal
|
||||
from typing import Optional, Union, Literal, Any
|
||||
|
||||
|
||||
def reassign_class(
|
||||
@@ -87,6 +87,7 @@ def reassign_class(
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
ifc_class: str = self.settings["ifc_class"]
|
||||
|
||||
@@ -29,11 +29,8 @@ def add_task_time(
|
||||
(especially for maintenance tasks).
|
||||
|
||||
:param task: The task to add time data to.
|
||||
:type task: ifcopenshell.entity_instance
|
||||
:param is_recurring: Whether or not the time should recur.
|
||||
:type is_recurring: bool
|
||||
:return: The newly created IfcTaskTime.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -61,11 +58,9 @@ def add_task_time(
|
||||
ifcopenshell.api.sequence.edit_task_time(model,
|
||||
task_time=time, attributes={"ScheduleStart": "2000-01-01", "ScheduleDuration": "P2D"})
|
||||
"""
|
||||
settings = {"task": task, "is_recurring": is_recurring}
|
||||
|
||||
if settings["is_recurring"]:
|
||||
if is_recurring:
|
||||
task_time = file.create_entity("IfcTaskTimeRecurring")
|
||||
else:
|
||||
task_time = file.create_entity("IfcTaskTime")
|
||||
settings["task"].TaskTime = task_time
|
||||
task.TaskTime = task_time
|
||||
return task_time
|
||||
|
||||
@@ -34,17 +34,13 @@ def assign_lag_time(
|
||||
are allowed.
|
||||
|
||||
:param rel_sequence: The IfcRelSequence to assign the lag time to.
|
||||
:type rel_sequence: ifcopenshell.entity_instance
|
||||
:param lag_value: An ISO standardised duration string.
|
||||
:type lag_value: str
|
||||
:param duration_type: Choose from WORKTIME for the associated
|
||||
calendar-based lag times (this is the most common scenario and is
|
||||
recommended as a default), or ELAPSEDTIME to not follow the
|
||||
calendar. You may also choose NOTDEFINED but the behaviour of this
|
||||
is unclear.
|
||||
:type duration_type: str
|
||||
:return: The newly created IfcLagTime
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -84,16 +80,10 @@ def assign_lag_time(
|
||||
# for whatever reason.
|
||||
ifcopenshell.api.sequence.assign_lag_time(model, rel_sequence=sequence, lag_value="P1D")
|
||||
"""
|
||||
settings = {
|
||||
"rel_sequence": rel_sequence,
|
||||
"lag_value": lag_value,
|
||||
"duration_type": duration_type,
|
||||
}
|
||||
|
||||
lag_value = file.createIfcDuration(ifcopenshell.util.date.datetime2ifc(settings["lag_value"], "IfcDuration"))
|
||||
lag_time = file.create_entity("IfcLagTime", DurationType=settings["duration_type"], LagValue=lag_value)
|
||||
if settings["rel_sequence"].is_a("IfcRelSequence"):
|
||||
if settings["rel_sequence"].TimeLag and len(file.get_inverse(settings["rel_sequence"].TimeLag)) == 1:
|
||||
file.remove(settings["rel_sequence"].TimeLag)
|
||||
settings["rel_sequence"].TimeLag = lag_time
|
||||
lag_value = file.create_entity("IfcDuration", ifcopenshell.util.date.datetime2ifc(lag_value, "IfcDuration"))
|
||||
lag_time = file.create_entity("IfcLagTime", DurationType=duration_type, LagValue=lag_value)
|
||||
if rel_sequence.is_a("IfcRelSequence"):
|
||||
if rel_sequence.TimeLag and len(file.get_inverse(rel_sequence.TimeLag)) == 1:
|
||||
file.remove(rel_sequence.TimeLag)
|
||||
rel_sequence.TimeLag = lag_time
|
||||
return lag_time
|
||||
|
||||
@@ -65,11 +65,8 @@ def assign_recurrence_pattern(
|
||||
:param parent: Either an IfcTaskTimeRecurring if you are defining a
|
||||
recurring schedule for a task, or IfcWorkTime if you are defining a
|
||||
recurring pattern for a workdays or holidays in a calendar.
|
||||
:type parent: ifcopenshell.entity_instance
|
||||
:param recurrence_type: One of the types of recurrences.
|
||||
:type recurrence_type: str
|
||||
:return: The newly created IfcRecurrencePattern
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -108,16 +105,14 @@ def assign_recurrence_pattern(
|
||||
ifcopenshell.api.sequence.edit_recurrence_pattern(model,
|
||||
recurrence_pattern=pattern, attributes={"DayComponent": [1], "Interval": 6})
|
||||
"""
|
||||
settings = {"parent": parent, "recurrence_type": recurrence_type}
|
||||
recurrence = file.create_entity("IfcRecurrencePattern", recurrence_type)
|
||||
|
||||
recurrence = file.createIfcRecurrencePattern(settings["recurrence_type"])
|
||||
|
||||
if settings["parent"].is_a("IfcWorkTime"):
|
||||
if settings["parent"].RecurrencePattern and len(file.get_inverse(settings["parent"].RecurrencePattern)) == 1:
|
||||
file.remove(settings["parent"].RecurrencePattern)
|
||||
settings["parent"].RecurrencePattern = recurrence
|
||||
elif settings["parent"].is_a("IfcTaskTimeRecurring"):
|
||||
if recurrence_old := settings["parent"].Recurrence and len(file.get_inverse(recurrence_old)) == 1:
|
||||
if parent.is_a("IfcWorkTime"):
|
||||
if parent.RecurrencePattern and len(file.get_inverse(parent.RecurrencePattern)) == 1:
|
||||
file.remove(parent.RecurrencePattern)
|
||||
parent.RecurrencePattern = recurrence
|
||||
elif parent.is_a("IfcTaskTimeRecurring"):
|
||||
if (recurrence_old := parent.Recurrence) and len(file.get_inverse(recurrence_old)) == 1:
|
||||
file.remove(recurrence_old)
|
||||
settings["parent"].Recurrence = recurrence
|
||||
parent.Recurrence = recurrence
|
||||
return recurrence
|
||||
|
||||
@@ -51,13 +51,10 @@ def assign_sequence(
|
||||
predecessor and successor tasks in the planning profession.
|
||||
|
||||
:param relating_process: The previous / predecessor task.
|
||||
:type relating_process: ifcopenshell.entity_instance
|
||||
:param related_process: The next / successor task.
|
||||
:type related_process: ifcopenshell.entity_instance
|
||||
:param sequence_type: Choose from FINISH_START, FINISH_FINISH,
|
||||
START_START, or START_FINISH.
|
||||
:return: The newly created IfcRelSequence
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -109,24 +106,18 @@ def assign_sequence(
|
||||
# to be 2000-01-05.
|
||||
ifcopenshell.api.sequence.cascade_schedule(model, task=formwork)
|
||||
"""
|
||||
settings = {
|
||||
"relating_process": relating_process,
|
||||
"related_process": related_process,
|
||||
"sequence_type": sequence_type,
|
||||
}
|
||||
|
||||
for rel in settings["related_process"].IsSuccessorFrom or []:
|
||||
if rel.RelatingProcess == settings["relating_process"]:
|
||||
for rel in related_process.IsSuccessorFrom or []:
|
||||
if rel.RelatingProcess == relating_process:
|
||||
return rel
|
||||
rel = file.create_entity(
|
||||
"IfcRelSequence",
|
||||
**{
|
||||
"GlobalId": ifcopenshell.guid.new(),
|
||||
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
|
||||
"RelatingProcess": settings["relating_process"],
|
||||
"RelatedProcess": settings["related_process"],
|
||||
"SequenceType": settings["sequence_type"],
|
||||
"RelatingProcess": relating_process,
|
||||
"RelatedProcess": related_process,
|
||||
"SequenceType": sequence_type,
|
||||
}
|
||||
)
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=settings["relating_process"])
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=relating_process)
|
||||
return rel
|
||||
|
||||
@@ -20,6 +20,7 @@ import math
|
||||
import ifcopenshell.api.sequence
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.element
|
||||
from typing import Union
|
||||
|
||||
|
||||
def calculate_task_duration(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> None:
|
||||
@@ -35,9 +36,7 @@ def calculate_task_duration(file: ifcopenshell.file, task: ifcopenshell.entity_i
|
||||
then nothing happens.
|
||||
|
||||
:param task: The IfcTask to calculate the duration for.
|
||||
:type task: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -82,18 +81,20 @@ def calculate_task_duration(file: ifcopenshell.file, task: ifcopenshell.entity_i
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"task": task}
|
||||
return usecase.execute()
|
||||
return usecase.execute(task)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, task: ifcopenshell.entity_instance) -> None:
|
||||
self.task = task
|
||||
self.seconds_per_workday = self.calculate_seconds_per_workday()
|
||||
duration = self.calculate_max_resource_usage_duration()
|
||||
if duration:
|
||||
self.set_task_duration(duration)
|
||||
|
||||
def calculate_seconds_per_workday(self):
|
||||
def calculate_seconds_per_workday(self) -> float:
|
||||
def get_work_schedule(task):
|
||||
for rel in task.HasAssignments or []:
|
||||
if rel.is_a("IfcRelAssignsToControl") and rel.RelatingControl.is_a("IfcWorkSchedule"):
|
||||
@@ -102,7 +103,7 @@ class Usecase:
|
||||
return get_work_schedule(rel.RelatingObject)
|
||||
|
||||
default_seconds_per_workday = 8 * 60 * 60
|
||||
work_schedule = get_work_schedule(self.settings["task"])
|
||||
work_schedule = get_work_schedule(self.task)
|
||||
if not work_schedule:
|
||||
return default_seconds_per_workday
|
||||
psets = ifcopenshell.util.element.get_psets(work_schedule)
|
||||
@@ -115,9 +116,9 @@ class Usecase:
|
||||
work_day_duration = ifcopenshell.util.date.ifc2datetime(psets["Pset_WorkControlCommon"]["WorkDayDuration"])
|
||||
return work_day_duration.seconds
|
||||
|
||||
def calculate_max_resource_usage_duration(self):
|
||||
def calculate_max_resource_usage_duration(self) -> float:
|
||||
max_duration = 0
|
||||
for rel in self.settings["task"].OperatesOn or []:
|
||||
for rel in self.task.OperatesOn or []:
|
||||
for related_object in rel.RelatedObjects:
|
||||
if related_object.is_a("IfcConstructionResource"):
|
||||
duration = self.calculate_duration_in_days(related_object)
|
||||
@@ -125,7 +126,7 @@ class Usecase:
|
||||
max_duration = duration
|
||||
return max_duration
|
||||
|
||||
def calculate_duration_in_days(self, resource):
|
||||
def calculate_duration_in_days(self, resource: ifcopenshell.entity_instance) -> Union[float, None]:
|
||||
def is_hourly_work(schedule_work):
|
||||
return "T" in schedule_work
|
||||
|
||||
@@ -140,7 +141,7 @@ class Usecase:
|
||||
schedule_seconds = (schedule_duration.days + partial_days) * self.seconds_per_workday
|
||||
return math.ceil((schedule_seconds / self.seconds_per_workday) / schedule_usage)
|
||||
|
||||
def set_task_duration(self, duration):
|
||||
if not self.settings["task"].TaskTime:
|
||||
ifcopenshell.api.sequence.add_task_time(self.file, task=self.settings["task"])
|
||||
self.settings["task"].TaskTime.ScheduleDuration = f"P{duration}D"
|
||||
def set_task_duration(self, duration: float) -> None:
|
||||
if not (task_time := self.task.TaskTime):
|
||||
ifcopenshell.api.sequence.add_task_time(self.file, task=self.task)
|
||||
task_time.ScheduleDuration = f"P{duration}D"
|
||||
|
||||
@@ -24,7 +24,7 @@ import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.sequence
|
||||
import ifcopenshell.util.system
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
def create_baseline(
|
||||
@@ -44,11 +44,8 @@ def create_baseline(
|
||||
* Same Resource Relationships
|
||||
|
||||
:param work_schedule: The planned work_schedule to baseline
|
||||
:type work_schedule: ifcopenshell.entity_instance
|
||||
:param name: baseline work schedule name
|
||||
:type name: str, optional
|
||||
:return: The baseline work_schedule
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
@@ -62,23 +59,20 @@ def create_baseline(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"work_schedule": work_schedule, "name": name}
|
||||
return usecase.execute()
|
||||
return usecase.execute(work_schedule, name)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
result = self.create_baseline_work_schedule(self.settings["work_schedule"])
|
||||
return result
|
||||
file: ifcopenshell.file
|
||||
|
||||
def create_baseline_work_schedule(self, work_schedule):
|
||||
def execute(self, work_schedule: ifcopenshell.entity_instance, name: Union[str, None]) -> None:
|
||||
# create work schedule
|
||||
if not work_schedule.PredefinedType == "PLANNED":
|
||||
return
|
||||
baseline_work_schedule = ifcopenshell.api.sequence.add_work_schedule(
|
||||
self.file, name=work_schedule.Name, predefined_type="BASELINE"
|
||||
)
|
||||
baseline_work_schedule.Name = self.settings["name"]
|
||||
baseline_work_schedule.Name = name
|
||||
self.create_baseline_reference(work_schedule, baseline_work_schedule)
|
||||
for summary_task in ifcopenshell.util.sequence.get_root_tasks(work_schedule):
|
||||
current, duplicate = ifcopenshell.api.sequence.duplicate_task(self.file, task=summary_task)
|
||||
@@ -88,7 +82,9 @@ class Usecase:
|
||||
for i, task in enumerate(current):
|
||||
self.create_baseline_reference(task, duplicate[i])
|
||||
|
||||
def create_baseline_reference(self, relating_object, related_object):
|
||||
def create_baseline_reference(
|
||||
self, relating_object: ifcopenshell.entity_instance, related_object: ifcopenshell.entity_instance
|
||||
) -> ifcopenshell.entity_instance:
|
||||
referenced_by = None
|
||||
if relating_object.Declares:
|
||||
referenced_by = relating_object.Declares[0]
|
||||
|
||||
@@ -23,9 +23,12 @@ import ifcopenshell.api.owner
|
||||
import ifcopenshell.api.sequence
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.sequence
|
||||
from typing import Union, Any
|
||||
|
||||
|
||||
def duplicate_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
def duplicate_task(
|
||||
file: ifcopenshell.file, task: ifcopenshell.entity_instance
|
||||
) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]]:
|
||||
"""Duplicates a task in the project
|
||||
|
||||
The following relationships are also duplicated:
|
||||
@@ -35,9 +38,7 @@ def duplicate_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance)
|
||||
* The copy will have duplicated nested tasks
|
||||
|
||||
:param task: The task to be duplicated
|
||||
:type task: ifcopenshell.entity_instance
|
||||
:return: The duplicated task or the list of duplicated tasks if the latter has children
|
||||
:rtype: ifcopenshell.entity_instance or list of ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
.. code:: python
|
||||
@@ -55,6 +56,9 @@ def duplicate_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
self.tracker = {"current": [], "duplicate": []}
|
||||
self.duplicate_task(self.settings["task"])
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_lag_time(file: ifcopenshell.file, lag_time: ifcopenshell.entity_instanc
|
||||
IfcLagTime, consult the IFC documentation.
|
||||
|
||||
:param lag_time: The IfcLagTime entity you want to edit
|
||||
:type lag_time: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -75,14 +72,12 @@ def edit_lag_time(file: ifcopenshell.file, lag_time: ifcopenshell.entity_instanc
|
||||
# Or, let's make it 2 days instead.
|
||||
ifcopenshell.api.sequence.edit_lag_time(model, lag_time=lag, attributes={"LagValue": "P2D"})
|
||||
"""
|
||||
settings = {"lag_time": lag_time, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if name == "LagValue" and value is not None:
|
||||
if isinstance(value, float):
|
||||
value = file.createIfcRatioMeasure(value)
|
||||
else:
|
||||
value = file.createIfcDuration(ifcopenshell.util.date.datetime2ifc(value, "IfcDuration"))
|
||||
setattr(settings["lag_time"], name, value)
|
||||
for rel in [r for r in file.get_inverse(settings["lag_time"]) if r.is_a("IfcRelSequence")]:
|
||||
setattr(lag_time, name, value)
|
||||
for rel in [r for r in file.get_inverse(lag_time) if r.is_a("IfcRelSequence")]:
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=rel.RelatedProcess)
|
||||
|
||||
@@ -30,11 +30,8 @@ def edit_recurrence_pattern(
|
||||
IfcRecurrencePattern, consult the IFC documentation.
|
||||
|
||||
:param recurrence_pattern: The IfcRecurrencePattern entity you want to edit
|
||||
:type recurrence_pattern: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -55,13 +52,8 @@ def edit_recurrence_pattern(
|
||||
ifcopenshell.api.sequence.edit_recurrence_pattern(model,
|
||||
recurrence_pattern=pattern, attributes={"WeekdayComponent": [1, 2, 3, 4, 5]})
|
||||
"""
|
||||
settings = {
|
||||
"recurrence_pattern": recurrence_pattern,
|
||||
"attributes": attributes,
|
||||
}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["recurrence_pattern"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(recurrence_pattern, name, value)
|
||||
|
||||
ifcopenshell.util.sequence.is_working_day.cache_clear()
|
||||
ifcopenshell.util.sequence.is_calendar_applicable.cache_clear()
|
||||
|
||||
@@ -30,11 +30,8 @@ def edit_sequence(
|
||||
IfcRelSequence, consult the IFC documentation.
|
||||
|
||||
:param rel_sequence: The IfcRelSequence entity you want to edit
|
||||
:type rel_sequence: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -62,9 +59,7 @@ def edit_sequence(
|
||||
ifcopenshell.api.sequence.edit_sequence(model,
|
||||
rel_sequence=sequence, attributes={"SequenceType": "START_START"})
|
||||
"""
|
||||
settings = {"rel_sequence": rel_sequence, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["rel_sequence"], name, value)
|
||||
if "SequenceType" in settings["attributes"].keys():
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=settings["rel_sequence"].RelatedProcess)
|
||||
for name, value in attributes.items():
|
||||
setattr(rel_sequence, name, value)
|
||||
if "SequenceType" in attributes.keys():
|
||||
ifcopenshell.api.sequence.cascade_schedule(file, task=rel_sequence.RelatedProcess)
|
||||
|
||||
@@ -26,11 +26,8 @@ def edit_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance, attri
|
||||
IfcTask, consult the IFC documentation.
|
||||
|
||||
:param task: The IfcTask entity you want to edit
|
||||
:type task: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -48,7 +45,5 @@ def edit_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance, attri
|
||||
# Change the identification
|
||||
ifcopenshell.api.sequence.edit_task(model, task=task, attributes={"Identification": "M"})
|
||||
"""
|
||||
settings = {"task": task, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["task"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(task, name, value)
|
||||
|
||||
@@ -36,11 +36,8 @@ def edit_task_time(
|
||||
IfcTaskTime, consult the IFC documentation.
|
||||
|
||||
:param task_time: The IfcTaskTime entity you want to edit
|
||||
:type task_time: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -61,94 +58,89 @@ def edit_task_time(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"task_time": task_time, "attributes": attributes}
|
||||
return usecase.execute()
|
||||
return usecase.execute(task_time, attributes)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, task_time: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
self.task_time = task_time
|
||||
self.task = self.get_task()
|
||||
self.calendar = ifcopenshell.util.sequence.derive_calendar(self.task)
|
||||
|
||||
# If the user specifies both an end date and a duration, the duration takes priority
|
||||
if (
|
||||
self.settings["attributes"].get("ScheduleDuration", None)
|
||||
and "ScheduleFinish" in self.settings["attributes"].keys()
|
||||
):
|
||||
del self.settings["attributes"]["ScheduleFinish"]
|
||||
if attributes.get("ScheduleDuration", None) and "ScheduleFinish" in attributes.keys():
|
||||
del attributes["ScheduleFinish"]
|
||||
|
||||
duration_type = self.settings["attributes"].get("DurationType", self.settings["task_time"].DurationType)
|
||||
finish = self.settings["attributes"].get("ScheduleFinish", None)
|
||||
duration_type = attributes.get("DurationType", self.task_time.DurationType)
|
||||
finish = attributes.get("ScheduleFinish", None)
|
||||
if finish:
|
||||
if isinstance(finish, str):
|
||||
finish = datetime.datetime.fromisoformat(finish)
|
||||
self.settings["attributes"]["ScheduleFinish"] = datetime.datetime.combine(
|
||||
attributes["ScheduleFinish"] = datetime.datetime.combine(
|
||||
ifcopenshell.util.sequence.get_soonest_working_day(finish, duration_type, self.calendar),
|
||||
datetime.time(17),
|
||||
)
|
||||
start = self.settings["attributes"].get("ScheduleStart", None)
|
||||
start = attributes.get("ScheduleStart", None)
|
||||
if start:
|
||||
if isinstance(start, str):
|
||||
start = datetime.datetime.fromisoformat(start)
|
||||
self.settings["attributes"]["ScheduleStart"] = datetime.datetime.combine(
|
||||
attributes["ScheduleStart"] = datetime.datetime.combine(
|
||||
ifcopenshell.util.sequence.get_soonest_working_day(start, duration_type, self.calendar),
|
||||
datetime.time(9),
|
||||
)
|
||||
|
||||
for name, value in self.settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if value is not None:
|
||||
if "Start" in name or "Finish" in name or name == "StatusTime":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||
elif name == "ScheduleDuration" or name == "ActualDuration" or name == "RemainingTime":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||
setattr(self.settings["task_time"], name, value)
|
||||
setattr(self.task_time, name, value)
|
||||
|
||||
if (
|
||||
"ScheduleDuration" in self.settings["attributes"].keys()
|
||||
and self.settings["task_time"].ScheduleDuration
|
||||
and self.settings["task_time"].ScheduleStart
|
||||
):
|
||||
if "ScheduleDuration" in attributes.keys() and task_time.ScheduleDuration and task_time.ScheduleStart:
|
||||
self.calculate_finish()
|
||||
elif self.settings["attributes"].get("ScheduleStart", None) and self.settings["task_time"].ScheduleDuration:
|
||||
elif attributes.get("ScheduleStart", None) and task_time.ScheduleDuration:
|
||||
self.calculate_finish()
|
||||
elif self.settings["attributes"].get("ScheduleFinish", None) and self.settings["task_time"].ScheduleStart:
|
||||
elif attributes.get("ScheduleFinish", None) and task_time.ScheduleStart:
|
||||
self.calculate_duration()
|
||||
|
||||
if self.settings["task_time"].ScheduleDuration and (
|
||||
"ScheduleStart" in self.settings["attributes"].keys()
|
||||
or "ScheduleFinish" in self.settings["attributes"].keys()
|
||||
or "ScheduleDuration" in self.settings["attributes"].keys()
|
||||
if task_time.ScheduleDuration and (
|
||||
"ScheduleStart" in attributes.keys()
|
||||
or "ScheduleFinish" in attributes.keys()
|
||||
or "ScheduleDuration" in attributes.keys()
|
||||
):
|
||||
ifcopenshell.api.sequence.cascade_schedule(self.file, task=self.task)
|
||||
if self.settings["task_time"].ScheduleDuration:
|
||||
if task_time.ScheduleDuration:
|
||||
self.handle_resource_calculation()
|
||||
|
||||
def calculate_finish(self):
|
||||
finish = ifcopenshell.util.sequence.get_start_or_finish_date(
|
||||
ifcopenshell.util.date.ifc2datetime(self.settings["task_time"].ScheduleStart),
|
||||
ifcopenshell.util.date.ifc2datetime(self.settings["task_time"].ScheduleDuration),
|
||||
self.settings["task_time"].DurationType,
|
||||
ifcopenshell.util.date.ifc2datetime(self.task_time.ScheduleStart),
|
||||
ifcopenshell.util.date.ifc2datetime(self.task_time.ScheduleDuration),
|
||||
self.task_time.DurationType,
|
||||
self.calendar,
|
||||
date_type="FINISH",
|
||||
)
|
||||
self.settings["task_time"].ScheduleFinish = ifcopenshell.util.date.datetime2ifc(finish, "IfcDateTime")
|
||||
self.task_time.ScheduleFinish = ifcopenshell.util.date.datetime2ifc(finish, "IfcDateTime")
|
||||
|
||||
def calculate_duration(self):
|
||||
start = ifcopenshell.util.date.ifc2datetime(self.settings["task_time"].ScheduleStart)
|
||||
finish = ifcopenshell.util.date.ifc2datetime(self.settings["task_time"].ScheduleFinish)
|
||||
start = ifcopenshell.util.date.ifc2datetime(self.task_time.ScheduleStart)
|
||||
finish = ifcopenshell.util.date.ifc2datetime(self.task_time.ScheduleFinish)
|
||||
current_date = datetime.date(start.year, start.month, start.day)
|
||||
finish_date = datetime.date(finish.year, finish.month, finish.day)
|
||||
duration = datetime.timedelta(days=1)
|
||||
while current_date < finish_date:
|
||||
if self.settings["task_time"].DurationType == "ELAPSEDTIME" or not self.calendar:
|
||||
if self.task_time.DurationType == "ELAPSEDTIME" or not self.calendar:
|
||||
duration += datetime.timedelta(days=1)
|
||||
elif ifcopenshell.util.sequence.is_working_day(current_date, self.calendar):
|
||||
duration += datetime.timedelta(days=1)
|
||||
current_date += datetime.timedelta(days=1)
|
||||
self.settings["task_time"].ScheduleDuration = ifcopenshell.util.date.datetime2ifc(duration, "IfcDuration")
|
||||
self.task_time.ScheduleDuration = ifcopenshell.util.date.datetime2ifc(duration, "IfcDuration")
|
||||
|
||||
def get_task(self) -> ifcopenshell.entity_instance:
|
||||
return next(e for e in self.file.get_inverse(self.settings["task_time"]) if e.is_a("IfcTask"))
|
||||
return next(e for e in self.file.get_inverse(self.task_time) if e.is_a("IfcTask"))
|
||||
|
||||
def handle_resource_calculation(self):
|
||||
resources = ifcopenshell.util.sequence.get_task_resources(self.task, is_deep=False)
|
||||
|
||||
@@ -28,11 +28,8 @@ def edit_work_calendar(
|
||||
IfcWorkCalendar, consult the IFC documentation.
|
||||
|
||||
:param work_calendar: The IfcWorkCalendar entity you want to edit
|
||||
:type work_calendar: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -45,7 +42,5 @@ def edit_work_calendar(
|
||||
ifcopenshell.api.sequence.edit_work_calendar(model,
|
||||
work_calendar=calendar, attributes={"Description": "Monday to Friday 8 hour days"})
|
||||
"""
|
||||
settings = {"work_calendar": work_calendar, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["work_calendar"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(work_calendar, name, value)
|
||||
|
||||
@@ -29,11 +29,8 @@ def edit_work_plan(
|
||||
IfcWorkPlan, consult the IFC documentation.
|
||||
|
||||
:param work_plan: The IfcWorkPlan entity you want to edit
|
||||
:type work_plan: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -46,12 +43,10 @@ def edit_work_plan(
|
||||
ifcopenshell.api.sequence.edit_work_plan(model,
|
||||
work_plan=work_plan, attributes={"Description": "Construction of phase 1"})
|
||||
"""
|
||||
settings = {"work_plan": work_plan, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if value:
|
||||
if "Date" in name or "Time" in name:
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||
elif name == "Duration" or name == "TotalFloat":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||
setattr(settings["work_plan"], name, value)
|
||||
setattr(work_plan, name, value)
|
||||
|
||||
@@ -29,11 +29,8 @@ def edit_work_schedule(
|
||||
IfcWorkSchedule, consult the IFC documentation.
|
||||
|
||||
:param work_schedule: The IfcWorkSchedule entity you want to edit
|
||||
:type work_schedule: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -50,12 +47,10 @@ def edit_work_schedule(
|
||||
ifcopenshell.api.sequence.edit_work_schedule(model,
|
||||
work_schedule=work_schedule, attributes={"Description": "3 crane design option"})
|
||||
"""
|
||||
settings = {"work_schedule": work_schedule, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if value:
|
||||
if "Date" in name or "Time" in name:
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
|
||||
elif name == "Duration" or name == "TotalFloat":
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
|
||||
setattr(settings["work_schedule"], name, value)
|
||||
setattr(work_schedule, name, value)
|
||||
|
||||
@@ -31,11 +31,8 @@ def edit_work_time(
|
||||
IfcWorkTime, consult the IFC documentation.
|
||||
|
||||
:param work_time: The IfcWorkTime entity you want to edit
|
||||
:type work_time: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -54,16 +51,14 @@ def edit_work_time(
|
||||
ifcopenshell.api.sequence.edit_work_time(model,
|
||||
work_time=work_time, attributes={"StartDate": "2000-01-01", "FinishDate": "2000-01-02"})
|
||||
"""
|
||||
settings = {"work_time": work_time, "attributes": attributes}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
for name, value in attributes.items():
|
||||
if name in ("Start", "StartDate"):
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDate")
|
||||
# 4 IfcWorktime Start
|
||||
settings["work_time"][4] = value
|
||||
work_time[4] = value
|
||||
elif name in ("Finish", "FinishDate"):
|
||||
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDate")
|
||||
# 5 IfcWorktime Finish
|
||||
settings["work_time"][5] = value
|
||||
work_time[5] = value
|
||||
else:
|
||||
setattr(settings["work_time"], name, value)
|
||||
setattr(work_time, name, value)
|
||||
|
||||
@@ -35,9 +35,7 @@ def recalculate_schedule(file: ifcopenshell.file, work_schedule: ifcopenshell.en
|
||||
error.
|
||||
|
||||
:param work_schedule: The IfcWorkSchedule to perform the calculation on.
|
||||
:type work_schedule: ifcopenshell.entity_instance
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -50,12 +48,14 @@ def recalculate_schedule(file: ifcopenshell.file, work_schedule: ifcopenshell.en
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {"work_schedule": work_schedule}
|
||||
return usecase.execute()
|
||||
return usecase.execute(work_schedule)
|
||||
|
||||
|
||||
class Usecase:
|
||||
def execute(self):
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, work_schedule: ifcopenshell.entity_instance) -> None:
|
||||
self.work_schedule = work_schedule
|
||||
# The method implemented is the same as shown here:
|
||||
# https://www.youtube.com/watch?v=qTErIV6OqLg
|
||||
self.start_dates = []
|
||||
@@ -88,7 +88,6 @@ class Usecase:
|
||||
|
||||
if is_cyclic:
|
||||
raise RecursionError("Task graph is cyclic and so critical path method cannot be performed.")
|
||||
return
|
||||
|
||||
self.pending_nodes = set(self.g.nodes)
|
||||
while self.pending_nodes:
|
||||
@@ -100,7 +99,7 @@ class Usecase:
|
||||
|
||||
self.update_task_times()
|
||||
|
||||
def build_network_graph(self):
|
||||
def build_network_graph(self) -> None:
|
||||
self.sequence_type_map = {
|
||||
None: "FS",
|
||||
"START_START": "SS",
|
||||
@@ -114,14 +113,14 @@ class Usecase:
|
||||
self.edges = []
|
||||
self.g.add_node("start", duration=0, duration_type="ELAPSEDTIME", calendar=None)
|
||||
self.g.add_node("finish", duration=0, duration_type="ELAPSEDTIME", calendar=None)
|
||||
for rel in self.settings["work_schedule"].Controls:
|
||||
for rel in self.work_schedule.Controls:
|
||||
for related_object in rel.RelatedObjects:
|
||||
if not related_object.is_a("IfcTask"):
|
||||
continue
|
||||
self.add_node(related_object)
|
||||
self.g.add_edges_from(self.edges)
|
||||
|
||||
def add_node(self, task):
|
||||
def add_node(self, task: ifcopenshell.entity_instance) -> None:
|
||||
if task.IsNestedBy:
|
||||
for rel in task.IsNestedBy:
|
||||
[self.add_node(o) for o in rel.RelatedObjects]
|
||||
@@ -176,7 +175,7 @@ class Usecase:
|
||||
if not successor_types:
|
||||
self.edges.append((task.id(), "finish", {"lag_time": 0, "type": "FF"}))
|
||||
|
||||
def update_task_times(self):
|
||||
def update_task_times(self) -> None:
|
||||
for ifc_definition_id in self.g.nodes:
|
||||
if ifc_definition_id in ("start", "finish"):
|
||||
continue
|
||||
@@ -198,12 +197,12 @@ class Usecase:
|
||||
},
|
||||
)
|
||||
|
||||
def offset_date(self, date, days, node):
|
||||
def offset_date(self, date: datetime.datetime, days: int, node: dict) -> datetime.datetime:
|
||||
return ifcopenshell.util.sequence.offset_date(
|
||||
date, datetime.timedelta(days=days), node["duration_type"], node["calendar"]
|
||||
)
|
||||
|
||||
def forward_pass(self, node):
|
||||
def forward_pass(self, node) -> bool:
|
||||
successors = self.g.successors(node)
|
||||
predecessors = list(self.g.predecessors(node))
|
||||
data = self.g.nodes[node]
|
||||
@@ -326,7 +325,7 @@ class Usecase:
|
||||
|
||||
return True
|
||||
|
||||
def backward_pass(self, node):
|
||||
def backward_pass(self, node) -> bool:
|
||||
successors = list(self.g.successors(node))
|
||||
predecessors = self.g.predecessors(node)
|
||||
data = self.g.nodes[node]
|
||||
@@ -496,12 +495,12 @@ class Usecase:
|
||||
|
||||
def calculate_free_float(
|
||||
self,
|
||||
predecessor_date,
|
||||
successor_date,
|
||||
lag_time,
|
||||
predecessor_data,
|
||||
successor_data,
|
||||
):
|
||||
predecessor_date: datetime.datetime,
|
||||
successor_date: datetime.datetime,
|
||||
lag_time: int,
|
||||
predecessor_data: dict,
|
||||
successor_data: dict,
|
||||
) -> datetime.timedelta:
|
||||
if not lag_time:
|
||||
min_successor_date = successor_date
|
||||
else:
|
||||
|
||||
@@ -29,12 +29,10 @@ def dereference_structure(
|
||||
"""Dereferences a list of products and space
|
||||
|
||||
:param products: The list of physical IfcElements that exists in the space.
|
||||
:type products: list[ifcopenshell.entity_instance]
|
||||
:param relating_structure: The IfcSpatialStructureElement element, such
|
||||
as IfcBuilding, IfcBuildingStorey, or IfcSpace that the element
|
||||
exists in.
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -68,14 +66,12 @@ def dereference_structure(
|
||||
# Actually, it only goes up to storey 2.
|
||||
ifcopenshell.api.spatial.dereference_structure(model, products=[column], relating_structure=storey3)
|
||||
"""
|
||||
settings = {"products": products, "relating_structure": relating_structure}
|
||||
|
||||
products = set(settings["products"])
|
||||
for rel in settings["relating_structure"].ReferencesElements:
|
||||
products_set = set(products)
|
||||
for rel in relating_structure.ReferencesElements:
|
||||
related_elements = set(rel.RelatedElements)
|
||||
if not related_elements.intersection(products):
|
||||
if not related_elements.intersection(products_set):
|
||||
continue
|
||||
related_elements = related_elements - products
|
||||
related_elements = related_elements - products_set
|
||||
if related_elements:
|
||||
rel.RelatedElements = list(related_elements)
|
||||
ifcopenshell.api.owner.update_owner_history(file, **{"element": rel})
|
||||
|
||||
@@ -46,14 +46,11 @@ def reference_structure(
|
||||
spaces simultaneously.
|
||||
|
||||
:param products: The list of physical IfcElements that exists in the space.
|
||||
:type products: list[ifcopenshell.entity_instance]
|
||||
:param relating_structure: The IfcSpatialStructureElement element, such
|
||||
as IfcBuilding, IfcBuildingStorey, or IfcSpace that the element
|
||||
exists in.
|
||||
:type relating_structure: ifcopenshell.entity_instance
|
||||
:return: The IfcRelReferencedInSpatialStructure relationship instance
|
||||
or `None` if `products` was an empty list.
|
||||
:rtype: Union[ifcopenshell.entity_instance, None]
|
||||
|
||||
Example:
|
||||
|
||||
@@ -85,19 +82,16 @@ def reference_structure(
|
||||
model, products=[column], relating_structure=[storey2, storey3]
|
||||
)
|
||||
"""
|
||||
settings = {
|
||||
"products": products,
|
||||
"relating_structure": relating_structure,
|
||||
}
|
||||
|
||||
structure = settings["relating_structure"]
|
||||
products = set(settings["products"])
|
||||
structure = relating_structure
|
||||
products_set = set(products)
|
||||
|
||||
if not products:
|
||||
if not products_set:
|
||||
return
|
||||
|
||||
referenced = ifcopenshell.util.element.get_structure_referenced_elements(structure)
|
||||
products_to_assign = products - referenced
|
||||
products_to_assign = products_set - referenced
|
||||
rel: Union[ifcopenshell.entity_instance, None]
|
||||
rel = next(iter(structure.ReferencesElements), None)
|
||||
|
||||
if not products_to_assign:
|
||||
|
||||
+2
-8
@@ -28,14 +28,8 @@ def edit_structural_analysis_model(
|
||||
IfcStructuralAnalysisModel, consult the IFC documentation.
|
||||
|
||||
:param structural_analysis_model: The IfcStructuralAnalysisModel entity you want to edit
|
||||
:type structural_analysis_model: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"structural_analysis_model": structural_analysis_model, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["structural_analysis_model"], name, value)
|
||||
return settings["structural_analysis_model"]
|
||||
for name, value in attributes.items():
|
||||
setattr(structural_analysis_model, name, value)
|
||||
|
||||
+2
-7
@@ -28,19 +28,14 @@ def edit_structural_boundary_condition(
|
||||
IfcBoundaryCondition, consult the IFC documentation.
|
||||
|
||||
:param condition: The IfcBoundaryCondition entity you want to edit
|
||||
:type condition: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"condition": condition, "attributes": attributes}
|
||||
|
||||
for name, data in settings["attributes"].items():
|
||||
for name, data in attributes.items():
|
||||
if data["type"] == "string" or data["type"] == "null":
|
||||
value = data["value"]
|
||||
elif data["type"] == "IfcBoolean":
|
||||
value = file.createIfcBoolean(data["value"])
|
||||
else:
|
||||
value = file.create_entity(data["type"], data["value"])
|
||||
setattr(settings["condition"], name, value)
|
||||
setattr(condition, name, value)
|
||||
|
||||
@@ -16,25 +16,21 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
import ifcopenshell
|
||||
from ifcopenshell.util.shape_builder import VectorType, ifc_safe_vector_type
|
||||
|
||||
|
||||
def edit_structural_item_axis(
|
||||
file: ifcopenshell.file,
|
||||
structural_item: ifcopenshell.entity_instance,
|
||||
axis: tuple[float, float, float] = (0.0, 0.0, 1.0),
|
||||
axis: VectorType = (0.0, 0.0, 1.0),
|
||||
) -> None:
|
||||
"""Edits the coordinate system of a structural connection
|
||||
|
||||
:param structural_item: The IfcStructuralItem you want to modify.
|
||||
:type structural_item: ifcopenshell.entity_instance
|
||||
:param axis: The unit Z axis vector defined as a list of 3 floats.
|
||||
Defaults to (0., 0., 1.).
|
||||
:type axis: tuple[float, float, float]
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"structural_item": structural_item, "axis": axis}
|
||||
|
||||
if len(file.get_inverse(settings["structural_item"].Axis)) == 1:
|
||||
file.remove(settings["structural_item"].Axis)
|
||||
settings["structural_item"].Axis = file.createIfcDirection(settings["axis"])
|
||||
if len(file.get_inverse(axis_dir := structural_item.Axis)) == 1:
|
||||
file.remove(axis_dir)
|
||||
structural_item.Axis = file.create_entity("IfcDirection", ifc_safe_vector_type(axis))
|
||||
|
||||
@@ -28,13 +28,8 @@ def edit_structural_load(
|
||||
IfcStructuralLoad, consult the IFC documentation.
|
||||
|
||||
:param structural_load: The IfcStructuralLoad entity you want to edit
|
||||
:type structural_load: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"structural_load": structural_load, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["structural_load"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(structural_load, name, value)
|
||||
|
||||
@@ -28,13 +28,8 @@ def edit_structural_load_case(
|
||||
IfcStructuralLoadCase, consult the IFC documentation.
|
||||
|
||||
:param load_case: The IfcStructuralLoadCase entity you want to edit
|
||||
:type load_case: ifcopenshell.entity_instance
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
settings = {"load_case": load_case, "attributes": attributes or {}}
|
||||
|
||||
for name, value in settings["attributes"].items():
|
||||
setattr(settings["load_case"], name, value)
|
||||
for name, value in attributes.items():
|
||||
setattr(load_case, name, value)
|
||||
|
||||
@@ -82,17 +82,13 @@ def add_surface_style(
|
||||
|
||||
:param style: The IfcSurfaceStyle you want to add to presentation item
|
||||
to. See ifcopenshell.api.style.add_style.
|
||||
:type style: ifcopenshell.entity_instance
|
||||
:param ifc_class: Choose from IfcSurfaceStyleShading,
|
||||
IfcSurfaceStyleRendering, IfcSurfaceStyleWithTextures,
|
||||
IfcSurfaceStyleLighting, IfcSurfaceStyleReflectance, or
|
||||
IfcExternallyDefinedSurfaceStyle.
|
||||
:type ifc_class: str
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:type attributes: dict, optional
|
||||
:return: The newly created presentation item based on the provided
|
||||
ifc_class.
|
||||
:rtype: ifcopenshell.entity_instance
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.style
|
||||
import ifcopenshell.util.element
|
||||
from typing import Any
|
||||
|
||||
|
||||
def assign_material_style(
|
||||
@@ -115,6 +116,9 @@ def assign_material_style(
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
self.style = self.settings["style"]
|
||||
if self.file.schema == "IFC2X3" or self.settings["should_use_presentation_style_assignment"]:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user