LoginSignup
7
7

More than 1 year has passed since last update.

正多面体のデータを作る

Last updated at Posted at 2019-12-26

正多面体のデータが欲しい。簡単に作れそうだけど、作る方法を考えると、簡単ではなさそう。プログラムを作ってはみたものの泥縄感が漂う。

生成方法

頂点が半径1の球の上にある正多面体のデータを作ります。

正多面体($M$)に対するテーブルは「1面の角数($N$)」と「頂点に接する面の数($F$)」のみです。

面の法線を求める

最初の頂点を $\left( 0,0,1 \right)$ として、接する面の辺の生成を目指します。

次の頂点 $\left( \sin{\theta}, 0, \cos{\theta} \right)$ を求めて、x-y 平面を「接する面の数」分割するように回転します。

すると、3番目は $\left( \sin{\theta} \cos{\phi}, \sin{\theta} \sin{\phi}, \cos{\theta} \right)$ になります。

$\phi$ は「接する面の数($F$)」から求まります。

$\theta$ は3つの頂点から求められますが、頂点を作る前に求めておかなくてはならないので


\begin{eqnarray}
\phi & = & \frac{2\pi}{F} \\
P_1 & = & (0, 0, 1) \\
P_2 & = & (\sin{\theta}, 0, \cos{\theta}) \\
P_3 & = & (\sin{\theta} \cos{\phi}, \sin{\theta} \sin{\phi}, \cos{\theta}) \\
L_1 & = & P_2 - P_1 \\
L_2 & = & P_3 - P_1 \\
\frac{L_1 \cdot L_2}{|L_1||L_2|} & = & \cos{ \frac{ \pi \left( N-2 \right) }{N} } \\
\cos{\theta} & = & \left( \cos^2{ \frac{\pi}{F} } - \cos{ \frac{ \pi \left( N-2 \right) }{N} } \right) \csc^2{ \frac{\pi}{F} } \\
 & = & 2 \cos^2{ \frac{\pi}{N} } \csc^2{ \frac{\pi}{F} } - 1 \\
\end{eqnarray}

として、$N,F$ から $\cos{\theta}$ を求めます。3つの頂点を求めたら、最初の「面の法線」が外積


N_1 = \frac{L_1 \times L_2}{ \left| L_1 \times L_2 \right|}

で求まるので、この法線を x-y 平面で一周分を角度 $\phi$ 毎に回転すると $F$ 個の「面の法線」が求まります。

正多面体の中心から面までの距離は、最初の頂点 $P_1$ と最初の面の法線 $N_1$ の内積になるので


\begin{eqnarray}
P_1 & = & \left( 0, 0, 1 \right) \\
N_1 & = & \left( n_x\ , n_y\ , n_z \right) \\
n_z & = & P_1 \cdot N_1 = D \\
\end{eqnarray}

として求めます。法線に対して $\left( n_z = D \right)$ の値を使うと面の式にできます。

追記: $D$ を変数のまま求めたところ


D = \cot{ \frac{\pi}{F} } \cot{ \frac{\pi}{N} }

となりました。

全ての面の法線を求める

法線は3つ以上求まっているので、隣接する面の法線 $N_1,N_2$ と、その隣の面の法線 $N_3$ の関係は


\begin{eqnarray}
n_x & = & N_1 \\
n_y & = & \frac{ n_x \times N_2 }{ \left| n_x \times N_2 \right| } \\
n_z & = & \frac{ n_x \times n_y }{ \left| n_x \times n_y \right| } \\
X_{cos} & = & n_x \cdot N_3 \\
Y_{cos} & = & n_y \cdot N_3 \\
Z_{cos} & = & n_z \cdot N_3 \\
\end{eqnarray}

とすることができます。これで、隣接する面の法線 $N_1,N_2$ から新たな法線 $N_3$ が


\begin{eqnarray}
n_x & = & N_1 \\
n_y & = & \frac{ n_x \times N_2 }{ \left| n_x \times N_2 \right| } \\
n_z & = & \frac{ n_x \times n_y }{ \left| n_x \times n_y \right| } \\
N_3 & = & X_{cos}\ n_x + Y_{cos}\ n_y + Z_{cos}\ n_z \\
\end{eqnarray}

で求められます。

2つの法線の総当たりで、新たな法線を求め、重複を排除して、増えなくなったら目的達成です。

頂点を求める

隣接する面の法線 $N_1,N_2$ と、正多面体の中心(原点)から面までの距離 $D$ で作られる平面の交線が「正多面体の辺」を通ります。この交線と半径 $1$ の球の交点が求める頂点です。

交線の方向は2つの法線の外積


L_V = \frac{ N_1 \times N_2 }{ \left| N_1 \times N_2 \right| }

で求まります。交線の基点を「辺の中心」にしたいので、2つの法線の中間を通る直線 $L_C$ と、面の交点 $L_P$ を


\begin{eqnarray}
L_C & = & \frac{ N_1 + N_2 }{ \left| N_1 + N_2 \right| } \\
\cos{\theta_L} & = & L_C \cdot N_1 = L_C \cdot N_2 \\
L_P & = & \frac{D}{\cos{\theta_L}} L_C
\end{eqnarray}

で求めます。$\left| L_P \right|$ は原点から頂点までの距離 $1$ に対して


\cos{\theta_P} = \left| L_P \right|

と表せるので、$L_P$ から頂点までの距離は


L_D = \sin{\theta_P} = \sqrt{1 - \cos^2{\theta_P}} = \sqrt{1 - \left( L_P \cdot L_P \right) }

となります。これは「面の法線を求める」にある $\left| L_1 \right|$ の半分だから


L_D = \frac{ \left| L_1 \right| }{2}

とすることもできます。(プログラムは前者のままです)

求める頂点は、辺の中心から等間隔にあるので


V = L_P \pm L_D L_V

になります。

これを「全ての法線」と同様に、2つの法線の総当たりで、辺と頂点を求めます。

あとは、データを整えて完了です。

プログラムと出力結果

正多面体 データ生成 Python プログラム

import math

flag_debug = False
flag_verbose = False
flag_rotate = False

paren_c = ('{', '}')
paren_vec = ('(', ')')
paren_out = ('(', ')')
paren_list = ('(', ')')

# 正多面体のデータ
# 面数: (面の角数, 頂点の接面数)
RP_TAB = {
    +4: (3, 3),
    +6: (4, 3),
    +8: (3, 4),
    12: (5, 3),
    20: (3, 5),
}

FP_THR = 1.0 / 1024  # 判定時の演算誤差の許容範囲

def cos_sin(r): return (math.cos(r), math.sin(r))

def vec_dump(v): return (paren_vec[0] + (' %+8.6f, %+8.6f, %+8.6f ' % tuple(v)) + paren_vec[1])
def vec_add(a, b): return (a[0] + b[0], a[1] + b[1], a[2] + b[2])
def vec_sub(a, b): return (a[0] - b[0], a[1] - b[1], a[2] - b[2])
def vec_mul(a, b): return (a[0] * b,    a[1] * b,    a[2] * b)

def vec_inner(a, b): # 内積
    return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])

def vec_cross(a, b): # 外積
    c1 = a[1] * b[2] - a[2] * b[1]
    c2 = a[2] * b[0] - a[0] * b[2]
    c3 = a[0] * b[1] - a[1] * b[0]
    return (c1, c2, c3)

def vec_cross_normalize(a, b): # 外積と正規化
    return vec_normalize(vec_cross(a, b))

def vec_normalize(a): # 正規化
    return vec_mul(a, 1.0 / math.sqrt(vec_inner(a, a)))

# X-Y 平面で回転
def vec_rot_xy(v, r):
    c, s = cos_sin(r)
    x = v[0] * c - v[1] * s
    y = v[0] * s + v[1] * c
    return (x, y, v[2])

# ベクトル データの追加 (重複を排除する)
def vec_append(l, v):
    r = len(l)
    for n in range(r):
        c = vec_inner(v, l[n])
        if c >= (1.0 - FP_THR):
            return n
        continue
    l.append(v)
    return r

