mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Move common code to create_mesh_from_shape
This commit is contained in:
@@ -589,6 +589,7 @@ class IfcImporter:
|
|||||||
obj.hide_select = True
|
obj.hide_select = True
|
||||||
|
|
||||||
def create_generic_sqlite_elements(self, elements: set[ifcopenshell.entity_instance]) -> None:
|
def create_generic_sqlite_elements(self, elements: set[ifcopenshell.entity_instance]) -> None:
|
||||||
|
assert isinstance(self.file, ifcopenshell.sql.sqlite)
|
||||||
self.geometry_cache = self.file.get_geometry([e.id() for e in elements])
|
self.geometry_cache = self.file.get_geometry([e.id() for e in elements])
|
||||||
for geometry_id, geometry in self.geometry_cache["geometry"].items():
|
for geometry_id, geometry in self.geometry_cache["geometry"].items():
|
||||||
mesh_name = tool.Loader.get_mesh_name_from_shape(type("Geometry", (), {"id": geometry_id}))
|
mesh_name = tool.Loader.get_mesh_name_from_shape(type("Geometry", (), {"id": geometry_id}))
|
||||||
@@ -598,21 +599,9 @@ class IfcImporter:
|
|||||||
mesh["has_cartesian_point_offset"] = False
|
mesh["has_cartesian_point_offset"] = False
|
||||||
|
|
||||||
if geometry["faces"]:
|
if geometry["faces"]:
|
||||||
num_vertices = len(verts) // 3
|
mesh = tool.Loader.create_mesh_from_shape(
|
||||||
total_faces = len(geometry["faces"])
|
mesh=mesh, faces=geometry["faces"].reshape(-1, 3), verts=verts.reshape(-1, 3)
|
||||||
loop_start = range(0, total_faces, 3)
|
)
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(geometry["faces"])
|
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", geometry["faces"])
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.update()
|
|
||||||
else:
|
else:
|
||||||
e = geometry["edges"]
|
e = geometry["edges"]
|
||||||
v = verts
|
v = verts
|
||||||
|
|||||||
@@ -1848,21 +1848,7 @@ class LoadLinkedProject(bpy.types.Operator):
|
|||||||
|
|
||||||
material_index = np.array([(material_to_slot[i] if i != -1 else 0) for i in material_ids], dtype="I")
|
material_index = np.array([(material_to_slot[i] if i != -1 else 0) for i in material_ids], dtype="I")
|
||||||
|
|
||||||
num_vertices = len(verts) // 3
|
mesh = tool.Loader.create_mesh_from_shape(geometry, mesh)
|
||||||
total_faces = len(faces)
|
|
||||||
loop_start = range(0, total_faces, 3)
|
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(faces)
|
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", faces)
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", [0] * total_faces)
|
|
||||||
mesh.polygons.foreach_set("material_index", material_index)
|
mesh.polygons.foreach_set("material_index", material_index)
|
||||||
mesh.update()
|
mesh.update()
|
||||||
|
|
||||||
@@ -1890,29 +1876,13 @@ class LoadLinkedProject(bpy.types.Operator):
|
|||||||
num_vertices = len(verts) // 3
|
num_vertices = len(verts) // 3
|
||||||
if not num_vertices:
|
if not num_vertices:
|
||||||
return
|
return
|
||||||
total_faces = len(faces)
|
|
||||||
loop_start = range(0, total_faces, 3)
|
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(faces)
|
|
||||||
|
|
||||||
mesh = bpy.data.meshes.new("Mesh")
|
mesh = tool.Loader.create_mesh_from_shape(verts=verts.reshape(-1, 3), faces=faces.reshape(-1, 3))
|
||||||
|
|
||||||
for material in materials:
|
for material in materials:
|
||||||
mesh.materials.append(material)
|
mesh.materials.append(material)
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", faces)
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", [0] * total_faces)
|
|
||||||
|
|
||||||
if material_ids.size > 0 and len(mesh.polygons) == len(material_ids):
|
if material_ids.size > 0 and len(mesh.polygons) == len(material_ids):
|
||||||
mesh.polygons.foreach_set("material_index", material_ids)
|
mesh.polygons.foreach_set("material_index", material_ids)
|
||||||
|
|
||||||
mesh.update()
|
mesh.update()
|
||||||
|
|
||||||
obj = bpy.data.objects.new("Chunk", mesh)
|
obj = bpy.data.objects.new("Chunk", mesh)
|
||||||
|
|||||||
@@ -1188,27 +1188,7 @@ def create_mesh_from_shape(
|
|||||||
settings.set("keep-bounding-boxes", True)
|
settings.set("keep-bounding-boxes", True)
|
||||||
shape = ifcopenshell.geom.create_shape(settings, element)
|
shape = ifcopenshell.geom.create_shape(settings, element)
|
||||||
geometry = shape.geometry if element.is_a("IfcRoot") else shape
|
geometry = shape.geometry if element.is_a("IfcRoot") else shape
|
||||||
faces = geometry.faces
|
return tool.Loader.create_mesh_from_shape(geometry)
|
||||||
verts = geometry.verts
|
|
||||||
|
|
||||||
mesh = bpy.data.meshes.new("myBeautifulMesh")
|
|
||||||
|
|
||||||
num_vertices = len(verts) // 3
|
|
||||||
total_faces = len(faces)
|
|
||||||
loop_start = range(0, total_faces, 3)
|
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(faces)
|
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", faces)
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.update()
|
|
||||||
return mesh
|
|
||||||
|
|
||||||
|
|
||||||
def get_bmesh_from_mesh(mesh: bpy.types.Mesh) -> bmesh.types.BMesh:
|
def get_bmesh_from_mesh(mesh: bpy.types.Mesh) -> bmesh.types.BMesh:
|
||||||
|
|||||||
@@ -972,10 +972,7 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
if verts is None:
|
if verts is None:
|
||||||
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
||||||
faces = ifcopenshell.util.shape.get_faces(geometry)
|
faces = ifcopenshell.util.shape.get_faces(geometry)
|
||||||
total_faces: int
|
if faces.shape[0] > 0:
|
||||||
if total_faces := faces.shape[0]:
|
|
||||||
num_vertices: int = verts.shape[0]
|
|
||||||
|
|
||||||
# See bug 3546
|
# See bug 3546
|
||||||
# ios_edges holds true edges that aren't triangulated.
|
# ios_edges holds true edges that aren't triangulated.
|
||||||
#
|
#
|
||||||
@@ -984,38 +981,7 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
ios_item_ids = ifcopenshell.util.shape.get_faces_representation_item_ids(geometry).tolist()
|
ios_item_ids = ifcopenshell.util.shape.get_faces_representation_item_ids(geometry).tolist()
|
||||||
mesh["ios_item_ids"] = ios_item_ids
|
mesh["ios_item_ids"] = ios_item_ids
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
mesh = tool.Loader.create_mesh_from_shape(mesh=mesh, verts=verts, faces=faces)
|
||||||
mesh.vertices.foreach_set("co", verts.ravel().astype("f"))
|
|
||||||
|
|
||||||
is_triangulated = True
|
|
||||||
num_vertex_indices = faces.size
|
|
||||||
if is_triangulated:
|
|
||||||
loop_start = np.arange(0, num_vertex_indices, 3, dtype="I")
|
|
||||||
loop_total = np.full(total_faces, 3, dtype="I")
|
|
||||||
use_smooth = np.zeros(num_vertex_indices, dtype="?")
|
|
||||||
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", faces.ravel().astype("I"))
|
|
||||||
mesh.polygons.add(total_faces)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", use_smooth)
|
|
||||||
else:
|
|
||||||
# TODO: optimize using correct numpy array types.
|
|
||||||
faces_array = np.array(geometry.faces, dtype=object)
|
|
||||||
loop_total = np.array(tuple(len(face) for face in faces_array), dtype="I")
|
|
||||||
loop_start = np.cumsum((0,) + loop_total)[:-1]
|
|
||||||
vertex_index = np.concatenate(faces_array)
|
|
||||||
use_smooth = np.zeros(num_vertex_indices, dtype="?")
|
|
||||||
|
|
||||||
mesh.loops.add(len(vertex_index))
|
|
||||||
mesh.loops.foreach_set("vertex_index", vertex_index)
|
|
||||||
mesh.polygons.add(len(loop_start))
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", use_smooth)
|
|
||||||
|
|
||||||
mesh.update()
|
|
||||||
|
|
||||||
rep_str: str = geometry.id
|
rep_str: str = geometry.id
|
||||||
if load_indexed_maps and "openings" not in rep_str:
|
if load_indexed_maps and "openings" not in rep_str:
|
||||||
@@ -1043,6 +1009,72 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
mesh["ios_material_ids"] = ifcopenshell.util.shape.get_faces_material_style_ids(geometry).tolist()
|
mesh["ios_material_ids"] = ifcopenshell.util.shape.get_faces_material_style_ids(geometry).tolist()
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_mesh_from_shape(
|
||||||
|
cls,
|
||||||
|
geometry: Optional[ifcopenshell.geom.ShapeType] = None,
|
||||||
|
mesh: Optional[bpy.types.Mesh] = None,
|
||||||
|
*,
|
||||||
|
verts: Optional[npt.NDArray[np.float64]] = None,
|
||||||
|
faces: Optional[npt.NDArray[np.int32]] = None,
|
||||||
|
) -> bpy.types.Mesh:
|
||||||
|
"""
|
||||||
|
Either geometry or verts+faces should be provided.
|
||||||
|
|
||||||
|
:param verts: Numpy array of shape (n, 3).
|
||||||
|
:param faces: Numpy array of shape (m, 3).
|
||||||
|
"""
|
||||||
|
assert geometry is not None or (verts is not None and faces is not None), (
|
||||||
|
"Either geometry or verts+faces should be provided.\n"
|
||||||
|
f"Current geometry: {geometry}\n"
|
||||||
|
f"Current verts: {verts}\n"
|
||||||
|
f"Current faces: {faces}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if mesh is None:
|
||||||
|
mesh = bpy.data.meshes.new("temp")
|
||||||
|
|
||||||
|
if verts is None or faces is None:
|
||||||
|
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
||||||
|
faces = ifcopenshell.util.shape.get_faces(geometry)
|
||||||
|
|
||||||
|
total_faces: int = faces.shape[0]
|
||||||
|
num_vertices: int = verts.shape[0]
|
||||||
|
mesh.vertices.add(num_vertices)
|
||||||
|
mesh.vertices.foreach_set("co", verts.ravel().astype("f"))
|
||||||
|
|
||||||
|
is_triangulated = True
|
||||||
|
num_vertex_indices = faces.size
|
||||||
|
if is_triangulated:
|
||||||
|
loop_start = np.arange(0, num_vertex_indices, 3, dtype="I")
|
||||||
|
loop_total = np.full(total_faces, 3, dtype="I")
|
||||||
|
use_smooth = np.zeros(num_vertex_indices, dtype="?")
|
||||||
|
|
||||||
|
mesh.loops.add(num_vertex_indices)
|
||||||
|
mesh.loops.foreach_set("vertex_index", faces.ravel().astype("I"))
|
||||||
|
mesh.polygons.add(total_faces)
|
||||||
|
mesh.polygons.foreach_set("loop_start", loop_start)
|
||||||
|
mesh.polygons.foreach_set("loop_total", loop_total)
|
||||||
|
mesh.polygons.foreach_set("use_smooth", use_smooth)
|
||||||
|
else:
|
||||||
|
# TODO: optimize using correct numpy array types.
|
||||||
|
faces_array = np.array(geometry.faces, dtype=object)
|
||||||
|
loop_total = np.array(tuple(len(face) for face in faces_array), dtype="I")
|
||||||
|
loop_start = np.cumsum((0,) + loop_total)[:-1]
|
||||||
|
vertex_index = np.concatenate(faces_array)
|
||||||
|
use_smooth = np.zeros(num_vertex_indices, dtype="?")
|
||||||
|
|
||||||
|
mesh.loops.add(len(vertex_index))
|
||||||
|
mesh.loops.foreach_set("vertex_index", vertex_index)
|
||||||
|
mesh.polygons.add(len(loop_start))
|
||||||
|
mesh.polygons.foreach_set("loop_start", loop_start)
|
||||||
|
mesh.polygons.foreach_set("loop_total", loop_total)
|
||||||
|
mesh.polygons.foreach_set("use_smooth", use_smooth)
|
||||||
|
|
||||||
|
mesh.update()
|
||||||
|
|
||||||
|
return mesh
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_active_bsdd_classification(cls) -> None:
|
def setup_active_bsdd_classification(cls) -> None:
|
||||||
ifc_file = tool.Ifc.get()
|
ifc_file = tool.Ifc.get()
|
||||||
|
|||||||
@@ -758,26 +758,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def create_mesh_from_shape(cls, shape: ifcopenshell.geom.ShapeElementType) -> bpy.types.Mesh:
|
def create_mesh_from_shape(cls, shape: ifcopenshell.geom.ShapeElementType) -> bpy.types.Mesh:
|
||||||
geometry = shape.geometry
|
geometry = shape.geometry
|
||||||
mesh = bpy.data.meshes.new("tmp")
|
return tool.Loader.create_mesh_from_shape(geometry)
|
||||||
verts = geometry.verts
|
|
||||||
if geometry.faces:
|
|
||||||
num_vertices = len(verts) // 3
|
|
||||||
total_faces = len(geometry.faces)
|
|
||||||
loop_start = range(0, total_faces, 3)
|
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(geometry.faces)
|
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", geometry.faces)
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", [0] * total_faces)
|
|
||||||
mesh.update()
|
|
||||||
return mesh
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_x_y_z_h_mat_from_obj(cls, obj: bpy.types.Object) -> tuple[float, float, float, float, Matrix]:
|
def get_x_y_z_h_mat_from_obj(cls, obj: bpy.types.Object) -> tuple[float, float, float, float, Matrix]:
|
||||||
|
|||||||
Reference in New Issue
Block a user