Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG follow path wrapper #346

Closed
33 changes: 25 additions & 8 deletions src/core/Animators/graphanimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "graphkey.h"
#include "qrealpoint.h"
#include "svgexporthelpers.h"
#include "appsupport.h"

GraphAnimator::GraphAnimator(const QString& name) : Animator(name) {
connect(this, &Animator::anim_addedKey, [this](Key * key) {
Expand Down Expand Up @@ -530,28 +531,41 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp,
const bool transform,
const QString& type,
const QString &beginEvent,
const QString &endEvent) const
const QString &endEvent,
const bool motion,
const bool motionRotate,
const QString &motionPath) const
{
Q_ASSERT(!transform || attrName == "transform");
const auto relRange = prp_absRangeToRelRange(exp.fAbsRange);
const auto idRange = prp_getIdenticalRelRange(visRange.fMin);
const int span = exp.fAbsRange.span();
if(idRange.inRange(visRange) || span == 1) {
if (idRange.inRange(visRange) || span == 1) {
if (motion) { return; }
auto value = valueGetter(visRange.fMin);
if(transform) {
value = parent.attribute(attrName) + " " +
type + "(" + value + ")";
if (transform) {
value = parent.attribute(attrName) + " " + type + "(" + value + ")";
}
parent.setAttribute(attrName, value.trimmed());
} else {
const auto tagName = transform ? "animateTransform" : "animate";
const auto tagName = motion ? "animateMotion" : transform ? "animateTransform" : "animate";
auto anim = exp.createElement(tagName);

if (!beginEvent.isEmpty()) { anim.setAttribute("begin", beginEvent); }
if (!endEvent.isEmpty()) { anim.setAttribute("end", endEvent); }

anim.setAttribute("attributeName", attrName);
if(!type.isEmpty()) anim.setAttribute("type", type);
if (!motion) {
anim.setAttribute("attributeName", attrName);
if (!type.isEmpty()) { anim.setAttribute("type", type); }
} else {
if (motionRotate) { anim.setAttribute("rotate", "auto"); }
if (!motionPath.isEmpty()) {
auto mpath = exp.createElement("mpath");
mpath.setAttribute("href", QString("#%1").arg(AppSupport::filterId(motionPath)));
anim.appendChild(mpath);
}
}

const qreal div = span - 1;
const qreal dur = div/exp.fFps;
anim.setAttribute("dur", QString::number(dur) + 's');
Expand Down Expand Up @@ -622,6 +636,9 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp,

anim.setAttribute("calcMode", "spline");
anim.setAttribute("values", values.join(';'));
if (motion) {
anim.setAttribute("keyPoints", values.join(';'));
}
anim.setAttribute("keyTimes", keyTimes.join(';'));
anim.setAttribute("keySplines", keySplines.join(';'));

Expand Down
5 changes: 4 additions & 1 deletion src/core/Animators/graphanimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ class CORE_EXPORT GraphAnimator : public Animator {
const bool transform = false,
const QString& type = "",
const QString& beginEvent = "",
const QString& endEvent = "") const;
const QString& endEvent = "",
const bool motion = false,
const bool motionRotate = false,
const QString & motionPath = QString()) const;
protected:
qreal graph_prevKeyWeight(const GraphKey * const prevKey,
const GraphKey * const nextKey,
Expand Down
41 changes: 34 additions & 7 deletions src/core/Animators/qpointfanimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,25 @@ void QPointFAnimator::saveQPointFSVGX(SvgExporter& exp,
const bool transform,
const QString& type,
const QString &beginEvent,
const QString &endEvent) const
const QString &endEvent,
const bool motion,
const bool motionRotate,
const QString &motionPath) const
{
const QString templ = "%1 " + QString::number(y);
mXAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier,
transform, type, templ, beginEvent, endEvent);
mXAnimator->saveQrealSVG(exp,
parent,
visRange,
name,
multiplier,
transform,
type,
templ,
beginEvent,
endEvent,
motion,
motionRotate,
motionPath);
}

void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp,
Expand All @@ -276,12 +290,25 @@ void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp,
const bool transform,
const QString& type,
const QString &beginEvent,
const QString &endEvent) const
const QString &endEvent,
const bool motion,
const bool motionRotate,
const QString &motionPath) const
{
const QString templ = QString::number(x) + " %1";
mYAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier,
transform, type, templ,
beginEvent, endEvent);
mYAnimator->saveQrealSVG(exp,
parent,
visRange,
name,
multiplier,
transform,
type,
templ,
beginEvent,
endEvent,
motion,
motionRotate,
motionPath);
}