# 正多面体データの作成
def make(F):          # F = 面の数
    P = RP_TAB[F][0]  # P = 面の角数
    K = RP_TAB[F][1]  # K = 頂点の接面数
    E = F * P / 2     # E = 辺数
    V = E - F + 2     # V = 頂点数

    if flag_verbose:
        print('面数 : %d' % F)
        print('辺数 : %d' % E)
        print('頂点数: %d' % V)
        pass

    # 頂点の接面数で一周
    rK1 = math.pi     / K   # rK1 =  π / K
    rK2 = math.pi * 2 / K   # rK2 = 2π / K
    cK1, sK1 = cos_sin(rK1)
    cK2, sK2 = cos_sin(rK2)

    # 多角形に関する要素
    rP = math.pi * (P - 2) / P  # rP = π(P-2) / P
    cP, sP = cos_sin(rP)

    # 辺と中心角に関する要素
    cR = (cK1 * cK1 - cP) / (sK1 * sK1)
    sR = math.sqrt(1 - cR * cR)

    # 3つの面の法線を求める
    p1 = (0, 0, 1)
    p2 = (sR, 0, cR)
    p3 = (sR * cK2, sR * sK2, cR)
    l1 = vec_sub(p2, p1)
    l2 = vec_sub(p3, p1)
    n0 = vec_cross_normalize(l1, l2)
    n1 = vec_rot_xy(n0, rK2 * 1)
    n2 = vec_rot_xy(n0, rK2 * 2)

    cD = n0[2]  # cD = 中心から平面までの距離
    sD = math.sqrt(1 - cD * cD)

    # 隣接する面の角度要素を求める
    ny = vec_cross_normalize(n0, n1)
    nz = vec_cross_normalize(n0, ny)
    N_cos = vec_inner(n0, n1)
    X_cos = vec_inner(n0, n2)
    Y_cos = vec_inner(ny, n2)
    Z_cos = vec_inner(nz, n2)

    # 正多面体の向きを修正する
    if P != 3 and flag_rotate:
        n0 = (0, 0, 1)
        ny = (cP, -sP, 0)
        nz = (sP,  cP, 0)
        ax = vec_mul(n0, X_cos)
        ay = vec_mul(ny, Y_cos)
        az = vec_mul(nz, Z_cos)
        n1 = vec_add(vec_add(ax, ay), az)
        pass

    # 全ての面の法線を求める
    nl = [n0, n1]
    loop = True
    while loop:
        CF = len(nl)
        for s in range(CF-1):
            for e in range(s+1,CF):
                n0 = nl[s]
                n1 = nl[e]

                # n0 と n1 が隣接する面か?
                nc = vec_inner(n0, n1)
                if abs(N_cos - nc) >= FP_THR:
                    continue

                # n0 から n1 方向の隣接面を追加
                ny = vec_cross_normalize(n0, n1)
                nz = vec_cross_normalize(n0, ny)
                ax = vec_mul(n0, X_cos)
                ay = vec_mul(ny, Y_cos)
                az = vec_mul(nz, Z_cos)
                na = vec_add(vec_add(ax, ay), az)
                vec_append(nl, na)
                continue
            continue
        loop = (CF != len(nl)) # 増えなくなったら終わり
        continue

    # 全ての辺と頂点を求める
    CF = len(nl)
    vl = []
    fl = {}
    for n in range(CF): fl[n] = []
    for s in range(CF):
        for e in range(s+1, CF):
            n0 = nl[s]
            n1 = nl[e]

            # n0 と n1 が隣接する面か?
            nc = vec_inner(n0, n1)
            if abs(N_cos - nc) >= FP_THR: continue

            # n0 と n1 の交線を求める(辺の中心を通る)
            lc = vec_normalize(vec_add(n0, n1))
            lv = vec_cross_normalize(n0, n1)
            lp = vec_mul(lc, cD / vec_inner(n0, lc))

            # 交線と半径1の球の交点を求める
            t0 = math.sqrt(1 - vec_inner(lp, lp))
            q1 = vec_add(vec_mul(lv, -t0), lp)
            q2 = vec_add(vec_mul(lv, +t0), lp)

            # 頂点と辺のデータを追加
            i1 = vec_append(vl, q1)
            i2 = vec_append(vl, q2)
            fl[s].append((i1, i2))
            fl[e].append((i1, i2))
            continue
        continue

    # データの整理
    rl = []
    el = {}
    for f in range(len(fl)):
        vd = fl[f]

        # ワイヤー フレーム向け辺データ
        for e in vd: el[e] = None

        # バラバラの辺データを連続にする(ポリゴン化)
        vm = {}
        s, e = vd[0]
        vm[s] = e
        il = vd[1:]
        while len(il):
            for n in range(len(il)):
                p, q = il[n]
                if e == p:
                    vm[e] = q
                    e = q
                elif e == q:
                    vm[e] = p
                    e = p
                else:
                    continue
                del il[n]
                break
            continue

        s, e = vd[0]
        il = [s]
        while s != e:
            il.append(e)
            e = vm[e]
            continue

        # ポリゴンの法線を修正
        nv = nl[f]
        p0 = vl[il[0]]
        p1 = vl[il[1]]
        p2 = vl[il[2]]
        v1 = vec_sub(p1, p0)
        v2 = vec_sub(p2, p1)
        pn = vec_cross(v1, v2)
        if vec_inner(nv, pn) < 0: il.reverse()

        rl.append((nv, il))
        continue

    return (vl, rl, el.keys())

# メイン関数
def main(F):
    vl, fl, el = make(F)

    # 頂点データの出力
    m = ('VERTEX[%d] = ' % len(vl)) + paren_out[0] + '\n'
    for n in range(len(vl)):
        m = m + ('  %s,' % vec_dump(vl[n]))
        if not args.uncomment: m = m + ('  #%d' % n)
        m = m + '\n'
        continue
    m = m + paren_out[1]
    print(m)

    # 法線データの出力
    if args.normal:
        m = ('NORMAL[%d] = ' % len(fl)) + paren_out[0] + '\n'
        for n in range(len(fl)):
            m = m + ('  %s,' % vec_dump(fl[n][0]))
            if not args.uncomment: m = m + ('  #%d' % n)
            m = m + '\n'
            continue
        m = m + paren_out[1]
        print(m)
        pass

    # 面データの出力 (法線, 頂点リスト)
    m = ('FACET[%d] = ' % len(fl)) + paren_out[0] + '\n'
    for n in range(len(fl)):
        if args.normal: m = m + ' '
        else: m = m + '  ' + vec_dump(fl[n][0]) + ','
        m = m + ' ' + paren_list[0]
        s = ''
        for i in fl[n][1]:
            m = m + ('%s %2d' % (s, i))
            s = ','
            continue
        m = m + ' ' + paren_list[1] + ','
        if not args.uncomment: m = m + ('  #%d' % n)
        m = m + '\n'
        continue
    m = m + paren_out[1]
    print(m)

    # 辺データの出力
    el = sorted(el)
    m = ('EDGE[%d] = ' % len(el)) + paren_out[0]
    for n in range(len(el)):
        if ((n & 3) == 0): m = m + '\n '
        m = m + (' %s %2d, %2d %s,' % (paren_list[0], el[n][0], el[n][1], paren_list[1]))
        continue
    m = m + '\n' + paren_out[1]
    print(m)

    return

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('N', nargs='+', type=int, help='面数={4|6|8|12|20}')
    parser.add_argument('-d', '--debug', action='store_true', help='デバッグ用')
    parser.add_argument('-v', '--verbose', action='store_true', help='冗長出力')
    parser.add_argument('-r', '--rotate', action='store_true', help='6,12面体の方向を修正')
    parser.add_argument('-c', '--cparen', action='store_true', help='括弧の文字を変更')
    parser.add_argument('-n', '--normal', action='store_true', help='法線データを分離')
    parser.add_argument('-u', '--uncomment', action='store_true', help='インデックスを排除')
    args = parser.parse_args()

    flag_debug = args.debug
    flag_verbose = args.verbose
    flag_rotate = args.rotate

    if args.cparen:
        paren_vec = paren_c
        paren_out = paren_c
        paren_list = paren_c
        pass

    s = '-' * 72
    sep = (len(args.N) > 1)
    for N in args.N:
        if sep: print(s)
        if N in RP_TAB:
            main(N)
        else:
            print('N=%d : 無効な面数です' % N)
            parser.print_help()
            pass
        continue
    if sep: print(s)
    pass

# 無駄な pass, continue, return は Emacs のインデント対策

出力結果: 正四面体

面数 : 4
辺数 : 6
頂点数: 4
VERTEX[4] = (
  ( +0.000000, +0.000000, +1.000000 ),  #0
  ( +0.942809, +0.000000, -0.333333 ),  #1
  ( -0.471405, +0.816497, -0.333333 ),  #2
  ( -0.471405, -0.816497, -0.333333 ),  #3
)
FACET[4] = (
  ( +0.471405, +0.816497, +0.333333 ), (  2,  0,  1 ),  #0
  ( -0.942809, +0.000000, +0.333333 ), (  3,  0,  2 ),  #1
  ( +0.471405, -0.816497, +0.333333 ), (  3,  1,  0 ),  #2
  ( +0.000000, -0.000000, -1.000000 ), (  3,  2,  1 ),  #3
)
EDGE[6] = (
  (  0,  1 ), (  1,  2 ), (  2,  0 ), (  2,  3 ),
  (  3,  0 ), (  3,  1 ),
)

出力結果: 正六面体

面数 : 6
辺数 : 12
頂点数: 8
VERTEX[8] = (
  ( +0.000000, +0.000000, +1.000000 ),  #0
  ( +0.942809, +0.000000, +0.333333 ),  #1
  ( -0.471405, +0.816497, +0.333333 ),  #2
  ( +0.471405, +0.816497, -0.333333 ),  #3
  ( -0.471405, -0.816497, +0.333333 ),  #4
  ( -0.942809, +0.000000, -0.333333 ),  #5
  ( +0.471405, -0.816497, -0.333333 ),  #6
  ( +0.000000, +0.000000, -1.000000 ),  #7
)
FACET[6] = (
  ( +0.408248, +0.707107, +0.577350 ), (  2,  0,  1,  3 ),  #0
  ( -0.816497, +0.000000, +0.577350 ), (  5,  4,  0,  2 ),  #1
  ( +0.408248, -0.707107, +0.577350 ), (  4,  6,  1,  0 ),  #2
  ( +0.816497, -0.000000, -0.577350 ), (  6,  7,  3,  1 ),  #3
  ( -0.408248, +0.707107, -0.577350 ), (  7,  5,  2,  3 ),  #4
  ( -0.408248, -0.707107, -0.577350 ), (  7,  6,  4,  5 ),  #5
)
EDGE[12] = (
  (  0,  1 ), (  1,  3 ), (  2,  0 ), (  2,  5 ),
  (  3,  2 ), (  4,  0 ), (  4,  6 ), (  5,  4 ),
  (  6,  1 ), (  6,  7 ), (  7,  3 ), (  7,  5 ),
)

********* 以下は、空間軸と面の向きが同じ

面数 : 6
辺数 : 12
頂点数: 8
VERTEX[8] = (
  ( -0.577350, -0.577350, +0.577350 ),  #0
  ( +0.577350, -0.577350, +0.577350 ),  #1
  ( +0.577350, +0.577350, +0.577350 ),  #2
  ( -0.577350, +0.577350, +0.577350 ),  #3
  ( +0.577350, -0.577350, -0.577350 ),  #4
  ( -0.577350, -0.577350, -0.577350 ),  #5
  ( +0.577350, +0.577350, -0.577350 ),  #6
  ( -0.577350, +0.577350, -0.577350 ),  #7
)
FACET[6] = (
  ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2,  3 ),  #0
  ( -0.000000, -1.000000, +0.000000 ), (  5,  4,  1,  0 ),  #1
  ( +1.000000, -0.000000, +0.000000 ), (  4,  6,  2,  1 ),  #2
  ( +0.000000, +1.000000, +0.000000 ), (  6,  7,  3,  2 ),  #3
  ( -1.000000, +0.000000, +0.000000 ), (  7,  5,  0,  3 ),  #4
  ( -0.000000, -0.000000, -1.000000 ), (  7,  6,  4,  5 ),  #5
)
EDGE[12] = (
  (  0,  1 ), (  0,  5 ), (  1,  2 ), (  2,  3 ),
  (  3,  0 ), (  4,  1 ), (  4,  6 ), (  5,  4 ),
  (  6,  2 ), (  6,  7 ), (  7,  3 ), (  7,  5 ),
)

