HN 日本語サマリー

← 一覧へ戻る
科学・技術

Variable-width Bézier curves (2025)

Variable-width Bézier curves (2025) (luthert.web.illinois.edu)

7 pointsby leduyquang7531 コメント

要約

この記事は、2DグラフィックスAPIで可変幅のベジェ曲線を描画する方法について解説しています。筆者は、大学でのボードワーク(板書)の経験から、スタイラスの筆圧に応じて線の太さを変える機能の重要性を認識し、その実装方法を探求してきました。記事では、筆圧のモデル、線とスプラインの比較、ベジェ曲線の数学的側面、そして可変幅ストロークのアウトライン生成やピクセルチェックによる描画アルゴリズムについて詳細に説明しています。

全文翻訳

Bézier curves

Variable-width Bézier Curves

© 2025-12-30 Luther Tychonievich

[画像: この作品はクリエイティブ・コモンズ 表示-非営利-継承 4.0 国際 ライセンスの下でライセンスされています]

現在の2DグラフィックスAPIでそれらをどのように描画するか、タブレットツールのサポートボード作業に必要なこと。

2013年に大学のクラスを教え始め、すぐにボードワーク(ライブでクラスの前で手書きで描画する)ができるようになりたいと思ったのですが、私の教室には生徒数に見合った十分な大きさのボードがなかったことに気づきました。そこでグラフィックスタブレットを購入しました¹。当初はWacom Intuos 4でしたが、その後いくつかの他のタブレットを購入し、当時存在していた様々なツールを試しました。それらすべてに不満があったため、2014年の夏に自分でボードワークアプリケーションを作成し、改良と書き直しを続けて、現在では8つの完成品があります。うち3つはJavaScriptで²、5つはD3で³です。

この開発経験を通じて、2Dグラフィックスライブラリに重要なプリミティブ、つまりペン幅座標を持つベジェ曲線がないことに常に不満を感じていました。この記事はそのトピックに特化しています。

Pressure

圧力入力は、2D描画プログラムによってさまざまな方法で使用できます。

アートプログラムはしばしば圧力に対して非常に複雑な処理を行い、不透明度やスケールを変更したり、圧力と距離に応じて変化するサンプルからペンプロファイルを選択したりします。これはシンプルなボードワークアプリケーションには複雑すぎます。計算量が多すぎ、ファイルサイズが大きくなりすぎ、近くで見ている人には気が散り、部屋の後ろにいる人には見えにくくなります。

ボードワークに適したほとんどのプログラムは、ストロークの幅を明確なエッジで示すために圧力を使用します。これにより、固定幅のストロークシステムよりもはるかに流動的な筆記や描画が可能になり、視覚的にも鮮明で、計算もシンプルで、後のファイルエクスポートのために高度に圧縮できます。

圧力ベースのストローク幅には、固定軸線形オフセット、ストローク整列線形オフセット、円形オフセットの3つのモデルがあります。

固定軸線形オフセットは、柔軟なペン先を使用した場合の西洋書道の仕組みをシミュレートします。熟練した書家には派手で魅力的に見えるかもしれませんが、ボードワークに必要な可読性には欠けます。

ストローク整列線形オフセットは、ストロークに沿った各点にストローク方向に垂直な線で塗りつぶし、その幅はストローク圧力に依存します。この技術は計算量が少なく、理論的には魅力的な塗りつぶしストローク形状を作成できますが、ほとんどの手の動きやデジタルスタイラスの離散化に伴うノイズやジッターに非常に敏感です。ペンのわずかなオフセットでもストローク方向が任意に変化し、結果のストロークに大きな視覚的影響を与える可能性があります。このジッターに対抗するため、アプリケーションはしばしば平滑化効果を追加します。これは仮想ペンの質量や慣性としてマーケティングされることもありますが、そのような平滑化は、遅く慎重なストロークをうまくレンダリングできますが、高周波の詳細を削除し、速い筆記を乱雑に見せます。

円形オフセットは、ストロークの各点に円を塗りつぶし、その半径はストローク圧力に依存します。この技術はジッターに対して堅牢で、高周波でも魅力的なストロークをレンダリングしますが、線形オフセットよりも計算コストが高くなる可能性があります。

