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