Casio Basic入門G07
Casio Basic入門
誤字脱字・記載ミスや分かりにくい表現は随時追記・修正します
更新 2015/08/09
更新 2015/08/09
5. Casio Basic でグラフィックス
前回: Casio Basic入門G06
Chapter G07
点線と ViewWindow
今回は、点線の描画について、詳しく調べます。
点線のスタイル設定については、fx-9860GII の取扱説明書(fx-9860GII_Soft_J_2.04.pdf)の 8-24 ページには、
SketchDot <Sketch文またはGraph文>
と記載があるだけです。今回は、点線を自由自在に描く方法を探りながら、グラフィックスプログラミングを詳しく調べてゆきます。
先ず最初に、点線を並べて以下のような描画を行う方法を調べます。

なかなか奥が深いことが分かりました。
前回作った点線を描画するプログラム DLINE1.1 は、以下です。
ファイル名: DLINE1.1
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
SketchDot F-Line 0,31,126,31
これを実行して、LCD画面を細かくみると、点線は、ピクセルが交互にON になっています。

点線はピクセルの ON と OFF が交互に並んだものですが、この ON/OFF のパターンを逆にできるのか?逆にするにはどうすれば良いのか? ここから調べて見ます。
と言うのも、点線を描画する書式;
SketchDot F-Line x1,y1,x2,y2
SketchDot Horizontal y
などには、ピクセルの ON/OFF の順序を指定するパラメータがありません。そこで、試しに長さの異なる点線を並べて描画させてみると、おもしろいことが分かります。
ファイル名: DLINE2.1
ClrGraph
CorrdOff
GrifOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
For 0→Y To 62
SketchDot F-Line 0,Y,Y,Y
Next
⇒ ダウンロード: DLINE2.1
SketchDot F-Line 0,Y,Y,Y
は、座標(0, Y) と座標(Y, Y) の間を点線で結ぶことを指示しています。
そして、For ループで、Y=0 の時から始めて、点線を描き、Y を1つづつ増やして、Y = 62 になるまで点線の描画を繰り返しています。
For 0→T To 62
SketchDot F-Line 0,Y,Y,Y
Next
Y=0 の時は、
座標(0, 0) と 座標(0, 0) を結ぶとなりますが、要するに 点(0, 0) に点を描くことになります。
Y=1 の時は、
座標(0, 1) と (1, 1) の間を結ぶ点線を描きます。Y座標値が 1 の位置に点線が描かれます。
Y=2 の時は、
座標(0, 2) と (2, 2) の間を結ぶ点線を描きます。Y座標値が 2 位置に点線が描かれます。
・・・・・・・・・・
最後に、Y=62 の時、つまり画面の一番上に点線を描きます。
では、ピクセルの ON と OFF のパターンが実際にどうなるのか、このプログラムを実行して確認します。

右端のピクセルが必ず ON になっています。言い換えれば、
SketchDot F-Line 0,Y,Y,Y
で線を描画する2つ端の端点の座標 (0, Y) と (Y, Y) のうち (Y, Y) に対応するピクセルが必ず ON になっています。つまり、点線描画の内部仕様がはっきりしました。
SketchDot F-Line の描画仕様
書式: SketchDot F-Line x1,y1,x2,y2
- 座標 (x1, y1) と座標 (x2, y2) を結ぶ点線を描画する。
- 座標 (x2, y2) に対応するピクセルは ON になる。
- 座標 (x2, y2) から (x1, y1) へ向かって描画される。
上のプログラムでは、ViewWindow座標系で (x1, y1) が左端の位置、(x2, y2) が右端の位置だったのですが、逆に、(x1, y1) に右端の位置、(x2, y2) に左端の位置を指定すると、どうなるでしょうか?
(x2, y2) のピクセル、つまり左端のピクセルを ON にしてから、右へ描画が進みます。従って、左端が必ず ON になるはずです。実際に試してみましょう。
ファイル名: DLINE2.2
ClrGraph
CorrdOff
GrifOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
For 0→Y To 62
SketchDot F-Line Y,Y,0,Y
Next
⇒ ダウンロード: DLINE2.2
これを実行してみます。