出力結果: 正八面体

面数 : 8
辺数 : 12
頂点数: 6
VERTEX[6] = (
  ( +0.000000, +0.000000, +1.000000 ),  #0
  ( +1.000000, +0.000000, +0.000000 ),  #1
  ( +0.000000, +1.000000, +0.000000 ),  #2
  ( -1.000000, +0.000000, +0.000000 ),  #3
  ( -0.000000, -1.000000, +0.000000 ),  #4
  ( +0.000000, -0.000000, -1.000000 ),  #5
)
FACET[8] = (
  ( +0.577350, +0.577350, +0.577350 ), (  2,  0,  1 ),  #0
  ( -0.577350, +0.577350, +0.577350 ), (  3,  0,  2 ),  #1
  ( -0.577350, -0.577350, +0.577350 ), (  4,  0,  3 ),  #2
  ( +0.577350, -0.577350, +0.577350 ), (  4,  1,  0 ),  #3
  ( +0.577350, -0.577350, -0.577350 ), (  5,  1,  4 ),  #4
  ( +0.577350, +0.577350, -0.577350 ), (  5,  2,  1 ),  #5
  ( -0.577350, +0.577350, -0.577350 ), (  5,  3,  2 ),  #6
  ( -0.577350, -0.577350, -0.577350 ), (  5,  4,  3 ),  #7
)
EDGE[12] = (
  (  0,  1 ), (  1,  2 ), (  2,  0 ), (  2,  3 ),
  (  3,  0 ), (  3,  4 ), (  4,  0 ), (  4,  1 ),
  (  4,  5 ), (  5,  1 ), (  5,  2 ), (  5,  3 ),
)

出力結果: 正十二面体

面数 : 12
辺数 : 30
頂点数: 20
VERTEX[20] = (
  ( +0.000000, +0.000000, +1.000000 ),  #0
  ( +0.666667, +0.000000, +0.745356 ),  #1
  ( -0.333333, +0.577350, +0.745356 ),  #2
  ( +0.745356, +0.577350, +0.333333 ),  #3
  ( +0.127322, +0.934172, +0.333333 ),  #4
  ( -0.333333, -0.577350, +0.745356 ),  #5
  ( -0.872678, +0.356822, +0.333333 ),  #6
  ( -0.872678, -0.356822, +0.333333 ),  #7
  ( +0.745356, -0.577350, +0.333333 ),  #8
  ( +0.127322, -0.934172, +0.333333 ),  #9
  ( +0.872678, +0.356822, -0.333333 ),  #10
  ( +0.872678, -0.356822, -0.333333 ),  #11
  ( -0.127322, +0.934172, -0.333333 ),  #12
  ( +0.333333, +0.577350, -0.745356 ),  #13
  ( -0.745356, +0.577350, -0.333333 ),  #14
  ( -0.745356, -0.577350, -0.333333 ),  #15
  ( -0.666667, +0.000000, -0.745356 ),  #16
  ( -0.127322, -0.934172, -0.333333 ),  #17
  ( +0.333333, -0.577350, -0.745356 ),  #18
  ( +0.000000, -0.000000, -1.000000 ),  #19
)
FACET[12] = (
  ( +0.303531, +0.525731, +0.794654 ), (  2,  0,  1,  3,  4 ),  #0
  ( -0.607062, +0.000000, +0.794654 ), (  6,  7,  5,  0,  2 ),  #1
  ( +0.303531, -0.525731, +0.794654 ), (  5,  9,  8,  1,  0 ),  #2
  ( +0.982247, -0.000000, +0.187592 ), (  8, 11, 10,  3,  1 ),  #3
  ( +0.491123, +0.850651, -0.187592 ), ( 10, 13, 12,  4,  3 ),  #4
  ( -0.491123, +0.850651, +0.187592 ), ( 12, 14,  6,  2,  4 ),  #5
  ( -0.982247, +0.000000, -0.187592 ), ( 14, 16, 15,  7,  6 ),  #6
  ( -0.491123, -0.850651, +0.187592 ), ( 15, 17,  9,  5,  7 ),  #7
  ( +0.491123, -0.850651, -0.187592 ), ( 17, 18, 11,  8,  9 ),  #8
  ( +0.607062, -0.000000, -0.794654 ), ( 18, 19, 13, 10, 11 ),  #9
  ( -0.303531, +0.525731, -0.794654 ), ( 19, 16, 14, 12, 13 ),  #10
  ( -0.303531, -0.525731, -0.794654 ), ( 19, 18, 17, 15, 16 ),  #11
)
EDGE[30] = (
  (  0,  1 ), (  1,  3 ), (  2,  0 ), (  2,  6 ),
  (  3,  4 ), (  4,  2 ), (  5,  0 ), (  5,  9 ),
  (  6,  7 ), (  7,  5 ), (  8,  1 ), (  8, 11 ),
  (  9,  8 ), ( 10,  3 ), ( 10, 13 ), ( 11, 10 ),
  ( 12,  4 ), ( 12, 14 ), ( 13, 12 ), ( 14,  6 ),
  ( 14, 16 ), ( 15,  7 ), ( 15, 17 ), ( 16, 15 ),
  ( 17,  9 ), ( 17, 18 ), ( 18, 11 ), ( 18, 19 ),
  ( 19, 13 ), ( 19, 16 ),
)

********* 以下は、Z軸の向きと同じ面がある

面数 : 12
辺数 : 30
頂点数: 20
VERTEX[20] = (
  ( -0.577350, -0.187592, +0.794654 ),  #0
  ( -0.000000, -0.607062, +0.794654 ),  #1
  ( +0.577350, -0.187592, +0.794654 ),  #2
  ( +0.356822, +0.491123, +0.794654 ),  #3
  ( -0.356822, +0.491123, +0.794654 ),  #4
  ( -0.000000, -0.982247, +0.187592 ),  #5
  ( -0.934172, -0.303531, +0.187592 ),  #6
  ( -0.577350, -0.794654, -0.187592 ),  #7
  ( +0.934172, -0.303531, +0.187592 ),  #8
  ( +0.577350, -0.794654, -0.187592 ),  #9
  ( +0.577350, +0.794654, +0.187592 ),  #10
  ( +0.934172, +0.303531, -0.187592 ),  #11
  ( -0.577350, +0.794654, +0.187592 ),  #12
  ( +0.000000, +0.982247, -0.187592 ),  #13
  ( -0.934172, +0.303531, -0.187592 ),  #14
  ( -0.356822, -0.491123, -0.794654 ),  #15
  ( -0.577350, +0.187592, -0.794654 ),  #16
  ( +0.356822, -0.491123, -0.794654 ),  #17
  ( +0.577350, +0.187592, -0.794654 ),  #18
  ( +0.000000, +0.607062, -0.794654 ),  #19
)
FACET[12] = (
  ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2,  3,  4 ),  #0
  ( -0.525731, -0.723607, +0.447214 ), (  6,  7,  5,  1,  0 ),  #1
  ( +0.525731, -0.723607, +0.447214 ), (  5,  9,  8,  2,  1 ),  #2
  ( +0.850651, +0.276393, +0.447214 ), (  8, 11, 10,  3,  2 ),  #3
  ( +0.000000, +0.894427, +0.447214 ), ( 10, 13, 12,  4,  3 ),  #4
  ( -0.850651, +0.276393, +0.447214 ), ( 12, 14,  6,  0,  4 ),  #5
  ( -0.850651, -0.276393, -0.447214 ), ( 14, 16, 15,  7,  6 ),  #6
  ( -0.000000, -0.894427, -0.447214 ), ( 15, 17,  9,  5,  7 ),  #7
  ( +0.850651, -0.276393, -0.447214 ), ( 17, 18, 11,  8,  9 ),  #8
  ( +0.525731, +0.723607, -0.447214 ), ( 18, 19, 13, 10, 11 ),  #9
  ( -0.525731, +0.723607, -0.447214 ), ( 19, 16, 14, 12, 13 ),  #10
  ( -0.000000, -0.000000, -1.000000 ), ( 19, 18, 17, 15, 16 ),  #11
)
EDGE[30] = (
  (  0,  1 ), (  0,  6 ), (  1,  2 ), (  2,  3 ),
  (  3,  4 ), (  4,  0 ), (  5,  1 ), (  5,  9 ),
  (  6,  7 ), (  7,  5 ), (  8,  2 ), (  8, 11 ),
  (  9,  8 ), ( 10,  3 ), ( 10, 13 ), ( 11, 10 ),
  ( 12,  4 ), ( 12, 14 ), ( 13, 12 ), ( 14,  6 ),
  ( 14, 16 ), ( 15,  7 ), ( 15, 17 ), ( 16, 15 ),
  ( 17,  9 ), ( 17, 18 ), ( 18, 11 ), ( 18, 19 ),
  ( 19, 13 ), ( 19, 16 ),
)

出力結果: 正二十面体

