98 lines
4.5 KiB
C#
98 lines
4.5 KiB
C#
using System.Drawing;
|
|
using System.Numerics;
|
|
|
|
namespace WebmrAPI.Utils.Sequences
|
|
{
|
|
public abstract class PerlinGenerator<T> : BaseGenerator<T>
|
|
{
|
|
private Perlin2D _perlin;
|
|
private double _amplitude = 100.0;
|
|
public double Amplitude { get => _amplitude; protected set => _amplitude = Math.Abs(value); }
|
|
public double Persistance { get; protected set; } = 0.5;
|
|
public double Frequency { get; protected set; } = 5.0;
|
|
public int Octaves { get; protected set; } = 4;
|
|
public double Seed { get; private set; }
|
|
public override double Step { get; protected set; }
|
|
protected double Noise { get => _perlin.Noise(Progress * Frequency, Seed, Octaves, Persistance); }
|
|
public PerlinGenerator(T min, T max, double seed)
|
|
: base(min, max)
|
|
{
|
|
Seed = seed;
|
|
_perlin = new Perlin2D((int)(Seed * 0x000fffff));
|
|
}
|
|
}
|
|
|
|
public sealed class PerlinNumberGenerator<T> : PerlinGenerator<T>, INumberGenerator<T> where T : struct, INumber<T>
|
|
{
|
|
public INumberGenerator<T> Self { get => this; }
|
|
public PerlinNumberGenerator<T> SetShapeFactor(double fShape) { FShape = fShape; return this; }
|
|
public PerlinNumberGenerator<T> SetFadeFactor(double fade) { FFade = fade; return this; }
|
|
public PerlinNumberGenerator<T> SetOctaves(int octaves) { Octaves = octaves; return this; }
|
|
public PerlinNumberGenerator<T> SetPersistence(double peristance) { Persistance = peristance; return this; }
|
|
public PerlinNumberGenerator<T> SetFrequency(double frequency) { Frequency = frequency; return this; }
|
|
public PerlinNumberGenerator<T> SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
|
|
protected override T Calc()
|
|
{
|
|
var offs = Noise * Scale * ((Self.DMax - Self.DMin) / 2.0);
|
|
|
|
return T.CreateChecked(Math.Clamp(Self.Mean + offs, Self.DMin, Self.DMax));
|
|
}
|
|
private static double GetSeed(T min, T max, double seed)
|
|
{
|
|
if (Double.IsNormal(seed)) return seed;
|
|
return (Double.CreateChecked(min) + Double.CreateChecked(max)) / 1000.0;
|
|
}
|
|
public PerlinNumberGenerator(T min, T max, int count = 10, double seed = Double.NaN) : base(min, max, GetSeed(min, max, seed))
|
|
{
|
|
Step = CalcStepByCount(count);
|
|
Amplitude = 1.0; // Set default
|
|
}
|
|
}
|
|
|
|
public sealed class PerlinPointGenerator : PerlinGenerator<Point>, IPointGenerator
|
|
{
|
|
private readonly double _pAngle;
|
|
public IPointGenerator Self { get => this; }
|
|
public PerlinPointGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; }
|
|
public PerlinPointGenerator SetFadeFactor(double fade) { FFade = fade; return this; }
|
|
public PerlinPointGenerator SetOctaves(int octaves) { Octaves = octaves; return this; }
|
|
public PerlinPointGenerator SetPersistence(double peristance) { Persistance = peristance; return this; }
|
|
public PerlinPointGenerator SetFrequency(double frequency) { Frequency = frequency; return this; }
|
|
public PerlinPointGenerator SetAmplitude(double amplitude) { Amplitude = amplitude; return this; }
|
|
protected override Point Calc()
|
|
{
|
|
return IPointGenerator.CalcPoint(Self.LinearX, Self.LinearY, Noise * Amplitude * Scale, _pAngle);
|
|
}
|
|
|
|
private static double GetSeed(Point start, Point end, double seed)
|
|
{
|
|
if (Double.IsNormal(seed)) return seed;
|
|
return (start.X + end.Y) / 1000.0;
|
|
}
|
|
|
|
public static PerlinPointGenerator CreateByCount(Point start, Point end, int count, double seed = Double.NaN)
|
|
{
|
|
return new PerlinPointGenerator(start, end, seed)
|
|
{
|
|
Step = CalcStepByCount(count)
|
|
};
|
|
}
|
|
public static PerlinPointGenerator CreateByStepSize(Point start, Point end, double pxPerStep = 5, double seed = Double.NaN)
|
|
{
|
|
return new PerlinPointGenerator(start, end, pxPerStep, seed);
|
|
}
|
|
|
|
public PerlinPointGenerator(Point start, Point end, double pxPerStep = 5, double seed = Double.NaN)
|
|
: this(start, end, seed)
|
|
{
|
|
Step = pxPerStep / IPointGenerator.CalcDistance(start, end);
|
|
}
|
|
|
|
private PerlinPointGenerator(Point start, Point end, double seed)
|
|
: base(start, end, GetSeed(start, end, seed))
|
|
{
|
|
_pAngle = IPointGenerator.CalcAngle(start, end) + Math.PI / 2.0;
|
|
}
|
|
}
|
|
}
|