左端が必ず ON になっていることが確認できました。点線のピクセルの ON/OFF パターンが全て同じになっています。
従って、上下左右のピクセルを交互に ON/OFF するパターン(千鳥格子のパターン)にするには、プログラム DLINE2.1 のように右端を常に ON になる点を交互に1ピクセルずらすようにすれば良いことが確認できました。
==========
点線を描画する SketchDot F-Line の描画仕様が、SketchDot コマンドによるのか、F-Line によるのかを確かめるために、次のプログラムを作り、さらに クロックアップツール Ftune2 を用いて、逆にクロックを落として処理速度を極端に遅くして、実際の描画の様子を調べました。
ファイル名: LINE1
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
F-Line 0,10,126,10◢
F-Line 126,20,0,20◢
Horizontal 30
⇒ ダウンロード: LINE1
オーバークロックツール Ftune2 を使って、逆に 1.84MHz までクロックを落としたところ、
F-Line 0,10,126,10 は右 (126, 10) から左へ描画され,
F-Line 126,20,0,20 は左 (0, 20) から右へ描画され、
Horizontal 30 は左から右へ描画されることが分かります。
Ftune シリーズは国産 (sentaro様作) のアドインプログラムで、海外の Casio プログラム電卓愛好家からも高い評価を受けるようになっているもので、かなり安全に使えるものです。PCのオーバークロックツールなどに比べて、様々なところに安全に使える配慮がなされています。管理人は愛用しており、大変便利なものです。当ブログでは、今のところ作者から直接サポートを受けられますので、ご興味があれば Ftune シリーズのページをご覧ください。但し、万が一ハードウェアが損傷を受けた場合、メーカー保証が受けられないことから、広く一般的に使用を勧める性格のものではないことを申し添えておきます。
さて、プログラム LINE1 の2つの F-Line の描画方向の実験結果から、
F-Line x1,y1,x2,y2
は、座標 (x2, y2) から (x1, y1) へ描画されることが分かりました。
つまり、SketchDot F-Line による点線の描画仕様は、F-Line の描画仕様によることも確認できました。
F-Line にスタイル設定をした時の描画仕様は、他にも色々ありますが、これについては次回取り上げることにして、画面全体にピクセルを交互にON/OFF して描画する今回のテーマについて、もう少し調べてゆきます。
座標系での位置と物理的なピクセルの位置
グラフィックスの描画とは、簡単に言ってしまえば、LCDのピクセルを ON/OFF させることに尽きます。この単純な操作を、様々なコマンドを使って便利に行うのが、グラフィックスプログラミングと言えます。
ピクセルは、物理的な大きさを持つ描画単位で、ピクセルの描画(ON/OFF)のためには、ピクセル位置を指定する必要があります。ピクセルの中心がピクセルの位置で、ピクセル座標 (Xpix, Ypix) を指定して、描画(ON/OFF)を行います。
fx-9860GII で使える座標系の1つに物理座標系があります。これはピクセル座標 (Xpix, Ypix) を直接指定する座標系です。

グラフィックス描画エリアの左上の位置を (Xpix, Ypix) = (1, 1) とし、座標値は Xpix = 1, 2, ... 63 の整数、Ypix = 1, 2, ... 127 の整数です。物理座標系では、座標値に小数を設定するとエラーになります。1pix はピクセル1個の大きさなので、ピクセル座標系は実際のピクセルサイズを単位とした座標系といえます。ピクセル座標系をピクセルサイズに関係無いように抽象化したものが物理座標系で、原点を (1, 1) としているのは、ピクセルを1個、2個とカウントする感覚と一致しています。
次に、グラフィックス描画エリアの範囲について、ピクセル座標系と物理座標系の違いをみてみます。グラフィックス描画エリアは、実際に大きさを持つピクセルが 127個 x 63個並んだ範囲、つまり 127pix x 63pix の範囲(広さ)です。一方で物理座標系は、ピクセルの大きさの概念を無くした抽象的な座標系なので、その範囲はピクセル中心の座標で決まります。ピクセル中心で考えた場合、左端のピクセルと右端のピクセルのそれぞれ中心間の距離は 126pix (127pix でないことに注意) で、上端のピクセルと下端のピクセルの中心間の距離は 62 pix (同様に 63pix でないことに注意) となります (上図参照)。従って物理座標系の範囲は、126 x 62 になります (pix 単位が無いことに注目)。
Text , PxlOn, PxlOff, PxlChg, PxlTest( ) コマンドは、物理座標系で動作します。 これらのコマンドをプログラムで使うと、指定した座標は、そのままピクセル座標として描画に使われます。X座標軸が上から下、Y座標軸が左から右の方向になっていることに注意が必要です。
なお、物理座標系はプログラムで明示的に設定することはできず、上記のコマンドを使う時だけに適用されるものです。
上記のコマンド以外のグラフィックスコマンドは、論理座標系やViewWindow座標系で使います。
==========