面数 : 20
辺数 : 30
頂点数: 12
VERTEX[12] = (
  ( +0.000000, +0.000000, +1.000000 ),  #0
  ( +0.894427, +0.000000, +0.447214 ),  #1
  ( +0.276393, +0.850651, +0.447214 ),  #2
  ( -0.723607, +0.525731, +0.447214 ),  #3
  ( -0.723607, -0.525731, +0.447214 ),  #4
  ( +0.276393, -0.850651, +0.447214 ),  #5
  ( +0.723607, -0.525731, -0.447214 ),  #6
  ( +0.723607, +0.525731, -0.447214 ),  #7
  ( -0.276393, +0.850651, -0.447214 ),  #8
  ( -0.894427, -0.000000, -0.447214 ),  #9
  ( -0.276393, -0.850651, -0.447214 ),  #10
  ( -0.000000, +0.000000, -1.000000 ),  #11
)
FACET[20] = (
  ( +0.491123, +0.356822, +0.794654 ), (  2,  0,  1 ),  #0
  ( -0.187592, +0.577350, +0.794654 ), (  3,  0,  2 ),  #1
  ( -0.607062, +0.000000, +0.794654 ), (  4,  0,  3 ),  #2
  ( -0.187592, -0.577350, +0.794654 ), (  5,  0,  4 ),  #3
  ( +0.491123, -0.356822, +0.794654 ), (  5,  1,  0 ),  #4
  ( +0.794654, -0.577350, +0.187592 ), (  6,  1,  5 ),  #5
  ( +0.982247, -0.000000, -0.187592 ), (  7,  1,  6 ),  #6
  ( +0.794654, +0.577350, +0.187592 ), (  7,  2,  1 ),  #7
  ( +0.303531, +0.934172, -0.187592 ), (  8,  2,  7 ),  #8
  ( -0.303531, +0.934172, +0.187592 ), (  8,  3,  2 ),  #9
  ( -0.794654, +0.577350, -0.187592 ), (  9,  3,  8 ),  #10
  ( -0.982247, -0.000000, +0.187592 ), (  9,  4,  3 ),  #11
  ( -0.794654, -0.577350, -0.187592 ), ( 10,  4,  9 ),  #12
  ( -0.303531, -0.934172, +0.187592 ), ( 10,  5,  4 ),  #13
  ( +0.303531, -0.934172, -0.187592 ), ( 10,  6,  5 ),  #14
  ( +0.187592, -0.577350, -0.794654 ), ( 11,  6, 10 ),  #15
  ( +0.607062, +0.000000, -0.794654 ), ( 11,  7,  6 ),  #16
  ( +0.187592, +0.577350, -0.794654 ), ( 11,  8,  7 ),  #17
  ( -0.491123, +0.356822, -0.794654 ), ( 11,  9,  8 ),  #18
  ( -0.491123, -0.356822, -0.794654 ), ( 11, 10,  9 ),  #19
)
EDGE[30] = (
  (  0,  1 ), (  1,  2 ), (  2,  0 ), (  2,  3 ),
  (  3,  0 ), (  3,  4 ), (  4,  0 ), (  4,  5 ),
  (  5,  0 ), (  5,  1 ), (  5,  6 ), (  6,  1 ),
  (  6,  7 ), (  7,  1 ), (  7,  2 ), (  7,  8 ),
  (  8,  2 ), (  8,  3 ), (  8,  9 ), (  9,  3 ),
  (  9,  4 ), (  9, 10 ), ( 10,  4 ), ( 10,  5 ),
  ( 10,  6 ), ( 10, 11 ), ( 11,  6 ), ( 11,  7 ),
  ( 11,  8 ), ( 11,  9 ),
)

新しい方法で生成

正多面体のデータを作る[改] (HTML+JavaScript版) にある方法で生成します。

正多面体 データ生成 Python3 プログラム ([改]方式)
#!/usr/bin/env python3

import math
import numbers
import operator

####
# 正多面体のデータ生成
####


class RegularPolyhedron:
    INDEX = {4: 1, 6: 2, 8: 3, 12: 4, 20: 5}
    POLYHEDRON = (4, 4, 6, 8, 12, 20)
    POLYGON = (3, 3, 4, 3, 5, 3)

    # 3ベクトルから残りのベクトルを求める.
    @staticmethod
    def create_vector_list(p1, p2, p3):
        v1 = p1.normalize()
        v2 = (p1 * p2).normalize()
        v3 = (v1 * v2).normalize()
        xcos, ycos, zcos = [v.dot(p3) for v in (v1, v2, v3)]
        pcos = p1.dot(p2)
        vecs = [p1, p2, p3]

        def vec_add(q1, q2):
            x = q1.normalize()
            y = (q1 * q2).normalize()
            z = (x * y).normalize()
            v = (x * xcos + y * ycos + z * zcos).normalize()
            if len(tuple(filter((lambda p: v.neareq(p)), vecs))) == 0:
                vecs.append(v)

        last_vlen = 0
        new_vlen = len(vecs)
        while last_vlen != new_vlen:
            for q1 in vecs[last_vlen:new_vlen]:
                for q2 in vecs:
                    if q1.doteq(q2, pcos):
                        vec_add(q1, q2)
                        vec_add(q2, q1)
            last_vlen = new_vlen
            new_vlen = len(vecs)

        return tuple([v.fixfp() for v in sorted(vecs, key=operator.itemgetter(2, 1, 0), reverse=True)])

    # ポリゴン情報の一覧を作成.
    @staticmethod
    def create_polygon_list(vertex, normal, pcos, ncos):
        vlen = len(vertex)
        r = []
        for n in normal:
            pvl = tuple(filter((lambda vi: n.doteq(vertex[vi], ncos)), range(vlen)))
            pvlen = len(pvl)
            ll = []
            for ci in range(pvlen):
                pc = vertex[pvl[ci]]
                pi, ni = tuple(filter(lambda qi: pc.doteq(vertex[pvl[qi]], pcos), range(pvlen)))
                pp, pn = vertex[pvl[pi]], vertex[pvl[ni]]
                pi, ni = (pi, ni) if n.neareq(((pc - pp) * (pn - pc)).normalize()) else (ni, pi)
                ll.append([ci, ni])
            ci, ni = ll[0]
            vl = [pvl[ci]]
            while ni != 0:
                vl.append(pvl[ni])
                ci, ni = ll[ni]
            r.append(tuple(vl))
        return tuple(r)

    # 辺情報の一覧を作成.
    @staticmethod
    def create_edge_list(polygon):
        r = []
        for poly in polygon:
            pp = poly[-1]
            for pn in poly:
                e = (pp, pn) if pp < pn else (pn, pp)
                if e not in r:
                    r.append(e)
                pp = pn
        return tuple(sorted(r))

    # コンストラクタ.
    def __init__(self, M):
        S = RegularPolyhedron
        self.M = M
        self.I = S.INDEX[M]
        self.V = S.POLYHEDRON[self.I ^ 1]
        self.F = S.POLYGON[self.I ^ 1]
        self.N = S.POLYGON[self.I]

        PPF = math.pi / self.F
        PPN = math.pi / self.N

        # 最初の3頂点を求める.
        rotXY = 2 * PPF
        cosXY = math.cos(rotXY)
        sinXY = math.sin(rotXY)
        cosZX = 2 * math.pow(math.cos(PPN) / math.sin(PPF), 2) - 1
        sinZX = math.sqrt(1 - cosZX * cosZX)

        p1 = Vector3(0, 0, 1)
        p2 = Vector3(sinZX, 0, cosZX)
        p3 = Vector3(sinZX * cosXY, sinZX * sinXY, cosZX)

        # 最初の3法線を求める.
        rm = Matrix33(cosXY, -sinXY, 0,
                      sinXY,  cosXY, 0,
                      +   0,      0, 1)
        n1 = ((p1 - p3) * (p2 - p1)).normalize()
        n2 = (rm * n1).normalize()
        n3 = (rm * n2).normalize()

        # 頂点と法線の一覧を作成する.
        self.main_vertex = S.create_vector_list(p1, p2, p3)
        self.main_normal = S.create_vector_list(n1, n2, n3)
        self.dual_vertex = self.main_normal
        self.dual_normal = self.main_vertex
        self.vertex = self.main_vertex
        self.normal = self.main_normal

        # 正多面体と対の両方の多角形データを作成する.
        self.main_polygon = S.create_polygon_list(self.main_vertex, self.main_normal, p1.dot(p2), p1.dot(n1))
        self.dual_polygon = S.create_polygon_list(self.dual_vertex, self.dual_normal, n1.dot(n2), p1.dot(n1))
        self.polygon = self.main_polygon

        # 正多面体と対の両方の辺データを作成する.
        self.main_edge = S.create_edge_list(self.main_polygon)
        self.dual_edge = S.create_edge_list(self.dual_polygon)
        self.edge = self.main_edge


####
# Vector3
####

