package cubrikproject.tud.likelines.util;

import java.util.List;

/**
 * Smoothed function generated by a series of Gaussians
 * 
 * @see <a href="https://github.com/ShinNoNoir/likelines-player/blob/51d6d05a199e2de709fc5b2241e2f736664c10e6/js/likelines.js#L893">JavaScript reference implementation</a>
 */
public class SmoothedFunction {
	/** Default smoothing kernel bandwidth */
	private static final double DEFAULT_SMOOTHING_BANDWIDTH = 1.0;
	
	/** points */
	private final List<? extends Double> data;
	
	
	/**
	 * Constructs a smoothed function object.
	 * 
	 * @param data List of points
	 */
	public SmoothedFunction(List<? extends Double> data) {
		this.data = data;
	}
	
	/** Function application */
	public double apply(double x) {
		return apply(x, DEFAULT_SMOOTHING_BANDWIDTH);
	}
	
	/** Function application */
	public double apply(double x, double h) {
		final int n = data.size();
		double y = 0;
		
		for (double point : data)
			y += gaussian( (x-point) / h );
		
		y /= n*h;
		return y;
	}
	
	/** Standard Gaussian. */
	private static double gaussian(double x) {
		return Math.exp(x*x/-2) / Math.sqrt(2 * Math.PI);
	}
}
package cubrikproject.tud.likelines.util;

import java.util.List;

/**
 * Smoothed function generated by a series of Gaussians
 * 
 * @see <a href="https://github.com/ShinNoNoir/likelines-player/blob/51d6d05a199e2de709fc5b2241e2f736664c10e6/js/likelines.js#L893">JavaScript reference implementation</a>
 */
public class SmoothedFunction {
	/** Default smoothing kernel bandwidth */
	private static final double DEFAULT_SMOOTHING_BANDWIDTH = 1.0;
	
	/** points */
	private final List<? extends Double> data;
	
	
	/**
	 * Constructs a smoothed function object.
	 * 
	 * @param data List of points
	 */
	public SmoothedFunction(List<? extends Double> data) {
		this.data = data;
	}
	
	/** Function application */
	public double apply(double x) {
		return apply(x, DEFAULT_SMOOTHING_BANDWIDTH);
	}
	
	/** Function application */
	public double apply(double x, double h) {
		final int n = data.size();
		double y = 0;
		
		for (double point : data)
			y += gaussian( (x-point) / h );
		
		if (n > 0)
			y /= n*h;
		return y;
	}
	
	/** Standard Gaussian. */
	private static double gaussian(double x) {
		return Math.exp(x*x/-2) / Math.sqrt(2 * Math.PI);
	}
}
Fix division by zero for SmoothedFunction([])