mirror of
https://github.com/Show-maket/Tween.git
synced 2025-06-27 20:59:36 +00:00
Create TimeWarp.h
This commit is contained in:
104
TimeWarp.h
Normal file
104
TimeWarp.h
Normal 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);
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user