This commit is contained in:
Andrej
2025-06-02 10:58:39 +05:00
parent 5a211c67eb
commit a614fac71a
8 changed files with 59 additions and 55 deletions
-3
View File
@@ -74,9 +74,6 @@ class Loader(bonsai.core.tool.Loader):
def get_representation_id_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> int:
representation_id: str = geometry.id
if "-" in representation_id:
# Example: 2432-openings-2468, where
# 2432 is mapped representation id
# and 2468 is IFCRELVOIDSELEMENT
representation_id = re.sub(r"\D", "", representation_id.split("-")[0])
else:
representation_id = re.sub(r"\D", "", representation_id)
@@ -38,17 +38,12 @@ def add_application(
:param application_developer: The IfcOrganization responsible for
creating the application. Defaults to generating an IfcOpenShell
organisation if none is provided.
:type application_developer: ifcopenshell.entity_instance, optional
:param version: The version of the application. Defaults to the
ifcopenshell.version data if not specified.
:type version: str, optional
:param application_full_name: The name of the application
:type application_full_name: str, optional
:param application_identifier: An identification string for the
application intended for computers to read.
:type application_identifier: str, optional
:return: The newly created IfcApplication
:rtype: ifcopenshell.entity_instance
Example:
@@ -218,7 +218,7 @@ class Element:
@property
def guid(self): ...
@property
def id(self): ...
def id(self) -> int: ...
@property
def name(self): ...
@property
@@ -227,9 +227,9 @@ class Element:
@property
def product(self): ...
@property
def transformation(self): ...
def transformation(self) -> Transformation: ...
@property
def transformation_buffer(self): ...
def transformation_buffer(self) -> bytes: ...
@property
def type(self): ...
@property
@@ -342,7 +342,13 @@ class OpaqueNumber:
class Representation:
def entity(self): ...
@property
def id(self): ...
def id(self) -> str:
"""
Example: `2432-openings-2468`, where
- 2432 - mapped representation id
- 2468 - IfcRelVoidsElement
"""
def settings(self): ...
class Serialization(Representation):
@@ -458,34 +464,34 @@ class Triangulation(Representation):
@property
def colors_buffer(self): ...
@property
def edges(self): ...
def edges(self) -> tuple[int, ...]: ...
@property
def edges_buffer(self): ...
def edges_item_ids(self): ...
def edges_buffer(self) -> bytes: ...
def edges_item_ids(self) -> tuple[int, ...]: ...
@property
def edges_item_ids_buffer(self): ...
def edges_item_ids_buffer(self) -> bytes: ...
@staticmethod
def empty(settings): ...
@property
def faces(self): ...
def faces(self) -> tuple[int, ...]: ...
@property
def faces_buffer(self): ...
def faces_buffer(self) -> bytes: ...
@property
def faces_tri(self): ...
def faces_tri(self) -> tuple[int, ...]: ...
@property
def item_ids(self): ...
def item_ids(self) -> tuple[int, ...]: ...
@property
def item_ids_buffer(self): ...
def item_ids_buffer(self) -> bytes: ...
@property
def material_ids(self): ...
def material_ids(self) -> tuple[int, ...]: ...
@property
def material_ids_buffer(self): ...
def material_ids_buffer(self) -> bytes: ...
@property
def materials(self): ...
def materials(self) -> tuple[style, ...]: ...
@property
def normals(self): ...
@property
def normals_buffer(self): ...
def normals_buffer(self) -> bytes: ...
@property
def polyhedral_faces_with_holes(self): ...
@property
@@ -497,13 +503,13 @@ class Triangulation(Representation):
def uvs(self): ...
def uvs_ref(self): ...
@property
def verts(self): ...
def verts(self) -> tuple[float, ...]: ...
@property
def verts_buffer(self): ...
def verts_buffer(self) -> bytes: ...
class TriangulationElement(Element):
@property
def geometry(self): ...
def geometry(self) -> Triangulation: ...
def geometry_pointer(self): ...
class TriangulationType:
@@ -1183,7 +1189,19 @@ class style(item):
def get_color(self): ...
def has_specularity(self): ...
def has_transparency(self): ...
def instance_id(self): ...
def instance_id(self) -> int:
"""
Possible values for `instance_id`:
- IFC style id if style assigned to the representation items directly
or through material with a style;
- IFC material id if both true:
- element has a material without a style;
- there are parts of the geometry that has no other style assigned to them;
- -1 in case if there is no material;
- 0 in case if there are default materials used.
"""
...
def kind(self): ...
class surface(geom_item): ...
@@ -277,17 +277,7 @@ def get_normals(geometry: ShapeType) -> npt.NDArray[np.float64]:
def get_shape_material_styles(geometry: ShapeType) -> tuple[W.style, ...]:
"""Get list of material styles.
Possible values for `style.instance_id()`:
- IFC style id if style assigned to the representation items directly
or through material with a style;
- IFC material id if both true:
- element has a material without a style;
- there are parts of the geometry that has no other style assigned to them;
- -1 in case if there is no material;
- 0 in case if there are default materials used.
"""
"""Get list of material styles."""
return geometry.materials
+2 -4
View File
@@ -29,6 +29,7 @@ import collections
import importlib
import importlib.util
import re
from pathlib import Path
from typing import Union, Iterable, Optional, Any, TypedDict, Literal, Sequence
from typing_extensions import NotRequired
@@ -106,19 +107,16 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]:
return output
def write(output: Union[ifcopenshell.file, str], filepath: str) -> None:
def write(output: Union[ifcopenshell.file, str], filepath: Union[Path, str]) -> None:
"""Write the output of an IFC patch to a file
Typically a patch output would be a patched IFC model file object, or as a
string. This function lets you agnostically write that output to a filepath.
:param output: The results from ifcpatch.execute()
:type output: ifcopenshell.file.file,str
:param filepath: A filepath to where the results of the patched model should
be written to.
:type filepath: str
:return: None
:rtype: None
"""
if output is None:
return
@@ -63,7 +63,6 @@ class Patcher:
Allowed imperial units include INCH, FOOT, MILE.
:param unit: The name of the desired unit, defaults to "METER"
:type unit: LengthUnit
Example:
+17 -9
View File
@@ -29,6 +29,7 @@ import numpy as np
import multiprocessing
import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.attribute
import ifcopenshell.util.element
import ifcopenshell.util.placement
@@ -36,8 +37,8 @@ import ifcopenshell.util.schema
import ifcopenshell.util.shape
import ifcopenshell.util.unit
from pathlib import Path
from ifcopenshell.geom import ShapeType
from typing import Any, TYPE_CHECKING, Literal
from typing import Any, TYPE_CHECKING, Literal, Union
from typing_extensions import assert_never
SQLTypes = typing.Literal["SQLite", "MySQL"]
@@ -132,6 +133,9 @@ class Patcher:
self.should_get_geometry = should_get_geometry
self.should_skip_geometry_data = should_skip_geometry_data
geometry_rows: dict[str, tuple[str, bytes, bytes, bytes, bytes, str]]
shape_rows: dict[int, tuple[int, list[float], list[float], list[float], bytes, str]]
def patch(self) -> None:
suffix = ".db" if self.sql_type == "SQLite" else ".sqlite"
database = Path(self.database)
@@ -153,6 +157,8 @@ class Patcher:
host=self.host, user=self.username, password=self.password, database=str(database)
)
self.c = self.db.cursor()
else:
assert False
self.create_id_map()
self.create_metadata()
@@ -165,7 +171,9 @@ class Patcher:
self.create_geometry()
if self.full_schema:
ifc_classes = [d.name() for d in self.schema.declarations() if str(d).startswith("<entity")]
ifc_classes = [
d.name() for d in self.schema.declarations() if isinstance(d, ifcopenshell.ifcopenshell_wrapper.entity)
]
else:
ifc_classes = self.file.wrapped_data.types()
@@ -249,22 +257,22 @@ class Patcher:
checkpoint = time.time()
shape = iterator.get()
if shape:
assert isinstance(shape, W.TriangulationElement)
shape_id = shape.id
geometry_id = shape.geometry.id
geometry = shape.geometry
geometry_id = geometry.id
if geometry_id not in self.geometry_rows:
geometry: ShapeType
geometry = shape.geometry
v = geometry.verts_buffer
e = geometry.edges_buffer
f = geometry.faces_buffer
mids = geometry.material_ids_buffer
m = json.dumps([m.instance_id() for m in shape.geometry.materials])
self.geometry_rows[geometry_id] = [geometry_id, v, e, f, mids, m]
m = json.dumps([m.instance_id() for m in geometry.materials])
self.geometry_rows[geometry_id] = (geometry_id, v, e, f, mids, m)
# Copy required since otherwise it is read-only
m = ifcopenshell.util.shape.get_shape_matrix(shape).copy()
m[:3, 3] /= self.unit_scale
x, y, z = m[:, 3][0:3].tolist()
self.shape_rows[shape_id] = [shape_id, x, y, z, m.tobytes(), geometry_id]
self.shape_rows[shape_id] = (shape_id, x, y, z, m.tobytes(), geometry_id)
if not iterator.next():
break
-1
View File
@@ -35,7 +35,6 @@ class Patcher:
possible. Upgrading to IFC4 is more stable than downgrading to IFC2X3.
:param schema: The schema identifier of the IFC version to migrate to.
:type schema: str
Example: