N2
NanToo
SVG path の M/L/C/Q/A — Bézier 曲線と楕円弧、W3C SVG 2 を読む
DDEVELOPER
開発10 分で読める

SVG path の M/L/C/Q/A — Bézier 曲線と楕円弧、W3C SVG 2 を読む

SVG エディタが書き出す <path d="M10,10 C20,20 40,20 50,10 A15,15 0 0 1 80,30 Z"/> — この呪文のような文字列の意味を、数学的根拠まで遡って理解できているでしょうか。本記事では W3C SVG 2 仕様 §9 (Paths) を一次資料として、10 種類の path コマンドと背景にあるBézier 曲線理論 (Pierre Bézier 1962, de Casteljau 1959)、そして実装上最難関とされる楕円弧 (A コマンド) の endpoint → 中心点変換を実例とともに整理します。

#SVG#path#Bézier#数学#W3C

path コマンド一覧 — 10 種類 × 大文字/小文字

W3C SVG 2 仕様 §9.3 で定義されている path コマンドは以下の 10 種類です。各コマンドは大文字 (絶対座標) と小文字 (現在点からの相対座標) のペアで存在し、計 20 種の文字が使えます。

文字名前引数意味
M / mmovetox yペンを移動 (描画なし)
L / llinetox y直線
H / hhorizontal linetox水平線
V / vvertical linetoy垂直線
C / ccubic Bézierx1 y1 x2 y2 x y3 次 Bézier 曲線
S / ssmooth cubicx2 y2 x y前の C を滑らかに継続
Q / qquadratic Bézierx1 y1 x y2 次 Bézier 曲線
T / tsmooth quadraticx y前の Q を滑らかに継続
A / aelliptical arcrx ry x-axis-rotation large-arc-flag sweep-flag x y楕円弧
Z / zclosepath(なし)始点へ直線で戻る

同じコマンドの引数を連続させるとコマンド文字を省略できます (例: L 10,20 30,40 50,60 = 3本の連続線)。これが SVG ファイルが暗号のように見える主因です。

Bézier 曲線の起源 — Renault 1962

3 次 Bézier 曲線 (Cubic Bézier) は、フランスの自動車メーカー Renault のエンジニア Pierre Bézier が 1960 年代初頭に車体デザインのために考案したものです。実は同時期に Citroën の Paul de Casteljau が同等の理論を独立に開発していましたが、Citroën が機密扱いとしたため、後に公表した Bézier の名前で広まりました。

3 次 Bézier 曲線は 4 つの制御点 P₀, P₁, P₂, P₃ から定義され、パラメータ t ∈ [0, 1] による曲線:

B(t) = (1-t)³ P₀ + 3(1-t)² t P₁ + 3(1-t) t² P₂ + t³ P₃

この式はバーンスタイン基底関数の和の形 (binomial expansion of (1-t)+t = 1) で、以下の重要な性質を持ちます。

  • 端点保存: t=0 で P₀、t=1 で P₃ を必ず通る (中間の P₁, P₂ は通らない)
  • 接線方向: t=0 での接線は P₀-P₁ 方向、t=1 での接線は P₂-P₃ 方向
  • 凸包性: 曲線は 4 制御点の凸包の内側に必ず収まる (描画範囲が予測しやすい)
  • アフィン不変性: 制御点を平行移動・回転・スケールすると曲線も同様に変換される

SVG の C コマンド C x1,y1 x2,y2 x,y は、現在の点を P₀、引数の (x1,y1) を P₁、(x2,y2) を P₂、(x,y) を P₃ として扱います。

de Casteljau アルゴリズム — 数値的に安定な評価

Bézier 曲線を数値計算する際、上記の多項式を直接展開するよりde Casteljau アルゴリズム (1959) を使う方が安定です。これは線形補間を再帰的に適用する手法で、丸め誤差が累積しません。

// 3 次 Bézier の de Casteljau (パラメータ t での点を求める)
function deCasteljau(P0, P1, P2, P3, t):
  Q0 = lerp(P0, P1, t)   // (1-t)P0 + t P1
  Q1 = lerp(P1, P2, t)
  Q2 = lerp(P2, P3, t)
  R0 = lerp(Q0, Q1, t)
  R1 = lerp(Q1, Q2, t)
  return lerp(R0, R1, t)

