First Commit

This commit is contained in:
2026-05-31 10:17:09 +07:00
commit 17a9c69379
4547 changed files with 1170384 additions and 0 deletions
@@ -0,0 +1,55 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Manage construction and maintenance resources
Resources include equipment (cranes, etc), labour, material, and products. They
are typically referenced in construction planning, maintenance schedules, or
cost items.
"""
from .. import wrap_usecases
from .add_resource import add_resource
from .add_resource_quantity import add_resource_quantity
from .add_resource_time import add_resource_time
from .assign_resource import assign_resource
from .calculate_resource_usage import calculate_resource_usage
from .calculate_resource_work import calculate_resource_work
from .edit_resource import edit_resource
from .edit_resource_quantity import edit_resource_quantity
from .edit_resource_time import edit_resource_time
from .remove_resource import remove_resource
from .remove_resource_quantity import remove_resource_quantity
from .unassign_resource import unassign_resource
wrap_usecases(__path__, __name__)
__all__ = [
"add_resource",
"add_resource_quantity",
"add_resource_time",
"assign_resource",
"calculate_resource_usage",
"calculate_resource_work",
"edit_resource",
"edit_resource_quantity",
"edit_resource_time",
"remove_resource",
"remove_resource_quantity",
"unassign_resource",
]
@@ -0,0 +1,89 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from typing import Optional
import ifcopenshell.api.nest
import ifcopenshell.api.project
import ifcopenshell.api.root
def add_resource(
file: ifcopenshell.file,
parent_resource: Optional[ifcopenshell.entity_instance] = None,
ifc_class: str = "IfcCrewResource",
name: Optional[str] = None,
predefined_type: str = "NOTDEFINED",
) -> ifcopenshell.entity_instance:
"""Add a new construction resource
Construction resources may be managed and connected to cost schedules
and construction schedules. This allows calculations to be done on
resource utilisation, cost optimisation (e.g. labour rates), and
optioneering on build strategies.
There are typically two types of resources. Crew resources are resources
where you manage your own crew and you have full control over the
equipment, labour, products, and materials used by your crew.
Alternatively, there are subcontractor resources, where you simply
delegate all the details to a subcontractor and it is not decomposed
into further levels of detail.
This means when adding resources, you'd first either add a crew or
subcontract resource. If it is a crew resource, you'd then add child
resources to that crew, such as equipment (cranes, excavators, hoists,
etc), material (wood, concrete, etc), and labour (rigging crews,
formworkers, etc).
:param parent_resource: If this is a child resource (typically to a crew
resource), then nominate the parent IfcConstructionResource here.
:param ifc_class: The class of resource chosen from
IfcConstructionEquipmentResource, IfcConstructionMaterialResource,
IfcConstructionProductResource, IfcCrewResource, IfcLaborResource,
or IfcSubContractResource.
:param name: The name of the resource
:param predefined_type: Consult the IFC documentation for the valid
predefined types for each type of resource class.
:return: The newly created resource depending on the nominated IFC
class.
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
ifcopenshell.api.resource.add_resource(model, parent_resource=crew, ifc_class="IfcLaborResource")
"""
resource = ifcopenshell.api.root.create_entity(
file,
ifc_class=ifc_class,
predefined_type=predefined_type,
name=name or "Unnamed",
)
# TODO: this is an ambiguity by buildingSMART: Can we nest an IfcCrewResource under an IfcCrewResource ?
# https://forums.buildingsmart.org/t/what-are-allowed-to-be-root-level-construction-resources/3550
if parent_resource:
ifcopenshell.api.nest.assign_object(file, related_objects=[resource], relating_object=parent_resource)
elif file.schema != "IFC2X3":
context = file.by_type("IfcContext")[0]
ifcopenshell.api.project.assign_declaration(file, definitions=[resource], relating_context=context)
return resource
@@ -0,0 +1,83 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.util.element
import ifcopenshell.util.resource
def add_resource_quantity(
file: ifcopenshell.file, resource: ifcopenshell.entity_instance, ifc_class: str = "IfcQuantityCount"
) -> ifcopenshell.entity_instance:
"""Adds a quantity to a resource
The quantity of a resource represents the "unit quantity" of that
resource. For example, labour might be hired on a daily basis (8 hours).
There are different types of quantities (e.g. volume, count, or time).
Which quantity is used depends on the type of resource. Material
resources may be quantified in terms of length, area, volume, or weight.
Equipment and labour resources are quantified in terms of time. Products
resources are quantified in terms of counts.
This base quantity is then used in other calculations.
:param resource: The IfcConstructionResource to add a quantity to.
: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).
:return: The newly created quantity depending on the IFC class
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
labour = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcLaborResource")
# Labour resource is quantified in terms of time.
quantity = ifcopenshell.api.resource.add_resource_quantity(model,
resource=labour, ifc_class="IfcQuantityTime")
# Store the time used in hours
ifcopenshell.api.resource.edit_resource_quantity(model,
physical_quantity=quantity, attributes={"TimeValue": 8.0})
"""
resource_type = resource.is_a()
supported_quantities = ifcopenshell.util.resource.RESOURCES_TO_QUANTITIES[resource_type]
if ifc_class not in supported_quantities:
raise ValueError(
f"Resource type '{resource_type}' does not support quantity type '{ifc_class}'. "
f"Supported quantities: {','.join(supported_quantities)}"
)
quantity = file.create_entity(ifc_class, Name="Unnamed")
# 3 IfcPhysicalSimpleQuantity Value
if ifc_class == "IfcQuantityCount":
quantity[3] = 0
else:
quantity[3] = 0.0
old_quantity = resource.BaseQuantity
resource.BaseQuantity = quantity
if old_quantity:
ifcopenshell.util.element.remove_deep2(file, old_quantity)
return quantity
@@ -0,0 +1,59 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.util.date
def add_resource_time(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
"""Adds the time that a resource is used for
For labour and equipment resources, the total duration that the resource
is used for may be stored. This may either be input manually or
calculated parametrically. This is known as the resource time, and may
be used to calculate other parameters like resource utilisation.
:param resource: The IfcConstructionResource to record time for.
:return: The newly created IfcResourceTime
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
labour = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcLaborResource")
# Labour resource is quantified in terms of time.
quantity = ifcopenshell.api.resource.add_resource_quantity(model,
resource=labour, ifc_class="IfcQuantityTime")
# Store the unit time used in hours
ifcopenshell.api.resource.edit_resource_quantity(model,
physical_quantity=quantity, attributes={"TimeValue": 8.0})
# Let's imagine we've used the resource for 2 days.
time = ifcopenshell.api.resource.add_resource_time(model, resource=labour)
ifcopenshell.api.resource.edit_resource_time(model,
resource_time=time, attributes={"ScheduleWork": "PT16H"})
"""
resource_time = file.create_entity("IfcResourceTime")
resource.Usage = resource_time
return resource_time
@@ -0,0 +1,106 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.api.owner
import ifcopenshell.guid
def assign_resource(
file: ifcopenshell.file,
relating_resource: ifcopenshell.entity_instance,
related_object: ifcopenshell.entity_instance,
) -> ifcopenshell.entity_instance:
"""Assigns a resource to an object
Two types of objects are typically assigned to resources: products and
actors.
If a product is assigned to a resource, that means that the product
represents the resource on site. This may be represented via material
handling zones on a construction site, or equipment like cranes and
their physical locations.
If an actor is assigned to a resource, that means that the actor (person
or organisation) is the actor consuming the resource (e.g. if the
resource is material or equipment) or the actor performing the work
(e.g. if the resource is a labour resource).
:param relating_resource: The IfcResource to assign the object to.
:param related_object: The IfcProduct or IfcActor to assign to the
object.
:return: The newly created IfcRelAssignsToResource
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some a tower crane to our crew.
crane = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcConstructionEquipmentResource", name="Tower Crane 01")
# Our tower crane will be placed via this physical product.
product = ifcopenshell.api.root.create_entity(model,
ifc_class="IfcBuildingElementProxy", predefined_type="CRANE")
# Let's place our crane at some X, Y coordinates.
matrix = numpy.eye(4)
matrix[0][3], matrix[1][3] = 3.0, 4.0
ifcopenshell.api.geometry.edit_object_placement(model, product=crane, matrix=matrix)
# Let's assign our crane to the resource. The crane now represents
# the resource.
ifcopenshell.api.resource.assign_resource(model, relating_resource=crane, related_object=product)
# Setup an organisation actor who will operate the crane
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="UCO", name="Unionised Crane Operators Pty Ltd")
role = ifcopenshell.api.owner.add_role(model, assigned_object=organisation, role="CREW")
actor = ifcopenshell.api.owner.add_actor(model, actor=organisation)
# This means that UCO is now our crane operator.
ifcopenshell.api.resource.assign_resource(model, relating_resource=crane, related_object=actor)
"""
if related_object.HasAssignments:
for assignment in related_object.HasAssignments:
if assignment.is_a("IfclRelAssignsToResource") and assignment.RelatingResource == relating_resource:
return assignment
resource_of = None
if relating_resource.ResourceOf:
resource_of = relating_resource.ResourceOf[0]
if resource_of:
related_objects = list(resource_of.RelatedObjects)
related_objects.append(related_object)
resource_of.RelatedObjects = related_objects
ifcopenshell.api.owner.update_owner_history(file, element=resource_of)
else:
resource_of = file.create_entity(
"IfcRelAssignsToResource",
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
"RelatedObjects": [related_object],
"RelatingResource": relating_resource,
}
)
return resource_of
@@ -0,0 +1,54 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.api
import ifcopenshell.util.constraint
import ifcopenshell.util.date
import ifcopenshell.util.resource
def calculate_resource_usage(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None:
"""Calculates the number of resources required to perform scheduled work on a task.
:param resource: The IfcConstructionResource to calculate the usage for.
:return: None
"""
if ifcopenshell.util.constraint.is_attribute_locked(resource, "Usage.ScheduleUsage"):
return
if not resource.Usage or not resource.Usage.ScheduleWork:
return
task = ifcopenshell.util.resource.get_task_assignments(resource)
if not task or not task.TaskTime:
return
if not task.TaskTime.DurationType or task.TaskTime.DurationType == "WORKTIME":
hours_per_day = 8
else:
hours_per_day = 24
task_duration = ifcopenshell.util.date.ifc2datetime(task.TaskTime.ScheduleDuration)
seconds = task_duration.days * hours_per_day * 60 * 60
seconds += task_duration.seconds
person_hours = ifcopenshell.util.date.ifc2datetime(resource.Usage.ScheduleWork)
required_resources = person_hours.total_seconds() / seconds
resource.Usage.ScheduleUsage = float(required_resources)
@@ -0,0 +1,61 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.api.resource
import ifcopenshell.util.constraint
import ifcopenshell.util.resource
def calculate_resource_work(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None:
"""Calculates the work that a resource is used for
This is an unofficial parametric calculation that may be done on a
resource based on careful analysis of the relationships between the
costing, scheduling, and resource domains in IFC.
A resource may store a productivity rate in a property set called
EPset_Productivity. This stores three properties:
* BaseQuantityConsumed - a duration that the resource is consumed for.
* BaseQuantityProducedName - what quantity the resource can produce,
such as area or volume.
* BaseQuantityProducedValue - what value of that quantity the resource
can produce during that duration.
For example, a labour or equipment resource might produce 100m3 of
NetVolume every day (i.e. 8 hours are consumed).
Then, if a resource is assigned to a construction task, and that
construction task is assigned to concrete slabs totalling 200m3, we can
calculate that the resource consumes 16 hours of work.
This calculated work is stored against the resource as scheduled work
under the resource time data.
:param resource: The IfcConstructionResource that you want to calculate
the work performed.
:return None:
"""
if ifcopenshell.util.constraint.is_attribute_locked(resource, "Usage.ScheduleWork"):
return
amount_worked = ifcopenshell.util.resource.get_resource_required_work(resource)
if not amount_worked:
return
if not resource.Usage:
ifcopenshell.api.resource.add_resource_time(file, resource=resource)
resource.Usage.ScheduleWork = amount_worked
@@ -0,0 +1,44 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
import ifcopenshell
def edit_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
"""Edits the attributes of an IfcResource
For more information about the attributes and data types of an
IfcResource, consult the IFC documentation.
:param resource: The IfcResource entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Change the name of the resource to "Zone A Crew"
ifcopenshell.api.resource.edit_resource(model, resource=resource, attributes={"Name": "Foo"})
"""
for name, value in attributes.items():
setattr(resource, name, value)
@@ -0,0 +1,55 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
import ifcopenshell
def edit_resource_quantity(
file: ifcopenshell.file, physical_quantity: ifcopenshell.entity_instance, attributes: dict[str, Any]
) -> None:
"""Edits the attributes of an IFC quantity
For more information about the attributes and data types of an
IfC quantity, consult the IFC documentation.
:param physical_quantity: The IfC quantity entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
labour = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcLaborResource")
# Labour resource is quantified in terms of time.
ifcopenshell.api.resource.add_resource_quantity(model,
resource=labour, ifc_class="IfcQuantityTime")
# Store the time used in hours
ifcopenshell.api.resource.edit_resource_quantity(model,
physical_quantity=time, attributes={"TimeValue": 8.0})
"""
for name, value in attributes.items():
setattr(physical_quantity, name, value)
@@ -0,0 +1,99 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
import ifcopenshell
import ifcopenshell.api.sequence
import ifcopenshell.util.constraint
import ifcopenshell.util.date
import ifcopenshell.util.resource
def edit_resource_time(
file: ifcopenshell.file, resource_time: ifcopenshell.entity_instance, attributes: dict[str, Any]
) -> None:
"""Edits the attributes of an IfcResourceTime
For more information about the attributes and data types of an
IfcResourceTime, consult the IFC documentation.
:param resource_time: The IfcResourceTime entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
labour = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcLaborResource")
# Labour resource is quantified in terms of time.
ifcopenshell.api.resource.add_resource_quantity(model,
resource=labour, ifc_class="IfcQuantityTime")
# Store the unit time used in hours
ifcopenshell.api.resource.edit_resource_quantity(model,
physical_quantity=time, attributes={"TimeValue": 8.0})
# Let's imagine we've used the resource for 2 days.
time = ifcopenshell.api.resource.add_resource_time(model, resource=labour)
ifcopenshell.api.resource.edit_resource_time(model,
resource_time=time, attributes={"ScheduleWork": "P16H"})
"""
usecase = Usecase()
usecase.file = file
return usecase.execute(resource_time, attributes)
class Usecase:
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 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 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:
if "Start" in name or "Finish" in name or name == "StatusTime":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDateTime")
elif name == "ScheduleWork" or name == "ActualWork" or name == "RemainingTime":
value = ifcopenshell.util.date.datetime2ifc(value, "IfcDuration")
setattr(resource_time, name, value)
if name == "ScheduleUsage" and ifcopenshell.util.constraint.get_metric_constraints(
resource, "Usage.ScheduleWork"
):
task = ifcopenshell.util.resource.get_task_assignments(resource)
if task:
ifcopenshell.api.sequence.calculate_task_duration(self.file, task=task)
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"))
@@ -0,0 +1,78 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021-2022, Dion Moult <dion@thinkmoult.com>, Yassine Oualid <yassine@sigmadimensions.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.api.resource
import ifcopenshell.util.element
def remove_resource(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None:
"""Removes a resource and all relationships
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Fire our crew
ifcopenshell.api.resource.remove_resource(model, resource=crew)
"""
settings = {"resource": resource}
def remove_consider_history(root: ifcopenshell.entity_instance) -> None:
history = root.OwnerHistory
file.remove(root)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
# TODO: review deep purge
for inverse in file.get_inverse(settings["resource"]):
if inverse.is_a("IfcRelNests"):
if inverse.RelatingObject == settings["resource"]:
# Remove rel before iteration over objects
# to simplify removal of nested resources and avoid crashes.
related_objects = inverse.RelatedObjects
remove_consider_history(inverse)
for related_object in related_objects:
ifcopenshell.api.resource.remove_resource(file, resource=related_object)
elif inverse.RelatedObjects == (resource,):
remove_consider_history(inverse)
elif inverse.is_a("IfcRelAssignsToControl"):
if len(inverse.RelatedObjects) == 1:
remove_consider_history(inverse)
else:
related_objects = list(inverse.RelatedObjects)
related_objects.remove(settings["resource"])
inverse.RelatedObjects = related_objects
elif inverse.is_a("IfcRelAssignsToResource"):
if inverse.RelatingResource == settings["resource"]:
for related_object in inverse.RelatedObjects:
ifcopenshell.api.resource.unassign_resource(
file, related_object=related_object, relating_resource=settings["resource"]
)
elif inverse.RelatedObjects == (resource,):
remove_consider_history(inverse)
# Usage was added in IFC4.
if usage := getattr(settings["resource"], "Usage", None):
file.remove(usage)
if settings["resource"].BaseQuantity:
ifcopenshell.api.resource.remove_resource_quantity(file, resource=settings["resource"])
remove_consider_history(resource)
@@ -0,0 +1,50 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.util.element
def remove_resource_quantity(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None:
"""Removes the base quantity of a resource
:param resource: The IfcConstructionResource to remove the quantity from.
:return: None
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some labour to our crew.
labour = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcLaborResource")
# Labour resource is quantified in terms of time.
ifcopenshell.api.resource.add_resource_quantity(model,
resource=labour, ifc_class="IfcQuantityTime")
# Let's say we only want to store the resource but no quantities,
# let's clean up our mess and remove the quantity.
ifcopenshell.api.resource.remove_resource_quantity(model, resource=labour)
"""
old_quantity = resource.BaseQuantity
resource.BaseQuantity = None
if old_quantity:
ifcopenshell.util.element.remove_deep2(file, old_quantity)
@@ -0,0 +1,72 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# 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.api.owner
import ifcopenshell.util.element
def unassign_resource(
file: ifcopenshell.file,
relating_resource: ifcopenshell.entity_instance,
related_object: ifcopenshell.entity_instance,
) -> None:
"""Removes the relationship between a resource and object
:param relating_resource: The IfcResource to assign the object to.
:param related_object: The IfcProduct or IfcActor to assign to the
object.
:return: None
Example:
.. code:: python
# Add our own crew
crew = ifcopenshell.api.resource.add_resource(model, ifc_class="IfcCrewResource")
# Add some a tower crane to our crew.
crane = ifcopenshell.api.resource.add_resource(model,
parent_resource=crew, ifc_class="IfcConstructionEquipmentResource", name="Tower Crane 01")
# Our tower crane will be placed via this physical product.
product = ifcopenshell.api.root.create_entity(model,
ifc_class="IfcBuildingElementProxy", predefined_type="CRANE")
# Let's assign our crane to the resource. The crane now represents
# the resource.
ifcopenshell.api.resource.assign_resource(model,
relating_resource=crane, related_object=product)
# Undo it.
ifcopenshell.api.resource.unassign_resource(model,
relating_resource=crane, related_object=product)
"""
for rel in related_object.HasAssignments or []:
if not rel.is_a("IfcRelAssignsToResource") or rel.RelatingResource != relating_resource:
continue
if len(rel.RelatedObjects) == 1:
history = rel.OwnerHistory
file.remove(rel)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
return
related_objects = list(rel.RelatedObjects)
related_objects.remove(related_object)
rel.RelatedObjects = related_objects
ifcopenshell.api.owner.update_owner_history(file, element=rel)