mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 19:07:57 +00:00
Special geometry data on meshes are also loaded as geometry attributes.
No functional change apart from in dissolve_triangulated_edges where it will try to load the attribute if it can. I believe it will be easier in the long term to use the builtin Attributes system. Unfortunately Curves don't support Attributes yet. Also, attributes are more lightweight compared to custom properties.
This commit is contained in:
@@ -1032,6 +1032,30 @@ class Blender(bonsai.core.tool.Blender):
|
||||
if child_obj:
|
||||
yield child_obj
|
||||
|
||||
class Attribute:
|
||||
@classmethod
|
||||
def fill_attribute(cls, data: bpy.types.ID, attribute_name: str, domain: str, data_type: str, values):
|
||||
attribute = cls.ensure_attribute(data, attribute_name, domain, data_type)
|
||||
attribute.data.foreach_set(cls.get_data_name(data_type), values)
|
||||
|
||||
@classmethod
|
||||
def ensure_attribute(cls, data: bpy.types.ID, attribute_name: str, domain: str, data_type: str):
|
||||
attribute = data.attributes.get(attribute_name)
|
||||
if not attribute:
|
||||
attribute = data.attributes.new(attribute_name, domain=domain, type=data_type)
|
||||
return attribute
|
||||
|
||||
@classmethod
|
||||
def get_data_name(cls, data_type: str):
|
||||
if data_type in ("FLOAT", "INT", "BOOLEAN", "STRING"):
|
||||
return "value"
|
||||
if data_type.endswith("VECTOR"):
|
||||
return "vector"
|
||||
elif data_type.endswith("COLOR"):
|
||||
return "color"
|
||||
else:
|
||||
raise NotImplementedError(f"Attribute data type `{data_type}` not implemented yet")
|
||||
|
||||
@classmethod
|
||||
def get_last_commit_hash(cls) -> Union[str, None]:
|
||||
"""Get 8 symbols of last commit hash if it's present or return None otherwise."""
|
||||
|
||||
@@ -261,9 +261,17 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
mesh_element.is_a("IfcShapeRepresentation")
|
||||
and ifcopenshell.util.representation.resolve_representation(mesh_element).RepresentationType
|
||||
== "AdvancedBrep"
|
||||
) or mesh_element.is_a("IfcAdvancedBrep"):
|
||||
) or mesh_element.is_a("IfcAdvancedBrep") or not obj.data:
|
||||
return
|
||||
if obj.data and "ios_edges" in obj.data:
|
||||
if hasattr(obj.data, "attributes") and (ios_edges_attribute := obj.data.attributes.get("ios_edges")):
|
||||
# Edges from a forced triangulation are stored as True in a boolean attribute on the mesh
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(obj.data)
|
||||
edges_to_dissolve = [e for i, e in enumerate(bm.edges) if not ios_edges_attribute.data[i].value]
|
||||
bmesh.ops.dissolve_edges(bm, edges=edges_to_dissolve)
|
||||
bm.to_mesh(obj.data)
|
||||
bm.free()
|
||||
elif "ios_edges" in obj.data:
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(obj.data)
|
||||
edges_to_keep = set(map(frozenset, obj.data["ios_edges"]))
|
||||
|
||||
@@ -939,7 +939,8 @@ class Loader(bonsai.core.tool.Loader):
|
||||
# we do `.tolist()` because Blender can't assign `np.int32` to it's custom attributes
|
||||
ios_edges = list(set(tuple(e) for e in ifcopenshell.util.shape.get_edges(geometry).tolist()))
|
||||
mesh["ios_edges"] = ios_edges
|
||||
mesh["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.vertices.add(num_vertices)
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
@@ -981,19 +982,13 @@ class Loader(bonsai.core.tool.Loader):
|
||||
if rep.is_a("IfcShapeRepresentation"):
|
||||
tool.Loader.load_indexed_colour_map(rep, mesh)
|
||||
|
||||
ios_edges_indices = [(e[0], e[1]) for e in ios_edges]
|
||||
attribute_ios_edges = mesh.attributes.get("ios_edges")
|
||||
if not attribute_ios_edges:
|
||||
attribute_ios_edges = mesh.attributes.new("ios_edges", domain="EDGE", type="BOOLEAN")
|
||||
|
||||
attribute_ios_edges.data.foreach_set(
|
||||
"value",
|
||||
[
|
||||
(e.vertices[0], e.vertices[1]) in ios_edges_indices
|
||||
or (e.vertices[1], e.vertices[0]) in ios_edges_indices
|
||||
for e in mesh.edges
|
||||
],
|
||||
)
|
||||
ios_edges_values = [
|
||||
(e.vertices[0], e.vertices[1]) in ios_edges
|
||||
or (e.vertices[1], e.vertices[0]) in ios_edges
|
||||
for e in mesh.edges
|
||||
]
|
||||
tool.Blender.Attribute.fill_attribute(mesh, "ios_edges", "EDGE", "BOOLEAN", ios_edges_values)
|
||||
tool.Blender.Attribute.fill_attribute(mesh, "ios_item_ids", "FACE", "INT", ios_item_ids)
|
||||
else:
|
||||
e = geometry.edges
|
||||
v = verts
|
||||
@@ -1006,9 +1001,11 @@ class Loader(bonsai.core.tool.Loader):
|
||||
except AttributeError:
|
||||
edges_item_ids = []
|
||||
mesh["ios_edges_item_ids"] = edges_item_ids
|
||||
tool.Blender.Attribute.fill_attribute(mesh, "ios_edges_item_ids", "EDGE", "INT", edges_item_ids)
|
||||
|
||||
mesh["ios_materials"] = [m.instance_id() for m in geometry.materials]
|
||||
mesh["ios_material_ids"] = geometry.material_ids
|
||||
tool.Blender.Attribute.fill_attribute(mesh, "ios_material_ids", "FACE", "INT", geometry.material_ids)
|
||||
return mesh
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user