18 #include "dynamic_graph.h"
59 float interpolation = 0;
63 bool deleting =
false;
76 : m_phases{ phase::idle, phase::disappear, phase::morph, phase::appear } {}
86 : m_phases{ phase::idle, phase::simultaneous } {}
123 auto count = [&](phase p){
124 return std::count(phases.begin(), phases.end(), p);
126 unsigned a = count(phase::appear);
127 unsigned d = count(phase::disappear);
128 unsigned m = count(phase::morph);
129 unsigned s = count(phase::simultaneous);
130 bool either_three = a > 0 || d > 0 || m > 0;
131 bool three_correct = a == 1 && d == 1 && m == 1;
132 if (s > 1 || a > 1 || d > 1 || m > 1) {
133 throw std::invalid_argument(
"a phase != idle present multiple times");
135 if ((s == 0 && !three_correct)
136 || (s == 1 && either_three)) {
137 throw std::invalid_argument(
"invalid phases");
139 m_phases = std::move(phases);
142 const std::vector<phase>& get_phases()
const {
return m_phases; }
168 case phase::idle:
return m_idle_time;
169 case phase::appear:
return m_appear_time;
170 case phase::disappear:
return m_disappear_time;
171 case phase::morph:
return m_morph_time;
172 case phase::simultaneous:
return m_simultaneous_time;
173 default:
throw std::out_of_range(
"invalid phase");
183 for (
const auto& p : m_phases) {
209 throw std::out_of_range(
"time < 0");
211 if (time >
length(dgraph)) {
212 throw std::out_of_range(
"time > length()");
214 if (dgraph.
states().empty()) {
221 frame_state animation;
223 std::pair<float, unsigned> current = get_current_phase(value);
225 for (
unsigned i = 0; i < current.second; ++i) {
226 perform_phase(m_phases[i],
duration(m_phases[i]), animation);
229 perform_phase(m_phases[current.second], current.first, animation);
231 index_one = std::min<unsigned>(index_one, dgraph.
states().size() - 1);
232 index_two = std::min<unsigned>(index_two, dgraph.
states().size() - 1);
237 for (
auto& n : current_state.
nodes()) {
240 for (
auto& e : current_state.
edges()) {
243 for (
auto n : next_state.
nodes()) {
249 for (
auto e : next_state.
edges()) {
257 for (
auto&
node : current_state.
nodes()) {
260 node.
pos().x = lerp(
node.
pos().x, next.pos().x, animation.interpolation);
261 node.
pos().y = lerp(
node.
pos().y, next.pos().y, animation.interpolation);
263 calc_alpha(
node, animation);
265 for (
auto&
edge : current_state.
edges()) {
266 calc_alpha(
edge, animation);
268 return current_state;
272 std::vector<phase> m_phases;
273 float m_idle_time = 0.5;
274 float m_appear_time = 0.25;
275 float m_disappear_time = 0.25;
276 float m_morph_time = 1.0;
277 float m_simultaneous_time = 1.5;
279 float lerp(
float a,
float b,
float value)
const {
280 return a + value * (b - a);
285 void calc_alpha(T& element,
const frame_state& animation)
const {
286 bool is_new = element.is_new();
287 bool is_old = element.is_old();
288 if (!is_old && !is_new) {
291 if (is_new && !animation.added) {
294 if (is_old && animation.deleted) {
297 bool ape = is_new && animation.adding && !animation.added;
298 bool dis = is_old && animation.deleting;
300 element.alpha((!ape + animation.alpha * ape)
301 * (1.0f - animation.alpha * dis));
305 std::pair<float, unsigned> get_current_phase(
float time)
const {
306 for (
unsigned i = 0; i < m_phases.size(); ++i) {
313 throw std::out_of_range(
"time overflow phases");
316 void perform_phase(phase p,
float time, frame_state& animation)
const {
322 animation.adding = time < d;
323 animation.alpha = time / d;
325 animation.added =
true;
328 case phase::disappear:
329 animation.deleting = time < d;
330 animation.alpha = time / d;
332 animation.deleted =
true;
336 animation.interpolation = time / d;
338 case phase::simultaneous:
339 animation.adding = time < d;
340 animation.deleting = time < d;
341 animation.alpha = time / d;
342 animation.interpolation = time / d;
344 animation.deleted =
true;
345 animation.added =
true;