私のボードワークツールはすべて円形オフセットを使用しています。円形オフセットが、この投稿の残りの部分のトピックです。

Line or Spline

ペンデータは、タブレットからオペレーティングシステムデバイスドライバを介して、(x,y,p) のトリプルのシーケンスとして配信されます。ここで p はデバイス定義の圧力入力です。私は一般的に p を r にマッピングします。これは、望ましいストローク幅とストローク半径が圧力にどれだけ速く反応してほしいかに基づいた重み付け関数を使用します。r = wp¹·⁵ と r = wp² の間のある値が、使用している特定のタブレットに応じて、私にはうまく機能します。ここで w は、アプリケーション実行中に調整するキーボードショートカットに接続するストローク幅乗数です。

私の最初のアプリケーションは、各点の間にピル形状を作成しました。各点に同じ半径の円があり、それらは同じ幅の長方形で接続されていました。これは可読性が高く実装も簡単ですが、圧力が変化するとストロークがでこぼこになり、ズームインがあまりうまくいきません。

私の2番目のアプリケーションは、各点の間に台形のピル形状を作成しました。各点に異なる半径の円があり、それらは両方に接する台形で接続されていました。これはピルアプローチよりもはるかに滑らかに見えますが、計算量はわずかに増加します。

これらのアプローチはどちらも、サンプルポイントを直線で接続します。しかし、私が速く書くとき、o の円全体で合計半ダースの (x,y,r) トリプルしか持たないかもしれません。また、ペンが書いている間に加速・減速するため、等間隔でない場合があり、直線が顕著に角張って見えることがあります。ハイエンドのグラフィックスタブレットとネイティブに近いドライバを使用すると、毎秒より多くのサンプルが得られ、この効果は軽減されますが、安価なタブレットやJavaScriptのようなイベント折り畳みAPIでは、角張りが視覚的に重要になります。

スプラインの世界へようこそ。タブレット提供のポイントを直線(可変幅ストローキング付き)で接続するのではなく、滑らかな曲線で接続します。特に、三次ベジェ曲線です。サンプルポイントに基づいて曲線を選択する方法は数多くありますが、私はポイント i-1 と i+1 の間の角度に基づいてポイント ii での曲線の傾きを選択することの視覚的な品質に満足しています。ポイント i+1 が入力されるまで描画を1サンプル遅延させることで、i-1 と ii の間の曲線を引くことができます。

ベジェ曲線は、コンピュータでの曲線描画の「ワークホース」です。計算効率、アーティストの直感、数値的安定性をうまく組み合わせています。

ベジェ曲線はベルンシュタイン基底多項式の特定のインスタンスです。ここではそれらをさらに区別せず、ベルンシュタインがより適切かもしれない文脈でもベジェと呼びます。

各ベジェ曲線は、制御点のシーケンスで指定されます。曲線は最初と最後の制御点に触れ、その間にある点に向かって、滑らかに、制御点の凸包から外れることなく進みます。制御点が多いほど、各点の影響は小さくなり、中央の点ほど影響は限定的になります。ほとんどの場合、4つの制御点を使用して三次ベジェ曲線⁴を生成します。

ベジェ曲線にとって重要なアルゴリズムはド・カステルジョのアルゴリズムであり、これは元のベジェ曲線を任意の点で2つのベジェ曲線に分割できます。0 < t < 1 を与えると、最初と最後の点はそれぞれ前方と後方の分割曲線の部分となり、次に新しい点が各線分に沿って t だけ見つかります。それらの新しい点の最初と最後はそれぞれ前方と後方の分割曲線の部分となり、次に新しい点が各線分に沿って t だけ見つかります。そして、1つの新しい点になるまで続きます。これは両方の分割曲線の一部です。

ド・カステルジョのアルゴリズム

入力

  • 制御点 𝐜₀, 𝐜₁, …, 𝐜<0xE2><0x82><0x99>
  • パラメータ値 t ∈ [0,1]

出力

  • 制御点 𝐚₀, 𝐚₁, …, 𝐚<0xE2><0x82><0x99>
  • 制御点 𝐛₀, 𝐛₁, …, 𝐛<0xE2><0x82><0x99>