class Vector3(numbers.Integral):
    MESSAGE_FORMAT = '(%+.6e, %+.6e, %+.6e)'

    def __init__(self, *args):
        if len(args) == 3:
            self.value = list(args)
            return
        if len(args) == 0:
            self.value = [0, 0, 0]
            return
        if len(args) == 1:
            self.value = args[0]
            return
        raise TypeError

    def __int__(self): raise NotImplemented
    def __repr__(self): return self.__str__()
    def __str__(self): return (Vector3.MESSAGE_FORMAT % tuple(self.value))

    def __bool__(self): return (sum(self.value) != 0)

    def __eq__(self, rhs):
        if type(rhs) is Vector3:
            return (self.value == rhs.value)
        return False

    def __lt__(self, rhs): raise NotImplemented
    def __le__(self, rhs): raise NotImplemented

    def __neg__(self):
        x, y, z = self.value
        return Vector3(-x, -y, -z)

    def __pos__(self): return Vector3(self)
    def __invert__(self): raise NotImplemented

    def __add__(self, rhs):
        if type(rhs) is Vector3:
            x1, y1, z1 = self.value
            x2, y2, z2 = rhs.value
            return Vector3(x1 + x2, y1 + y2, z1 + z2)
        raise NotImplemented

    def __sub__(self, rhs):
        if type(rhs) is Vector3:
            x1, y1, z1 = self.value
            x2, y2, z2 = rhs.value
            return Vector3(x1 - x2, y1 - y2, z1 - z2)
        raise NotImplemented

    def __mul__(self, rhs):
        x1, y1, z1 = self.value
        if type(rhs) in (int, float):
            return Vector3(x1 * rhs, y1 * rhs, z1 * rhs)
        if type(rhs) is Vector3:
            x2, y2, z2 = rhs.value
            return Vector3(y1 * z2 - z1 * y2,
                           z1 * x2 - x1 * z2,
                           x1 * y2 - y1 * x2)
        if type(rhs) is Matrix33:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = rhs.value
            return Vector3(x1 * m11 + y1 * m21 + z1 * m31,
                           x1 * m12 + y1 * m22 + z1 * m32,
                           x1 * m13 + y1 * m23 + z1 * m33)
        raise NotImplemented

    def __pow__(self, rhs): raise NotImplemented

    def __divmod__(self, rhs):
        if type(rhs) in (int, float):
            return [self.__truediv__(rhs), self.__mod__(rhs)]
        raise NotImplemented

    def __truediv__(self, rhs):
        if type(rhs) in (int, float):
            x, y, z = self.value
            return Vector3(x / rhs, y / rhs, z / rhs)
        raise NotImplemented

    def __floordiv__(self, rhs):
        if type(rhs) in (int, float):
            x, y, z = self.value
            return Vector3(math.floor(x / rhs),
                           math.floor(y / rhs),
                           math.floor(z / rhs))
        raise NotImplemented

    def __mod__(self, rhs):
        if type(rhs) in (int, float):
            x, y, z = self.value
            return Vector3(x % rhs, y % rhs, z % rhs)
        raise NotImplemented

    # 内積とする.
    def __and__(self, rhs):
        if type(rhs) is Vector3:
            return self.dot(rhs)
        raise NotImplemented

    def __xor__(self, rhs): raise NotImplemented
    def __or__(self, rhs): raise NotImplemented

    def __lshift__(self, rhs): raise NotImplemented
    def __rshift__(self, rhs): raise NotImplemented

    def __radd__(self, lhs): raise NotImplemented
    def __rsub__(self, lhs): raise NotImplemented
    def __rmul__(self, lhs): raise NotImplemented
    def __rmod__(self, lhs): raise NotImplemented
    def __rtruediv__(self, lhs): raise NotImplemented
    def __rfloordiv__(self, lhs): raise NotImplemented
    def __rpow__(self, lhs): raise NotImplemented

    def __rand__(self, lhs): raise NotImplemented
    def __rxor__(self, lhs): raise NotImplemented
    def __ror__(self, lhs): raise NotImplemented

    def __rlshift__(self, lhs): raise NotImplemented
    def __rrshift__(self, lhs): raise NotImplemented

    def __iadd__(self, rhs):
        if type(rhs) is Vector3:
            x1, y1, z1 = self.value
            x2, y2, z2 = rhs.value
            self.value = [x1 + x2, y1 + y2, z1 + z2]
            return self
        raise NotImplemented

    def __isub__(self, rhs):
        if type(rhs) is Vector3:
            x1, y1, z1 = self.value
            x2, y2, z2 = rhs.value
            self.value = [x1 - x2, y1 - y2, z1 - z2]
            return self
        raise NotImplemented

    def __imul__(self, rhs):
        x1, y1, z1 = self.value
        if type(rhs) in (int, float):
            self.value = (x1 * rhs, y1 * rhs, z1 * rhs)
            return self
        if type(rhs) is Vector3:
            x2, y2, z2 = rhs.value
            self.value = [y1 * z2 - z1 * y2,
                          z1 * x2 - x1 * z2,
                          x1 * y2 - y1 * x2]
            return self
        if type(rhs) is Matrix33:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = rhs.value
            self.value = [x1 * m11 + y1 * m21 + z1 * m31,
                          x1 * m12 + y1 * m22 + z1 * m32,
                          x1 * m13 + y1 * m23 + z1 * m33]
            return self
        raise NotImplemented

    def __itruediv__(self, rhs):
        if type(rhs) in (int, float):
            x, y, z = self.value
            self.value = [x / rhs, y / rhs, z / rhs]
            return self
        raise NotImplemented

    def __imod__(self, rhs):
        if type(rhs) in (int, float):
            x, y, z = self.value
            self.value = [x % rhs, y % rhs, z % rhs]
            return self
        raise NotImplemented

    def __abs__(self):
        x, y, z = self.value
        return math.sqrt(x * x + y * y + z * z)

    def __ceil__(self):
        x, y, z = self.value
        return Vector3(math.ceil(x), math.ceil(y), math.ceil(z))

    def __floor__(self):
        x, y, z = self.value
        return Vector3(math.floor(x), math.floor(y), math.floor(z))

    def __round__(self):
        x, y, z = self.value
        return Vector3(round(x), round(y), round(z))

    def __trunc__(self):
        x, y, z = self.value
        return Vector3(math.trunc(x), math.trunc(y), math.trunc(z))

    def __getitem__(self, key):
        return self.value[key]

    def __setitem__(self, key, value):
        self.value[key] = value

    ####

    def dot(self, rhs):
        x1, y1, z1 = self.value
        x2, y2, z2 = rhs.value
        return (x1 * x2 + y1 * y2 + z1 * z2)

    def neareq(self, rhs, thr=(1 / (1 << 20))):
        return (abs(1.0 - self.dot(rhs)) < thr)

    def doteq(self, rhs, cos, thr=(1 / (1 << 20))):
        return (abs(cos - self.dot(rhs)) < thr)

    def normalize(self):
        return self.__truediv__(self.__abs__())

    def fixfp(self):
        return Vector3([Vector3.vfixfp(v) for v in self.value])

    @staticmethod
    def vfixfp(v):
        return (round(v) if (abs(v - round(v)) < (1 / (1 << 24))) else v)


####
# Matrix33
####