論理座標系は、画面の中央を原点 (0, 0) とし、
- 座標値 X は、0.1 刻みの値 X = -6.3, -6.2, -6.1, ..., -0,2, -0.1, 0, 0.1, 0.2, ..., 6.1, 6.2, 6.3 が、Xpix = 1, 2, ..., 125, 126 に対応します。
- 座標値 Y は、0.1 刻みの値 Y = -3.1, -3.0, -2.9 ..., -0.2, -0.1, 0. 0.1, 0.2, ..., 2.9, 3.0, 3.1 が、Ypix = 1, 2, ..., 62, 63 に対応します。
ピクセル座標系との1対1の関係が崩れる一例として、座標 (0.05, 0) の位置に描画した点は (0.1, 0) に描画した点と重なります。
確認プログラム
ClrGraph
CorrdOn
GridOff
AxesOff
LabelOff
Plot 0.05,0◢
Plot 0.1,0
このプログラムでは、ClrGraph により自動的に論理座標系に設定されることを利用しています。
これを実行してみると、Plot 0.05,0◢ で表示される十字カーソルの位置は、X=0.1, Y=0 となっています。[EXE] を押して、次の Plot 0.1,0 を実行すると、同じ位置にカーソルが表示されます。カーソルを移動させると点が1個しか描画されません。このプログラムで Plot コマンドに指定した座標値は、描画処理のためにピクセル座標系の座標値へ変換されますが、論理座標系の 0.1 がピクセル座標系の 1 に対応するので、0.05 が四捨五入されて 0.1 に換算されてから、描画処理が行われていることが分かります。
==========
さて、ViewWindow座標系は、デフォルトの論理座標系 (ClrGraph で設定) を自由に拡張するものです。そこでデフォルトの論理座標系を ViewWindowで設定することもできます。
・デフォルトの論理座標系: ViewWindow -6.3,6.3,0,-3.1,3.1,0
さて、ViewWindow 0,126,0,0,62,0 で設定した ViewWindow座標系は以下のようになります。

左下隅を原点 (0, 0) として、座標値が1刻みでピクセル1個に対応させた座標系です。プログラムで座標値に整数を使えば、確実にピクセルと1対1に対応できて、分かりやすいですね。そのため、この座標系を多用しています。
==========
ViewWindow座標系は、好きな位置を原点にして、X軸方向(左右方向)やY軸方向(上下方向)を好きな方向で好きな範囲を指定できるのが最大の利点です。座標値に小数を設定できる(エラーにならない)のはデフォルトの論理座標と同じです。
ViewWindow 0,126,0,0,62,0 で設定した座標系では、X座標値やY座標値が整数の場合は、ピクセルの位置と一致するので分かりやすいと上で述べました。例えば、座標値を (10, 10) から (11, 10) に変えると、描画されるピクセルの位置は右隣のピクセルへ変化します。ところが、座標値が (10, 10) から (10.2, 10) へ変化した場合は、同じピクセルを指すことになります。

この座標系では、X座標軸(横方向)の幅は 126 で、ピクセル座標系での横幅も 126 なので、X座標値 1 にピクセル1個が対応しています。つまり、座標値が 1 刻みに変化すると、実際に描画されるピクセルが1つ変化します。ピクセル1個に相当する座標値の刻みは、Xdot という変数で管理されていて、この刻みの値は自動的に Xdot に収められます。上の ViewWindow座標系では、Xdot = 1 です。プログラムで Xdot を参照したり、設定ができます。
Xdot の入力方法: [VARS] [F1] (V・WIN) [F1] (X) [F4] (dot)
ClrGraph コマンドで 自動的に論理座標系が設定される時は、ViewWindow での設定がなくても Xdot = 0.1 となり、自動的に計算され Xdot に格納されます。Xdot の値は座標系が変更されるまでは保持されます。Xdot の挙動は実際に Casio Basic プログラムで確認できます (ここでは割愛しますが、興味があれば確認してみてください)。なお、Ydot もグラフィックス描画の際には必ず内部で計算しているはずですが、何故だかプログラムで参照可能な変数 Ydot はありません。
参考までに、ViewWindow の設定 (直交座標) で指定する各パラメータは
ViewWindow Xmin,Xmax,Xscl,Ymin,Ymax,Yscl
として、それぞれが変数として参照できます。逆に、現在設定されている ViewWindow 設定のうち、これら変数を使って特定のパラメータだけをプログラム内で変更できます。
内部的には、(Xmax-Xmin)÷126=Xdot が成り立つように、各パラメータが自動的に計算されまが、幾つかの条件があるようです。
- Xmax や Xmin のいずれか、或いは両方が変更されると Xdot が自動的に変更される。
- Xdot が変更されると、Xmin を変えずに Xmax が自動的に変更される。
- Xdot に負の数を設定するとエラーになるが、逆に例えば 6.3→Xmin:-6.3→Xmax とすると Xdot は -0.1 となる (X座標の向きを反転させる例)。
話を元に戻すと、ViewWindow の設定を行うと、以下の計算を自動的に行って ピクセル座標系の座標値 (Xpix とYpix)を算出して描画を行っています。
- (Xmax-Xmin)÷126→Xdot の処理
- 描画のために使われる X座標値 X から X÷Xdot を計算、これから Xpix を求める。
- Xpix = X÷Xdot は整数値でなければならないので、小数の場合は四捨五入で Xpix を算出
Y 軸方向については、Ydot が変数として準備されていませんが、同じ計算を行っています(下記参照)。
==========
fx-9860GII のCasio Basic では、グラフィックス描画エリアが ピクセル数で 127個 X 63個と変則的で、プログラミングに慣れた人は 128個 X 64 個が描画エリアだと思い込んで、勘違いしやすいと思います。そして明かにこの勘違いによって、座標系設定を
ViewWindow 0,127,0,0,63,0
としているプログラム例をホームページやブログでたまに見かけます。Casio Basic の動作を正しく理解していれば、そしてタイプミスでなければ、このような設定にはしないと思います。
目的のプログラムが目的通りに動作すれば、目くじらを立てることもでありませんが、たまたま問題が表面化していないので、間違いに気付かないだけの可能性が大いにあります。というのも、この設定にはプログラム通りに描画されない可能性を内包していて、要注意なのです。
描画のために設定した座標値から整数のピクセル座標値 に換算する計算過程から、この問題の可能性を想像できると思います。問題の具体例は以下で紹介します。
さて、今回の目標の描画は、以下のものです。