これらは曲線 t で分割します: 𝐚₀ = 𝐜₀, 𝐛<0xE2><0x82><0x99> = 𝐜<0xE2><0x82><0x99>, そして 𝐚<0xE2><0x82><0x99> = 𝐛₀ = パラメータ t における曲線上の点。

  1. s = 1-t と定義します。
  2. 𝐝ᵢ,ⱼ = { s 𝐝ᵢ₋₁,ⱼ + t 𝐝ᵢ₋₁,ⱼ₊₁ if 0 < i ≤ n and 0 ≤ j ≤ n-i; 𝐜ⱼ if i = 0 and 0 ≤ j ≤ n }
  3. 𝐚ᵢ = 𝐝ᵢ,₀
  4. 𝐛ᵢ = 𝐝<0xE2><0x82><0x99>₋ᵢ,ᵢ

曲線上の単一の値が必要な場合、ド・カステルジョのアルゴリズムで提供できますが、n(n+1)回の乗算が必要です。制御点が多い曲線の場合、ホーナーのアルゴリズムは 5n-7 回の乗算と n-2 回の除算でこれを実行するため、3つを超える制御点を持つ曲線ではより効率的です。

ホーナーのアルゴリズム

ホーナーのアルゴリズムはべき乗基底で動作し、ベルンシュタイン基底ではありません。そのため、ホーナーのアルゴリズムループ中にこれらの基底を変換するために二項係数を計算します。

入力

  • 制御点 𝐜₀, 𝐜₁, …, 𝐜<0xE2><0x82><0x99>
  • パラメータ値 t ∈ [0, 1]

出力

パラメータ t における曲線上の点 𝐩

  1. s = 1-t と定義します。
  2. b = (ⁿ₀) = 1 と初期化します。
  3. k = t⁰ = 1 と初期化します。
  4. 𝐩 = 𝐜₀ と初期化します。
  5. i を 1 から n まで繰り返します:
    1. k を t で乗算します (k = tⁱ になります)
    2. b を (n-i+1) で乗算し、i で割ります (b = (ⁿᵢ) になります)
    3. 𝐩 を 𝐩s + kb 𝐜ᵢ に置き換えます。

ベジェ曲線の重要な特性は、その導関数(座標が変化する速度)も曲線であり、ホドグラフと呼ばれることです。ホドグラフは元の曲線よりも制御点が1つ少なくなります。元の制御点が 𝐂ᵢ (i は 0 から n まで) でラベル付けされている場合、ホドグラフの制御点は 𝐇ᵢ = n/Δt (𝐂ᵢ₊₁ - 𝐂ᵢ) (i は 0 から n-1 まで) となります。Δt は曲線の全パラメータ範囲(通常は 1)です。

ベジェ曲線は分離可能であり、(x,y,r) 制御点を持つベジェ曲線で作業することは、x 制御点を持つ1つのベジェ多項式、y 制御点を持つ1つのベジェ多項式、z 制御点を持つ1つのベジェ多項式で作業することと全く同じ結果をもたらします。

A ベジェ多項式は、制御点を適切な二項係数で乗算し、それ自体で制御点のリストを畳み込み、適切な二項係数で割ることによって二乗できます。例えば、制御点 (a,b,c,d) を持つ三次多項式は (1,3,3,1) で乗算されて (a,3b,3c,d) になり、(a², 6ab, 6ac + 9b², 2ad + 18bc, 6bd + 9c², 6cd, d²) に畳み込まれ、(1,6,15,20,15,6,1) で割られて (a², ab, 0.4ac + 0.6b², 0.1ad + 0.9bc, 0.4bd + 0.6c², cd, d²) になります。

A ベジェ多項式の根は、その制御点を 0 と 1 の間に均等に x 軸に沿って配置することによって見つけることができます(その配置は明示的ベジェ曲線と呼ばれます)。その後、根を見つけるためにいくつかのツールを使用できます。

区間狭窄

ベジェ曲線は制御点の凸包内に留まるため、y=0 を横切る場所を見つけることは、凸包が x 軸を横切る最小値と最大値を繰り返し見つけ、ド・カステルジョのアルゴリズムを使用してそれらの境界を超える曲線の部分を削除することによって行うことができます。

