穿过已知点画平滑曲线-lua

参考原文

https://www.iteye.com/blog/westice-745173

贝塞尔曲线

为了把一串点连成光滑的曲线,先研究贝塞尔曲线,又搞B样条插值。。。。都没有成功(数学没那么强)。

后来在

[翻译] AGG 之贝塞尔插值http://liyiwen.iteye.com/blog/705489 。看到一种比较好的方法:

运用贝塞尔曲线的光滑性来穿过这些点。

大致思路就是 先算出相邻原始点的中点,在把相邻中点连成的线段平移到对应的原始点,以平移后的中点作为控制点,相邻原始点为起始点画贝塞尔曲线,这样就保证了连接处的光滑。而贝塞尔曲线本身是光滑的,所以就把这些原始点用光滑曲线连起来了。

lua代码


---@class Bezier
local Bezier = Lib.class("Bezier")
local new = Bezier.new
function Bezier:ctor()
end

-- local originPoint = {
--         [1] = Lib.v2(0,600),
--         [2] = Lib.v2(100,500),
--         [3] = Lib.v2(200,300),
--         [4] = Lib.v2(600,0),
--     }
function Bezier:createCurve(originPoint)
    local scale = 0.6

    -- 控制点收缩系数 ,经调试0.6较好,CvPoint是opencv的,可自行定义结构体(x,y)
    local originCount = #originPoint

    local midpoints = {}
    -- 生成中点
    for i = 1, originCount do
        midpoints[i] = {}
        local nexti = i+1;
        if nexti == originCount + 1 then
            nexti = 1
        end
        local prei = i-1;
        if prei == 0 then
            prei = originCount
        end
        midpoints[i].prei = prei
        midpoints[i].nexti = nexti
        midpoints[i].x = (originPoint[i].x + originPoint[nexti].x)/2.0;
        midpoints[i].y = (originPoint[i].y + originPoint[nexti].y)/2.0;
    end

    -- 平移中点,originPoint[i] 的前后两个中点,也就是midpoints[i] 和 midpoints[i-1] 的平移点
    local extrapoints1 = {}
    local extrapoints2 = {}

    for i = 1, originCount do
        extrapoints1[i] = {}
        extrapoints2[i] = {}
    end

    for i = 1, originCount do
        local prei = midpoints[i].prei;

        local midinmid = {}
        midinmid.x = (midpoints[i].x + midpoints[prei].x)/2.0;
        midinmid.y = (midpoints[i].y + midpoints[prei].y)/2.0;
        local offsetx = originPoint[i].x - midinmid.x;
        local offsety = originPoint[i].y - midinmid.y;

        extrapoints1[i].x = midpoints[i].x + offsetx
        extrapoints1[i].y = midpoints[i].y + offsety
        --朝 originPoint[i]方向收缩   
        local addx = (extrapoints1[i].x - originPoint[i].x) * scale;
        local addy = (extrapoints1[i].y - originPoint[i].y) * scale;
        extrapoints1[i].x = originPoint[i].x + addx
        extrapoints1[i].y = originPoint[i].y + addy

        extrapoints2[prei].x = midpoints[prei].x + offsetx
        extrapoints2[prei].y = midpoints[prei].y + offsety
        --朝 originPoint[i]方向收缩
        addx = (extrapoints2[prei].x - originPoint[i].x) * scale
        addy = (extrapoints2[prei].y - originPoint[i].y) * scale
        extrapoints2[prei].x = originPoint[i].x + addx
        extrapoints2[prei].y = originPoint[i].y + addy
    end

    local curvePoint = {}
    local controlList = {}
    --生成4控制点,产生贝塞尔曲线
    for i = 1, originCount-1 do
        local controlPoint = {}
        controlPoint[1] = originPoint[i]
        controlPoint[2] = extrapoints1[i]
        controlPoint[3] = extrapoints2[i]
        local nexti = i+1;
        if i == originCount then
            nexti = 1
        end
        controlPoint[4] = originPoint[nexti]
        local u = 1
        while(u >= 0) do
            local px = self:bezier3funcX(u,controlPoint)
            local py = self:bezier3funcY(u,controlPoint)
            --u的步长决定曲线的疏密
            u = u - 0.05
            local tempP = Lib.v2(px,py)
            --存入曲线点
            table.insert(curvePoint, tempP)
        end
        table.insert(controlList, controlPoint)
    end
    return curvePoint
end

-- 三次贝塞尔曲线
function Bezier:bezier3funcX(uu, controlP)
    local part0 = controlP[1].x * uu * uu * uu;
    local part1 = 3 * controlP[2].x * uu * uu * (1 - uu);
    local part2 = 3 * controlP[3].x * uu * (1 - uu) * (1 - uu);
    local part3 = controlP[4].x * (1 - uu) * (1 - uu) * (1 - uu);
    return part0 + part1 + part2 + part3;
end

function Bezier:bezier3funcY(uu, controlP)
    local part0 = controlP[1].y * uu * uu * uu;
    local part1 = 3 * controlP[2].y * uu * uu * (1 - uu);
    local part2 = 3 * controlP[3].y * uu * (1 - uu) * (1 - uu);
    local part3 = controlP[4].y * (1 - uu) * (1 - uu) * (1 - uu);
    return part0 + part1 + part2 + part3;
end
return Bezier


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值