Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 89 additions & 14 deletions src/core/TransformEffects/parenteffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,24 @@
#include "Boxes/boundingbox.h"
#include "Animators/transformanimator.h"
#include "Animators/qrealanimator.h"
#include "matrixdecomposition.h"

ParentEffect::ParentEffect() :
FollowObjectEffectBase("parent", TransformEffectType::parent) {}

void ParentEffect::applyEffect(
const qreal relFrame,
qreal& pivotX, qreal& pivotY,
qreal& posX, qreal& posY,
qreal& rot,
qreal& scaleX, qreal& scaleY,
qreal& shearX, qreal& shearY,
QMatrix& postTransform,
BoundingBox* const parent) {
void ParentEffect::applyEffect(const qreal relFrame,
qreal& pivotX,
qreal& pivotY,
qreal& posX,
qreal& posY,
qreal& rot,
qreal& scaleX,
qreal& scaleY,
qreal& shearX,
qreal& shearY,
QMatrix& postTransform,
BoundingBox* const parent)
{
Q_UNUSED(pivotX)
Q_UNUSED(pivotY)
Q_UNUSED(posX)
Expand All @@ -51,14 +56,84 @@ void ParentEffect::applyEffect(
Q_UNUSED(shearX)
Q_UNUSED(shearY)

if(!isVisible()) return;
if (!isVisible() || !parent) { return; }

if(!parent) return;
const auto target = targetProperty()->getTarget();
if(!target) return;
if (!target) { return; }

const qreal absFrame = prp_relFrameToAbsFrameF(relFrame);
const qreal targetRelFrame = target->prp_absFrameToRelFrameF(absFrame);

const auto targetTransAnim = target->getTransformAnimator();
postTransform = targetTransAnim->getRelativeTransformAtFrame(targetRelFrame);

const QMatrix targetTransform =
targetTransAnim->getRelativeTransformAtFrame(targetRelFrame);
const QPointF targetPivot = target->getPivotRelPos(targetRelFrame);
const auto targetValues =
MatrixDecomposition::decomposePivoted(targetTransform, targetPivot);

// Get influence values with reasonable bounds to prevent extreme values
const qreal posXInfl = qBound(-10.0, mPosInfluence->getEffectiveXValue(relFrame), 10.0);
const qreal posYInfl = qBound(-10.0, mPosInfluence->getEffectiveYValue(relFrame), 10.0);
const qreal scaleXInfl = qBound(-10.0, mScaleInfluence->getEffectiveXValue(relFrame), 10.0);
const qreal scaleYInfl = qBound(-10.0, mScaleInfluence->getEffectiveYValue(relFrame), 10.0);
const qreal rotInfl = qBound(-10.0, mRotInfluence->getEffectiveValue(relFrame), 10.0);

// Validate influence values for safety
if (!validateInfluenceValues(posXInfl, posYInfl, scaleXInfl, scaleYInfl, rotInfl)) {
return; // Skip effect if invalid values detected
}

// Check for near-zero rotation influence
const bool zeroRotInfluence = std::abs(rotInfl) < 1e-6;

// Apply influence to transform values using helper method
TransformValues influencedValues = targetValues;
applyInfluenceToTransform(influencedValues, targetValues, posXInfl, posYInfl, scaleXInfl, scaleYInfl);

// Handle rotation influence with linear interpolation
qreal translationRotInfl = 1.0;

influencedValues.fRotation = targetValues.fRotation * translationRotInfl;

const qreal desiredRotation = zeroRotInfluence
? -targetValues.fRotation
: targetValues.fRotation * rotInfl;
const qreal rotDeltaZero = -targetValues.fRotation;
const qreal rotDeltaFull = desiredRotation - influencedValues.fRotation;

if (rotInfl >= 0.0 && rotInfl <= 1.0) {
const qreal t = rotInfl;
const qreal blendedDelta = rotDeltaZero + t * (rotDeltaFull - rotDeltaZero);
rot += blendedDelta;
} else if (zeroRotInfluence) {
rot += rotDeltaZero;
} else {
rot += rotDeltaFull;
}

// Calculate final transform matrix
postTransform = influencedValues.calculate();
}

bool ParentEffect::validateInfluenceValues(const qreal posXInfl, const qreal posYInfl,
const qreal scaleXInfl, const qreal scaleYInfl,
const qreal rotInfl) const
{
// Check for NaN or infinite values
return std::isfinite(posXInfl) && std::isfinite(posYInfl) &&
std::isfinite(scaleXInfl) && std::isfinite(scaleYInfl) &&
std::isfinite(rotInfl);
}

void ParentEffect::applyInfluenceToTransform(TransformValues& values,
const TransformValues& targetValues,
const qreal posXInfl, const qreal posYInfl,
const qreal scaleXInfl, const qreal scaleYInfl) const
{
values.fMoveX = targetValues.fMoveX * posXInfl;
values.fMoveY = targetValues.fMoveY * posYInfl;

// Scale influence: interpolate between no scaling (1.0) and target scaling
values.fScaleX = 1.0 + (targetValues.fScaleX - 1.0) * scaleXInfl;
values.fScaleY = 1.0 + (targetValues.fScaleY - 1.0) * scaleYInfl;
}
11 changes: 11 additions & 0 deletions src/core/TransformEffects/parenteffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#define PARENTEFFECT_H

#include "followobjecteffectbase.h"
#include "transformvalues.h"

class ParentEffect : public FollowObjectEffectBase {
public:
Expand All @@ -40,6 +41,16 @@ class ParentEffect : public FollowObjectEffectBase {
qreal &shearX, qreal &shearY,
QMatrix& postTransform,
BoundingBox* const parent) override;

private:
bool validateInfluenceValues(const qreal posXInfl, const qreal posYInfl,
const qreal scaleXInfl, const qreal scaleYInfl,
const qreal rotInfl) const;

void applyInfluenceToTransform(TransformValues& values,
const TransformValues& targetValues,
const qreal posXInfl, const qreal posYInfl,
const qreal scaleXInfl, const qreal scaleYInfl) const;
};

#endif // PARENTEFFECT_H
17 changes: 13 additions & 4 deletions src/core/TransformEffects/trackeffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ qreal calculateTrackAngle(const QPointF& parentPos,
return trackAngle;
}

void TrackEffect::setRotScaleAfterTargetChange(
BoundingBox* const oldTarget, BoundingBox* const newTarget) {
const auto parent = getFirstAncestor<BoundingBox>();
void TrackEffect::setRotScaleAfterTargetChange(BoundingBox* const oldTarget,
BoundingBox* const newTarget)
{
Q_UNUSED(oldTarget)
Q_UNUSED(newTarget)

// https://github.com/friction2d/friction/issues/591

// I see no reason to apply the rotation here (or anywhere else)
// it only breaks the original state of the bounding box.

/*const auto parent = getFirstAncestor<BoundingBox>();
if(!parent) return;

const qreal infl = mInfluence->getEffectiveValue();
Expand All @@ -70,7 +79,7 @@ void TrackEffect::setRotScaleAfterTargetChange(
}

parent->startRotTransform();
parent->rotateBy(rot);
parent->rotateBy(rot);*/
}

void TrackEffect::applyEffect(
Expand Down