feat(渲染编辑): 补全网格渐变与径向延伸
build.yaml / build (push) Successful in 42s

This commit is contained in:
xiaoqidun committed 2026-09-27 13:44:41 +08:00
1 parent affc84459e
commit e78ea6f919
18 files changed
+567 -51

No files matched your search

+47 -6
View File
@@ -81,15 +81,18 @@ type RasterGradientKind uint8
const (
RasterLinear RasterGradientKind = iota
RasterRadial
RasterMesh
)
// RasterGradient 局部坐标下的线性或双圆径向渐变,Spread为空时延续边界颜色
// RasterGradient 局部坐标下的轴向、双圆径向或三角网格渐变
// 轴向及径向渐变的Spread为空时延续边界颜色,网格渐变使用Mesh
type RasterGradient struct {
Kind RasterGradientKind
Start, End RasterPoint
R0, R1 float64
Stops []ColorStop
Spread *RasterSpread
Mesh *MeshShading
}
// RasterSpread 保存OFD渐变延伸和周期,nil表示连续延伸
@@ -140,19 +143,30 @@ func (m RasterMatrix) Inverse() (RasterMatrix, error) {
// 入参: x 横坐标, y 纵坐标
// 返回: color.RGBA 采样颜色
func (g *RasterGradient) At(x, y float64) color.RGBA {
if g.Kind == RasterMesh {
return g.Mesh.At(x, y)
}
dx, dy := g.End.X-g.Start.X, g.End.Y-g.Start.Y
px, py := x-g.Start.X, y-g.Start.Y
t := 0.0
if g.Kind == RasterRadial {
dr := g.R1 - g.R0
a, b, c := dx*dx+dy*dy-dr*dr, -2*(px*dx+py*dy+g.R0*dr), px*px+py*py-g.R0*g.R0
t = rasterRadialPosition(a, b, c, g.R0, dr)
if g.Spread != nil && math.Hypot(dx, dy) < math.Abs(dr) {
d := b*b - 4*a*c
if d < 0 {
if g.Spread != nil && math.Hypot(dx, dy) >= math.Abs(dr) {
var ok bool
t, ok = rasterRadialDomain(a, b, c, g.R0, dr, g.Spread.Extend)
if !ok {
return color.RGBA{}
}
t = (-b - math.Copysign(math.Sqrt(d), dr)) / (2 * a)
} else {
t = rasterRadialPosition(a, b, c, g.R0, dr)
if g.Spread != nil && math.Hypot(dx, dy) < math.Abs(dr) {
d := b*b - 4*a*c
if d < 0 {
return color.RGBA{}
}
t = (-b - math.Copysign(math.Sqrt(d), dr)) / (2 * a)
}
}
} else if length := dx*dx + dy*dy; length > 0 {
t = (px*dx + py*dy) / length
@@ -175,6 +189,33 @@ func (g *RasterGradient) At(x, y float64) color.RGBA {
return g.colorAt(t)
}
// rasterRadialDomain 求延伸区间内半径非负的最后一个双圆参数
// 入参: a、b、c 方程系数, radius 起始半径, delta 半径变化, extend 延伸标志
// 返回: float64 参数, bool 是否覆盖采样点
func rasterRadialDomain(a, b, c, radius, delta float64, extend int) (float64, bool) {
x, y := math.NaN(), math.NaN()
if a == 0 {
if b != 0 {
x = -c / b
}
} else if d := b*b - 4*a*c; d >= 0 {
q := -.5 * (b + math.Copysign(math.Sqrt(d), b))
if q == 0 {
x = -b / (2 * a)
} else {
x, y = q/a, c/q
}
}
best := math.Inf(-1)
for _, t := range []float64{x, y} {
if !finite(t) || radius+delta*t < 0 || t < 0 && extend&1 == 0 || t > 1 && extend&2 == 0 {
continue
}
best = math.Max(best, t)
}
return best, !math.IsInf(best, -1)
}
// rasterRadialPosition 求双圆渐变中半径非负的有效参数
// 入参: a 二次项系数, b 一次项系数, c 常数项, radius 起始半径, delta 半径增量
// 返回: float64 渐变位置,范围为0至1