拡大してみると、
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
このように、点線の点が左右、そして上下に交互にずれるように描画する必要があります。
プログラム DLINE2.1 で分かったように、ピクセルを ON にしたい点の座標を、SketchDot F-Line の3つめと4つめパラメータで指定すれば良いので、例えば以下のようにすれば良さそうです。
ViewWindow 0,126,0,0,62,0
SketchDot F-Line 0,0,126,0
SketchDot F-Line 0,1,125,1
とすると、画面の一番下は X = 126 の位置のピクセルが ON、その1つ上は X = 125 の位置のピクセルが ON になるので、ON/OFF パターンがうまくずれてくれます。
試しに、点線を下から4本、パターンをずらして描画してみます。
ファイル名: DLINE2.3
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
Sketch F-Line 0,0,126,0
Sketch F-Line 0,1,125,1
Sketch F-Line 0,2,126,2
Sketch F-Line 0,3,125,3
Sketch F-Line 0,4,126,4
⇒ ダウンロード: DLINE2.3
これを実行すると、

確かに、点線の ON/OFF パターンが交互になっていますね。
では、この調子で、画面全体に点線を描画させましょう。
ファイル名: DLINE2
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,62,0
For 0→Y To 62
SketchDot F-Line 0,Y,126-MOD(Y,2),Y
Next
⇒ ダウンロード: DLINE2
下から上まで連続的に 点線を描画するため、For ループを使っています。
⇒ Casio Basic コマンドリファレンス - For ループ 参照
ポイントは、SketchDot F-Line の3つめのパラメータです。ここでは MOD( ) 関数を使っています。MOD(Y,2) は、Y を 2 で割った余りを計算します。Y が偶数の時、2 で割った余りは 0 なので 126-MOD(Y,2) は126、奇数の時は、2 で割った余りは 1 なので 126-MOD(Y,2) は125 になり、Y の値から自動的に ON にしたい右端のピクセルの位置が計算できます。
MOD 関数
・書式: MOD (N,R)
- N を R で割った余りを計算する。
- N、R は整数。整数でないとエラーになる。
- N、R には、関数、式、変数、、数値が使える。
これを実行すると、点線が下から上へ描画され、以下のようになります。

さて、DLINE2 を少し変更して、以下のプログラムを実行してみましょう。
ファイル名: DLINE3.1
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,63,0
For 0→Y To 63
SketchDot F-Line 0,Y,126-MOD(Y,2),Y
Next
⇒ ダウンロード: DLINE3.1
上で、こうするとプログラム通りに描画されない可能性があると上で指摘した問題を、実際に試してみます。
ViewWindow座標系の Y方向(上下)の幅を 63 に拡大し、点線を Y座標値(上下位置)0 から 63 まで描画させます。
これを実行すると、以下のようになります。

