feat: 初始化Easy Patch插件及依赖文件
- 添加Blender插件核心文件:__init__.py、ui.py、property.py、preference.py - 添加插件工具模块:g.py、loop.py、generate_loop.py、const.py、op.py - 添加翻译工具:utils/trans.py - 添加PuLP线性规划库及其依赖文件,包括CBC求解器二进制文件 - 添加.gitignore和VSCode配置文件
This commit is contained in:
194
generate_loop.py
Normal file
194
generate_loop.py
Normal file
@@ -0,0 +1,194 @@
|
||||
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
|
||||
Reference in New Issue
Block a user