class Matrix33(numbers.Integral):
    MESSAGE_FORMAT = '((%+.6e, %+.6e, %+.6e), (%+.6e, %+.6e, %+.6e), (%+.6e, %+.6e, %+.6e))'

    def __init__(self, *args):
        if len(args) == 9:
            self.value = list(args)
            return
        if len(args) == 0:
            self.value = [1, 0, 0, 0, 1, 0, 0, 0, 1]
            return
        if len(args) == 1:
            arg = args[0]
            if type(arg) is Matrix33:
                self.value = arg.value * 1
                return
        raise TypeError

    def __int__(self): raise NotImplemented
    def __repr__(self): return self.__str__()
    def __str__(self): return (Matrix33.MESSAGE_FORMAT % tuple(self.value))

    def __bool__(self): return (sum(self.value) != 0)

    def __eq__(self, rhs):
        if type(rhs) is Matrix33:
            return (self.value == rhs.value)
        return False

    def __lt__(self, rhs): raise NotImplemented
    def __le__(self, rhs): raise NotImplemented

    def __neg__(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(-m11, -m12, -m13,
                        -m21, -m22, -m23,
                        -m31, -m32, -m33)

    def __pos__(self): return Matrix33(self)
    def __invert__(self): return self.inverse()

    def __add__(self, rhs):
        if type(rhs) is Matrix33:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            return Matrix33(m11 + r11, m12 + r12, m13 + r13,
                            m21 + r21, m22 + r22, m23 + r23,
                            m31 + r31, m32 + r32, m33 + r33)
        raise NotImplemented

    def __sub__(self, rhs):
        if type(rhs) is Matrix33:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            return Matrix33(m11 - r11, m12 - r12, m13 - r13,
                            m21 - r21, m22 - r22, m23 - r23,
                            m31 - r31, m32 - r32, m33 - r33)
        raise NotImplemented

    def __mul__(self, rhs):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        if type(rhs) in (int, float):
            return Matrix33(m11 * rhs, m12 * rhs, m13 * rhs,
                            m21 * rhs, m22 * rhs, m23 * rhs,
                            m31 * rhs, m32 * rhs, m33 * rhs)
        if type(rhs) is Vector3:
            x, y, z = rhs.value
            return Vector3(m11 * x + m12 * y + m13 * z,
                           m21 * x + m22 * y + m23 * z,
                           m31 * x + m32 * y + m33 * z)
        if type(rhs) is Matrix33:
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            return Matrix33(m11 * r11 + m12 * r21 + m13 * r31,
                            m21 * r11 + m22 * r21 + m23 * r31,
                            m31 * r11 + m32 * r21 + m33 * r31,

                            m11 * r12 + m12 * r22 + m13 * r32,
                            m21 * r12 + m22 * r22 + m23 * r32,
                            m31 * r12 + m32 * r22 + m33 * r32,

                            m11 * r13 + m12 * r23 + m13 * r33,
                            m21 * r13 + m22 * r23 + m23 * r33,
                            m31 * r13 + m32 * r23 + m33 * r33)
        raise NotImplemented

    def __pow__(self, rhs): raise NotImplemented

    def __divmod__(self, rhs):
        if type(rhs) in (int, float):
            return [self.__truediv__(rhs), self.__mod__(rhs)]
        raise NotImplemented

    def __truediv__(self, rhs):
        if type(rhs) in (int, float):
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            return Matrix33(m11 / rhs, m12 / rhs, m13 / rhs,
                            m21 / rhs, m22 / rhs, m23 / rhs,
                            m31 / rhs, m32 / rhs, m33 / rhs)
        raise NotImplemented

    def __floordiv__(self, rhs):
        if type(rhs) in (int, float):
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            return Matrix33(math.floor(m11 / rhs), math.floor(m12 / rhs), math.floor(m13 / rhs),
                            math.floor(m21 / rhs), math.floor(m22 / rhs), math.floor(m23 / rhs),
                            math.floor(m31 / rhs), math.floor(m32 / rhs), math.floor(m33 / rhs))
        raise NotImplemented

    def __mod__(self, rhs):
        if type(rhs) in (int, float):
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            return Matrix33(m11 % rhs, m12 % rhs, m13 % rhs,
                            m21 % rhs, m22 % rhs, m23 % rhs,
                            m31 % rhs, m32 % rhs, m33 % rhs)
        raise NotImplemented

    def __and__(self, rhs): raise NotImplemented
    def __xor__(self, rhs): raise NotImplemented
    def __or__(self, rhs): raise NotImplemented

    def __lshift__(self, rhs): raise NotImplemented
    def __rshift__(self, rhs): raise NotImplemented

    def __radd__(self, lhs): raise NotImplemented
    def __rsub__(self, lhs): raise NotImplemented
    def __rmul__(self, lhs): raise NotImplemented
    def __rmod__(self, lhs): raise NotImplemented
    def __rtruediv__(self, lhs): raise NotImplemented
    def __rfloordiv__(self, lhs): raise NotImplemented
    def __rpow__(self, lhs): raise NotImplemented

    def __rand__(self, lhs): raise NotImplemented
    def __rxor__(self, lhs): raise NotImplemented
    def __ror__(self, lhs): raise NotImplemented

    def __rlshift__(self, lhs): raise NotImplemented
    def __rrshift__(self, lhs): raise NotImplemented

    def __iadd__(self, rhs):
        if type(rhs) is Vector3:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            self.value = [m11 + r11, m12 + r12, m13 + r13,
                          m21 + r21, m22 + r22, m23 + r23,
                          m31 + r31, m32 + r32, m33 + r33]
            return self
        raise NotImplemented

    def __isub__(self, rhs):
        if type(rhs) is Matrix33:
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            self.value = [m11 - r11, m12 - r12, m13 - r13,
                          m21 - r21, m22 - r22, m23 - r23,
                          m31 - r31, m32 - r32, m33 - r33]
            return self
        raise NotImplemented

    def __imul__(self, rhs):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        if type(rhs) in (int, float):
            self.value = [m11 * rhs, m12 * rhs, m13 * rhs,
                          m21 * rhs, m22 * rhs, m23 * rhs,
                          m31 * rhs, m32 * rhs, m33 * rhs]
            return self
        if type(rhs) is Matrix33:
            r11, r12, r13, r21, r22, r23, r31, r32, r33 = rhs.value
            self.value = [m11 * r11 + m12 * r21 + m13 * r31,
                          m21 * r11 + m22 * r21 + m23 * r31,
                          m31 * r11 + m32 * r21 + m33 * r31,

                          m11 * r12 + m12 * r22 + m13 * r32,
                          m21 * r12 + m22 * r22 + m23 * r32,
                          m31 * r12 + m32 * r22 + m33 * r32,

                          m11 * r13 + m12 * r23 + m13 * r33,
                          m21 * r13 + m22 * r23 + m23 * r33,
                          m31 * r13 + m32 * r23 + m33 * r33]
            return self
        raise NotImplemented

    def __itruediv__(self, rhs):
        if type(rhs) in (int, float):
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            self.value = [m11 / rhs, m12 / rhs, m13 / rhs,
                          m21 / rhs, m22 / rhs, m23 / rhs,
                          m31 / rhs, m32 / rhs, m33 / rhs]
            return self
        raise NotImplemented

    def __imod__(self, rhs):
        if type(rhs) in (int, float):
            m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
            self.value = [m11 % rhs, m12 % rhs, m13 % rhs,
                          m21 % rhs, m22 % rhs, m23 % rhs,
                          m31 % rhs, m32 % rhs, m33 % rhs]
            return self
        raise NotImplemented

    def __abs__(self): return self.det()

    def __ceil__(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(math.ceil(m11), math.ceil(m12), math.ceil(m13),
                        math.ceil(m21), math.ceil(m22), math.ceil(m23),
                        math.ceil(m31), math.ceil(m32), math.ceil(m33))

    def __floor__(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(math.floor(m11), math.floor(m12), math.floor(m13),
                        math.floor(m21), math.floor(m22), math.floor(m23),
                        math.floor(m31), math.floor(m32), math.floor(m33))

    def __round__(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(round(m11), round(m12), round(m13),
                        round(m21), round(m22), round(m23),
                        round(m31), round(m32), round(m33))

    def __trunc__(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(trunc(m11), trunc(m12), trunc(m13),
                        trunc(m21), trunc(m22), trunc(m23),
                        trunc(m31), trunc(m32), trunc(m33))

    def __getitem__(self, key):
        if type(key) is tuple:
            key = key[0] * 3 + key[1]
        return self.value[key]

    def __setitem__(self, key, value):
        if type(key) is tuple:
            key = key[0] * 3 + key[1]
        self.value[key] = value

    def det(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return (m11 * (m22 * m33 - m23 * m32) +
                m12 * (m23 * m31 - m21 * m33) +
                m13 * (m21 * m32 - m22 * m31))

    def inverse(self):
        det = self.det()
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33((m22 * m33 - m23 * m32) / det,
                        (m23 * m31 - m21 * m33) / det,
                        (m21 * m32 - m22 * m31) / det,
                        (m32 * m13 - m33 * m12) / det,
                        (m33 * m11 - m31 * m13) / det,
                        (m31 * m12 - m32 * m11) / det,
                        (m12 * m23 - m13 * m22) / det,
                        (m13 * m21 - m11 * m23) / det,
                        (m11 * m22 - m12 * m21) / det)

    def transpose(self):
        m11, m12, m13, m21, m22, m23, m31, m32, m33 = self.value
        return Matrix33(m11, m21, m31, m12, m22, m32, m13, m23, m33)


####
# Main
####

if __name__ == '__main__':
    def dump(dual, vertex, normal, edge, polygon):
        M = len(normal)
        m = []
        m.append('*'*40)
        m.append(('正%d面体' % M) + (dual and '(対)' or ''))
        m.append('*'*40)
        m.append('面数 : %d' % len(normal))
        m.append('辺数 : %d' % len(edge))
        m.append('頂点数: %d' % len(vertex))
        m.append('')

        m.append('VERTEX[%d] = %s' % (len(vertex), paren_out[0]))
        for vi in range(len(vertex)):
            v = vertex[vi]
            m.append('    %s %+8.6f, %+8.6f, %+8.6f %s,%s'
                     % tuple([paren_vec[0], *v, paren_vec[1], (comment and ('  # %d' % vi) or '')]))
        m.append(paren_out[1])
        m.append('')

        if dump_normal:
            m.append('NORMAL[%d] = %s' % (len(normal), paren_out[0]))
            for ni in range(len(normal)):
                n = normal[ni]
                m.append('    %s %+8.6f, %+8.6f, %+8.6f %s,%s'
                         % tuple([paren_vec[0], *n, paren_vec[1], (comment and ('  # %d' % ni) or '')]))
            m.append(paren_out[1])
            m.append('')

        m.append('FACET[%d] = %s' % (len(polygon), paren_out[0]))
        for pi in range(len(polygon)):
            n = normal[pi]
            p = polygon[pi]
            mn = ('%s %+8.6f, %+8.6f, %+8.6f %s, ' % (paren_vec[0], *n, paren_vec[1])) if not dump_normal else ''
            mp = paren_list[0] + ' ' + ', '.join(['%2d' % p for p in polygon[pi]]) + ' ' + paren_list[1]
            m.append('    %s%s,%s' % tuple([mn, mp, (comment and ('  # %d' % pi) or '')]))
        m.append(paren_out[1])
        m.append('')

        m.append('EDGE[%d] = %s' % (len(edge), paren_out[0]))
        es = [(paren_list[0] + ' ' + ', '.join(['%2d' % p for p in el]) + ' ' + paren_list[1]) for el in edge]
        for e in range(0, len(es), 4):
            m.append('    ' + ', '.join(es[e:e+4]) + ',')
        m.append(paren_out[1])
        m.append('')

        m.append('')
        print('\n'.join(m))

    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--cparen', action='store_true', help='括弧の文字を変更')
    parser.add_argument('-n', '--normal', action='store_true', help='法線データを分離')
    parser.add_argument('-u', '--uncomment', action='store_true', help='インデックスのコメントを排除')
    args = parser.parse_args()

    paren_c = ('{', '}')
    paren_vec = ('(', ')')
    paren_out = ('(', ')')
    paren_list = ('(', ')')

    dump_normal = args.normal
    comment = not args.uncomment
    if args.cparen:
        paren_vec = paren_c
        paren_out = paren_c
        paren_list = paren_c

    rp_table = [RegularPolyhedron(i) for i in RegularPolyhedron.INDEX.keys()]
    for rp in rp_table:
        dump(False, rp.main_vertex, rp.main_normal, rp.main_edge, rp.main_polygon)
    for ri in (0, 2, 1, 4, 3):
        rp = rp_table[ri]
        dump(True, rp.dual_vertex, rp.dual_normal, rp.dual_edge, rp.dual_polygon)

    pass

####
# END
出力結果
****************************************
正4面体
****************************************
面数 : 4
辺数 : 6
頂点数: 4

VERTEX[4] = (
    ( +0.000000, +0.000000, +1.000000 ),  # 0
    ( -0.471405, +0.816497, -0.333333 ),  # 1
    ( +0.942809, +0.000000, -0.333333 ),  # 2
    ( -0.471405, -0.816497, -0.333333 ),  # 3
)

FACET[4] = (
    ( +0.471405, +0.816497, +0.333333 ), (  0,  2,  1 ),  # 0
    ( -0.942809, +0.000000, +0.333333 ), (  0,  1,  3 ),  # 1
    ( +0.471405, -0.816497, +0.333333 ), (  0,  3,  2 ),  # 2
    ( +0.000000, +0.000000, -1.000000 ), (  1,  2,  3 ),  # 3
)

EDGE[6] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  1,  2 ),
    (  1,  3 ), (  2,  3 ),
)


****************************************
正6面体
****************************************
面数 : 6
辺数 : 12
頂点数: 8

VERTEX[8] = (
    ( +0.000000, +0.000000, +1.000000 ),  # 0
    ( -0.471405, +0.816497, +0.333333 ),  # 1
    ( +0.942809, +0.000000, +0.333333 ),  # 2
    ( -0.471405, -0.816497, +0.333333 ),  # 3
    ( +0.471405, +0.816497, -0.333333 ),  # 4
    ( -0.942809, +0.000000, -0.333333 ),  # 5
    ( +0.471405, -0.816497, -0.333333 ),  # 6
    ( +0.000000, +0.000000, -1.000000 ),  # 7
)

FACET[6] = (
    ( +0.408248, +0.707107, +0.577350 ), (  0,  2,  4,  1 ),  # 0
    ( -0.816497, +0.000000, +0.577350 ), (  0,  1,  5,  3 ),  # 1
    ( +0.408248, -0.707107, +0.577350 ), (  0,  3,  6,  2 ),  # 2
    ( +0.816497, +0.000000, -0.577350 ), (  2,  6,  7,  4 ),  # 3
    ( -0.408248, +0.707107, -0.577350 ), (  1,  4,  7,  5 ),  # 4
    ( -0.408248, -0.707107, -0.577350 ), (  3,  5,  7,  6 ),  # 5
)

EDGE[12] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  1,  4 ),
    (  1,  5 ), (  2,  4 ), (  2,  6 ), (  3,  5 ),
    (  3,  6 ), (  4,  7 ), (  5,  7 ), (  6,  7 ),
)


****************************************
正8面体
****************************************
面数 : 8
辺数 : 12
頂点数: 6

VERTEX[6] = (
    ( +0.000000, +0.000000, +1.000000 ),  # 0
    ( +0.000000, +1.000000, +0.000000 ),  # 1
    ( -1.000000, +0.000000, +0.000000 ),  # 2
    ( +1.000000, +0.000000, +0.000000 ),  # 3
    ( +0.000000, -1.000000, +0.000000 ),  # 4
    ( +0.000000, +0.000000, -1.000000 ),  # 5
)

FACET[8] = (
    ( +0.577350, +0.577350, +0.577350 ), (  0,  3,  1 ),  # 0
    ( -0.577350, +0.577350, +0.577350 ), (  0,  1,  2 ),  # 1
    ( -0.577350, -0.577350, +0.577350 ), (  0,  2,  4 ),  # 2
    ( +0.577350, -0.577350, +0.577350 ), (  0,  4,  3 ),  # 3
    ( -0.577350, +0.577350, -0.577350 ), (  1,  5,  2 ),  # 4
    ( +0.577350, +0.577350, -0.577350 ), (  1,  3,  5 ),  # 5
    ( +0.577350, -0.577350, -0.577350 ), (  3,  4,  5 ),  # 6
    ( -0.577350, -0.577350, -0.577350 ), (  2,  5,  4 ),  # 7
)

EDGE[12] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  0,  4 ),
    (  1,  2 ), (  1,  3 ), (  1,  5 ), (  2,  4 ),
    (  2,  5 ), (  3,  4 ), (  3,  5 ), (  4,  5 ),
)


