def solve_triangular_faces(self): """Modify the decomposition mesh from polylines to make it a quad mesh by converting the degenerated quad faces that appear as triangular faces. """ mesh = self.mesh for fkey in list(mesh.faces()): if len(mesh.face_vertices(fkey)) == 3: boundary_vertices = [vkey for vkey in mesh.face_vertices(fkey) if mesh.is_vertex_on_boundary(vkey)] case = sum(mesh.is_vertex_on_boundary(vkey) for vkey in mesh.face_vertices(fkey)) if case == 1: #convert triangular face to quad by duplicating the boundary vertex #due to compas_singular face vertices at the same location u = boundary_vertices[0] v = mesh.add_vertex(attr_dict = {attr: xyz for attr, xyz in zip(['x', 'y', 'z'], mesh.vertex_coordinates(u))}) # modify adjacent faces vertex_faces = mesh.vertex_faces(u, ordered = True) mesh_substitute_vertex_in_faces(mesh, u, v, vertex_faces[: vertex_faces.index(fkey)]) # modify triangular face mesh_insert_vertex_on_edge(mesh, u, mesh.face_vertex_ancestor(fkey, u), v) elif case == 2: # remove triangular face and merge the two boundary vertices # due to singularities at the same location polyline = Polyline(self.decomposition_polyline(*map(lambda x: geometric_key(mesh.vertex_coordinates(x)), boundary_vertices))) point = polyline.point(t = .5, snap = True) new_vkey = mesh.add_vertex(attr_dict = {'x': point.x, 'y': point.y , 'z': point.z}) # modify triangular face mesh.delete_face(fkey) # modify adjacent faces for old_vkey in boundary_vertices: mesh_substitute_vertex_in_faces(mesh, old_vkey, new_vkey, mesh.vertex_faces(old_vkey)) mesh.delete_vertex(old_vkey) to_move = {} # give some length to the new edge for edge in mesh.edges(): threshold = 1e-6 if mesh.edge_length(*edge) < threshold: for vkey in edge: xyz = centroid_points([mesh.vertex_coordinates(nbr) for nbr in mesh.vertex_neighbors(vkey)]) xyz0 = mesh.vertex_coordinates(vkey) to_move[vkey] = [0.1 * (a - a0) for a, a0 in zip(xyz, xyz0)] for vkey, xyz in to_move.items(): attr = mesh.vertex[vkey] attr['x'] += xyz[0] attr['y'] += xyz[1] attr['z'] += xyz[2]
def test_mesh_substitute_vertex_in_faces(mesh_0): mesh_substitute_vertex_in_faces(mesh_0, 0, 4) assert 4 in mesh_0.face_vertices(0) assert 0 not in mesh_0.face_vertices(0) assert 4 in mesh_0.face_vertices(1) assert 0 not in mesh_0.face_vertices(1) mesh_substitute_vertex_in_faces(mesh_0, 4, 0, [1]) assert 4 in mesh_0.face_vertices(0) assert 0 not in mesh_0.face_vertices(0) assert 0 in mesh_0.face_vertices(1) assert 4 not in mesh_0.face_vertices(1)
def delete_strip(mesh, skey, update_data=True): """Delete a strip. Parameters ---------- mesh : QuadMesh A quad mesh. skey : hashable A strip key. update_data : bool, optional Update strip data. Default is True. Returns ------- skey_to_skeys : dict, None If strip splits were applied to preserve boundaries, a dictionary of the initial strip key to the refining strip keys. None otherwise. """ # build network between vertices of the edges of the strip to delete to get the disconnect parts of vertices to merge network = strip_edge_network(mesh, skey) disc_vertices = network_disconnected_vertices(network) # delete strip faces for fkey in mesh.strip_faces(skey): mesh.delete_face(fkey) old_vkeys_to_new_vkeys = {} # merge strip edge vertices that are connected for vertices in disc_vertices: # new vertex x, y, z = centroid_points( [mesh.vertex_coordinates(vkey) for vkey in vertices]) new_vkey = mesh.add_vertex(attr_dict={'x': x, 'y': y, 'z': z}) old_vkeys_to_new_vkeys.update( {old_vkey: new_vkey for old_vkey in vertices}) # replace the old vertices for old_vkey in vertices: new_faces = mesh_substitute_vertex_in_faces( mesh, old_vkey, new_vkey, mesh.vertex_faces(old_vkey)) # delete the old vertices for old_vkey in vertices: mesh.delete_vertex(old_vkey) # update strip data if update_data: update_strip_data(mesh, old_vkeys_to_new_vkeys) return old_vkeys_to_new_vkeys
def add_strip(mesh, polyedge): full_updated_polyedge = [] # store data left_polyedge = [] right_polyedge = [] new_faces = [] # exception if closed is_closed = polyedge[0] == polyedge[-1] if is_closed: polyedge.pop() k = -1 count = len(polyedge) * 2 while count and len(polyedge) > 0: k += 1 count -= 1 # select u, v, w if not closed if not is_closed: # u if len(new_faces) != 0: u1, u2 = left_polyedge[-1], right_polyedge[-1] else: u1, u2 = None, None # v v = polyedge.pop(0) full_updated_polyedge.append(v) # w if len(polyedge) != 0: w = polyedge[0] else: w = None # select u, v, w if closed else: # u if len(new_faces) != 0: u1, u2 = left_polyedge[-1], right_polyedge[-1] else: u1 = polyedge[-1] # artificial u1 # v v = polyedge.pop(0) # w if len(polyedge) != 0: w = polyedge[0] else: w = left_polyedge[0] # add new vertices faces = sort_faces(mesh, u1, v, w) v1, v2 = mesh.add_vertex(attr_dict=mesh.vertex[v]), mesh.add_vertex(attr_dict=mesh.vertex[v]) if type(faces[0]) == list: faces_1, faces_2 = faces else: # exception necessary for U-turns if faces[0] in mesh.vertex_faces(left_polyedge[-2]): faces_1 = faces faces_2 = [] else: faces_1 = [] faces_2 = faces mesh_substitute_vertex_in_faces(mesh, v, v1, faces_1) mesh_substitute_vertex_in_faces(mesh, v, v2, faces_2) mesh.delete_vertex(v) left_polyedge.append(v1) right_polyedge.append(v2) # add new faces, different if at the start, end or main part of the polyedge if len(new_faces) == 0: if not is_closed: new_faces.append(mesh.add_face([v1, w, v2])) else: new_faces.append(mesh.add_face([v1, v2, u1])) new_faces.append(mesh.add_face([v1, w, v2])) elif len(polyedge) == 0: if not is_closed: u1, u2 = left_polyedge[-2], right_polyedge[-2] face = new_faces.pop() mesh.delete_face(face) new_faces.append(mesh.add_face([u1, v1, v2, u2])) else: u1, u2 = left_polyedge[-2], right_polyedge[-2] face = new_faces.pop() mesh.delete_face(face) new_faces.append(mesh.add_face([v1, u1, u2, v2])) face = new_faces.pop(0) mesh.delete_face(face) u1, u2 = left_polyedge[0], right_polyedge[0] new_faces.append(mesh.add_face([v1, u1, u2, v2])) mesh_substitute_vertex_in_faces(mesh, v, v1) mesh_substitute_vertex_in_faces(mesh, v, v2) else: face = new_faces.pop() mesh.delete_face(face) new_faces.append(mesh.add_face([u1, v1, v2, u2])) new_faces.append(mesh.add_face([v1, w, v2])) # update updated_polyedge = [] via_vkeys = [v1, v2] for i, vkey in enumerate(polyedge): if vkey != v: updated_polyedge.append(vkey) else: from_vkey = polyedge[i - 1] to_vkey = polyedge[i + 1] updated_polyedge += polyedge_from_to_via_vertices(mesh, from_vkey, to_vkey, via_vkeys)[1:-1] polyedge = updated_polyedge # include pseudo closed polyedges old_vkeys_to_new_vkeys = {u0: (u1, u2) for u0, u1, u2 in zip(full_updated_polyedge, left_polyedge, right_polyedge)} #for fkey in mesh.faces(): # print(mesh.face_vertices(fkey)) n = update_strip_data(mesh, full_updated_polyedge, old_vkeys_to_new_vkeys) #print(left_polyedge, right_polyedge) return n, old_vkeys_to_new_vkeys
def add_strip(mesh, polyedge): """Add a strip along a mesh polyedge. Parameters ---------- mesh : Mesh A mesh. polyedge : list List of vertex keys forming path. Returns ------- new_skey, left_polyedge, right_polyedge : tuple The key of the new strip, the new strip vertices on the left, the new strip vertices on the right. """ kinks_xyz = [ mesh.vertex_coordinates(vkey) for vkey in mesh.boundary_kinks(pi / 12) ] # close or open status closed = polyedge[0] == polyedge[-1] # store transversal strips to update later update = { mesh.edge_strip(edge): i for i, edge in enumerate(pairwise(polyedge)) } transverse_strips = set(update.keys()) # list faces on the left and right of the polyedge left_faces = [mesh.halfedge[u][v] for u, v in pairwise(polyedge)] right_faces = [mesh.halfedge[v][u] for u, v in pairwise(polyedge)] # add extremities for looping on data if closed: left_faces = [left_faces[-1]] + left_faces + [left_faces[0]] right_faces = [right_faces[-1]] + right_faces + [right_faces[0]] else: left_faces = [None] + left_faces + [None] right_faces = [None] + right_faces + [None] # remove duplicat extremity if closed: polyedge.pop() # duplicate polyedge left_polyedge = [ mesh.add_vertex(attr_dict=mesh.vertex[vkey]) for vkey in polyedge ] right_polyedge = [ mesh.add_vertex(attr_dict=mesh.vertex[vkey]) for vkey in polyedge ] # store changes to apply all at once later to_substitute = {vkey: [] for vkey in polyedge} all_left_faces = [] all_right_faces = [] # collect all faces to update along polyedge with corresponding new vertex for i, vkey in enumerate(polyedge): vertex_faces = mesh.vertex_faces(vkey, ordered=True, include_none=True) # on the left faces = sublist_from_to_items_in_closed_list(vertex_faces, left_faces[i], left_faces[i + 1]) all_left_faces += faces to_substitute[vkey].append((left_polyedge[i], faces)) # on the right faces = sublist_from_to_items_in_closed_list(vertex_faces, right_faces[i + 1], right_faces[i]) all_right_faces += faces to_substitute[vkey].append((right_polyedge[i], faces)) all_left_faces = list(set(all_left_faces)) all_right_faces = list(set(all_right_faces)) left_strips = list( set([ skey for fkey in all_left_faces if fkey is not None for skey in mesh.face_strips(fkey) if skey not in transverse_strips ])) right_strips = list( set([ skey for fkey in all_right_faces if fkey is not None for skey in mesh.face_strips(fkey) if skey not in transverse_strips ])) # apply changes for key, substitutions in to_substitute.items(): for substitution in substitutions: new_key, faces = substitution mesh_substitute_vertex_in_faces( mesh, key, new_key, [face for face in faces if face is not None]) # delete old vertices for vkey in polyedge: mesh.delete_vertex(vkey) # add strip faces if closed: polyedge.append(polyedge[0]) left_polyedge.append(left_polyedge[0]) right_polyedge.append(right_polyedge[0]) for i in range(len(polyedge) - 1): mesh.add_face([ right_polyedge[i], right_polyedge[i + 1], left_polyedge[i + 1], left_polyedge[i] ]) # update transverse strip data for skey, i in update.items(): mesh.data['attributes']['strips'][skey] = mesh.collect_strip( *list(pairwise(left_polyedge))[i]) # add new strip data new_skey = list(mesh.strips())[-1] + 1 mesh.data['attributes']['strips'][new_skey] = mesh.collect_strip( left_polyedge[0], right_polyedge[0]) # update adjacent strips for i in range(len(polyedge)): old, left, right = polyedge[i], left_polyedge[i], right_polyedge[i] mesh.substitute_vertex_in_strips(old, left, left_strips) mesh.substitute_vertex_in_strips(old, right, right_strips) func_1(mesh, kinks_xyz, 20, 0.5) return new_skey, left_polyedge, right_polyedge
def delete_strip(mesh, skey, preserve_boundaries=False): """Delete a strip. Parameters ---------- mesh : QuadMesh A quad mesh. skey : hashable A strip key. preserve_boundaries : bool A boolean whether to preserve boundaries that would be collapsed by refining strips without adding singularities. Returns ------- skey_to_skeys : dict, None If strip splits were applied to preserve boundaries, a dictionary of the initial strip key to the refining strip keys. None otherwise. """ if skey not in list(mesh.strips()): return 0 if preserve_boundaries: skey_to_skeys = split_strips(mesh, boundary_strip_preserve(mesh, [skey])) old_boundary_vertices = list(mesh.vertices_on_boundary()) # get strip data strip_edges = mesh.strip_edges(skey) strip_faces = mesh.strip_faces(skey) # collateral strip deletions collateral_deleted_strips = [] #print('strip_faces: ', strip_faces) for skey_2 in mesh.strips(): if skey_2 == skey: continue #print('strip_faces_2: ', mesh.strip_faces(skey_2), [mesh.strip_faces(skey_2) in strip_faces]) if all([fkey in strip_faces for fkey in mesh.strip_faces(skey_2)]): collateral_deleted_strips.append(skey_2) #print('collateral_deleted_strips: ', collateral_deleted_strips) # build network between vertices of the edges of the strip to delete to # get the disconnect parts of vertices to merge vertices = set([i for edge in strip_edges for i in edge]) # maps between old and new indices old_to_new = {vkey: i for i, vkey in enumerate(vertices)} new_to_old = {i: vkey for i, vkey in enumerate(vertices)} # network vertex_coordinates = [mesh.vertex_coordinates(vkey) for vkey in vertices] edges = [(old_to_new[u], old_to_new[v]) for u, v in strip_edges] network = Network.from_vertices_and_edges(vertex_coordinates, edges) # disconnected parts parts = network_disconnected_vertices(network) # delete strip faces for fkey in strip_faces: mesh.delete_face_in_strips(fkey) for fkey in strip_faces: mesh.delete_face(fkey) old_vkeys_to_new_vkeys = {} # merge strip edge vertices that are connected for part in parts: # move back from network vertices to mesh vertices vertices = [new_to_old[vkey] for vkey in part] # skip adding a vertex if all vertices of the part are disconnected if any(mesh.is_vertex_connected(vkey) for vkey in vertices): # get position based on disconnected vertices that used to be on # the boundary if any if any(not mesh.is_vertex_connected(vkey) for vkey in vertices): points = [ mesh.vertex_coordinates(vkey) for vkey in vertices if not mesh.is_vertex_connected(vkey) ] # or based on old boundary vertices if any elif any(vkey in old_boundary_vertices for vkey in vertices): points = [ mesh.vertex_coordinates(vkey) for vkey in vertices if vkey in old_boundary_vertices ] else: points = [mesh.vertex_coordinates(vkey) for vkey in vertices] # new vertex x, y, z = centroid_points(points) new_vkey = mesh.add_vertex(attr_dict={'x': x, 'y': y, 'z': z}) old_vkeys_to_new_vkeys.update( {old_vkey: new_vkey for old_vkey in vertices}) # replace the old vertices for old_vkey in vertices: mesh.substitute_vertex_in_strips(old_vkey, new_vkey) mesh_substitute_vertex_in_faces(mesh, old_vkey, new_vkey, mesh.vertex_faces(old_vkey)) # delete the old vertices for old_vkey in vertices: mesh.delete_vertex(old_vkey) # delete data of deleted strip and collateral deleted strips del mesh.data['attributes']['strips'][skey] for skey_2 in collateral_deleted_strips: del mesh.data['attributes']['strips'][skey_2] #print(old_vkeys_to_new_vkeys) #print(mesh.data['attributes']['face_pole']) if 'face_pole' in mesh.data['attributes']: for fkey, pole in mesh.data['attributes']['face_pole'].items(): if fkey in mesh.data['attributes']['face_pole']: #print(fkey, pole, mesh.data['attributes']['face_pole']) if pole == mesh.data['attributes']['face_pole'][fkey]: if pole in old_vkeys_to_new_vkeys: mesh.data['attributes']['face_pole'][ fkey] = old_vkeys_to_new_vkeys[pole] return old_vkeys_to_new_vkeys