1 | // Aseprite |
2 | // Copyright (C) 2020-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2016 David Capello |
4 | // |
5 | // This program is distributed under the terms of |
6 | // the End-User License Agreement for Aseprite. |
7 | |
8 | #ifndef APP_TRANSFORMATION_H_INCLUDED |
9 | #define APP_TRANSFORMATION_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #include "gfx/point.h" |
13 | #include "gfx/rect.h" |
14 | #include <vector> |
15 | |
16 | #define CORNER_THICK_FOR_TILEMAP_MODE 0.001 |
17 | #define CORNER_THICK_FOR_PIXELS_MODE 1.0 |
18 | |
19 | namespace app { |
20 | |
21 | // Represents a transformation that can be done by the user in the |
22 | // document when he/she moves the mask using the selection handles. |
23 | class Transformation { |
24 | public: |
25 | class Corners { |
26 | public: |
27 | enum { |
28 | LEFT_TOP = 0, |
29 | RIGHT_TOP = 1, |
30 | RIGHT_BOTTOM = 2, |
31 | LEFT_BOTTOM = 3, |
32 | NUM_OF_CORNERS = 4 |
33 | }; |
34 | |
35 | Corners() : m_corners(NUM_OF_CORNERS) { } |
36 | Corners(const gfx::RectF bounds) : m_corners(NUM_OF_CORNERS) { |
37 | m_corners[LEFT_TOP].x = bounds.x; |
38 | m_corners[LEFT_TOP].y = bounds.y; |
39 | m_corners[RIGHT_TOP].x = bounds.x2(); |
40 | m_corners[RIGHT_TOP].y = bounds.y; |
41 | m_corners[RIGHT_BOTTOM].x = bounds.x2(); |
42 | m_corners[RIGHT_BOTTOM].y = bounds.y2(); |
43 | m_corners[LEFT_BOTTOM].x = bounds.x; |
44 | m_corners[LEFT_BOTTOM].y = bounds.y2(); |
45 | } |
46 | |
47 | std::size_t size() const { return m_corners.size(); } |
48 | |
49 | gfx::PointF& operator[](int index) { return m_corners[index]; } |
50 | const gfx::PointF& operator[](int index) const { return m_corners[index]; } |
51 | |
52 | const gfx::PointF& leftTop() const { return m_corners[LEFT_TOP]; } |
53 | const gfx::PointF& rightTop() const { return m_corners[RIGHT_TOP]; } |
54 | const gfx::PointF& rightBottom() const { return m_corners[RIGHT_BOTTOM]; } |
55 | const gfx::PointF& leftBottom() const { return m_corners[LEFT_BOTTOM]; } |
56 | |
57 | void leftTop(const gfx::PointF& pt) { m_corners[LEFT_TOP] = pt; } |
58 | void rightTop(const gfx::PointF& pt) { m_corners[RIGHT_TOP] = pt; } |
59 | void rightBottom(const gfx::PointF& pt) { m_corners[RIGHT_BOTTOM] = pt; } |
60 | void leftBottom(const gfx::PointF& pt) { m_corners[LEFT_BOTTOM] = pt; } |
61 | |
62 | gfx::RectF bounds(double cornerThick) const { |
63 | gfx::RectF bounds; |
64 | for (int i=0; i<Corners::NUM_OF_CORNERS; ++i) |
65 | bounds |= gfx::RectF(m_corners[i].x, m_corners[i].y, cornerThick, cornerThick); |
66 | return bounds.floor(); |
67 | } |
68 | |
69 | private: |
70 | std::vector<gfx::PointF> m_corners; |
71 | }; |
72 | |
73 | Transformation(); |
74 | Transformation(const gfx::RectF& bounds, double cornerThick); |
75 | |
76 | // Simple getters and setters. The angle is in radians. |
77 | |
78 | const gfx::RectF& bounds() const { return m_bounds; } |
79 | const gfx::PointF& pivot() const { return m_pivot; } |
80 | double cornerThick() const { return m_cornerThick; } |
81 | double angle() const { return m_angle; } |
82 | double skew() const { return m_skew; } |
83 | |
84 | void bounds(const gfx::RectF& bounds) { m_bounds = bounds; } |
85 | void pivot(const gfx::PointF& pivot) { m_pivot = pivot; } |
86 | void angle(double angle) { m_angle = angle; } |
87 | void skew(double angle) { m_skew = angle; } |
88 | |
89 | // Applies the transformation (rotation with angle/pivot) to the |
90 | // current bounds (m_bounds). |
91 | Corners transformedCorners() const; |
92 | |
93 | // Changes the pivot to another location, adjusting the bounds to |
94 | // keep the current rotated-corners in the same location. |
95 | void displacePivotTo(const gfx::PointF& newPivot); |
96 | |
97 | gfx::RectF transformedBounds() const; |
98 | |
99 | // Static helper method to rotate points. |
100 | static gfx::PointF rotatePoint(const gfx::PointF& point, |
101 | const gfx::PointF& pivot, |
102 | const double angle, |
103 | const double skew); |
104 | |
105 | private: |
106 | gfx::RectF m_bounds = gfx::RectF(0.0, 0.0, 0.0, 0.0); |
107 | gfx::PointF m_pivot = gfx::PointF(0.0, 0.0); |
108 | double m_angle = 0.0; |
109 | double m_skew = 0.0; |
110 | double m_cornerThick = CORNER_THICK_FOR_PIXELS_MODE; |
111 | }; |
112 | |
113 | } // namespace app |
114 | |
115 | #endif |
116 | |