エルミート曲線
- 2018/04/16 01:50
-
典型的なパラメトリック曲線の一種である, エルミート曲線についてのメモ.
パラメトリック曲線
そもそもパラメトリック曲線とは, 任意のパラメータから各々の座標を陽関数形式で表現できる曲線のことをいう. このとき定義できる関数 がパラメータ 1 の多項式である場合, それを多項式曲線といい, 有理式である場合, それを有理曲線という. 例えば, 直線の方程式 は,
とパラメタライズできる. この方程式では, パラメタライズせずとも, に 1 つの実数を代入すれば, 必ず が求まる(逆も言える)ことは明らかである. 次に, 3 次曲線 について考える. に 1 つの実数を代入すると, は,
- のとき ,
- のとき ,
- のとき複素数
となり, の値によっては, グラフが存在しない. これを
とパラメタライズすることで, 任意の実数 に対するグラフ上の一点を定めることができる2.
エルミート曲線
エルミート曲線は, 始点 とその速度ベクトル , 終点 とその速度ベクトル を与えたときに, 始点と終点の間をつなぐ 3 次パラメトリック曲線である. 3 次パラメトリック曲線と言うからには, これを一般の 3 次多項式で表現できるはずである. パラメトリック曲線は と をそれぞれ別々に扱えるので, まず について考える. 4 つの係数, が得られれば, 任意の に対するエルミート曲線の が得られるはずである. まず, 始点の座標を求める. のときを始点, のときを終点としたとき, のときに始点の座標, のときに終点の座標が得られることは明らかなので, に , および に を代入して次の二式が得られる. ここで, ある地点 での曲線の傾きを求めるために, 一階微分した次の式を得る. 始点 () と終点 () をそれぞれ式 の に代入し, 始点における曲線の傾きと, 終点における曲線の傾きが得られる.
式 に式 , を, 式 に式 を代入すると, 次の二式が得られる.
式 , の連立方程式を解くと,
となる. 式 を式 に代入すると であるから, 式 から に対するエルミート曲線の が取れることがわかった. についても, を に, を にすると, 同様にして得られるから
がいえる.
さらに, から ( についても同様) の係数にそれぞれ着目して, 次のように定義する.
- の係数に着目し, , これを とする
- の係数に着目し, , これを とする
- の係数に着目し, , これを とする
- の係数に着目し, , これを とする
すると, 先ほど導出した の式は次のように定義できる.
エルミート曲線
これは, 3 次エルミート多項式によるエルミート曲線の定義と同義である.
実際に描く
始点 での速度ベクトルを , 終点 での速度ベクトルを として, 上記に導いたエルミート曲線に従い, 点を打ってみた3.
{-# OPTIONS_GHC -Wall #-}
module Main where
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Control.Monad (forM_)
import Control.Arrow ((&&&))
type Float' = GLfloat
linspaceWithDensity :: Float' -> Int -> Int -> [Float']
= let distance = round (realToFrac (abs et + abs bt) / density) in
linspaceWithDensity density bt et take distance $ iterate (+density) (realToFrac bt :: Float')
-- | The function that generates a coordinate list of Hermite curve according to
--
-- the start point, the velocity vector of the start point, the end point, the velocity vector of the end point,
-- the density of the points and the range of @t@ (@bt <= t <= et@).
hermite :: (Float', Float') -> (Float', Float') -> (Float', Float') -> (Float', Float') -> Float' -> Int -> Int -> [(Float', Float')]
= ((map (herX &&& herY).).).linspaceWithDensity
hermite st stVec ed edVec where
= (2 * t + 1) * (1 - t)^2
h30 t = t * (1 - t)^2
h31 t = -t^2 * (1 - t)
h32 t = t^2 * (3 - 2 * t)
h33 t = h30 t * v1 + h31 t * v2 + h32 t * v3 + h33 t * v4
hermite' t v1 v2 v3 v4 = hermite' t (fst st) (fst stVec) (fst edVec) (fst ed)
herX t = hermite' t (snd st) (snd stVec) (snd edVec) (snd ed)
herY t
resize :: Size -> IO ()
@(Size w h) = do
resize s$= (Position 0 0, s)
viewport
loadIdentity-w') w' (-h') h' (-1.0) 1.0
ortho (where
= realToFrac w / 200.0
w' = realToFrac h / 200.0
h'
disp :: IO ()
= do
disp ColorBuffer]
clear [Color3 0 0 0 :: Color3 GLdouble)
color ($= 1.0
pointSize Points $ forM_ hcurve (vertex.(uncurry Vertex2))
renderPrimitive
flushwhere
= hermite (1, 0) (0, 1) (-1, 0) (0, -1) 0.001 (-2) 2
hcurve
main :: IO ()
= do
main <- getArgsAndInitialize
(progname, _) $= [RGBAMode]
initialDisplayMode <- createWindow progname
_ $= Color4 1 1 1 1
clearColor $= "Hermite curve"
windowTitle $= disp
displayCallback $= Just resize
reshapeCallback mainLoop
次の曲線を得た.
活動継続のためのご支援を募集しています