1// Aseprite
2// Copyright (C) 2020-2022 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/transformation.h"
13
14#include "gfx/point.h"
15#include "gfx/size.h"
16
17#include <cmath>
18
19namespace app {
20
21using namespace gfx;
22
23Transformation::Transformation()
24{
25}
26
27Transformation::Transformation(const RectF& bounds, double cornerThick)
28 : m_bounds(bounds)
29 , m_cornerThick(cornerThick)
30{
31 m_pivot.x = bounds.x + bounds.w/2;
32 m_pivot.y = bounds.y + bounds.h/2;
33}
34
35Transformation::Corners Transformation::transformedCorners() const
36{
37 Corners corners(m_bounds);
38
39 // TODO We could create a composed 4x4 matrix with all
40 // transformation and apply the same matrix to avoid calling
41 // rotatePoint/cos/sin functions 4 times, anyway, it's not
42 // critical at this point.
43
44 for (std::size_t c=0; c<corners.size(); ++c)
45 corners[c] = Transformation::rotatePoint(corners[c], m_pivot,
46 m_angle, m_skew);
47 return corners;
48}
49
50void Transformation::displacePivotTo(const PointF& newPivot)
51{
52 // Calculate the rotated corners
53 Corners corners = transformedCorners();
54
55 // Rotate-back the position of the rotated origin (corners[0]) using
56 // the new pivot.
57 PointF pt = corners.leftTop();
58 pt = rotatePoint(pt, newPivot, -m_angle, 0.0);
59 pt = rotatePoint(pt, newPivot, 0.0, -m_skew);
60
61 // Change the new pivot.
62 m_pivot = newPivot;
63 m_bounds = RectF(pt, m_bounds.size());
64}
65
66PointF Transformation::rotatePoint(
67 const PointF& point,
68 const PointF& pivot,
69 const double angle,
70 const double skew)
71{
72 double cos = std::cos(-angle);
73 double sin = std::sin(-angle);
74 double tan = std::tan(skew);
75 double dx = point.x - pivot.x;
76 double dy = point.y - pivot.y;
77 dx += dy*tan;
78 return PointF(pivot.x + dx*cos - dy*sin,
79 pivot.y + dx*sin + dy*cos);
80}
81
82RectF Transformation::transformedBounds() const
83{
84 // Get transformed corners
85 Corners corners = transformedCorners();
86
87 // Create a union of all corners
88 RectF bounds;
89 for (int i=0; i<Corners::NUM_OF_CORNERS; ++i)
90 bounds = bounds.createUnion(RectF(corners[i].x, corners[i].y, m_cornerThick, m_cornerThick));
91
92 return bounds.floor();
93}
94
95} // namespace app
96