プログラマーが使う高校数学(その3)

2026年04月27日
社員のつぶやき

皆さん、こんにちは。システム商品開発グループの入澤です。
暖かな日差しで満開に咲いた桜が、強風と雨で儚く散っていきました。暦の上では春が終わりを告げて夏に向かっていきます。着る服に困る今日この頃です。

さて、本題に進みまして今回も数学のお話に少々お付き合いください。グラフィクスの処理に不可欠な計算の一つに「注目している位置から最も近い対象を探す」というものがあります(ベクタ/ラスタの種類に限らず)。人間は画像をぱっと見ただけで全体の位置関係を瞬時に把握しておおよその近さを無意識に比較できます。しかし、すべてが数値だけで表現されたプログラムの世界ではそうもいきません。例えば、次のような状況を考えてみましょう。

 

平面上に重ならない2点 P 1 = ( x 1 , y 1 ) P 2 = ( x 2 , y 2 ) をとり、水平線 L h : y = h の上を動く注目点 Q = ( x , h ) からどちらが近いかを求めます。具体的なイメージとしては、ラスタ画像で横一列のピクセルを順番に調べながら近い方の点に応じた処理をする(そしてそれを全行で繰り返す)ような感じです。単純に距離を都度比較して判定するだけでも目的は達成できますが、効率が悪すぎるのでもっといい方法を模索してみましょう。

固定された2点に対して任意の座標からどちらが近いかは、2点間の垂直二等分線 L 12 で分かれるどちらの半平面にあるかに還元できます。

L 12 : ( y 2 y 1 ) y + ( x 2 x 1 ) x + 1 2 ( x 1 2 x 2 2 + y 1 2 y 2 2 ) = 0   ...   Eq.1

さらに水平線 L h 上に限定すると、 L 12 L h の交点X座標 x 12 を境にどちらの半直線にあるか、ということになります。Eq.1に y = h を代入して x について解けば x 12 が求まります(※ x 2 = x 1 のときは L 12 も水平線になるので交点がありません)。

x 12 = x 2 2 x 1 2 + y 2 2 y 1 2 2 ( y 2 y 1 ) h 2 ( x 2 x 1 )   ...   Eq.2

では、もう1点 P 3 = ( x 3 , y 3 ) を追加した場合はどうなるでしょうか。

考えなければならない垂直二等分線が3本( L 12 L 13 L 23 )に増え、水平線 L h 上の交差X座標( x 12 x 13 x 23 )の関係も複雑になります。点の数が n 個なら組み合わせとして n ( n 1 ) / 2 本になり簡単には扱いきれません。そこで、少し視点を変えて距離に着目してみましょう。点 P i   ( i = 1 , 2 , , n ) から水平線 L h 上の任意の点 Q = ( x , h ) までの距離は ( x i x ) 2 + ( y i h ) 2 と表せます。今 h は定数なので変数 x の二次関数として次を定義してみます。

F i ( x ) := ( x i x ) 2 + ( y i h ) 2   ...   Eq.3

加えて、 P i x i が互いに異なり小さい順に並んでいると仮定します。つまり x 1 < x 2 < < x n です(※X座標が同じ点はY座標が水平線に近い方しか関与しないのであらかじめ除外しておき、小さい順になるよう番号を振り直す感じです)。この関数の集合 { F i ( x )   |   i = 1 , 2 , , n } を使うと、水平線 L h 上の任意の点 Q = ( x , h ) から最も距離が近い点 P k を探す問題が、入力 x において最も下側にある関数 F k ( x ) を見つける問題に読み換えることができます。とは言え x が与えられるたびに都度すべての F i ( x ) を比べようとすると n ( n 1 ) / 2 回かかってしまうので、水平線上で各点 P i が最も近くなる区間の集合として先に計算することにします。

最初の2点 P 1 , P 2 に対しては、Eq.2で求めた x 12 で2つの区間 ( , x 12 ] , [ x 12 , ) に分かれます。ここに P i を追加することを考えましょう。 F 3 ( x ) F 1 ( x ) , F 2 ( x ) とどのように交差するか( x 12 , x 23 , x 13 の関係性)は、次のような手順で調べることができます。

  1. F 3 ( x 12 ) > F 2 ( x 12 )     x 23 > x 12     ( , x 12 ] , [ x 12 , x 23 ] , [ x 23 , )
  2. F 3 ( x 12 ) F 2 ( x 12 )     x 13 x 12     ( , x 13 ] , [ x 13 , )

とくにケース2を見ると F 2 ( x ) が区間を持たなくなり、水平線 L h と点 P 2 が最も近くなる位置は存在しなくなります。しかも P 4 , P 5 , , P n を追加したとしても変わることはありません。次々と点を追加していって作られた分割済みの区間 ( , x i 1 i 2 ] , [ x i 2 i 3 , x i 3 i 4 ] , , [ x i m 2 i m 1 , x i m 1 i m ] , [ x i m 1 i m , ) に点 P j を追加するたびに、 F j ( x ) がどこの区間をより細かく分割するのかを右から順に一対一で比較して探すことになります。上記のケース2のように F j ( x ) が入り込む位置によって、それより値の大きい区間は消えて紐付けられていた点も以降は考慮する必要がありません。

このように、右から比較して一度でも通り過ぎた区間に対応する点は考慮する必要がない、という性質から P 1 , P 2 , , P n に対して L h 上の区間を求める処理は比較と交差X座標の計算を合わせても n の定数倍程度の回数で済みます。ラスタ画像では n 10 4 の入力を扱うことも多く、 n ( n 1 ) / 2 10 8 n c 10 4 c     ( c n ) の違いは歴然です。使われている数学自体は簡単なはずなのに、この手法に初めて触れたとき衝撃を覚えました。

今回は少しプログラミング(アルゴリズム)寄りの内容になりました。テーマとして扱った「注目している位置から最も近い対象を探す」という処理はなかなか奥が深く、対象が多くなったとしても如何に効率良く探索できるかが常に問われているのです。以上、お付き合いいただきありがとうございました。プログラマーが日々何に取り組んでいるのか、一端だけでも知っていただけたら幸いです。

月別アーカイブ