QDomElement QPointFAnimator::prp_writePropertyXEV_impl(const XevExporter& exp) const {
Expand Down
10 changes: 8 additions & 2 deletions src/core/Animators/qpointfanimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator {
const bool transform = false,
const QString& type = "",
const QString& beginEvent = "",
const QString& endEvent = "") const;
const QString& endEvent = "",
const bool motion = false,
const bool motionRotate = false,
const QString & motionPath = QString()) const;
void saveQPointFSVGY(SvgExporter& exp,
QDomElement& parent,
const FrameRange& visRange,
Expand All @@ -121,7 +124,10 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator {
const bool transform = false,
const QString& type = "",
const QString& beginEvent = "",
const QString& endEvent = "") const;
const QString& endEvent = "",
const bool motion = false,
const bool motionRotate = false,
const QString & motionPath = QString()) const;
QDomElement prp_writePropertyXEV_impl(const XevExporter& exp) const;
protected:
qsptr<QrealAnimator> mXAnimator;
Expand Down
58 changes: 45 additions & 13 deletions src/core/Animators/qrealanimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,37 +796,69 @@ void QrealAnimator::saveQrealSVG(SvgExporter& exp,
const QString& type,
const QString& templ,
const QString &beginEvent,
const QString &endEvent)
const QString &endEvent,
const bool motion,
const bool motionRotate,
const QString &motionPath)
{
const auto mangler = [multiplier](const qreal value) {
return value*multiplier;
};
saveQrealSVG(exp, parent, visRange, attrName,
mangler, transform, type, templ, beginEvent, endEvent);
saveQrealSVG(exp,
parent,
visRange,
attrName,
mangler,
transform,
type,
templ,
beginEvent,
endEvent,
motion,
motionRotate,
motionPath);
}

void QrealAnimator::saveQrealSVG(SvgExporter& exp, QDomElement& parent,
const FrameRange& visRange, const QString& attrName,
const Mangler& mangler, const bool transform,
const QString& type, const QString& templ,
const QString &beginEvent, const QString &endEvent)
void QrealAnimator::saveQrealSVG(SvgExporter& exp,
QDomElement& parent,
const FrameRange& visRange,
const QString& attrName,
const Mangler& mangler,
const bool transform,
const QString& type,
const QString& templ,
const QString &beginEvent,
const QString &endEvent,
const bool motion,
const bool motionRotate,
const QString &motionPath)
{
if(hasValidExpression()) {
if (hasValidExpression()) {
const auto copy = enve::make_shared<QrealAnimator>("");
const auto relRange = prp_absRangeToRelRange(exp.fAbsRange);
copy->prp_setInheritedFrameShift(prp_getTotalFrameShift(), nullptr);
copy->setExpression(mExpression.sptr());
copy->applyExpression(relRange, 10, false);
copy->saveQrealSVG(exp, parent, visRange, attrName,
mangler, transform, type, templ,
beginEvent, endEvent);
copy->saveQrealSVG(exp,
parent,
visRange,
attrName,
mangler,
transform,
type,
templ,
beginEvent,
endEvent,
motion,
motionRotate,
motionPath);
setExpression(mExpression.sptr());
} else {
graph_saveSVG(exp, parent, visRange, attrName,
[this, mangler, &templ](const int relFrame) {
const qreal val = mangler(getEffectiveValue(relFrame));
return templ.arg(val);
}, transform, type, beginEvent, endEvent);
}, transform, type, beginEvent, endEvent, motion, motionRotate, motionPath);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/core/Animators/qrealanimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator {
const QString& type = "",
const QString& templ = "%1",
const QString& beginEvent = "",
const QString& endEvent = "");
const QString& endEvent = "",
const bool motion = false,
const bool motionRotate = false,
const QString & motionPath = QString());
using Mangler = std::function<qreal(qreal)>;
void saveQrealSVG(SvgExporter& exp,
QDomElement& parent,
Expand All @@ -194,7 +197,10 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator {
const QString& type = "",
const QString& templ = "%1",
const QString& beginEvent = "",
const QString& endEvent = "");
const QString& endEvent = "",
const bool motion = false,
const bool motionRotate = false,
const QString & motionPath = QString());
private:
qreal calculateBaseValueAtRelFrame(const qreal frame) const;
void startBaseValueTransform();
Expand Down
36 changes: 34 additions & 2 deletions src/core/Boxes/boundingbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "Boxes/boundingbox.h"
#include "Boxes/containerbox.h"
#include "TransformEffects/followpatheffect.h"
#include "canvas.h"
#include "swt_abstraction.h"
#include "Timeline/durationrectangle.h"
Expand Down Expand Up @@ -358,6 +359,23 @@ bool BoundingBox::hasTransformEffects() const {
return mTransformEffectCollection->ca_hasChildren();
}

