【Aegisub】上篇代码

因为现在b站评论显示不出""引号和大于小于符号,所以就把上一篇专栏对应的代码发在这里,同时也是这个视频对应的代码
function Xshape.isZero(d)
return (d>-1e-6 and d<1e-6)
end
function Xshape.cuberoot(x)
return (x>0) and math.pow(x,(1/3)) or -math.pow(math.abs(x),(1/3))
end
function Xshape.solveQuadric(c0,c1,c2)
if Xshape.isZero(c0) then
if Xshape.isZero(c1) then
return nil
else
return -c2/c1
end
end
local p,q=c1/(2*c0),c2/c0 local D=p^2-q
if Xshape.isZero(D) then
return -p
elseif D<0 then
return
else
local sqrt_D=math.sqrt(D)
return sqrt_D-p,-sqrt_D-p
end
end
function Xshape.solveCubic(c0,c1,c2,c3)
if Xshape.isZero(c0) then
return Xshape.solveQuadric(c1,c2,c3)
end
local s0,s1,s2
local A,B,C=c1/c0,c2/c0,c3/c0
local p,q=(1/3)*(-(1/3)*A^2+B),0.5*((2/27)*A^3-(1/3)*A*B+C)
local D=q^2+p^3 local sub=(1/3)*A local n,a,b,c=c0*1000,c1*1000,c2*1000,c3*1000
local is_pZero=b==a^2/(n*3) local is_qZero=9*n*a*b-2*a^3==27*n*c local isDZero=is_qZero and is_pZero
if isDZero then
if is_qZero then
s0=-sub
else
local u=Xshape.cuberoot(-q)
s0=2*u-sub s1=-u-sub
end
elseif D<0 then
local phi=(1/3)*math.acos(-q/math.sqrt(-p^3))
local t=2*math.sqrt(-p)
local n1,n2=-t*math.cos(phi+math.pi/3)-sub,-t*math.cos(phi-math.pi/3)-sub
s0=t*math.cos(phi)-sub
if math.round(n1,5)~=math.round(s0,5) then
s1=n1
end
if s1 then
if math.round(n2,5)~=math.round(s0,5) and math.round(n2,5)~=math.round(s1,5) then
s2=n2
end
else
if math.round(n2,5)~=math.round(s0,5) then
s2=n2
end
end
else
local sqrt_D=math.sqrt(D)
local u=Xshape.cuberoot(sqrt_D-q)
local v=-Xshape.cuberoot(sqrt_D+q)
s0=u+v-sub
if math.round(s0,5)~=0 and math.round(s0,5)~=1 then
if Xshape.isZero(c0+c1+c2+c3) then
s1=1
elseif Xshape.isZero(c3) then
s1=0
end
end
end
return s0,s1,s2
end
绘图转像素:
function Xshape.get_px(ass_shape,d)
local _,T,_,B=Xshape.bounding(ass_shape) local px,each,iscet={},{} local step=d and 0.5 or 1
local function line(x1,y1,x2,y2,y)
local top,bottom=math.min(y1,y2),math.max(y1,y2)
if y>=top and y<bottom and bottom-top>1e-4 then
iscet[#iscet+1]={x1+((x2-x1)/(y2-y1))*(y-y1),Xshape.sgn(y2-y1)}
end
end
local function isTop(y1,y2,y3,y4)
local y={y1,y2,y3,y4}
for i=1,3 do
if y[i]<y[i+1] then
return 1
elseif y[i]>y[i+1] then
return 0
end
end
return 0
end
local function ignore_max_extreme_pt(x1,y1,y2,y3,x4,y4,t)
if t==0 then
iscet[#iscet+1]={x1,isTop(y1,y2,y3,y4)}
elseif t==1 then
iscet[#iscet+1]={x4,-isTop(y4,y3,y2,y1)}
end
end
local function count(x1,y1,x2,y2,x3,y3,x4,y4,t)
if t then
t=math.round(t,5)
if t<1 and t>0 then
local ang=-Xshape.angle_at(t,x1,y1,x2,y2,x3,y3,x4,y4)
iscet[#iscet+1]={Xshape.cubic_bezier(x1,x2,x3,x4,t),Xshape.sgn(ang%180==0 and 0 or ang)}
else ignore_max_extreme_pt(x1,y1,y2,y3,x4,y4,t)
end
end
end
local function bezier(x1,y1,x2,y2,x3,y3,x4,y4,y)
local top,bottom=math.min(y1,y2,y3,y4),math.max(y1,y2,y3,y4)
local left,right=math.min(x1,x2,x3,x4),math.max(x1,x2,x3,x4)
if right-left<1e-4 then
line(x1,y1,x4,y4,y)
else
if y>=top and y<=bottom and bottom-top>1e-4 then
local a,b,c,d=math.round(3*y2+y4-3*y3-y1,5),math.round(3*y1-6*y2+3*y3,5),math.round(3*y2-3*y1,5),math.round(y1,5)
local t1,t2,t3=Xshape.solveCubic(a,b,c,d-y)
count(x1,y1,x2,y2,x3,y3,x4,y4,t1) count(x1,y1,x2,y2,x3,y3,x4,y4,t2) count(x1,y1,x2,y2,x3,y3,x4,y4,t3)
end
end
end
for m in ass_shape:gmatch('m[^m]+') do
local cmd={}
for mlb in m:gmatch('[mlb][-. %d]+') do
local pt={}
for num in mlb:gmatch('([-.%d]+)') do
pt[#pt+1]=num*1
end
cmd[#cmd+1]=pt
end
if cmd[1][1]~=cmd[#cmd][#cmd[#cmd]-1] or cmd[1][2]~=cmd[#cmd][#cmd[#cmd]] then
cmd[#cmd+1]={cmd[1][1],cmd[1][2]}
end
for i=1,#cmd-1 do
if #cmd[i+1]==2 then
each[#each+1]={cmd[i][#cmd[i]-1],cmd[i][#cmd[i]],cmd[i+1][1],cmd[i+1][2]}
else
each[#each+1]={cmd[i][#cmd[i]-1],cmd[i][#cmd[i]],cmd[i+1][1],cmd[i+1][2],cmd[i+1][3],cmd[i+1][4],cmd[i+1][5],cmd[i+1][6]}
end
end
end
for y=T,B,step do
iscet={} local cnt=0
for i=1,#each do
if #each[i]==4 then
line(each[i][1],each[i][2],each[i][3],each[i][4],math.round(y*1,3))
else bezier(each[i][1],each[i][2],each[i][3],each[i][4],each[i][5],each[i][6],each[i][7],each[i][8],math.round(y*1,3))
end
end
table.sort(iscet,function (a,b) return a[1]<b[1] end)
for i=1,#iscet-1 do
cnt=cnt+iscet[i][2]
if cnt~=0 then
for x=math.round(iscet[i][1]),math.round(iscet[i+1][1])-1 do
px[#px+1]={x=x,y=math.round(y)}
end
end
end
end
return px
end
判断点包含:
function Xshape.contains_pt(ass_shape,pt_x,pt_y)
local cnt=0 local pt_x,pt_y=math.round(pt_x*1,3),math.round(pt_y*1,3)
local function line_isect_cnt(x1,y1,x2,y2,y)
local top,bottom=math.min(y1,y2),math.max(y1,y2)
if y>=top and y<bottom and bottom-top>1e-4 then
local x=x1+((x2-x1)/(y2-y1))*(y-y1)
if x and x<=pt_x then
cnt=cnt+Xshape.sgn(y2-y1)
end
end
end
local function isTop(y1,y2,y3,y4)
local y={y1,y2,y3,y4}
for i=1,3 do
if y[i]<y[i+1] then
return 1
elseif y[i]>y[i+1] then
return 0
end
end
return 0
end
local function ignore_max_extreme_pt(x1,y1,y2,y3,x4,y4,t,x)
if t==0 and x1<=x then
cnt=cnt+isTop(y1,y2,y3,y4)
elseif t==1 and x4<=x then
cnt=cnt-isTop(y4,y3,y2,y1)
end
end
local function count(x1,y1,x2,y2,x3,y3,x4,y4,t)
if t then
t=math.round(t,5)
if t<1 and t>0 then
if Xshape.cubic_bezier(x1,x2,x3,x4,t)<=pt_x then
local ang=-Xshape.angle_at(t,x1,y1,x2,y2,x3,y3,x4,y4)
cnt=cnt+Xshape.sgn(ang%180==0 and 0 or ang)
end
else ignore_max_extreme_pt(x1,y1,y2,y3,x4,y4,t,pt_x)
end
end
end
local function bezier_isect_cnt(x1,y1,x2,y2,x3,y3,x4,y4,y)
local top,bottom=math.min(y1,y2,y3,y4),math.max(y1,y2,y3,y4)
local left,right=math.min(x1,x2,x3,x4),math.max(x1,x2,x3,x4)
if right-left<1e-4 then
line_isect_cnt(x1,y1,x4,y4,y)
else
if y>=top and y<=bottom and bottom-top>1e-4 then
local a,b,c,d=math.round(3*y2+y4-3*y3-y1,5),math.round(3*y1-6*y2+3*y3,5),math.round(3*y2-3*y1,5),math.round(y1,5)
local t1,t2,t3=Xshape.solveCubic(a,b,c,d-y)
count(x1,y1,x2,y2,x3,y3,x4,y4,t1) count(x1,y1,x2,y2,x3,y3,x4,y4,t2) count(x1,y1,x2,y2,x3,y3,x4,y4,t3)
end
end
end
for m in ass_shape:gmatch('m[^m]+') do
local cmd={}
for mlb in m:gmatch('[mlb][-. %d]+') do
local pt={}
for num in mlb:gmatch('([-.%d]+)') do
pt[#pt+1]=num*1
end
cmd[#cmd+1]=pt
end
if cmd[1][1]~=cmd[#cmd][#cmd[#cmd]-1] or cmd[1][2]~=cmd[#cmd][#cmd[#cmd]] then
cmd[#cmd+1]={cmd[1][1],cmd[1][2]}
end
for i=1,#cmd-1 do
if #cmd[i+1]==2 then
line_isect_cnt(cmd[i][#cmd[i]-1],cmd[i][#cmd[i]],cmd[i+1][1],cmd[i+1][2],pt_y)
else
bezier_isect_cnt(cmd[i][#cmd[i]-1],cmd[i][#cmd[i]],cmd[i+1][1],cmd[i+1][2],cmd[i+1][3],cmd[i+1][4],cmd[i+1][5],cmd[i+1][6],pt_y)
end
end
end
return cnt~=0
end