Files
blender-easy-patch/pattern.py
小煜 ab91b120e6 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配置文件
2026-03-03 19:24:57 +08:00

1663 lines
44 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import bmesh
import numpy as np
import os
import sys
import copy
from . import loop # 不要调用,仅作为提示
from .utils import functions
from . import g
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "utils"))
sys.path.append(lib_path)
from .utils import pulp
from .utils.trans import t
class Pattern:
def __init__(
self,
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info={},
):
self.name = name
self.A = A
self.b_r = b_r
self.loop = None
self.pattern_check = pattern_check
self.vert_coords = vert_coords
self.edge_idxs = edge_idxs
self.face_idxs = face_idxs
self.split_vert_idxs = split_vert_idxs
self.additional_edge_flow_info = additional_edge_flow_info
self.op_instance = None
self.rotation = 0
self.verts = []
self.edges = []
self.faces = []
self.interior_verts = []
self.interior_edges = []
self.solution = None
@property
def boundary_num(self):
return len(self.b_r)
def remove_mesh(self):
interior_verts = self.interior_verts
interior_edges = self.interior_edges
faces = self.faces
# 先置为空再删除,防止绘图先获取
self.interior_verts = []
self.interior_edges = []
functions.remove_bm_faces(g.obj_bm, faces)
functions.remove_bm_edges(g.obj_bm, interior_edges)
functions.delete_bm_verts(g.obj_bm, interior_verts)
bmesh.update_edit_mesh(g.obj_me)
def create_mesh(self, pattern_solution, rotation):
functions.log("creating patern mesh")
vert_coords = self.vert_coords
edge_idxs = self.edge_idxs
face_idxs = self.face_idxs
split_vert_idxs = self.split_vert_idxs
# pattern_solution符合input需要旋转符合pattern才能合并边缘
padding_list = functions.rotate_list(
pattern_solution[: self.boundary_num], rotation
)
# 用于检查形状
rotated_boundaries_verts = [
boundary.verts if d else boundary.verts[::-1]
for boundary, d in functions.rotate_list(self.loop.b_and_d_list, rotation)
]
patch_boundary_shape = [len(i) for i in rotated_boundaries_verts]
me = g.obj_me
bm = g.obj_bm
# 创建顶点
init_verts = []
for idx, coord in enumerate(vert_coords):
vert = bm.verts.new(coord)
init_verts.append(vert)
split_verts = [init_verts[idx] for idx in split_vert_idxs]
# 创建网格前确保顶点索引更新
bm.verts.ensure_lookup_table()
# 创建边
init_edges = []
for edge_indices in edge_idxs:
edge = bm.edges.new(
(init_verts[edge_indices[0]], init_verts[edge_indices[1]])
)
init_edges.append(edge)
# 创建面
init_faces = []
for face_indices in face_idxs:
face = bm.faces.new([init_verts[i] for i in face_indices])
init_faces.append(face)
# 细分创建附加边流
misc_edge_flow_verts = []
misc_edge_flow_edges = []
misc_edge_flow_faces = []
for key, idx in self.additional_edge_flow_info.items():
cut_num = 0
edge = init_edges[idx]
if key == "x":
cut_num = pattern_solution[self.boundary_num]
elif key == "y":
cut_num = pattern_solution[self.boundary_num + 1]
elif key == "z":
cut_num = pattern_solution[self.boundary_num + 2]
else:
continue
result = bmesh.ops.subdivide_edgering(
bm,
edges=functions.edge_loops(bm, edge),
cuts=int(cut_num),
profile_shape="INVERSE_SQUARE",
profile_shape_factor=0.0,
)
for face in result["faces"]:
for vert in face.verts:
misc_edge_flow_verts.append(vert)
for edge in face.edges:
misc_edge_flow_edges.append(edge)
misc_edge_flow_faces.append(face)
# 挤出
misc_extruded_subdivide_verts = []
misc_extruded_subdivide_edges = []
misc_extruded_subdivide_faces = []
for i, padding_num in enumerate(padding_list):
if padding_num == 0:
continue
start_split_vert = split_verts[i]
if i + 1 == len(padding_list):
end_split_vert = split_verts[0]
else:
end_split_vert = split_verts[i + 1]
boundary_edges = []
# 寻找需要挤出的边2个边组的情况另算
# 这里是在细分之后,寻找方法是分割点寻找最近点,
if self.loop.length >= 3:
_, boundary_edges = functions.dijkstra(
bm, start_split_vert, end_split_vert
)
elif self.loop.length == 2:
# 第一个是边数多的,因为长度较短
first_boundary_verts, first_boundary_edges = functions.dijkstra(
bm,
start_split_vert,
end_split_vert,
exclude_edges=[],
is_along_boundary=True,
)
second_boundary_verts, second_boundary_edges = functions.dijkstra(
bm,
end_split_vert,
start_split_vert,
exclude_edges=first_boundary_edges,
is_along_boundary=True,
)
# 根据旋转赋值长短边
# pattern默认第一个边是下面那一个也就是边数多的那一个
# dijk获取的边第一个是边数少的那个
if i == 0:
boundary_edges = second_boundary_edges
else:
boundary_edges = first_boundary_edges
# for i in bm.verts:
# i.select = False
# start_split_vert.select = True
# end_split_vert.select = True
# bmesh.update_edit_mesh(me)
# return
else:
raise Exception("Ivalide boundary num")
extruded = bmesh.ops.extrude_edge_only(bm, edges=boundary_edges)
extruded_verts = [
v for v in extruded["geom"] if isinstance(v, bmesh.types.BMVert)
]
extruded_edges = [
v for v in extruded["geom"] if isinstance(v, bmesh.types.BMEdge)
]
extruded_faces = [
v for v in extruded["geom"] if isinstance(v, bmesh.types.BMFace)
]
misc_extruded_subdivide_verts += extruded_verts
misc_extruded_subdivide_edges += extruded_edges
misc_extruded_subdivide_faces += extruded_faces
# 找新分割点
new_start_split_vert = None
new_end_split_vert = None
len_1 = float("inf")
len_2 = float("inf")
for vert in extruded_verts:
new_len_1 = len(functions.dijkstra(bm, start_split_vert, vert)[0])
if new_len_1 < len_1:
len_1 = new_len_1
new_start_split_vert = vert
new_len_2 = len(functions.dijkstra(bm, end_split_vert, vert)[0])
if new_len_2 < len_2:
len_2 = new_len_2
new_end_split_vert = vert
# 更新找分割点
for idx, vert in enumerate(split_verts):
if vert == start_split_vert:
split_verts[idx] = new_start_split_vert
if vert == end_split_vert:
split_verts[idx] = new_end_split_vert
# 细分挤出,作为作为挤出段数
if padding_num > 1:
first_extrudeedge = functions.dijkstra(
bm, start_split_vert, new_start_split_vert
)[1][0]
result = bmesh.ops.subdivide_edgering(
bm,
edges=functions.edge_loops(bm, first_extrudeedge),
cuts=int(padding_num - 1),
profile_shape="INVERSE_SQUARE",
profile_shape_factor=0.0,
)
for face in result["faces"]:
for vert in face.verts:
misc_extruded_subdivide_verts.append(vert)
for edge in face.edges:
misc_extruded_subdivide_edges.append(edge)
misc_extruded_subdivide_faces.append(face)
# 不能使用edge获取内部边因合并的问题当内部edge连接到了要被合并的顶点则该edge会被新的替代
# 去除不存在和重复
edges = set(init_edges).union(
misc_extruded_subdivide_edges, misc_edge_flow_edges
)
verts = set(init_verts).union(
misc_extruded_subdivide_verts, misc_edge_flow_verts
)
faces = set(init_faces).union(
misc_extruded_subdivide_faces, misc_edge_flow_faces
)
# inter绘图用verts删除用
# # 去除不存在的
# 合并点会破坏点和边的索引,需要用面找边
self.faces = [face for face in faces if face in bm.faces]
# 也要记录vert因为重建boundary会把面破坏掉
verts, edges = functions.get_verts_and_edges_from_faces(g.obj_bm, self.faces)
verts = [vert for vert in verts if vert in bm.verts]
edges = [edge for edge in edges if edge in bm.edges]
self.edges = edges
self.verts = verts
self.interior_verts = [vert for vert in verts if not vert.is_boundary]
# 获取将要合并的顶点列表单独处理2个边的情况
pattern_boundaries_verts = []
if len(self.loop.shape) >= 3:
for i in range(len(split_verts)):
start_split_vert = split_verts[i]
if i + 1 == len(padding_list):
end_split_vert = split_verts[0]
else:
end_split_vert = split_verts[i + 1]
boundary_verts, _ = functions.dijkstra(
bm, start_split_vert, end_split_vert
)
pattern_boundaries_verts.append(boundary_verts)
elif len(self.loop.shape) == 2:
first_boundary_start_vert = split_verts[0]
first_boundary_end_vert = split_verts[1]
first_boundary_verts, first_boundary_edges = functions.dijkstra(
bm,
first_boundary_start_vert,
first_boundary_end_vert,
exclude_edges=[],
is_along_boundary=True,
)
second_boundary_start_vert = split_verts[1]
second_boundary_end_vert = split_verts[0]
second_boundary_verts, second_boundary_edges = functions.dijkstra(
bm,
second_boundary_start_vert,
second_boundary_end_vert,
exclude_edges=first_boundary_edges,
is_along_boundary=True,
)
pattern_boundaries_verts = [
first_boundary_verts,
second_boundary_verts,
]
# 两条边无法区分顺序,自行翻转顺序
pattern_boundary_shape = [len(i) for i in pattern_boundaries_verts]
if (
len(self.loop.shape) == 2
and pattern_boundary_shape != patch_boundary_shape
):
pattern_boundaries_verts = pattern_boundaries_verts[::-1]
else:
raise Exception("Ivalid boundary num")
# 检查形状
pattern_boundary_shape = [len(i) for i in pattern_boundaries_verts]
if len(self.loop.shape) >= 2 and pattern_boundary_shape != patch_boundary_shape:
self.remove_mesh()
msg = f"\n{self.name}\ninput {self.loop.shape}\nsolution {pattern_solution}\nrotation {rotation}\npattern shape {pattern_boundary_shape}\npatch shape {patch_boundary_shape}\nshape not match"
raise Exception(msg)
for i, (verts_1, verts_2) in enumerate(
zip(pattern_boundaries_verts, rotated_boundaries_verts)
):
for j, (vert_1, vert_2) in enumerate(zip(verts_1, verts_2)):
if j == len(verts_1) - 1:
continue
bmesh.ops.pointmerge(
bm, verts=[vert_2, vert_1], merge_co=vert_2.co
) # 会破坏点线面对象和索引
# 要在合并顶点后获取edges合并会破坏edge对象
verts, edges = functions.get_verts_and_edges_from_faces(g.obj_bm, self.faces)
self.interior_edges = [
edge for edge in edges if edge in bm.edges and edge not in self.loop.edges
]
self.interior_verts = [
vert
for vert in verts
if vert in bm.verts and vert not in self.loop.boundary_verts_walk
]
functions.smooth_verts_by_normal(g.obj, bm, self.verts)
# 更新网格
# 计算法线方向
bmesh.ops.recalc_face_normals(
bm, faces=list([i for i in faces if i in bm.faces])
)
if g.is_snap_surface:
functions.snap_verts_to_surface_along_normal(
functions.get_edit_obj(),
g.obj_bm,
self.interior_verts,
g.snap_bvh_trees,
allow_opposite_direction=False,
)
bmesh.update_edit_mesh(me)
bm.normal_update()
# def clear(self):
# bmesh.ops.delete(
# self.op_instance.bm,
# geom=self.interior_verts,
# context="VERTS",
# )
# bmesh.update_edit_mesh(self.op_instance.me)
# self.boundary_verts = []
# self.interior_verts = []
def validate_input_and_get_rotation(self, boundary_shape):
all_reduced_inputs = functions.get_all_reduced_inputs(boundary_shape)
boundary_shape = all_reduced_inputs[0]
rotation = None
boundary_shape_temp = None
for r in range(len(boundary_shape)):
boundary_shape_temp = functions.rotate_list(boundary_shape, r)
rotation = r
for a, b in zip(self.pattern_check, boundary_shape_temp):
if isinstance(a, int) and a != b:
rotation = None
continue
if callable(a):
result = a(boundary_shape_temp)
if isinstance(result, int) and result < 0:
rotation = None
continue
if isinstance(result, float) and (
result < 0 or not result.is_integer()
):
rotation = None
continue
if rotation is None:
continue
else:
# 匹配
functions.log(f"reduce: {boundary_shape}")
functions.log(f"rotation: {r}")
return r
return None
def solve_pattern_lp(
self, boundary_shape, rotation, constraint_list=[], is_suggest=False
):
# TODO: ilp没加整数校验
boundary_input = functions.rotate_list(boundary_shape, rotation)
boundary_input_len = len(boundary_input)
constraint_list = (
functions.rotate_list(constraint_list[:boundary_input_len], rotation)
+ constraint_list[boundary_input_len:]
)
functions.log(f"solver shape input: {boundary_input}")
functions.log(f"solver constraint input: {constraint_list}")
functions.log(f"solver rotation input: {rotation}")
A = np.array(self.A)
b_l = np.array(boundary_input)
b_r = np.array(self.b_r)
b = b_l - b_r
num_cols = A.shape[1] # 列变量数p和边流
num_rows = A.shape[0] # 行即约束数p
indices = list(range(num_cols))
p = [
pulp.LpVariable(f"p_{i}", lowBound=0, cat=pulp.LpInteger)
for i in range(num_rows)
]
edge_flow_vars = []
if num_cols > num_rows:
for i in range(num_cols - num_rows):
var_name = None
if i == 0:
var_name = "x"
if i == 1:
var_name = "y"
if i == 2:
var_name = "z"
if var_name:
edge_flow_var = pulp.LpVariable(
var_name, lowBound=0, cat=pulp.LpInteger
)
edge_flow_vars.append(edge_flow_var)
vars = p + edge_flow_vars
if is_suggest:
# 软约束
prob = pulp.LpProblem("ProbLp", pulp.LpMinimize)
dev_pos_list = [
pulp.LpVariable(f"dev_{i}_pos", lowBound=0) for i in range(num_rows)
]
dev_neg_list = [
pulp.LpVariable(f"dev_{i}_neg", lowBound=0) for i in range(num_rows)
]
prob += pulp.lpSum(dev_pos_list) + pulp.lpSum(dev_neg_list)
for i in range(num_rows):
prob += (
pulp.lpSum([A[i][j] * vars[j] for j in indices])
== b[i] + dev_pos_list[i] - dev_neg_list[i]
)
# 用户附加约束
for i, j in zip(vars, constraint_list):
if j is None:
continue
prob += i == j
status = prob.solve(pulp.PULP_CBC_CMD(msg=0))
# 求的时候建议了旋转,解的时候转回来
solution = [
i.value() for i in functions.rotate_list(dev_pos_list, -rotation)
] + [i.value() for i in functions.rotate_list(dev_neg_list, -rotation)]
# solution = [i.value() for i in dev_pos_list] + [
# i.value() for i in dev_neg_list
# ]
else:
# 硬约束
prob = pulp.LpProblem("ProbLp", pulp.LpMaximize)
prob += pulp.lpSum(p)
b = b_l - b_r
for i in range(num_rows):
prob += pulp.lpSum([A[i][j] * vars[j] for j in indices]) == b[i]
# 用户附加约束
for i, j in zip(vars, constraint_list):
if j is None:
continue
prob += i == j
status = prob.solve(pulp.PULP_CBC_CMD(msg=0))
solution = [
i.value()
for i in (
functions.rotate_list(vars[:boundary_input_len], -rotation)
+ vars[boundary_input_len:]
)
]
# solution = [i.value() for i in vars]
if status != 1:
functions.log("no solution")
return None
# 如果edgeflow缺了,手动附加
if len(vars) - len(solution) > 0:
solution += [0.0 for _ in range(len(vars) - len(solution))]
if is_suggest:
functions.log(f"suggest: {solution}")
else:
functions.log(f"solution: {solution}")
return solution
# 这里写的很乱,理一理
def recreate_pattern(loop):
if not loop:
return None
if loop.pattern:
loop.pattern.remove_mesh()
loop.pattern = None
loop.solver_msg = ""
loop.suggest_solution = None
# 检查奇偶
if sum(loop.shape) % 2 != 0:
loop.solver_msg = t("not_even_num_edges")
return None
boundary_shape = loop.shape
pattern_instance = None
rotation = None
pattern_solution = None
constraint_pattern = loop.solver_constraint_pattern
constraint_list = loop.solver_constraint_list
# 有pattern约束且没有rotation约束则搜索rotation否则rotation就是当前约束
if constraint_pattern:
pattern_instance = copy.deepcopy(constraint_pattern)
constraint_rotation = loop.solver_constraint_rotation
# 没有约束但rotation没定义则遍历搜索rotation,因此用户调整var的时候如果没有rotation约束会搜索n次很慢
if constraint_rotation is None:
# 遍历rotation计算n次
for r in range(len(loop.shape)):
pattern_solution = pattern_instance.solve_pattern_lp(
loop.shape, r, constraint_list=constraint_list
)
if pattern_solution is not None:
rotation = r
break
else:
pattern_solution = pattern_instance.solve_pattern_lp(
loop.shape, constraint_rotation, constraint_list=constraint_list
)
rotation = constraint_rotation
else:
# 初始化遍历寻找符合的pattern
for pattern in pattern_list:
# 匹配长度
if len(boundary_shape) != pattern.boundary_num:
continue
rotation = pattern.validate_input_and_get_rotation(boundary_shape)
if rotation is None:
continue
pattern_instance = copy.deepcopy(pattern)
break
if not pattern_instance:
loop.solver_msg = t("no_match_pattern")
return None
pattern_solution = pattern_instance.solve_pattern_lp(loop.shape, rotation)
# 无解,给出建议
if pattern_solution is None:
# 这里的rotation变量是承接上文的有可能是None
if rotation is not None:
suggest_rotation = rotation
else:
# 如果是带约束到这一步之前会执行n次ilp因为要解决旋转问题如果不带约束则在这之前只执行了一次
suggest_rotation = get_suggest_rotation(pattern_instance, loop.shape)
functions.log(f"suggest rotation: suggest_rotation")
suggest_solution = pattern_instance.solve_pattern_lp(
loop.shape,
suggest_rotation,
constraint_list=constraint_list,
is_suggest=True,
)
if suggest_solution:
loop.suggest_solution = suggest_solution
loop.solver_msg = t("no_solution")
return None
pattern_instance.rotation = rotation
pattern_instance.loop = loop
pattern_instance.solution = pattern_solution
pattern_instance.create_mesh(pattern_solution, rotation)
return pattern_instance
# 没有rotation的情况给建议先找rotation通过与pattern_check的差异查找
def get_suggest_rotation(pattern, boundary_shape):
all_reduced_inputs = functions.get_all_reduced_inputs(
boundary_shape, is_remove_duplicated_rotation=False
)
pattern_check = pattern.pattern_check
suggest_rotation = 0
dev_min = float("inf")
for boundary_shape in all_reduced_inputs:
for rotation in range(len(boundary_shape)):
boundary_shape_temp = functions.rotate_list(boundary_shape, rotation)
dev = 0
for a, b in zip(pattern_check, boundary_shape_temp):
if isinstance(a, int):
dev += abs(a - b)
if callable(a):
result = a(boundary_shape_temp)
dev += abs(result)
if dev < dev_min:
dev_min = dev
suggest_rotation = rotation
return suggest_rotation
def try_create_pattern():
pass
pattern_list = []
# 2-0
name = "2-0"
A = [
[0, 2, 2, 1],
[2, 0, 0, 1],
]
b_r = [3, 1]
pattern_check = [lambda i: (i[0] - i[1] - 2) / 2, lambda i: i[1] - 1]
vert_coords = [[2.0, 1.0, 0.0], [-2.0, 1.0, 0.0], [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]]
edge_idxs = [[3, 2], [0, 1], [2, 0], [1, 3]]
face_idxs = [[3, 2, 0, 1]]
split_vert_idxs = (1, 0)
additional_edge_flow_info = {"x": 3, "y": 0}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 2-1
name = "2-1"
A = [
[0, 2, 1, 1],
[2, 0, 1, 1],
]
b_r = [2, 2]
pattern_check = [lambda i: 0.999 * (i[0] - i[1]), lambda i: i[0] - 2]
vert_coords = [
[-1.4142135381698608, 0.0, 0.0],
[0.0, -2.4142136573791504, 0.0],
[0.0, 1.4142135381698608, 0.0],
[1.4142135381698608, 0.0, 0.0],
]
edge_idxs = [[0, 1], [2, 0], [3, 2], [1, 3]]
face_idxs = [[0, 1, 3, 2]]
split_vert_idxs = [0, 3]
additional_edge_flow_info = {"x": 0, "y": 3}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 3-0
name = "3-0"
A = [
[0, 1, 1],
[1, 0, 1],
[1, 1, 0],
]
b_r = [2, 1, 1]
pattern_check = [2, 1, 1]
vert_coords = [
(0.0, 1.0, 0.0),
(-0.8660253882408142, -0.5, 0.0),
(0.8660253882408142, -0.5, 0.0),
(0.0, -0.5, 0.0),
]
edge_idxs = [(1, 0), (3, 1), (0, 2), (2, 3)]
face_idxs = [[1, 3, 2, 0]]
split_vert_idxs = [1, 2, 0]
additional_edge_flow_info = {}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 3-1
name = "3-1"
A = (
(0, 1, 1, 2),
(1, 0, 1, 0),
(1, 1, 0, 0),
)
b_r = [4, 1, 1]
pattern_check = [lambda i: (i[0] - 4) / 2, 1, 1]
vert_coords = [
(0.0, 1.0, 0.0),
(-0.8660253882408142, -0.5, 0.0),
(0.8660253882408142, -0.5, 0.0),
(0.0, 0.0, 0.0),
(0.0, -0.5, 0.0),
(0.4330126941204071, -0.5, 0.0),
(-0.4330126941204071, -0.5, 0.0),
]
edge_idxs = [(1, 0), (6, 1), (0, 2), (4, 6), (5, 4), (2, 5), (3, 5), (3, 6), (0, 3)]
face_idxs = [[4, 5, 3, 6], [1, 6, 3, 0], [2, 0, 3, 5]]
split_vert_idxs = (1, 2, 0)
additional_edge_flow_info = {"x": 8}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 4-0
name = "4-0"
A = (
(0, 1, 0, 1),
(1, 0, 1, 0),
(0, 1, 0, 1),
(1, 0, 1, 0),
)
b_r = (1, 1, 1, 1)
pattern_check = (1, 1, 1, 1)
vert_coords = [(1.0, 1.0, 0.0), (-1.0, 1.0, 0.0), (1.0, -1.0, 0.0), (-1.0, -1.0, 0.0)]
edge_idxs = [(2, 0), (3, 2), (0, 1), (1, 3)]
face_idxs = [[3, 2, 0, 1]]
split_vert_idxs = [3, 2, 0, 1]
additional_edge_flow_info = {}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 4-1
name = "4-1"
A = (
(0, 1, 0, 1, 1),
(1, 0, 1, 0, 1),
(0, 1, 0, 1, 0),
(1, 0, 1, 0, 0),
)
b_r = (2, 2, 1, 1)
# pattern_check = (
# lambda i: 0.5 * (i[0] != i[1]),
# lambda i: i[1] - 2,
# 1,
# 1,
# )
pattern_check = (
lambda i: 0.999 * (i[0] - i[1]),
lambda i: i[1] - 2,
1,
1,
)
vert_coords = [
(1.0, 1.0, 0.0),
(-1.0, 1.0, 0.0),
(1.0, -1.0, 0.0),
(-1.0, -1.0, 0.0),
(0.0, 0.0, 0.0),
(1.0, 0.0, 0.0),
(0.0, -1.0, 0.0),
]
edge_idxs = [(0, 1), (6, 2), (1, 3), (5, 0), (4, 6), (4, 5), (2, 5), (3, 6), (1, 4)]
face_idxs = [[6, 4, 5, 2], [0, 5, 4, 1], [3, 1, 4, 6]]
split_vert_idxs = (3, 2, 0, 1)
additional_edge_flow_info = {"x": 8}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 4-2
name = "4-2"
A = (
(0, 1, 0, 1, 1, 1),
(1, 0, 1, 0, 1, 0),
(0, 1, 0, 1, 0, 0),
(1, 0, 1, 0, 0, 1),
)
b_r = (3, 1, 1, 1)
# pattern_check = [
# lambda i: i[1] - 1,
# lambda i: i[3] - 1,
# 1,
# lambda i: 0.5 * (i[0] - i[1] - i[3] != 1),
# ]
pattern_check = [
lambda i: i[1] - 1,
lambda i: i[3] - 1,
1,
lambda i: 0.999 * (i[0] - i[1] - i[3] - 1),
]
vert_coords = [
(0.3333333134651184, -1.0, 0.0),
(-0.3333333134651184, -1.0, 0.0),
(1.0, 1.0, 0.0),
(-1.0, 1.0, 0.0),
(1.0, -1.0, 0.0),
(-1.0, -1.0, 0.0),
]
edge_idxs = [(3, 5), (0, 4), (1, 0), (5, 1), (1, 2), (4, 2), (2, 3)]
face_idxs = [[3, 2, 1, 5], [0, 1, 2, 4]]
split_vert_idxs = (5, 4, 2, 3)
additional_edge_flow_info = {"x": 2, "y": 4}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
name = "4-2-i"
# pattern_check = [
# lambda i: 0.5 * (i[-1] - i[-2] - i[0] != 1),
# 1,
# lambda i: i[0] - 1,
# lambda i: i[-2] - 1,
# ]
pattern_check = [
lambda i: 0.999 * (i[-1] - i[-2] - i[0] - 1),
1,
lambda i: i[0] - 1,
lambda i: i[-2] - 1,
]
pattern_list.append(
Pattern(
name,
functions.flip_A(A),
b_r[::-1],
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
(split_vert_idxs[0],) + split_vert_idxs[:0:-1],
additional_edge_flow_info,
)
)
# 4-3
name = "4-3"
A = (
(0, 1, 0, 1, 2, 1),
(1, 0, 1, 0, 0, 0),
(0, 1, 0, 1, 0, 1),
(1, 0, 1, 0, 0, 0),
)
b_r = (3, 1, 1, 1)
pattern_check = [lambda i: (i[0] - i[2] - 2) / 2, 1, lambda i: i[2] - 1, 1]
vert_coords = [
(1.0, 1.0, 0.0),
(-1.0, 1.0, 0.0),
(1.0, -1.0, 0.0),
(-1.0, -1.0, 0.0),
(-0.3333333134651184, -1.0, 0.0),
(0.3333333134651184, -1.0, 0.0),
(-0.3333333134651184, 0.0, 0.0),
(0.3333333134651184, 0.0, 0.0),
]
edge_idxs = [
(5, 2),
(1, 3),
(0, 1),
(2, 0),
(3, 4),
(4, 5),
(6, 7),
(4, 6),
(5, 7),
(0, 7),
(1, 6),
]
face_idxs = [[5, 7, 6, 4], [2, 0, 7, 5], [0, 1, 6, 7], [3, 4, 6, 1]]
split_vert_idxs = (3, 2, 0, 1)
additional_edge_flow_info = {"x": 10, "y": 6}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 4-4
name = "4-4"
A = (
(0, 1, 0, 1, 2, 1),
(1, 0, 1, 0, 0, 1),
(0, 1, 0, 1, 0, 0),
(1, 0, 1, 0, 0, 0),
)
b_r = (4, 2, 1, 1)
pattern_check = [lambda i: (i[0] - i[1] - 2) / 2, lambda i: i[1] - 2, 1, 1]
vert_coords = [
(-0.5, 0.0, 0.0),
(0.5, -0.5, 0.0),
(0.0, 0.0, 0.0),
(0.5, -1.0, 0.0),
(0.0, -1.0, 0.0),
(-0.5, -1.0, 0.0),
(1.0, 1.0, 0.0),
(-1.0, 1.0, 0.0),
(1.0, -1.0, 0.0),
(-1.0, -1.0, 0.0),
(1.0, 0.0, 0.0),
]
edge_idxs = [
(3, 8),
(4, 3),
(2, 4),
(0, 2),
(10, 6),
(5, 4),
(9, 5),
(0, 7),
(0, 5),
(1, 10),
(2, 6),
(7, 9),
(6, 7),
(1, 2),
(1, 3),
(8, 10),
]
face_idxs = [
[3, 1, 10, 8],
[6, 10, 1, 2],
[4, 5, 0, 2],
[4, 2, 1, 3],
[0, 7, 6, 2],
[9, 7, 0, 5],
]
split_vert_idxs = (9, 8, 6, 7)
additional_edge_flow_info = {"x": 7, "y": 13}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
name = "4-4-i"
pattern_check = [1, 1, lambda i: i[-2] - 2, lambda i: (i[-1] - i[-2] - 2) / 2]
pattern_list.append(
Pattern(
name,
functions.flip_A(A),
b_r[::-1],
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
(split_vert_idxs[0],) + split_vert_idxs[:0:-1],
additional_edge_flow_info,
)
)
# # 4-circ
# name = "4-circ"
# A = (
# (0, 1, 0, 1, 0),
# (1, 0, 1, 0, 0),
# (0, 1, 0, 1, 0),
# (1, 0, 1, 0, 0),
# )
# b_r = (1, 1, 1, 1)
# pattern_check = (1, 1, 1, 1)
# vert_coords = [
# (-1.0, -1.0, 0.0),
# (1.0, -1.0, 0.0),
# (-1.0, 1.0, 0.0),
# (1.0, 1.0, 0.0),
# (-0.5, -0.5, 0.0),
# (0.5, -0.5, 0.0),
# (-0.5, 0.5, 0.0),
# (0.5, 0.5, 0.0),
# ]
# edge_idxs = [
# (2, 0),
# (0, 1),
# (1, 3),
# (3, 2),
# (6, 4),
# (4, 5),
# (5, 7),
# (7, 6),
# (0, 4),
# (6, 2),
# (7, 3),
# (1, 5),
# ]
# face_idxs = [
# [0, 2, 3, 1],
# [4, 5, 7, 6],
# [2, 0, 4, 6],
# [3, 2, 6, 7],
# [0, 1, 5, 4],
# [1, 3, 7, 5],
# ]
# split_vert_idxs = (0, 1, 3, 2)
# additional_edge_flow_info = {"x": 8}
# pattern_list.append(
# Pattern(
# name,
# A,
# b_r,
# pattern_check,
# vert_coords,
# edge_idxs,
# face_idxs,
# split_vert_idxs,
# additional_edge_flow_info,
# )
# )
# 5-0
name = "5-0"
A = (
(0, 1, 0, 0, 1),
(1, 0, 1, 0, 0),
(0, 1, 0, 1, 0),
(0, 0, 1, 0, 1),
(1, 0, 0, 1, 0),
)
b_r = (2, 1, 1, 1, 1)
pattern_check = [2, 1, 1, 1, 1]
vert_coords = [
(0.0, 1.0, 0.0),
(-0.9510565400123596, 0.30901700258255005, 0.0),
(-0.5877852439880371, -0.80901700258255, 0.0),
(0.5877852439880371, -0.80901700258255, 0.0),
(0.9510565400123596, 0.30901700258255005, 0.0),
(0.0, -0.80901700258255, 0.0),
]
edge_idxs = [(1, 0), (2, 1), (5, 2), (4, 3), (0, 4), (3, 5), (0, 5)]
face_idxs = [[1, 2, 5, 0], [4, 0, 5, 3]]
split_vert_idxs = (2, 3, 4, 0, 1)
additional_edge_flow_info = {}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 5-1
name = "5-1"
A = (
(0, 1, 0, 0, 1, 1),
(1, 0, 1, 0, 0, 1),
(0, 1, 0, 1, 0, 0),
(0, 0, 1, 0, 1, 0),
(1, 0, 0, 1, 0, 0),
)
b_r = (2, 1, 1, 1, 1)
# pattern_check = [lambda i: i[1] - 1, lambda i: 0.5 * (i[0] - i[1] != 1), 1, 1, 1]
pattern_check = [lambda i: i[1] - 1, lambda i: 0.999 * (i[0] - i[1] - 1), 1, 1, 1]
vert_coords = [
(0.0, -0.80901700258255, 0.0),
(0.9510565400123596, 0.30901700258255005, 0.0),
(0.5877852439880371, -0.80901700258255, 0.0),
(-0.5877852439880371, -0.80901700258255, 0.0),
(-0.9510565400123596, 0.30901700258255005, 0.0),
(0.0, 1.0, 0.0),
]
edge_idxs = [(1, 3), (1, 2), (0, 3), (3, 4), (2, 0), (4, 5), (5, 1)]
face_idxs = [[5, 4, 3, 1], [0, 2, 1, 3]]
split_vert_idxs = (3, 2, 1, 5, 4)
additional_edge_flow_info = {"x": 2}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
name = "5-1-i"
# pattern_check = [1, 1, 1, lambda i: 0.5 * (i[-1] - i[-2] != 1), lambda i: i[-2] - 1]
pattern_check = [1, 1, 1, lambda i: 0.999 * (i[-1] - i[-2] - 1), lambda i: i[-2] - 1]
pattern_list.append(
Pattern(
name,
functions.flip_A(A),
b_r[::-1],
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
(split_vert_idxs[0],) + split_vert_idxs[:0:-1],
additional_edge_flow_info,
)
)
# 5-2
name = "5-2"
A = (
(0, 1, 0, 0, 1, 2),
(1, 0, 1, 0, 0, 0),
(0, 1, 0, 1, 0, 0),
(0, 0, 1, 0, 1, 0),
(1, 0, 0, 1, 0, 0),
)
b_r = (4, 1, 1, 1, 1)
pattern_check = (lambda i: (i[0] - 4) / 2, 1, 1, 1, 1)
vert_coords = [
(0.29389262199401855, -0.80901700258255, 0.0),
(0.9510565400123596, 0.30901700258255005, 0.0),
(0.5877852439880371, -0.80901700258255, 0.0),
(-0.5877852439880371, -0.80901700258255, 0.0),
(-0.9510565400123596, 0.30901700258255005, 0.0),
(0.0, 1.0, 0.0),
(0.0, -0.80901700258255, 0.0),
(-0.29389262199401855, -0.80901700258255, 0.0),
(0.0, 0.0, 0.0),
(0.0, -0.404508501291275, 0.0),
]
edge_idxs = [
(7, 3),
(5, 1),
(0, 6),
(3, 4),
(2, 0),
(4, 5),
(1, 2),
(6, 7),
(7, 9),
(0, 9),
(8, 9),
(3, 8),
(2, 8),
(5, 8),
]
face_idxs = [[7, 9, 8, 3], [0, 2, 8, 9], [6, 0, 9, 7], [1, 5, 8, 2], [4, 3, 8, 5]]
split_vert_idxs = (3, 2, 1, 5, 4)
additional_edge_flow_info = {"x": 10}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 5-3
name = "5-3"
A = (
(0, 1, 0, 0, 1, 2, 1),
(1, 0, 1, 0, 0, 0, 1),
(0, 1, 0, 1, 0, 0, 0),
(0, 0, 1, 0, 1, 0, 0),
(1, 0, 0, 1, 0, 0, 0),
)
b_r = (5, 2, 1, 1, 1)
pattern_check = [lambda i: (i[0] - i[1] - 3) / 2, lambda i: i[1] - 2, 1, 1, 1]
vert_coords = [
(-0.5089906454086304, 0.0, 0.0),
(-0.35267114639282227, -0.80901700258255, 0.0),
(-0.11755704879760742, -0.80901700258255, 0.0),
(0.11755704879760742, -0.80901700258255, 0.0),
(0.35267114639282227, -0.80901700258255, 0.0),
(0.9510565400123596, 0.30901700258255005, 0.0),
(0.5877852439880371, -0.80901700258255, 0.0),
(-0.5877852439880371, -0.80901700258255, 0.0),
(-0.9510565400123596, 0.30901700258255005, 0.0),
(0.0, 1.0, 0.0),
(-0.22425960004329681, 0.34856167435646057, 0.0),
(0.08892543613910675, 0.0, 0.0),
(0.31710362434387207, -0.24705025553703308, 0.0),
(0.769420862197876, -0.25, 0.0),
]
edge_idxs = [
(3, 2),
(10, 0),
(4, 3),
(9, 5),
(11, 10),
(1, 7),
(7, 8),
(0, 1),
(8, 9),
(6, 4),
(2, 1),
(13, 6),
(2, 10),
(3, 11),
(12, 4),
(12, 11),
(5, 13),
(13, 12),
(11, 5),
(9, 10),
(0, 8),
]
face_idxs = [
[10, 2, 1, 0],
[10, 11, 3, 2],
[11, 12, 4, 3],
[4, 12, 13, 6],
[12, 11, 5, 13],
[9, 5, 11, 10],
[10, 0, 8, 9],
[1, 7, 8, 0],
]
split_vert_idxs = (7, 6, 5, 9, 8)
additional_edge_flow_info = {"x": 20, "y": 15}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
name = "5-3-i"
pattern_check = [1, 1, 1, lambda i: i[-2] - 2, lambda i: (i[-1] - i[-2] - 3) / 2]
pattern_list.append(
Pattern(
name,
functions.flip_A(A),
b_r[::-1],
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
(split_vert_idxs[0],) + split_vert_idxs[:0:-1],
additional_edge_flow_info,
)
)
# 6-0
name = "6-0"
A = (
(0, 1, 0, 0, 0, 1, 1),
(1, 0, 1, 0, 0, 0, 0),
(0, 1, 0, 1, 0, 0, 0),
(0, 0, 1, 0, 1, 0, 1),
(0, 0, 0, 1, 0, 1, 0),
(1, 0, 0, 0, 1, 0, 0),
)
b_r = (1, 1, 1, 1, 1, 1)
# pattern_check = [lambda i: i[0] - 1, 1, 1, lambda i: 0.5 * (i[0] != i[3]), 1, 1]
pattern_check = [lambda i: i[0] - 1, 1, 1, lambda i: 0.999 * (i[0] - i[3]), 1, 1]
vert_coords = [
(1.0, 0.0, 0.0),
(0.5000000596046448, 0.8660253882408142, 0.0),
(-0.4999999701976776, 0.866025447845459, 0.0),
(-1.0, 0.0, 0.0),
(-0.5000000596046448, -0.8660253882408142, 0.0),
(0.4999999701976776, -0.866025447845459, 0.0),
]
edge_idxs = [(1, 0), (2, 1), (3, 2), (4, 3), (5, 4), (0, 5), (3, 0)]
face_idxs = [[4, 5, 0, 3], [1, 2, 3, 0]]
split_vert_idxs = (4, 5, 0, 1, 2, 3)
additional_edge_flow_info = {"x": 6}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 6-1
name = "6-1"
A = (
(0, 1, 0, 0, 0, 1, 1),
(1, 0, 1, 0, 0, 0, 1),
(0, 1, 0, 1, 0, 0, 0),
(0, 0, 1, 0, 1, 0, 0),
(0, 0, 0, 1, 0, 1, 0),
(1, 0, 0, 0, 1, 0, 0),
)
b_r = (2, 2, 1, 1, 1, 1)
# pattern_check = [lambda i: i[0] - 2, lambda i: 0.5 * (i[0] != i[1]), 1, 1, 1, 1]
pattern_check = [lambda i: i[0] - 2, lambda i: 0.999 * (i[0] - i[1]), 1, 1, 1, 1]
vert_coords = [
(0.4999999701976776, -0.866025447845459, 0.0),
(-0.5000000596046448, -0.8660253882408142, 0.0),
(-1.0, 0.0, 0.0),
(-0.4999999701976776, 0.866025447845459, 0.0),
(0.5000000596046448, 0.8660253882408142, 0.0),
(1.0, 0.0, 0.0),
(0.0, -9.934107758624577e-09, 0.0),
(0.25, -0.4330127239227295, 0.0),
(0.75, -0.4330127239227295, 0.0),
(-2.9802322387695312e-08, -0.866025447845459, 0.0),
]
edge_idxs = [
(1, 2),
(2, 3),
(3, 4),
(4, 5),
(8, 0),
(9, 1),
(6, 7),
(7, 8),
(7, 9),
(5, 8),
(0, 9),
(1, 6),
(5, 6),
(3, 6),
]
face_idxs = [[9, 7, 6, 1], [8, 7, 9, 0], [7, 8, 5, 6], [4, 3, 6, 5], [2, 1, 6, 3]]
split_vert_idxs = (1, 0, 5, 4, 3, 2)
additional_edge_flow_info = {"x": 6}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 6-2
name = "6-2"
A = (
(0, 1, 0, 0, 0, 1, 2, 1),
(1, 0, 1, 0, 0, 0, 0, 0),
(0, 1, 0, 1, 0, 0, 0, 0),
(0, 0, 1, 0, 1, 0, 0, 1),
(0, 0, 0, 1, 0, 1, 0, 0),
(1, 0, 0, 0, 1, 0, 0, 0),
)
b_r = (3, 1, 1, 1, 1, 1)
pattern_check = [lambda i: i[3] - 1, 1, 1, lambda i: (i[0] - i[3] - 2) / 2, 1, 1]
vert_coords = [
(0.16666662693023682, -0.38941529393196106, 0.0),
(-0.16666671633720398, -0.38941529393196106, 0.0),
(-0.16666671633720398, -0.866025447845459, 0.0),
(0.16666662693023682, -0.866025447845459, 0.0),
(0.4999999701976776, -0.866025447845459, 0.0),
(-0.5000000596046448, -0.8660253882408142, 0.0),
(-1.0, 0.0, 0.0),
(-0.4999999701976776, 0.866025447845459, 0.0),
(0.5000000596046448, 0.8660253882408142, 0.0),
(1.0, 0.0, 0.0),
(0.28053152561187744, 0.0, 0.0),
(-0.2805315852165222, 0.0, 0.0),
]
edge_idxs = [
(11, 1),
(0, 1),
(3, 2),
(9, 4),
(0, 3),
(5, 11),
(6, 7),
(7, 8),
(8, 9),
(2, 5),
(1, 2),
(10, 11),
(5, 6),
(4, 3),
(10, 0),
(10, 4),
(8, 10),
(7, 11),
]
face_idxs = [
[3, 0, 10, 4],
[4, 10, 8, 9],
[5, 11, 1, 2],
[1, 0, 3, 2],
[1, 11, 10, 0],
[7, 8, 10, 11],
[7, 11, 5, 6],
]
split_vert_idxs = (5, 4, 9, 8, 7, 6)
additional_edge_flow_info = {"x": 0, "y": 1}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
# 6-3
name = "6-3"
A = (
(0, 1, 0, 0, 0, 1, 2, 1),
(1, 0, 1, 0, 0, 0, 0, 1),
(0, 1, 0, 1, 0, 0, 0, 0),
(0, 0, 1, 0, 1, 0, 0, 0),
(0, 0, 0, 1, 0, 1, 0, 0),
(1, 0, 0, 0, 1, 0, 0, 0),
)
b_r = (4, 2, 1, 1, 1, 1)
pattern_check = [lambda i: i[1] - 2, lambda i: (i[0] - i[1] - 2) / 2, 1, 1, 1, 1]
vert_coords = [
(0.75, -0.4330127239227295, 0.0),
(-2.9802322387695312e-08, -0.0053040385246276855, 0.0),
(-0.2500000298023224, -0.0053040385246276855, 0.0),
(-0.2500000298023224, -0.866025447845459, 0.0),
(-2.9802322387695312e-08, -0.866025447845459, 0.0),
(0.2499999701976776, -0.866025447845459, 0.0),
(0.4999999701976776, -0.866025447845459, 0.0),
(-0.5000000596046448, -0.8660253882408142, 0.0),
(-1.0, 0.0, 0.0),
(-0.4999999701976776, 0.866025447845459, 0.0),
(0.5000000596046448, 0.8660253882408142, 0.0),
(1.0, 0.0, 0.0),
(0.43703240156173706, -0.4330127239227295, 0.0),
(-2.9802322387695312e-08, 0.43600431084632874, 0.0),
(-0.2500000298023224, 0.43600431084632874, 0.0),
]
edge_idxs = [
(12, 5),
(2, 3),
(1, 2),
(1, 11),
(5, 4),
(0, 6),
(3, 7),
(8, 9),
(1, 4),
(12, 1),
(10, 11),
(6, 5),
(11, 0),
(12, 0),
(4, 3),
(9, 10),
(7, 8),
(14, 13),
(13, 1),
(13, 10),
(9, 14),
(2, 14),
(8, 2),
]
face_idxs = [
[6, 0, 12, 5],
[11, 1, 12, 0],
[3, 4, 1, 2],
[5, 12, 1, 4],
[11, 10, 13, 1],
[13, 10, 9, 14],
[1, 13, 14, 2],
[9, 8, 2, 14],
[7, 3, 2, 8],
]
split_vert_idxs = (7, 6, 11, 10, 9, 8)
additional_edge_flow_info = {"x": 22, "y": 9}
pattern_list.append(
Pattern(
name,
A,
b_r,
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
split_vert_idxs,
additional_edge_flow_info,
)
)
name = "6-3-i"
pattern_check = [1, 1, 1, 1, lambda i: (i[-1] - i[-2] - 2) / 2, lambda i: i[-2] - 2]
pattern_list.append(
Pattern(
name,
functions.flip_A(A),
b_r[::-1],
pattern_check,
vert_coords,
edge_idxs,
face_idxs,
(split_vert_idxs[0],) + split_vert_idxs[:0:-1],
additional_edge_flow_info,
)
)