Create TimeWarp.h

This commit is contained in:
2025-05-12 17:25:43 +03:00
parent 9635922022
commit c6c72fcca8

104
TimeWarp.h Normal file
View File

@ -0,0 +1,104 @@
#pragma once
#include <vector>
#include <utility> // std::pair
#include <cstdlib> // rand()
#include <algorithm> // std::sort
class TimeWarp {
public:
struct Segment {
float t_start, t_end; // входной интервал
float y_start, y_end; // выходной интервал
bool is_plateau;
};
private:
std::vector<Segment> segments;
public:
TimeWarp(int numPlateaus, float minWidth, float maxWidth, unsigned int seed = 0) {
if (seed != 0) std::srand(seed);
std::vector<std::pair<float, float>> 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);
}
};