今回は線の描画を使ってスクリーンセーバー(画面の焼き付き防止)を作ってみます。通常であれば線を描画する機能がありそうなものですが、casioplotモジュールには線を描画する機能がありません。公式マニュアルを見ても線の描画機能だけでなく円などの描画機能もありません。必要なグラフィック機能は自分で作らないといけません。そこで今回は線と円を描画するプログラムを作成します。

線を描画する

 線を描画するにはどうしたらよいのでしょうか。2点間を直線で結べばよいのでy=axの計算式に従って点を表示していくことになります。ここで、横の水平線と縦の垂直線は別途処理してしまいます。これは線の傾きで判断します。その後、横の長さと縦の長さに応じて処理を分けます。
 線を描画する際、関数として定義しておくと後々使いやすいものになります。ここではgLineという名前の関数にしてあります。必要なパラメーターは(x1,y1)と(x2,y2)の座標値、そして線の色を示す値(タプル型)になります。
 実際のプログラムは以下のようになります。fx-CG50には横255文字×300行までという数制限があるので、あまり長いプログラムにしてしまうと後々満足なプログラムが作れなくなってしまいます。Python言語仕様で行数的には短くすることができますので、興味ある人は改良してみてください。

from casioplot import *

def gLine(x1,y1,x2,y2,col):
  x=x1
  y=y1
  sx=1
  sy=1
  dx=x2-x1
  dy=y2-y1
  if dx<0:
    sx=-1
  if dy<0:
    sy=-1
  if dx==0:
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      y=y+sy
    return
  if dy==0:
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
    return
  if abs(dx)>abs(dy):
    d=dy/abs(dx)
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
      y=y+d
  else:
    d=dx/abs(dy)
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      x=x+d
      y=y+sy

clear_screen()
gLine(50,50,50,50,(0,0,0))

gLine(0,0,383,0,(0,0,0))
gLine(0,0,0,191,(0,0,0))
gLine(383,0,383,191,(0,0,0))
gLine(0,191,383,191,(0,0,0))

gLine(0,0,383,191,(255,0,0))
gLine(383,0,0,191,(0,255,0))
gLine(200,191,180,0,(0,0,255))
show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF1.pyとしてあります。実行すると図のようになります。上下左右の端に黒い線が描かれます。そして、対角線と中央付近に色がついた線が表示されます。

 次に画面をぐるっと一周した感じで線を描画してみます。線を描画する関数部分は変わりません。forで線の座標を変化させながら描いていますが、間隔1で表示すると画面が塗りつぶされた状態になります。これだと見栄え的に面白くないので間隔を4にしています。これはrange(0,384,4)の4の部分が該当します。range(0,384,4)の指定だと0から383まで4間隔ごとに値が変化します。

from casioplot import *

def gLine(x1,y1,x2,y2,col):
  x=x1
  y=y1
  sx=1
  sy=1
  dx=x2-x1
  dy=y2-y1
  if dx<0:
    sx=-1
  if dy<0:
    sy=-1
  if dx==0:
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      y=y+sy
    return
  if dy==0:
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
    return
  if abs(dx)>abs(dy):
    d=dy/abs(dx)
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
      y=y+d
  else:
    d=dx/abs(dy)
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      x=x+d
      y=y+sy

clear_screen()
for x in range(0,384,4):
  gLine(x,0,384-x,192,(255,0,0))
  show_screen()
for y in range(0,192,4):
  gLine(0,192-y,384,y,(255,0,0))
  show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF2.pyとしてあります。実行すると図のようになります。中には大昔(1980年代)、このようなグラフィックを見た人もいるかもしれません。

ランダムに線を表示

 次にランダムな位置にランダムな色で線を表示してみます。これは座標値と色を乱数値にするだけです。いずれも整数の乱数にするのでrandint()を使うと簡単にできます。
 実際のプログラムは以下のようになります。

from casioplot import *
from random import *

def gLine(x1,y1,x2,y2,col):
  x=x1
  y=y1
  sx=1
  sy=1
  dx=x2-x1
  dy=y2-y1
  if dx<0:
    sx=-1
  if dy<0:
    sy=-1
  if dx==0:
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      y=y+sy
    return
  if dy==0:
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
    return
  if abs(dx)>abs(dy):
    d=dy/abs(dx)
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
      y=y+d
  else:
    d=dx/abs(dy)
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      x=x+d
      y=y+sy

