I am currently trying to connect two opposite loops of faces by generating a connector between them. I managed to get it working, if the opposing loops have the same number of faces, however I am struggling to figure out what to do if the face counts are different. I figured out, that I should iterate over the faces of the smaller loop and subdivide the largest faces in half until the number of faces inside the loop is equal to the other loop. Unfortunately, I cannot figure out how to do it in code and this is what I have got so far: """ Creates connectors between two face loops by finding the optimal face ordering for loop2_faces relative to loop1_faces to minimize connector length. Args: loop1_faces (list of BMFace): List of faces in the first loop. loop2_faces (list of BMFace): List of faces in the second loop. obj1 (Object): Blender object containing loop1. obj2 (Object): Blender object containing loop2. Returns: list of Object: List of connector objects created between the loops. """ if obj1.mode != 'EDIT' or obj2.mode != 'EDIT': raise ValueError("Both objects must be in edit mode to perform this operation.") while len(loop1_faces) != len(loop2_faces): print("len(loop1_faces) != len(loop2_faces)") print(f"len of loop1_faces: {len(loop1_faces)}, len of loop2_faces: {len(loop2_faces)}") bm = bmesh.from_edit_mesh(obj2.data) for face in bm.faces: face.select = False for face in loop2_faces: if face.is_valid: face.select = True bmesh.update_edit_mesh(obj2.data) largest_face = find_largest_face(loop2_faces) print("Largest face:", largest_face) divided_faces = divide_face_in_half(obj2, largest_face) bm.faces.ensure_lookup_table() loop2_faces.remove(largest_face) new_faces = [f for f in bm.faces if f.select and f.is_valid] loop2_faces.extend(new_faces) bmesh.update_edit_mesh(obj2.data) print(f"Updated loop2_faces: {[f.index for f in loop2_faces]}") print(f"len of loop1_faces: {len(loop1_faces)}, len of loop2_faces: {len(loop2_faces)}") ordered_loop1_faces = order_faces_by_adjacency(loop1_faces[0], loop1_faces, clockwise=True) """ Safely divide a quadrilateral face into two smaller quads using bpy.ops.mesh.subdivide with adjusted parameters to prevent grid-like results. Args: obj (bpy.types.Object): The Blender object containing the face. face (BMFace): The quadrilateral face to be divided. Returns: list: Updated list of faces after division, or an empty list if the operation fails. """ # Ensure the object is in edit mode bpy.context.view_layer.objects.active = obj if obj.mode != 'EDIT': bpy.ops.object.mode_set(mode='EDIT') # Get the BMesh for the object's edit mesh bm = bmesh.from_edit_mesh(obj.data) # Ensure face lookups are refreshed bm.faces.ensure_lookup_table() bm.edges.ensure_lookup_table() # Match the target face matching_face = next((bm_face for bm_face in bm.faces if bm_face.index == face.index), None) if not matching_face: print("Target face not found in BMesh.") return [] num_edges = len(matching_face.edges) if num_edges == 4: # Deselect all geometry for bm_face in bm.faces: bm_face.select = False for bm_edge in bm.edges: bm_edge.select = False # Select only two opposite edges edges = list(matching_face.edges) edges[0].select = True # Select one edge edges[2].select = True # Select the opposite edge # Update the mesh selection for Blender print("yesyes") bmesh.update_edit_mesh(obj.data, loop_triangles=False) # Subdivide the selected edges try: bpy.ops.mesh.subdivide( number_cuts=1, smoothness=0, ngon=False, # Ensure quads remain quadcorner='STRAIGHT_CUT', # Enforce straight cuts fractal=0, fractal_along_normal=0, seed=0, ) # Refresh the BMesh bm = bmesh.from_edit_mesh(obj.data) bm.faces.ensure_lookup_table() # Collect new faces created by subdivision new_faces = [f for f in bm.faces if f.select and f != matching_face] print(f"Successfully divided face {face.index} into {len(new_faces)} new faces.") return new_faces except Exception as e: print(f"Subdivision failed: {e}") return [] else: print(f"Face with {num_edges} edges cannot be divided into two quads.") return [] """ Orders faces in the loop based on physical adjacency starting from start_face. Args: start_face (BMFace): The starting face in the loop. face_loop (list of BMFace]): List of faces in the second loop. clockwise (bool): If True, traverse the loop in a clockwise direction. Returns: list of BMFace: Faces ordered by adjacency. """ ordered_faces = [start_face] face_set = set(face_loop) face_set.remove(start_face) current_face = start_face while face_set: next_face = None # Find the next face in the loop that shares an edge with the current face for edge in current_face.edges: for linked_face in edge.link_faces: if linked_face in face_set: next_face = linked_face break if next_face: break if next_face is None: print("WARNING: Stopping early, some faces are disconnected.") break # Prevent infinite loops # Add face and remove it from the remaining set ordered_faces.append(next_face) face_set.remove(next_face) current_face = next_face # If we didn't order all faces, print debugging info if len(ordered_faces) != len(face_loop): print(f"ERROR: Only {len(ordered_faces)} / {len(face_loop)} faces ordered!") print(f"Remaining unprocessed faces: {[f.index for f in face_set]}") return ordered_faces if clockwise else list(reversed(ordered_faces)) Currently, it seems to work splitting the faces in half, but it fails here: WARNING: Stopping early, some faces are disconnected. It seems to me, that the new faces (resulting from the subdivisions) do not share the same edges with the other faces of the loop and that is why that fails, but in the viewport they seem to be in the correct place. ERROR: Only 7 / 40 faces ordered! Remaining unprocessed faces: [46009, 45973, 46010, 45974, 76013, 46013, 45977, 46014, 45978, 46017, 45981, 46018, 45982, 46021, 45985, 45986, 45989, 45990, 45993, 45994, 75998, 45997, 45998, 46001, 45965, 46002, 45966, 76005, 46005, 45969, 46006, 45970, 76010] I apologize for the post sloppiness, it is my first stackoverflow question. example of a face loop I figured out, that I should iterate over the faces of the smaller loop and subdivide the largest faces in half until the number of faces inside the loop is equal to the other loop. Unfortunately, I cannot figure out how to do it in code and this is what I have got so far. I also tried splitting the faces (in the smaller loop) manually, but then the script didn't work due to some index out of range error. Continue reading...