【问题标题】:Random smooth graph随机平滑图
【发布时间】:2012-12-25 17:02:41
【问题描述】:

我想要类似于下图中的图表。我想实现类似于 cos/sin 的图形,但有一点随机性。图表不应超过(100)或低于(0)限制。 没有随机性,我们可以这样写函数:

f(x)=cos(x)*50+50

我正在寻找任何语言的实现或只是一个简单的解释。

【问题讨论】:

  • 出于什么目的?这有点太开放了……
  • @RBarryYoung 为一个简单的游戏生成随机地形。
  • 啊,好的。我记得,随机地形最好由 f(0) 和 f(1) 过程的组合生成......
  • 您想要 a) 生成一组点,b) 分析函数,c) 绘图工具吗?

标签: c# math graph


【解决方案1】:

您可以简单地将一些 sin/cos 与随机系数和周期相​​加。

实现示例:

internal struct SineWave
{
    internal readonly double Amplitude;
    internal readonly double OrdinaryFrequency;
    internal readonly double AngularFrequency;
    internal readonly double Phase;
    internal readonly double ShiftY;

    internal SineWave(double amplitude, double ordinaryFrequency, double phase, double shiftY)
    {
        Amplitude = amplitude;
        OrdinaryFrequency = ordinaryFrequency;
        AngularFrequency = 2 * Math.PI * ordinaryFrequency;
        Phase = phase;
        ShiftY = shiftY;
    }
}

public class RandomCurve
{
    private SineWave[] m_sineWaves;

    public RandomCurve(int components, double minY, double maxY, double flatness)
    {
        m_sineWaves = new SineWave[components];

        double totalPeakToPeakAmplitude = maxY - minY;
        double averagePeakToPeakAmplitude = totalPeakToPeakAmplitude / components;

        int prime = 1;
        Random r = new Random();
        for (int i = 0; i < components; i++)
        {
            // from 0.5 to 1.5 of averagePeakToPeakAmplitude 
            double peakToPeakAmplitude = averagePeakToPeakAmplitude * (r.NextDouble() + 0.5d);

            // peak amplitude is a hald of peak-to-peak amplitude
            double amplitude = peakToPeakAmplitude / 2d;

            // period should be a multiple of the prime number to avoid regularities
            prime = Utils.GetNextPrime(prime);
            double period = flatness * prime;

            // ordinary frequency is reciprocal of period
            double ordinaryFrequency = 1d / period;

            // random phase
            double phase = 2 * Math.PI * (r.NextDouble() + 0.5d);

            // shiftY is the same as amplitude
            double shiftY = amplitude;

            m_sineWaves[i] =
                new SineWave(amplitude, ordinaryFrequency, phase, shiftY);
        }
    }

    public double GetY(double x)
    {
        double y = 0;
        for (int i = 0; i < m_sineWaves.Length; i++)
            y += m_sineWaves[i].Amplitude * Math.Sin(m_sineWaves[i].AngularFrequency * x + m_sineWaves[i].Phase) + m_sineWaves[i].ShiftY;

        return y;
    }
}

internal static class Utils
{
    internal static int GetNextPrime(int i)
    {
        int nextPrime = i + 1;
        for (; !IsPrime(nextPrime); nextPrime++) ;
        return nextPrime;
    }

    private static bool IsPrime(int number)
    {
        if (number == 1) return false;
        if (number == 2)  return true;

        for (int i = 2; i < number; ++i)
            if (number % i == 0) return false;

        return true;
    } 
}

【讨论】:

  • 我猜也是随机的?
【解决方案2】:

所以这是一个用 C# 编写的代码,它可以通过随机输入值进行更多随机化。 我只是给你一些带有值的输出,看看它是否适合你。可以针对余弦值和正弦值修改 Amplite。最后添加偏移量(因此最小值始终为 0)并进行缩放以确保最大值为 100。如您所见,可以添加噪声(图 3、图 4)。

terr1: RandomTerrarain(1000, 4, 1, 10, 5, 0); Figure 1

terr2: RandomTerrarain(1000, 2, 3, -10, 5, 0); Figure 2

希望这会有所帮助!

      private static Random rnd = new Random();
    private double[] RandomTerrarain(int length, int sinuses, int cosinuses, double amplsin, double amplcos, double noise)
    {
        if (length <= 0)
            throw new ArgumentOutOfRangeException("length", length, "Length must be greater than zero!");
        double[] returnValues = new double[length];

        for (int i = 0; i < length; i++)
        {
            // sin
            for (int sin = 1; sin <= sinuses; sin++)
            {
                returnValues[i] += amplsin * Math.Sin((2 * sin * i * Math.PI) / (double)length);
            }
            // cos
            for (int cos = 1; cos <= cosinuses; cos++)
            {
                returnValues[i] += amplcos * Math.Cos((2 * cos * i * Math.PI) / (double)length);
            }
            // noise
            returnValues[i] += (noise * rnd.NextDouble()) - (noise * rnd.NextDouble());
        }
        // give offset so it be higher than 0
        double ofs = returnValues.Min();
        if (ofs < 0)
        {
            ofs *= -1;
            for (int i = 0; i < length; i++)
            {
                returnValues[i] += ofs;
            }
        }
        // resize to be fit in 100
        double max = returnValues.Max();
        if (max >= 100)
        {
            double scaler = max / 100.0;
            for (int i = 0; i < length; i++)
            {
                returnValues[i] /= scaler;
            }
        }
        return returnValues;
    }

【讨论】:

    【解决方案3】:

    对于您的函数,您可以使用Math 类和Cos() 方法。

    public static double GetCosFunction(double d)
    {
         return Math.Cos(d) * 50 + 50;
    }
    

    对于图形解决方案,您可以查看这些主题;

    【讨论】:

    • 我认为您误解了这个问题。他不是在问如何绘制该函数,而是在问如何使该函数更加随机。
    • “使函数更随机”是什么意思?功能工作清除输入和清除输出。一个更随机的函数怎么可能只与一个名为 cos(x)*50+50 的表达式一起工作?请点亮我..
    • 他想要一个与那个函数相似但有一些随机性的函数。
    【解决方案4】:

    忘记了……

    terr3: RandomTerrarain(1000, 5, 5, -2, 5, 2); Figure 3

    terr4: RandomTerrarain(1000, 4, 1, 5, -20, 1); Figure 4

    【讨论】:

      【解决方案5】:

      看看xkcd-style graphs,这是一种向图形添加随机噪声并以使其看起来像手绘的方式对其进行平滑处理的方法,模仿xkcd cartoons 的风格。虽然这不是您想要的,但我认为只需将输入图设置为零(例如 y = 0)并将噪声平滑参数调整为更大的噪声幅度和更大的平滑距离可能会导致随机图的类型你正在寻找。

      【讨论】:

        猜你喜欢
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-31
        • 2017-08-03
        相关资源
        最近更新 更多