| #include "rive/constraints/transform_constraint.hpp" |
| #include "rive/transform_component.hpp" |
| #include "rive/math/mat2d.hpp" |
| #include "rive/math/math_types.hpp" |
| #include "rive/math/aabb.hpp" |
| |
| using namespace rive; |
| |
| const Mat2D TransformConstraint::targetTransform() const |
| { |
| AABB bounds = m_Target->localBounds(); |
| Mat2D local = |
| Mat2D::fromTranslate(bounds.left() + bounds.width() * originX(), |
| bounds.top() + bounds.height() * originY()); |
| return m_Target->worldTransform() * local; |
| } |
| |
| void TransformConstraint::originXChanged() { markConstraintDirty(); } |
| |
| void TransformConstraint::originYChanged() { markConstraintDirty(); } |
| |
| void TransformConstraint::constrain(TransformComponent* component) |
| { |
| if (m_Target == nullptr || m_Target->isCollapsed()) |
| { |
| return; |
| } |
| |
| const Mat2D& transformA = component->worldTransform(); |
| Mat2D transformB(targetTransform()); |
| if (sourceSpace() == TransformSpace::local) |
| { |
| const Mat2D& targetParentWorld = getParentWorld(*m_Target); |
| |
| Mat2D inverse; |
| if (!targetParentWorld.invert(&inverse)) |
| { |
| return; |
| } |
| transformB = inverse * transformB; |
| } |
| if (destSpace() == TransformSpace::local) |
| { |
| const Mat2D& targetParentWorld = getParentWorld(*component); |
| transformB = targetParentWorld * transformB; |
| } |
| |
| TransformConstraint::constrainWorld(component, |
| transformA, |
| m_ComponentsA, |
| transformB, |
| m_ComponentsB, |
| strength()); |
| } |
| |
| void TransformConstraint::constrainWorld(TransformComponent* component, |
| Mat2D from, |
| TransformComponents componentsFrom, |
| Mat2D to, |
| TransformComponents componentsTo, |
| float strength) |
| { |
| componentsFrom = from.decompose(); |
| componentsTo = to.decompose(); |
| |
| float angleA = std::fmod(componentsFrom.rotation(), math::PI * 2); |
| float angleB = std::fmod(componentsTo.rotation(), math::PI * 2); |
| float diff = angleB - angleA; |
| if (diff > math::PI) |
| { |
| diff -= math::PI * 2; |
| } |
| else if (diff < -math::PI) |
| { |
| diff += math::PI * 2; |
| } |
| |
| float t = strength; |
| float ti = 1.0f - t; |
| |
| componentsTo.rotation(angleA + diff * t); |
| componentsTo.x(componentsFrom.x() * ti + componentsTo.x() * t); |
| componentsTo.y(componentsFrom.y() * ti + componentsTo.y() * t); |
| componentsTo.scaleX(componentsFrom.scaleX() * ti + |
| componentsTo.scaleX() * t); |
| componentsTo.scaleY(componentsFrom.scaleY() * ti + |
| componentsTo.scaleY() * t); |
| componentsTo.skew(componentsFrom.skew() * ti + componentsTo.skew() * t); |
| |
| component->mutableWorldTransform() = Mat2D::compose(componentsTo); |
| } |