summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/Geometry.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/Geometry.h')
-rw-r--r--xbmc/utils/Geometry.h484
1 files changed, 484 insertions, 0 deletions
diff --git a/xbmc/utils/Geometry.h b/xbmc/utils/Geometry.h
new file mode 100644
index 0000000..878905b
--- /dev/null
+++ b/xbmc/utils/Geometry.h
@@ -0,0 +1,484 @@
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
22template <typename T> class CPointGen
23{
24public:
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
88template<typename T>
89constexpr bool operator==(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
90{
91 return (point1.x == point2.x && point1.y == point2.y);
92}
93
94template<typename T>
95constexpr bool operator!=(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
96{
97 return !(point1 == point2);
98}
99
100using CPoint = CPointGen<float>;
101using CPointInt = CPointGen<int>;
102
103
104/**
105 * Generic two-dimensional size representation
106 *
107 * Class invariant: width and height are both non-negative
108 * Throws std::out_of_range if invariant would be violated. The class
109 * is exception-safe. If modification would violate the invariant, the size
110 * is not changed.
111 */
112template <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
130public:
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
230template<typename T>
231inline bool operator==(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
232{
233 return (size1.Width() == size2.Width() && size1.Height() == size2.Height());
234}
235
236template<typename T>
237inline bool operator!=(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
238{
239 return !(size1 == size2);
240}
241
242using CSize = CSizeGen<float>;
243using CSizeInt = CSizeGen<int>;
244
245
246template <typename T> class CRectGen
247{
248public:
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 this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE
285 {
286 x1 -= point.x;
287 y1 -= point.y;
288 x2 -= point.x;
289 y2 -= point.y;
290 return *this;
291 };
292
293 constexpr this_type operator-(const point_type &point) const
294 {
295 return {x1 - point.x, y1 - point.y, x2 - point.x, y2 - point.y};
296 }
297
298 this_type& operator+=(const point_type &point) XBMC_FORCE_INLINE
299 {
300 x1 += point.x;
301 y1 += point.y;
302 x2 += point.x;
303 y2 += point.y;
304 return *this;
305 };
306
307 constexpr this_type operator+(const point_type &point) const
308 {
309 return {x1 + point.x, y1 + point.y, x2 + point.x, y2 + point.y};
310 }
311
312 this_type& operator-=(const size_type &size)
313 {
314 x2 -= size.Width();
315 y2 -= size.Height();
316 return *this;
317 };
318
319 constexpr this_type operator-(const size_type &size) const
320 {
321 return {x1, y1, x2 - size.Width(), y2 - size.Height()};
322 }
323
324 this_type& operator+=(const size_type &size)
325 {
326 x2 += size.Width();
327 y2 += size.Height();
328 return *this;
329 };
330
331 constexpr this_type operator+(const size_type &size) const
332 {
333 return {x1, y1, x2 + size.Width(), y2 + size.Height()};
334 }
335
336 this_type& Intersect(const this_type &rect)
337 {
338 x1 = clamp_range(x1, rect.x1, rect.x2);
339 x2 = clamp_range(x2, rect.x1, rect.x2);
340 y1 = clamp_range(y1, rect.y1, rect.y2);
341 y2 = clamp_range(y2, rect.y1, rect.y2);
342 return *this;
343 };
344
345 this_type& Union(const this_type &rect)
346 {
347 if (IsEmpty())
348 *this = rect;
349 else if (!rect.IsEmpty())
350 {
351 x1 = std::min(x1,rect.x1);
352 y1 = std::min(y1,rect.y1);
353
354 x2 = std::max(x2,rect.x2);
355 y2 = std::max(y2,rect.y2);
356 }
357
358 return *this;
359 };
360
361 constexpr bool IsEmpty() const XBMC_FORCE_INLINE
362 {
363 return (x2 - x1) * (y2 - y1) == 0;
364 };
365
366 constexpr point_type P1() const XBMC_FORCE_INLINE
367 {
368 return {x1, y1};
369 }
370
371 constexpr point_type P2() const XBMC_FORCE_INLINE
372 {
373 return {x2, y2};
374 }
375
376 constexpr T Width() const XBMC_FORCE_INLINE
377 {
378 return x2 - x1;
379 };
380
381 constexpr T Height() const XBMC_FORCE_INLINE
382 {
383 return y2 - y1;
384 };
385
386 constexpr T Area() const XBMC_FORCE_INLINE
387 {
388 return Width() * Height();
389 };
390
391 size_type ToSize() const
392 {
393 return {Width(), Height()};
394 };
395
396 std::vector<this_type> SubtractRect(this_type splitterRect)
397 {
398 std::vector<this_type> newRectanglesList;
399 this_type intersection = splitterRect.Intersect(*this);
400
401 if (!intersection.IsEmpty())
402 {
403 this_type add;
404
405 // add rect above intersection if not empty
406 add = this_type(x1, y1, x2, intersection.y1);
407 if (!add.IsEmpty())
408 newRectanglesList.push_back(add);
409
410 // add rect below intersection if not empty
411 add = this_type(x1, intersection.y2, x2, y2);
412 if (!add.IsEmpty())
413 newRectanglesList.push_back(add);
414
415 // add rect left intersection if not empty
416 add = this_type(x1, intersection.y1, intersection.x1, intersection.y2);
417 if (!add.IsEmpty())
418 newRectanglesList.push_back(add);
419
420 // add rect right intersection if not empty
421 add = this_type(intersection.x2, intersection.y1, x2, intersection.y2);
422 if (!add.IsEmpty())
423 newRectanglesList.push_back(add);
424 }
425 else
426 {
427 newRectanglesList.push_back(*this);
428 }
429
430 return newRectanglesList;
431 }
432
433 std::vector<this_type> SubtractRects(std::vector<this_type> intersectionList)
434 {
435 std::vector<this_type> fragmentsList;
436 fragmentsList.push_back(*this);
437
438 for (typename std::vector<this_type>::iterator splitter = intersectionList.begin(); splitter != intersectionList.end(); ++splitter)
439 {
440 typename std::vector<this_type> toAddList;
441
442 for (typename std::vector<this_type>::iterator fragment = fragmentsList.begin(); fragment != fragmentsList.end(); ++fragment)
443 {
444 std::vector<this_type> newFragmentsList = fragment->SubtractRect(*splitter);
445 toAddList.insert(toAddList.end(), newFragmentsList.begin(), newFragmentsList.end());
446 }
447
448 fragmentsList.clear();
449 fragmentsList.insert(fragmentsList.end(), toAddList.begin(), toAddList.end());
450 }
451
452 return fragmentsList;
453 }
454
455 void GetQuad(point_type (&points)[4])
456 {
457 points[0] = { x1, y1 };
458 points[1] = { x2, y1 };
459 points[2] = { x2, y2 };
460 points[3] = { x1, y2 };
461 }
462
463 T x1{}, y1{}, x2{}, y2{};
464private:
465 static constexpr T clamp_range(T x, T l, T h) XBMC_FORCE_INLINE
466 {
467 return (x > h) ? h : ((x < l) ? l : x);
468 }
469};
470
471template<typename T>
472constexpr bool operator==(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
473{
474 return (rect1.x1 == rect2.x1 && rect1.y1 == rect2.y1 && rect1.x2 == rect2.x2 && rect1.y2 == rect2.y2);
475}
476
477template<typename T>
478constexpr bool operator!=(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
479{
480 return !(rect1 == rect2);
481}
482
483using CRect = CRectGen<float>;
484using CRectInt = CRectGen<int>;