NoWestさん、レス有難うございます。
早速頂いたレスを読ませてもらっていたのですが、ただ、
「何故、同じように始点と終点がセットされたライン描画が
時と場合により①と②のように違うピクセルを点灯して描画
されるのか」ということが分からないでいました。
結局のところラインを引くのに必要な情報は「始点」と「終点」。
直線を描画するアルゴリズムに他に偶然的な要素が入る余地は無い
と思うので、もし座標(0,0)-(2,1)にラインを描くとすると例えば
①のようにピクセルを点すアルゴリズムならその後何度実行しても
①のように、また、もし②のようにピクセルを点灯するアルゴリズム
ならその後何度実行しても②の様に同じように描かれる筈じゃないか、
と思って。実行した時によって①になったり②になったりというのは、
どうにもしっくり来なかったんです。
とりあえず直線を描画する関数を自作してみたんですが、
(x1,y1に始点、x2,y2に終点をセットしてDrawLineをコールしてみて
下さい。)
(ここにソースが表示されます) [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]
コード: 全て選択
#prompt
Dim x1 As Long
Dim y1 As Long
Dim x2 As Long
Dim y2 As Long
Dim col As DWord
Dim hPromptDC As HDC
x1=0
y1=0
x2=2
y2=1
col=RGB(255,255,255)
hPromptDC=GetDC(_PromptSys_hWnd)
DrawLine(hPromptDC, x1,y1,x2,y2, col)
ReleaseDC(_PromptSys_hWnd,hPromptDC)
'
'●ライン描画
'
Function DrawLine(ByVal hDC As HDC, ByVal x1 As Long, ByVal y1 As Long, ByVal x2 As Long, ByVal y2 As Long, ByVal col As DWord) As Long
Dim fx As Long
Dim fy As Long
Dim vx As Long
Dim vy As Long
Dim x As Long
Dim y As Long
Dim s As Long
Dim i As Long
fx=Sgn(x2-x1)
fy=Sgn(y2-y1)
vx=Abs(x2-x1)
vy=Abs(y2-y1)
x=x1
y=y1
s=0
If vx>vy Then
For i=0 to vx
SetPixel(hDC,x,y,col)
x=x+fx
s=s+vy
If s>=vx Then
s=s-vx
y=y+fy
End If
Next i
Else
For i=0 to vy
SetPixel(hDC,x,y,col)
y=y+fy
s=s+vx
If s>=vy Then
s=s-vy
x=x+fx
End If
Next i
End If
End Function
この直線描画のアルゴリズムはどこにでもある、最も基本的なものの
一つだと思います。確か自分が知ったときには
「多くの場合コンピューター内部ではこのようにして直線を描画
している」とあったように記憶しています。
このルーチンを使って(0,0)-(2,1)のラインを引くと、
まず間違いなく「①」のようにピクセルが点灯したラインを
描画します。その後何度やっても①となり、決して②のようには
描画されることはありません。(「始点」と「終点」を入れ替えでも
しない限り。)
いずれにしてもこのようなコンピューターの処理において、
"①になったり②なったり"とというような「偶発的」な要素が
入り込む余地はないんじゃないかと思ったのですが。。
もう一つ気になるのが、処理速度の問題です。
①と描画される時と、②と描画される時であまりにも差がある
場合があるのでどうしてなんだろうかと思っています。
今のところ速度について分かっているのは次のようなことです。
「①のように描画される時、プログラムは非常に速く実行
される時と、非常に遅く実行される時がある」
「②のように描画される時、プログラムは①の"非常に遅い時"
よりもやや速い程度で実行される」
「①の"非常に速い時"と"非常に遅い時"の速さの差は
ひどいとき10倍以上あるように感じられる」
(速さの差がライン描画に起因するものなのかどうかは全く
分かりません。ので「ライン描画の速度」とせず
「プログラムの実行速度」と書きました。)
元々はこの"プログラムは全く改変していないのに実行速度が
時と場合であまりにも違う"ということを調べていて、
そうする内にラインの点灯ピクセルがどうも同様に違うみたい
だと。
当初はその時々の速度の違いは「ハードディスクがひどい
フラグメンテーションでも起こしてて、その関係で」かとも
思っていたんですか、ラインの描画具合が違うということに至って、
これは何か直さなければならない所があるんじゃないかと
思ったんです。
先に投稿した質問に記載のテストプログラム(メインウインドウと
プロンプトウインドウに(0,0)-(2,1)のラインを描画するもの)で
現在実行していて頻繁に現れるパターンは
「メインに①、プロンプトに②が描画され」、
「実行後前面に来ているプロンプトウインドウを
何か他のウインドウで一旦隠してから、もう一度前面に持って
くると②だったラインが①に変わっている」というものです。
プロンプトへはABが見えているスクリーンと
バックメモリスクリーン両方に二度描画を行うのでその際に変化が
起こっているものと考えますが、やはり不思議に感じられます。
ただしいつもいつもこのように出るのかといえばそうでは無く、
「メインに②が、プロンプトに①が」というときもまま見られます。
いずれにしてもこの問題が
「プログラマにはどうしようもない問題」ということならば
あきらめざるを得ない、ことですね。
自作の関数を使うか、どうにかして方法を探りたいと思っています。
それから、takさん、レス有難うございます。
1. に関して、他の環境にプログラムを持って行ったら違った描画になる
ことも考えられます。
ドキュメントなどで動作結果が厳密に保証されているわけではないので、
GDI を使う限り諦めるしかないです。
2. についても、それがよほど大問題でなければ受け入れるしかないでしょうね。
そもそも速度的にシビアなプログラムなら GDI は使うべきでないです。
では何を使えばよいか、というのは既にNoWestさんが提案されているとおり。
あきらめざるを得ないというのは自分にとっては少し残念な結果
なんですが、、やっぱり仕方ないことなんですね。
正直なところGDIが"一定の描画結果を得られる保証がない。"ってのは
ちょっと後ろ髪を引かれる思いでいます。
最近やっと、どうにかこうにかGDIが使えるようになってきたかって
所だったので。(笑)
いずれにしても「CreateDIBSection()」で描画関係を自作。
ちょっと道は険しそうですが出来れば少しずつやっていきたいと
思います。
長くなってしまいましたが
NoWestさん、takさん、レスありがとうございました。
またよろしくお願いします。