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()); } }