此项目旨在生成常见的样条曲线,项目inspired by 叶飞影
首先是各种曲线的基类
#ifndef __SPLINE_BASE__ #define __SPLINE_BASE__ #include <cstddef> class SplineBase { public: // 计算样条数值 virtual bool BuildSpline(const void* ctrlValuesPtr, int ctrlStride, int ctrlCount, void* splineValuesPtr, int splineStride) const = NULL; // 计算切线数值 virtual bool BuildTangent(const void* ctrlValuesPtr, int ctrlStride, int ctrlCount, void* tangentValuesPtr, int tangentStride) const { return false; } }; inline float YfGetFloatValue(const void* valuesPtr, int stride, int index) { return *(float*)((char*)valuesPtr + stride * index); } #endif //__SPLINE_BASE__
每种曲线的类都会继承此基类,并实现 BuildSpline或者同时实现BuildSpline和Buildtangent两个函数。
N阶Bezier 曲线
1. 原理参考我的另外一篇博客:N 阶贝塞尔曲线生成,此篇代码每次都要计算N次方,比较耗时,可以在绘制图形之前,先计算好各阶数值即可。如下代码分别是bezier.h 和 bezier.cpp实现N阶贝塞尔曲线
/**************************************************************** File name : bezier.h Author : Shike Version : 1.0 Create Date : 2020/05/01 Description : Bezier Spline *****************************************************************/ #ifndef __BEZIER__SPLINE__ #define __BEZIER__SPLINE__ #include "spline_base.h" #define YD_MAX_BEZIER_CONTROL_VALUE 33 class Bezier : public SplineBase { public: Bezier(); ~Bezier(); // 设置输出样条值的数目 void SetSplineValuesCount(int count); // 获得输出样条值的数目 int GetSplineValuesCount() const; // 计算样条数值 bool BuildSpline(const void* ctrlValuesPtr, int ctrlStride, int ctrlCount, void* splineValuesPtr, int splineStride) const; protected: void ClearPowT(); void BuildPowT(); double GetValueT(int t, int p) const { return m_pow_t[YD_MAX_BEZIER_CONTROL_VALUE*t + p]; } protected: int m_valuesCount; double *m_pow_t; protected: static void BuildYanghuiTriangle(); //pascal's triangle static int m_yanghuiRowIndex[YD_MAX_BEZIER_CONTROL_VALUE]; static int m_yanghuiTriangle[(YD_MAX_BEZIER_CONTROL_VALUE + 1)*YD_MAX_BEZIER_CONTROL_VALUE / 2]; }; #endif // __BEZIER__SPLINE__
bezier.cpp
#include "bezier.h" #include "assert.h" #include "stdlib.h" #include <cstdio> int Bezier::m_yanghuiRowIndex[YD_MAX_BEZIER_CONTROL_VALUE] = { 0 }; int Bezier::m_yanghuiTriangle[(YD_MAX_BEZIER_CONTROL_VALUE + 1)*YD_MAX_BEZIER_CONTROL_VALUE / 2] = { 0 }; Bezier::Bezier() { if (m_yanghuiTriangle[0] == 0) { BuildYanghuiTriangle(); } m_valuesCount = 0; m_pow_t = NULL; SetSplineValuesCount(100); } Bezier::~Bezier() { ClearPowT(); } void Bezier::BuildYanghuiTriangle() { // 第0行 m_yanghuiRowIndex[0] = 0; m_yanghuiTriangle[0] = 1; int index = 1; int t0, t1; int* lastRow; for (int i = 1; i < YD_MAX_BEZIER_CONTROL_VALUE; i++) { m_yanghuiRowIndex[i] = index; m_yanghuiTriangle[index] = 1; index++; for (int j = 1; j <= i; j++) { lastRow = m_yanghuiTriangle + m_yanghuiRowIndex[i - 1]; t0 = lastRow[j - 1]; t1 = (j < i) ? lastRow[j] : 0; m_yanghuiTriangle[index] = t0 + t1; index++; } } assert(index == (YD_MAX_BEZIER_CONTROL_VALUE + 1)*YD_MAX_BEZIER_CONTROL_VALUE / 2); } //设置输出样条值的数目 void Bezier::SetSplineValuesCount(int count) { if (count < 2) { count = 2; } if (count == m_valuesCount) { return; } m_valuesCount = count; BuildPowT(); } //获得输出样条值的数目 int Bezier::GetSplineValuesCount() const { return m_valuesCount; } void Bezier::ClearPowT() { if (m_pow_t) { free(m_pow_t); m_pow_t = NULL; } } void Bezier::BuildPowT() { ClearPowT(); m_pow_t = (double*)malloc(m_valuesCount*YD_MAX_BEZIER_CONTROL_VALUE * sizeof(double)); double t; for (int i = 0; i < m_valuesCount; i++) { t = i / (m_valuesCount - 1.0f); m_pow_t[i*YD_MAX_BEZIER_CONTROL_VALUE] = 1.0f; for (int j = 1; j < YD_MAX_BEZIER_CONTROL_VALUE; j++) { m_pow_t[i*YD_MAX_BEZIER_CONTROL_VALUE + j] = m_pow_t[i*YD_MAX_BEZIER_CONTROL_VALUE + j - 1] * t; } } } //计算样条数值 bool Bezier::BuildSpline(const void* ctrlValuesPtr, int ctrlStride, int ctrlCount, void* splineValuesPtr, int splineStride) const { if (ctrlCount < 2 || ctrlCount > YD_MAX_BEZIER_CONTROL_VALUE) { return false; } double* destValue; double* srcValue; double v; const int* yanghuiRow = m_yanghuiTriangle + m_yanghuiRowIndex[ctrlCount - 1]; for (int i = 0; i < m_valuesCount; i++) { for (int dim = 0; dim < ctrlStride; dim++) { v = 0.0f; for (int j = 0; j < ctrlCount; j++) { srcValue = (double*)ctrlValuesPtr + ctrlStride * j + dim; v += yanghuiRow[j] * (*srcValue) * GetValueT(i, j) * GetValueT(m_valuesCount - 1 - i, ctrlCount - 1 - j); } destValue = (double*)splineValuesPtr + splineStride * i + dim; *destValue = v; } } return true; }
显示效果如下