これはニュートン法の⁵ように、最初の根と最後の根に速く収束します。また、最小値または最大値のみを使用して、1つの根のみを見つけることもできます。

分割

ベジェ曲線は、その制御点の符号変化の回数よりも多くの根を持つことはできないという、変動減少特性を持っています。例えば、制御点が2回しか符号を切り替えない場合(例: (+,+,−,−,−,−,+))、多項式は最大2つの根を持ちます。

曲線が2つ以上の根を持つ場合、ド・カステルジョのアルゴリズムを使用して、根が≤2の曲線に分割できます。

デフレート

ベジェ多項式の最初の制御点が 0 の場合、その根を取り除き、他の根を保持するデフレートされた多項式は、n-1 個の制御点 𝐜ᵢ' = n/(i+1) 𝐜ᵢ₊₁ で定義できます。

ベジェ多項式の最後の制御点が 0 の場合、その根を取り除き、他の根を保持するデフレートされた多項式は、n-1 個の制御点 𝐜ᵢ' = n/(n-i) 𝐜ᵢ で定義できます。

Visible strokes

ベジェ曲線は拡張は持つが幅を持たない数学的なパスであり、ピクセルをタッチしたピクセルを色付けしようとしても、どのピクセルも色付けされないことを意味します。それらを視覚的に描画するには、曲線から一定の距離内にあるピクセルを塗りつぶす必要があります。これはすべてのベジェ曲線に当てはまりますが、ストロークの半径が曲線の座標自体である場合には、おそらくさらに当てはまります。これらのピクセルを見つけて描画するプロセスは、曲線をストローキングと呼びます。

曲線をストローキングするには、2つの基本的なアプローチがあります。

1つのオプションは、ストロークの両端に多数の点を見つけ、それらを十分に近接した頂点を持つ大きなポリゴンに接続し、そのポリゴンを塗りつぶすことです。数千の頂点を持つポリゴンを含む、ポリゴンのレンダリングにはいくつかの効率的なアルゴリズムがあります。

もう1つのオプションは、各ピクセルが曲線からどれだけ離れているかを確認し、その距離がストロークの一部であるのに十分小さい場合に塗りつぶすことです。客観的にはポリゴンアプローチよりも多くの作業が必要であり、特に小さな曲線以外ではすべてのピクセルに対して大幅に多くの算術計算が必要ですが、このアプローチはGPUのような高度に並列化されたSIMD実装に適しています。

私は時々、ポリゴンオプションのバリアントとして、線分ではなくベジェ曲線を使用してストロークの境界を定義するという3番目のアプローチを提案されているのを見かけます。これらの中間ベジェ曲線は、上記の2つのアプローチのいずれかを使用してレンダリングする必要があるため、この中間ステップを追加することは、実装者にとっては便利ですが、実際の計算上の利点ではないようです。

固定幅ストロークについては、2つのアプローチ(ポリゴン境界とピクセルチェック)が広く実装されていますが、可変幅ストロークについては、多くの実装や明確な説明を見たことがありません。この投稿の残りの部分でそれを是正しようと試みます。

Variable-width stroke outlines

ストロークアウトラインを作成するための基本的なアプローチは、曲線上の点のシーケンスを見つけ、各点について、ストロークのエッジにある左側と右側の点を見つけることです。見つかった左側点は一緒にチェーンされ、次に(エンドキャップを介して)右側点と逆順に接続され、次に(再びエンドキャップで)左側点に戻って接続されます。

半径を3番目の座標とする2Dベジェ曲線の場合、曲線上の点の左側点と右側点は、単に曲線の進行方向に対して90°オフセットされるわけではありません。代わりに、それらの点を見つける方法は次のとおりです。

ストロークポイントペア(視覚化付き)

入力

  • (x,y,r) のベジェ曲線
  • 曲線上の一点

出力

その点で半径 r の円がストロークのエッジに接する2つの点。

