You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SVG S命令贝塞尔曲线转数学公式后路径不匹配问题排查

问题描述

我有一段SVG路径:M 0, 100 S 27, 2, 200 0,尝试用贝塞尔方程将其转换为数学公式绘制线条,但发现SVG绘制的蓝色线条和公式计算出的红色线条不匹配。是不是我在提取控制点的时候理解错了?

原始代码

let c = document.getElementById('c')
let ctx = c.getContext('2d')

ctx.strokeStyle = 'blue'
ctx.stroke(new Path2D(`M 0, 100  S 27, 2, 200 0`))

// bezier control points, derived from SVG path
let x1 = 0,    y1 = 100,
    x2 = 27,   y2 = 2,
    x3 = 200,  y3 = 0

ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.moveTo(x1, y1)

for(let t=0; t<=1; t+=0.0001) {
  ctx.lineTo(
    (1-t)**2 * x1 + 2*(1-t) * t * x2 + t**2 * x3,
    (1-t)**2 * y1 + 2*(1-t) * t * y2 + t**2 * y3
  )
}
ctx.stroke()
<canvas id="c" width="200" height="100"></canvas>
问题原因与解决方法

你错把SVG的S命令当成了二次贝塞尔曲线,但实际上S是光滑三次贝塞尔曲线的简写,对应的是三次贝塞尔公式,不是二次。

SVG S命令的规则

S x2,y2 x,y 表示从当前点绘制一条光滑三次贝塞尔曲线到终点(x,y):

  • 如果前一个路径段是贝塞尔曲线(C/S/Q/T),则第一个控制点是前一段第二个控制点关于当前点的对称点;
  • 如果前一个路径段不是贝塞尔曲线(比如这里的M命令),则第一个控制点等于当前点(起点);
  • 第二个控制点是你指定的(x2,y2),终点是(x,y)。

所以你的S 27,2 200,0对应的完整三次贝塞尔控制点是:

  • P0(起点):(0, 100)
  • P1(第一个控制点):(0, 100)(因为前面是M命令,无前置贝塞尔控制点)
  • P2(第二个控制点):(27, 2)
  • P3(终点):(200, 0)

修正后的代码

let c = document.getElementById('c')
let ctx = c.getContext('2d')

ctx.strokeStyle = 'blue'
ctx.stroke(new Path2D(`M 0, 100  S 27, 2, 200 0`))

// 正确解析SVG S命令的三次贝塞尔控制点
let x0 = 0,    y0 = 100,
    x1 = 0,    y1 = 100, // 自动生成的第一个控制点
    x2 = 27,   y2 = 2,
    x3 = 200,  y3 = 0

ctx.strokeStyle = 'red'
ctx.beginPath()
ctx.moveTo(x0, y0)

for(let t=0; t<=1; t+=0.0001) {
  ctx.lineTo(
    (1-t)**3 * x0 + 3*(1-t)**2 * t * x1 + 3*(1-t)*t**2 * x2 + t**3 * x3,
    (1-t)**3 * y0 + 3*(1-t)**2 * t * y1 + 3*(1-t)*t**2 * y2 + t**3 * y3
  )
}
ctx.stroke()
<canvas id="c" width="200" height="100"></canvas>

修改后,红色线条会和蓝色线条完全重合。

内容的提问来源于stack exchange,提问作者Andrew Parks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:33:38