画面中央がプログラムで意図した点線ではなく、Normal スタイルの線になっています。
==========
この横線が描画されている Y座標値を調べるために、DLINE3.1 を少し改造して、以下のプログラムにして実行してみましょう。
ファイル名: DLINE3.2
ClrGraph
CoordOn
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,63,0
For 0→Y To 63
SketchDot F-Line 0,Y,126-MOD(Y,2),Y
Next
Plot
⇒ ダウンロード: DLINE3.2
CoordOn を設定しておいて Plot コマンドが一旦停止すると、十時カーソルが現れ、その位置の座標値が表示される機能を使います。
これを実行すると、以下のようになります;

Plot はプログラムの最後にあるので、一旦停止になっていて、十時カーソルを動かすと座標値が表示されます。このようにパラメータ無しで Plot コマンドが一旦停止になると、画面の中央に十時カーソルが現れる仕様です。Plot はデバッグツールとして役立つと思います。
カーソルはちょうど異常な線の上にあり、Y座標値は Y=31.5 と表示されています。このあたりで何か意図しないことが起きているようです。
そこで、Y=30 まで点線を連続描画させ、そこで一旦止めて、[EXE] を押すたびに点線を1本づつ描画させるようにして、描画の挙動を詳しく確かめるために、プログラムを改造します。
さらに幾つかの数値に注目して、それを表示させるようにします。

注目する数値は、以下のものです。
- Y : プログラムで点線を描画する Y座標値(上下位置)。プログラム上、正しく指定している。
- Ydot : これは Xdot と同様に 1ピクセルに相当する Y座標値。Casio Basic では変数 Ydot が準備されていないので、Xdot を得る方法と同じ計算で Ydot を求めます。下端と上端のピクセル中心間の距離は 62pix (上図参照)。一方、最下端と最上端の距離は、今の ViewWindow 座標系では 63 です。従って、Ydot = 63/62 と算出できて、1 にならない。そもそもこれが原因。
- Y/Ydot : 点線を描画する Y座標値を Y で指定している。Y/Ydot を計算して、Y座標値を pix 単位に換算する。今の場合、Ydot は整数でないので、Y/Ydot も整数でなくて小数となる。Y/Ydot = Y/(63/62) = 62Y/63 と算出できる。
- Ypix : 実際に描画されるピクセル位置の値が Ypix で、これは整数値でなければならない。そこで Y/Ydot を小数点1桁で四捨五入したものを Ypix とする。Ypix = Round(Y/Ydot) = Int(Y/Ydot +0.5) = Int(62Y/63 + 0.5)で算出する。
ファイル名: DLINE3.3
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,63,0
For 0→Y To 63
SketchDot F-Line 0,Y,126-MOD(Y,2),Y
If Y≥30:Then
Text 1,1,"Y= "
Text 1,10,Y
Text 7,1,"Ydot= "
Text 7,22,63÷62
Text 13,1,"Y/Ydot= "
Text 13,30," " (スペース12個)
Text 13,30,62Y÷63
Text 19,1,"Ypix= Round(Y/Ydot "
Text 19,80,Int (62Y÷63+0.5)◢
IfEnd
Next
⇒ ダウンロード: DLINE3.3
これを起動すると、先ずは以下の画面が表示されます;

ここで、着目した数値は以下のようになっています。
Y=30
Ydot=1.016129032
Y/Ydot=29.52380952
Ypix= Round(Y/Ydot)= 30
プログラムでは最後に描画した点線の Y座標値(上下位置) Y は、Y=30 となっています。
Y/Ydot は、30から少しずれているが、四捨五入した Ypix は 30 となっていて、設定位置と同じ値になっています。
そして、実際に点線は正常に描画されています。
ここで、[EXE] を一回押すと;

点線が1本追加され、正常に描画されます。着目している数値の表示は以下;
Y=31
Ydot=1.016129032
Y/Ydot=30.50793651
Ypix= Round(Y/Ydot)= 31
プログラム上、点線を1本追加しているので、Y = 31 は正常、プログラムに問題はありません。
Y/Ydot は、ほぼ 30.5 になって、ズレが大きくなっていますが、四捨五入するとギリギリ 31。
Ypix は、なんとか 31 になっていて、実際に点線が描画された Y座標値(上下位置)は、プログラム上の設定値 Y と等しくなっています。
[EXE] をもう一回押すと;