0 または ∞ のような点がある場合は失敗します。

  1. ド・カステルジョのアルゴリズムを使用して、曲線上の点 p とそのホドグラフ上の対応する点 H⃗ を見つけます。

  2. それらの値の有用な部分を導出/計算します:

    • r = pᵣ、この点でのストロークの半径。
    • q = (pₓ, p<0xE1><0xB5><0xA7>)、この点の空間的位置。
    • t⃗ = (Hₓ, H<0xE1><0xB5><0xA7>)、H⃗ の空間部分。
    • Hᵣ、H⃗ の半径部分。
    • s⃗ = (H<0xE1><0xB5><0xA7>, -Hₓ)、t⃗ に垂直な2Dベクトル。
    • ℓ = ||t⃗||² = ||s⃗||² = Hₓ² + H<0xE1><0xB5><0xA7>²、t⃗ の二乗長。
  3. ℓ = 0 または ℓ < Hᵣ² の場合、失敗します。

  4. ストロークのエッジ上の左側点と右側点は、q + r (-Hᵣ/ℓ) t⃗ ± r sqrt(ℓ - Hᵣ²)/ℓ s⃗ です。
    Hᵣ が 0 の場合、これは単に q ± r s⃗/||s⃗||、q の左側と右側 r の点です。Hᵣ が正の場合、ストロークは前方に広がり、点は Hᵣ/||t⃗|| によって後方に押され、次のベジェ制御点 p + H⃗ に接する台形の点を見つけます。

A demo of stroke point finding, showing that the points connect as tangent to the control points, and are not defined if one circle is inside another.

このアプローチでは、望ましい滑らかなストローク境界が得られないケースが2つあります。

ℓ = 0 の場合、曲線には急激な方向変化を伴う尖点がある可能性があり、尖点の前後でのストロークの境界が不連続になる可能性があります。この不連続性は、両側にエンドキャップを持つ2つの部分にストロークを分割することで正しくレンダリングできます。明白な視覚的アーティファクト⁶を避けるために、ℓ = 0 の正確な点がサンプリングされていなくても、この分割は重要です。隣接するサンプルポイントに接続する曲線の部分のホドグラフの凸包が 0⃗ を含み、サンプルが十分に近いため追加のサブディビジョンが不要な場合、ストロークの分割が必要です。

ℓ < Hᵣ² の場合、半径は点が進むよりも速く変化しており、その点での円が直前の点(Hᵣ < 0)または次の点(Hᵣ > 0)の円に完全に覆われることを意味します。これはしばしば曲線のストレッチで発生し、その中でストローク境界を描画すべきではありません。これらの省略された曲線の部分のすぐ外側で、ストロークの左側点と右側点が一致し、エンドキャップを必要としない自然な分割が作成されます。

これらすべてを組み合わせることで、次のアルゴリズムを導き出すことができます。

Variable-width stroke outlines (with visualization)

  1. ポイントペアとベジェ制御点の空のスタックを初期化します。
  2. 左側セグメントと右側セグメントの空のリストを初期化します。セグメントは点のリストです。
  3. 開始点と終了点の制御点を持つエンドキャップのリストを初期化します。
  4. 開始点のペア pp と終了点のペア qq を見つけます。
    • pp が見つかった場合(0 でもなく ℓ < Hᵣ² でもない)、その点を単一の左側および右側セグメントとして追加します。
  5. 次のいずれかのケースを繰り返し選択します:
    • ホドグラフのいずれかの座標が大きい場合、
      または pp がなく qq ポイントが離れている場合、
      または qq がなく pp ポイントが離れている場合、
      または pp と qq の左側または右側ポイントが離れている場合:

      1. 現在のベジェを半分に分割します。後方の半分をベジェ制御点のスタックにプッシュし、現在のベジェを前方の半分に置き換えます。
      2. qq をポイントペアのスタックにプッシュします。
      3. 現在のベジェの終点の新しいポイントペア qq を見つけます。
    • ホドグラフの凸包が原点を含む場合

      1. qq の点を新しい単一の左側および右側セグメントとして追加します。
      2. 現在のベジェの開始点と終了点をエンドキャップとして追加します。
    • それ以外の場合

      1. pp が見つからなかったが qq が見つかった場合:
        1. qq の点を新しい単一の左側および右側セグメントとして追加します。
      2. pp と qq の両方が見つかった場合:
        1. qq を最も最近追加された左側および右側セグメントリストに追加します。
      3. pp を qq に置き換えます。
      4. スタックが空の場合、ループを停止します。
      5. スタックからベジェをポップして新しい現在のベジェにします。
      6. スタックからポイントペアをポップして新しい qq にします。
  6. マッチした左側および右側セグメントをポリゴンとして結合します。また、エンドキャップ用の円を描画します。

