| 106 | } |
| 107 | |
| 108 | std::vector<double> LNLib::Interpolation::GetCentripetalParameterization(const std::vector<XYZ>& throughPoints) |
| 109 | { |
| 110 | const size_t size = throughPoints.size(); |
| 111 | |
| 112 | if (size == 0) { |
| 113 | return {}; |
| 114 | } |
| 115 | if (size == 1) { |
| 116 | return { 0.0 }; |
| 117 | } |
| 118 | if (size == 2) { |
| 119 | return { 0.0, 1.0 }; |
| 120 | } |
| 121 | |
| 122 | std::vector<double> segmentLengths; |
| 123 | segmentLengths.reserve(size - 1); |
| 124 | double totalLength = 0.0; |
| 125 | |
| 126 | for (size_t i = 1; i < size; ++i) { |
| 127 | double euclideanDist = throughPoints[i].Distance(throughPoints[i - 1]); |
| 128 | double centripetalSeg = std::sqrt(euclideanDist); |
| 129 | segmentLengths.push_back(centripetalSeg); |
| 130 | totalLength += centripetalSeg; |
| 131 | } |
| 132 | |
| 133 | if (MathUtils::IsAlmostEqualTo(totalLength, 0.0)) { |
| 134 | std::vector<double> uk(size); |
| 135 | for (size_t i = 0; i < size; ++i) { |
| 136 | uk[i] = static_cast<double>(i) / static_cast<double>(size - 1); |
| 137 | } |
| 138 | return uk; |
| 139 | } |
| 140 | |
| 141 | std::vector<double> uk(size); |
| 142 | uk[0] = 0.0; |
| 143 | uk[size - 1] = 1.0; |
| 144 | |
| 145 | double accumulated = 0.0; |
| 146 | for (size_t i = 1; i < size - 1; ++i) { |
| 147 | accumulated += segmentLengths[i - 1]; |
| 148 | uk[i] = accumulated / totalLength; |
| 149 | } |
| 150 | |
| 151 | return uk; |
| 152 | } |
| 153 | |
| 154 | std::vector<double> LNLib::Interpolation::AverageKnotVector(int degree, const std::vector<double>& params) |
| 155 | { |