using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Subsurface { static class MathUtils { public static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float amount) { return new Vector2( MathHelper.SmoothStep(v1.X, v2.X, amount), MathHelper.SmoothStep(v1.Y, v2.Y, amount)); } public static float Round(float value, float div) { return (float)Math.Floor(value / div) * div; } public static float VectorToAngle(Vector2 vector) { return (float)Math.Atan2(vector.Y, vector.X); } public static float CurveAngle(float from, float to, float step) { // Ensure that 0 <= angle < 2pi for both "from" and "to" while (from < 0) from += MathHelper.TwoPi; while (from >= MathHelper.TwoPi) from -= MathHelper.TwoPi; while (to < 0) to += MathHelper.TwoPi; while (to >= MathHelper.TwoPi) to -= MathHelper.TwoPi; if (Math.Abs(from - to) < MathHelper.Pi) { // The simple case - a straight lerp will do. return MathHelper.Lerp(from, to, step); } // If we get here we have the more complex case. // First, increment the lesser value to be greater. if (from < to) from += MathHelper.TwoPi; else to += MathHelper.TwoPi; float retVal = MathHelper.Lerp(from, to, step); // Now ensure the return value is between 0 and 2pi if (retVal >= MathHelper.TwoPi) retVal -= MathHelper.TwoPi; return retVal; } public static float WrapAngleTwoPi(float angle) { // Ensure that 0 <= angle < 2pi for both "from" and "to" while (angle < 0) angle += MathHelper.TwoPi; while (angle >= MathHelper.TwoPi) angle -= MathHelper.TwoPi; return angle; } public static float WrapAnglePi(float angle) { // Ensure that -pi <= angle < pi for both "from" and "to" while (angle < -MathHelper.Pi) angle += MathHelper.TwoPi; while (angle >= MathHelper.Pi) angle -= MathHelper.TwoPi; return angle; } public static float GetShortestAngle(float from, float to) { // Ensure that 0 <= angle < 2pi for both "from" and "to" from = WrapAngleTwoPi(from); to = WrapAngleTwoPi(to); if (Math.Abs(from - to) < MathHelper.Pi) { return to - from; } // If we get here we have the more complex case. // First, increment the lesser value to be greater. if (from < to) from += MathHelper.TwoPi; else to += MathHelper.TwoPi; return to - from; } /// /// solves the angle opposite to side a (parameters: lengths of each side) /// public static float SolveTriangleSSS(float a, float b, float c) { float A = (float)Math.Acos((b * b + c * c - a * a) / (2 * b * c)); if (float.IsNaN(A)) A = 1.0f; return A; } public static byte AngleToByte(float angle) { angle = WrapAngleTwoPi(angle); angle = angle * (255.0f / MathHelper.TwoPi); return Convert.ToByte(angle); } public static float ByteToAngle(byte b) { float angle = (float)b; angle = angle * (MathHelper.TwoPi / 255.0f); return angle; } } class CompareCCW : IComparer { private Vector2 center; public CompareCCW(Vector2 center) { this.center = center; } public int Compare(Vector2 a, Vector2 b) { if (a.X - center.X >= 0 && b.X - center.X < 0) return -1; if (a.X - center.X < 0 && b.X - center.X >= 0) return 1; if (a.X - center.X == 0 && b.X - center.X == 0) { if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(b.Y - a.Y); return Math.Sign(a.Y - b.Y); } // compute the cross product of vectors (center -> a) x (center -> b) float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y); if (det < 0) return -1; if (det > 0) return 1; // points a and b are on the same line from the center // check which point is closer to the center float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y); float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y); return Math.Sign(d2 - d1); } } }