このアウトラインが完全なポリゴンではなく三角形のセットとしてレンダリングされる場合、ストロークの反対側の点は常に、それらの間の線がストロークの内部にあるペアとして生成されるため、三角形ストリップは円形のエンドキャップ以外すべてに十分です。

A variable-width cubic Bézier rendered on the CPU using the stroke outline algorithm; rendered with an <svg> element with each part of the stroke outline outlined and each sample point indicated by an inward-facing tick.

線分ではなく、同じストローク境界上の点を接続するために三次ベジェ曲線を使用することも可能です。各点の導関数を使用して内部制御点を選択します。これは、三次ベジェ曲線と可変幅ストロークをサポートしないプリンターやファイルにエクスポートする場合に役立ちます。ただし、ホドグラフがゼロに近づくとこれらの導関数は無限大に近づくため、それを検出して処理しないと奇妙な視覚的アーティファクトが発生する可能性があります。

A variable-width cubic Bézier rendered on the CPU using the stroke outline algorithm with cubic Bezier curves between samples. The very large derivatives are not detected, illustrating the problems they can cause.

A variable-width cubic Bézier rendered on the CPU using the stroke outline algorithm with cubic Bezier curves between samples and derivative magnitudes set to minimize strain as explained in DOI:10.1016/j.cagd.2003.08.003.

Checking each pixel

最初に注意すべき点として、このセクションは前のセクションのアウトライン技術よりも著しく効率が悪くなります。ただし、GPUのようなSIMDプロセッサで高度に並列化して実装された場合は除きます。

曲線がカバーする可能性のあるピクセルのセット(半径でパディングされた制御点のバウンディングボックスなど)がわかっている場合、各ピクセルが個別にストローク内にあるかどうかを確認できます。ピクセルと曲線の距離の二乗はベジェ多項式であり、各点での曲線の半径の二乗も同様です。それらを差し引くと、ストロークの内側では負、外側では正になるベジェ多項式が得られます。

アンチエイリアシングのために、ピクセルが境界から1ピクセル直径以内にあるかどうか、そしてその場合、境界からどれだけ離れていてどちらの方向にあるかを知ることが役立つ場合があります。ストロークエッジからの距離の近似は、((距離² - ストローク中心線からの距離²) - ストローク半径²) / (ストローク半径²) として見つけることができますが、この近似は中心線からの距離がストローク半径に近い場合にのみ良好です。

Checking pixels against the stroke (with visualizations)

入力

  • 曲線の (x,y,r) 制御点の共有シーケンス。
  • スレッドごとのピクセル (x,y) の位置。
  1. 各制御点の x および y からピクセル位置を差し引き、ピクセル相対ベジェ曲線を作成します。制御点は (Δx,Δy,r) となります。

  2. ピクセル相対ベジェ曲線の x、y、r 座標を二乗して、(Δx², Δy², r²) 制御点を持つ曲線を作成します。

  3. 3つの座標を Δx² + Δy² - r² で結合して、ストロークのエッジからの距離の1座標ベジェ多項式を作成します。

  4. 次のいずれかを行います:

    • ピクセルがストローク内にあるかどうかを、ベジェ多項式の根があるかどうかを確認して見つけます。

      視覚的に満足のいく結果を得るには、16回のド・カステルジョ呼び出しで十分であることがわかりました。分割なしで、8回のラウンドで曲線の低位と高位の両方をクリッピングするか、16回のラウンドで一方のみをクリッピングします。それらの反復回数の後も区間が縮小しない場合、ピクセルはストローク内にあるとレンダリングします。

    • ピクセルがストローク境界からどれだけ離れているかを見つけます。

      1. ベジェ多項式の最小値を求めます。

      2. 結果を、同じパラメータでの元の曲線の r 座標の値で割ります。

      3. 結果が -w より小さい場合は内部、w より大きい場合は外部、その間はアンチエイリアシングとしてレンダリングします。ここで w は1ピクセルの幅です。

        正方形のピクセルは、対角線方向と軸方向で幅が異なることに注意してください。この方法はスーパーサンプリングと同じようにアンチエイリアシングしません。代わりにピクセルを円として扱います。また、この方法の調整を使用して、ストロークのアウトラインをストロークすることもできることに注意してください。

      最小値を見つける方法には、ホドグラフの根を見つける、分割して各部分の制御点の範囲を最小値の境界として使用する、最小値制御点の近くで分割して端に最小値を持つ部分を見つける、より一般的な極値探索(ヒルクライミングなど)など、いくつかのオプションがあります。ホーナーのアルゴリズムを使用してホドグラフを評価するニュートンヒルクライミング、ニュートン更新の1/4乗数、4回のニュートン反復、並列で実行される8つの均等に配置された開始点からの実行を使用しました。これらの値は特定の metodologia ではなく試行錯誤によって選択されたものであり、すべてのケースで正しい答えに収束することが保証されているわけではありません。

