Enhanced ShapeRule type to carry more information and to be easier to use
This commit is contained in:
parent
b02f37e961
commit
9c9d79c54d
|
@ -226,8 +226,8 @@ add_library(rhubarb-animation
|
||||||
src/animation/pauseAnimation.h
|
src/animation/pauseAnimation.h
|
||||||
src/animation/roughAnimation.cpp
|
src/animation/roughAnimation.cpp
|
||||||
src/animation/roughAnimation.h
|
src/animation/roughAnimation.h
|
||||||
src/animation/shapeRule.cpp
|
src/animation/ShapeRule.cpp
|
||||||
src/animation/shapeRule.h
|
src/animation/ShapeRule.h
|
||||||
src/animation/shapeShorthands.h
|
src/animation/shapeShorthands.h
|
||||||
src/animation/targetShapeSet.cpp
|
src/animation/targetShapeSet.cpp
|
||||||
src/animation/targetShapeSet.h
|
src/animation/targetShapeSet.h
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "shapeRule.h"
|
#include "ShapeRule.h"
|
||||||
#include <boost/range/adaptor/transformed.hpp>
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
#include "ContinuousTimeline.h"
|
#include "ContinuousTimeline.h"
|
||||||
|
|
||||||
|
@ -13,12 +13,37 @@ ContinuousTimeline<optional<T>, AutoJoin> boundedTimelinetoContinuousOptional(co
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShapeRule::ShapeRule(const ShapeSet& shapeSet, const optional<Phone>& phone, TimeRange phoneTiming) :
|
||||||
|
shapeSet(shapeSet),
|
||||||
|
phone(phone),
|
||||||
|
phoneTiming(phoneTiming)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ShapeRule ShapeRule::getInvalid() {
|
||||||
|
return {{}, boost::none,{0_cs, 0_cs}};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeRule::operator==(const ShapeRule& rhs) const {
|
||||||
|
return shapeSet == rhs.shapeSet && phone == rhs.phone && phoneTiming == rhs.phoneTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeRule::operator!=(const ShapeRule& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeRule::operator<(const ShapeRule& rhs) const {
|
||||||
|
return shapeSet < rhs.shapeSet
|
||||||
|
|| phone < rhs.phone
|
||||||
|
|| phoneTiming.getStart() < rhs.phoneTiming.getStart()
|
||||||
|
|| phoneTiming.getEnd() < rhs.phoneTiming.getEnd();
|
||||||
|
}
|
||||||
|
|
||||||
ContinuousTimeline<ShapeRule> getShapeRules(const BoundedTimeline<Phone>& phones) {
|
ContinuousTimeline<ShapeRule> getShapeRules(const BoundedTimeline<Phone>& phones) {
|
||||||
// Convert to continuous timeline so that silences aren't skipped when iterating
|
// Convert to continuous timeline so that silences aren't skipped when iterating
|
||||||
auto continuousPhones = boundedTimelinetoContinuousOptional(phones);
|
auto continuousPhones = boundedTimelinetoContinuousOptional(phones);
|
||||||
|
|
||||||
// Create timeline of shape rules
|
// Create timeline of shape rules
|
||||||
ContinuousTimeline<ShapeRule> shapeRules(phones.getRange(), ShapeRule({Shape::X}, boost::none));
|
ContinuousTimeline<ShapeRule> shapeRules(phones.getRange(), {{Shape::X}, boost::none, {0_cs, 0_cs}});
|
||||||
centiseconds previousDuration = 0_cs;
|
centiseconds previousDuration = 0_cs;
|
||||||
for (const auto& timedPhone : continuousPhones) {
|
for (const auto& timedPhone : continuousPhones) {
|
||||||
optional<Phone> phone = timedPhone.getValue();
|
optional<Phone> phone = timedPhone.getValue();
|
||||||
|
@ -34,7 +59,7 @@ ContinuousTimeline<ShapeRule> getShapeRules(const BoundedTimeline<Phone>& phones
|
||||||
// Copy to timeline.
|
// Copy to timeline.
|
||||||
// Later shape sets may overwrite earlier ones if overlapping.
|
// Later shape sets may overwrite earlier ones if overlapping.
|
||||||
for (const auto& timedShapeSet : phoneShapeSets) {
|
for (const auto& timedShapeSet : phoneShapeSets) {
|
||||||
shapeRules.set(timedShapeSet.getTimeRange(), ShapeRule(timedShapeSet.getValue(), phone));
|
shapeRules.set(timedShapeSet.getTimeRange(), ShapeRule(timedShapeSet.getValue(), phone, timedPhone.getTimeRange()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Phone.h"
|
||||||
|
#include "animationRules.h"
|
||||||
|
#include "BoundedTimeline.h"
|
||||||
|
#include "ContinuousTimeline.h"
|
||||||
|
|
||||||
|
struct ShapeRule {
|
||||||
|
ShapeSet shapeSet;
|
||||||
|
boost::optional<Phone> phone;
|
||||||
|
TimeRange phoneTiming;
|
||||||
|
|
||||||
|
ShapeRule(const ShapeSet& shapeSet, const boost::optional<Phone>& phone, TimeRange phoneTiming);
|
||||||
|
|
||||||
|
static ShapeRule getInvalid();
|
||||||
|
|
||||||
|
bool operator==(const ShapeRule&) const;
|
||||||
|
bool operator!=(const ShapeRule&) const;
|
||||||
|
bool operator<(const ShapeRule&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns shape rules for an entire timeline of phones.
|
||||||
|
ContinuousTimeline<ShapeRule> getShapeRules(const BoundedTimeline<Phone>& phones);
|
|
@ -1,6 +1,6 @@
|
||||||
#include "mouthAnimation.h"
|
#include "mouthAnimation.h"
|
||||||
#include "timedLogging.h"
|
#include "timedLogging.h"
|
||||||
#include "shapeRule.h"
|
#include "ShapeRule.h"
|
||||||
#include "roughAnimation.h"
|
#include "roughAnimation.h"
|
||||||
#include "pauseAnimation.h"
|
#include "pauseAnimation.h"
|
||||||
#include "tweening.h"
|
#include "tweening.h"
|
||||||
|
|
|
@ -19,11 +19,9 @@ JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule
|
||||||
centiseconds lastAnticipatedShapeStart = -1_cs;
|
centiseconds lastAnticipatedShapeStart = -1_cs;
|
||||||
for (auto it = shapeRules.begin(); it != shapeRules.end(); ++it) {
|
for (auto it = shapeRules.begin(); it != shapeRules.end(); ++it) {
|
||||||
const ShapeRule shapeRule = it->getValue();
|
const ShapeRule shapeRule = it->getValue();
|
||||||
const ShapeSet shapeSet = std::get<ShapeSet>(shapeRule);
|
const Shape shape = getClosestShape(referenceShape, shapeRule.shapeSet);
|
||||||
const Shape shape = getClosestShape(referenceShape, shapeSet);
|
|
||||||
animation.set(it->getTimeRange(), shape);
|
animation.set(it->getTimeRange(), shape);
|
||||||
const auto phone = std::get<optional<Phone>>(shapeRule);
|
const bool anticipateShape = shapeRule.phone && isVowel(*shapeRule.phone) && shapeRule.shapeSet.size() == 1;
|
||||||
const bool anticipateShape = phone && isVowel(*phone) && shapeSet.size() == 1;
|
|
||||||
if (anticipateShape) {
|
if (anticipateShape) {
|
||||||
// Animate backwards a little
|
// Animate backwards a little
|
||||||
const Shape anticipatedShape = shape;
|
const Shape anticipatedShape = shape;
|
||||||
|
@ -40,7 +38,7 @@ JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule
|
||||||
if (anticipationDuration > maxAnticipationDuration) break;
|
if (anticipationDuration > maxAnticipationDuration) break;
|
||||||
|
|
||||||
// Overwrite forward-animated shape with backwards-animated, anticipating shape
|
// Overwrite forward-animated shape with backwards-animated, anticipating shape
|
||||||
const Shape anticipatingShape = getClosestShape(referenceShape, std::get<ShapeSet>(reverseIt->getValue()));
|
const Shape anticipatingShape = getClosestShape(referenceShape, reverseIt->getValue().shapeSet);
|
||||||
animation.set(reverseIt->getTimeRange(), anticipatingShape);
|
animation.set(reverseIt->getTimeRange(), anticipatingShape);
|
||||||
|
|
||||||
// Make sure the new, backwards-animated shape still resembles the anticipated shape
|
// Make sure the new, backwards-animated shape still resembles the anticipated shape
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "shapeRule.h"
|
#include "ShapeRule.h"
|
||||||
|
|
||||||
// Does a rough animation (no tweening, special pause animation, etc.) using a bidirectional algorithm.
|
// Does a rough animation (no tweening, special pause animation, etc.) using a bidirectional algorithm.
|
||||||
JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule>& shapeRules);
|
JoiningContinuousTimeline<Shape> animateRough(const ContinuousTimeline<ShapeRule>& shapeRules);
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Phone.h"
|
|
||||||
#include "animationRules.h"
|
|
||||||
#include "BoundedTimeline.h"
|
|
||||||
#include "ContinuousTimeline.h"
|
|
||||||
|
|
||||||
// A shape set with its original phone
|
|
||||||
using ShapeRule = std::tuple<ShapeSet, boost::optional<Phone>>;
|
|
||||||
|
|
||||||
// Returns shape rules for an entire timeline of phones.
|
|
||||||
ContinuousTimeline<ShapeRule> getShapeRules(const BoundedTimeline<Phone>& phones);
|
|
|
@ -23,7 +23,7 @@ ContinuousTimeline<ShapeRule> convertToTargetShapeSet(const ContinuousTimeline<S
|
||||||
ContinuousTimeline<ShapeRule> result(shapeRules);
|
ContinuousTimeline<ShapeRule> result(shapeRules);
|
||||||
for (const auto& timedShapeRule : shapeRules) {
|
for (const auto& timedShapeRule : shapeRules) {
|
||||||
ShapeRule rule = timedShapeRule.getValue();
|
ShapeRule rule = timedShapeRule.getValue();
|
||||||
std::get<ShapeSet>(rule) = convertToTargetShapeSet(std::get<ShapeSet>(rule), targetShapeSet);
|
rule.shapeSet = convertToTargetShapeSet(rule.shapeSet, targetShapeSet);
|
||||||
result.set(timedShapeRule.getTimeRange(), rule);
|
result.set(timedShapeRule.getTimeRange(), rule);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
#include "shapeRule.h"
|
#include "ShapeRule.h"
|
||||||
|
|
||||||
// Returns the closest shape to the specified one that occurs in the target shape set.
|
// Returns the closest shape to the specified one that occurs in the target shape set.
|
||||||
Shape convertToTargetShapeSet(Shape shape, const ShapeSet& targetShapeSet);
|
Shape convertToTargetShapeSet(Shape shape, const ShapeSet& targetShapeSet);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "shapeRule.h"
|
#include "ShapeRule.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::map;
|
using std::map;
|
||||||
|
|
Loading…
Reference in New Issue