技術解説 |
陰関数の高速描画 |
最終更新日:2007/05/11
新規 |
●概要
従来Tipsで紹介していた方法は、時間が掛かり、ユーザのインタラクティブな処理に対応できない。今回、これを高速化したので紹介する。
●原理
z = f(x, y) とすると、z = 0
となる点の集合がその陰関数のグラフとなる。但し、多価関数になることが多いので、順序を持った点集合(つまり、曲線)としては認識できない。陽関数や、媒介変数関数に展開できない場合、闇雲に
x, y を与えても、z = 0
となるのは奇跡なので、うまい方法が必要となる。
極値でない場合、 z = 0 の前後では、z
は、符号を変化している。例えば、
z > 0 at f(x, y)
z = 0 at f(xt, y)
z < 0 at f(x + dx, y)
である。xt
は、0になる真値で不明とする。しかし、dxで走査し、符号の反転があれば、少なくとも、x
と x + dx の間に z = 0 となる、xt があることになる。dx
が、例えば表示系のピクセル幅以下のような十分に小さければ、x
= xt とできる。y 方向も同様な処理を行えば良い。
●高速化
従来はビットマップで描画しており、サイズも固定で、処理時間が掛かっていたが、今回は、可変サイズでオンライン処理とした。以下のようである。
- x、y の任意の範囲が外部より与えられる。
- その範囲を、1200分割して走査する。1200
は、最大の画面の幅を考慮した値。
- 関数値の符号を求め、一行分を保存。直前行と現在行の二行分を持つ。
- x、y方向で符号の反転点を検出する。検出したら、その点の、関数座標(x,
y) を記録する。
- 全範囲を処理する。
この方法であれば、範囲の変化に対応して、曲線の再演算がほぼリアルタイムで可能となる。
・コード例
dx = (m_VRange.VMax - m_VRange.VMin) / 1200 '関数の変数刻み
dy = (m_FRange.VMax - m_FRange.VMin) / 1200
pp = 0
Dim CMap(1200) As Integer '現在行符号バッファ
Dim PMap(1200) As Integer '直前行符号バッファ
For i = 0 To 1200
Y = m_FRange.VMin + i * dy
Array.Clear(CMap, 0, 1201)
For j = 0 To 1200
X = m_VRange.VMin + j * dx
d = m_FuncXY(X,
Y) '関数値
CMap(j) =
Sign(d)
'その符号を保存
Z = 0
If CMap(j) = 0 Then
Z =
1
'関数0点
Else
If i > 0 Then
If CMap(j)
<> PMap(j) Then
Z =
1
'X方向0クロス点
End If
End If
If j > 0 Then
If CMap(j)
<> CMap(j - 1) Then
Z =
1
'Y方向0クロス点
End If
End If
End If
If Z = 1 Then
ReDim Preserve m_PD(pp)
m_PD(pp).X = X
m_PD(pp).Y =
Y '座標点を保存(DoubleによるPoint構造体)
pp = pp + 1
End If
Next
PMap =
CMap.Clone '現在行を直前行にする
Next
・表示
座標点 m_PD()
があれば、プロットすべき点のみの処理となり、高速に描画できる(元の座標点が100万点あっても、実際に描画すべき点は高々数千程度となる)。座標値は関数での値なので、描画時に、表示領域の物理座標に変換する。
|