SVG path 指令解析:貝茲曲線、S/T 接點與橢圓弧 A
DDEVELOPER
開發發布: 12 分鐘閱讀

SVG path 指令解析:貝茲曲線、S/T 接點與橢圓弧 A

SVG path 用移動、直線、曲線與封閉指令描述形狀。讀取 M10,10 C20,20 40,20 50,10 時,先分清目前點、控制點與終點,就能理解路徑。本文依照 SVG 2 的 Paths 章(2018 年 10 月 4 日候選推薦標準)與 SVG 1.1 的橢圓弧實作附註,說明幾何與編輯時的限制。

日文原文發布: 2026-04-25

10 類指令與大小寫規則

表格若超出畫面寬度,可左右捲動。

指令參數用途
M / mx y移動,不畫線
L / lx y直線
H / hx水平線
V / vy垂直線
C / cx1 y1 x2 y2 x y三次貝茲曲線
S / sx2 y2 x y依前一段 C/S 反射控制點
Q / qx1 y1 x y二次貝茲曲線
T / tx y依前一段 Q/T 反射控制點
A / arx ry rotation large-arc sweep x y橢圓弧
Z / z封閉目前子路徑

大寫使用絕對座標,小寫使用相對於目前點的座標;Z/z 沒有座標參數,兩者作用相同。同一指令可連續給參數,例如 L 10,20 30,40 50,60 畫出三段直線。M 後第二組起的座標視為 L。

Z 將路徑封閉,描邊會使用接合處理;只用 L 回到起點,仍可能保留開放路徑的端點樣式,兩者不完全相同。

三次貝茲曲線的四個控制點

三次貝茲曲線由 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 基底的權重在此範圍內非負,總和為 1。曲線通過 P₀ 與 P₃,一般不通過中間的 P₁、P₂;整條曲線位於全部四個控制點的凸包內。平移、旋轉或縮放控制點,曲線也會跟著做相同的仿射變換。

端點導數為 B′(0)=3(P₁−P₀)、B′(1)=3(P₃−P₂)。若向量為零,不能只靠這個式子決定切線方向。C 指令以目前點作 P₀,三組參數依序給出 P₁、P₂、P₃。

用 de Casteljau 演算法求值與分割

de Casteljau 反覆使用線性內插來求曲線上的點,通常比直接展開多項式更穩定,但仍有浮點捨入誤差。以下為虛擬碼:

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 處分成兩條貝茲曲線,在數學上保持原形狀。t=0.5 的分割可作為編輯器「在曲線中加入節點」的基礎,但不能據此斷言每套編輯器的所有操作都使用同一實作。

S/T 何時會反射控制點?

只有前一個指令是 C 或 S 時,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

這兩條路徑相同。相同次數、各段都以 t∈[0,1] 參數化時,反射會使接點的一階導數相同;不能省略前一指令的條件,將 S/T 當成任何接點都平滑的保證。

橢圓弧 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 1.1 附錄 F.6.5 說明端點、半徑與旗標如何換成中心、起始角與掃掠角。x1、y1 是起點,x2、y2 是終點,rx、ry 是半徑,phi 對應旋轉角 φ,fA 是 large-arc-flag,fS 是 sweep-flag。以下先排除同點與零半徑,將半徑取絕對值,並將旋轉角 φ 從度換成弧度:

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

先旋轉到橢圓座標系,再以 λ 判斷半徑是否足以連接端點;λ>1 時兩個半徑同乘 √λ。接著選取中心符號,轉回原座標,最後依 sweep-flag 修正角度方向。

虛擬碼中的 ^ 表示乘方,不是 JavaScript 的 XOR 運算子。max(0, …) 處理捨入造成的小幅負值。這段是解釋公式的虛擬碼,並非完整數值函式庫;極端值仍可能溢位,也不能用來保證特定編輯器的內部演算法。

用四種方式描述圓

以下以 (100,100) 為圓心、半徑 50,比較 circle 元素、兩段 A、四段 C 與四段 Q。後兩者是近似:

<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.0273%。它讓端點與中點落在圓上,並非每種誤差指標下的最佳係數。四段 Q 的近似誤差更大;多項式貝茲曲線一般不等於真正圓弧。

SVGO 的 convertShapeToPath 可透過 convertArcs 設定轉換 circle/ellipse,但不是「一律轉成四段 C」。改變元素表示也不一定縮小檔案。

G⁰、G¹、C¹、C² 的差異

表格若超出畫面寬度,可左右捲動。

條件接點要求
G⁰位置相同,未保證沒有尖角
位置與切線方向相同,假設接點正則
位置與一階導數相同
滿足 C¹,且二階導數相同

各段的參數範圍皆取 [0,1]。幾何上的曲率連續不等於 C²;S/T 的反射也只在上述條件下保證一階導數相同。SVG path 沒有直接表示 B-spline 或 NURBS 的指令,需要轉成可表示的分段或近似。

縮短 path 時要保留哪些條件?

  • 省略重複指令,例如 L 10,10 L 20,20 改成 L 10,10 20,20。
  • 比較絕對與相對座標,選擇較短的表示。
  • 在符合反射條件時用 S/T 縮寫。
  • 減少小數位、轉換基本形狀或合併可合併的路徑。

省略指令與捨入座標是不同操作。捨入會改變形狀,合併路徑也可能影響填色、標記、動畫與外部參照。保留原檔,依實際縮放比例與使用情境比較,不保證固定縮減率或完全相同的外觀。

重點整理

  • path 有 10 類指令,M 的連續參數與 Z/z 有各自規則。
  • 貝茲曲線可由控制點求值,de Casteljau 也可用於分割。
  • S/T 的反射取決於前一指令。
  • A 要處理退化情況、半徑修正、旗標與座標方向。
  • 圓形近似與座標捨入不能當作精確保形。

參考資料與來源

編輯說明

本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

相關文章