
SVG path 指令與 Bézier 曲線:S/T 接點、橢圓弧 A 及圓形近似
SVG path 用一串指令描述移動、直線、曲線及封閉路徑。例如 M10,10 C20,20 40,20 50,10,只要分清目前位置與控制點,就能逐段理解。
本文以 W3C SVG 2 的 Paths 章(2018 年 10 月 4 日候選推薦標準)及 SVG 1.1 橢圓弧實作說明為依據,整理計算方式與編輯時容易混淆的條件。
日文原文發布: 2026-04-25
10 類指令與絕對、相對座標
大寫指令一般使用絕對座標,小寫則使用相對目前位置的座標。Z/z 沒有座標參數,兩者作用相同。
如表格未能完整顯示,可左右捲動。
| 指令 | 參數 | 作用 |
|---|---|---|
| M/m | x y | 移動,不畫線 |
| L/l | x y | 直線 |
| H/h | x | 水平線 |
| V/v | y | 垂直線 |
| C/c | x1 y1 x2 y2 x y | 三次 Bézier 曲線 |
| S/s | x2 y2 x y | 按前一段 C/S 決定首個控制點 |
| Q/q | x1 y1 x y | 二次 Bézier 曲線 |
| T/t | x y | 按前一段 Q/T 決定控制點 |
| A/a | rx ry rotation large sweep x y | 橢圓弧 |
| Z/z | 無 | 封閉目前子路徑 |
相同指令的參數可連續書寫,例如 L 10,20 30,40 50,60 是三段線。M 後第二組及其後的座標當作 L 處理。Z 會把描邊兩端作封閉接合,與用 L 返回起點但保留開放端點不同。
三次 Bézier 曲線的四個控制點
三次曲線由 P₀、P₁、P₂、P₃ 四個控制點決定,參數 t∈[0,1]:
B(t) = (1-t)³ P₀ + 3(1-t)² t P₁ + 3(1-t) t² P₂ + t³ P₃這是 Bernstein 基底的加權和。曲線在 t=0 和 t=1 通過兩端點,但通常不通過中間兩個控制點;整條曲線位於四點的凸包內。平移、旋轉或縮放控制點,亦會對曲線作相同的仿射變換。
端點導數為 B′(0)=3(P₁−P₀)、B′(1)=3(P₃−P₂)。若向量為零,不能只靠這兩式判定切線方向。C 的目前位置是 P₀,其餘三組參數依次指定 P₁、P₂ 和 P₃。
用 de Casteljau 評估及分割曲線
de Casteljau 反覆作線性插值,比直接展開多項式更適合穩定地評估曲線,但仍會受浮點捨入影響。以下是偽代碼,lerp(a,b,t) 表示 (1−t)a+tb:
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 將曲線分成兩條 Bézier 曲線;精確算術下形狀不變。t=0.5 的分割可作為編輯器在曲線中間加點的數學基礎,但不代表所有編輯器的操作都採用相同實作。
S/T 並非任何情況都會平滑接駁
S 只有在前一個指令是 C 或 S 時,才把上一段最後的控制點以目前位置為中心反射,作為新一段的首個控制點;否則首個控制點就是目前位置。T 也只有在 Q 或 T 之後才反射,其他情況以目前位置作控制點。
reflectedX = 2 * currentX - previousControlX
reflectedY = 2 * currentY - previousControlY
M 0,0 C 10,10 30,10 40,20 S 60,10 70,20
M 0,0 C 10,10 30,10 40,20 C 50,30 60,10 70,20兩條 path 表示相同曲線。相同次數、每段 t∈[0,1] 的參數化下,反射使接點的一階導數相同;不能略去前一個指令的條件,便宣稱所有接點都平滑。
橢圓弧 A 的七個參數
A 使用以下參數:
A rx ry x-axis-rotation large-arc-flag sweep-flag x y- rx、ry 是橢圓兩軸的半徑。
- x-axis-rotation 是橢圓旋轉角,以度表示。
- large-arc-flag 為 0 時選擇 180 度或以下的弧,為 1 時選擇 180 度或以上的弧;半圓時可能重合。
- sweep-flag 為 0 表示負角度方向,為 1 表示正角度方向。在一般 y 軸向下的 SVG 座標系中,分別看起來是逆時針和順時針。
- x、y 是終點。
一般情況最多有四個候選弧,但半徑修正後可能重合。負半徑按絕對值處理;任一半徑為零時改畫直線;起點與終點相同則省略該弧。單一 A 指令不能畫出完整圓形。
由端點形式換算中心與角度
SVG A 以端點、半徑、旋轉及旗標指定弧;需要中心形式的程式則要換算中心、起始角及掃掠角。SVG 1.1 附錄 F.6.5 提供這項轉換。
以下偽代碼中,(x1,y1) 和 (x2,y2) 是起點與終點,fA、fS 分別是 large-arc-flag、sweep-flag,phi 是已換成弧度的旋轉角。xp、yp 是轉換後的起點,cxp、cyp 是轉換座標中的中心;cx、cy 是原座標中的中心。^ 表示乘方,不是 JavaScript 的 XOR。
// 先處理相同端點和零半徑;rx、ry 取絕對值,phi 使用弧度
xp = cos(phi)*(x1-x2)/2 + sin(phi)*(y1-y2)/2
yp = -sin(phi)*(x1-x2)/2 + cos(phi)*(y1-y2)/2
lambda = (xp/rx)^2 + (yp/ry)^2
if lambda > 1:
rx *= sqrt(lambda)
ry *= sqrt(lambda)
sign = (fA != fS) ? +1 : -1
factor = sign * sqrt(max(0, (rx^2*ry^2 - rx^2*yp^2 - ry^2*xp^2) / (rx^2*yp^2 + ry^2*xp^2)))
cxp = factor * rx*yp / ry
cyp = factor * -ry*xp / rx
cx = cos(phi)*cxp - sin(phi)*cyp + (x1+x2)/2
cy = sin(phi)*cxp + cos(phi)*cyp + (y1+y2)/2
start = atan2((yp-cyp)/ry, (xp-cxp)/rx)
sweep = atan2((-yp-cyp)/ry, (-xp-cxp)/rx) - start
if !fS and sweep > 0: sweep -= 2*pi
if fS and sweep < 0: sweep += 2*pi當兩端點無法放入原半徑的橢圓時,先按 lambda 放大半徑。max(0,…) 避免捨入造成極小負數而無法開平方。極端數值仍可能溢位,因此這不是可直接取代完整數值函式庫的程式,也不是特定編輯器的內部實作保證。
四種圓形表示:精確與近似要分開
以下以 (100,100) 為中心、半徑 50 作比較。依次為 circle 元素、兩段 A、四段 C 近似及四段 Q 近似;circle 本身不是 path。
<circle cx="100" cy="100" r="50"/>
<path d="M 50,100 A 50,50 0 0 1 150,100 A 50,50 0 0 1 50,100"/>
<path d="M 100,50 C 127.614237,50 150,72.385763 150,100 C 150,127.614237 127.614237,150 100,150 C 72.385763,150 50,127.614237 50,100 C 50,72.385763 72.385763,50 100,50"/>
<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"/>四段 C 採用經典係數 κ=4(√2−1)/3≈0.5523。未捨入係數的最大徑向誤差約為半徑的 0.0273%;這並非所有誤差準則下的最優係數。四段 Q 的誤差更大,形狀較接近圓角方形。一般多項式 Bézier 曲線不是精確圓弧。
SVGO 的 convertShapeToPath 可透過 convertArcs 設定把 circle/ellipse 轉為 path,但不是永遠轉成四段 C。改換表示方式亦不保證檔案更小。
位置、切線與導數的連續性
每段參數均取 t∈[0,1] 時,可分開比較以下條件:
如表格未能完整顯示,可左右捲動。
| 條件 | 含義 |
|---|---|
| G⁰ | 接點位置相同,未指定有沒有角 |
| G¹ | 位置及切線方向相同,假設接點正則 |
| C¹ | 位置及一階導數相同 |
| C² | 符合 C¹,且二階導數相同 |
幾何上的曲率連續與 C² 並不等同。S/T 在上述條件下只保證一階導數相同,不會自動帶來 C²。SVG path 沒有直接指定 B-spline 或 NURBS 的指令,須轉成支援的分段或近似表示。
縮短 path 不等於完全保留效果
- 省略重複指令,例如將 L 10,10 L 20,20 寫成 L 10,10 20,20。
- 按字串長度選用絕對或相對座標。
- 減少小數位,但要接受可能改變形狀。
- 在適合時把基本形狀轉為 path。
- 控制點符合反射條件時,用 S/T 簡寫。
- 合併可安全合併的 path。
省略指令與捨入座標是不同操作。合併可能影響填色、標記、動畫或外部參照。保留原圖,按實際縮放比例和使用位置比較結果,不要把固定縮減率或完全相同外觀當作保證。
重點整理
- 10 類指令各有規則,M 的後續座標與 Z 的封閉尤其要留意。
- Bézier 曲線由控制點決定,可用 de Casteljau 評估及分割。
- S/T 的控制點反射取決於前一個指令。
- A 要處理退化情況、半徑修正、旗標及座標方向。
- 圓形近似、座標捨入與精確形狀保存並不相同。
參考資料及來源
編輯說明
本文使用 AI 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

