Dencyuman
@Dencyuman (田中 匠美)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Pythonで任意のパラメータkを用いてN芒星を描画するプログラム

解決したいこと

Pythonの練習でN芒星を描画するプログラムを書いています。
参考書には以下のようなプログラムが記載されていました。

#N=5(5芒星)の場合 
from PIL from Image, ImageDraw
from math import pi, sin, cos

img = Image.new("L",(256, 256), 255)
draw = ImageDraw.Draw(img)
cx = 128
cy = 128
r = 96
draw.ellipse((cx-r, cy-r, cx+r, cy+r))
N = 5
s = 2 * pi / N
k = N // 2
for i in range(N):
  s1=((j * k) % N) * s - 0.5 * pi
  s2=s1+s*k
  x1=r*cos(s1)+cx
  y1=r*sin(s1)+cy
  x2=r*cos(s2)+cx
  y2=r*sin(s2)+cy
  draw.line((x1, y1, x2, y2))
img

しかし、k=N//2とするとNが奇数の場合しか描画できないため、N芒星を描画可能なkの値をリスト化し、リスト内の任意のkによって再描画を繰り返すというプログラムに改良したいと思い、以下のようなプログラムを書きました。

#N=7(7芒星)の場合

img = Image.new("L",(256, 256), 255)
draw = ImageDraw.Draw(img)
cx = 128 
cy = 128 
r = 96 
draw.ellipse((cx-r, cy-r, cx+r, cy+r))
N=7
s=2*pi/N
mylist=[2, 3, 4, 5]

num=0 #以下のwhile文の制御変数

while num < 1:
  k=int(input(str(mylist)+"の中から好きな数値を選んでください。処理を終了したい場合は0と入力してください。"))
  if k in mylist:
    print("true")
    for j in range(N):
      s1=((j * k) % N) * s - 0.5 * pi
      s2=s1+s*k
      x1=r*cos(s1)+cx
      y1=r*sin(s1)+cy
      x2=r*cos(s2)+cx
      y2=r*sin(s2)+cy
      draw.line((x1, y1, x2, y2))
    img
  elif k == 0:
    break
  else:
    print("エラー") #選択肢外の数値を選択したらもう一度入力させる

kの値によって描画されるN芒星のパターンが変わります。
そのため、N芒星の描画が可能なkの値を示し、その中から任意のkを繰り返し入力してもらい、その都度再描画させることによって、kの値によるN芒星の形状の変化を表現したいのです。

しかし実行してみると、以下の写真のように描画だけがされない状態になります。

問題.jpg

自分で試したこと

描画を実行する命令であるimgをif文の外に出し、num += 1でwhile文を抜けさせると、以下の写真のように描画はされました。しかし、ユーザーが終了の合図である0を入力するまで繰り返し再描画させたいので、これでは本末転倒です。
問題2.jpg
pythonにお詳しい方、是非お知恵をお貸しいただけると嬉しいです。

0

2Answer

こちらの方法で毎回図形を描画できると思います。

+ from IPython.display import display

-    img
+    display(img)

参考記事

あと、毎回imgを初期化してあげないと、処理がループするたびに図形が重なって描画されていくことになると思うのでご注意ください。

1Like

Comments

  1. @Dencyuman

    Questioner

    while文でユーザーが0を入力するまで再描画し続けるようとすると、display(img)が実行されたタイミングで、while文を脱出してしまい、一つしか描画されませんでした。
    しかし、for文ですべてのkの値のN芒星を描画するようにプログラムを書き換えたらうまくいきました!ありがとうございました。

参考までに、while文ではなくfor文で全てのkの値についてN芒星を描画するように書き換えたプログラムを以下に示しておきます。

img = Image.new("L",(256, 256), 255) #変数imgに新しい描画領域を代入
draw = ImageDraw.Draw(img) #変数Drawに描画領域imgを作成する動作を代入
cx = 128 #円の中心のx座標
cy = 128 #円の中心のy座標
r = 96 #円の半径
draw.ellipse((cx-r, cy-r, cx+r, cy+r)) #円の描画

def gcd(x, y):  #引数x,yの最大公約数を求める関数gcdを作成
    if y == 0: #もしyが0であれば
        return x #引数xの値を返す
    else: #yが0以外の数であれば
        return gcd(y,x%y) #引数xにy,引数yにxをyで割った余りを代入

N=int(input("描画したいN芒星のNの値を数値のみ入力してください。")) #描画したいN芒星のNの値を入力してもらい、int型で変数Nに代入
s=2*pi/N #s1からs2へ移動する際の中心角を定義
num = 2 #N芒星において、1とN-1は必ず芒星にならないため、Nと互いに素である組み合わせの検討初期値として2を代入している
gcd_list = [] #以下のwhile文においてNと互いに素であると判定された数値numのリスト(=N芒星が描画可能なkの値)

while num < N-1: #このwhile文で、Nと互いに素である数値numを判定し、gcd_listに格納している。
  gcdnum = gcd(num, N) #gcd関数で求めた最大公約数を変数gcdnumに代入
  if gcdnum == 1: #もしgcdnum(numとNの最大公約数)が0ならば(=numとNが互いに素であれば)
    gcd_list.append(num) #そのnumは芒星が描画可能なkの値の一つなので、gcd_listに格納
  num += 1 #for文のパラメータであるiをインクリメント

gcd_len=int(len(gcd_list)) #gcd_listの要素数
half_gcd_len=int(len(gcd_list)/2) #描画パターンは描画可能なkの値の半分なので、gcd_listの要素数の半分を変数half_gcd_lenに代入
print(gcd_list)
print(gcd_len)

for i in range(half_gcd_len): #描画可能なすべてのパターンの芒星を描画するためのfor文
  k = gcd_list[i] #gcd_listの0番目の要素から順に代入
  rk = gcd_list[gcd_len-1-i] #gcd_listの最後から順に代入
  print("k=" + str(k) + "," + str(rk))
  for j in range(N): #ここで芒星を描画
    s1=((j * k) % N) * s - 0.5 * pi
    s2=s1+s*k
    x1=r*cos(s1)+cx
    y1=r*sin(s1)+cy
    x2=r*cos(s2)+cx
    y2=r*sin(s2)+cy
    draw.line((x1, y1, x2, y2))
  display(img)
0Like

Your answer might help someone💌