181 lines
6.2 KiB
C#
181 lines
6.2 KiB
C#
using System.Collections;
|
|
using System.Drawing;
|
|
using System.Numerics;
|
|
|
|
namespace WebmrAPI.Utils.Sequences
|
|
{
|
|
public interface ISequenceGenerator<T> : IEnumerable<T>
|
|
{
|
|
public static bool IsZero(double val, double epsilon = Double.Epsilon)
|
|
{
|
|
return Math.Abs(val) < epsilon;
|
|
}
|
|
public T Min { get; }
|
|
public T Max { get; }
|
|
public double Progress { get; }
|
|
public double Step { get; }
|
|
public bool HasValues { get; }
|
|
public T Next();
|
|
public ISequenceGenerator<T> Reset();
|
|
}
|
|
|
|
public interface INumberGenerator<T> : ISequenceGenerator<T> where T : struct, INumber<T>
|
|
{
|
|
public INumberGenerator<T> Self { get; }
|
|
public virtual double DMin { get => Double.CreateChecked(Min); }
|
|
public virtual double DMax { get => Double.CreateChecked(Max); }
|
|
public virtual double Mean { get => (DMin + DMax) / 2.0; }
|
|
}
|
|
|
|
public interface IPointGenerator : ISequenceGenerator<Point>
|
|
{
|
|
public static double CalcDistance(Point pt1, Point pt2)
|
|
{
|
|
return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2));
|
|
}
|
|
public static double CalcAngle(Point pt1, Point pt2)
|
|
{
|
|
return Math.Atan2(pt2.Y - pt1.Y, pt2.X - pt1.X);
|
|
}
|
|
public static Point CalcPoint(double x, double y, double offset, double pAngle)
|
|
{
|
|
return new Point((int)Math.Round(x + offset * Math.Cos(pAngle)), (int)Math.Round(y + offset * Math.Sin(pAngle)));
|
|
}
|
|
public static Point CalcMiddle(Point start, Point end)
|
|
{
|
|
return new Point(
|
|
(int)Math.Round(start.X + (end.X - start.X) / 2.0),
|
|
(int)Math.Round(start.Y + (end.Y - start.Y) / 2.0)
|
|
);
|
|
}
|
|
|
|
public static (double distance, double angle) CalcDistanceAngle(Point pt1, Point pt2)
|
|
{
|
|
double dx = pt2.X - pt1.X;
|
|
double dy = pt2.Y - pt1.Y;
|
|
|
|
return (Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2)), Math.Atan2(dy, dx));
|
|
}
|
|
|
|
public static double DegreesToRadians(double degrees)
|
|
{
|
|
return degrees * Math.PI / 180.0;
|
|
}
|
|
|
|
public static double RadiansToDegrees(double radians)
|
|
{
|
|
return radians * (180.0 / Math.PI);
|
|
}
|
|
|
|
public static Point NewPointAngleDistance(Point refPt, double distance, double aRadians, double epsilon = Double.Epsilon)
|
|
{
|
|
int x, y;
|
|
|
|
if (IsZero(distance, epsilon)) return new Point(refPt.X, refPt.Y);
|
|
|
|
x = (int)Math.Round(refPt.X + distance * Math.Cos(aRadians));
|
|
y = (int)Math.Round(refPt.Y + distance * Math.Sin(aRadians));
|
|
|
|
return new Point(x, y);
|
|
}
|
|
|
|
public static Point NewPointDistance(Point refPt, Point targetPt, double distance, double epsilon = Double.Epsilon)
|
|
{
|
|
return NewPointAngleDistance(refPt, distance, CalcAngle(refPt, targetPt), epsilon);
|
|
}
|
|
|
|
public static Point NewPointAngle(Point refPt, Point targetPt, double aRadians, double epsilon = Double.Epsilon)
|
|
{
|
|
return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt), aRadians, epsilon);
|
|
}
|
|
|
|
public static Point NewPointDistanceFactor(Point refPt, Point targetPt, double factor, double epsilon = Double.Epsilon)
|
|
{
|
|
return NewPointAngleDistance(refPt, CalcDistance(refPt, targetPt) * factor, CalcAngle(refPt, targetPt), epsilon);
|
|
}
|
|
|
|
public static Point GetRandomPointInRect(Rectangle rect)
|
|
{
|
|
double x = BaseRandom.NextGenerate(rect.X, rect.Width);
|
|
double y = BaseRandom.NextGenerate(rect.Y, rect.Height);
|
|
|
|
return new Point((int)Math.Round(x), (int)Math.Round(y));
|
|
}
|
|
|
|
public IPointGenerator Self { get; }
|
|
public virtual Point Start { get => Min; }
|
|
public virtual Point End { get => Max; }
|
|
public virtual double LinearX { get => Start.X + (End.X - Start.X) * Progress; }
|
|
public virtual double LinearY { get => Start.Y + (End.Y - Start.Y) * Progress; }
|
|
}
|
|
|
|
public abstract class BaseGenerator<T> : BaseRandom, ISequenceGenerator<T>
|
|
{
|
|
protected virtual double Epsilon { get; set; } = 0.01;
|
|
protected virtual bool IsZero(double val)
|
|
{
|
|
return ISequenceGenerator<T>.IsZero(val, Epsilon);
|
|
}
|
|
private double _fShape = 1.0;
|
|
private double _fFade = 0.5;
|
|
|
|
public T Min { get; protected set; }
|
|
public T Max { get; protected set; }
|
|
public virtual double Progress { get; protected set; } = -1.0;
|
|
public double ProgressRemainder { get => 1.0 - Progress; }
|
|
public virtual bool HasValues { get; protected set; } = true;
|
|
public double FShape { get => _fShape; protected set => _fShape = Math.Clamp(value, 0.0, 1.0); }
|
|
public double FFade { get => _fFade; protected set => _fFade = Math.Clamp(value, Epsilon, 1.0); }
|
|
protected double Scale { get => Math.Pow(Progress * ProgressRemainder * 4.0, FFade) * FShape; }
|
|
public abstract double Step { get; protected set; }
|
|
public BaseGenerator(T min, T max)
|
|
{
|
|
Min = min;
|
|
Max = max;
|
|
}
|
|
protected static double CalcStepByCount(int count)
|
|
{
|
|
return 1.0 / count;
|
|
}
|
|
|
|
protected abstract T Calc();
|
|
protected virtual T First() => Calc();
|
|
protected virtual T Last() => Calc();
|
|
|
|
public virtual T Next()
|
|
{
|
|
if (Progress < 0)
|
|
{
|
|
Progress = 0;
|
|
return First();
|
|
}
|
|
|
|
if ((Progress += Step) >= 1.0)
|
|
{
|
|
HasValues = false;
|
|
Progress = 1.0;
|
|
return Last();
|
|
}
|
|
|
|
return Calc();
|
|
}
|
|
public virtual ISequenceGenerator<T> Reset()
|
|
{
|
|
HasValues = true;
|
|
Progress = -1.0;
|
|
return this;
|
|
}
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
while (HasValues)
|
|
{
|
|
yield return Next();
|
|
}
|
|
}
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
}
|