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
|
||||
|
||||
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])
|
||||
for geometry_id, geometry in self.geometry_cache["geometry"].items():
|
||||
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
|
||||
|
||||
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.update()
|
||||
mesh = tool.Loader.create_mesh_from_shape(
|
||||
mesh=mesh, faces=geometry["faces"].reshape(-1, 3), verts=verts.reshape(-1, 3)
|
||||
)
|
||||
else:
|
||||
e = geometry["edges"]
|
||||
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")
|
||||
|
||||
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.polygons.foreach_set("use_smooth", [0] * total_faces)
|
||||
mesh = tool.Loader.create_mesh_from_shape(geometry, mesh)
|
||||
mesh.polygons.foreach_set("material_index", material_index)
|
||||
mesh.update()
|
||||
|
||||
@@ -1890,29 +1876,13 @@ class LoadLinkedProject(bpy.types.Operator):
|
||||
num_vertices = len(verts) // 3
|
||||
if not num_vertices:
|
||||
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:
|
||||
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):
|
||||
mesh.polygons.foreach_set("material_index", material_ids)
|
||||
|
||||
mesh.update()
|
||||
|
||||
obj = bpy.data.objects.new("Chunk", mesh)
|
||||
|
||||
@@ -1188,27 +1188,7 @@ def create_mesh_from_shape(
|
||||
settings.set("keep-bounding-boxes", True)
|
||||
shape = ifcopenshell.geom.create_shape(settings, element)
|
||||
geometry = shape.geometry if element.is_a("IfcRoot") else shape
|
||||
faces = geometry.faces
|
||||
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
|
||||
return tool.Loader.create_mesh_from_shape(geometry)
|
||||
|
||||
|
||||
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:
|
||||
verts = ifcopenshell.util.shape.get_vertices(geometry)
|
||||
faces = ifcopenshell.util.shape.get_faces(geometry)
|
||||
total_faces: int
|
||||
if total_faces := faces.shape[0]:
|
||||
num_vertices: int = verts.shape[0]
|
||||
|
||||
if faces.shape[0] > 0:
|
||||
# See bug 3546
|
||||
# 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()
|
||||
mesh["ios_item_ids"] = ios_item_ids
|
||||
|
||||
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()
|
||||
mesh = tool.Loader.create_mesh_from_shape(mesh=mesh, verts=verts, faces=faces)
|
||||
|
||||
rep_str: str = geometry.id
|
||||
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()
|
||||
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
|
||||
def setup_active_bsdd_classification(cls) -> None:
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
@@ -758,26 +758,7 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
@classmethod
|
||||
def create_mesh_from_shape(cls, shape: ifcopenshell.geom.ShapeElementType) -> bpy.types.Mesh:
|
||||
geometry = shape.geometry
|
||||
mesh = bpy.data.meshes.new("tmp")
|
||||
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
|
||||
return tool.Loader.create_mesh_from_shape(geometry)
|
||||
|
||||
@classmethod
|
||||
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