class SegmentGraphUtilities {

    public static <T> double getValueAt(List<T> segments, ToDoubleFunction<T> segmentToXExtent, BiFunction<T, Double, Double> yValueInterpolator, double xValue) {
        double xValueAtBoundary = 0;
        for (T segment : segments) {
            double xExtent = segmentToXExtent.applyAsDouble(segment);
            double xDistanceIntoSegment = Math.max(xValue - xValueAtBoundary, 0); //protect against a rounding error
            if (xExtent >= xDistanceIntoSegment) {
                return yValueInterpolator.apply(segment, xDistanceIntoSegment);
            }

            xValueAtBoundary += xExtent;
        }

        if (xValue - xValueAtBoundary < xValue * ERROR_TOLERANCE) {
            T lastRegion = Iterables.getLast(segments, null);
            return yValueInterpolator.apply(lastRegion, segmentToXExtent.applyAsDouble(lastRegion));
        }

        throw Failer.fail("Should have found an answer in loop");
    }

    private  SegmentGraphUtilities();

}