public static <T> Point<T> interpolate(Point<T> p1, Point<T> p2, Instant targetTime) {
        checkNotNull(p1, "Cannot perform interpolation when the first input points is null");
        checkNotNull(p2, "Cannot perform interpolation when the second input points is null");
        checkNotNull(targetTime, "Cannot perform interpolation when the targetTime is null");

        checkArgument(
            p1.time().isBefore(p2.time()) || p1.time().equals(p2.time()),
            "The input points must be in chronological order"
        );

        TimeWindow window = TimeWindow.of(p1.time(), p2.time());

        checkArgument(
            window.contains(targetTime),
            "The targetTime is outside the required time window"
        );

        if (p1.time().equals(targetTime)) {
            return (new PointBuilder<T>(p1)).build();
        } else if (p2.time().equals(targetTime)) {
            return (new PointBuilder<T>(p2)).build();
        } else {

            double fraction = window.toFractionOfRange(targetTime);

            //build an interpolated point
            LatLong interpolatedLatLong = interpolateLatLong(p1.latLong(), p2.latLong(), fraction);

            Double interpolatedCourseInDegrees = interpolateCourse(
                isNull(p1.course()) ? null : p1.course().inDegrees(),
                isNull(p2.course()) ? null : p2.course().inDegrees(),
                fraction
            );

            //correct the interpolated course when one of the input values was null
            if (interpolatedCourseInDegrees == null) {
                interpolatedCourseInDegrees = Spherical.courseInDegrees(p1.latLong(), p2.latLong());
            }

            double interpolatedSpeed = interpolateSpeed(p1, p2, fraction);

            Distance interpolatedAltitude = interpolate(
                p1.altitude(),
                p2.altitude(),
                fraction
            );

            //return a copy of the 1st input point but with corrected trajectory data
            return (new PointBuilder<T>(p1))
                .latLong(interpolatedLatLong)
                .course(Course.ofDegrees(interpolatedCourseInDegrees))
                .speed(Speed.ofKnots(interpolatedSpeed))
                .altitude(interpolatedAltitude)
                .time(targetTime)
                .build();
        }
    }
@Test
    public void testInterpolatePointWithBadNulCourse() {

        //The RH message shown in s1 has no course
        String s1 = "[RH],STARS,GEG,07/08/2017,14:09:11.474,,,,1200,0,0,,47.61734,-117.54339,655,0,0.3008,-0.1445,,,,GEG,,,,,,,IFR,,,,,,,,,,,,{RH}\n";
        //The RH message shown in s2 has a course of 253
        String s2 = "[RH],STARS,GEG,07/08/2017,14:09:16.284,,,,1200,28,88,253,47.61675,-117.54618,655,0,0.1876,-0.1797,,,,GEG,,,,,,,IFR,,,,,,,,,,,,{RH}\n";

        Point<NopHit> p1 = NopHit.from(s1);
        Point<NopHit> p2 = NopHit.from(s2);

        Point<NopHit> interpolated = interpolate(p1, p2, p1.time().plusSeconds(2));

        assertThat(
            "The course of the interpolated point is set even though the 1st point had no course",
            Spherical.courseInDegrees(p1.latLong(), p2.latLong()),
            is(interpolated.course().inDegrees())
        );
    }