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,80 @@
# 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/>.
"""An element may have an owner, indicating who is responsible, liable, or
contactable regarding that element
Note that in IFC2X3, element ownership is mandatory and must be addressed prior
to the creation of any element at all. See :func:`create_owner_history` for
examples.
"""
from .. import wrap_usecases
from .add_actor import add_actor
from .add_address import add_address
from .add_application import add_application
from .add_organisation import add_organisation
from .add_person import add_person
from .add_person_and_organisation import add_person_and_organisation
from .add_role import add_role
from .assign_actor import assign_actor
from .create_owner_history import create_owner_history
from .edit_actor import edit_actor
from .edit_address import edit_address
from .edit_application import edit_application
from .edit_organisation import edit_organisation
from .edit_person import edit_person
from .edit_role import edit_role
from .remove_actor import remove_actor
from .remove_address import remove_address
from .remove_application import remove_application
from .remove_organisation import remove_organisation
from .remove_person import remove_person
from .remove_person_and_organisation import remove_person_and_organisation
from .remove_role import remove_role
from .unassign_actor import unassign_actor
from .update_owner_history import update_owner_history
wrap_usecases(__path__, __name__)
__all__ = [
"add_actor",
"add_address",
"add_application",
"add_organisation",
"add_person",
"add_person_and_organisation",
"add_role",
"assign_actor",
"create_owner_history",
"edit_actor",
"edit_address",
"edit_application",
"edit_organisation",
"edit_person",
"edit_role",
"remove_actor",
"remove_address",
"remove_application",
"remove_organisation",
"remove_person",
"remove_person_and_organisation",
"remove_role",
"unassign_actor",
"update_owner_history",
]
@@ -0,0 +1,70 @@
# 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/>.
from typing import Literal
import ifcopenshell
import ifcopenshell.api.root
ACTOR_TYPE = Literal["IfcActor", "IfcOccupant"]
def add_actor(
file: ifcopenshell.file,
actor: ifcopenshell.entity_instance,
ifc_class: ACTOR_TYPE = "IfcActor",
) -> ifcopenshell.entity_instance:
"""Adds a new actor
An actor is a person or an organisation who has a responsibility or role
to play in a project. Actor roles include design consultants,
architects, engineers, cost planners, suppliers, manufacturers,
warrantors, owners, subcontractors, etc.
Actors may either be project actors, who are responsible for the
delivery of the project, or occupants, who are responsible for the
consumption of the project.
Identifying and managing actors is critical for asset management, and
identifying liability for legal submissions.
:param actor: Most commonly, an IfcOrganization (in compliance with GDPR
requirements for non personally identifiable information), or an
IfcPerson if it is a sole individual, or an IfcPersonAndOrganization
if a specific person is liable within an organisation and must be
legally nominated.
:param ifc_class: Either "IfcActor" or "IfcOccupant".
:return: The newly created IfcActor or IfcOccupant
Example:
.. code:: python
# Setup an organisation with a single role
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
role = ifcopenshell.api.owner.add_role(model, assigned_object=organisation, role="ARCHITECT")
# Assign that organisation to a newly created actor
actor = ifcopenshell.api.owner.add_actor(model, actor=organisation)
"""
ifc_class = ifc_class or "IfcActor"
actor_ = ifcopenshell.api.root.create_entity(file, ifc_class=ifc_class)
actor_.TheActor = actor
return actor_
@@ -0,0 +1,71 @@
# 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 Literal
import ifcopenshell
ADDRESS_TYPE = Literal["IfcPostalAddress", "IfcTelecomAddress"]
def add_address(
file: ifcopenshell.file, assigned_object: ifcopenshell.entity_instance, ifc_class: ADDRESS_TYPE = "IfcPostalAddress"
) -> ifcopenshell.entity_instance:
"""Add a new telecom or postal address to an organisation or person
A person or organisation may have associated contact details such as
phone numbers, mailing addresses, websites, email addresses, and instant
messaging handles. This information is critical in recording the contact
information of manufacturers and suppliers for facility management, or
liable actors.
There are two types of addresses, postal addresses for physical snail
mail, and telecom addresses for telephone or internet contact numbers
and addresses.
:param assigned_object: The IfcOrganization or IfcPerson the contact
address belongs to.
:param ifc_class: Either IfcPostalAddress or IfcTelecomAddress. Defaults
to IfcPostalAddress.
:return: The new IfcPostalAddress or IfcTelecomAddress
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model)
# A snail mail address
postal = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcPostalAddress")
ifcopenshell.api.owner.edit_address(model, address=postal,
attributes={"Purpose": "OFFICE", "AddressLines": ["42 Wallaby Way"],
"Town": "Sydney", "Region": "NSW", "PostalCode": "2000"})
# A phone or internet address
telecom = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcTelecomAddress")
ifcopenshell.api.owner.edit_address(model, address=telecom,
attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"],
"ElectronicMailAddresses": ["bobthebuilder@example.com"],
"WWWHomePageURL": "https://thinkmoult.com"})
"""
address = file.create_entity(ifc_class, "OFFICE")
addresses = list(assigned_object.Addresses) if assigned_object.Addresses else []
addresses.append(address)
assigned_object.Addresses = addresses
return address
@@ -0,0 +1,124 @@
# 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, Union
import ifcopenshell.api
import ifcopenshell.api.owner
import ifcopenshell.api.pset
def add_application(
file: ifcopenshell.file,
application_developer: Optional[ifcopenshell.entity_instance] = None,
version: Optional[str] = None,
application_full_name: str = "IfcOpenShell",
application_identifier: str = "IfcOpenShell",
) -> ifcopenshell.entity_instance:
"""Adds a new application
IFC data may be associated with an authoring application to identify
which application was responsible for editing or authoring the data. An
application is defined by the developing organisation, as well as a full
name and identifier. This is akin to how web browsers have an
identification string.
:param application_developer: The IfcOrganization responsible for
creating the application. Defaults to generating an IfcOpenShell
organisation if none is provided.
:param version: The version of the application. Defaults to the
ifcopenshell.version data if not specified.
:param application_full_name: The name of the application
:param application_identifier: An identification string for the
application intended for computers to read.
:return: The newly created IfcApplication
Example:
.. code:: python
application = ifcopenshell.api.owner.add_application(model)
"""
usecase = Usecase()
usecase.file = file
return usecase.execute(
application_developer,
version or ifcopenshell.version,
application_full_name,
application_identifier,
)
class Usecase:
file: ifcopenshell.file
def execute(
self,
application_developer: Union[ifcopenshell.entity_instance, None],
version: str,
application_full_name: str,
application_identifier: str,
) -> ifcopenshell.entity_instance:
if not application_developer:
application_developer = self.create_application_organisation()
return self.file.create_entity(
"IfcApplication",
ApplicationDeveloper=application_developer,
Version=version,
ApplicationFullName=application_full_name,
ApplicationIdentifier=application_identifier,
)
def create_application_organisation(self) -> ifcopenshell.entity_instance:
result = self.file.create_entity(
"IfcOrganization",
**{
"Name": "IfcOpenShell",
"Description": "IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.",
"Roles": [
self.file.create_entity("IfcActorRole", **{"Role": "USERDEFINED", "UserDefinedRole": "CONTRIBUTOR"})
],
},
)
# 0 IfcOrganization.Identification / Id (IFC2X3).
result[0] = "IfcOpenShell"
# 4 IfcOrganization.Addresses
if self.file.schema == "IFC4X3":
# IfcTelecomAddress is deprecated in IFC4X3.
actor = ifcopenshell.api.owner.add_actor(self.file, result)
pset = ifcopenshell.api.pset.add_pset(self.file, actor, "PEnum_AddressType")
ifcopenshell.api.pset.edit_pset(
self.file,
pset,
properties={
"Purpose": "OTHER",
"UserDefinedPurpose": "WEBPAGE",
"WWWHomePageURL": "https://ifcopenshell.org",
},
)
else:
result[4] = [
self.file.create_entity(
"IfcTelecomAddress",
Purpose="USERDEFINED",
UserDefinedPurpose="WEBPAGE",
WWWHomePageURL="https://ifcopenshell.org",
),
]
return result
@@ -0,0 +1,49 @@
# 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
def add_organisation(
file: ifcopenshell.file, identification: str = "APTR", name: str = "Aperture Science"
) -> ifcopenshell.entity_instance:
"""Adds a new organisation
Organisations are the main way to identify manufacturers, suppliers, and
other actors who do not have a single representative or must not have
any personally identifiable information.
:param identification: The short code identifying the organisation.
Sometimes used in drawing naming schemes. Otherise used as a
canonicalised way of computers to identify the organisation. Like
their stock name.
:param name: The legal name of the organisation
:return: The newly created IfcOrganization
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
"""
data = {"Name": name}
if file.schema == "IFC2X3":
data["Id"] = identification
else:
data["Identification"] = identification
return file.create_entity("IfcOrganization", **data)
@@ -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
def add_person(
file: ifcopenshell.file,
identification: str = "HSeldon",
family_name: str = "Seldon",
given_name: str = "Hari",
) -> ifcopenshell.entity_instance:
"""Adds a new person
Persons are used to identify a legal or liable representative of an
organisation or point of contact.
:param identification: The computer readable unique identification of
the person. For example, their username in a CDE or alias.
:param family_name: The family name
:param given_name: The given name
:return: The newly created IfcPerson
Example:
.. code:: python
ifcopenshell.api.owner.add_person(model,
identification="bobthebuilder", family_name="Thebuilder", given_name="Bob")
"""
data = {"FamilyName": family_name, "GivenName": given_name}
if file.schema == "IFC2X3":
data["Id"] = identification
else:
data["Identification"] = identification
return file.create_entity("IfcPerson", **data)
@@ -0,0 +1,48 @@
# 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
def add_person_and_organisation(
file: ifcopenshell.file,
person: ifcopenshell.entity_instance,
organisation: ifcopenshell.entity_instance,
) -> ifcopenshell.entity_instance:
"""Adds a paired person and organisation
A person and an organisation may be paired to create a representative
belonging to a company.
:param person: The IfcPerson being the representative of the
organisation.
:param organisation: The IfcOrganization it
:return: The newly created IfcPersonAndOrganization
Example:
.. code:: python
person = ifcopenshell.api.owner.add_person(model,
identification="lecorbycorbycorb", family_name="Curbosiar", given_name="Le")
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
ifcopenshell.api.owner.add_person_and_organisation(model,
person=person, organisation=organisation)
"""
return file.create_entity("IfcPersonAndOrganization", person, organisation)
@@ -0,0 +1,58 @@
# 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
def add_role(
file: ifcopenshell.file, assigned_object: ifcopenshell.entity_instance, role: str = "ARCHITECT"
) -> ifcopenshell.entity_instance:
"""Adds and assigns a new role
People and organisations must play one or more roles on a project. Roles
include architects, engineers, subcontractors, clients, manufacturers,
etc. Typically these roles and their corresponding responsibilities will
be outlined in contractual documents.
This function will both add and assign the role to the person or
organisation.
:param assigned_object: The IfcPerson or IfcOrganization the role should
be assigned to.
:param role: The type of role, taken from the IFC documentation for
IfcActorRole, or a custom name. Defaults to "ARCHITECT".
:return: The newly created IfcActorRole
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
ifcopenshell.api.owner.add_role(model, assigned_object=organisation, role="ARCHITECT")
"""
element = file.create_entity("IfcActorRole", Role="ARCHITECT")
if role:
try:
element.Role = role
except:
element.Role = "USERDEFINED"
element.UserDefinedRole = role
roles = list(assigned_object.Roles) if assigned_object.Roles else []
roles.append(element)
assigned_object.Roles = roles
return element
@@ -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/>.
import ifcopenshell
import ifcopenshell.api.owner
import ifcopenshell.guid
def assign_actor(
file: ifcopenshell.file, relating_actor: ifcopenshell.entity_instance, related_object: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
"""Assigns an actor to an object
An actor may be assigned to objects which implies that the actor is
responsible for. This is most commonly used in facility management for
indicating the manufacturers, suppliers, and warrantors for product
types.
Here are a list of objects you may assign an actor to:
* IfcControl: Indicates project directives issued by the actor.
* IfcGroup: Indicates groups for which the actor is responsible.
* IfcProduct: Indicates products for which the actor is responsible.
* IfcProcess: Indicates processes for which the actor is responsible.
* IfcResource: Indicates resources for which the actor is responsible to
allocate, manage, or delegate. This is not the actor actually using
the resource or performing the work. For that type of actor, see
ifcopenshell.api.resource.assign_resource.
:param relating_actor: The IfcActor who is responsible for the object.
:param related_object: The object the actor is responsible for.
:return: The newly created IfcRelAssignsToActor relationship.
Example:
.. code:: python
# We need to procure and install 2 of this particular pump type in our facility.
pump_type = ifcopenshell.api.root.create_entity(model, ifc_class="IfcPumpType")
# Define who the manufacturer is
manufacturer = ifcopenshell.api.owner.add_organisation(model,
identification="PWP", name="Pumps With Power")
ifcopenshell.api.owner.add_role(model, assigned_object=manufacturer, role="MANUFACTURER")
# To help our facility manager, it's nice to provide contact details
# of the manufacturer so they know how to call when the pump breaks.
telecom = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcTelecomAddress")
ifcopenshell.api.owner.edit_address(model, address=telecom,
attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"],
"ElectronicMailAddresses": ["contact@example.com"],
"WWWHomePageURL": "https://example.com"})
# Make the manufacturer responsible for that pump type.
ifcopenshell.api.owner.assign_actor(model,
relating_actor=manufacturer, related_object=pump_type)
"""
if related_object.HasAssignments:
for rel in related_object.HasAssignments:
if rel.is_a("IfcRelAssignsToActor") and rel.RelatingActor == relating_actor:
return rel
rel = None
if relating_actor.IsActingUpon:
rel = relating_actor.IsActingUpon[0]
if rel:
related_objects = list(rel.RelatedObjects)
related_objects.append(related_object)
rel.RelatedObjects = related_objects
ifcopenshell.api.owner.update_owner_history(file, element=rel)
else:
rel = file.create_entity(
"IfcRelAssignsToActor",
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
"RelatedObjects": [related_object],
"RelatingActor": relating_actor,
}
)
return rel
@@ -0,0 +1,117 @@
# 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 time
from typing import Union
import ifcopenshell
import ifcopenshell.api.owner.settings
def create_owner_history(file: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None]:
"""Creates a new owner history indicating an element was added
Any object in IFC with a unique ID and name (such as physical products,
tasks, calendars, etc) may have an owner associated with it. An owner is
a liable person and/or organisation which a bit of metadata indicating
whether they have created the object, edited the object, when the change
was made, and which application they used.
IFC does not offer a comprehensive specification for version control and
change tracking, as this is completely out of scope. However this
similar ability allows IFC to satisfy legal requirements where object
ownership, responsibilities, and permissions must be specified.
Recording the owner is mandatory in IFC2X3 but optional in IFC4. It is
not recommended to store this ownership data in IFC4 unless a legal
requirement is in place.
Because owner tracking is mandatory in IFC2X3, be aware that some
configuration may be required to work correctly. Read on.
To track the owner, at a minimum we have to know the application that
the element was authored from, as well as the user (person and
organisation) that made the change. The IfcOpenShell API is a low level
software library and will not know what application the API is being
called from, and nor does it have the responsibility to manage the
"active user" making edits, which may be as simple as hardcoding it to
"Bob" or even be as complex as integration with a CDE's authentication
system. As a result, the developer responsible to integrate with
IfcOpenShell is expected to overload the
ifcopenshell.api.owner.settings.get_user and
ifcopenshell.api.owner.settings.get_application functions.
It is not necessary to call this function directly if you are already
using other API calls. It is a low level function only available if you
are writing your own advanced scripts and want to take advantage of the
easier ownership tracking.
:return: The newly created IfcOwnerHistory element or `None` if it's
not IFC2X3 and user or application is not found in the current project.
Example:
.. code:: python
# Let's imagine we're writing a small script, not large enough to be
# its own fully branded application. In this case, let's use the
# default application which is prepopulated with "IfcOpenShell" as
# the name and version.
application = ifcopenshell.api.owner.add_application(model)
# Let's imagine we run this as an automated QA process in an
# architectural firm. However, the results must be signed off by the
# registered architect who is liable for the project.
person = ifcopenshell.api.owner.add_person(model,
identification="LPARTEE", family_name="Partee", given_name="Leeable")
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
user = ifcopenshell.api.owner.add_person_and_organisation(model,
person=person, organisation=organisation)
# Let's configure our owner settings to hardcode always returning
# the application and user. In theory, you could build complex user
# access control lookup functions here, but this is simple enough.
ifcopenshell.api.owner.settings.get_user = lambda x: user
ifcopenshell.api.owner.settings.get_application = lambda x: application
# We've finished our ownership setup. Now let's start our script and
# create a space. Notice we don't actually call
# create_owner_history at all. This is already automatically handled
# by the API when necessary. Under the hood, the API is actually
# running this code on the IfcSpace element:
# element.OwnerHistory = ifcopenshell.api.owner.create_owner_history(model)
space = ifcopenshell.api.root.create_entity(model, ifc_class="IfcSpace")
"""
user = ifcopenshell.api.owner.settings.get_user(file)
if file.schema != "IFC2X3" and not user:
return
application = ifcopenshell.api.owner.settings.get_application(file)
if file.schema != "IFC2X3" and not application:
return
return file.create_entity(
"IfcOwnerHistory",
OwningUser=user,
OwningApplication=application,
State="READWRITE",
ChangeAction="ADDED",
LastModifiedDate=int(time.time()),
LastModifyingUser=user,
LastModifyingApplication=application,
CreationDate=int(time.time()),
)
@@ -0,0 +1,51 @@
# 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/>.
from typing import Any
import ifcopenshell
def edit_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
"""Edits the attributes of an IfcActor
For more information about the attributes and data types of an
IfcActor, consult the IFC documentation.
:param actor: The IfcActor entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
# Setup an organisation with a single role
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
role = ifcopenshell.api.owner.add_role(model, assigned_object=organisation)
ifcopenshell.api.owner.edit_role(model, role=role, attributes={"Role": "ARCHITECT"})
# Assign that organisation to a newly created actor
actor = ifcopenshell.api.owner.add_actor(model, actor=organisation)
# Edit the description of the attribute.
ifcopenshell.api.actor.edit_actor(model,
actor=actor, attributes={"Description": "Responsible for buildings A, B, and C."})
"""
for name, value in attributes.items():
setattr(actor, name, value)
@@ -0,0 +1,53 @@
# 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_address(file: ifcopenshell.file, address: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
"""Edits the attributes of an IfcAddress
For more information about the attributes and data types of an
IfcAddress, consult the IFC documentation.
:param address: The IfcAddress entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
# A snail mail address
postal = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcPostalAddress")
ifcopenshell.api.owner.edit_address(model, address=postal,
attributes={"Purpose": "OFFICE", "AddressLines": ["42 Wallaby Way"],
"Town": "Sydney", "Region": "NSW", "PostalCode": "2000"})
# A phone or internet address
telecom = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcTelecomAddress")
ifcopenshell.api.owner.edit_address(model, address=telecom,
attributes={"Purpose": "OFFICE", "TelephoneNumbers": ["+61432466949"],
"ElectronicMailAddresses": ["bobthebuilder@example.com"],
"WWWHomePageURL": "https://thinkmoult.com"})
"""
for name, value in attributes.items():
setattr(address, name, value)
@@ -0,0 +1,45 @@
# 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_application(
file: ifcopenshell.file, application: ifcopenshell.entity_instance, attributes: dict[str, Any]
) -> None:
"""Edits the attributes of an IfcApplication
For more information about the attributes and data types of an
IfcApplication, consult the IFC documentation.
:param application: The IfcApplication entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
application = ifcopenshell.api.owner.add_application(model,
application_full_name="My App")
ifcopenshell.api.owner.edit_application(model, application=application,
attributes={"ApplicationFullName": "My App New Name"})
"""
for name, value in attributes.items():
setattr(application, name, value)
@@ -0,0 +1,45 @@
# 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_organisation(
file: ifcopenshell.file, organisation: ifcopenshell.entity_instance, attributes: dict[str, Any]
) -> None:
"""Edits the attributes of an IfcOrganization
For more information about the attributes and data types of an
IfcOrganization, consult the IFC documentation.
:param organisation: The IfcOrganization entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects With Ballpens")
ifcopenshell.api.owner.edit_organisation(model, organisation=organisation,
attributes={"name": "Architects Without Ballpens"})
"""
for name, value in attributes.items():
setattr(organisation, name, value)
@@ -0,0 +1,43 @@
# 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_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
"""Edits the attributes of an IfcPerson
For more information about the attributes and data types of an
IfcPerson, consult the IFC documentation.
:param person: The IfcPerson entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
person = ifcopenshell.api.owner.add_person(model,
identification="bobthebuilder", family_name="Thebuilder", given_name="Bob")
ifcopenshell.api.owner.edit_person(model, person=person,
attributes={"MiddleNames": ["The"], "FamilyName": "Builder"})
"""
for name, value in attributes.items():
setattr(person, name, value)
@@ -0,0 +1,47 @@
# 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_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
"""Edits the attributes of an IfcActorRole
For more information about the attributes and data types of an
IfcActorRole, consult the IFC documentation.
:param role: The IfcActorRole entity you want to edit
:param attributes: a dictionary of attribute names and values.
:return: None
Example:
.. code:: python
person = ifcopenshell.api.owner.add_person(model,
identification="bobthebuilder", family_name="Thebuilder", given_name="Bob")
# By default, the role is an architect
role = ifcopenshell.api.owner.add_role(model, assigned_object=person)
# But Bob is not an architect
ifcopenshell.api.owner.edit_role(model, role=role, attributes={"Role": "CONSTRUCTIONMANAGER"})
"""
for name, value in attributes.items():
setattr(role, name, value)
@@ -0,0 +1,48 @@
# 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/>.
import ifcopenshell
import ifcopenshell.util.element
def remove_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance) -> None:
"""Removes an actor
:param actor: The IfcActor to remove.
:return: None
Example:
.. code:: python
# Setup an organisation with a single role
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
role = ifcopenshell.api.owner.add_role(model, assigned_object=organisation)
ifcopenshell.api.owner.edit_role(model, role=role, attributes={"Role": "ARCHITECT"})
# Assign that organisation to a newly created actor
actor = ifcopenshell.api.owner.add_actor(model, actor=organisation)
# Actually we need ballpens on this project
ifcopenshell.api.owner.remove_actor(model, actor=actor)
"""
history = actor.OwnerHistory
file.remove(actor)
if history:
ifcopenshell.util.element.remove_deep2(file, history)
@@ -0,0 +1,45 @@
# 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
def remove_address(file: ifcopenshell.file, address: ifcopenshell.entity_instance) -> None:
"""Removes an address
Naturally, any organisations or people using that address will have the
relationship removed.
:param address: The IfcAddress to remove.
:return: None
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model)
address = ifcopenshell.api.owner.add_address(model,
assigned_object=organisation, ifc_class="IfcPostalAddress")
# Change our mind and delete it
ifcopenshell.api.owner.remove_address(model, address=address)
"""
for inverse in file.get_inverse(address):
if inverse.is_a() in ("IfcOrganization", "IfcPerson"):
if inverse.Addresses == (address,):
inverse.Addresses = None
file.remove(address)
@@ -0,0 +1,37 @@
# 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
def remove_application(file: ifcopenshell.file, application: ifcopenshell.entity_instance) -> None:
"""Removes an application
Warning: removing an application may invalidate ownership histories.
Check whether or not the application is used anywhere prior to removal.
:param address: The IfcApplication to remove.
:return: None
Example:
.. code:: python
application = ifcopenshell.api.owner.add_application(model)
ifcopenshell.api.owner.remove_address(model, application=application)
"""
file.remove(application)
@@ -0,0 +1,65 @@
# 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.owner
import ifcopenshell.api.root
def remove_organisation(file: ifcopenshell.file, organisation: ifcopenshell.entity_instance) -> None:
"""Remove an organisation
All roles and addresses assigned to the organisation will also be
removed.
:param organisation: The IfcOrganization to remove
:return: None
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
ifcopenshell.api.owner.remove_organisation(model, organisation=organisation)
"""
for role in organisation.Roles or []:
if (file.get_total_inverses(role)) == 1:
ifcopenshell.api.owner.remove_role(file, role=role)
for address in organisation.Addresses or []:
if (file.get_total_inverses(address)) == 1:
ifcopenshell.api.owner.remove_address(file, address=address)
for inverse in file.get_inverse(organisation):
if inverse.is_a("IfcOrganizationRelationship"):
if inverse.RelatingOrganization == organisation:
file.remove(inverse)
elif inverse.RelatedOrganizations == (organisation,):
file.remove(inverse)
elif inverse.is_a("IfcDocumentInformation"):
if inverse.Editors == (organisation,):
inverse.Editors = None
elif inverse.is_a("IfcPersonAndOrganization"):
ifcopenshell.api.owner.remove_person_and_organisation(file, person_and_organisation=inverse)
elif inverse.is_a("IfcActor"):
ifcopenshell.api.root.remove_product(file, product=inverse)
elif inverse.is_a("IfcResourceLevelRelationship") and not inverse.is_a("IfcOrganizationRelationship"):
if inverse.RelatedResourceObjects == (organisation,):
file.remove(inverse)
elif inverse.is_a("IfcApplication"):
ifcopenshell.api.owner.remove_application(file, application=inverse)
file.remove(organisation)
@@ -0,0 +1,68 @@
# 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.owner
import ifcopenshell.api.root
def remove_person(file: ifcopenshell.file, person: ifcopenshell.entity_instance) -> None:
"""Remove an person
All roles and addresses assigned to the person will also be
removed.
In IFC2X3 will also remove related inventories if `person` was
the only responsile person for them.
:param person: The IfcPerson to remove
:return: None
Example:
.. code:: python
ifcopenshell.api.owner.add_person(model,
identification="bobthebuilder", family_name="Thebuilder", given_name="Bob")
ifcopenshell.api.owner.remove_person(model, person=person)
"""
for role in person.Roles or []:
if file.get_total_inverses(role) == 1:
ifcopenshell.api.owner.remove_role(file, role=role)
for address in person.Addresses or []:
if file.get_total_inverses(address) == 1:
ifcopenshell.api.owner.remove_address(file, address=address)
for inverse in file.get_inverse(person):
if inverse.is_a("IfcWorkControl"):
if inverse.Creators == (person,):
inverse.Creators = None
elif inverse.is_a("IfcInventory"):
if inverse.ResponsiblePersons == (person,):
# in IFC2X3 ResponsiblePersons is not optional and without it IfcInventory is not valid
if file.schema == "IFC2X3":
ifcopenshell.api.root.remove_product(file, product=inverse)
elif inverse.is_a("IfcDocumentInformation"):
if inverse.Editors == (person,):
inverse.Editors = None
elif inverse.is_a("IfcPersonAndOrganization"):
ifcopenshell.api.owner.remove_person_and_organisation(file, person_and_organisation=inverse)
elif inverse.is_a("IfcActor"):
ifcopenshell.api.root.remove_product(file, product=inverse)
elif inverse.is_a("IfcResourceLevelRelationship"):
if inverse.RelatedResourceObjects == (person,):
file.remove(inverse)
file.remove(person)
@@ -0,0 +1,58 @@
# 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.root
def remove_person_and_organisation(
file: ifcopenshell.file, person_and_organisation: ifcopenshell.entity_instance
) -> None:
"""Removes a person and organisation
Note that the underlying person and organisation is not removed, only
the "person and organisation" group.
:param person_and_organisation: The IfcPersonAndOrganization to remove.
:return: None
Example:
.. code:: python
person = ifcopenshell.api.owner.add_person(model,
identification="lecorbycorbycorb", family_name="Curbosiar", given_name="Le")
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
user = ifcopenshell.api.owner.add_person_and_organisation(model,
person=person, organisation=organisation)
ifcopenshell.api.owner.remove_person_and_organisation(model, person_and_organisation=user)
"""
for inverse in file.get_inverse(person_and_organisation):
if inverse.is_a("IfcDocumentInformation"):
if inverse.Editors == (person_and_organisation,):
inverse.Editors = None
elif inverse.is_a("IfcActor"):
ifcopenshell.api.root.remove_product(file, product=inverse)
elif inverse.is_a("IfcResourceLevelRelationship"):
if inverse.RelatedResourceObjects == (person_and_organisation,):
file.remove(inverse)
elif inverse.is_a("IfcOwnerHistory"):
file.remove(inverse)
file.remove(person_and_organisation)
@@ -0,0 +1,49 @@
# 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
def remove_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance) -> None:
"""Removes a role
People and organisations using the role will be untouched. This may
leave some of them without roles.
:param role: The IfcActorRole to remove.
:return: None
Example:
.. code:: python
organisation = ifcopenshell.api.owner.add_organisation(model,
identification="AWB", name="Architects Without Ballpens")
role = ifcopenshell.api.owner.add_role(model, assigned_object=organisation, role="ARCHITECT")
# After running this, the organisation will have no role again
ifcopenshell.api.owner.remove_role(model, role=role)
"""
for inverse in file.get_inverse(role):
if inverse.is_a() in ("IfcOrganization", "IfcPerson", "IfcPersonAndOrganization"):
if inverse.Roles == (role,):
inverse.Roles = None
elif inverse.is_a("IfcResourceLevelRelationship"):
# IfcResourceConstraintRelationship or other rels with IfcResourceObjectSelect.
if inverse.RelatedResourceObjects == (role,):
file.remove(inverse)
file.remove(role)
@@ -0,0 +1,103 @@
# 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/>.
# Note: it is the intent for you to override these with your own functions
from typing import Union
import ifcopenshell
def get_application(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None]:
"""Returns the application representing the authoring software
It is expected for you to overload this function with your own
IfcApplication. See ifcopenshell.api.owner.create_owner_history for details.
:param ifc: The IFC file object that is being edited.
:return: The IfcApplication with metadata of the authoring software.
"""
app = next(iter(ifc.by_type("IfcApplication")), None)
if not app and ifc.schema == "IFC2X3":
raise Exception(
"Please create an application to continue. See the owner.create_owner_history docs for more info."
"https://docs.ifcopenshell.org/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
)
return app
def get_user(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None]:
"""Returns the active authoring user
It is expected for you to overload this function with your own
IfcApplication. See ifcopenshell.api.owner.create_owner_history for details.
:param ifc: The IFC file object that is being edited.
:return: The IfcPersonAndOrganization with metadata of the authoring user.
"""
pao = next(iter(ifc.by_type("IfcPersonAndOrganization")), None)
if not pao and ifc.schema == "IFC2X3":
raise Exception(
"Please create a user to continue. See the owner.create_owner_history docs for more info."
"https://docs.ifcopenshell.org/autoapi/ifcopenshell/api/owner/create_owner_history/index.html"
)
return pao
get_application_factory = get_application
get_application_backup = get_application
get_user_factory = get_user
get_user_backup = get_user
def factory_reset():
"""Reset the get_user and get_application functions to what came out of box
When you are developing a custom application, you will typically override
the get_user and get_application function to your own needs. Sometimes you
want to reset it to before you monkey-patched it. This function does that
reset.
"""
global get_application_factory
global get_application_backup
global get_application
global get_user_factory
global get_user_backup
global get_user
get_application_backup = get_application
get_application = get_application_factory
get_user_backup = get_user
get_user = get_user_factory
def restore():
"""Restore the get_user and get_application function prior to a reset
In case you want to restore the monkey-patched version of get_user and
get_application that existed before you applied a factory_reset(), this
function will do that.
"""
global get_application_factory
global get_application_backup
global get_application
global get_user_factory
global get_user_backup
global get_user
get_application = get_application_backup
get_user = get_user_backup
@@ -0,0 +1,67 @@
# 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_actor(
file: ifcopenshell.file, relating_actor: ifcopenshell.entity_instance, related_object: ifcopenshell.entity_instance
) -> None:
"""Unassigns an actor to an object
This means that the actor is no longer responsible for the object.
:param relating_actor: The IfcActor who is responsible for the object.
:param related_object: The object the actor is responsible for.
:return: None
Example:
.. code:: python
# We need to procure and install 2 of this particular pump type in our facility.
pump_type = ifcopenshell.api.root.create_entity(model, ifc_class="IfcPumpType")
# Define who the manufacturer is
manufacturer = ifcopenshell.api.owner.add_organisation(model,
identification="PWP", name="Pumps With Power")
ifcopenshell.api.owner.add_role(model, assigned_object=manufacturer, role="MANUFACTURER")
# Make the manufacturer responsible for that pump type.
ifcopenshell.api.owner.assign_actor(model,
relating_actor=manufacturer, related_object=pump_type)
# Undo the assignment
ifcopenshell.api.owner.unassign_actor(model,
relating_actor=manufacturer, related_object=pump_type)
"""
for rel in related_object.HasAssignments or []:
if not rel.is_a("IfcRelAssignsToActor") or rel.RelatingActor != relating_actor:
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)
@@ -0,0 +1,88 @@
# 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 time
from typing import Union
import ifcopenshell
import ifcopenshell.api.owner.settings
import ifcopenshell.util.element
def update_owner_history(
file: ifcopenshell.file, element: ifcopenshell.entity_instance
) -> Union[ifcopenshell.entity_instance, None]:
"""Updates the owner that is assigned to an object
This ensures that the owner is tracked to have modified the object last,
including the time when the change occured. See
ifcopenshell.api.owner.create_owner_history for details.
:param element: The IfcRoot element to update the ownership details on
when a change is made.
:return: The updated IfcOwnerHistory element.
Example:
.. code:: python
# See ifcopenshell.api.owner.create_owner_history for setup
# [ ... example setup code ... ]
# We've finished our ownership setup. Now let's start our script and
# create a space. Notice we don't actually call
# create_owner_history at all. This is already automatically handled
# by the API when necessary. Under the hood, the API is actually
# running this code on the IfcSpace element:
# element.OwnerHistory = ifcopenshell.api.owner.create_owner_history(model)
space = ifcopenshell.api.root.create_entity(model, ifc_class="IfcSpace")
# Any edits we make will have ownership tracking automatically
# applied. There is no need to run any owner.update_owner_history
# API calls either.
ifcopenshell.api.attribute.edit_attributes(model, product=space, attributes={"Name": "Lobby"})
"""
if not element.is_a("IfcRoot"):
return
user = ifcopenshell.api.owner.settings.get_user(file)
if not user:
return
application = ifcopenshell.api.owner.settings.get_application(file)
if not application:
return
# 1 IfcRoot IfcOwnerHistory
owner_history = element[1]
if not owner_history:
owner_history = ifcopenshell.api.owner.create_owner_history(file)
element[1] = owner_history
return owner_history
if file.get_total_inverses(owner_history) > 1:
owner_history = ifcopenshell.util.element.copy(file, owner_history)
element[1] = owner_history
# 3 IfcOwnerHistory ChangeAction
owner_history[3] = "MODIFIED"
# 4 IfcOwnerHistory LastModifiedDate
owner_history[4] = int(time.time())
# 5 IfcOwnerHistory LastModifyingUser
owner_history[5] = user
# 6 IfcOwnerHistory LastModifyingApplication
owner_history[6] = application
return owner_history