using System.Drawing; using System.Numerics; namespace WebmrAPI.Utils.Sequences { public abstract class PerlinGenerator : BaseGenerator { 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 : PerlinGenerator, INumberGenerator where T : struct, INumber { public INumberGenerator Self { get => this; } public PerlinNumberGenerator SetShapeFactor(double fShape) { FShape = fShape; return this; } public PerlinNumberGenerator SetFadeFactor(double fade) { FFade = fade; return this; } public PerlinNumberGenerator SetOctaves(int octaves) { Octaves = octaves; return this; } public PerlinNumberGenerator SetPersistence(double peristance) { Persistance = peristance; return this; } public PerlinNumberGenerator SetFrequency(double frequency) { Frequency = frequency; return this; } public PerlinNumberGenerator 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, 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; } } }