def calc_vert_tangents(self):
        """self.loop_tris.bmのBORDERフラグが立っている頂点のtangentを計算。
        :return: キーがBMVert, 値が[tangent, tangent(min), tangent(max)]の
            辞書を返す。tangentはself.align_edgesが偽の場合に、tangent(min)と
            tangent(max)はself.align_edgesが真の場合に利用する。
            fallbackはVector((0, 0, 0))とする。
        :rtype: dict[BMVert, list[Vector]]
        """
        WIRE = self.WIRE
        BORDER = self.BORDER

        loop_tris = self.loop_tris
        vert_dict = loop_tris.vert_dict()

        vert_tangents = {}  # eve: Vector

        for eve in loop_tris.bm.verts:
            if not loop_tris.vflags[eve] & BORDER:
                continue

            # eveに接続する二頂点(vert_next, vert_prev)を求める
            eve_next, eve_prev = [eed.other_vert(eve) for eed in eve.link_edges if loop_tris.eflags[eed] & BORDER]

            # tangent (used when self.align_edges is False)
            tris = []
            for tri in vert_dict[eve]:
                efa = tri[0].face
                if not efa.hide:
                    # if not self.use_outside_calculation and efa.select or \
                    #    self.use_outside_calculation and not efa.select:
                    #     tris.append(tri)
                    if (
                        self.tangent_calculation in ("selected", "individual")
                        and efa.select
                        or self.tangent_calculation == "deselected"
                        and not efa.select
                    ):
                        tris.append(tri)
            tangent = LoopTris.vert_tangent(eve, eve_prev, eve_next, tris, fallback=Vector((0, 0, 0)))

            # tangent_min, tangent_max (used when self.align_edges is True)
            edges = []
            for eed in eve.link_edges:
                if eed.hide or loop_tris.eflags[eed] & (WIRE | BORDER):
                    continue
                # if not self.use_outside_calculation and eed.select or \
                #    self.use_outside_calculation and not eed.select:
                #     edges.append(eed)
                if (
                    self.tangent_calculation in ("selected", "individual")
                    and eed.select
                    or self.tangent_calculation == "deselected"
                    and not eed.select
                ):
                    edges.append(eed)
            tangent_min_max = []
            if len(edges) == 1:
                eed = edges[0]
                vec = eed.other_vert(eve).co - eve.co
                if vec.length > 0:
                    vec.normalize()
                    vec1 = eve_prev.co - eve.co
                    if vec1.length > 0:
                        vec1.normalize()
                        f1 = vec1.cross(vec).length
                        if f1 > EPS:
                            tangent_min_max.append(vec / f1)
                    vec2 = eve_next.co - eve.co
                    if vec2.length > 0:
                        vec2.normalize()
                        f2 = vec2.cross(vec).length
                        if f2 > EPS:
                            tangent_min_max.append(vec / f2)
            tangent_min_max.sort(key=lambda v: v.length)

            if len(tangent_min_max) == 0:
                tangents = [tangent] * 3
            elif len(tangent_min_max) == 1:
                tangents = [tangent] + tangent_min_max * 2
            else:
                tangents = [tangent] + tangent_min_max
            vert_tangents[eve] = tangents

        return vert_tangents
    def init(self, context):
        if self.use_world_coords:
            if self.init_called[1]:
                return
        else:
            if self.init_called[0]:
                return

        bm = vabm.from_object(
            context.active_object,
            apply_modifiers=self.use_mirror_modifiers,
            settings="PREVIEW",
            modifier_types={"MIRROR"},
            layer_name="original",
            add_faces_layers=True,
        )
        vabm.LoopTris.index_update(bm)
        if self.use_world_coords:
            bm.transform(context.active_object.matrix_world)
            bm.normal_update()  # 必要か?

        # LoopTris。要素の変更は無いのでキャッシュを有効にする
        loop_tris = LoopTris(bm)
        loop_tris.bm = bm
        loop_tris.vert_verts = vabm.vert_verts_dict(bm)
        memo = loop_tris.memoize
        memo.read = memo.write = True
        loop_tris.correct()

        # 編集中のbmeshの頂点インデックスから、modifier適用後のbmeshの頂点を
        # 参照する
        # vert用
        loop_tris.derived_vert_from_original_index = d = {}
        layer = bm.verts.layers.int["original"]
        indices = set()
        for eve in bm.verts:
            i = eve[layer]
            if i != -1 and i not in indices:
                d[i] = eve
                indices.add(i)
        # face用
        loop_tris.derived_face_from_original_index = d = {}
        layer = bm.faces.layers.int["original"]
        indices = set()
        for efa in bm.faces:
            i = efa[layer]
            if i != -1 and i not in indices:
                d[i] = efa
                indices.add(i)

        # --- Shift Outline ---
        loop_tris.eflags = eflags = {}
        for eed in bm.edges:
            flag = 0
            selected = deselected = 0
            for efa in eed.link_faces:
                if not efa.hide:
                    if efa.select:
                        selected += 1
                    else:
                        deselected += 1
            if eed.select and not eed.hide:
                if selected == 0 and deselected <= 2:
                    flag = self.WIRE
                elif selected == 1 and deselected <= 1:
                    flag = self.BORDER
            eflags[eed] = flag

        loop_tris.vflags = vflags = {}
        for eve in bm.verts:
            flag = 0
            wire_num = border_num = 0
            for eed in eve.link_edges:
                f = eflags[eed]
                if f & self.WIRE:
                    wire_num += 1
                elif f & self.BORDER:
                    border_num += 1
            if 1 <= wire_num <= 2 and border_num == 0:
                flag = self.WIRE
            elif wire_num == 0 and border_num == 2:
                flag = self.BORDER
            vflags[eve] = flag

        # --- Solidify ---
        # 頂点のhideとtriの面積により、法線計算に使えるか否かのフラグを付ける
        for eve in bm.verts:
            eve.tag = not eve.hide
        for tri in loop_tris:
            tri.tag = not tri[0].face.hide and tri.area > EPS

        if self.use_world_coords:
            self.init_called[1] = True
            self._loop_tris_world = loop_tris
        else:
            self._loop_tris = loop_tris
            self.init_called[0] = True