異常な横線が現れました。既に一番上のあった点線の上に、新たな点線が上書きされて、Normal スタイルの線に変化したように見えます。
着目している数値は;
Y=32
Ydot=1.016129032
Y/Ydot=31.49206345
Ypix= Round(Y/Ydot)= 31
Y=32 になっているので、プログラム上は正しく動作しています。
Y/Ydot が 31.5 未満なので、四捨五入しても 32 にならない。ズレが大きくなってついに破綻した模様。
従って、Ypix=31 が 示すように、物理的な描画は Y座標値(上下位置) 31 になっている。点線が同じ Y座標位置に上書きされたことを裏付けています。

分かりにくいかも知れないので、図を見ながら、もう一度描画挙動を追いかけてみます。
ピクセル1個あたりの Y座標値(Ydot)をこの座標系での値に換算すると、Ydot = 63/62 = 1.016... と 1 よりも多くなります。
プログラムで Y=30 に対して、対応するピクセル位置 Ypix (整数値)を割り出すために、fx-9860GII 内部で、先ず 指定した Y をピクセル1個の座標値 Ydot で割って、ピクセル座標系の位置 Ypix = 30.507... を得て、これを四捨五入して得られた整数値 Ypix = 31 の位置に描画します。
次に、1増やした Y=31 に対応するピクセル位置 Ypix (整数値)を割り出すために、同様に Y を Ydot で割って 31.492... を得るものの、四捨五入すると、Ypix = 31 と、同じ位置になってしまいます。
従って、Y=30 の時と、Y=31 の時は、共に Ypix=31 の位置に点線を描画しますが、これら2つの点線は ピクセル ON/OFF パターンが逆になっているので、ON と OFF のピクセルを互いを埋めた結果、Normal スタイルの線になったわけです。
DLINE3.3 を再起動して、点線が Ypix=31 の位置に上書きされる様子を確認できます。
今回の異常な描画結果は、プログラムの問題 (バグ) ではなくて、実際の描画メカニズム、つまり内部仕様の結果だと分かりました。
もし、ViewWindw座標系の上下幅をもっと大きくすると、プログラムで指定する描画位置に対して、実際の描画位置は、さらに大きくズレることが十分に考えられます。
そこで、ViewWindow座標系の設定で、最下端を 0 、最上端を自由に設定した時、点線の描画位置がどのように破綻するのかを確認するプログラムを作ってみました。DLINE3.3 をベースに改造したので、あまり美しいロジックではありませんが、実用的なグラフィックスプログラミングを作るための、準備・練習のために作りました。3つの工夫を追加しています。
このプログラムでは、点線の追加だけでなく、削除もできます。Casio Basic には線の削除を行うコマンドが無いので、点線を描画するたびに画面コピーをとっておき、1つ前の画面コピーを表示することで、点線を削除したのと同じ効果を狙います。これには、StoPict / RclPict コマンドを使います。但し画面コピーできる枚数には制限があります。Casio Basicの仕様上、最大20枚です。しかしメインメモリに余裕がなければ、保存できる画面コピーの枚数はさらに減ります。従って、プログラムの最初で、1~20 の間の整数を入力させて、画像コピーの最大枚数を指定します。ちなみに、私の fx-9860GII はグラフィックスコマンドを色々と試すために多くのプログラムが保存されていて、画面コピー20枚も保存できない事情があって、20 以下の値を設定する必要があったので、このようにしていて、お行儀の良いプログラムになったと思います。
もう一つの工夫は、ViewWindowで設定する画面上端の Y座標値を自由に設定する点です。これまでは 63 の場合をみてきましたが、より大きな数を設定した時の異常の挙動を調べられるようにします。
3つめの工夫は、上記設定後、プログラムが走り出した時はフリーランで連続的に点線の追加表示を行い、異常が見つかったら [(-)] キーで表示を一旦停止する点です。fx-9860GII のノーマルクロックでは、グラフィックス描画が比較的遅いので、このようにしました。
一旦停止後は、[▲] キーで点線を上に1本追加、[▼] キーで一番上の点線を1本削除します。異常発生の前後で、点線をの追加と削除を繰り返すことができて、その際の注目数値の変化も確認しながら、じっくりと異常の挙動を調べられます。
フリーラン後は、[EXIT] で正常終了します。さらに、フリーランでの連続描画および[▲] キーで描画する点線が画面上端を超えると、正常終了します。
一応、実用プログラム作成を意識した作りにしました。
先ずは、入力するかダウンロードして、以下のプログラムを実行してください。
ファイル名: VW.LINE3
"Y-Value/V-Win Top"?→V
"Max Pict# (1-20)"?→Q
1→F:V→S
ClrGraph
CoordOff
GridOff
AxesOff
LabelOff
ViewWindow 0,126,0,0,V,0
Text 1,90,"Pict#:"
Text 1,115,Q
Text 7,90,"Y-Val:"
Text 7,115,V
0→L
For 0→Y To V
SketchDot F-Line 0,Y,126-MOD(Y,2),Y
If F=0:Then
Text 1,1,"Y= "
Text 1,10,Y
Text 7,1,"Ydot= "
Text 7,22,V÷62
Text 13,1,"Y/Ydot= "
Text 13,30," " (スペース13個)
Text 13,30,62Y÷V
Text 19,1,"Ypix= Round(Y/Ydot "
Text 19,80,Int (62Y÷V+0.5)◢
IfEnd
Whle 1
Do
F⇒Break
Getkey→K
LpWhile K=0
While Getkey
F⇒Break
WhileEnd
If FS:Then
MOD(Y,Q)+1→P
StoPict P
Y-Q+2→L:Y<Q-2⇒0→L
S-1→S
While Getlkey=41
0→F:Break
WhileEnd
Break
Else If K=47:Then
ClrText
Locate 9,5,"bye!"
Retuen
Else If K=28:Then
MOD(Y,Q)+1→P
StoPict P
L→M
Y-Q+2→L:Y<Q-2⇒0→L
L<M⇒M→L
Break
Else If K=37:Then
If Y=0:Then
-1→Y:break
IfEnd
If Y≦L:Then Y+Q→Y
MOD(Y-2,Q)+1→P
Else
MOD(Y-1,Q)+1→P
IfEnd
Cls
RclPict P
Y-2→Y
Break
IfEnd:IfEnd
IfEnd:IfEnd
WhileEnd
Next
ClrText
Locate 9,5,"bye!"
⇒ ダウンロード: VW.LINE3
プログラムの動作について、簡単に紹介します。
プログラムを起動すると、

