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 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#ifdef __GNUC__
+// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations.
+#define XBMC_FORCE_INLINE __attribute__((always_inline))
+#else
+#define XBMC_FORCE_INLINE
+#endif
+
+#include <algorithm>
+#include <stdexcept>
+#include <vector>
+
+template <typename T> class CPointGen
+{
+public:
+ typedef CPointGen<T> this_type;
+
+ CPointGen() noexcept = default;
+
+ constexpr CPointGen(T a, T b)
+ : x{a}, y{b}
+ {}
+
+ template<class U> explicit constexpr CPointGen(const CPointGen<U>& rhs)
+ : x{static_cast<T> (rhs.x)}, y{static_cast<T> (rhs.y)}
+ {}
+
+ constexpr this_type operator+(const this_type &point) const
+ {
+ return {x + point.x, y + point.y};
+ };
+
+ this_type& operator+=(const this_type &point)
+ {
+ x += point.x;
+ y += point.y;
+ return *this;
+ };
+
+ constexpr this_type operator-(const this_type &point) const
+ {
+ return {x - point.x, y - point.y};
+ };
+
+ this_type& operator-=(const this_type &point)
+ {
+ x -= point.x;
+ y -= point.y;
+ return *this;
+ };
+
+ constexpr this_type operator*(T factor) const
+ {
+ return {x * factor, y * factor};
+ }
+
+ this_type& operator*=(T factor)
+ {
+ x *= factor;
+ y *= factor;
+ return *this;
+ }
+
+ constexpr this_type operator/(T factor) const
+ {
+ return {x / factor, y / factor};
+ }
+
+ this_type& operator/=(T factor)
+ {
+ x /= factor;
+ y /= factor;
+ return *this;
+ }
+
+ T x{}, y{};
+};
+
+template<typename T>
+constexpr bool operator==(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
+{
+ return (point1.x == point2.x && point1.y == point2.y);
+}
+
+template<typename T>
+constexpr bool operator!=(const CPointGen<T> &point1, const CPointGen<T> &point2) noexcept
+{
+ return !(point1 == point2);
+}
+
+using CPoint = CPointGen<float>;
+using CPointInt = CPointGen<int>;
+
+
+/**
+ * Generic two-dimensional size representation
+ *
+ * Class invariant: width and height are both non-negative
+ * Throws std::out_of_range if invariant would be violated. The class
+ * is exception-safe. If modification would violate the invariant, the size
+ * is not changed.
+ */
+template <typename T> class CSizeGen
+{
+ T m_w{}, m_h{};
+
+ void CheckSet(T width, T height)
+ {
+ if (width < 0)
+ {
+ throw std::out_of_range("Size may not have negative width");
+ }
+ if (height < 0)
+ {
+ throw std::out_of_range("Size may not have negative height");
+ }
+ m_w = width;
+ m_h = height;
+ }
+
+public:
+ typedef CSizeGen<T> this_type;
+
+ CSizeGen() noexcept = default;
+
+ CSizeGen(T width, T height)
+ {
+ CheckSet(width, height);
+ }
+
+ T Width() const
+ {
+ return m_w;
+ }
+
+ T Height() const
+ {
+ return m_h;
+ }
+
+ void SetWidth(T width)
+ {
+ CheckSet(width, m_h);
+ }
+
+ void SetHeight(T height)
+ {
+ CheckSet(m_w, height);
+ }
+
+ void Set(T width, T height)
+ {
+ CheckSet(width, height);
+ }
+
+ bool IsZero() const
+ {
+ return (m_w == static_cast<T> (0) && m_h == static_cast<T> (0));
+ }
+
+ T Area() const
+ {
+ return m_w * m_h;
+ }
+
+ CPointGen<T> ToPoint() const
+ {
+ return {m_w, m_h};
+ }
+
+ template<class U> explicit CSizeGen<T>(const CSizeGen<U>& rhs)
+ {
+ CheckSet(static_cast<T> (rhs.m_w), static_cast<T> (rhs.m_h));
+ }
+
+ this_type operator+(const this_type& size) const
+ {
+ return {m_w + size.m_w, m_h + size.m_h};
+ };
+
+ this_type& operator+=(const this_type& size)
+ {
+ CheckSet(m_w + size.m_w, m_h + size.m_h);
+ return *this;
+ };
+
+ this_type operator-(const this_type& size) const
+ {
+ return {m_w - size.m_w, m_h - size.m_h};
+ };
+
+ this_type& operator-=(const this_type& size)
+ {
+ CheckSet(m_w - size.m_w, m_h - size.m_h);
+ return *this;
+ };
+
+ this_type operator*(T factor) const
+ {
+ return {m_w * factor, m_h * factor};
+ }
+
+ this_type& operator*=(T factor)
+ {
+ CheckSet(m_w * factor, m_h * factor);
+ return *this;
+ }
+
+ this_type operator/(T factor) const
+ {
+ return {m_w / factor, m_h / factor};
+ }
+
+ this_type& operator/=(T factor)
+ {
+ CheckSet(m_w / factor, m_h / factor);
+ return *this;
+ }
+};
+
+template<typename T>
+inline bool operator==(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
+{
+ return (size1.Width() == size2.Width() && size1.Height() == size2.Height());
+}
+
+template<typename T>
+inline bool operator!=(const CSizeGen<T>& size1, const CSizeGen<T>& size2) noexcept
+{
+ return !(size1 == size2);
+}
+
+using CSize = CSizeGen<float>;
+using CSizeInt = CSizeGen<int>;
+
+
+template <typename T> class CRectGen
+{
+public:
+ typedef CRectGen<T> this_type;
+ typedef CPointGen<T> point_type;
+ typedef CSizeGen<T> size_type;
+
+ CRectGen() noexcept = default;
+
+ constexpr CRectGen(T left, T top, T right, T bottom)
+ : x1{left}, y1{top}, x2{right}, y2{bottom}
+ {}
+
+ constexpr CRectGen(const point_type &p1, const point_type &p2)
+ : x1{p1.x}, y1{p1.y}, x2{p2.x}, y2{p2.y}
+ {}
+
+ constexpr CRectGen(const point_type &origin, const size_type &size)
+ : x1{origin.x}, y1{origin.y}, x2{x1 + size.Width()}, y2{y1 + size.Height()}
+ {}
+
+ template<class U> explicit constexpr CRectGen(const CRectGen<U>& rhs)
+ : x1{static_cast<T> (rhs.x1)}, y1{static_cast<T> (rhs.y1)}, x2{static_cast<T> (rhs.x2)}, y2{static_cast<T> (rhs.y2)}
+ {}
+
+ void SetRect(T left, T top, T right, T bottom)
+ {
+ x1 = left;
+ y1 = top;
+ x2 = right;
+ y2 = bottom;
+ }
+
+ constexpr bool PtInRect(const point_type &point) const
+ {
+ return (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2);
+ };
+
+ this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE
+ {
+ x1 -= point.x;
+ y1 -= point.y;
+ x2 -= point.x;
+ y2 -= point.y;
+ return *this;
+ };
+
+ constexpr this_type operator-(const point_type &point) const
+ {
+ return {x1 - point.x, y1 - point.y, x2 - point.x, y2 - point.y};
+ }
+
+ this_type& operator+=(const point_type &point) XBMC_FORCE_INLINE
+ {
+ x1 += point.x;
+ y1 += point.y;
+ x2 += point.x;
+ y2 += point.y;
+ return *this;
+ };
+
+ constexpr this_type operator+(const point_type &point) const
+ {
+ return {x1 + point.x, y1 + point.y, x2 + point.x, y2 + point.y};
+ }
+
+ this_type& operator-=(const size_type &size)
+ {
+ x2 -= size.Width();
+ y2 -= size.Height();
+ return *this;
+ };
+
+ constexpr this_type operator-(const size_type &size) const
+ {
+ return {x1, y1, x2 - size.Width(), y2 - size.Height()};
+ }
+
+ this_type& operator+=(const size_type &size)
+ {
+ x2 += size.Width();
+ y2 += size.Height();
+ return *this;
+ };
+
+ constexpr this_type operator+(const size_type &size) const
+ {
+ return {x1, y1, x2 + size.Width(), y2 + size.Height()};
+ }
+
+ this_type& Intersect(const this_type &rect)
+ {
+ x1 = clamp_range(x1, rect.x1, rect.x2);
+ x2 = clamp_range(x2, rect.x1, rect.x2);
+ y1 = clamp_range(y1, rect.y1, rect.y2);
+ y2 = clamp_range(y2, rect.y1, rect.y2);
+ return *this;
+ };
+
+ this_type& Union(const this_type &rect)
+ {
+ if (IsEmpty())
+ *this = rect;
+ else if (!rect.IsEmpty())
+ {
+ x1 = std::min(x1,rect.x1);
+ y1 = std::min(y1,rect.y1);
+
+ x2 = std::max(x2,rect.x2);
+ y2 = std::max(y2,rect.y2);
+ }
+
+ return *this;
+ };
+
+ constexpr bool IsEmpty() const XBMC_FORCE_INLINE
+ {
+ return (x2 - x1) * (y2 - y1) == 0;
+ };
+
+ constexpr point_type P1() const XBMC_FORCE_INLINE
+ {
+ return {x1, y1};
+ }
+
+ constexpr point_type P2() const XBMC_FORCE_INLINE
+ {
+ return {x2, y2};
+ }
+
+ constexpr T Width() const XBMC_FORCE_INLINE
+ {
+ return x2 - x1;
+ };
+
+ constexpr T Height() const XBMC_FORCE_INLINE
+ {
+ return y2 - y1;
+ };
+
+ constexpr T Area() const XBMC_FORCE_INLINE
+ {
+ return Width() * Height();
+ };
+
+ size_type ToSize() const
+ {
+ return {Width(), Height()};
+ };
+
+ std::vector<this_type> SubtractRect(this_type splitterRect)
+ {
+ std::vector<this_type> newRectanglesList;
+ this_type intersection = splitterRect.Intersect(*this);
+
+ if (!intersection.IsEmpty())
+ {
+ this_type add;
+
+ // add rect above intersection if not empty
+ add = this_type(x1, y1, x2, intersection.y1);
+ if (!add.IsEmpty())
+ newRectanglesList.push_back(add);
+
+ // add rect below intersection if not empty
+ add = this_type(x1, intersection.y2, x2, y2);
+ if (!add.IsEmpty())
+ newRectanglesList.push_back(add);
+
+ // add rect left intersection if not empty
+ add = this_type(x1, intersection.y1, intersection.x1, intersection.y2);
+ if (!add.IsEmpty())
+ newRectanglesList.push_back(add);
+
+ // add rect right intersection if not empty
+ add = this_type(intersection.x2, intersection.y1, x2, intersection.y2);
+ if (!add.IsEmpty())
+ newRectanglesList.push_back(add);
+ }
+ else
+ {
+ newRectanglesList.push_back(*this);
+ }
+
+ return newRectanglesList;
+ }
+
+ std::vector<this_type> SubtractRects(std::vector<this_type> intersectionList)
+ {
+ std::vector<this_type> fragmentsList;
+ fragmentsList.push_back(*this);
+
+ for (typename std::vector<this_type>::iterator splitter = intersectionList.begin(); splitter != intersectionList.end(); ++splitter)
+ {
+ typename std::vector<this_type> toAddList;
+
+ for (typename std::vector<this_type>::iterator fragment = fragmentsList.begin(); fragment != fragmentsList.end(); ++fragment)
+ {
+ std::vector<this_type> newFragmentsList = fragment->SubtractRect(*splitter);
+ toAddList.insert(toAddList.end(), newFragmentsList.begin(), newFragmentsList.end());
+ }
+
+ fragmentsList.clear();
+ fragmentsList.insert(fragmentsList.end(), toAddList.begin(), toAddList.end());
+ }
+
+ return fragmentsList;
+ }
+
+ void GetQuad(point_type (&points)[4])
+ {
+ points[0] = { x1, y1 };
+ points[1] = { x2, y1 };
+ points[2] = { x2, y2 };
+ points[3] = { x1, y2 };
+ }
+
+ T x1{}, y1{}, x2{}, y2{};
+private:
+ static constexpr T clamp_range(T x, T l, T h) XBMC_FORCE_INLINE
+ {
+ return (x > h) ? h : ((x < l) ? l : x);
+ }
+};
+
+template<typename T>
+constexpr bool operator==(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
+{
+ return (rect1.x1 == rect2.x1 && rect1.y1 == rect2.y1 && rect1.x2 == rect2.x2 && rect1.y2 == rect2.y2);
+}
+
+template<typename T>
+constexpr bool operator!=(const CRectGen<T> &rect1, const CRectGen<T> &rect2) noexcept
+{
+ return !(rect1 == rect2);
+}
+
+using CRect = CRectGen<float>;
+using CRectInt = CRectGen<int>;