ScummVM API documentation
Rect.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef QDENGINE_MINIGAMES_ADV_RECT_H
23 #define QDENGINE_MINIGAMES_ADV_RECT_H
24 
25 #include "qdengine/xmath.h"
26 #include "qdengine/minigames/adv/Range.h"
27 
28 namespace QDEngine {
29 
30 /*
31  * FIXME: Подразумевается, что left < right и top < bottom, добавить
32  * стратегию для кустомизации этого понятия?
33  */
34 
36 
40 template<typename scalar_type, class vect_type>
41 struct Rect {
42  typedef vect_type VectType;
43  typedef scalar_type ScalarType;
45  typedef Rangef RangeType;
46 
47  // конструкторы
48  Rect() :
49  _left(ScalarType(0)),
50  _top(ScalarType(0)),
51  _width(ScalarType(0)),
52  _height(ScalarType(0)) {}
53 
55  Rect(const VectType& size) :
56  _top(ScalarType(0)),
57  _left(ScalarType(0)),
58  _width(size.x),
59  _height(size.y) {}
60 
61  Rect(ScalarType left, ScalarType top, ScalarType width, ScalarType height) :
62  _left(left),
63  _top(top),
64  _width(width),
65  _height(height) {}
66 
67  Rect(const VectType& _topleft, const VectType& size) :
68  _left(_topleft.x),
69  _top(_topleft.y),
70  _width(size.x),
71  _height(size.y) {}
72 
73  void set(ScalarType left, ScalarType top, ScalarType width, ScalarType height) {
74  _left = left;
75  _top = top;
76  _width = width;
77  _height = height;
78  }
79 
80  inline ScalarType left() const {
81  return _left;
82  }
83  inline ScalarType top() const {
84  return _top;
85  }
86  inline ScalarType width() const {
87  return _width;
88  }
89  inline ScalarType height() const {
90  return _height;
91  }
92 
93  VectType _lefttop() const {
94  return VectType(_left, _top);
95  }
96  VectType right_top() const {
97  return VectType(_left + _width, _top);
98  }
99  VectType _leftbottom() const {
100  return VectType(_left, _top + _height);
101  }
102  VectType right_bottom() const {
103  return VectType(_left + _width, _top + _height);
104  }
105 
106  // аксессоры (вычисляющие):
107  inline ScalarType right() const {
108  return _left + _width;
109  }
110  inline ScalarType bottom() const {
111  return _top + _height;
112  }
113 
114  /*
115  * FIXME: для float и double деление на 2 лучше заменить на умножение на 0.5,
116  * для целых типов лучше исползовать сдвиг.
117  */
118 
120  inline VectType center() const {
121  return VectType(_left + _width / ScalarType(2),
122  _top + _height / ScalarType(2));
123  }
125  inline VectType size() const {
126  return VectType(_width, _height);
127  }
128 
129  // сеттеры:
130  inline void left(ScalarType left) {
131  _left = left;
132  }
133  inline void top(ScalarType top) {
134  _top = top;
135  }
136  inline void width(ScalarType width) {
137  _width = width;
138  }
139  inline void height(ScalarType height) {
140  _height = height;
141  }
142 
143  // сеттеры (вычисляющие):
144  inline void right(ScalarType right) {
145  _left = right - _width;
146  }
147  inline void bottom(ScalarType bottom) {
148  _top = bottom - _height;
149  }
150 
152  inline void center(const VectType& center) {
153  _left = center.x - _width / ScalarType(2);
154  _top = center.y - _height / ScalarType(2);
155  }
156  /*
157  * FIXME: размер должен менятся относительно левого-верхнего угла (как у
158  * сеттеров width и height) или относительно центра? Добавить
159  * класс-стратегию для этих целей? Фунцию с другим именем (напр
160  * scale (), которая принимает центр, относительно которого происходит
161  * скэлинг)?
162  */
164  inline void size(const VectType& size) {
165  _width = size.x;
166  _height = size.y;
167  }
168 
169  // утилиты:
170 
172  inline bool point_inside(const VectType& point) const {
173  if (point.x >= left() && point.y >= top() &&
174  point.x <= right() && point.y <= bottom())
175  return true;
176  else
177  return false;
178  }
180  inline bool rect_inside(const RectType& rect) const {
181  if (rect.left() >= left() && rect.top() >= top() &&
182  rect.bottom() <= bottom() && rect.right() <= right())
183  return true;
184  else
185  return false;
186  }
187 
188  inline bool rect_overlap(const RectType& rect) const {
189  if (left() > rect.right() || right() < rect.left()
190  || top() > rect.bottom() || bottom() < rect.top())
191  return false;
192 
193  return true;
194  }
195 
197 
201  inline RectType scaled(const VectType& scale, const VectType& origin) const {
202  return (*this - origin) * scale + origin;
203  }
204 
206  inline void validate() {
207  if (width() < ScalarType(0)) {
208  left(left() + width());
209  width(-width());
210  }
211  if (height() < ScalarType(0)) {
212  top(top() + height());
213  height(-height());
214  }
215  }
216 
217  inline RectType intersection(const RectType& rect) const {
218  RangeType xRange = RangeType(left(), right()).intersection(RangeType(rect.left(), rect.right()));
219  RangeType yRange = RangeType(top(), bottom()).intersection(RangeType(rect.top(), rect.bottom()));
220  return RectType(xRange.minimum(), yRange.minimum(), xRange.length(), yRange.length());
221  }
222 
223  // Операторы
224  RectType operator+(const VectType& point) const {
225  return RectType(left() + point.x, top() + point.y,
226  width(), height());
227  }
228 
229  RectType operator-(const VectType& point) const {
230  return RectType(left() - point.x, top() - point.y,
231  width(), height());
232  }
233 
234  RectType operator*(const VectType& point) const {
235  return RectType(left() * point.x, top() * point.y,
236  width() * point.x, height() * point.y);
237  }
238 
239  RectType operator*(const RectType& rhs) const {
240  VectType leftTop(left() + width() * rhs.left(), top() + height() * rhs.top());
241  VectType size(this->size() * rhs.size());
242  return RectType(leftTop, size);
243  }
244 
245  RectType operator/(const RectType& rhs) const {
246  VectType leftTop((left() - rhs.left()) / rhs.width(), (top() - rhs.top()) / rhs.height());
247  VectType size(width() / rhs.width(), height() / rhs.height());
248  return RectType(leftTop, size);
249  }
250 
251  RectType operator/(const VectType& point) const {
252  return RectType(left() / point.x, top() / point.y,
253  width() / point.x, height() / point.y);
254  }
255 
256  bool operator==(const RectType& rect) const {
257  return (_left == rect._left && _top == rect._top &&
258  _width == rect._width && _height == rect._height);
259  }
260 
261  bool eq(const RectType& rect, ScalarType eps = FLT_COMPARE_TOLERANCE) const {
262  return (abs(_left - rect._left) < eps && abs(_top - rect._top) < eps &&
263  abs(_width - rect._width) < eps && abs(_height - rect._height) < eps);
264  }
265 
266  bool operator!=(const RectType& rect) const {
267  return (_left != rect._left || _top != rect._top ||
268  _width != rect._width || _height != rect._height);
269  }
270 
271 protected:
272  ScalarType _left;
273  ScalarType _top;
274  ScalarType _width;
275  ScalarType _height;
276 
277 #if 0
278 public:
279  // SideKick на этом обламывается:
280  template<class ST, class VT>
281  operator ::Rect<ST, VT>() const {
282  return ::Rect<ST, VT>(static_cast<ST>(left()),
283  static_cast<ST>(top()),
284  static_cast<ST>(width()),
285  static_cast<ST>(height()));
286  }
287 #endif
288 
289  bool clipLine(VectType& pos0, VectType& pos1) const;
290 };
291 
292 template<typename ScalarType, class VectType>
293 bool Rect<ScalarType, VectType>::clipLine(VectType& pos0, VectType& pos1) const {
294  VectType p0(pos0), p1(pos1);
295 
296  bool b0 = point_inside(p0);
297  bool b1 = point_inside(p1);
298 
299  if (b0 && b1) // вся линия внутри clip
300  return true;
301  else {
302  float tc;
303  float t[4] = {-1.0f, -1.0f, -1.0f, -1.0f};
304  int find = 0;
305  ScalarType dx = p1.x - p0.x;
306  ScalarType dy = p1.y - p0.y;
307 
308  ScalarType crd;
309 
310  if (abs(dy) > 0) {
311  tc = (float)(top() - p0.y) / dy;
312  if (tc >= 0.0f && tc <= 1.0f) {
313  crd = p0.x + tc * dx;
314  if (crd >= left() && crd <= right())
315  t[find++] = tc;
316  }
317 
318  tc = (float)(bottom() - p0.y) / dy;
319  if (tc >= 0.0f && tc <= 1.0f) {
320  crd = p0.x + tc * dx;
321  if (crd >= left() && crd <= right())
322  t[find++] = tc;
323  }
324  }
325 
326  if (abs(dx) > 0) {
327  tc = (float)(left() - p0.x) / dx;
328  if (tc >= 0.0f && tc <= 1.0f) {
329  crd = p0.y + tc * dy;
330  if (crd >= top() && crd <= bottom())
331  t[find++] = tc;
332  }
333 
334  tc = (float)(right() - p0.x) / dx;
335  if (tc >= 0.0f && tc <= 1.0f) {
336  crd = p0.y + tc * dy;
337  if (crd >= top() && crd <= bottom())
338  t[find++] = tc;
339  }
340  }
341 
342  if (b0) { //внутри только точка p0
343  pos1.set(p0.x + t[0]*dx, p0.y + t[0]*dy);
344  pos0.set(p0.x, p0.y);
345  } else if (b1) { //внутри только точка p1
346  pos0.set(p0.x + t[0]*dx, p0.y + t[0]*dy);
347  pos1.set(p1.x, p1.y);
348  } else if (find) { //обе точки снаружи, но часть отрезка внутри
349  if (t[0] < t[1]) {
350  pos0.set(p0.x + t[0]*dx, p0.y + t[0]*dy);
351  pos1.set(p0.x + t[1]*dx, p0.y + t[1]*dy);
352  } else {
353  pos1.set(p0.x + t[0]*dx, p0.y + t[0]*dy);
354  pos0.set(p0.x + t[1]*dx, p0.y + t[1]*dy);
355  }
356  } else
357  return false;
358  }
359  return true;
360 }
361 
362 } // namespace QDEngine
363 
364 #endif // QDENGINE_MINIGAMES_ADV_RECT_H
RectType scaled(const VectType &scale, const VectType &origin) const
Производит скэлинг.
Definition: Rect.h:201
bool rect_inside(const RectType &rect) const
Проверяет не находится ли прямоугольник _rect внутри прямоугольника
Definition: Rect.h:180
Definition: Range.h:27
void center(const VectType &center)
Переносит центр прямоугольника в точку _center не изменяя его размер.
Definition: Rect.h:152
VectType size() const
Возвращает размер прямоугольника.
Definition: Rect.h:125
void size(const VectType &size)
Устанавливает новые размеры, сохраняя левый-верхний угол в преждней точке.
Definition: Rect.h:164
In find(In first, In last, const T &v)
Definition: algorithm.h:225
void validate()
Исправляет отрицательную ширину/высоту
Definition: Rect.h:206
Graphics::Surface * scale(const Graphics::Surface &srcImage, int xSize, int ySize)
Базовый класс для игровых ресурсов.
Definition: console.h:28
bool point_inside(const VectType &point) const
Проверяет не находится ли точка _point внутри прямоугольника
Definition: Rect.h:172
VectType center() const
Возвращает координаты цетра прямоугольника.
Definition: Rect.h:120
Rect(const VectType &size)
Создаёт Rect размера _size, левый-верхний угол остаётся в точке (0, 0).
Definition: Rect.h:55
Абстрактый прямоугольник.
Definition: Rect.h:41