MonotoneSpline.kt

1
package com.github.sanity.pav.spline
2
3
import com.github.sanity.pav.BinarySearchResult
4
import com.github.sanity.pav.Point
5
import com.github.sanity.pav.betterBinarySearch
6
import java.util.*
7
8
/**
9
 * Creates a monotone cubic spline from a given set of control points, implementing
10
 * the algorithm described [here](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation).
11
12
 * The spline is guaranteed to pass through each control point exactly.
13
 * Moreover, assuming the control points are monotonic (Y is non-decreasing or
14
 * non-increasing) then the interpolated values will also be monotonic.
15
16
 * @param xPoints The X component of the control points, strictly increasing.
17
 * *
18
 * @param yPoints The Y component of the control points, monotonic.
19
 * *
20
 * @return
21
 * *
22
 * *
23
 * @throws IllegalArgumentException if the X or Y arrays are null, have
24
 * * different lengths or have fewer than 2 values.
25
 * *
26
 * @throws IllegalArgumentException if the control points are not monotonic.
27
*/
28
29
class MonotoneSpline(inputPoints: List<Point>, tangentStrategy: TangentStrategy = FritschCarlsonTangentStrategy()) {
30
31
    private val points: ArrayList<PointWithTangents>
32
33
    init {
34
        val pointsWithSecants = SecantsCalculator.calculate(inputPoints)
35
        points = tangentStrategy.compute(pointsWithSecants)
36
    }
37
38
    /**
39
     * Interpolates the value of Y = f(X) for given X.
40
     * Clamps X to the domain of the spline.
41
42
     * @param x The X value.
43
     * *
44
     * @return The interpolated Y = f(X) value.
45
     */
46
    fun interpolate(x: Double): Double {
47
        val firstPoint = points.first()
48 3 1. interpolate : changed conditional boundary → SURVIVED
2. interpolate : negated conditional → KILLED
3. interpolate : replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED
        if (x < firstPoint.x) return firstPoint.y
49
        val lastPoint = points.last()
50 3 1. interpolate : changed conditional boundary → SURVIVED
2. interpolate : negated conditional → KILLED
3. interpolate : replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED
        if (x > lastPoint.x) return lastPoint.y
51
        val binarySearchResult = points.map { it.x }.toDoubleArray().betterBinarySearch(x)
52 1 1. interpolate : replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED
        return when (binarySearchResult) {
53 1 1. interpolate : negated conditional → KILLED
            is BinarySearchResult.Exact -> points[binarySearchResult.index].y
54 1 1. interpolate : negated conditional → KILLED
            is BinarySearchResult.Between -> {
55
                val x1 = points[binarySearchResult.lowIndex].x
56
                val y1 = points[binarySearchResult.lowIndex].y
57
                val m1 = points[binarySearchResult.lowIndex].tangent
58
                val x2 = points[binarySearchResult.highIndex].x
59
                val y2 = points[binarySearchResult.highIndex].y
60
                val m2 = points[binarySearchResult.highIndex].tangent
61
                val chs = CubicHermiteSpline(x1 = x1, y1 = y1, m1 = m1, x2 = x2, y2 = y2, m2 = m2)
62 1 1. interpolate : replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED
                return chs.interpolate(x)
63
            }
64
            else -> TODO("Remove this, shouldn't be necessary")
65
        }
66
    }
67
}
68

Mutations

48

1.1
Location : interpolate
Killed by : none
changed conditional boundary → SURVIVED

2.2
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
negated conditional → KILLED

3.3
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED

50

1.1
Location : interpolate
Killed by : none
changed conditional boundary → SURVIVED

2.2
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
negated conditional → KILLED

3.3
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED

52

1.1
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED

53

1.1
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
negated conditional → KILLED

54

1.1
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
negated conditional → KILLED

62

1.1
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
replaced return of double value with -(x + 1) for com/github/sanity/pav/spline/MonotoneSpline::interpolate → KILLED

71

1.1
Location : interpolate
Killed by : com.github.sanity.pav.spline.MonotoneSplineSpec.com.github.sanity.pav.spline.MonotoneSplineSpec
negated conditional → KILLED

Active mutators

Tests examined


Report generated by PIT 1.1.10