clear_screen()
while True:
  x1=randint(0,384)
  y1=randint(0,192)
  x2=randint(0,384)
  y2=randint(0,192)
  r=randint(0,255)
  g=randint(0,255)
  b=randint(0,255)
  gLine(x1,y1,x2,y2,(r,g,b))
  show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF3.pyとしてあります。実行すると図のようになります。中には大昔(1980年代)、このようなグラフィックを見た人もいるかもしれません。

線を動かすスクリーンセーバー

 それではスクリーンセーバーを作成しましょう。ここでは線が端に反射しながら移動するスクリーンセーバーにします。スクリーンセーバーでなくてもラインアニメーションとして見たようなことがあるかもしれません。
 線の2点の座標値とそれぞれどの方向に移動するかを示す値をdx1,dy1、dx2,dy2に入れておきます。座標値に加算していき端の座標を超えたら符号を反転させます。符号を反転させるには-dx1のように先頭に-をつけるだけです。
 実際のプログラムは以下のようになります。

from casioplot import *
from random import *

def gLine(x1,y1,x2,y2,col):
  x=x1
  y=y1
  sx=1
  sy=1
  dx=x2-x1
  dy=y2-y1
  if dx<0:
    sx=-1
  if dy<0:
    sy=-1
  if dx==0:
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      y=y+sy
    return
  if dy==0:
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
    return
  if abs(dx)>abs(dy):
    d=dy/abs(dx)
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
      y=y+d
  else:
    d=dx/abs(dy)
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      x=x+d
      y=y+sy

x1=30
y1=4
x2=380
y2=180
dx1=1
dy1=1
dx2=-1
dy2=-1

while True:
  x1=x1+dx1
  y1=y1+dy1
  x2=x2+dx2
  y2=y2+dy2
  if x1<0 or x1>383:
    dx1=-dx1
  if y1<0 or y1>191:
    dy1=-dy1
  if x2<0 or x2>383:
    dx2=-dx2
  if y2<0 or y2>191:
    dy2=-dy2
  clear_screen()
  gLine(x1,y1,x2,y2,(255,0,0))
  show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF4.pyとしてあります。実行すると図のようになります。電卓の処理速度が、そこそこ遅いので、まったりと見られるスクリーンセーバーになっています。

線を描画する部分をモジュール化する

 ここまでは1つのプログラム(pyファイル)内に線を描画する関数を書いていました。しかし、使うたびにこんなに長いプログラムがコード内にあると見通しも悪く、また300行の制限にも引っかかってしまいます。そこで線を描画する関数部分をモジュール化します。つまり別のpyファイルにしてしまいます。このようにするとimportで指定するだけで使うことができ便利になります。
 まず、線を描画する部分だけ抜き出します。これをglib.pyという名前で保存します。なお、モジュールを呼び出して実行するpyファイルと同じ階層においておいた方がよいでしょう。

from casioplot import *
def gLine(x1,y1,x2,y2,col):
  x=x1
  y=y1
  sx=1
  sy=1
  dx=x2-x1
  dy=y2-y1
  if dx<0:
    sx=-1
  if dy<0:
    sy=-1
  if dx==0:
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      y=y+sy
    return
  if dy==0:
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
    return
  if abs(dx)>abs(dy):
    d=dy/abs(dx)
    for i in range(abs(dx)):
      set_pixel(int(x),int(y),col)
      x=x+sx
      y=y+d
  else:
    d=dx/abs(dy)
    for i in range(abs(dy)):
      set_pixel(int(x),int(y),col)
      x=x+d
      y=y+sy

 次に上記のモジュールを読み込んで使ってみます。先ほどのスクリーンセーバーのプログラムをglib.pyを読み込んで使うように変更します。これは使う前に

from glib import *

 とするだけです。あとは、これまでと同様にgLineで線を描画できます。
 実際のプログラムは以下のようになります。プログラムも短くなって見やすくなりました。

from glib import *

x1=30
y1=4
x2=380
y2=180
dx1=1
dy1=1
dx2=-1
dy2=-1

while True:
  x1=x1+dx1
  y1=y1+dy1
  x2=x2+dx2
  y2=y2+dy2
  if x1<0 or x1>383:
    dx1=-dx1
  if y1<0 or y1>191:
    dy1=-dy1
  if x2<0 or x2>383:
    dx2=-dx2
  if y2<0 or y2>191:
    dy2=-dy2
  clear_screen()
  gLine(x1,y1,x2,y2,(255,0,0))
  show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF5.pyとしてあります。実行して問題がないか確認します。エラーが出なければOKです。これで手軽に線を描画する機能を利用できるようになりました。

