From c6c72fcca8405ababc14c96189929c7e4c6af5c2 Mon Sep 17 00:00:00 2001 From: DashyFox Date: Mon, 12 May 2025 17:25:43 +0300 Subject: [PATCH] Create TimeWarp.h --- TimeWarp.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 TimeWarp.h diff --git a/TimeWarp.h b/TimeWarp.h new file mode 100644 index 0000000..17c0fd0 --- /dev/null +++ b/TimeWarp.h @@ -0,0 +1,104 @@ +#pragma once +#include +#include // std::pair +#include // rand() +#include // std::sort + +class TimeWarp { +public: + struct Segment { + float t_start, t_end; // входной интервал + float y_start, y_end; // выходной интервал + bool is_plateau; + }; + +private: + std::vector segments; + +public: + TimeWarp(int numPlateaus, float minWidth, float maxWidth, unsigned int seed = 0) { + if (seed != 0) std::srand(seed); + + std::vector> plateaus; + + int maxTries = 1000; + int tries = 0; + float totalPlateauWidth = 0; + + // Сгенерировать непересекающиеся плато + while ((int)plateaus.size() < numPlateaus && tries++ < maxTries) { + float width = randRange(minWidth, maxWidth); + float start = randRange(0.0f, 1.0f - width); + float end = start + width; + + bool overlaps = false; + for (auto& p : plateaus) { + if (!(end <= p.first || start >= p.second)) { + overlaps = true; + break; + } + } + if (!overlaps) { + plateaus.emplace_back(start, end); + totalPlateauWidth += width; + } + } + + // Сортировать по началу + std::sort(plateaus.begin(), plateaus.end()); + + // Собрать сегменты + float currentT = 0.0f; + float currentY = 0.0f; + float dynamicSpan = 1.0f - totalPlateauWidth; + + for (auto& p : plateaus) { + float start = p.first; + float end = p.second; + + // Рамп перед плато + if (start > currentT) { + float t0 = currentT; + float t1 = start; + float ratio = (t1 - t0) / dynamicSpan; + float y1 = currentY + ratio; + segments.push_back({ t0, t1, currentY, y1, false }); + currentY = y1; + currentT = t1; + } + + // Плато + float width = end - start; + segments.push_back({ start, end, currentY, currentY, true }); + currentT = end; + } + + // Рамп после последнего плато + if (currentT < 1.0f) { + float t0 = currentT; + float t1 = 1.0f; + float ratio = (t1 - t0) / dynamicSpan; + float y1 = currentY + ratio; + segments.push_back({ t0, t1, currentY, y1, false }); + } + } + + float apply(float t) const { + for (const auto& seg : segments) { + if (t >= seg.t_start && t <= seg.t_end) { + if (seg.is_plateau) { + return seg.y_start; + } else { + float localT = (t - seg.t_start) / (seg.t_end - seg.t_start); + return seg.y_start + localT * (seg.y_end - seg.y_start); + } + } + } + return 1.0f; // если что-то пошло не так + } + +private: + float randRange(float minVal, float maxVal) { + return minVal + (std::rand() / (float)RAND_MAX) * (maxVal - minVal); + } +};