Skip to content

Instantly share code, notes, and snippets.

@steamb23
Created August 15, 2021 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steamb23/b596dd32d81d305a69de9402acf20b4b to your computer and use it in GitHub Desktop.
Save steamb23/b596dd32d81d305a69de9402acf20b4b to your computer and use it in GitHub Desktop.
/*
Copyright 2021 SteamB23
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// 이하 define문은 벡터의 어느 방향을 원점으로 볼지 결정합니다.
// 다만 회전방향은 무조건 시계방향입니다.
#define POSITIVE_Y_ORIGIN
// #define POSITIVE_X_ORIGIN
// #define NEGATIVE_Y_ORIGIN
// #define NEGATIVE_X_ORIGIN
// 이하 define문은 Smith의 공식을 이용하여 더 정확한 나눗셈을 보장할 것인지 결정합니다.
// 쓰지 않는다면 켤레복소수 곱셈을 이용합니다.
// #define USE_ACCURATE_DIVISION_METHOD
using System;
using UnityEngine;
/// <summary>
/// 유니티와 함께 동작하는 복소수를 표현합니다.
/// </summary>
public struct Complex : IEquatable<Complex>
{
public Complex(float real, float imaginary)
{
Real = real;
Imaginary = imaginary;
}
public Complex(Vector2 vector)
{
#if POSITIVE_Y_ORIGIN
// up to right
Real = -vector.y;
Imaginary = vector.x;
#elif POSITIVE_X_ORIGIN
// right to right
Real = vector.x;
Imaginary = vector.y;
#elif NEGATIVE_Y_ORIGIN
// down to right
Real = vector.y;
Imaginary = -vector.x;
#elif NEGATIVE_X_ORIGIN
// left to right
Real = -vector.x;
Imaginary = -vector.y;
#endif
}
public static Complex FromPolarCoordinates(float magnitude, float phase)
{
/* Factory method to take polar inputs and create a Complex object */
return new Complex(magnitude * Mathf.Cos(phase), magnitude * Mathf.Sin(phase));
}
private static readonly Complex Zero = new Complex(0f, 0f);
private static readonly Complex ImaginaryOne = new Complex(0f, 1f);
private static readonly Complex One = new Complex(1f, 0f);
/// <summary>
/// 복소수의 실수부를 나타냅니다.
/// </summary>
public float Real;
/// <summary>
/// 복소수의 허수부를 나타냅니다.
/// </summary>
public float Imaginary;
public static Complex operator *(Complex left, Complex right) =>
// Multiplication: (a + bi)(c + di) = (ac -bd) + (bc + ad)i
new Complex(
real: left.Real * right.Real - left.Imaginary * right.Imaginary,
imaginary: left.Imaginary * right.Real + left.Real * right.Imaginary
);
public static Complex Add(Complex left, Complex right)
{
return left + right;
}
public static Complex Subtract(Complex left, Complex right)
{
return left - right;
}
public static Complex Multiply(Complex left, Complex right)
{
return left * right;
}
public static Complex Divide(Complex dividend, Complex divisor)
{
return dividend / divisor;
}
public static Complex operator +(Complex left, Complex right) =>
new Complex((left.Real + right.Real), (left.Imaginary + right.Imaginary));
public static Complex operator -(Complex left, Complex right) =>
new Complex((left.Real - right.Real), (left.Imaginary - right.Imaginary));
public static Complex operator /(Complex left, Complex right)
{
#if USE_ACCURATE_DIVISION_METHOD
// Michael Baudin, Robert L. Smith, 2011, Improved Complex Division, forge.scilab.org
var a = left.Real;
var b = left.Imaginary;
var c = right.Real;
var d = right.Imaginary;
if (Mathf.Abs(d) < Mathf.Abs(c))
{
var r = d / c;
var t = 1 / (c + d * r);
return r == 0
? new Complex((a + d * (b / c)) * t, (b - d * (a / c)) * t)
: new Complex((a + b * r) * t, (b - a * r) * t);
}
else
{
var r = c / d;
var t = 1 / (c * r + d);
return r == 0
? new Complex((c * (a / d) + b) * t, (c * (b / d) - a) * t)
: new Complex((a * r + b) * t, (b * r - a) * t);
}
#else
return left * Conjugate(right);
#endif
}
public static float Abs(Complex value)
{
if (float.IsInfinity(value.Real) || float.IsInfinity(value.Imaginary))
{
return float.PositiveInfinity;
}
float c = Mathf.Abs(value.Real);
float d = Mathf.Abs(value.Imaginary);
if (c > d)
{
float r = d / c;
return c * Mathf.Sqrt(1f + r * r);
}
else if (d == 0.0)
{
return c; // c is either 0.0 or NaN
}
else
{
float r = c / d;
return d * Mathf.Sqrt(1f + r * r);
}
}
public static Complex Conjugate(Complex value)
{
// Conjugate of a Complex number: the conjugate of x+i*y is x-i*y
return new Complex(value.Real, -value.Imaginary);
}
public static Complex Reciprocal(Complex value)
{
// Reciprocal of a Complex number : the reciprocal of x+i*y is 1/(x+i*y)
if (value.Real == 0 && value.Imaginary == 0)
{
return Zero;
}
return One / value;
}
public static explicit operator Vector2(Complex complex)
{
#if POSITIVE_Y_ORIGIN
// right to up
return new Vector2(complex.Imaginary, -complex.Real);
#elif POSITIVE_X_ORIGIN
// right to right
return new Vector2(complex.Real, complex.Imaginary);
#elif NEGATIVE_Y_ORIGIN
// right to down
return new Vector2(-complex.Imaginary, complex.Real);
#elif NEGATIVE_X_ORIGIN
// right to left
return new Vector2(-complex.Real, -complex.Imaginary);
#endif
}
public static implicit operator Complex(Vector2 vector)
{
return new Complex(vector);
}
public bool Equals(Complex other)
{
return Real.Equals(other.Real) && Imaginary.Equals(other.Imaginary);
}
public override bool Equals(object obj)
{
return obj is Complex other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (Real.GetHashCode() * 397) ^ Imaginary.GetHashCode();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment