// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef FLUTTER_IMPELLER_GEOMETRY_POINT_H_ #define FLUTTER_IMPELLER_GEOMETRY_POINT_H_ #include #include #include #include #include #include #include "impeller/geometry/scalar.h" #include "impeller/geometry/size.h" #include "impeller/geometry/type_traits.h" namespace impeller { #define ONLY_ON_FLOAT_M(Modifiers, Return) \ template \ Modifiers std::enable_if_t, Return> #define ONLY_ON_FLOAT(Return) DL_ONLY_ON_FLOAT_M(, Return) template struct TPoint { using Type = T; Type x = {}; Type y = {}; constexpr TPoint() = default; template explicit constexpr TPoint(const TPoint& other) : TPoint(static_cast(other.x), static_cast(other.y)) {} template explicit constexpr TPoint(const TSize& other) : TPoint(static_cast(other.width), static_cast(other.height)) {} constexpr TPoint(Type x, Type y) : x(x), y(y) {} static constexpr TPoint MakeXY(Type x, Type y) { return {x, y}; } template static constexpr TPoint Round(const TPoint& other) { return TPoint{static_cast(std::round(other.x)), static_cast(std::round(other.y))}; } constexpr bool operator==(const TPoint& p) const { return p.x == x && p.y == y; } constexpr bool operator!=(const TPoint& p) const { return p.x != x || p.y != y; } template inline TPoint operator+=(const TPoint& p) { x += static_cast(p.x); y += static_cast(p.y); return *this; } template inline TPoint operator+=(const TSize& s) { x += static_cast(s.width); y += static_cast(s.height); return *this; } template inline TPoint operator-=(const TPoint& p) { x -= static_cast(p.x); y -= static_cast(p.y); return *this; } template inline TPoint operator-=(const TSize& s) { x -= static_cast(s.width); y -= static_cast(s.height); return *this; } template inline TPoint operator*=(const TPoint& p) { x *= static_cast(p.x); y *= static_cast(p.y); return *this; } template inline TPoint operator*=(const TSize& s) { x *= static_cast(s.width); y *= static_cast(s.height); return *this; } template >> inline TPoint operator*=(U scale) { x *= static_cast(scale); y *= static_cast(scale); return *this; } template inline TPoint operator/=(const TPoint& p) { x /= static_cast(p.x); y /= static_cast(p.y); return *this; } template inline TPoint operator/=(const TSize& s) { x /= static_cast(s.width); y /= static_cast(s.height); return *this; } template >> inline TPoint operator/=(U scale) { x /= static_cast(scale); y /= static_cast(scale); return *this; } constexpr TPoint operator-() const { return {-x, -y}; } constexpr TPoint operator+(const TPoint& p) const { return {x + p.x, y + p.y}; } template constexpr TPoint operator+(const TSize& s) const { return {x + static_cast(s.width), y + static_cast(s.height)}; } constexpr TPoint operator-(const TPoint& p) const { return {x - p.x, y - p.y}; } template constexpr TPoint operator-(const TSize& s) const { return {x - static_cast(s.width), y - static_cast(s.height)}; } template >> constexpr TPoint operator*(U scale) const { return {static_cast(x * scale), static_cast(y * scale)}; } constexpr TPoint operator*(const TPoint& p) const { return {x * p.x, y * p.y}; } template constexpr TPoint operator*(const TSize& s) const { return {x * static_cast(s.width), y * static_cast(s.height)}; } template >> constexpr TPoint operator/(U d) const { return {static_cast(x / d), static_cast(y / d)}; } constexpr TPoint operator/(const TPoint& p) const { return {x / p.x, y / p.y}; } template constexpr TPoint operator/(const TSize& s) const { return {x / static_cast(s.width), y / static_cast(s.height)}; } constexpr Type GetDistanceSquared(const TPoint& p) const { double dx = p.x - x; double dy = p.y - y; return dx * dx + dy * dy; } constexpr TPoint Min(const TPoint& p) const { return {std::min(x, p.x), std::min(y, p.y)}; } constexpr TPoint Max(const TPoint& p) const { return {std::max(x, p.x), std::max(y, p.y)}; } constexpr TPoint Floor() const { return {std::floor(x), std::floor(y)}; } constexpr TPoint Ceil() const { return {std::ceil(x), std::ceil(y)}; } constexpr TPoint Round() const { return {std::round(x), std::round(y)}; } constexpr Type GetDistance(const TPoint& p) const { return sqrt(GetDistanceSquared(p)); } constexpr Type GetLengthSquared() const { return GetDistanceSquared({}); } constexpr Type GetLength() const { return GetDistance({}); } constexpr TPoint Normalize() const { const auto length = GetLength(); if (length == 0) { return {1, 0}; } return {x / length, y / length}; } constexpr TPoint Abs() const { return {std::fabs(x), std::fabs(y)}; } constexpr Type Cross(const TPoint& p) const { return (x * p.y) - (y * p.x); } constexpr Type Dot(const TPoint& p) const { return (x * p.x) + (y * p.y); } constexpr TPoint Reflect(const TPoint& axis) const { return *this - axis * this->Dot(axis) * 2; } constexpr TPoint Rotate(const Radians& angle) const { const auto cos_a = std::cosf(angle.radians); const auto sin_a = std::sinf(angle.radians); return {x * cos_a - y * sin_a, x * sin_a + y * cos_a}; } constexpr Radians AngleTo(const TPoint& p) const { return Radians{std::atan2(this->Cross(p), this->Dot(p))}; } constexpr TPoint Lerp(const TPoint& p, Scalar t) const { return *this + (p - *this) * t; } constexpr bool IsZero() const { return x == 0 && y == 0; } ONLY_ON_FLOAT_M(constexpr, bool) IsFinite() const { return std::isfinite(x) && std::isfinite(y); } }; // Specializations for mixed (float & integer) algebraic operations. template > constexpr TPoint operator+(const TPoint& p1, const TPoint& p2) { return {p1.x + static_cast(p2.x), p1.y + static_cast(p2.y)}; } template > constexpr TPoint operator+(const TPoint& p1, const TPoint& p2) { return p2 + p1; } template > constexpr TPoint operator-(const TPoint& p1, const TPoint& p2) { return {p1.x - static_cast(p2.x), p1.y - static_cast(p2.y)}; } template > constexpr TPoint operator-(const TPoint& p1, const TPoint& p2) { return {static_cast(p1.x) - p2.x, static_cast(p1.y) - p2.y}; } template > constexpr TPoint operator*(const TPoint& p1, const TPoint& p2) { return {p1.x * static_cast(p2.x), p1.y * static_cast(p2.y)}; } template > constexpr TPoint operator*(const TPoint& p1, const TPoint& p2) { return p2 * p1; } template > constexpr TPoint operator/(const TPoint& p1, const TPoint& p2) { return {p1.x / static_cast(p2.x), p1.y / static_cast(p2.y)}; } template > constexpr TPoint operator/(const TPoint& p1, const TPoint& p2) { return {static_cast(p1.x) / p2.x, static_cast(p1.y) / p2.y}; } // RHS algebraic operations with arithmetic types. template >> constexpr TPoint operator*(U s, const TPoint& p) { return p * s; } template >> constexpr TPoint operator/(U s, const TPoint& p) { return {static_cast(s) / p.x, static_cast(s) / p.y}; } // RHS algebraic operations with TSize. template constexpr TPoint operator+(const TSize& s, const TPoint& p) { return p + s; } template constexpr TPoint operator-(const TSize& s, const TPoint& p) { return {static_cast(s.width) - p.x, static_cast(s.height) - p.y}; } template constexpr TPoint operator*(const TSize& s, const TPoint& p) { return p * s; } template constexpr TPoint operator/(const TSize& s, const TPoint& p) { return {static_cast(s.width) / p.x, static_cast(s.height) / p.y}; } template constexpr TPoint operator-(const TPoint& p, T v) { return {p.x - v, p.y - v}; } using Point = TPoint; using IPoint = TPoint; using IPoint32 = TPoint; using UintPoint32 = TPoint; using Vector2 = Point; using Quad = std::array; #undef ONLY_ON_FLOAT #undef ONLY_ON_FLOAT_M } // namespace impeller namespace std { template inline std::ostream& operator<<(std::ostream& out, const impeller::TPoint& p) { out << "(" << p.x << ", " << p.y << ")"; return out; } } // namespace std #endif // FLUTTER_IMPELLER_GEOMETRY_POINT_H_