このアルゴリズムは曲線分割にも使えます。t = 0.5 で得られる点と中間結果を組み合わせれば、元の曲線を 2 本の同形 Bézier に分割でき、SVG エディタの「曲線の途中に点を追加」機能の数学的基礎になっています。Adobe Illustrator や Inkscape の path 編集はすべてこの分割アルゴリズムで実装されています。

S / T コマンド — 滑らかな接続

長い曲線を C コマンド連続で書くと制御点が冗長になります。SVG では S (smooth cubic) と T (smooth quadratic) で、前のコマンドの第 2 制御点を起点側の制御点として自動継承できます。

// S は次のように展開される:
//   前の C/S が x2_prev, y2_prev で終わっていたら
//   現在点 (cx, cy) を中心に対称反転した点が新しい x1, y1 になる
//   x1 = 2 cx - x2_prev
//   y1 = 2 cy - y2_prev

つまり C 10,10 30,10 40,20 S 60,10 70,20C 10,10 30,10 40,20 C 50,30 60,10 70,20 と等価。C¹ 連続 (滑らかさ class 1) を保証する書き方です。Q/T も同じ仕組みで、quadratic 用の制御点反転になります。

A コマンド — 楕円弧の 7 引数

楕円弧 A は SVG path で最も難解とされるコマンドです。引数は 7 つ:

A rx ry x-axis-rotation large-arc-flag sweep-flag x y
  • rx, ry: 楕円の半径 (x 方向、y 方向)
  • x-axis-rotation: 楕円自体の回転角度 (度)
  • large-arc-flag: 0 なら短い弧、1 なら長い弧
  • sweep-flag: 0 なら反時計回り、1 なら時計回り
  • x, y: 終点の座標

始点 (現在点) と終点を結ぶ楕円弧は2 つ存在し (large-arc-flag で短/長を選択)、さらにそれぞれ進行方向で 2 通り (sweep-flag) あるので、計 4 通りから 1 つを選ぶ仕組みです。

endpoint → 中心点変換 — W3C SVG 1.1 Implementation Notes F.6.5

SVG の A コマンドは「始点 + 終点 + 半径 + フラグ」で曲線を指定しますが、内部のレンダラは「中心 + 半径 + 開始角 + 角度範囲」が必要です。両者を結ぶ変換式は W3C SVG 1.1 Implementation Notes Appendix F.6.5 で定義されています。

// 入力: 始点 (x1,y1), 終点 (x2,y2), rx, ry, φ (回転), fA (large), fS (sweep)

// Step 1: 楕円が回転していない座標系に変換
x1' = cos(φ)·(x1-x2)/2 + sin(φ)·(y1-y2)/2
y1' = -sin(φ)·(x1-x2)/2 + cos(φ)·(y1-y2)/2

// Step 2: 半径補正 (端点間距離が直径より長いとき自動拡大)
λ = (x1'/rx)² + (y1'/ry)²
if λ > 1:
  rx *= sqrt(λ)
  ry *= sqrt(λ)

// Step 3: 中心点 (回転前座標で)
sign = (fA != fS) ? +1 : -1
factor = sign · sqrt( (rx²·ry² - rx²·y1'² - ry²·x1'²) / (rx²·y1'² + ry²·x1'²) )
cx' = factor · rx·y1' / ry
cy' = factor · -ry·x1' / rx

// Step 4: 元の座標系に戻す
cx = cos(φ)·cx' - sin(φ)·cy' + (x1+x2)/2
cy = sin(φ)·cx' + cos(φ)·cy' + (y1+y2)/2

// Step 5: 開始角と掃引角度
θ_start = atan2((y1'-cy')/ry, (x1'-cx')/rx)
Δθ      = atan2((-y1'-cy')/ry, (-x1'-cx')/rx) - θ_start
if !fS and Δθ > 0: Δθ -= 2π
if  fS and Δθ < 0: Δθ += 2π

この変換は単純な公式ではなく 5 段階の代数操作です。Inkscape や Illustrator が path をプレビューする際、この計算を全 A コマンドに対して行っています。手書きで楕円弧 path を書く機会はほぼなく、エディタが計算してくれるのが通常です。

実例 — 円を path で描く 4 つの方法

