void KeyframeEffectModelBase::ensureKeyframeGroups() const { if (m_keyframeGroups) return; m_keyframeGroups = adoptPtrWillBeNoop(new KeyframeGroupMap); const KeyframeVector keyframes = normalizedKeyframes(getFrames()); for (KeyframeVector::const_iterator keyframeIter = keyframes.begin(); keyframeIter != keyframes.end(); ++keyframeIter) { const Keyframe* keyframe = keyframeIter->get(); PropertySet keyframeProperties = keyframe->properties(); for (PropertySet::const_iterator propertyIter = keyframeProperties.begin(); propertyIter != keyframeProperties.end(); ++propertyIter) { CSSPropertyID property = *propertyIter; ASSERT_WITH_MESSAGE(!isExpandedShorthand(property), "Web Animations: Encountered shorthand CSS property (%d) in normalized keyframes.", property); KeyframeGroupMap::iterator groupIter = m_keyframeGroups->find(property); PropertySpecificKeyframeGroup* group; if (groupIter == m_keyframeGroups->end()) group = m_keyframeGroups->add(property, adoptPtrWillBeNoop(new PropertySpecificKeyframeGroup)).storedValue->value.get(); else group = groupIter->value.get(); group->appendKeyframe(keyframe->createPropertySpecificKeyframe(property)); } } // Add synthetic keyframes. for (KeyframeGroupMap::iterator iter = m_keyframeGroups->begin(); iter != m_keyframeGroups->end(); ++iter) { iter->value->addSyntheticKeyframeIfRequired(this); iter->value->removeRedundantKeyframes(); } }
void InspectorAnimationAgent::setTiming(ErrorString* errorString, const String& animationId, double duration, double delay) { Animation* animation = assertAnimation(errorString, animationId); if (!animation) return; AnimationType type = m_idToAnimationType.get(animationId); if (type == AnimationType::CSSTransition) { KeyframeEffect* effect = toKeyframeEffect(animation->effect()); KeyframeEffectModelBase* model = toKeyframeEffectModelBase(effect->model()); const AnimatableValueKeyframeEffectModel* oldModel = toAnimatableValueKeyframeEffectModel(model); // Refer to CSSAnimations::calculateTransitionUpdateForProperty() for the structure of transitions. const KeyframeVector& frames = oldModel->getFrames(); ASSERT(frames.size() == 3); KeyframeVector newFrames; for (int i = 0; i < 3; i++) newFrames.append(toAnimatableValueKeyframe(frames[i]->clone().get())); // Update delay, represented by the distance between the first two keyframes. newFrames[1]->setOffset(delay / (delay + duration)); model->setFrames(newFrames); AnimationEffectTiming* timing = animation->effect()->timing(); UnrestrictedDoubleOrString unrestrictedDuration; unrestrictedDuration.setUnrestrictedDouble(duration + delay); timing->setDuration(unrestrictedDuration); } else if (type == AnimationType::WebAnimation) { AnimationEffectTiming* timing = animation->effect()->timing(); UnrestrictedDoubleOrString unrestrictedDuration; unrestrictedDuration.setUnrestrictedDouble(duration); timing->setDuration(unrestrictedDuration); timing->setDelay(delay); } }
TEST_F(KeyframeEffectModelTest, EvenlyDistributed3) { KeyframeVector keyframes(12); keyframes[0] = AnimatableValueKeyframe::create(); keyframes[0]->setOffset(0); keyframes[1] = AnimatableValueKeyframe::create(); keyframes[2] = AnimatableValueKeyframe::create(); keyframes[3] = AnimatableValueKeyframe::create(); keyframes[4] = AnimatableValueKeyframe::create(); keyframes[4]->setOffset(0.5); keyframes[5] = AnimatableValueKeyframe::create(); keyframes[6] = AnimatableValueKeyframe::create(); keyframes[7] = AnimatableValueKeyframe::create(); keyframes[7]->setOffset(0.8); keyframes[8] = AnimatableValueKeyframe::create(); keyframes[9] = AnimatableValueKeyframe::create(); keyframes[10] = AnimatableValueKeyframe::create(); keyframes[11] = AnimatableValueKeyframe::create(); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(12U, result.size()); EXPECT_DOUBLE_EQ(0.0, result[0]->offset()); EXPECT_DOUBLE_EQ(0.125, result[1]->offset()); EXPECT_DOUBLE_EQ(0.25, result[2]->offset()); EXPECT_DOUBLE_EQ(0.375, result[3]->offset()); EXPECT_DOUBLE_EQ(0.5, result[4]->offset()); EXPECT_DOUBLE_EQ(0.6, result[5]->offset()); EXPECT_DOUBLE_EQ(0.7, result[6]->offset()); EXPECT_DOUBLE_EQ(0.8, result[7]->offset()); EXPECT_DOUBLE_EQ(0.85, result[8]->offset()); EXPECT_DOUBLE_EQ(0.9, result[9]->offset()); EXPECT_DOUBLE_EQ(0.95, result[10]->offset()); EXPECT_DOUBLE_EQ(1.0, result[11]->offset()); }
bool loadKeyframes( KeyframeVector& keyframes, const std::string& path) { keyframes.clear(); int kf_idx = 0; while(true) { std::stringstream ss_idx; ss_idx << std::setw(4) << std::setfill('0') << kf_idx; std::string path_kf = path + "/" + ss_idx.str(); if (boost::filesystem::exists(path_kf)) { ROS_INFO("Loading %s", path_kf.c_str()); RGBDKeyframe keyframe; bool result_load = RGBDKeyframe::load(keyframe, path_kf); if (result_load) keyframes.push_back(keyframe); else { ROS_WARN("Error loading"); return false; } } else return true; kf_idx++; } }
void CompositorAnimationsImpl::addKeyframesToCurve(blink::WebAnimationCurve& curve, const KeyframeVector& keyframes, const TimingFunction& timingFunction) { for (size_t i = 0; i < keyframes.size(); i++) { const TimingFunction* keyframeTimingFunction = 0; if (i + 1 < keyframes.size()) { // Last keyframe has no timing function switch (timingFunction.type()) { case TimingFunction::LinearFunction: case TimingFunction::CubicBezierFunction: keyframeTimingFunction = &timingFunction; break; case TimingFunction::ChainedFunction: { const ChainedTimingFunction& chained = toChainedTimingFunction(timingFunction); // ChainedTimingFunction criteria was checked in isCandidate, // assert it is valid. ASSERT(keyframes.size() == chained.m_segments.size() + 1); keyframeTimingFunction = chained.m_segments[i].m_timingFunction.get(); break; } case TimingFunction::StepsFunction: default: ASSERT_NOT_REACHED(); } } ASSERT(!keyframes[i]->value()->dependsOnUnderlyingValue()); RefPtr<AnimatableValue> value = keyframes[i]->value()->compositeOnto(0); switch (curve.type()) { case blink::WebAnimationCurve::AnimationCurveTypeFilter: { OwnPtr<blink::WebFilterOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createFilterOperations()); bool converted = toWebFilterOperations(toAnimatableFilterOperations(value.get())->operations(), ops.get()); ASSERT_UNUSED(converted, converted); blink::WebFilterKeyframe filterKeyframe(keyframes[i]->offset(), ops.release()); blink::WebFilterAnimationCurve* filterCurve = static_cast<blink::WebFilterAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*filterCurve, filterKeyframe, keyframeTimingFunction); break; } case blink::WebAnimationCurve::AnimationCurveTypeFloat: { blink::WebFloatKeyframe floatKeyframe(keyframes[i]->offset(), toAnimatableDouble(value.get())->toDouble()); blink::WebFloatAnimationCurve* floatCurve = static_cast<blink::WebFloatAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*floatCurve, floatKeyframe, keyframeTimingFunction); break; } case blink::WebAnimationCurve::AnimationCurveTypeTransform: { OwnPtr<blink::WebTransformOperations> ops = adoptPtr(blink::Platform::current()->compositorSupport()->createTransformOperations()); toWebTransformOperations(toAnimatableTransform(value.get())->transformOperations(), FloatSize(), ops.get()); blink::WebTransformKeyframe transformKeyframe(keyframes[i]->offset(), ops.release()); blink::WebTransformAnimationCurve* transformCurve = static_cast<blink::WebTransformAnimationCurve*>(&curve); addKeyframeWithTimingFunction(*transformCurve, transformKeyframe, keyframeTimingFunction); break; } default: ASSERT_NOT_REACHED(); } } }
TEST_F(KeyframeEffectModelTest, LastOne) { KeyframeEffectModel::KeyframeVector keyframes(3); keyframes[0] = Keyframe::create(); keyframes[0]->setOffset(-1); keyframes[1] = Keyframe::create(); keyframes[2] = Keyframe::create(); keyframes[2]->setOffset(2); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(1U, result.size()); EXPECT_DOUBLE_EQ(1.0, result[0]->offset()); }
TEST_F(KeyframeEffectModelTest, NotLooselySorted) { KeyframeEffectModel::KeyframeVector keyframes(4); keyframes[0] = Keyframe::create(); keyframes[1] = Keyframe::create(); keyframes[1]->setOffset(9); keyframes[2] = Keyframe::create(); keyframes[3] = Keyframe::create(); keyframes[3]->setOffset(1); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(0U, result.size()); }
TEST_F(KeyframeEffectModelTest, FirstZero) { KeyframeEffectModel::KeyframeVector keyframes(3); keyframes[0] = Keyframe::create(); keyframes[0]->setOffset(-1); keyframes[1] = Keyframe::create(); keyframes[2] = Keyframe::create(); keyframes[2]->setOffset(0.25); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(2U, result.size()); EXPECT_DOUBLE_EQ(0.0, result[0]->offset()); EXPECT_DOUBLE_EQ(0.25, result[1]->offset()); }
TEST_F(KeyframeEffectModelTest, EvenlyDistributed1) { KeyframeVector keyframes(5); keyframes[0] = AnimatableValueKeyframe::create(); keyframes[0]->setOffset(0.125); keyframes[1] = AnimatableValueKeyframe::create(); keyframes[2] = AnimatableValueKeyframe::create(); keyframes[3] = AnimatableValueKeyframe::create(); keyframes[4] = AnimatableValueKeyframe::create(); keyframes[4]->setOffset(0.625); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(5U, result.size()); EXPECT_DOUBLE_EQ(0.125, result[0]->offset()); EXPECT_DOUBLE_EQ(0.25, result[1]->offset()); EXPECT_DOUBLE_EQ(0.375, result[2]->offset()); EXPECT_DOUBLE_EQ(0.5, result[3]->offset()); EXPECT_DOUBLE_EQ(0.625, result[4]->offset()); }
KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes) { double lastOffset = 0; KeyframeVector result; result.reserveCapacity(keyframes.size()); for (size_t i = 0; i < keyframes.size(); ++i) { double offset = keyframes[i]->offset(); if (!isNull(offset)) { ASSERT(offset >= 0); ASSERT(offset <= 1); ASSERT(offset >= lastOffset); lastOffset = offset; } result.append(keyframes[i]->clone()); } if (result.isEmpty()) { return result; } if (isNull(result.last()->offset())) result.last()->setOffset(1); if (result.size() > 1 && isNull(result[0]->offset())) result[0]->setOffset(0); size_t lastIndex = 0; lastOffset = result[0]->offset(); for (size_t i = 1; i < result.size(); ++i) { double offset = result[i]->offset(); if (!isNull(offset)) { for (size_t j = 1; j < i - lastIndex; ++j) result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex)); lastIndex = i; lastOffset = offset; } } return result; }
void trainSURFMatcher( const KeyframeVector& keyframes, cv::FlannBasedMatcher& matcher) { std::vector<cv::Mat> descriptors_vector; for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx) { const RGBDKeyframe& keyframe = keyframes[kf_idx]; descriptors_vector.push_back(keyframe.descriptors); } matcher.add(descriptors_vector); matcher.train(); }
TEST_F(KeyframeEffectModelTest, EvenlyDistributed2) { KeyframeEffectModel::KeyframeVector keyframes(8); keyframes[0] = Keyframe::create(); keyframes[0]->setOffset(-0.1); keyframes[1] = Keyframe::create(); keyframes[2] = Keyframe::create(); keyframes[3] = Keyframe::create(); keyframes[4] = Keyframe::create(); keyframes[4]->setOffset(0.75); keyframes[5] = Keyframe::create(); keyframes[6] = Keyframe::create(); keyframes[7] = Keyframe::create(); keyframes[7]->setOffset(1.1); const KeyframeVector result = normalizedKeyframes(keyframes); EXPECT_EQ(6U, result.size()); EXPECT_DOUBLE_EQ(0.0, result[0]->offset()); EXPECT_DOUBLE_EQ(0.25, result[1]->offset()); EXPECT_DOUBLE_EQ(0.5, result[2]->offset()); EXPECT_DOUBLE_EQ(0.75, result[3]->offset()); EXPECT_DOUBLE_EQ(0.875, result[4]->offset()); EXPECT_DOUBLE_EQ(1.0, result[5]->offset()); }
bool saveKeyframes( const KeyframeVector& keyframes, const std::string& path) { for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx) { std::stringstream ss_idx; ss_idx << std::setw(4) << std::setfill('0') << kf_idx; std::string kf_path = path + "/" + ss_idx.str(); bool save_result = RGBDKeyframe::save(keyframes[kf_idx], kf_path); if (!save_result) return false; } return true; }
KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes) { // keyframes [beginIndex, endIndex) will remain after removing all keyframes if they are not // loosely sorted by offset, and after removing keyframes with positional offset outide [0, 1]. size_t beginIndex = 0; size_t endIndex = keyframes.size(); // Becomes the most recent keyframe with an explicit offset. size_t lastIndex = endIndex; double lastOffset = std::numeric_limits<double>::quiet_NaN(); for (size_t i = 0; i < keyframes.size(); ++i) { double offset = keyframes[i]->offset(); if (!isNull(offset)) { if (lastIndex < i && offset < lastOffset) { // The keyframes are not loosely sorted by offset. Exclude all. endIndex = beginIndex; break; } if (offset < 0) { // Remove all keyframes up to and including this keyframe. beginIndex = i + 1; } else if (offset > 1) { // Remove all keyframes from this keyframe onwards. Note we must complete our checking // that the keyframes are loosely sorted by offset, so we can't exit the loop early. endIndex = std::min(i, endIndex); } lastIndex = i; lastOffset = offset; } } KeyframeVector result; if (beginIndex != endIndex) { result.reserveCapacity(endIndex - beginIndex); for (size_t i = beginIndex; i < endIndex; ++i) { result.append(keyframes[i]->clone()); } if (isNull(result[result.size() - 1]->offset())) result[result.size() - 1]->setOffset(1); if (result.size() > 1 && isNull(result[0]->offset())) result[0]->setOffset(0); lastIndex = 0; lastOffset = result[0]->offset(); for (size_t i = 1; i < result.size(); ++i) { double offset = result[i]->offset(); if (!isNull(offset)) { if (lastIndex + 1 < i) { for (size_t j = 1; j < i - lastIndex; ++j) result[lastIndex + j]->setOffset(lastOffset + (offset - lastOffset) * j / (i - lastIndex)); } lastIndex = i; lastOffset = offset; } } } return result; }
KeyframeEffectModelBase::KeyframeVector KeyframeEffectModelBase::normalizedKeyframes(const KeyframeVector& keyframes) { double lastOffset = 0; KeyframeVector result; result.reserveCapacity(keyframes.size()); for (const auto& keyframe : keyframes) { double offset = keyframe->offset(); if (!isNull(offset)) { DCHECK_GE(offset, 0); DCHECK_LE(offset, 1); DCHECK_GE(offset, lastOffset); lastOffset = offset; } result.push_back(keyframe->clone()); } if (result.isEmpty()) return result; if (isNull(result.back()->offset())) result.back()->setOffset(1); if (result.size() > 1 && isNull(result[0]->offset())) result.front()->setOffset(0); size_t lastIndex = 0; lastOffset = result.front()->offset(); for (size_t i = 1; i < result.size(); ++i) { double offset = result[i]->offset(); if (!isNull(offset)) { for (size_t j = 1; j < i - lastIndex; ++j) result[lastIndex + j]->setOffset( lastOffset + (offset - lastOffset) * j / (i - lastIndex)); lastIndex = i; lastOffset = offset; } } return result; }