17#include "layercamera.h"
20#include <QEasingCurve>
27 setName(tr(
"Camera Layer"));
30 mFieldW = settings.value(
"FieldW").toInt();
31 mFieldH = settings.value(
"FieldH").toInt();
32 if (mFieldW < 2 || mFieldH < 2)
37 viewRect =
QRect(
QPoint(-mFieldW / 2, -mFieldH / 2),
QSize(mFieldW, mFieldH));
40LayerCamera::~LayerCamera()
44bool LayerCamera::addKeyFrame(
int position,
KeyFrame *pKeyFrame)
46 bool keyAdded = Layer::addKeyFrame(position, pKeyFrame);
48 splitControlPointIfNeeded(position);
53bool LayerCamera::removeKeyFrame(
int position)
55 mergeControlPointIfNeeded(position);
56 return Layer::removeKeyFrame(position);;
59Camera* LayerCamera::getCameraAtFrame(
int frameNumber)
const
61 return static_cast<Camera*
>(getKeyFrameAt(frameNumber));
64Camera* LayerCamera::getLastCameraAtFrame(
int frameNumber,
int increment)
const
66 return static_cast<Camera*
>(getLastKeyFrameAtPosition(frameNumber + increment));
69QTransform LayerCamera::getViewAtFrame(
int frameNumber)
const
71 if (keyFrameCount() == 0)
77 if (frameNumber < firstKeyFramePosition())
79 frameNumber = firstKeyFramePosition();
82 Camera* camera1 =
static_cast<Camera*
>(getLastKeyFrameAtPosition(frameNumber));
84 int nextFrame = getNextKeyFramePosition(frameNumber);
85 Camera* camera2 =
static_cast<Camera*
>(getLastKeyFrameAtPosition(nextFrame));
87 if (camera1 ==
nullptr && camera2 ==
nullptr)
91 else if (camera1 ==
nullptr && camera2 !=
nullptr)
93 return camera2->getView();
95 else if (camera2 ==
nullptr && camera1 !=
nullptr)
97 return camera1->getView();
100 if (camera1->compare(*camera2))
102 return camera1->getView();
105 double frame1 = camera1->pos();
106 double frame2 = camera2->pos();
109 qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1) / (frame2 - frame1));
110 auto lerp = [](
double f1,
double f2,
double percent) ->
double
112 return f1 * (1.0 - percent) + f2 * percent;
115 QPointF controlPoint = camera1->getPathControlPoint();
116 if (!camera1->pathControlPointMoved()) {
117 controlPoint = getCenteredPathPoint(frame1);
120 const QPointF& point = getBezierPoint(camera1->translation(), camera2->translation(),
121 -controlPoint, percent);
123 double dx = point.
x();
124 double dy = point.
y();
125 double r = lerp(camera1->rotation(), camera2->rotation(), percent);
126 double s = lerp(camera1->scaling(), camera2->scaling(), percent);
129 camTransform.
scale(s, s);
136void LayerCamera::linearInterpolateTransform(
Camera* cam)
138 if (keyFrameCount() == 0)
141 int frameNumber = cam->pos();
142 Camera* camera1 =
static_cast<Camera*
>(getLastKeyFrameAtPosition(frameNumber - 1));
144 int nextFrame = getNextKeyFramePosition(frameNumber);
145 Camera* camera2 =
static_cast<Camera*
>(getLastKeyFrameAtPosition(nextFrame));
147 if (camera1 ==
nullptr && camera2 ==
nullptr)
152 else if (camera1 ==
nullptr && camera2 !=
nullptr)
154 return cam->assign(*camera2);
157 else if (camera2 ==
nullptr && camera1 !=
nullptr)
159 return cam->assign(*camera1);
162 if (camera1->compare(*camera2))
164 return cam->assign(*camera1);
167 double frame1 = camera1->pos();
168 double frame2 = camera2->pos();
171 qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1)/ (frame2 - frame1));
173 auto lerp = [](
double f1,
double f2,
double percent) ->
double
175 return f1 * (1.0 - percent) + f2 * percent;
178 QPointF controlPoint = camera1->getPathControlPoint();
179 if (!camera1->pathControlPointMoved()) {
180 controlPoint = getCenteredPathPoint(frame1);
183 QPointF point = getBezierPoint(camera1->translation(), camera2->translation(),
184 -controlPoint, percent);
185 double dx = point.
x();
186 double dy = point.
y();
187 double r = lerp(camera1->rotation(), camera2->rotation(), percent);
188 double s = lerp(camera1->scaling(), camera2->scaling(), percent);
190 cam->translate(dx, dy);
195qreal LayerCamera::getInterpolationPercent(CameraEasingType type, qreal percent)
const
242 default: Q_UNREACHABLE();
break;
249 QLineF line1(first, pathPoint);
250 QLineF line2(pathPoint, last);
251 return QLineF(line1.pointAt(percent), line2.pointAt(percent)).
pointAt(percent);
254void LayerCamera::splitControlPointIfNeeded(
int frame)
const
256 int next = getNextKeyFramePosition(frame);
257 int prev = getPreviousKeyFramePosition(frame);
260 if (frame > prev && (frame > 1) && frame < next)
262 Camera* camFrame = getLastCameraAtFrame(frame, 0);
263 Camera* camPrev = getCameraAtFrame(prev);
264 Camera* camNext = getCameraAtFrame(next);
265 Q_ASSERT(camPrev && camFrame && camNext);
267 if (camPrev->pathControlPointMoved()) {
268 qreal t =
static_cast<qreal
>(frame - prev) / (next - prev);
269 QPointF previousControlPoint = camPrev->getPathControlPoint();
272 QLineF interpolatedLineCN =
QLineF(previousControlPoint, -camNext->translation());
275 QLineF interpolatedLinePC =
QLineF(-camPrev->translation(), previousControlPoint);
277 camPrev->setPathControlPoint(interpolatedLinePC.
pointAt(t));
278 camFrame->setPathControlPoint(interpolatedLineCN.
pointAt(t));
279 camFrame->setPathControlPointMoved(
true);
282 Camera* camPrev = getCameraAtFrame(prev);
283 camPrev->setPathControlPointMoved(
false);
287void LayerCamera::mergeControlPointIfNeeded(
int frame)
const
289 int next = getNextKeyFramePosition(frame);
290 int prev = getPreviousKeyFramePosition(frame);
293 if (frame > prev && (frame > 1) && frame < next)
295 Camera* camPrev = getCameraAtFrame(prev);
296 Camera* camFrame = getLastCameraAtFrame(frame, 0);
297 Camera* camNext = getCameraAtFrame(next);
298 Q_ASSERT(camPrev && camFrame && camNext);
300 if (camPrev->pathControlPointMoved()) {
303 const QLineF& interpolatedLineCN =
QLineF(camFrame->getPathControlPoint(), -camNext->translation());
306 const QLineF& interpolatedLinePC =
QLineF(-camPrev->translation(), camPrev->getPathControlPoint());
309#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
310 auto intersection = interpolatedLinePC.
intersects(interpolatedLineCN, &mergedCPoint);
312 auto intersection = interpolatedLinePC.
intersect(interpolatedLineCN, &mergedCPoint);
316 QLineF(camFrame->getPathControlPoint(), mergedCPoint).
length() < mControlPointMergeThreshold)
318 camPrev->setPathControlPoint(mergedCPoint);
319 camPrev->setPathControlPointMoved(
true);
321 camPrev->setPathControlPointMoved(
false);
327QRect LayerCamera::getViewRect()
const
332QSize LayerCamera::getViewSize()
const
334 return viewRect.
size();
337void LayerCamera::setViewRect(
QRect newViewRect)
339 viewRect = newViewRect;
342void LayerCamera::setCameraEasingAtFrame(CameraEasingType type,
int frame)
const
344 Camera* camera = getLastCameraAtFrame(frame, 0);
345 camera->setEasingType(type);
346 camera->updateViewTransform();
349void LayerCamera::resetCameraAtFrame(CameraFieldOption type,
int frame)
const
351 int frameToModify = frame;
352 if (!keyExists(frame)) {
353 frameToModify = getPreviousKeyFramePosition(frame);
355 Camera* camera = getLastCameraAtFrame(frameToModify, 0);
359 case CameraFieldOption::RESET_FIELD:
360 camera->resetTransform();
362 case CameraFieldOption::RESET_TRANSLATION:
363 camera->translate(
QPoint(0,0));
365 case CameraFieldOption::RESET_SCALING:
368 case CameraFieldOption::RESET_ROTATION:
371 case CameraFieldOption::ALIGN_HORIZONTAL: {
372 qreal otherYCoord = camera->translation().
y();
373 Camera* nextCam = getCameraAtFrame(getNextKeyFramePosition(frameToModify));
374 nextCam->translate(nextCam->translation().
x(), otherYCoord);
375 camera->setPathControlPointMoved(
false);
378 case CameraFieldOption::ALIGN_VERTICAL: {
379 qreal otherXCoord = camera->translation().
x();
380 Camera* nextCam = getCameraAtFrame(getNextKeyFramePosition(frameToModify));
381 nextCam->translate(otherXCoord, nextCam->translation().
y());
382 camera->setPathControlPointMoved(
false);
385 case CameraFieldOption::HOLD_FRAME: {
387 if (getMaxKeyFramePosition() == camera->pos()) {
return; }
389 QPointF translation = camera->translation();
390 qreal rotation = camera->rotation();
391 qreal scaling = camera->scaling();
392 camera->setPathControlPointMoved(
false);
393 Camera* nextCamera = getLastCameraAtFrame(getNextKeyFramePosition(frame), 0);
394 nextCamera->translate(translation);
395 nextCamera->scale(scaling);
396 nextCamera->rotate(rotation);
397 nextCamera->setPathControlPointMoved(
false);
405 if (type != CameraFieldOption::RESET_SCALING && type != CameraFieldOption::RESET_ROTATION) {
406 setPathMovedAtFrame(frame - 1,
false);
409 camera->updateViewTransform();
412void LayerCamera::updateDotColor(DotColorType color)
416 case DotColorType::RED:
419 case DotColorType::GREEN:
422 case DotColorType::BLUE:
425 case DotColorType::BLACK:
428 case DotColorType::WHITE:
432 mDotColorType = color;
435QString LayerCamera::getInterpolationTextAtFrame(
int frame)
const
437 Camera* camera = getLastCameraAtFrame(frame, 0);
438 return getInterpolationText(camera->getEasingType());
441QPointF LayerCamera::getPathControlPointAtFrame(
int frame)
const
443 Camera* camera = getCameraAtFrame(getPreviousKeyFramePosition(frame));
446 return camera->getPathControlPoint();
449bool LayerCamera::hasSameTranslation(
int frame1,
int frame2)
const
451 Camera* camera1 = getCameraAtFrame(frame1);
452 Camera* camera2 = getCameraAtFrame(frame2);
454 if (camera1 ==
nullptr)
458 else if (camera2 ==
nullptr)
463 return camera1->translation() == camera2->translation();
466QList<QPointF> LayerCamera::getBezierPointsAtFrame(
int frame)
const
469 int prevFrame = getPreviousKeyFramePosition(frame);
470 int nextFrame = getNextKeyFramePosition(frame);
471 if (prevFrame < nextFrame)
473 Camera* prevCam = getCameraAtFrame(prevFrame);
474 Camera* nextCam = getCameraAtFrame(nextFrame);
476 if (prevCam->pathControlPointMoved()) {
486QPointF LayerCamera::getCenteredPathPoint(
int frame)
const
488 if (!keyExists(frame) || frame == getMaxKeyFramePosition())
489 frame = getPreviousKeyFramePosition(frame);
490 int nextFrame = getNextKeyFramePosition(frame);
491 Camera* cam1 = getCameraAtFrame(frame);
492 Camera* cam2 = getCameraAtFrame(nextFrame);
494 if (cam1 && cam2 ==
nullptr) {
495 return -cam1->translation();
496 }
else if (cam2 && cam1 ==
nullptr) {
497 return -cam2->translation();
498 }
else if (cam1 ==
nullptr && cam2 ==
nullptr) {
501 return QLineF(-cam1->translation(), -cam2->translation()).
pointAt(0.5);
504void LayerCamera::setPathMovedAtFrame(
int frame,
bool moved)
const
506 Camera* cam = getLastCameraAtFrame(frame, 0);
509 cam->setPathControlPointMoved(moved);
512void LayerCamera::updatePathControlPointAtFrame(
const QPointF& point,
int frame)
const
514 Camera* camera = getLastCameraAtFrame(frame, 0);
517 camera->setPathControlPoint(point);
518 camera->setPathControlPointMoved(
true);
521void LayerCamera::loadImageAtFrame(
int frameNumber, qreal dx, qreal dy, qreal rotate, qreal scale, CameraEasingType easing,
const QPointF& pathPoint,
bool pathMoved)
523 if (keyExists(frameNumber))
525 removeKeyFrame(frameNumber);
528 camera->setPos(frameNumber);
529 camera->setEasingType(easing);
531 camera->setPathControlPoint(pathPoint);
532 camera->setPathControlPointMoved(pathMoved);
546 c->setEasingType(CameraEasingType::LINEAR);
547 linearInterpolateTransform(c);
548 c->setPathControlPoint(c->translation());
562 if (mDotColorType != DotColorType::RED) {
563 layerElem.
setAttribute(
"pathColorType",
static_cast<int>(mDotColorType));
566 foreachKeyFrame([&](
KeyFrame* pKeyFrame)
577 if (camera->getEasingType() != CameraEasingType::LINEAR) {
578 keyTag.
setAttribute(
"easing",
static_cast<int>(camera->getEasingType()));
580 if (camera->pathControlPointMoved()) {
581 keyTag.
setAttribute(
"pathCPX", camera->getPathControlPoint().
x());
582 keyTag.
setAttribute(
"pathCPY", camera->getPathControlPoint().
y());
590void LayerCamera::loadDomElement(
const QDomElement& element,
QString dataDirPath, ProgressCallback progressStep)
592 Q_UNUSED(dataDirPath)
593 Q_UNUSED(progressStep)
595 this->loadBaseDomElement(element);
600 updateDotColor(
static_cast<DotColorType
>(element.
attribute(
"pathColorType").
toInt()));
601 viewRect =
QRect(-width / 2, -height / 2, width, height);
604 while (!imageTag.
isNull())
607 if (!imageElement.
isNull())
609 if (imageElement.
tagName() ==
"camera")
617 CameraEasingType easing =
static_cast<CameraEasingType
>(imageElement.
attribute(
"easing",
"0").
toInt());
621 bool pathMoved = pathX != 0 || pathY != 0;
623 loadImageAtFrame(frame, dx, dy, rotate, scale, easing,
QPointF(pathX, pathY), pathMoved);
QDomElement createElement(const QString &tagName)
QString attribute(const QString &name, const QString &defValue) const const
void setAttribute(const QString &name, const QString &value)
QString tagName() const const
QDomNode appendChild(const QDomNode &newChild)
QDomNode firstChild() const const
bool isNull() const const
QDomNode nextSibling() const const
QDomElement toElement() const const
void setType(QEasingCurve::Type type)
qreal valueForProgress(qreal progress) const const
QLineF::IntersectType intersect(const QLineF &line, QPointF *intersectionPoint) const const
QLineF::IntersectionType intersects(const QLineF &line, QPointF *intersectionPoint) const const
qreal length() const const
QPointF pointAt(qreal t) const const
void append(const T &value)
double toDouble(bool *ok) const const
int toInt(bool *ok, int base) const const