Y-Value/V-Win top?
と表示されますが、これは、ViewWindow 設定での 画面上端の Y座標値の入力を求めています。これまでは、63 の時の挙動を調べましたが、65, 70 など大きな数を入力してどうなるのかを調べられます。今は、65 を入力してみます。
入力して [EXE] を押すと、

今度は、
Max Pict# (1-20)?
と表示され、点線削除のための画面コピーの最大枚数を 1~20 の範囲の整数で入力します。
ここでは、10 を入力して [EXE] を押してください。
すると、破線が下から上へ連続的に描画されてゆきます(スキャンモード)。
ここで、異常が現れたら [(-)] キーを押して、描画を止めて下さい。

描画が止まり、着目している数値も表示されます。
ここで、[▼] キーを押すと、一番上の点線が消え、着目している値も変化します。

異常の線が一番上に来るまで [(-)] を何回か押してください。

着目している数値のうち、Y と Ypix を見ると、Y=11、Ypix= Round(Y/Ydot) = 10 と表示されています。Y と Ypix が一致していないので、確かに異常です。
もう一度 [(-)] キーを押すと、

Y と Ypix がともに 10 になって一致し、描画の異常も消えました。
ここで、[▲] を押すと、

上に点線が追加され、また異常が戻りました。
このようにして、異常の発生状況を、繰り返し確認できます。
なお、グラフィックスが描画されている時に [EXIT] を押すと、

と表示して、正常終了するようにしています。
さらに、最初のフリーランによる点線の連続描画で、[(-)] を押さずに放置する時、および [▲] で最上端に点線を描画したあとさらに [▲] を押した時も、プログラム上は最上端描画の後にさらに点線を描画しようとすると正常終了するようにしています。
[▼] キーで点線を削除するために使う画面コピーの枚数は限られます。仮に 10 枚保存している場合、一番上の点線を含めて10本分の点線しか削除できないので、11本目を削除しようとすると、一番上の点線が描画された画面に一気に戻ることで、誤動作を防いでいます。
==========
ViewWindow 設定の画面上端の Y座標値を、70 など大きな数を試すと、1画面で異常が何度も発生することが分かります。例えば、65 にすると、異常が3回、70 にすると異常が8回現れます。異常がが現れる回数が多くなるほど Y と Ypix のズレはさらに大きくなることが確認できます。
==========
ところで、万一メモリ不足でエラーになった場合は、画面コピーのデータを削除する必要があります。
エラーの出たプログラムを [AC] で強制終了し、[MENU] を押して MAIN MENU を表示します。

ここで MEMORY アイコンを選択して [EXE] を押して、Memory Manager 画面を表示します。

続いて [F1] (F1:Main Memory) で、Main Mem を表示します。

残りメモリが 17144バイト だと表示されています。
<PICTUR> があります。これは、StoPict コマンドで画面コピーした画像データが入ったフォルダです。
そこで、矢印キーで、<PICTURE> にカーソルを合わせ、

