mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
add_representation - detect non consequtive curves and handle them
Basically if current mesh curve is non consequtive we handle it in similar way to b03c4da7b - convert it to curves using Blender and then save them to ifc.
The advantage is that it creates less curves in ifc because mesh method wasn't able to detect separate curves correctly if vertex order was messed up (usually it is) and it would create separate curve for each curve segment.
I've also replaced figuring vertex duplicates with `bmesh.ops.remove_doubles` manually with `bmesh.ops.remove_doubles` and it's now much faster. In some cases because of the manual calculations it was taking too long - in #3233 Ryan mentiones that it freezes blender, it wasn't really freezing Blender but to finish calculations it would take 10 minutes.
This commit is contained in:
@@ -362,52 +362,100 @@ class Usecase:
|
||||
results.append(self.file.createIfcSweptDiskSolid(curve, radius))
|
||||
return results
|
||||
|
||||
def is_mesh_curve_consequtive(self, geom_data):
|
||||
import blenderbim.tool as tool
|
||||
bm = tool.Blender.get_bmesh_for_mesh(geom_data)
|
||||
bm.verts.ensure_lookup_table()
|
||||
start_vert = bm.verts[0]
|
||||
n_verts = len(bm.verts)
|
||||
cur_edges = bm.verts[0].link_edges
|
||||
|
||||
if len(cur_edges) > 2:
|
||||
return False
|
||||
elif cur_edges == 2:
|
||||
edge0, edge1 = cur_edges
|
||||
else:
|
||||
edge0, edge1 = cur_edges[0], None
|
||||
|
||||
processed_verts = set()
|
||||
processed_verts.add(start_vert)
|
||||
def validate_edge(edge, start_vert, processed_verts):
|
||||
cur_vert = edge.other_vert(start_vert)
|
||||
while True:
|
||||
if cur_vert == start_vert:
|
||||
break
|
||||
if cur_vert in processed_verts:
|
||||
return
|
||||
processed_verts.add(cur_vert)
|
||||
edges = cur_vert.link_edges
|
||||
if len(edges) > 2:
|
||||
return
|
||||
elif len(edges) == 1:
|
||||
return True
|
||||
edge = next(e for e in edges if e != edge)
|
||||
cur_vert = edge.other_vert(cur_vert)
|
||||
return True
|
||||
|
||||
if not validate_edge(edge0, start_vert, processed_verts):
|
||||
return
|
||||
|
||||
if edge1 and not validate_edge(edge1, start_vert, processed_verts):
|
||||
return
|
||||
|
||||
if len(processed_verts) != n_verts:
|
||||
return False
|
||||
return True
|
||||
|
||||
def create_curves(self, should_exclude_faces=False, is_2d=False):
|
||||
if isinstance(self.settings["geometry"], bpy.types.Mesh):
|
||||
if self.file.schema == "IFC2X3":
|
||||
return self.create_curves_from_mesh_ifc2x3(should_exclude_faces=should_exclude_faces, is_2d=is_2d)
|
||||
else:
|
||||
return self.create_curves_from_mesh(should_exclude_faces=should_exclude_faces, is_2d=is_2d)
|
||||
elif isinstance(self.settings["geometry"], bpy.types.Curve):
|
||||
import blenderbim.tool as tool
|
||||
geom_data = self.settings["geometry"]
|
||||
|
||||
selected_objects = bpy.context.selected_objects
|
||||
active_object = bpy.context.active_object
|
||||
if isinstance(geom_data, bpy.types.Mesh):
|
||||
if self.is_mesh_curve_consequtive(geom_data):
|
||||
if self.file.schema == "IFC2X3":
|
||||
return self.create_curves_from_mesh_ifc2x3(should_exclude_faces=should_exclude_faces, is_2d=is_2d)
|
||||
else:
|
||||
return self.create_curves_from_mesh(should_exclude_faces=should_exclude_faces, is_2d=is_2d)
|
||||
|
||||
# create dummy object that will have more detailed curves
|
||||
# since now we do not really support splines curves natively
|
||||
obj = self.settings["blender_object"]
|
||||
dummy = bpy.data.objects.new("Dummy", obj.data.copy())
|
||||
bpy.context.scene.collection.objects.link(dummy)
|
||||
tool.Blender.select_and_activate_single_object(bpy.context, dummy)
|
||||
import blenderbim.tool as tool
|
||||
|
||||
selected_objects = bpy.context.selected_objects
|
||||
active_object = bpy.context.active_object
|
||||
|
||||
# create dummy object that will have more detailed curves
|
||||
# since now we do not really support splines curves natively
|
||||
obj = self.settings["blender_object"]
|
||||
dummy = bpy.data.objects.new("Dummy", obj.data.copy())
|
||||
bpy.context.scene.collection.objects.link(dummy)
|
||||
tool.Blender.select_and_activate_single_object(bpy.context, dummy)
|
||||
if not isinstance(geom_data, bpy.types.Mesh):
|
||||
bpy.ops.object.convert(target="MESH")
|
||||
bpy.ops.object.convert(target="CURVE")
|
||||
self.remove_doubles_from_mesh(dummy.data)
|
||||
bpy.ops.object.convert(target="CURVE")
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
curves = self.create_curves_from_curve_ifc2x3(is_2d=is_2d, curve_object_data=dummy.data)
|
||||
else:
|
||||
curves = self.create_curves_from_curve(is_2d=is_2d, curve_object_data=dummy.data)
|
||||
if self.file.schema == "IFC2X3":
|
||||
curves = self.create_curves_from_curve_ifc2x3(is_2d=is_2d, curve_object_data=dummy.data)
|
||||
else:
|
||||
curves = self.create_curves_from_curve(is_2d=is_2d, curve_object_data=dummy.data)
|
||||
|
||||
# restore objects selection
|
||||
bpy.data.objects.remove(dummy)
|
||||
tool.Blender.set_objects_selection(bpy.context, active_object, selected_objects)
|
||||
return curves
|
||||
# restore objects selection
|
||||
bpy.data.objects.remove(dummy)
|
||||
tool.Blender.set_objects_selection(bpy.context, active_object, selected_objects)
|
||||
return curves
|
||||
|
||||
def create_curves_from_mesh(self, should_exclude_faces=False, is_2d=False):
|
||||
geom_data = self.settings["geometry"].copy()
|
||||
self.remove_doubles_from_mesh(geom_data)
|
||||
curves = []
|
||||
points = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices, is_2d=is_2d)
|
||||
points = self.create_cartesian_point_list_from_vertices(geom_data.vertices, is_2d=is_2d)
|
||||
edge_loops = []
|
||||
previous_edge = None
|
||||
edge_loop = []
|
||||
face_edges = set()
|
||||
if should_exclude_faces:
|
||||
[face_edges.union([self.settings["geometry"].edge_keys.index(ek) for ek in p.edge_keys]) for p in self.settings["geometry"].polygons]
|
||||
for i, edge in enumerate(self.settings["geometry"].edges):
|
||||
[face_edges.union([geom_data.edge_keys.index(ek) for ek in p.edge_keys]) for p in geom_data.polygons]
|
||||
for i, edge in enumerate(geom_data.edges):
|
||||
if should_exclude_faces and i in face_edges:
|
||||
continue
|
||||
if (Vector(points.CoordList[edge.vertices[0]]) - Vector(points.CoordList[edge.vertices[1]])).length < 0.001:
|
||||
# Maybe we should warn the user to weld vertices in this scenario?
|
||||
continue
|
||||
elif previous_edge is None:
|
||||
edge_loop = [self.file.createIfcLineIndex((edge.vertices[0] + 1, edge.vertices[1] + 1))]
|
||||
elif edge.vertices[0] == previous_edge.vertices[1]:
|
||||
@@ -421,11 +469,19 @@ class Usecase:
|
||||
curves.append(self.file.createIfcIndexedPolyCurve(points, edge_loop))
|
||||
return curves
|
||||
|
||||
def remove_doubles_from_mesh(self, mesh):
|
||||
import blenderbim.tool as tool
|
||||
bm = tool.Blender.get_bmesh_for_mesh(mesh)
|
||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
|
||||
tool.Blender.apply_bmesh(mesh, bm)
|
||||
|
||||
def create_curves_from_mesh_ifc2x3(self, should_exclude_faces=False, is_2d=False):
|
||||
geom_data = self.settings["geometry"].copy()
|
||||
self.remove_doubles_from_mesh(geom_data)
|
||||
curves = []
|
||||
points = [
|
||||
self.create_cartesian_point(v.co.x, v.co.y, v.co.z if not is_2d else None)
|
||||
for v in self.settings["geometry"].vertices
|
||||
for v in geom_data.vertices
|
||||
]
|
||||
coord_list = [p.Coordinates for p in points]
|
||||
edge_loops = []
|
||||
@@ -433,13 +489,10 @@ class Usecase:
|
||||
edge_loop = []
|
||||
face_edges = set()
|
||||
if should_exclude_faces:
|
||||
[face_edges.union([self.settings["geometry"].edge_keys.index(ek) for ek in p.edge_keys]) for p in self.settings["geometry"].polygons]
|
||||
for i, edge in enumerate(self.settings["geometry"].edges):
|
||||
[face_edges.union([geom_data.edge_keys.index(ek) for ek in p.edge_keys]) for p in geom_data.polygons]
|
||||
for i, edge in enumerate(geom_data.edges):
|
||||
if should_exclude_faces and i in face_edges:
|
||||
continue
|
||||
if (Vector(coord_list[edge.vertices[0]]) - Vector(coord_list[edge.vertices[1]])).length < 0.001:
|
||||
# Maybe we should warn the user to weld vertices in this scenario?
|
||||
continue
|
||||
elif previous_edge is None:
|
||||
edge_loop = [edge.vertices]
|
||||
elif edge.vertices[0] == previous_edge.vertices[1]:
|
||||
|
||||
Reference in New Issue
Block a user