diff --git a/Source/Engine/Core/Math/Double2.cpp b/Source/Engine/Core/Math/Double2.cpp new file mode 100644 index 000000000..4aa16249f --- /dev/null +++ b/Source/Engine/Core/Math/Double2.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "Double2.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" +#include "Color.h" +#include "Int2.h" +#include "Int3.h" +#include "Int4.h" +#include "../Types/String.h" + +static_assert(sizeof(Double2) == 16, "Invalid Double2 type size."); + +const Double2 Double2::Zero(0); +const Double2 Double2::One(1); +const Double2 Double2::UnitX(1, 0); +const Double2 Double2::UnitY(0, 1); +const Double2 Double2::Minimum(MIN_double); +const Double2 Double2::Maximum(MAX_double); + +Double2::Double2(const Int2& xy) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) +{ +} + +Double2::Double2(const Int3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) +{ +} + +Double2::Double2(const Int4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) +{ +} + +Double2::Double2(const Vector2& xy) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) +{ +} + +Double2::Double2(const Vector3& xyz) + : X(xyz.X) + , Y(xyz.Y) +{ +} + +Double2::Double2(const Vector4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) +{ +} + +Double2::Double2(const Color& color) + : X(color.R) + , Y(color.G) +{ +} + +String Double2::ToString() const +{ + return String::Format(TEXT("{}"), *this); +} + +Double2 Double2::Normalize(const Double2& v) +{ + Double2 result = v; + const double length = v.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1. / length; + result.X *= inv; + result.Y *= inv; + } + return result; +} + +Int2 Double2::CeilToInt(const Double2& v) +{ + return Int2(Math::CeilToInt(v.X), Math::CeilToInt(v.Y)); +} + +Int2 Double2::FloorToInt(const Double2& v) +{ + return Int2(Math::FloorToInt(v.X), Math::FloorToInt(v.Y)); +} + +double Double2::TriangleArea(const Double2& v0, const Double2& v1, const Double2& v2) +{ + return Math::Abs((v0.X * (v1.Y - v2.Y) + v1.X * (v2.Y - v0.Y) + v2.X * (v0.Y - v1.Y)) / 2.); +} diff --git a/Source/Engine/Core/Math/Double2.h b/Source/Engine/Core/Math/Double2.h new file mode 100644 index 000000000..a01e44fcb --- /dev/null +++ b/Source/Engine/Core/Math/Double2.h @@ -0,0 +1,644 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Math.h" +#include "Mathd.h" +#include "Engine/Core/Formatting.h" +#include "Engine/Core/Templates.h" + +struct Vector2; +struct Vector3; +struct Vector4; +struct Int2; +struct Int3; +struct Int4; +struct Color; +struct Matrix; + +/// +/// Represents a two dimensional mathematical vector. +/// +API_STRUCT() struct FLAXENGINE_API Double2 +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(Double2); +public: + + union + { + struct + { + /// + /// The X component of the vector. + /// + API_FIELD() double X; + + /// + /// The Y component of the vector. + /// + API_FIELD() double Y; + }; + + // Raw values + double Raw[2]; + }; + +public: + + // Vector with all components equal 0 + static const Double2 Zero; + + // Vector with all components equal 1 + static const Double2 One; + + // Vector X=1, Y=0 + static const Double2 UnitX; + + // Vector X=0, Y=1 + static const Double2 UnitY; + + // A minimum Double2 + static const Double2 Minimum; + + // A maximum Double2 + static const Double2 Maximum; + +public: + + /// + /// Empty constructor. + /// + Double2() + { + } + + // Init + // @param xy Value to assign to the all components + Double2(double xy) + : X(xy) + , Y(xy) + { + } + + // Init + // @param x X component value + // @param y Y component value + Double2(double x, double y) + : X(x) + , Y(y) + { + } + + // Init + // @param v Int2 to use X and Y components + explicit Double2(const Int2& xy); + + // Init + // @param v Int3 to use X and Y components + explicit Double2(const Int3& xyz); + + // Init + // @param v Int4 to use X and Y components + explicit Double2(const Int4& xyzw); + + // Init + // @param v Vector2 to use X and Y components + explicit Double2(const Vector2& xy); + + // Init + // @param v Vector3 to use X and Y components + explicit Double2(const Vector3& xyz); + + // Init + // @param v Vector4 to use X and Y components + explicit Double2(const Vector4& xyzw); + + // Init + // @param color Color value + explicit Double2(const Color& color); + +public: + + String ToString() const; + +public: + + // Arithmetic operators with Double2 + Double2 operator+(const Double2& b) const + { + return Add(*this, b); + } + + Double2 operator-(const Double2& b) const + { + return Subtract(*this, b); + } + + Double2 operator*(const Double2& b) const + { + return Multiply(*this, b); + } + + Double2 operator/(const Double2& b) const + { + return Divide(*this, b); + } + + Double2 operator-() const + { + return Double2(-X, -Y); + } + + // op= operators with Double2 + Double2& operator+=(const Double2& b) + { + *this = Add(*this, b); + return *this; + } + + Double2& operator-=(const Double2& b) + { + *this = Subtract(*this, b); + return *this; + } + + Double2& operator*=(const Double2& b) + { + *this = Multiply(*this, b); + return *this; + } + + Double2& operator/=(const Double2& b) + { + *this = Divide(*this, b); + return *this; + } + + // Arithmetic operators with double + Double2 operator+(double b) const + { + return Add(*this, b); + } + + Double2 operator-(double b) const + { + return Subtract(*this, b); + } + + Double2 operator*(double b) const + { + return Multiply(*this, b); + } + + Double2 operator/(double b) const + { + return Divide(*this, b); + } + + // op= operators with double + Double2& operator+=(double b) + { + *this = Add(*this, b); + return *this; + } + + Double2& operator-=(double b) + { + *this = Subtract(*this, b); + return *this; + } + + Double2& operator*=(double b) + { + *this = Multiply(*this, b); + return *this; + } + + Double2& operator/=(double b) + { + *this = Divide(*this, b); + return *this; + } + + // Comparison operators + bool operator==(const Double2& b) const + { + return X == b.X && Y == b.Y; + } + + bool operator!=(const Double2& b) const + { + return X != b.X || Y != b.Y; + } + + bool operator>(const Double2& b) const + { + return X > b.X && Y > b.Y; + } + + bool operator>=(const Double2& b) const + { + return X >= b.X && Y >= b.Y; + } + + bool operator<(const Double2& b) const + { + return X < b.X && Y < b.Y; + } + + bool operator<=(const Double2& b) const + { + return X <= b.X && Y <= b.Y; + } + +public: + + static bool NearEqual(const Double2& a, const Double2& b) + { + return Math::NearEqual(a.X, b.X) && Math::NearEqual(a.Y, b.Y); + } + + static bool NearEqual(const Double2& a, const Double2& b, double epsilon) + { + return Math::NearEqual(a.X, b.X, epsilon) && Math::NearEqual(a.Y, b.Y, epsilon); + } + +public: + + static double Dot(const Double2& a, const Double2& b) + { + return a.X * b.X + a.Y * b.Y; + } + + static double Cross(const Double2& a, const Double2& b) + { + return a.X * b.Y - a.Y * b.X; + } + + static void Add(const Double2& a, const Double2& b, Double2& result) + { + result.X = a.X + b.X; + result.Y = a.Y + b.Y; + } + + static Double2 Add(const Double2& a, const Double2& b) + { + Double2 result; + Add(a, b, result); + return result; + } + + static void Subtract(const Double2& a, const Double2& b, Double2& result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + } + + static Double2 Subtract(const Double2& a, const Double2& b) + { + Double2 result; + Subtract(a, b, result); + return result; + } + + static Double2 Multiply(const Double2& a, const Double2& b) + { + return Double2(a.X * b.X, a.Y * b.Y); + } + + static Double2 Multiply(const Double2& a, double b) + { + return Double2(a.X * b, a.Y * b); + } + + static Double2 Divide(const Double2& a, const Double2& b) + { + return Double2(a.X / b.X, a.Y / b.Y); + } + + static Double2 Divide(const Double2& a, double b) + { + return Double2(a.X / b, a.Y / b); + } + + // Calculates distance between two points in 2D + // @param a 1st point + // @param b 2nd point + // @returns Distance + static double Distance(const Double2& a, const Double2& b) + { + const double x = a.X - b.X; + const double y = a.Y - b.Y; + return Math::Sqrt(x * x + y * y); + } + + // Calculates the squared distance between two points in 2D + // @param a 1st point + // @param b 2nd point + // @returns Distance + static double DistanceSquared(const Double2& a, const Double2& b) + { + const double x = a.X - b.X; + const double y = a.Y - b.Y; + return x * x + y * y; + } + + // Clamp vector values within given range + // @param v Vector to clamp + // @param min Minimum value + // @param max Maximum value + // @returns Clamped vector + static Double2 Clamp(const Double2& v, double min, double max) + { + return Double2(Math::Clamp(v.X, min, max), Math::Clamp(v.Y, min, max)); + } + + // Clamp vector values within given range + // @param v Vector to clamp + // @param min Minimum value + // @param max Maximum value + // @returns Clamped vector + static Double2 Clamp(const Double2& v, const Double2& min, const Double2& max) + { + return Double2(Math::Clamp(v.X, min.X, max.X), Math::Clamp(v.Y, min.Y, max.Y)); + } + + // Performs vector normalization (scales vector up to unit length) + void Normalize() + { + const double length = Length(); + if (!Math::IsZero(length)) + { + const double invLength = 1. / length; + X *= invLength; + Y *= invLength; + } + } + +public: + + // Gets a value indicting whether this instance is normalized + bool IsNormalized() const + { + return Math::IsOne(X * X + Y * Y); + } + + // Gets a value indicting whether this vector is zero + bool IsZero() const + { + return Math::IsZero(X) && Math::IsZero(Y); + } + + // Gets a value indicting whether any vector component is zero + bool IsAnyZero() const + { + return Math::IsZero(X) || Math::IsZero(Y); + } + + // Gets a value indicting whether this vector is zero + bool IsOne() const + { + return Math::IsOne(X) && Math::IsOne(Y); + } + + // Calculates length of the vector + // @returns Length of the vector + double Length() const + { + return Math::Sqrt(X * X + Y * Y); + } + + // Calculates the squared length of the vector + // @returns The squared length of the vector + double LengthSquared() const + { + return X * X + Y * Y; + } + + // Calculates inverted length of the vector (1 / Length()) + double InvLength() const + { + return 1. / Length(); + } + + // Calculates a vector with values being absolute values of that vector + Double2 GetAbsolute() const + { + return Double2(Math::Abs(X), Math::Abs(Y)); + } + + // Calculates a vector with values being opposite to values of that vector + Double2 GetNegative() const + { + return Double2(-X, -Y); + } + + /// + /// Returns average arithmetic of all the components + /// + /// Average arithmetic of all the components + double AverageArithmetic() const + { + return (X + Y) * 0.5; + } + + /// + /// Gets sum of all vector components values + /// + /// Sum of X,Y and Z + double SumValues() const + { + return X + Y; + } + + /// + /// Gets multiplication result of all vector components values + /// + /// X * Y + double MulValues() const + { + return X * Y; + } + + /// + /// Returns minimum value of all the components + /// + /// Minimum value + double MinValue() const + { + return Math::Min(X, Y); + } + + /// + /// Returns maximum value of all the components + /// + /// Maximum value + double MaxValue() const + { + return Math::Max(X, Y); + } + + /// + /// Returns true if vector has one or more components is not a number (NaN) + /// + /// True if one or more components is not a number (NaN) + bool IsNaN() const + { + return isnan(X) || isnan(Y); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity + /// + /// True if one or more components equal to +/- infinity + bool IsInfinity() const + { + return isinf(X) || isinf(Y); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity or NaN + /// + /// True if one or more components equal to +/- infinity or NaN + bool IsNanOrInfinity() const + { + return IsInfinity() || IsNaN(); + } + +public: + + // Performs a linear interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the linear interpolation of the two vectors + static void Lerp(const Double2& start, const Double2& end, double amount, Double2& result) + { + result.X = Math::Lerp(start.X, end.X, amount); + result.Y = Math::Lerp(start.Y, end.Y, amount); + } + + // + // Performs a linear interpolation between two vectors. + // + // @param start Start vector, + // @param end End vector, + // @param amount Value between 0 and 1 indicating the weight of @paramref end"/>, + // @returns The linear interpolation of the two vectors + static Double2 Lerp(const Double2& start, const Double2& end, double amount) + { + Double2 result; + Lerp(start, end, amount, result); + return result; + } + + static Double2 Abs(const Double2& v) + { + return Double2(Math::Abs(v.X), Math::Abs(v.Y)); + } + + // Creates vector from minimum components of two vectors + static Double2 Min(const Double2& a, const Double2& b) + { + return Double2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y); + } + + // Creates vector from minimum components of two vectors + static void Min(const Double2& a, const Double2& b, Double2& result) + { + result = Double2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y); + } + + // Creates vector from maximum components of two vectors + static Double2 Max(const Double2& a, const Double2& b) + { + return Double2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y); + } + + // Creates vector from maximum components of two vectors + static void Max(const Double2& a, const Double2& b, Double2& result) + { + result = Double2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y); + } + + // Returns normalized vector + static Double2 Normalize(const Double2& v); + + static Double2 Round(const Double2& v) + { + return Double2(Math::Round(v.X), Math::Round(v.Y)); + } + + static Double2 Ceil(const Double2& v) + { + return Double2(Math::Ceil(v.X), Math::Ceil(v.Y)); + } + + static Double2 Floor(const Double2& v) + { + return Double2(Math::Floor(v.X), Math::Floor(v.Y)); + } + + static Double2 Frac(const Double2& v) + { + return Double2(v.X - (int64)v.X, v.Y - (int64)v.Y); + } + + static Int2 CeilToInt(const Double2& v); + static Int2 FloorToInt(const Double2& v); + + static Double2 Mod(const Double2& v) + { + return Double2( + v.X - (int64)v.X, + v.Y - (int64)v.Y + ); + } + +public: + + /// + /// Calculates the area of the triangle. + /// + /// The first triangle vertex. + /// The second triangle vertex. + /// The third triangle vertex. + /// The triangle area. + static double TriangleArea(const Double2& v0, const Double2& v1, const Double2& v2); +}; + +inline Double2 operator+(double a, const Double2& b) +{ + return b + a; +} + +inline Double2 operator-(double a, const Double2& b) +{ + return Double2(a) - b; +} + +inline Double2 operator*(double a, const Double2& b) +{ + return b * a; +} + +inline Double2 operator/(double a, const Double2& b) +{ + return Double2(a) / b; +} + +namespace Math +{ + FORCE_INLINE static bool NearEqual(const Double2& a, const Double2& b) + { + return Double2::NearEqual(a, b); + } +} + +template<> +struct TIsPODType +{ + enum { Value = true }; +}; + +DEFINE_DEFAULT_FORMATTING(Double2, "X:{0} Y:{1}", v.X, v.Y);