****************************************
正12面体
****************************************
面数 : 12
辺数 : 30
頂点数: 20

VERTEX[20] = (
    ( +0.000000, +0.000000, +1.000000 ),  # 0
    ( -0.333333, +0.577350, +0.745356 ),  # 1
    ( +0.666667, +0.000000, +0.745356 ),  # 2
    ( -0.333333, -0.577350, +0.745356 ),  # 3
    ( +0.127322, +0.934172, +0.333333 ),  # 4
    ( -0.872678, -0.356822, +0.333333 ),  # 5
    ( +0.745356, -0.577350, +0.333333 ),  # 6
    ( +0.127322, -0.934172, +0.333333 ),  # 7
    ( -0.872678, +0.356822, +0.333333 ),  # 8
    ( +0.745356, +0.577350, +0.333333 ),  # 9
    ( -0.127322, +0.934172, -0.333333 ),  # 10
    ( -0.745356, -0.577350, -0.333333 ),  # 11
    ( -0.745356, +0.577350, -0.333333 ),  # 12
    ( -0.127322, -0.934172, -0.333333 ),  # 13
    ( +0.872678, +0.356822, -0.333333 ),  # 14
    ( +0.872678, -0.356822, -0.333333 ),  # 15
    ( -0.666667, +0.000000, -0.745356 ),  # 16
    ( +0.333333, -0.577350, -0.745356 ),  # 17
    ( +0.333333, +0.577350, -0.745356 ),  # 18
    ( +0.000000, +0.000000, -1.000000 ),  # 19
)

FACET[12] = (
    ( +0.303531, +0.525731, +0.794654 ), (  0,  2,  9,  4,  1 ),  # 0
    ( -0.607062, +0.000000, +0.794654 ), (  0,  1,  8,  5,  3 ),  # 1
    ( +0.303531, -0.525731, +0.794654 ), (  0,  3,  7,  6,  2 ),  # 2
    ( +0.982247, +0.000000, +0.187592 ), (  2,  6, 15, 14,  9 ),  # 3
    ( -0.491123, -0.850651, +0.187592 ), (  3,  5, 11, 13,  7 ),  # 4
    ( -0.491123, +0.850651, +0.187592 ), (  1,  4, 10, 12,  8 ),  # 5
    ( +0.491123, +0.850651, -0.187592 ), (  4,  9, 14, 18, 10 ),  # 6
    ( +0.491123, -0.850651, -0.187592 ), (  6,  7, 13, 17, 15 ),  # 7
    ( -0.982247, +0.000000, -0.187592 ), (  5,  8, 12, 16, 11 ),  # 8
    ( -0.303531, +0.525731, -0.794654 ), ( 10, 18, 19, 16, 12 ),  # 9
    ( +0.607062, +0.000000, -0.794654 ), ( 14, 15, 17, 19, 18 ),  # 10
    ( -0.303531, -0.525731, -0.794654 ), ( 11, 16, 19, 17, 13 ),  # 11
)

EDGE[30] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  1,  4 ),
    (  1,  8 ), (  2,  6 ), (  2,  9 ), (  3,  5 ),
    (  3,  7 ), (  4,  9 ), (  4, 10 ), (  5,  8 ),
    (  5, 11 ), (  6,  7 ), (  6, 15 ), (  7, 13 ),
    (  8, 12 ), (  9, 14 ), ( 10, 12 ), ( 10, 18 ),
    ( 11, 13 ), ( 11, 16 ), ( 12, 16 ), ( 13, 17 ),
    ( 14, 15 ), ( 14, 18 ), ( 15, 17 ), ( 16, 19 ),
    ( 17, 19 ), ( 18, 19 ),
)


****************************************
正20面体
****************************************
面数 : 20
辺数 : 30
頂点数: 12

VERTEX[12] = (
    ( +0.000000, +0.000000, +1.000000 ),  # 0
    ( +0.276393, +0.850651, +0.447214 ),  # 1
    ( -0.723607, +0.525731, +0.447214 ),  # 2
    ( +0.894427, +0.000000, +0.447214 ),  # 3
    ( +0.276393, -0.850651, +0.447214 ),  # 4
    ( -0.723607, -0.525731, +0.447214 ),  # 5
    ( -0.894427, +0.000000, -0.447214 ),  # 6
    ( -0.276393, +0.850651, -0.447214 ),  # 7
    ( +0.723607, +0.525731, -0.447214 ),  # 8
    ( +0.723607, -0.525731, -0.447214 ),  # 9
    ( -0.276393, -0.850651, -0.447214 ),  # 10
    ( +0.000000, +0.000000, -1.000000 ),  # 11
)

FACET[20] = (
    ( -0.187592, -0.577350, +0.794654 ), (  0,  5,  4 ),  # 0
    ( -0.187592, +0.577350, +0.794654 ), (  0,  1,  2 ),  # 1
    ( +0.491123, +0.356822, +0.794654 ), (  0,  3,  1 ),  # 2
    ( -0.607062, +0.000000, +0.794654 ), (  0,  2,  5 ),  # 3
    ( +0.491123, -0.356822, +0.794654 ), (  0,  4,  3 ),  # 4
    ( -0.303531, -0.934172, +0.187592 ), (  4,  5, 10 ),  # 5
    ( +0.794654, +0.577350, +0.187592 ), (  1,  3,  8 ),  # 6
    ( -0.982247, +0.000000, +0.187592 ), (  2,  6,  5 ),  # 7
    ( -0.303531, +0.934172, +0.187592 ), (  1,  7,  2 ),  # 8
    ( +0.794654, -0.577350, +0.187592 ), (  3,  4,  9 ),  # 9
    ( -0.794654, +0.577350, -0.187592 ), (  2,  7,  6 ),  # 10
    ( -0.794654, -0.577350, -0.187592 ), (  5,  6, 10 ),  # 11
    ( +0.303531, +0.934172, -0.187592 ), (  1,  8,  7 ),  # 12
    ( +0.982247, +0.000000, -0.187592 ), (  3,  9,  8 ),  # 13
    ( +0.303531, -0.934172, -0.187592 ), (  4, 10,  9 ),  # 14
    ( +0.187592, +0.577350, -0.794654 ), (  7,  8, 11 ),  # 15
    ( +0.607062, +0.000000, -0.794654 ), (  8,  9, 11 ),  # 16
    ( -0.491123, +0.356822, -0.794654 ), (  6,  7, 11 ),  # 17
    ( +0.187592, -0.577350, -0.794654 ), (  9, 10, 11 ),  # 18
    ( -0.491123, -0.356822, -0.794654 ), (  6, 11, 10 ),  # 19
)

EDGE[30] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  0,  4 ),
    (  0,  5 ), (  1,  2 ), (  1,  3 ), (  1,  7 ),
    (  1,  8 ), (  2,  5 ), (  2,  6 ), (  2,  7 ),
    (  3,  4 ), (  3,  8 ), (  3,  9 ), (  4,  5 ),
    (  4,  9 ), (  4, 10 ), (  5,  6 ), (  5, 10 ),
    (  6,  7 ), (  6, 10 ), (  6, 11 ), (  7,  8 ),
    (  7, 11 ), (  8,  9 ), (  8, 11 ), (  9, 10 ),
    (  9, 11 ), ( 10, 11 ),
)


****************************************
正4面体(対)
****************************************
面数 : 4
辺数 : 6
頂点数: 4

VERTEX[4] = (
    ( +0.471405, +0.816497, +0.333333 ),  # 0
    ( -0.942809, +0.000000, +0.333333 ),  # 1
    ( +0.471405, -0.816497, +0.333333 ),  # 2
    ( +0.000000, +0.000000, -1.000000 ),  # 3
)

FACET[4] = (
    ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2 ),  # 0
    ( -0.471405, +0.816497, -0.333333 ), (  0,  3,  1 ),  # 1
    ( +0.942809, +0.000000, -0.333333 ), (  0,  2,  3 ),  # 2
    ( -0.471405, -0.816497, -0.333333 ), (  1,  3,  2 ),  # 3
)

EDGE[6] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  1,  2 ),
    (  1,  3 ), (  2,  3 ),
)


****************************************
正6面体(対)
****************************************
面数 : 6
辺数 : 12
頂点数: 8

