mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +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
|
# 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_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.add(num_vertices)
|
||||||
mesh.vertices.foreach_set("co", verts)
|
mesh.vertices.foreach_set("co", verts)
|
||||||
|
|||||||
@@ -1651,6 +1651,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
|||||||
should_sync_changes_first=False,
|
should_sync_changes_first=False,
|
||||||
apply_openings=False,
|
apply_openings=False,
|
||||||
)
|
)
|
||||||
|
tool.Geometry.apply_item_ids_as_vertex_groups(obj)
|
||||||
tool.Geometry.dissolve_triangulated_edges(obj)
|
tool.Geometry.dissolve_triangulated_edges(obj)
|
||||||
obj.data.BIMMeshProperties.mesh_checksum = tool.Geometry.get_mesh_checksum(obj.data)
|
obj.data.BIMMeshProperties.mesh_checksum = tool.Geometry.get_mesh_checksum(obj.data)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import blenderbim.core.system
|
|||||||
import blenderbim.core.geometry
|
import blenderbim.core.geometry
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.import_ifc
|
import blenderbim.bim.import_ifc
|
||||||
|
from collections import defaultdict
|
||||||
from math import radians, pi
|
from math import radians, pi
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
@@ -173,6 +174,39 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
bm.free()
|
bm.free()
|
||||||
del obj.data["ios_edges"]
|
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
|
@classmethod
|
||||||
def does_representation_id_exist(cls, representation_id: int) -> bool:
|
def does_representation_id_exist(cls, representation_id: int) -> bool:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -727,3 +727,35 @@ class TestRemoveRepresentationItemFromShapeAspect(NewFile):
|
|||||||
subject.remove_representation_items_from_shape_aspect([items[1]], shape_aspect1)
|
subject.remove_representation_items_from_shape_aspect([items[1]], shape_aspect1)
|
||||||
representation = shape_aspect1.ShapeRepresentations[0]
|
representation = shape_aspect1.ShapeRepresentations[0]
|
||||||
assert set(representation.Items) == {items[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)])
|
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]:
|
def get_shape_vertices(shape: ShapeType, geometry: ShapeType) -> npt.NDArray[np.float64]:
|
||||||
"""Get the shape's vertices as a numpy array
|
"""Get the shape's vertices as a numpy array
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user