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