パスのストロークと結合方法
久方ぶりのUI基本のキシリーズkeroxp.icon2020/8/22 とある事情からパスの境界線(アウトライン)を作成する手法を調べることになったのでまとめる
あらまし
たとえばHTML5のCanvas APIなどでは、以下のようなコードが利用できる
code:js
const ctx = canvas.getContext("2d")
ctx.beginPath()
ctx.moveTo(0,0)
ctx.lineTo(100,100)
ctx.lineWidth = 10
ctx.stroke()
こうするとcanvas上には線幅10pxの線が描かれる
点(0,0)と(100,100)がつながったパスは閉じていないので、領域はない
しかし実際の描画結果は塗りつぶされた領域になっている
https://gyazo.com/7a3264a73e7bccdb0f8b57ef85a7d697
つまりパスのストロークを描画するという処理は、実際はパスから別のパスを作成してその領域を塗りつぶすという処理を行うということなのである
ではあるパスのストロークを描くにはどのような処理が必要になるだろうか?
疑問
https://gyazo.com/9a6917099808b11a9c3a56e3dfbf2657
このようなパスが存在した場合、このパスのストロークはどのようになるだろうか
直感的には、パスの線分をストローク幅だけ拡張させれば良さそうに思える
しかし単純にパスの線分を拡張しただけではうまく行かない
https://gyazo.com/78e503800ed2ac82b4e71680167623f6
なので、パスの結合点を何かしらの方法できれいに繋がなくてはいけない
このような処理をLine Joinという(?正式な名前はわからない)
一般的にLine Joinには3種類の結合手法がある
それがMiter Join, Bevel Join, Round Joinの3つである
それぞれの手法をみていく
下準備
まず、どの手法あっても基本は同じで、パスの線分を両側に線幅の半分ずつ拡張した平行線を引くところから始まる
https://gyazo.com/2fd8ccaed941d532601ac5f9d7b4b140
Miter Join
1つ目はMiter Join(マイター結合)である
マイター結合の特徴としては、角がカクカクと尖るような結合方法である
まず、隣り合う線分の平行線同士の交点を求める
https://gyazo.com/d73a152fe823c5ca7ca85e08dd7e7a96
そしてその交点同士をつなぐ。こうすることで角が尖ったような領域が完成する
https://gyazo.com/90f5a3dd00889dbe899fcb14fdd2205b
Bevel Join
Bevel Join(ベベル結合)は、ベベル(縁取り)という名の通りマイター結合で目立った尖った角を平らにする結合方法である
まずはマイター結合と同様に隣り合う線分の平行線の交点を求めていく
マイター結合と異なるのは、平行線の線分上に交点がない場合は交点を使わないという点である
https://gyazo.com/bfd5b1dd6be1830070c5aa3c457c7f6c
交点が線分上にない場合はもとの線分を延長せずに、終点と次の始点をそのまま結合する
https://gyazo.com/e225d19b052c15e70601d8543f5360c4
こうすることでマイター結合よりも平らな結合点が出来上がる
Round Join
最後はRound Join(ラウンド結合)である
おそらくこれが最も使われるであろう結合方法である
特徴としてはマイター、ベベルとは異なり柔らかく自然な見た目になるという点がある
まずベベルで使った結合点と同じものを算出する
https://gyazo.com/34a011e27c65ca71ab29834bdac25f0e
次に、ベベルで平らにされた2点を線でつなぐのではなく、直径が線幅の円弧でつなぐ
この円弧は、円が2つの線分に接するように描かれるので、角度によらず丸さが同じになるのが特徴である
https://gyazo.com/57dc166f5cae949f3e2b0ae022bf30ca
https://gyazo.com/be5a9dcaae32731509933de0ed8f7c9f
線端の形状
パスの始点と終点は、Line Capと呼ばれ、それらをどのように閉じるかも領域の形状に影響を与える
Line CapはLine Joinにくらべとても単純なので解説は割愛する。以下のような資料を見ればわかる。
おわりに
普段CanvasのAPIやベクターグラフィックスのソフトでよく使っている「パスのストローク」というものだが、改めて考えてみるとなるほどという手法で実現されていることが分かって感心した
ちなみに、
線分ごとに線幅が異なる場合はどうなるか
Bezeir CurveやQuadratic Curveのパスはどのように領域化するか
などはまだよく分かってない
ネット上にこういう資料があれば記事にする必要はなかったのだが、毎度の如く見つけられなかったのでまとめた
補足
見返していて、
マイター結合の結合点は、パスの線分同士のなす角の二等分線上の、線幅の半分の位置になる
ラウンド結合の円弧の円は必ず元のパスの点を中心にした直径線幅の円になる
ということに気がついた
なるほど納得であった