const QStringList BoundingBox::checkTransformEffectsForSVGSupport()
{
QStringList result;
const int totalEffects = mTransformEffectCollection->ca_getNumberOfChildren();
for (int i = 0; i < totalEffects; ++i) {
const auto effect = enve_cast<TransformEffect*>(mTransformEffectCollection->getChild(i));
if (!effect) { continue; }
if (!effect->isVisible()) { continue; }
bool isSafeForSVG = false;
if (const auto followPath = enve_cast<FollowPathEffect*>(effect)) {
isSafeForSVG = true;
}
if (!isSafeForSVG) { result.append(effect->prp_getName()); }
}
return result;
}

ContainerBox *BoundingBox::getFirstParentLayer() const {
const auto parent = getParentGroup();
if(!parent) return nullptr;
Expand Down Expand Up @@ -1433,15 +1451,29 @@ eTask* BoundingBox::saveSVGWithTransform(SvgExporter& exp,
taskPtr->addDependent({[ptr, taskPtr, expPtr, parentPtr, visRange, maskId]() {
auto& ele = taskPtr->element();
if (ptr) {
ele.setAttribute("id", AppSupport::filterId(ptr->prp_getName()));
SvgExportHelpers::assignVisibility(*expPtr, ele, visRange);

const auto transformEffects = ptr->mTransformEffectCollection.get();
const bool hasTransformEffects = transformEffects->hasEffectsSVG();

const auto transform = ptr->mTransformAnimator.get();
const auto transformed = transform->saveSVG(*expPtr, visRange, ele);
const auto effects = ptr->mRasterEffectsAnimators.get();
const auto withEffects = effects->saveEffectsSVG(*expPtr, visRange, transformed);
const auto withEffects = hasTransformEffects ?
transformEffects->saveEffectsSVG(*expPtr,
visRange,
ele,
effects->saveEffectsSVG(*expPtr,
visRange,
transformed)) :
effects->saveEffectsSVG(*expPtr,
visRange,
transformed);

if (maskId == ptr->prp_getName()) { // move mask to defs
auto& eleMask = taskPtr->initialize("mask");
eleMask.setAttribute("id", QString(ptr->prp_getName()).simplified().replace(" ", ""));
eleMask.setAttribute("id", QString("%1Mask").arg(AppSupport::filterId(ptr->prp_getName())));
eleMask.appendChild(withEffects);
expPtr->addToDefs(eleMask);
} else {
Expand Down
1 change: 1 addition & 0 deletions src/core/Boxes/boundingbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ class CORE_EXPORT BoundingBox : public eBoxOrSound {
QMatrix& postTransform);

bool hasTransformEffects() const;
const QStringList checkTransformEffectsForSVGSupport();

ContainerBox* getFirstParentLayer() const;

Expand Down
2 changes: 1 addition & 1 deletion src/core/Boxes/containerbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class GroupSaverSVG : public ComplexTask
}
}
if (!mItemMaskId.isEmpty()) {
mEle.setAttribute("mask", QString("url(#%1)").arg(QString(mItemMaskId).simplified().replace(" ", "")));
mEle.setAttribute("mask", QString("url(#%1Mask)").arg(AppSupport::filterId(mItemMaskId)));
}
}
}
Expand Down
Loading