Bezier n阶通用版本C++实现

#pragma once
#include "gstl.h"
#include <vector>
#include "SmoothSampling.h"

using namespace gstl;

/*
    n阶 bezier 曲线通用公式
*/
class GachaBazier
{
public:
    GachaBazier(const Vector2<f32>& start,const Vector2<f32>& dest);
    void addCtrlPoint(const Vector2<f32>& ctrlPoint);
    Vector2<f32> getInterpolatePos(float t);
private:
    float getKanbudong(float n, float i);
    float getJieCheng(int n);

private:
    Vector2<f32>    m_start;
    Vector2<f32>    m_dest;
    std::vector<Vector2<f32>>    m_ctrl;
};

class GachaBezierSmooth : public BoloScriptFastLib,public GachaBazier
{
generatedBoloObject(GachaBezierSmooth,"GachaBezierSmooth");
    GachaBezierSmooth();
    virtual ~GachaBezierSmooth();
public:
    void sampling(int fSamplingNum = 100);
    float getSmoothY(float fx);
    vec2 getMinSampling();
    vec2 getMaxSampling();

    void setStart(vec2 tStart);
    void setEnd(vec2 tEnd);

private:
    SmoothSampling m_tSmoothSampling;
    // 网页上 看到的 起始点和目标点都是 写死的 0,0  1,1 两个点, 对应返回的百分比需要按比例变大变小
    vec2 m_tStart;
    vec2 m_tEnd;
};


/*
    3次贝塞尔曲线差值器
    http://cubic-bezier.com

    css3 3次贝塞尔曲线 cubic-bezier
    https://blog.csdn.net/zhaozjc112/article/details/52909172/

    起点永远算作 (0,0) 终点永远算作 (1,1)

    控制点有且只有2个
    (m_x1,m_y1) (m_x2,m_y2)
*/
class GachaCubicBezierInter
{
public:
    GachaCubicBezierInter();
    ~GachaCubicBezierInter();

    void setPt1(float x,float y);
    void setPt2(float x,float y);
    void prepare();

    f32 getY(float x);
private:
    Vector2<f32>    m_pt1;
    Vector2<f32>    m_pt2;
    GachaBazier*    m_bezier = nullptr;
};
#include "GachaBezierInter.h"
#include <math.h>
#include <cassert>

extern float clampf(float& v, float min, float max);

GachaBazier::GachaBazier(const Vector2<f32>& start, const Vector2<f32>& dest)
{
    m_start = start;
    m_dest = dest;
    m_ctrl.push_back(m_start);
    m_ctrl.push_back(m_dest);
}

void GachaBazier::addCtrlPoint(const Vector2<f32>& point) {
    Vector2<f32> pt = point;
    size_t len = m_ctrl.size();
    m_ctrl.insert(m_ctrl.begin() + len - 1, pt);
}


Vector2<f32> GachaBazier::getInterpolatePos(float t) 
{
    //t = clampf(t, -1.f, 1.f);
    if (t < -1.f)
    {
        printf("dddaaa\n");
    }
    if (t < 0.f)
    {
        printf("fsfdsa\n");
    }
    if (t > 1.f)
    {
        printf("ddd\n");
    }
    Vector2<f32> pt;
    assert(m_ctrl.size() >= 2);

    int n = m_ctrl.size() - 1;
    for (int i = 0; i <= n; i++) {
        pt.x += getKanbudong(n, i) * pow((1 - t), n - i) * pow(t, i) * m_ctrl[i].x;
        pt.y += getKanbudong(n, i) * pow((1 - t), n - i) * pow(t, i) * m_ctrl[i].y;
    }

    return pt;
}

float GachaBazier::getKanbudong(float n, float i) {
    return getJieCheng(n) / (getJieCheng(i) * getJieCheng(n - i));
}

float GachaBazier::getJieCheng(int n) {
    float result = 1.0f;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }
    return result;
}

//////////////////////////////////////////////////////////////////////////

GachaBezierSmooth::~GachaBezierSmooth()
{

}

GachaBezierSmooth::GachaBezierSmooth() : GachaBazier(vec2::zero, vec2(1.f, 1.f))
{

}

void GachaBezierSmooth::setStart(vec2 tStart)
{
    m_tStart = tStart;
}

void GachaBezierSmooth::setEnd(vec2 tEnd)
{
    m_tEnd = tEnd;
}

void GachaBezierSmooth::sampling(int fSamplingNum)
{
    // 需要添加对应的采样点
    float fDelay = 1.f / fSamplingNum;
    for (float i = 0.f; i < 1.f; i += fDelay)
    {
        vec2 tVec2 = getInterpolatePos(i);
        tVec2 = (m_tEnd - m_tStart) * tVec2 + m_tStart;
        m_tSmoothSampling.insertPoint(tVec2.x, tVec2.y);
    }
}