[F1] (SEL) を押すと、

<PICTURE> が選択され、左に ▶ マークが付きます。
ここで、[F6] (DEL) を押すと、

ポップアップ画面が現れて、選んだデータを全て削除しますか?と聞いてくるので、[F1] (Yes:[F1]) を押すと

<PICTUR> フォルダが削除され、残りメモリが 37824バイト に増えました。
[MENU] で MAIN MENU に戻り、

PRGM アイコンで Program List 画面へ移ります。
==========
座標系の座標値からピクセル座標への換算計算で、うまく割り切れない時に、意図した描画ができないケースを条件を変えて再現する目的で、このプログラムを作りました。
それだけでは面白くないので、実用的なグラフィックスプログラムを想定して、画面コピーの使いこなしを試みました。一応、構造化プログラミングになっています。ここ重要 (^_-)
PCと異なり、fx-9860GII では、画面コピーの枚数には限りがあるので、例えば、Pict 1 から Pict 10 を有効活用する方法を試しました。Pict 1 から順に画面コピーをしてゆき Pict 10 まで使った後は、Pct 1 へ戻って順に上書きするようにしています。いわゆる「リングバッファ」とか「リングメモリ」と言われる手法で、限られたリソースを有効活用するものです。
実際は、点線を1本描画するたびに、画面コピーして、Pict 1 から順に Pict 10 までコピーしてゆきます(画面コピー枚数が 10 枚の時)。Pict 10 の次は Pict 1 へ戻って上書きしてゆきます。
変数 P を Pict# とし、Pの初期値は1、その後10まで1つづつ増やし、11 の代わりに P を 1 に戻します。点線描画の Y座標値から、Pict # である P を割り出すのに 剰余系の考え方を使っています。 画面コピーの最大枚数を Q に入れておき、Mod(Y,Q)+1→P で Pict# P を計算しています。For ループの中で動作させるので、状況に応じて Y の代わりに Y-1 や Y-2 から P を計算しています。
このリングバッファの管理のために、変数 P を現在の Pict# を示すインデックスとして使い、保存している画面コピーの中で点線が一番少ない時に最も上にある点線位置の Y座標を 変数 L で管理し、点線を追加描画する時に L を更新します。L の更新を正しく行うために、変数 M も使っています。L より下の点線を削除しようとした時は、削除せずに 保持している画面コピーで一番上まで点線が描画されている画面を表示するので、一気に点線が植えたようになります。
リングバッファの使い方としては、あまり良いサンプルではないのですが、興味のある方は、プログラムをじっくりと見てください。プログラム DLINE3.3 に無理矢理リングバッファを実装しています。 プログラミング本でリングバッファと言えば、必ず配列を使ってインデックス管理していますが、fx-9860GII ではアクセス速度が遅い行列やリストを敢えて使わないようにして、単なる変数でインデックス管理をしています。従って、決して美しい方法では無いのですが、Casio Basic に合わせた実装方法として、試しに作ってみました。
今回のまとめ
- F-Line x1,y1,x2,y2 は、座標 (x2, y2) から (x1, y1) へ向かって描画される。
- SketchDot F-Line x1,y1,x2,y2 は、先ず (x2, y2) に対応するピクセルを ON にし、(x1, y1) へ向けて、ピクセルを交互に ON/OFF にしてゆく。
- SketchDot F-Line x1,y1,x2,y2 や SketchBroken F-Line x1,y1,x2,y2 は、ピクセルを ON にしたい座標 (x2, y2) を指定することで、ON/OFF のパターンを制御できる。
- 物理座標系は、物理的大きさを持つピクセル座標系から大きさの概念を取り払い、抽象化した座標系。ピクセルに1対1対応した整数のみを座標値として使え、範囲外の整数や小数を座標値に設定するとエラーになる。
- 論理座標系では、座標値の違いが 0.1 未満の場合は小数点以下2桁目で四捨五入され、0.1 刻みに換算される。一例として、座標 (0.05, 0) と (0.1, 0) 同じピクセルを描画する。
- ViewWindow 座標系では、設定によっては、座標 (X, Y) とピクセル位置 (Xpix, Ypix) が必ずしも1対1に対応しない。
- ViewWindow 座標系で 座標 (X, Y) とピクセル座標 (Xpix, Ypix) が1対1に対応しない時、期待した描画結果にならないことがある。
今回使ったグラフィックス コマンド
- F-Line
- SketchDot
- MOD ( )
- StoPict / RclPict
つづく...
⇒ Casio Basic入門 G08 / 目次
応援クリックをお願いします。励みになるので...