using System;
using System.Collections.Generic;
using System.Linq;
using Chernobyl.Collections.Generic;
using Chernobyl.Extensions;
using MoreLinq;
namespace Chernobyl.Mathematics.Space
{
///
/// Utilities for working with waves.
///
public static class Wave
{
///
/// Returns as a .
///
public static Func Sin => Math.Sin;
///
/// Returns as a .
///
public static Func Cos => Math.Cos;
///
/// Creates a method that generates a square wave whose waves are defined by the points
/// specified.
///
/// Defines the structure of the wave. The first value of the tuple
/// is the the value of the wave. The second value is the number of times the returned method
/// must be invoked before the wave changes.
/// The method that generates the wave.
public static Func Square(this Func> source)
{
var current = source();
var invokeCount = 0;
return Func.StaticFactory(0).Select(_ =>
{
invokeCount++;
while (current.Item2 < invokeCount)
{
current = source();
invokeCount = 1;
}
return current.Item1;
});
}
///
/// Returns a method whose return value increases by the result of
/// each time the returned method is invoked.
///
/// The method that determines the difference between each invocation of
/// the returned method.
/// The starting value for the returned method.
/// Returns true if the current value should be returned to the start.
/// Set to null if
public static Func Step(double step, double start = 0, Func reset = null)
{
return Step(() => step, () => start, reset);
}
///
/// Returns a method whose return value increases by the result of
/// each time the returned method is invoked.
///
/// The method that determines the difference between each invocation of
/// the returned method.
/// The starting value for the returned method.
/// Returns true if the current value should be returned to the start.
/// Set to null if
public static Func Step(Func step, Func start = null, Func reset = null)
{
reset = reset ?? (curr => false);
start = start ?? (() => 0);
double current = start();
return () =>
{
var input = current;
current += step();
if (reset(current)) current = start();
return input;
};
}
///
/// Applies a multiplicative factor onto the wave produced by .
/// This will increase (if is greater than one), decrease (if
/// is greater than zero or less than one), or 'silence' (if
/// is zero) the verticality of the wave (operand). If
/// is negative, it will flip the wave vertically.
///
/// The function whose result is to be multiplied against
/// .
/// The value to multiply the result by.
/// The method that returns the multiplied result.
public static Func Multiply(this Func waveFunction, double operand) =>
waveFunction.Multiply(() => operand);
///
/// Applies a multiplicative factor onto the wave produced by .
/// This will increase (if is greater than one), decrease (if
/// is greater than zero or less than one), or 'silence' (if
/// is zero) the verticality of the wave (operand). If
/// is negative, it will flip the wave vertically.
///
/// The function whose result is to be multiplied against
/// .
/// The value to multiply the result by.
/// The method that returns the multiplied result.
public static Func Multiply(this Func waveFunction, Func operand) =>
waveFunction.Select(value => value * operand());
}
}