float GachaBezierSmooth::getSmoothY(float fx)
{
    return m_tSmoothSampling.getSmooth(fx);
}

vec2 GachaBezierSmooth::getMinSampling()
{
    auto it = m_tSmoothSampling.m_sortMpSampling.begin();
    if (it == m_tSmoothSampling.m_sortMpSampling.end())
    {
        return vec2::zero;
    }
    return vec2(it->first, it->second);
}
vec2 GachaBezierSmooth::getMaxSampling()
{
    if (m_tSmoothSampling.m_sortMpSampling.size() <= 0)
    {
        return vec2::zero;
    }
    auto it = m_tSmoothSampling.m_sortMpSampling.end();
    it--;
    return vec2(it->first, it->second);
}

SC_Entry GachaBezierSmooth_setStart(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    float fx = bolo_float(stack);
    float fy = bolo_float(stack);
    pGachaBezierSmooth->setStart(vec2(fx, fy));
    return SC_Entry();
}

SC_Entry GachaBezierSmooth_setEnd(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    float fx = bolo_float(stack);
    float fy = bolo_float(stack);
    pGachaBezierSmooth->setEnd(vec2(fx, fy));
    return SC_Entry();
}

SC_Entry GachaBezierSmooth_addCtrlPoint(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    float fx = bolo_float(stack);
    float fy = bolo_float(stack);
    pGachaBezierSmooth->addCtrlPoint(vec2(fx, fy));
    return SC_Entry();
}

SC_Entry GachaBezierSmooth_sampling(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    int nSamplingNum = bolo_int(stack);
    pGachaBezierSmooth->sampling(nSamplingNum);
    return SC_Entry();
}

SC_Entry GachaBezierSmooth_getSmoothY(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    float fx = bolo_float(stack);
    return pGachaBezierSmooth->getSmoothY(fx);
}

SC_Entry GachaBezierSmooth_getMinSampling(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    vec2 tPos = pGachaBezierSmooth->getMinSampling();
    SC_Entry* pVec = new SC_Entry[2]
    {
        tPos.x, tPos.y
    };
    return SC_Entry(pVec, 2);
}

SC_Entry GachaBezierSmooth_getMaxSampling(BoloScriptFast* stack, BoloScriptFastLib* ptr)
{
    GachaBezierSmooth* pGachaBezierSmooth = dynamic_cast<GachaBezierSmooth*>(ptr);
    vec2 tPos = pGachaBezierSmooth->getMaxSampling();
    SC_Entry* pVec = new SC_Entry[2]
    {
        tPos.x, tPos.y
    };
    return SC_Entry(pVec, 2);
}


void GachaBezierSmooth::registerReflection(s32 id)
{
    registerFunc(id, "setStart", GachaBezierSmooth_setStart);
    registerFunc(id, "setEnd", GachaBezierSmooth_setEnd);
    registerFunc(id, "addCtrlPoint", GachaBezierSmooth_addCtrlPoint);
    registerFunc(id, "sampling", GachaBezierSmooth_sampling);
    registerFunc(id, "getSmoothY", GachaBezierSmooth_getSmoothY);
    registerFunc(id, "getMinSampling", GachaBezierSmooth_getMinSampling);
    registerFunc(id, "getMaxSampling", GachaBezierSmooth_getMaxSampling);
    
}

///////////////////////////////

GachaCubicBezierInter::GachaCubicBezierInter()
{
    m_pt1.x = 0.f;
    m_pt1.y = 0.f;
    m_pt2.x = 1.f;
    m_pt2.y = 1.f;

    Vector2<f32> start(0.f, 0.f);
    Vector2<f32> dest(1.f,1.f);
    m_bezier = new GachaBazier(start,dest);
}

GachaCubicBezierInter::~GachaCubicBezierInter()
{
    delete m_bezier;
    m_bezier = nullptr;
}

f32 GachaCubicBezierInter::getY(float x)
{
    Vector2<f32> pos = m_bezier->getInterpolatePos(x);
    return pos.y;
}

void GachaCubicBezierInter::setPt1(float x, float y)
{
    m_pt1.x = x;
    m_pt1.y = y;
}

void GachaCubicBezierInter::setPt2(float x, float y)
{
    m_pt2.x = x;
    m_pt2.y = y;
}

void GachaCubicBezierInter::prepare()
{
    m_bezier->addCtrlPoint(m_pt1);
    m_bezier->addCtrlPoint(m_pt2);
}

 

posted @ 2020-07-09 14:56  BackSword  阅读(522)  评论(0编辑  收藏  举报