ifc2sql - support saving element types geometry

This commit is contained in:
Andrej730
2025-09-05 11:48:57 +05:00
parent 062bf8e60b
commit 0cf3bb3da9
+39 -12
View File
@@ -33,6 +33,7 @@ import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.attribute
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import ifcopenshell.util.schema
import ifcopenshell.util.shape
import ifcopenshell.util.unit
@@ -249,29 +250,29 @@ class Patcher(ifcpatch.BasePatcher):
self.geometry_rows = {}
if self.file.schema in ("IFC2X3", "IFC4"):
self.elements = self.file.by_type("IfcElement") + self.file.by_type("IfcProxy")
elements = self.file.by_type("IfcElement") + self.file.by_type("IfcProxy")
else:
self.elements = self.file.by_type("IfcElement")
elements = self.file.by_type("IfcElement")
self.settings = ifcopenshell.geom.settings()
self.settings.set("apply-default-materials", False)
self.body_contexts = [
body_contexts = [
c.id()
for c in self.file.by_type("IfcGeometricRepresentationSubContext")
if c.ContextIdentifier in ["Body", "Facetation"]
]
# Ideally, all representations should be in a subcontext, but some BIM programs don't do this correctly
self.body_contexts.extend(
body_contexts.extend(
[
c.id()
for c in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False)
if c.ContextType == "Model"
]
)
self.settings.set("context-ids", self.body_contexts)
self.settings.set("context-ids", body_contexts)
products = self.elements
products = elements
iterator = ifcopenshell.geom.iterator(self.settings, self.file, multiprocessing.cpu_count(), include=products)
valid_file = iterator.initialize()
if not valid_file:
@@ -301,12 +302,7 @@ class Patcher(ifcpatch.BasePatcher):
geometry = shape.geometry
geometry_id = geometry.id
if geometry_id not in self.geometry_rows:
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 geometry.materials])
self.geometry_rows[geometry_id] = (geometry_id, v, e, f, mids, m)
self.add_geometry_row(geometry_id, geometry)
# Copy required since otherwise it is read-only
m = ifcopenshell.util.shape.get_shape_matrix(shape).copy()
m[:3, 3] /= self.unit_scale
@@ -315,6 +311,37 @@ class Patcher(ifcpatch.BasePatcher):
if not iterator.next():
break
# Process element types geometry.
element_types = self.file.by_type("IfcElementType")
body_contexts = [self.file.by_id(i) for i in body_contexts]
m_bytes = np.eye(4, dtype=np.float64).tobytes()
for element_type in element_types:
representation = None
for context in body_contexts:
representation = ifcopenshell.util.representation.get_representation(element_type, context)
if representation:
break
geometry_id = None
if representation:
geometry_id_ = str(representation.id())
if geometry_id_ in self.geometry_rows:
geometry_id = geometry_id_
elif geometry := ifcopenshell.geom.create_shape(self.settings, representation):
geometry_id = geometry_id_
assert isinstance(geometry, W.Triangulation)
self.add_geometry_row(geometry_id, geometry)
shape_id = element_type.id()
self.shape_rows[shape_id] = (shape_id, *(0.0, 0.0, 0.0), m_bytes, geometry_id)
def add_geometry_row(self, geometry_id: str, geometry: W.Triangulation) -> None:
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 geometry.materials])
self.geometry_rows[geometry_id] = (geometry_id, v, e, f, mids, m)
def check_existing_ifc_database(self) -> None:
if self.sql_type == "sqlite":
cursor = self.c.execute("SELECT 1 FROM sqlite_master WHERE type='table' AND name='id_map'")