using UnityEngine;
using System.Collections;
namespace ProjectX
{
public class XMath
{
public const float Epsilon = 0.00001f;
public const float Sqrt2 = 1.4142135623730950488016887242097f;
public const float Sqrt3 = 1.7320508075688772935274463415059f;
public static bool FloatEqual(float a, float b)
{
return (a - b > -XMath.Epsilon) && (a - b < XMath.Epsilon);
}
public static bool FloatEqual(Vector2 a, Vector2 b)
{
return XMath.FloatEqual(a.x, b.x)
&& XMath.FloatEqual(a.y, b.y);
}
public static bool FloatEqual(Vector3 a, Vector3 b)
{
return XMath.FloatEqual(a.x, b.x)
&& XMath.FloatEqual(a.y, b.y)
&& XMath.FloatEqual(a.z, b.z);
}
public static Vector2 RandomRange(Vector2 a, Vector2 b)
{
float x = Random.Range(a.x, b.x);
float y = Random.Range(a.y, b.y);
Vector2 result = Vector2.zero;
result.Set(x, y);
return result;
}
public static Vector3 RandomRange(Vector3 a, Vector3 b)
{
float x = Random.Range(a.x, b.x);
float y = Random.Range(a.y, b.y);
float z = Random.Range(a.z, b.z);
Vector3 result = Vector3.zero;
result.Set(x, y, z);
return result;
}
public static Vector3 Clamp(Vector3 value, Vector3 min, Vector3 max)
{
float x = Mathf.Clamp(value.x, min.x, max.x);
float y = Mathf.Clamp(value.y, min.y, max.y);
float z = Mathf.Clamp(value.z, min.z, max.z);
Vector3 result = Vector3.zero;
result.Set(x, y, z);
return result;
}
public static float AngleToRadian(float angle)
{
return angle * Mathf.PI / 180.0f;
}
public static float RadianToAngle(float radians)
{
return radians * 180.0f / Mathf.PI;
}
///
/// Normalize radians to [0 ~ 2pi)
///
public static float NormalizeRadian(float radians)
{
float result = radians;
while (result >= Mathf.PI * 2)
result = result - Mathf.PI * 2;
while (result < 0)
result = result + Mathf.PI * 2;
return result;
}
///
/// Normalize angle to [0 ~ 360)
///
public static float NormalizeAngle(float angle)
{
float result = angle;
while (result >= 360)
result = result - 360;
while (result < 0)
result = result + 360;
return result;
}
///
/// Symmetrize radians to [-pi ~ +pi]
///
public static float SymmetrizeRadian(float radians)
{
float result = radians;
while (result > Mathf.PI)
result = result - Mathf.PI * 2;
while (result < -Mathf.PI)
result = result + Mathf.PI * 2;
return result;
}
///
/// Symmetrize angle to [-180 ~ +180]
///
public static float SymmetrizeAngle(float angle)
{
float result = angle;
while (result > 180)
result = result - 360;
while (result < -180)
result = result + 360;
return result;
}
public static bool Intersect(Rect area1, Rect area2)
{
if (area1.x >= area2.x + area2.width)
return false;
if (area1.x + area1.width <= area2.x)
return false;
if (area1.y >= area2.y + area2.height)
return false;
if (area1.y + area1.height <= area2.y)
return false;
return true;
}
///
/// intersetion-test between sphere and line-segment
///
/// sphere center
/// sphere radius
/// line-segment p1
/// line-segment p2
///
public static bool Intersect(Vector3 center, float radius, Vector3 p1, Vector3 p2)
{
Vector3 point = XMath.NearestPointOnLineSeg(center, p1, p2);
return (center - point).sqrMagnitude <= radius * radius;
}
///
/// Get the nearest point on the line(p1->p2) from the point p
///
/// the known point
/// the line segment point p1
/// the line segment point p2
///
public static Vector3 NearestPointOnLineSeg(Vector3 p, Vector3 p1, Vector3 p2)
{
Vector3 vl = p2 - p1;
Vector3 vp = p - p1;
float len = vl.magnitude;
vl.Normalize();
float u = Vector3.Dot(vp, vl);
if (u <= 0) return p1;
else if (u >= len) return p2;
else return p1 + vl * u;
}
///
/// Compute elastic force between two points (p0 and p1).
///
/// the force-caster point
/// the force-receiver point
/// elastic strength
/// The force is pushing if the distance of two points less than this value.
/// The force is pulling if the distance of two points greater than this value.
///
public static Vector3 Elastic(Vector3 p0, Vector3 p1, float strength, float minlen, float maxlen)
{
if (Mathf.Approximately(strength, 0))
return Vector3.zero;
Vector3 dir = p0 - p1;
float len = dir.magnitude;
float delta = 0.0f;
if (len < minlen) delta = len - minlen;
else if (len > maxlen) delta = len - maxlen;
if (Mathf.Approximately(delta, 0))
return Vector3.zero;
if (len <= Mathf.Epsilon)
dir = XMath.RandomRange(-Vector3.one, Vector3.one);
return dir.normalized * strength * delta;
}
///
/// compute a parabola-curve f(x) = ax^2 + bx
/// p0 = (0, 0), p1(x, y), top = ymax + h
///
/// a factor for f(x)
/// b factor for f(x)
public static void ComputeParabola(float x, float y, float h, out float a, out float b)
{
float top = Mathf.Max(y, 0) + h;
float x_2 = x * x;
float delta = x_2 - x_2 * y / top;
float _2A = x_2 / top * 0.5f;
float _nB = x;
b = (_nB + Mathf.Sqrt(delta)) / _2A;
a = -b * b / (4 * top);
}
public static float SampleParabola(float x, float a, float b, float c)
{
return a * x * x + b * x + c;
}
///
/// b(t) = (1-t)^2*p0 + 2t(1-t)*p1 + t^2 * p2
///
public static Vector3 SampleBezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, float t)
{
return (1 - t) * (1 - t) * p0 + 2 * t * (1 - t) * p1 + t * t * p2;
}
///
/// b(t) = (1-t)^3*p0 + 3t(1-t)^2*p1 + 3t^2(1-t)*p2 + t^3*p3
///
public static Vector3 SampleBezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
return
(1 - t) * (1 - t) * (1 - t) * p0 +
3 * t * (1 - t) * (1 - t) * p1 +
3 * t * t * (1 - t) * p2 +
t * t * t * p3;
}
public static void Smooth(float[,] data, float innerWeight = 0.5f, float outerWeight = 0.5f)
{
int h = data.GetLength(0);
int w = data.GetLength(1);
for (int y = 1; y < h - 1; y++)
{
for (int x = 1; x < w - 1; x++)
{
float value = 0;
value += data[y, x] * innerWeight + data[y - 1, x - 1] * outerWeight;
value += data[y, x] * innerWeight + data[y - 1, x] * outerWeight;
value += data[y, x] * innerWeight + data[y - 1, x + 1] * outerWeight;
value += data[y, x] * innerWeight + data[y, x - 1] * outerWeight;
value += data[y, x] * innerWeight + data[y, x + 1] * outerWeight;
value += data[y, x] * innerWeight + data[y + 1, x - 1] * outerWeight;
value += data[y, x] * innerWeight + data[y + 1, x] * outerWeight;
value += data[y, x] * innerWeight + data[y + 1, x + 1] * outerWeight;
data[y, x] = value * 0.125f; // value / 8
}
}
}
public static void Smooth(float[] data, int w, int h, float innerWeight = 0.5f, float outerWeight = 0.5f)
{
if (data.Length != w * h)
throw new System.ArgumentException("data.Length != w * h");
for (int y = 1; y < h - 1; y++)
{
for (int x = 1; x < w - 1; x++)
{
float value = 0;
value += data[y * w + x] * innerWeight + data[(y - 1) * w + (x - 1)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y - 1) * w + (x + 0)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y - 1) * w + (x + 1)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y + 0) * w + (x - 1)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y + 0) * w + (x + 1)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y + 1) * w + (x - 1)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y + 1) * w + (x + 0)] * outerWeight;
value += data[y * w + x] * innerWeight + data[(y + 1) * w + (x + 1)] * outerWeight;
data[y * w + x] = value * 0.125f; // value / 8
}
}
}
}
}