kodi
Geometry.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #ifdef __GNUC__
12 // under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations.
13 #define XBMC_FORCE_INLINE __attribute__((always_inline))
14 #else
15 #define XBMC_FORCE_INLINE
16 #endif
17 
18 #include <algorithm>
19 #include <stdexcept>
20 #include <vector>
21 
22 template <typename T> class CPointGen
23 {
24 public:
25  typedef CPointGen<T> this_type;
26 
27  CPointGen() noexcept = default;
28 
29  constexpr CPointGen(T a, T b)
30  : x{a}, y{b}
31  {}
32 
33  template<class U> explicit constexpr CPointGen(const CPointGen<U>& rhs)
34  : x{static_cast<T> (rhs.x)}, y{static_cast<T> (rhs.y)}
35  {}
36 
37  constexpr this_type operator+(const this_type &point) const
38  {
39  return {x + point.x, y + point.y};
40  };
41 
42  this_type& operator+=(const this_type &point)
43  {
44  x += point.x;
45  y += point.y;
46  return *this;
47  };
48 
49  constexpr this_type operator-(const this_type &point) const
50  {
51  return {x - point.x, y - point.y};
52  };
53 
54  this_type& operator-=(const this_type &point)
55  {
56  x -= point.x;
57  y -= point.y;
58  return *this;
59  };
60 
61  constexpr this_type operator*(T factor) const
62  {
63  return {x * factor, y * factor};
64  }
65 
66  this_type& operator*=(T factor)
67  {
68  x *= factor;
69  y *= factor;
70  return *this;
71  }
72 
73  constexpr this_type operator/(T factor) const
74  {
75  return {x / factor, y / factor};
76  }
77 
78  this_type& operator/=(T factor)
79  {
80  x /= factor;
81  y /= factor;
82  return *this;
83  }
84 
85  T x{}, y{};
86 };
87 
88 template<typename T>
89 constexpr bool operator==(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
90 {
91  return (point1.x == point2.x && point1.y == point2.y);
92 }
93 
94 template<typename T>
95 constexpr bool operator!=(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
96 {
97  return !(point1 == point2);
98 }
99 
100 using CPoint = CPointGen<float>;
101 using CPointInt = CPointGen<int>;
102 
103 
112 template <typename T> class CSizeGen
113 {
114  T m_w{}, m_h{};
115 
116  void CheckSet(T width, T height)
117  {
118  if (width < 0)
119  {
120  throw std::out_of_range("Size may not have negative width");
121  }
122  if (height < 0)
123  {
124  throw std::out_of_range("Size may not have negative height");
125  }
126  m_w = width;
127  m_h = height;
128  }
129 
130 public:
131  typedef CSizeGen<T> this_type;
132 
133  CSizeGen() noexcept = default;
134 
135  CSizeGen(T width, T height)
136  {
137  CheckSet(width, height);
138  }
139 
140  T Width() const
141  {
142  return m_w;
143  }
144 
145  T Height() const
146  {
147  return m_h;
148  }
149 
150  void SetWidth(T width)
151  {
152  CheckSet(width, m_h);
153  }
154 
155  void SetHeight(T height)
156  {
157  CheckSet(m_w, height);
158  }
159 
160  void Set(T width, T height)
161  {
162  CheckSet(width, height);
163  }
164 
165  bool IsZero() const
166  {
167  return (m_w == static_cast<T> (0) && m_h == static_cast<T> (0));
168  }
169 
170  T Area() const
171  {
172  return m_w * m_h;
173  }
174 
175  CPointGen<T> ToPoint() const
176  {
177  return {m_w, m_h};
178  }
179 
180  template<class U> explicit CSizeGen<T>(const CSizeGen<U>& rhs)
181  {
182  CheckSet(static_cast<T> (rhs.m_w), static_cast<T> (rhs.m_h));
183  }
184 
185  this_type operator+(const this_type& size) const
186  {
187  return {m_w + size.m_w, m_h + size.m_h};
188  };
189 
190  this_type& operator+=(const this_type& size)
191  {
192  CheckSet(m_w + size.m_w, m_h + size.m_h);
193  return *this;
194  };
195 
196  this_type operator-(const this_type& size) const
197  {
198  return {m_w - size.m_w, m_h - size.m_h};
199  };
200 
201  this_type& operator-=(const this_type& size)
202  {
203  CheckSet(m_w - size.m_w, m_h - size.m_h);
204  return *this;
205  };
206 
207  this_type operator*(T factor) const
208  {
209  return {m_w * factor, m_h * factor};
210  }
211 
212  this_type& operator*=(T factor)
213  {
214  CheckSet(m_w * factor, m_h * factor);
215  return *this;
216  }
217 
218  this_type operator/(T factor) const
219  {
220  return {m_w / factor, m_h / factor};
221  }
222 
223  this_type& operator/=(T factor)
224  {
225  CheckSet(m_w / factor, m_h / factor);
226  return *this;
227  }
228 };
229 
230 template<typename T>
231 inline bool operator==(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
232 {
233  return (size1.Width() == size2.Width() && size1.Height() == size2.Height());
234 }
235 
236 template<typename T>
237 inline bool operator!=(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
238 {
239  return !(size1 == size2);
240 }
241 
242 using CSize = CSizeGen<float>;
243 using CSizeInt = CSizeGen<int>;
244 
245 
246 template <typename T> class CRectGen
247 {
248 public:
249  typedef CRectGen<T> this_type;
250  typedef CPointGen<T> point_type;
251  typedef CSizeGen<T> size_type;
252 
253  CRectGen() noexcept = default;
254 
255  constexpr CRectGen(T left, T top, T right, T bottom)
256  : x1{left}, y1{top}, x2{right}, y2{bottom}
257  {}
258 
259  constexpr CRectGen(const point_type &p1, const point_type &p2)
260  : x1{p1.x}, y1{p1.y}, x2{p2.x}, y2{p2.y}
261  {}
262 
263  constexpr CRectGen(const point_type &origin, const size_type &size)
264  : x1{origin.x}, y1{origin.y}, x2{x1 + size.Width()}, y2{y1 + size.Height()}
265  {}
266 
267  template<class U> explicit constexpr CRectGen(const CRectGen<U>& rhs)
268  : x1{static_cast<T> (rhs.x1)}, y1{static_cast<T> (rhs.y1)}, x2{static_cast<T> (rhs.x2)}, y2{static_cast<T> (rhs.y2)}
269  {}
270 
271  void SetRect(T left, T top, T right, T bottom)
272  {
273  x1 = left;
274  y1 = top;
275  x2 = right;
276  y2 = bottom;
277  }
278 
279  constexpr bool PtInRect(const point_type &point) const
280  {
281  return (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2);
282  };
283 
284  constexpr bool Intersects(const this_type& rect) const
285  {
286  return (x1 < rect.x2 && x2 > rect.x1 && y1 < rect.y2 && y2 > rect.y1);
287  };
288 
289  this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE
290  {
291  x1 -= point.x;
292  y1 -= point.y;
293  x2 -= point.x;
294  y2 -= point.y;
295  return *this;
296  };
297 
298  constexpr this_type operator-(const point_type &point) const
299  {
300  return {x1 - point.x, y1 - point.y, x2 - point.x, y2 - point.y};
301  }
302 
303  this_type& operator+=(const point_type &point) XBMC_FORCE_INLINE
304  {
305  x1 += point.x;
306  y1 += point.y;
307  x2 += point.x;
308  y2 += point.y;
309  return *this;
310  };
311 
312  constexpr this_type operator+(const point_type &point) const
313  {
314  return {x1 + point.x, y1 + point.y, x2 + point.x, y2 + point.y};
315  }
316 
317  this_type& operator-=(const size_type &size)
318  {
319  x2 -= size.Width();
320  y2 -= size.Height();
321  return *this;
322  };
323 
324  constexpr this_type operator-(const size_type &size) const
325  {
326  return {x1, y1, x2 - size.Width(), y2 - size.Height()};
327  }
328 
329  this_type& operator+=(const size_type &size)
330  {
331  x2 += size.Width();
332  y2 += size.Height();
333  return *this;
334  };
335 
336  constexpr this_type operator+(const size_type &size) const
337  {
338  return {x1, y1, x2 + size.Width(), y2 + size.Height()};
339  }
340 
341  this_type& Intersect(const this_type &rect)
342  {
343  x1 = clamp_range(x1, rect.x1, rect.x2);
344  x2 = clamp_range(x2, rect.x1, rect.x2);
345  y1 = clamp_range(y1, rect.y1, rect.y2);
346  y2 = clamp_range(y2, rect.y1, rect.y2);
347  return *this;
348  };
349 
350  this_type& Union(const this_type &rect)
351  {
352  if (IsEmpty())
353  *this = rect;
354  else if (!rect.IsEmpty())
355  {
356  x1 = std::min(x1,rect.x1);
357  y1 = std::min(y1,rect.y1);
358 
359  x2 = std::max(x2,rect.x2);
360  y2 = std::max(y2,rect.y2);
361  }
362 
363  return *this;
364  };
365 
366  constexpr bool IsEmpty() const XBMC_FORCE_INLINE
367  {
368  return (x2 - x1) * (y2 - y1) == 0;
369  };
370 
371  constexpr point_type P1() const XBMC_FORCE_INLINE
372  {
373  return {x1, y1};
374  }
375 
376  constexpr point_type P2() const XBMC_FORCE_INLINE
377  {
378  return {x2, y2};
379  }
380 
381  constexpr T Width() const XBMC_FORCE_INLINE
382  {
383  return x2 - x1;
384  };
385 
386  constexpr T Height() const XBMC_FORCE_INLINE
387  {
388  return y2 - y1;
389  };
390 
391  constexpr T Area() const XBMC_FORCE_INLINE
392  {
393  return Width() * Height();
394  };
395 
396  size_type ToSize() const
397  {
398  return {Width(), Height()};
399  };
400 
401  std::vector<this_type> SubtractRect(this_type splitterRect)
402  {
403  std::vector<this_type> newRectanglesList;
404  this_type intersection = splitterRect.Intersect(*this);
405 
406  if (!intersection.IsEmpty())
407  {
408  this_type add;
409 
410  // add rect above intersection if not empty
411  add = this_type(x1, y1, x2, intersection.y1);
412  if (!add.IsEmpty())
413  newRectanglesList.push_back(add);
414 
415  // add rect below intersection if not empty
416  add = this_type(x1, intersection.y2, x2, y2);
417  if (!add.IsEmpty())
418  newRectanglesList.push_back(add);
419 
420  // add rect left intersection if not empty
421  add = this_type(x1, intersection.y1, intersection.x1, intersection.y2);
422  if (!add.IsEmpty())
423  newRectanglesList.push_back(add);
424 
425  // add rect right intersection if not empty
426  add = this_type(intersection.x2, intersection.y1, x2, intersection.y2);
427  if (!add.IsEmpty())
428  newRectanglesList.push_back(add);
429  }
430  else
431  {
432  newRectanglesList.push_back(*this);
433  }
434 
435  return newRectanglesList;
436  }
437 
438  std::vector<this_type> SubtractRects(const std::vector<this_type>& intersectionList)
439  {
440  std::vector<this_type> fragmentsList;
441  fragmentsList.push_back(*this);
442 
443  for (typename std::vector<this_type>::iterator splitter = intersectionList.begin(); splitter != intersectionList.end(); ++splitter)
444  {
445  typename std::vector<this_type> toAddList;
446 
447  for (typename std::vector<this_type>::iterator fragment = fragmentsList.begin(); fragment != fragmentsList.end(); ++fragment)
448  {
449  std::vector<this_type> newFragmentsList = fragment->SubtractRect(*splitter);
450  toAddList.insert(toAddList.end(), newFragmentsList.begin(), newFragmentsList.end());
451  }
452 
453  fragmentsList.clear();
454  fragmentsList.insert(fragmentsList.end(), toAddList.begin(), toAddList.end());
455  }
456 
457  return fragmentsList;
458  }
459 
460  void GetQuad(point_type (&points)[4])
461  {
462  points[0] = { x1, y1 };
463  points[1] = { x2, y1 };
464  points[2] = { x2, y2 };
465  points[3] = { x1, y2 };
466  }
467 
468  T x1{}, y1{}, x2{}, y2{};
469 private:
470  static constexpr T clamp_range(T x, T l, T h) XBMC_FORCE_INLINE
471  {
472  return (x > h) ? h : ((x < l) ? l : x);
473  }
474 };
475 
476 template<typename T>
477 constexpr bool operator==(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
478 {
479  return (rect1.x1 == rect2.x1 && rect1.y1 == rect2.y1 && rect1.x2 == rect2.x2 && rect1.y2 == rect2.y2);
480 }
481 
482 template<typename T>
483 constexpr bool operator!=(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
484 {
485  return !(rect1 == rect2);
486 }
487 
488 using CRect = CRectGen<float>;
489 using CRectInt = CRectGen<int>;
Definition: StreamInfo.h:15
Definition: Geometry.h:22
Generic two-dimensional size representation.
Definition: Geometry.h:112