A variable-width cubic Bézier rendered on the CPU using the pixel-checking algorithm; rendered with an <svg> element using a <rect> for each pixel.

A variable-width cubic Bézier rendered on the GPU using the pixel-checking algorithm; rendered with a <canvas> element using a WebGL2 fragment shader.

A variable-width cubic Bézier rendered on the GPU using the anti-aliased pixel-distance algorithm; rendered with a <canvas> element using a WebGL2 fragment shader.

Export and print

1982年のAdobeの元のPostScript仕様の導入以来、印刷可能なファイル形式とプリンターファームウェアの両方が、三次ベジェ曲線と円弧をサポートしており、それらを塗りつぶす領域の境界として、また固定幅の円形オフセットストロークを作成するためのパスとして使用しています。これには、多くのプリンターで直接サポートされている形式(.ps、.eps、.pdf)や、表示と印刷の両方の役割を持つ形式(.svg、.ai)が含まれます。これらの形式のいずれも、可変幅ストロークの直接サポートはありません。

可変幅ストローキングがこれらの形式に追加される日を夢見ています。残念ながら、それは単なる夢です。それを現実にする方法がわかりません。

可変幅ストロークのネイティブ表現がないこと、そしてそのようなストロークの境界が三次ベジェ曲線と円弧のみを使用して完全に表現されないことに注意すると、ボードワークをそのようなファイルやプリンターにエクスポートするための残りのオプションは、ストロークのアウトラインを近似することです。これは、ストロークアウトラインアルゴリズムで行われるように行われます。

ファイルサイズを最適化し、より滑らかなストローク境界をサポートするために、境界点の数を減らし、それらを線分ではなく三次ベジェ曲線で接続することが望ましい場合があります。曲線の境界が三次多項式である場合、これらの曲線を見つけることは、各ストローク境界点のパラメータ空間導関数を見つけることと同じくらい簡単です。これは、variable-width stroke outlines の視覚化の1つで行われているように行われます。しかし、ストロークのアウトラインは、ストローク方向が反転する近くでパラメータ空間において強く非多項式であり、強い視覚的アーティファクトを避けるために追加のサンプリングと変動制限が必要です。それらの領域の再パラメータ化またはその他の平滑化は、より滑らかなアウトラインをもたらす可能性があります。

Extensions

ストローク境界アルゴリズムは、各サンプルポイントでリング(ペアではなく)のストローク境界ポイントを生成することによって3Dに拡張できます。そのような3D要素の説得力のある用途はわかりません。

円形オフセットは中央軸に関連しています。自己交差しない、または半径のホドグラフが位置のホドグラフよりも大きい点を持たない可変幅ベジェストロークが与えられた場合、ストロークの中央軸はベジェ曲線です。

ドロネー三角形分割の外接円の中心と中央軸の関係により、ストロークの三角形ストリップはドロネー三角形分割に近く、そのペアの点を生成した曲線の点は、それらの点ペアを接続する三角形の外接円の中心に近いことになります。

Code

これらのアルゴリズムの実装は、このページ(ヘッダーの <script> 要素内)で提供されており、ロイヤリティや帰属表示なしで、誰でも目的のために使用できます。ライセンスはunlicenseに従います。各 <script> 要素の先頭にあるコメントを参照してください。