1 module prova.math.rect;
2 
3 import prova.math,
4        std.math;
5 
6 ///
7 enum Side { LEFT, RIGHT, TOP, BOTTOM }
8 
9 ///
10 struct Rect
11 {
12   ///
13   float left = 0;
14   ///
15   float top = 0;
16   ///
17   float width = 0;
18   ///
19   float height = 0;
20 
21   ///
22   this(float left, float top, float width, float height)
23   {
24     set(left, top, width, height);
25   }
26 
27   //// Sets the position and dimensions of the rect in a single statement
28   void set(float left, float top, float width, float height)
29   {
30     this.left = left;
31     this.top = top;
32     this.width = width;
33     this.height = height;
34   }
35 
36   ///
37   @property float right() const
38   {
39     return left + width;
40   }
41 
42   ///
43   @property void right(float value)
44   {
45     left = value - width;
46   }
47 
48   ///
49   @property float bottom() const
50   {
51     return top - height;
52   }
53 
54   ///
55   @property void bottom(float value)
56   {
57     top = value + height;
58   }
59 
60   ///
61   Vector2 getSize() const
62   {
63     return Vector2(width, height);
64   }
65 
66   ///
67   Vector2 getCenter() const
68   {
69     return Vector2(left + width / 2, top - height / 2);
70   }
71 
72   ///
73   Vector2 getTopLeft() const
74   {
75     return Vector2(left, top);
76   }
77 
78   ///
79   Vector2 getTopRight() const
80   {
81     return Vector2(right, top);
82   }
83 
84   ///
85   Vector2 getBottomLeft() const
86   {
87     return Vector2(left, bottom);
88   }
89 
90   ///
91   Vector2 getBottomRight() const
92   {
93     return Vector2(right, bottom);
94   }
95 
96   Side getClosestSide(Rect rect) const
97   {
98     const Vector2 center = getCenter();
99     const Vector2 rectCenter = rect.getCenter();
100 
101     return getClosestSide(
102       (rectCenter.x - center.x) / (width + rect.width),
103       (rectCenter.y - center.y) / (height + rect.height)
104     );
105   }
106 
107   Side getClosestSide(Vector2 position) const
108   {
109     const Vector2 center = getCenter();
110 
111     return getClosestSide(
112       (position.x - center.x) / width,
113       (position.y - center.y) / height
114     );
115   }
116 
117   private Side getClosestSide(float fractionX, float fractionY) const
118   {
119     if(abs(fractionX) > abs(fractionY)) {
120       if(fractionX > 0)
121         return Side.RIGHT;
122       if(fractionX < 0)
123         return Side.LEFT;
124     } else {
125       if(fractionY > 0)
126         return Side.TOP;
127       if(fractionY < 0)
128         return Side.BOTTOM;
129     }
130 
131     // default to the left side
132     return Side.LEFT;
133   }
134 }