Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarSpline.hpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarSpline.hpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/core/StarSpline.hpp')
-rw-r--r--source/core/StarSpline.hpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/source/core/StarSpline.hpp b/source/core/StarSpline.hpp
new file mode 100644
index 0000000..4656eaa
--- /dev/null
+++ b/source/core/StarSpline.hpp
@@ -0,0 +1,158 @@
+#ifndef STAR_SPLINE_HPP
+#define STAR_SPLINE_HPP
+
+#include "StarVector.hpp"
+#include "StarInterpolation.hpp"
+#include "StarLogging.hpp"
+#include "StarLruCache.hpp"
+
+namespace Star {
+
+// Implementation of DeCasteljau Algorithm for Bezier Curves
+template <typename DataT, size_t Dimension, size_t Order, class PointT = Vector<DataT, Dimension>>
+class Spline : public Array<PointT, Order + 1> {
+public:
+ typedef Array<PointT, Order + 1> PointData;
+
+ template <typename... T>
+ Spline(PointT const& e1, T const&... rest)
+ : PointData(e1, rest...) {
+ m_pointCache.setMaxSize(1000);
+ m_lengthCache.setMaxSize(1000);
+ }
+
+ Spline() : PointData(PointData::filled(PointT())) {
+ m_pointCache.setMaxSize(1000);
+ m_lengthCache.setMaxSize(1000);
+ }
+
+ PointT pointAt(float t) const {
+ float u = clamp<float>(t, 0, 1);
+ if (u != t) {
+ t = u;
+ Logger::warn("Passed out of range time to Spline::pointAt");
+ }
+
+ if (auto p = m_pointCache.ptr(t))
+ return *p;
+
+ PointData intermediates(*this);
+ PointData temp;
+ for (size_t order = Order + 1; order > 1; order--) {
+ for (size_t i = 1; i < order; i++) {
+ temp[i - 1] = lerp(t, intermediates[i - 1], intermediates[i]);
+ }
+ intermediates = std::move(temp);
+ }
+
+ m_pointCache.set(t, intermediates[0]);
+ return intermediates[0];
+ }
+
+ PointT tangentAt(float t) const {
+ float u = clamp<float>(t, 0, 1);
+ if (u != t) {
+ t = u;
+ Logger::warn("Passed out of range time to Spline::tangentAt");
+ }
+
+ // constructs a hodograph and returns pointAt
+ Spline<DataT, Dimension, Order - 1> hodograph;
+ for (size_t i = 0; i < Order; i++) {
+ hodograph[i] = ((*this)[i + 1] - (*this)[i]) * Order;
+ }
+ return hodograph.pointAt(t);
+ }
+
+ DataT length(float begin = 0, float end = 1, size_t subdivisions = 100) const {
+ if (!(begin <= 1 && begin >= 0 && end <= 1 && end >= 0 && begin <= end)) {
+ Logger::warn("Passed invalid range to Spline::length");
+ return 0;
+ }
+
+ if (!begin) {
+ if (auto p = m_lengthCache.ptr(end))
+ return *p;
+ }
+
+ DataT res = 0;
+ PointT previousPoint = pointAt(begin);
+ for (size_t i = 1; i <= subdivisions; i++) {
+ PointT currentPoint = pointAt(i / subdivisions * (end - begin));
+ res += (currentPoint - previousPoint).magnitude();
+ previousPoint = currentPoint;
+ }
+
+ if (!begin)
+ m_lengthCache.set(end, res);
+
+ return res;
+ }
+
+ float arcLenPara(float u, DataT epsilon = .01) const {
+ if (u == 0)
+ return 0;
+ if (u == 1)
+ return 1;
+ u = clamp<float>(u, 0, 1);
+ if (u == 0 || u == 1) {
+ Logger::warn("Passed out of range time to Spline::arcLenPara");
+ return u;
+ }
+ DataT targetLength = length() * u;
+ float t = .5;
+ float lower = 0;
+ float upper = 1;
+ DataT approxLen = length(0, t);
+ while (targetLength - approxLen > epsilon || targetLength - approxLen < -epsilon) {
+ if (targetLength > approxLen) {
+ lower = t;
+ } else {
+ upper = t;
+ }
+ t = (upper - lower) * .5 + lower;
+ approxLen = length(0, t);
+ }
+ return t;
+ }
+
+ PointT& origin() {
+ m_pointCache.clear();
+ m_lengthCache.clear();
+ return (*this)[0];
+ }
+
+ PointT const& origin() const {
+ return (*this)[0];
+ }
+
+ PointT& dest() {
+ m_pointCache.clear();
+ m_lengthCache.clear();
+ return (*this)[Order];
+ }
+
+ PointT const& dest() const {
+ return (*this)[Order];
+ }
+
+ PointT& operator[](size_t index) {
+ m_pointCache.clear();
+ m_lengthCache.clear();
+ return PointData::operator[](index);
+ }
+
+ PointT const& operator[](size_t index) const {
+ return PointData::operator[](index);
+ }
+
+protected:
+ mutable LruCache<float, PointT> m_pointCache;
+ mutable LruCache<float, DataT> m_lengthCache;
+};
+
+typedef Spline<float, 2, 3, Vec2F> CSplineF;
+
+}
+
+#endif