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, ) )