VERTEX[8] = (
    ( +0.577350, +0.577350, +0.577350 ),  # 0
    ( -0.577350, +0.577350, +0.577350 ),  # 1
    ( -0.577350, -0.577350, +0.577350 ),  # 2
    ( +0.577350, -0.577350, +0.577350 ),  # 3
    ( -0.577350, +0.577350, -0.577350 ),  # 4
    ( +0.577350, +0.577350, -0.577350 ),  # 5
    ( +0.577350, -0.577350, -0.577350 ),  # 6
    ( -0.577350, -0.577350, -0.577350 ),  # 7
)

FACET[6] = (
    ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2,  3 ),  # 0
    ( +0.000000, +1.000000, +0.000000 ), (  0,  5,  4,  1 ),  # 1
    ( -1.000000, +0.000000, +0.000000 ), (  1,  4,  7,  2 ),  # 2
    ( +1.000000, +0.000000, +0.000000 ), (  0,  3,  6,  5 ),  # 3
    ( +0.000000, -1.000000, +0.000000 ), (  2,  7,  6,  3 ),  # 4
    ( +0.000000, +0.000000, -1.000000 ), (  4,  5,  6,  7 ),  # 5
)

EDGE[12] = (
    (  0,  1 ), (  0,  3 ), (  0,  5 ), (  1,  2 ),
    (  1,  4 ), (  2,  3 ), (  2,  7 ), (  3,  6 ),
    (  4,  5 ), (  4,  7 ), (  5,  6 ), (  6,  7 ),
)


****************************************
正8面体(対)
****************************************
面数 : 8
辺数 : 12
頂点数: 6

VERTEX[6] = (
    ( +0.408248, +0.707107, +0.577350 ),  # 0
    ( -0.816497, +0.000000, +0.577350 ),  # 1
    ( +0.408248, -0.707107, +0.577350 ),  # 2
    ( +0.816497, +0.000000, -0.577350 ),  # 3
    ( -0.408248, +0.707107, -0.577350 ),  # 4
    ( -0.408248, -0.707107, -0.577350 ),  # 5
)

FACET[8] = (
    ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2 ),  # 0
    ( -0.471405, +0.816497, +0.333333 ), (  0,  4,  1 ),  # 1
    ( +0.942809, +0.000000, +0.333333 ), (  0,  2,  3 ),  # 2
    ( -0.471405, -0.816497, +0.333333 ), (  1,  5,  2 ),  # 3
    ( +0.471405, +0.816497, -0.333333 ), (  0,  3,  4 ),  # 4
    ( -0.942809, +0.000000, -0.333333 ), (  1,  4,  5 ),  # 5
    ( +0.471405, -0.816497, -0.333333 ), (  2,  5,  3 ),  # 6
    ( +0.000000, +0.000000, -1.000000 ), (  3,  5,  4 ),  # 7
)

EDGE[12] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  0,  4 ),
    (  1,  2 ), (  1,  4 ), (  1,  5 ), (  2,  3 ),
    (  2,  5 ), (  3,  4 ), (  3,  5 ), (  4,  5 ),
)


****************************************
正12面体(対)
****************************************
面数 : 12
辺数 : 30
頂点数: 20

VERTEX[20] = (
    ( -0.187592, -0.577350, +0.794654 ),  # 0
    ( -0.187592, +0.577350, +0.794654 ),  # 1
    ( +0.491123, +0.356822, +0.794654 ),  # 2
    ( -0.607062, +0.000000, +0.794654 ),  # 3
    ( +0.491123, -0.356822, +0.794654 ),  # 4
    ( -0.303531, -0.934172, +0.187592 ),  # 5
    ( +0.794654, +0.577350, +0.187592 ),  # 6
    ( -0.982247, +0.000000, +0.187592 ),  # 7
    ( -0.303531, +0.934172, +0.187592 ),  # 8
    ( +0.794654, -0.577350, +0.187592 ),  # 9
    ( -0.794654, +0.577350, -0.187592 ),  # 10
    ( -0.794654, -0.577350, -0.187592 ),  # 11
    ( +0.303531, +0.934172, -0.187592 ),  # 12
    ( +0.982247, +0.000000, -0.187592 ),  # 13
    ( +0.303531, -0.934172, -0.187592 ),  # 14
    ( +0.187592, +0.577350, -0.794654 ),  # 15
    ( +0.607062, +0.000000, -0.794654 ),  # 16
    ( -0.491123, +0.356822, -0.794654 ),  # 17
    ( +0.187592, -0.577350, -0.794654 ),  # 18
    ( -0.491123, -0.356822, -0.794654 ),  # 19
)

FACET[12] = (
    ( +0.000000, +0.000000, +1.000000 ), (  0,  4,  2,  1,  3 ),  # 0
    ( +0.276393, +0.850651, +0.447214 ), (  1,  2,  6, 12,  8 ),  # 1
    ( -0.723607, +0.525731, +0.447214 ), (  1,  8, 10,  7,  3 ),  # 2
    ( +0.894427, +0.000000, +0.447214 ), (  2,  4,  9, 13,  6 ),  # 3
    ( +0.276393, -0.850651, +0.447214 ), (  0,  5, 14,  9,  4 ),  # 4
    ( -0.723607, -0.525731, +0.447214 ), (  0,  3,  7, 11,  5 ),  # 5
    ( -0.894427, +0.000000, -0.447214 ), (  7, 10, 17, 19, 11 ),  # 6
    ( -0.276393, +0.850651, -0.447214 ), (  8, 12, 15, 17, 10 ),  # 7
    ( +0.723607, +0.525731, -0.447214 ), (  6, 13, 16, 15, 12 ),  # 8
    ( +0.723607, -0.525731, -0.447214 ), (  9, 14, 18, 16, 13 ),  # 9
    ( -0.276393, -0.850651, -0.447214 ), (  5, 11, 19, 18, 14 ),  # 10
    ( +0.000000, +0.000000, -1.000000 ), ( 15, 16, 18, 19, 17 ),  # 11
)

EDGE[30] = (
    (  0,  3 ), (  0,  4 ), (  0,  5 ), (  1,  2 ),
    (  1,  3 ), (  1,  8 ), (  2,  4 ), (  2,  6 ),
    (  3,  7 ), (  4,  9 ), (  5, 11 ), (  5, 14 ),
    (  6, 12 ), (  6, 13 ), (  7, 10 ), (  7, 11 ),
    (  8, 10 ), (  8, 12 ), (  9, 13 ), (  9, 14 ),
    ( 10, 17 ), ( 11, 19 ), ( 12, 15 ), ( 13, 16 ),
    ( 14, 18 ), ( 15, 16 ), ( 15, 17 ), ( 16, 18 ),
    ( 17, 19 ), ( 18, 19 ),
)


****************************************
正20面体(対)
****************************************
面数 : 20
辺数 : 30
頂点数: 12

VERTEX[12] = (
    ( +0.303531, +0.525731, +0.794654 ),  # 0
    ( -0.607062, +0.000000, +0.794654 ),  # 1
    ( +0.303531, -0.525731, +0.794654 ),  # 2
    ( +0.982247, +0.000000, +0.187592 ),  # 3
    ( -0.491123, -0.850651, +0.187592 ),  # 4
    ( -0.491123, +0.850651, +0.187592 ),  # 5
    ( +0.491123, +0.850651, -0.187592 ),  # 6
    ( +0.491123, -0.850651, -0.187592 ),  # 7
    ( -0.982247, +0.000000, -0.187592 ),  # 8
    ( -0.303531, +0.525731, -0.794654 ),  # 9
    ( +0.607062, +0.000000, -0.794654 ),  # 10
    ( -0.303531, -0.525731, -0.794654 ),  # 11
)

FACET[20] = (
    ( +0.000000, +0.000000, +1.000000 ), (  0,  1,  2 ),  # 0
    ( -0.333333, +0.577350, +0.745356 ), (  0,  5,  1 ),  # 1
    ( +0.666667, +0.000000, +0.745356 ), (  0,  2,  3 ),  # 2
    ( -0.333333, -0.577350, +0.745356 ), (  1,  4,  2 ),  # 3
    ( +0.127322, +0.934172, +0.333333 ), (  0,  6,  5 ),  # 4
    ( -0.872678, -0.356822, +0.333333 ), (  1,  8,  4 ),  # 5
    ( +0.745356, -0.577350, +0.333333 ), (  2,  7,  3 ),  # 6
    ( +0.127322, -0.934172, +0.333333 ), (  2,  4,  7 ),  # 7
    ( -0.872678, +0.356822, +0.333333 ), (  1,  5,  8 ),  # 8
    ( +0.745356, +0.577350, +0.333333 ), (  0,  3,  6 ),  # 9
    ( -0.127322, +0.934172, -0.333333 ), (  5,  6,  9 ),  # 10
    ( -0.745356, -0.577350, -0.333333 ), (  4,  8, 11 ),  # 11
    ( -0.745356, +0.577350, -0.333333 ), (  5,  9,  8 ),  # 12
    ( -0.127322, -0.934172, -0.333333 ), (  4, 11,  7 ),  # 13
    ( +0.872678, +0.356822, -0.333333 ), (  3, 10,  6 ),  # 14
    ( +0.872678, -0.356822, -0.333333 ), (  3,  7, 10 ),  # 15
    ( -0.666667, +0.000000, -0.745356 ), (  8,  9, 11 ),  # 16
    ( +0.333333, -0.577350, -0.745356 ), (  7, 11, 10 ),  # 17
    ( +0.333333, +0.577350, -0.745356 ), (  6, 10,  9 ),  # 18
    ( +0.000000, +0.000000, -1.000000 ), (  9, 10, 11 ),  # 19
)

EDGE[30] = (
    (  0,  1 ), (  0,  2 ), (  0,  3 ), (  0,  5 ),
    (  0,  6 ), (  1,  2 ), (  1,  4 ), (  1,  5 ),
    (  1,  8 ), (  2,  3 ), (  2,  4 ), (  2,  7 ),
    (  3,  6 ), (  3,  7 ), (  3, 10 ), (  4,  7 ),
    (  4,  8 ), (  4, 11 ), (  5,  6 ), (  5,  8 ),
    (  5,  9 ), (  6,  9 ), (  6, 10 ), (  7, 10 ),
    (  7, 11 ), (  8,  9 ), (  8, 11 ), (  9, 10 ),
    (  9, 11 ), ( 10, 11 ),
)


7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7