半径 50 の円を中心 (100, 100) に描く path を 4 通りに書き分けてみます。

// 方法 1: circle 要素 (path ではない)
<circle cx="100" cy="100" r="50"/>

// 方法 2: A コマンド 2 個 (上半分 + 下半分)
<path d="M 50,100 A 50,50 0 0 1 150,100 A 50,50 0 0 1 50,100"/>

// 方法 3: C コマンド 4 個 (近似、誤差 ~ 0.027%)
//   κ = 4·(√2 - 1) / 3 ≒ 0.5523
<path d="M 100,50 C 127.6,50 150,72.4 150,100 C 150,127.6 127.6,150 100,150 C 72.4,150 50,127.6 50,100 C 50,72.4 72.4,50 100,50"/>

// 方法 4: Q コマンド 4 個 (近似、誤差大、円というより四角に近い)
<path d="M 100,50 Q 150,50 150,100 Q 150,150 100,150 Q 50,150 50,100 Q 50,50 100,50"/>

方法 3 の係数 κ = 4(√2 - 1)/3 ≒ 0.5523 は、4 本の Cubic Bézier で円を描くときに最も誤差が小さくなる理論値です。Adobe Illustrator など多くのベクターエディタは「円のオブジェクトを path 化」すると方法 3 で書き出します。SVGO の convertShapeToPath プラグインも同じ動作で、<circle> を 4 個の C で書き換えます。

本サイトの SVG 最適化ツール はこの変換を自動で行い、結果としてファイルサイズを削減します。

Bézier の連続性 (G⁰ / G¹ / C¹ / C²)

複数の Bézier をつなぐとき、接続点での「滑らかさ」には 4 段階あります。

クラス条件見た目
G⁰位置が一致角が見える (折れ線)
位置 + 接線方向が一致滑らかに見える
位置 + 接線ベクトルが一致 (大きさも)速度も連続
C¹ + 曲率も一致車体・光沢面で重要

SVG の S コマンドが提供するのは G¹ (接線方向の連続)。これで多くの用途では十分滑らかですが、車体パネルの A 級曲面や光沢面のように曲率連続まで要求される場面は B-スプラインや NURBS の出番です (SVG はサポートしません)。

SVG エディタが path を最適化するロジック

Inkscape の "Optimize Paths" / Illustrator の "Simplify"、SVGO の各種プラグインは、概ね以下の最適化を行います。

  • 連続点を集約: L 10,10 L 20,20L 10,10 20,20 (コマンド文字省略)
  • 絶対 → 相対座標 (条件付き): 大きな値より小さな相対値の方が文字数が少ないとき
  • 小数桁削減: 50.00000150
  • shape → path: <rect>M ... L ... L ... L ... Z に変換
  • 連続曲線を S/T に: 制御点が対称なら S/T で省略
  • 結合可能な path をマージ: 同属性の連続パスを1つに

これらは可逆変換 (見た目を変えない) として安全に適用でき、典型的な Inkscape 出力で 50-80% のサイズ削減が見込めます。

まとめ

  • SVG path は 10 種類のコマンド (M/L/H/V/C/S/Q/T/A/Z) で構成、大文字 = 絶対、小文字 = 相対
  • 曲線の主役は Bézier (Renault 1962) と de Casteljau (1959) アルゴリズム
  • 3 次 Bézier の式は 4 制御点 + バーンスタイン基底
  • S / T は前のコマンドから制御点を継承、C¹ 連続を保証
  • A コマンドの endpoint → 中心点変換は W3C 仕様 F.6.5 の 5 段階代数
  • 円を C コマンドで近似する係数 κ = 4(√2-1)/3 は古典的
  • SVGO の最適化は可逆変換のみを適用、見た目を変えない

参考文献・ソース

記事作成に関する注記

本記事は AI(大規模言語モデル)を編集補助として活用して作成しています。 公開前に編集者が内容を確認していますが、事実誤認・仕様の解釈ミス・最新情報との齟齬が含まれる可能性があります。 重要な判断を行う際は、本文中の一次ソースや公式ドキュメントを必ずご自身でご確認ください。 誤りにお気づきの場合は、お問い合わせフォームよりご連絡いただけると助かります。

🔧 関連ツール

📚 関連記事