なお、Pythonにはパラメーターを指定し忘れた時に備えてデフォルトパラメーターを指定することができます。例えば線の色を黒にしておくには関数定義の最初の部分で以下のようにcolの値を指定しておきます。

def gLine(x1,y1,x2,y2,col=(0,0,0)):

glib.pyを書き換えて試すと色指定されていない場合は黒い線が描画されます。

円を描画する

 次に円を描画して見ます。円を描画する計算式はいくつかありますが、ここでは三角関数を使ってみます。三角関数(sin,cos,tan)はmathモジュールに含まれています。importでmathモジュールを読み込まないと使えません。また、通常のPythonのmathモジュールの全ての機能が用意されているわけではないため、サポートされていない機能は自分で作成する必要があります。
 まず、三角関数を使って計算させてみましょう。ここでは円周率のpi、サインのsin()、コサインのcos()、タンジェントのtan()の計算結果を表示させます。実際のプログラムは以下のようになります。

from math import *
print(pi)
deg=30
rad=deg*pi/180
print(cos(rad))
print(sin(rad))
print(tan(rad))

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF6.pyとしてあります。実行するとシェルに結果が表示されます。演算誤差はどうしても発生するのでパソコン等で計算させた結果と異なる場合があります。

 三角関数が問題なく使えることがわかったので、円を描いてみましょう。円を描く計算式は以下のようになります。ラジアン値を変化させることで任意の角度から角度まで円を描くことができます。なお、値は角度ではなくラジアン値になります。

X座標 = 中心X座標 + cos(値) × 円の半径
Y座標 = 中心Y座標 + sin(値) × 円の半径

 以下の円を描くプログラムではforで角度を指定しています。角度からラジアンにするには「角度×円周率÷180」の式で計算できます。

from math import *
from glib import *

x=192
y=96
r=60
clear_screen()
for deg in range(0,360,1):
  rad=deg*pi/180
  xx=x+cos(rad)*r
  yy=y+sin(rad)*r
  set_pixel(int(xx),int(yy),(255,0,0))
show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF7.pyとしてあります。実行すると半径60ピクセルの赤い色の正円が描かれます。

多角形・円を描画する

 最後に多角形を描いてみましょう。先ほどは点で描きましたが、正64角形などの多角形を描いても円が描画されます。384×192くらいであれば正96角形くらい描けば十分正円に見えるでしょう。
 多角形で描くために先ほど作成した線のモジュールを読み込みます。求めた円の座標を線で結べば多角形や正円を描くことができます。
 以下のプログラムは正36角形を描いて円に見えるようにしています。

from math import *
from glib import *

x=192
y=96
r=60
oldx=-1
oldy=-1
clear_screen()
for deg in range(0,360+10,10):
  rad=deg*pi/180
  xx=int(x+cos(rad)*r)
  yy=int(y+sin(rad)*r)
  if oldx==-1:
    oldx=xx
    oldy=yy
  gLine(oldx,oldy,xx,yy,(255,0,0))
  oldx=xx
  oldy=yy
show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF8.pyとしてあります。実行すると赤い円が描かれます。

 range(0,360+10,10)部分の数値を変えることで任意の多角形を描くことができます。開始角度,終了角度+間隔,間隔の順番で指定します。終了角度に間隔を加算しないと最後の線が表示されません。
 以下のプログラムは正六角形を描きます。

from math import *
from glib import *

x=192
y=96
r=60
oldx=-1
oldy=-1
clear_screen()
for deg in range(0,360+60,60):
  rad=deg*pi/180
  xx=int(x+cos(rad)*r)
  yy=int(y+sin(rad)*r)
  if oldx==-1:
    oldx=xx
    oldy=yy
  gLine(oldx,oldy,xx,yy,(255,0,0))
  oldx=xx
  oldy=yy
show_screen()

 これまでと同様にパソコン側でファイルを作成しておき、電卓に転送します。ファイル名はF9.pyとしてあります。

 直線と円が描ければ、後は応用なので曲線でも何でも描くことができます。自分用のグラフィックライブラリを作っておけば便利ではないでしょうか。

著者 仲村三郎
日本のお家芸である小型化を体現したのが古き良き時代のポケットコンピューター(略してポケコンと呼ばれていました)。関数電卓はポケットコンピューターとは違いますが、今ではPythonでプログラミングできるまでに進化。進化した関数電卓を使って楽しもうではありませんか。