mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Store item_ids in imported meshes and set them on toggling edit mode
It will be used later to add more IFC capabilities to EDIT mode. Example - https://imgur.com/a/HAkjoCY
This commit is contained in:
@@ -1387,6 +1387,7 @@ class IfcImporter:
|
||||
#
|
||||
# we do `.tolist()` because Blender can't assign `np.int32` to it's custom attributes
|
||||
mesh["ios_edges"] = list(set(tuple(e) for e in ifcopenshell.util.shape.get_edges(geometry).tolist()))
|
||||
mesh["ios_item_ids"] = ifcopenshell.util.shape.get_representation_item_ids(geometry).tolist()
|
||||
|
||||
mesh.vertices.add(num_vertices)
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
|
||||
@@ -1651,6 +1651,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
||||
should_sync_changes_first=False,
|
||||
apply_openings=False,
|
||||
)
|
||||
tool.Geometry.apply_item_ids_as_vertex_groups(obj)
|
||||
tool.Geometry.dissolve_triangulated_edges(obj)
|
||||
obj.data.BIMMeshProperties.mesh_checksum = tool.Geometry.get_mesh_checksum(obj.data)
|
||||
else:
|
||||
|
||||
@@ -37,6 +37,7 @@ import blenderbim.core.system
|
||||
import blenderbim.core.geometry
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.import_ifc
|
||||
from collections import defaultdict
|
||||
from math import radians, pi
|
||||
from mathutils import Vector, Matrix
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
@@ -173,6 +174,39 @@ class Geometry(blenderbim.core.tool.Geometry):
|
||||
bm.free()
|
||||
del obj.data["ios_edges"]
|
||||
|
||||
@classmethod
|
||||
def apply_item_ids_as_vertex_groups(cls, obj: bpy.types.Object) -> None:
|
||||
"""Save mesh-object item_ids as vertex groups in format 'ios_item_id_xxxx'.
|
||||
|
||||
Since ios_item_ids are item ids for original faces (triangulated),
|
||||
this method should be used before `dissolve_triangulated_edges`."""
|
||||
|
||||
mesh = obj.data
|
||||
assert isinstance(mesh, bpy.types.Mesh)
|
||||
# I guess, they're already applied.
|
||||
if "ios_item_ids" not in mesh:
|
||||
return
|
||||
|
||||
# Just to be safe.
|
||||
if "ios_edges" not in mesh:
|
||||
raise Exception("Triangulated edges are already dissolved, cannot aply item ids.")
|
||||
|
||||
polygon_verts = np.empty(len(mesh.polygons) * 3, dtype="I")
|
||||
mesh.polygons.foreach_get("vertices", polygon_verts)
|
||||
polygon_verts = polygon_verts.reshape(-1, 3)
|
||||
|
||||
ios_item_ids: list[int] = mesh["ios_item_ids"]
|
||||
vertices_by_item_ids = defaultdict(list[int])
|
||||
for i, item_id in enumerate(ios_item_ids):
|
||||
# .tolist() as VertexGroup.add() is not ready for uints.
|
||||
vertices_by_item_ids[item_id].extend(polygon_verts[i].tolist())
|
||||
|
||||
for item_id, verts in vertices_by_item_ids.items():
|
||||
vg = obj.vertex_groups.new(name=f"ios_item_id_{item_id}")
|
||||
vg.add(verts, weight=1.0, type="ADD")
|
||||
|
||||
del mesh["ios_item_ids"]
|
||||
|
||||
@classmethod
|
||||
def does_representation_id_exist(cls, representation_id: int) -> bool:
|
||||
try:
|
||||
|
||||
@@ -727,3 +727,35 @@ class TestRemoveRepresentationItemFromShapeAspect(NewFile):
|
||||
subject.remove_representation_items_from_shape_aspect([items[1]], shape_aspect1)
|
||||
representation = shape_aspect1.ShapeRepresentations[0]
|
||||
assert set(representation.Items) == {items[0]}
|
||||
|
||||
|
||||
class TestApplyItemIdsAsVertexGroups(NewFile):
|
||||
def test_run(self):
|
||||
bpy.ops.mesh.primitive_cube_add(size=10, location=(0, 0, 4))
|
||||
obj = bpy.data.objects["Cube"]
|
||||
bpy.ops.object.editmode_toggle()
|
||||
bpy.ops.mesh.quads_convert_to_tris()
|
||||
bpy.ops.mesh.duplicate_move()
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
mesh = obj.data
|
||||
assert isinstance(mesh, bpy.types.Mesh)
|
||||
assert len(mesh.polygons) == 24
|
||||
|
||||
mesh["ios_edges"] = [] # Method requirement.
|
||||
ios_item_ids = (95,) * 12 + (45,) * 12
|
||||
mesh["ios_item_ids"] = ios_item_ids
|
||||
unique = tuple(dict.fromkeys(ios_item_ids))
|
||||
ios_item_ids_unique = [unique.index(i) for i in ios_item_ids]
|
||||
|
||||
tool.Geometry.apply_item_ids_as_vertex_groups(obj)
|
||||
|
||||
vertex_group_names = [vg.name for vg in obj.vertex_groups]
|
||||
assert vertex_group_names == [f"ios_item_id_{i}" for i in unique]
|
||||
|
||||
verts = mesh.vertices
|
||||
for i, polygon in enumerate(mesh.polygons):
|
||||
for vi in polygon.vertices:
|
||||
vert = verts[vi]
|
||||
groups = [g.group for g in vert.groups]
|
||||
assert groups == [ios_item_ids_unique[i]]
|
||||
|
||||
@@ -275,6 +275,11 @@ def get_faces(geometry: ShapeType) -> npt.NDArray[np.int32]:
|
||||
return np.array([[faces[i], faces[i + 1], faces[i + 2]] for i in range(0, len(faces), 3)])
|
||||
|
||||
|
||||
def get_representation_item_ids(geometry: ShapeType) -> npt.NDArray[np.int32]:
|
||||
"""Get representation item ids for the geometry faces."""
|
||||
return np.frombuffer(geometry.item_ids_buffer, dtype="i")
|
||||
|
||||
|
||||
def get_shape_vertices(shape: ShapeType, geometry: ShapeType) -> npt.NDArray[np.float64]:
|
||||
"""Get the shape's vertices as a numpy array
|
||||
|
||||
|
||||
Reference in New Issue
Block a user