from . import g from .loop import Loop from collections import defaultdict # 因为要引用Loop patch,所以单独放了 def regenerate_loops(is_force_refresh=False): boundaries = g.boundaries # 假设 'g' 有一个 'boundaries' 属性,它包含边界对象 graph = {} # 构建无向图 for boundary in boundaries: graph.setdefault(boundary.start_vertex, []).append(boundary.end_vertex) graph.setdefault(boundary.end_vertex, []).append(boundary.start_vertex) # 方向字典 boundary_direction = { (boundary.start_vertex, boundary.end_vertex): (boundary, True) for boundary in boundaries } boundary_direction.update( { (boundary.end_vertex, boundary.start_vertex): (boundary, False) for boundary in boundaries } ) def dfs(node, start, path, visited, current_loops): max_length = 6 if len(path) > max_length: return visited.add(node) path.append(node) for neighbor in graph[node]: # 2条边在拓扑结构上是一摸一样的,没办法通过拓扑办法识别最小圈 if neighbor == start and len(path) > 2: # 找到一个环路,创建对应的环路(每条边是一个元组,包含boundary和方向) loop = Loop() for i in range(len(path) - 1): start_vertex = path[i] end_vertex = path[i + 1] if (start_vertex, end_vertex) in boundary_direction: boundary, direction = boundary_direction[ (start_vertex, end_vertex) ] loop.add_edge(boundary, direction) else: boundary, direction = boundary_direction[ (end_vertex, start_vertex) ] loop.add_edge(boundary, direction) # 处理闭合边(path[-1] 到 path[0]) start_vertex = path[-1] end_vertex = path[0] if (start_vertex, end_vertex) in boundary_direction: boundary, direction = boundary_direction[(start_vertex, end_vertex)] loop.add_edge(boundary, direction) else: boundary, direction = boundary_direction[(end_vertex, start_vertex)] loop.add_edge(boundary, direction) current_loops.append(loop) elif neighbor not in visited: dfs(neighbor, start, path, visited, current_loops) path.pop() visited.remove(node) loops = [] # 所有环路 for node in graph: current_loops = [] # 用来存储当前节点发现的环路 dfs(node, node, [], set(), current_loops) loops.extend(current_loops) # 将当前节点的环路加入到结果中 # 去重环路 unique_loops = set(loops) # 使用 set 去重环路 # 删除长度超过6的 unique_loops = {loop for loop in unique_loops if len(loop.boundaries) <= 6} # 如果一个环路,他有弦,则删掉 to_be_delete_loops = set() # 获取连续1 2 3条boundary的映射,并且要标记属于哪个loop的 start_v_and_end_v_to_loops_of_length = [ defaultdict(set) for _ in range(3) ] # 0是长度为1的,1为长度为2的,2为长度为3的,元素为字典,key是两个顶点,value是相关的loop for loop in unique_loops: verts = loop.controll_verts for vert_idx, vert in enumerate(verts): for offset in range(1, 4): # 1~3 vert_1 = verts[vert_idx] vert_2 = verts[(vert_idx + offset) % len(verts)] sorted_start_v_and_end_v_tuple = tuple( sorted([vert_1, vert_2], key=lambda v: v.index) ) start_v_and_end_v_to_loops_of_length[offset - 1][ sorted_start_v_and_end_v_tuple ].add(loop) # # debug形状 # print(len(start_v_and_end_v_to_loops_of_length)) # for i, start_v_and_end_v_to_loops in enumerate( # start_v_and_end_v_to_loops_of_length # ): # print(f"长度{i+1}") # for (vert_1, vert_2), loops in start_v_and_end_v_to_loops.items(): # print(len(loops)) for loop in unique_loops: if loop.length <= 3: # 小于3不检查弦 continue offset_range = loop.length - 3 loop_controll_verts = loop.controll_verts for offset in range(1, offset_range + 1): # 隔一个顶点就检查1条的,隔两个顶点就检查1和2条的,隔三个就检查123条的 # offset就是boundary的条数 # 遍历两两不相邻的顶点 for i in range(len(loop_controll_verts)): for j in range(len(loop_controll_verts)): # 确保 j 不等于 i,并且 j 不是 i 的相邻边界 if ( i != j and (j != (i + 1) % len(loop_controll_verts)) and (j != (i - 1) % len(loop_controll_verts)) ): vert_1 = loop_controll_verts[i] vert_2 = loop_controll_verts[j] sorted_start_v_and_end_v_tuple = tuple( sorted([vert_1, vert_2], key=lambda v: v.index) ) # 隔一个顶点就检查1条的,2和3跳过 # 如果 i 和 j 隔了 1 个顶点,跳过 offset 为 1 和 2 distance = min( abs(i - j), len(loop_controll_verts) - abs(i - j) ) # 0 1距离1 # print(loop.length, distance, offset) if distance == 2 and (offset == 2 or offset == 3): continue # 跳过 offset 为 1 或 2 的情况 # 如果 i 和 j 隔了 2 个顶点,跳过 offset 为 2 if distance == 3 and offset == 2: continue # 跳过 offset 为 2 的情况 related_loops = start_v_and_end_v_to_loops_of_length[ offset - 1 ].get(sorted_start_v_and_end_v_tuple) if not related_loops: continue # 排除自身的影响,并且用-号而不用remove()这样搞不会导致start_v_and_end_v_to_loops_of_length被修改 remaining_loops = related_loops - {loop} if remaining_loops: to_be_delete_loops.add(loop) # TODO:一旦被认为是弦,则对该loop的循环就要退出了,但是层数太多了 break # # 从所有的loops中删除外层loop unique_loops.difference_update(to_be_delete_loops) # 防止重建网格 updated_loops = [] if not is_force_refresh: loop_tobe_assign = set() for loop in unique_loops: if loop in g.loops: continue g.loops.append(loop) updated_loops.append(loop) else: g.loops = unique_loops updated_loops = unique_loops # print(len(g.loops)) # for loop in g.loops: # print("---") # print(loop.shape) # for b, d in loop.b_and_d_list: # print(b.start_vertex.index, b.end_vertex.index, d) for updated_loop in updated_loops: updated_loop.recreate_pattern() return updated_loops