本文深入探讨了NURBS曲线的概念、原理及应用,揭示了其在数字设计领域的独特价值和广泛影响。NURBS曲线作为一种强大的数学工具,为设计师们提供了更加灵活、精确的曲线创建方式,从而极大地提升了设计作品的质感和表现力。本文首先介绍了NURBS曲线的基本概念和数学原理,进而分析了其在工业设计、动画制作、3D打印等领域的实际应用。此外,本文还探讨了NURBS曲线的未来发展前景,以及它如何继续推动数字设计领域的创新和进步。
1. 基本理论
NURBS是非均匀有理B样条(Non-Uniform Rational B-Splines)的缩写。
学习得从更特殊的形式学起,否则会比较懵。来看看各种曲线的关系图。
所以,似乎先学贝塞尔曲线应该是个好的开始。
2. C++代码实现
2.1. 辅助结构体定义
struct ColOfMatrix {
int32_t start_;
int32_t end_;
std::vector<double> vec_;
ColOfMatrix() : start_(-1), end_(0) {
}
};
2.2. 分割参数空间
template<class Point3_T>
bool splitParamSpace(const std::vector<Point3_T> &vInputPoint,
const std::vector<int> &vDPIndex,
std::vector<float> &vU,
std::vector<float> &vKnot) const {
bool bRet = true;
if (vInputPoint.empty() || vDPIndex.empty()) {
LOG(ERROR) << "vInputPoint.size() = " << vInputPoint.size() << ", vDPIndex.size() = " << vDPIndex.size();
bRet = false;
} else if (vDPIndex.front() != 0 || vDPIndex.back() != static_cast<int>(vInputPoint.size()) - 1) {
LOG(ERROR) << "The first and last element of vDPIndex is: " << vDPIndex.front() << ", " << vDPIndex.back()
<< "vInputPoint.size() = " << vInputPoint.size();
bRet = false;
} else {
int32_t numDistance = static_cast<int>(vInputPoint.size()) - 1;
std::vector<float> vDistance;
vDistance.reserve(numDistance);
double tmpDistance, tmpDiff;
for (auto first = vInputPoint.begin(), second = first + 1; second < vInputPoint.end(); ++first, ++second) {
tmpDiff = first->x - second->x;
tmpDistance = tmpDiff * tmpDiff;
tmpDiff = first->z - second->z;
tmpDistance += tmpDiff * tmpDiff;
vDistance.emplace_back(std::sqrt(tmpDistance));
}
double sumDistance = std::accumulate(vDistance.begin(), vDistance.end(), 0.f);
//Generate the vector U, U is u bar
vU.clear();
vU.reserve(vInputPoint.size());
if (sumDistance < 0.1f) {
LOG(ERROR) << "The line is too short.";
bRet = false;
} else {
double divisor = 1.f / sumDistance, elem(0);
for (auto it = vDistance.begin(); it < vDistance.end(); ++it) {
vU.emplace_back(elem);
elem += (*it) * divisor;
if (elem - 1.f > FLT_MIN) {
elem = 1.f;
}
}
vU.emplace_back(1.f);
}
if (bRet) {
//generate knot
vKnot.clear();
vKnot.reserve(vDPIndex.size() + 4u);
vKnot.emplace_back(0);
vKnot.emplace_back(0);
for (auto it = vDPIndex.begin(); it < vDPIndex.end(); ++it) {
vKnot.emplace_back(vU[*it]);
}
vKnot.emplace_back(1);
vKnot.emplace_back(1);
}
}
return bRet;
}