欢迎光临散文网 会员登陆 & 注册

【Aegisub】上篇代码

2021-08-27 11:38 作者:多华宫与火火里  | 我要投稿

        因为现在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





【Aegisub】上篇代码的评论 (共 条)

分享到微博请遵守国家法律