This commit is contained in:
Andrej730
2024-04-26 15:14:00 +05:00
parent 344cc1fb7d
commit 31d85b715a
10 changed files with 75 additions and 33 deletions
+2 -2
View File
@@ -223,7 +223,7 @@ def redo_post(scene):
tool.Ifc.rebuild_element_maps() tool.Ifc.rebuild_element_maps()
def get_application(ifc): def get_application(ifc: ifcopenshell.file) -> ifcopenshell.entity_instance:
# TODO: cache this for even faster application retrieval. It honestly makes a difference on long scripts. # TODO: cache this for even faster application retrieval. It honestly makes a difference on long scripts.
version = get_application_version() version = get_application_version()
for element in ifc.by_type("IfcApplication"): for element in ifc.by_type("IfcApplication"):
@@ -238,7 +238,7 @@ def get_application(ifc):
) )
def get_application_version(): def get_application_version() -> str:
return ".".join( return ".".join(
[ [
str(x) str(x)
+3 -1
View File
@@ -19,6 +19,8 @@
import bpy import bpy
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
import ifcopenshell
from typing import Union
class Owner(blenderbim.core.tool.Owner): class Owner(blenderbim.core.tool.Owner):
@@ -27,7 +29,7 @@ class Owner(blenderbim.core.tool.Owner):
bpy.context.scene.BIMOwnerProperties.active_user_id = user.id() bpy.context.scene.BIMOwnerProperties.active_user_id = user.id()
@classmethod @classmethod
def get_user(cls): def get_user(cls) -> Union[ifcopenshell.entity_instance, None]:
if bpy.context.scene.BIMOwnerProperties.active_user_id: if bpy.context.scene.BIMOwnerProperties.active_user_id:
return tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_user_id) return tool.Ifc.get().by_id(bpy.context.scene.BIMOwnerProperties.active_user_id)
elif tool.Ifc.get_schema() == "IFC2X3": elif tool.Ifc.get_schema() == "IFC2X3":
@@ -17,20 +17,34 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import numpy as np import numpy as np
import numpy.typing as npt
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.placement import ifcopenshell.util.placement
from typing import Optional, Union
NPArrayOfFloats = npt.NDArray[np.float64]
class Usecase: class Usecase:
def __init__(self, file, **settings): def __init__(
self,
file: ifcopenshell.file,
product: ifcopenshell.entity_instance,
matrix: Optional[NPArrayOfFloats] = None,
is_si=True,
should_transform_children=False,
):
self.file = file self.file = file
self.settings = {"product": None, "matrix": np.eye(4), "is_si": True, "should_transform_children": False} self.settings = {
for key, value in settings.items(): "product": product,
self.settings[key] = value "matrix": matrix if matrix is not None else np.eye(4),
"is_si": is_si,
"should_transform_children": should_transform_children,
}
def execute(self): def execute(self) -> ifcopenshell.entity_instance:
if not hasattr(self.settings["product"], "ObjectPlacement"): if not hasattr(self.settings["product"], "ObjectPlacement"):
return return
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
@@ -69,12 +83,12 @@ class Usecase:
return new_placement return new_placement
def convert_matrix_to_si(self, matrix): def convert_matrix_to_si(self, matrix: NPArrayOfFloats):
matrix[0][3] *= self.unit_scale matrix[0][3] *= self.unit_scale
matrix[1][3] *= self.unit_scale matrix[1][3] *= self.unit_scale
matrix[2][3] *= self.unit_scale matrix[2][3] *= self.unit_scale
def get_placement_rel_to(self): def get_placement_rel_to(self) -> Union[ifcopenshell.entity_instance, None]:
if getattr(self.settings["product"], "Decomposes", None): if getattr(self.settings["product"], "Decomposes", None):
relating_object = self.settings["product"].Decomposes[0].RelatingObject relating_object = self.settings["product"].Decomposes[0].RelatingObject
return relating_object.ObjectPlacement if hasattr(relating_object, "ObjectPlacement") else None return relating_object.ObjectPlacement if hasattr(relating_object, "ObjectPlacement") else None
@@ -96,7 +110,7 @@ class Usecase:
elif getattr(self.settings["product"], "ContainedInStructure", None): elif getattr(self.settings["product"], "ContainedInStructure", None):
return self.settings["product"].ContainedInStructure[0].RelatingStructure.ObjectPlacement return self.settings["product"].ContainedInStructure[0].RelatingStructure.ObjectPlacement
def get_children_settings(self, placement): def get_children_settings(self, placement: Union[ifcopenshell.entity_instance, None]) -> list[dict]:
if not placement: if not placement:
return [] return []
results = [] results = []
@@ -116,7 +130,9 @@ class Usecase:
results.append({"product": obj, "matrix": matrix, "is_si": False, "should_transform_children": True}) results.append({"product": obj, "matrix": matrix, "is_si": False, "should_transform_children": True})
return results return results
def get_relative_placement(self, placement_rel_to): def get_relative_placement(
self, placement_rel_to: Union[ifcopenshell.entity_instance, None]
) -> ifcopenshell.entity_instance:
if placement_rel_to: if placement_rel_to:
relating_object_matrix = ifcopenshell.util.placement.get_local_placement(placement_rel_to) relating_object_matrix = ifcopenshell.util.placement.get_local_placement(placement_rel_to)
relating_object_matrix[0][3] = self.convert_unit_to_si(relating_object_matrix[0][3]) relating_object_matrix[0][3] = self.convert_unit_to_si(relating_object_matrix[0][3])
@@ -136,19 +152,21 @@ class Usecase:
relative_placement_matrix[:, 0][0:3], relative_placement_matrix[:, 0][0:3],
) )
def create_ifc_axis_2_placement_3d(self, point, up, forward): def create_ifc_axis_2_placement_3d(
self, point: NPArrayOfFloats, up: NPArrayOfFloats, forward: NPArrayOfFloats
) -> ifcopenshell.entity_instance:
return self.file.createIfcAxis2Placement3D( return self.file.createIfcAxis2Placement3D(
self.create_cartesian_point(point), self.create_cartesian_point(point),
self.file.createIfcDirection(up.tolist()), self.file.createIfcDirection(up.tolist()),
self.file.createIfcDirection(forward.tolist()), self.file.createIfcDirection(forward.tolist()),
) )
def create_cartesian_point(self, co): def create_cartesian_point(self, co: NPArrayOfFloats) -> ifcopenshell.entity_instance:
co = self.convert_si_to_unit(co) co = self.convert_si_to_unit(co)
return self.file.createIfcCartesianPoint(co.tolist()) return self.file.createIfcCartesianPoint(co.tolist())
def convert_si_to_unit(self, co): def convert_si_to_unit(self, co: NPArrayOfFloats) -> NPArrayOfFloats:
return co / self.unit_scale return co / self.unit_scale
def convert_unit_to_si(self, co): def convert_unit_to_si(self, co: NPArrayOfFloats) -> NPArrayOfFloats:
return co * self.unit_scale return co * self.unit_scale
@@ -15,10 +15,11 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell
class Usecase: class Usecase:
def __init__(self, file, identification="APTR", name="Aperture Science"): def __init__(self, file: ifcopenshell.file, identification: str = "APTR", name: str = "Aperture Science"):
"""Adds a new organisation """Adds a new organisation
Organisations are the main way to identify manufacturers, suppliers, and Organisations are the main way to identify manufacturers, suppliers, and
@@ -45,7 +46,7 @@ class Usecase:
self.file = file self.file = file
self.settings = {"identification": identification, "name": name} self.settings = {"identification": identification, "name": name}
def execute(self): def execute(self) -> ifcopenshell.entity_instance:
data = {"Name": self.settings["name"]} data = {"Name": self.settings["name"]}
if self.file.schema == "IFC2X3": if self.file.schema == "IFC2X3":
data["Id"] = self.settings["identification"] data["Id"] = self.settings["identification"]
@@ -15,10 +15,17 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell
class Usecase: class Usecase:
def __init__(self, file, identification="HSeldon", family_name="Seldon", given_name="Hari"): def __init__(
self,
file: ifcopenshell.entity_instance,
identification: str = "HSeldon",
family_name: str = "Seldon",
given_name: str = "Hari",
):
"""Adds a new person """Adds a new person
Persons are used to identify a legal or liable representative of an Persons are used to identify a legal or liable representative of an
@@ -48,7 +55,7 @@ class Usecase:
"given_name": given_name, "given_name": given_name,
} }
def execute(self): def execute(self) ->ifcopenshell.entity_instance:
data = {"FamilyName": self.settings["family_name"], "GivenName": self.settings["given_name"]} data = {"FamilyName": self.settings["family_name"], "GivenName": self.settings["given_name"]}
if self.file.schema == "IFC2X3": if self.file.schema == "IFC2X3":
data["Id"] = self.settings["identification"] data["Id"] = self.settings["identification"]
@@ -15,10 +15,16 @@
# #
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell
class Usecase: class Usecase:
def __init__(self, file, person=None, organisation=None): def __init__(
self,
file: ifcopenshell.entity_instance,
person: ifcopenshell.entity_instance,
organisation: ifcopenshell.entity_instance,
):
"""Adds a paired person and organisation """Adds a paired person and organisation
A person and an organisation may be paired to create a representative A person and an organisation may be paired to create a representative
@@ -47,5 +53,5 @@ class Usecase:
self.file = file self.file = file
self.settings = {"person": person, "organisation": organisation} self.settings = {"person": person, "organisation": organisation}
def execute(self): def execute(self) -> ifcopenshell.entity_instance:
return self.file.createIfcPersonAndOrganization(self.settings["person"], self.settings["organisation"]) return self.file.createIfcPersonAndOrganization(self.settings["person"], self.settings["organisation"])
@@ -19,10 +19,11 @@
import time import time
import ifcopenshell import ifcopenshell
import ifcopenshell.api.owner.settings import ifcopenshell.api.owner.settings
from typing import Union
class Usecase: class Usecase:
def __init__(self, file): def __init__(self, file: ifcopenshell.entity_instance):
"""Creates a new owner history indicating an element was added """Creates a new owner history indicating an element was added
Any object in IFC with a unique ID and name (such as physical products, Any object in IFC with a unique ID and name (such as physical products,
@@ -59,8 +60,9 @@ class Usecase:
are writing your own advanced scripts and want to take advantage of the are writing your own advanced scripts and want to take advantage of the
easier ownership tracking. easier ownership tracking.
:return: The newly created IfcOwnerHistory element. :return: The newly created IfcOwnerHistory element or `None` if it's
:rtype: ifcopenshell.entity_instance.entity_instance not IFC2X3 and user or application is not found in the current project.
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
Example: Example:
@@ -99,7 +101,7 @@ class Usecase:
self.file = file self.file = file
self.settings = {} self.settings = {}
def execute(self): def execute(self) -> Union[ifcopenshell.entity_instance, None]:
user = ifcopenshell.api.owner.settings.get_user(self.file) user = ifcopenshell.api.owner.settings.get_user(self.file)
if self.file.schema != "IFC2X3" and not user: if self.file.schema != "IFC2X3" and not user:
return return
@@ -23,7 +23,9 @@ import ifcopenshell.util.placement
class Usecase: class Usecase:
def __init__(self, file, opening=None, element=None): def __init__(
self, file: ifcopenshell.file, opening: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
):
"""Create an opening in an element """Create an opening in an element
It is often necessary to cut out openings in elements like walls and It is often necessary to cut out openings in elements like walls and
@@ -103,18 +105,18 @@ class Usecase:
self.file = file self.file = file
self.settings = {"opening": opening, "element": element} self.settings = {"opening": opening, "element": element}
def execute(self): def execute(self) -> ifcopenshell.entity_instance:
voids_elements = self.settings["opening"].VoidsElements voids_elements = self.settings["opening"].VoidsElements
if voids_elements: if voids_elements:
if voids_elements[0].RelatingBuildingElement == self.settings["element"]: if voids_elements[0].RelatingBuildingElement == self.settings["element"]:
return return voids_elements[0]
history = voids_elements[0].OwnerHistory history = voids_elements[0].OwnerHistory
self.file.remove(voids_elements[0]) self.file.remove(voids_elements[0])
if history: if history:
ifcopenshell.util.element.remove_deep2(self.file, history) ifcopenshell.util.element.remove_deep2(self.file, history)
self.file.create_entity( rel = self.file.create_entity(
"IfcRelVoidsElement", "IfcRelVoidsElement",
**{ **{
"GlobalId": ifcopenshell.guid.new(), "GlobalId": ifcopenshell.guid.new(),
@@ -133,3 +135,5 @@ class Usecase:
matrix=ifcopenshell.util.placement.get_local_placement(self.settings["opening"].ObjectPlacement), matrix=ifcopenshell.util.placement.get_local_placement(self.settings["opening"].ObjectPlacement),
is_si=False, is_si=False,
) )
return rel
@@ -17,10 +17,11 @@
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.element
class Usecase: class Usecase:
def __init__(self, file, opening=None): def __init__(self, file: ifcopenshell.entity_instance, opening: ifcopenshell.entity_instance):
"""Remove an opening """Remove an opening
Fillings are retained as orphans. Voided elements remain. Openings Fillings are retained as orphans. Voided elements remain. Openings
@@ -47,7 +48,7 @@ class Usecase:
self.file = file self.file = file
self.settings = {"opening": opening} self.settings = {"opening": opening}
def execute(self): def execute(self) -> None:
for rel in self.settings["opening"].VoidsElements: for rel in self.settings["opening"].VoidsElements:
history = rel.OwnerHistory history = rel.OwnerHistory
self.file.remove(rel) self.file.remove(rel)
@@ -67,8 +67,9 @@ def set_unsupported_attribute(*args):
_method_dict = {} _method_dict = {}
def register_schema_attributes(schema): def register_schema_attributes(schema: ifcopenshell_wrapper.schema_definition) -> None:
for decl in schema.declarations(): for decl in schema.declarations():
decl: ifcopenshell_wrapper.declaration
if hasattr(decl, "argument_types"): if hasattr(decl, "argument_types"):
fq_name = ".".join((schema.name(), decl.name())) fq_name = ".".join((schema.name(), decl.name()))