162 lines
6.6 KiB
C#
162 lines
6.6 KiB
C#
|
|
using System.Drawing;
|
|||
|
|
using System.Numerics;
|
|||
|
|
|
|||
|
|
namespace WebmrAPI.Utils.Sequences
|
|||
|
|
{
|
|||
|
|
public abstract class BezierGenerator<T, TControl> : BaseGenerator<T> where TControl : struct
|
|||
|
|
{
|
|||
|
|
public bool IsCubic { get => Control2 != null; }
|
|||
|
|
protected TControl Control1 { get; set; }
|
|||
|
|
protected TControl? Control2 { get; set; }
|
|||
|
|
public override double Step { get; protected set; }
|
|||
|
|
protected double CalcBezier(double start, double end, double ctrl1, double? ctrl2)
|
|||
|
|
{
|
|||
|
|
double t = Progress;
|
|||
|
|
double rt = ProgressRemainder;
|
|||
|
|
|
|||
|
|
if (IsCubic && ctrl2 != null)
|
|||
|
|
{
|
|||
|
|
double rt3 = rt * rt * rt;
|
|||
|
|
double t3 = t * t * t;
|
|||
|
|
double rt2_t = rt * rt * t;
|
|||
|
|
double rt_t2 = rt * t * t;
|
|||
|
|
|
|||
|
|
return rt3 * start +
|
|||
|
|
3 * rt2_t * ctrl1 +
|
|||
|
|
3 * rt_t2 * ctrl2.Value +
|
|||
|
|
t3 * end;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double rt2 = rt * rt;
|
|||
|
|
double t2 = t * t;
|
|||
|
|
double rt_t = rt * t;
|
|||
|
|
|
|||
|
|
return rt2 * start +
|
|||
|
|
2 * rt_t * ctrl1 +
|
|||
|
|
t2 * end;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public BezierGenerator(T min, T max, TControl ctrl1, TControl? ctrl2)
|
|||
|
|
: base(min, max)
|
|||
|
|
{
|
|||
|
|
Control1 = ctrl1;
|
|||
|
|
Control2 = ctrl2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public class BezierNumberGenerator<T> : BezierGenerator<T, double>, INumberGenerator<T> where T : struct, INumber<T>
|
|||
|
|
{
|
|||
|
|
public INumberGenerator<T> Self { get => this; }
|
|||
|
|
private double Bezier { get => CalcBezier(Self.DMin, Self.DMax, Control1, Control2); }
|
|||
|
|
public BezierNumberGenerator<T> SetShapeFactor(double shape) { FShape = shape; return this; }
|
|||
|
|
public BezierNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
|
|||
|
|
protected override T Calc()
|
|||
|
|
{
|
|||
|
|
return T.CreateChecked(Math.Clamp(Self.Mean + (Bezier - Self.Mean) * Scale, Self.DMin, Self.DMax));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public BezierNumberGenerator(T start, T end, double ctrl1, double? ctrl2 = null, int count = 10)
|
|||
|
|
: base(start, end, ctrl1, ctrl2) { Step = CalcStepByCount(count); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class ArcNumberGenerator<T> : BezierNumberGenerator<T> where T : struct, INumber<T>
|
|||
|
|
{
|
|||
|
|
public ArcNumberGenerator(T start, T end, int count = 10, bool bidirectional = true, bool reverse = false)
|
|||
|
|
: base(start, end, Double.NaN, null, count)
|
|||
|
|
{
|
|||
|
|
var hMean = (Self.DMax - Self.Mean);
|
|||
|
|
if (bidirectional)
|
|||
|
|
{
|
|||
|
|
Control1 = (reverse) ? Self.DMin : Self.DMax;
|
|||
|
|
Control2 = (reverse) ? Self.DMax : Self.DMin;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Control1 = (reverse) ? Self.DMin : Self.DMax;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class BezierPointGenerator : BezierGenerator<Point, Point>, IPointGenerator
|
|||
|
|
{
|
|||
|
|
protected readonly double _pAngle;
|
|||
|
|
public IPointGenerator Self { get => this; }
|
|||
|
|
public BezierPointGenerator SetShapeFactor(double shape) { FShape = shape; return this; }
|
|||
|
|
public BezierPointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
|
|||
|
|
private double BezierX { get => CalcBezier(Min.X, Max.X, Control1.X, Control2?.X); }
|
|||
|
|
private double BezierY { get => CalcBezier(Min.Y, Max.Y, Control1.Y, Control2?.Y); }
|
|||
|
|
|
|||
|
|
protected override Point Calc()
|
|||
|
|
{
|
|||
|
|
double dx = BezierX - Self.LinearX;
|
|||
|
|
double dy = BezierY - Self.LinearY;
|
|||
|
|
|
|||
|
|
return IPointGenerator.CalcPoint(Self.LinearX + dx * Scale, Self.LinearY + dy * Scale, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static BezierPointGenerator CreateByCount(Point start, Point end, Point ctrl1, Point? ctrl2 = null, int count = 10)
|
|||
|
|
{
|
|||
|
|
return new BezierPointGenerator(start, end, ctrl1, ctrl2)
|
|||
|
|
{
|
|||
|
|
Step = CalcStepByCount(count)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static BezierPointGenerator CreateByStepSize(Point start, Point end, Point ctrl1, Point? ctrl2 = null, double pxPerStep = 5)
|
|||
|
|
{
|
|||
|
|
return new BezierPointGenerator(start, end, ctrl1, ctrl2, pxPerStep);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public BezierPointGenerator(Point start, Point end, Point ctrl1, Point? ctrl2 = null, double pxPerStep = 5)
|
|||
|
|
: this(start, end, ctrl1, ctrl2)
|
|||
|
|
{
|
|||
|
|
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public BezierPointGenerator(Point start, Point end, Point ctrl1, Point? ctrl2 = null)
|
|||
|
|
: base(start, end, ctrl1, ctrl2)
|
|||
|
|
{
|
|||
|
|
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public sealed class ArcPointGenerator : BezierPointGenerator
|
|||
|
|
{
|
|||
|
|
public new ArcPointGenerator SetShapeFactor(double shape) { base.SetShapeFactor(shape); return this; }
|
|||
|
|
public new ArcPointGenerator SetFadeFactor(double fade) { base.SetFadeFactor(fade); return this; }
|
|||
|
|
|
|||
|
|
public static ArcPointGenerator CreateByCount(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, int count = 10)
|
|||
|
|
{
|
|||
|
|
return new ArcPointGenerator(start, end, bidirectional, reverse, arcHeight)
|
|||
|
|
{
|
|||
|
|
Step = CalcStepByCount(count)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static ArcPointGenerator CreateByStepSize(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, double pxPerStep = 5)
|
|||
|
|
{
|
|||
|
|
return new ArcPointGenerator(start, end, bidirectional, reverse, arcHeight, pxPerStep);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ArcPointGenerator(Point start, Point end, bool bidirectional = false, bool reverse = false, double arcHeight = 15.0, double pxPerStep = 5)
|
|||
|
|
: this(start, end, bidirectional, reverse, arcHeight)
|
|||
|
|
{
|
|||
|
|
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private ArcPointGenerator(Point start, Point end, bool bidirectional, bool reverse, double arcHeight)
|
|||
|
|
: base(start, end, Point.Empty, null)
|
|||
|
|
{
|
|||
|
|
var height = (reverse) ? -arcHeight : arcHeight;
|
|||
|
|
|
|||
|
|
if (bidirectional)
|
|||
|
|
{
|
|||
|
|
Control1 = IPointGenerator.NewPointAngleDistance(IPointGenerator.NewPointDistanceFactor(start, end, 1.0 / 3.0), height, _pAngle);
|
|||
|
|
Control2 = IPointGenerator.NewPointAngleDistance(IPointGenerator.NewPointDistanceFactor(start, end, 2.0 / 3.0), -height, _pAngle);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Control1 = IPointGenerator.NewPointAngleDistance(IPointGenerator.CalcMiddle(start, end), height, _pAngle);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|