def test_distance_point_grad(self):
        # Test gradient with respect to each projected point, leaving the
        # polyline fixed.
        # Move pts along simple polyline and compare gradients.
        # Points are a bit tunes, because at discontinuous points, the numerical
        # gradient jumps to far for the tested precision, although the plots are
        # perfectly ok
        pl = Polyline([[0, 0], [1, 0.8], [1.1, 1.9]])
        test_eps = 1e-2  # Max allowed deviation, chose suitable for num grad
        npts = 1000

        # Test x gradient
        ys = [-1, 2]
        x = np.linspace(-1, 2, npts)

        for yi in ys:
            y = yi + np.zeros_like(x)
            pts = np.vstack((x, y)).T

            dists, _, _, proj_vecs = pl.get_dist_to_line(pts)

            # Gradients are simply the normalized negative projection vectors
            _norm = np.linalg.norm(proj_vecs,
                                   axis=1).reshape(len(proj_vecs), 1)
            gradients = -proj_vecs / _norm

            # Directional gradient along x
            num_grad = np.gradient(dists, x)
            grad = np.dot(gradients, [1, 0])
            assert np.allclose(num_grad, grad, atol=test_eps)

        # Test y gradient
        xs = [-1, 2]
        y = np.linspace(-1, 1.5, npts)

        for xi in xs:
            x = xi + np.zeros_like(y)
            pts = np.vstack((x, y)).T

            dists, dists_grad, _, proj_vecs = pl.get_dist_to_line(pts)

            # Gradients are simply the normalized negative projection vectors
            _norm = np.linalg.norm(proj_vecs,
                                   axis=1).reshape(len(proj_vecs), 1)
            gradients = -proj_vecs / _norm

            # Directional gradient along x
            num_grad = np.gradient(dists, y)
            grad = np.dot(gradients, [0, 1])
            assert np.allclose(num_grad, grad, atol=test_eps)

        return
    def test_distance(self):
        v = [[1, 3], [3, 5], [6, 2], [2, 2]]
        pl = Polyline(v)

        # Test values are chosen to yield simple distances and vectors and were
        # calculated by hand apriori
        pts = [[1, 2], [1.5, 5.5], [3, 6], [3.5, 3.5], [5.5, 3.5], [4, 1],
               [2, 2.5]]
        dists, _, proj_to, proj_vecs = pl.get_dist_to_line(pts)

        # Should show from pt to closest part of the polyline
        proj_vecs_exp = [[0, 1], [1, -1], [0, -1], [0.5, 0.5], [-0.5, -0.5],
                         [0, 1], [0, -0.5]]
        dists_exp = [1., sqrt(2.), 1., sqrt(2.) / 2., sqrt(2.) / 2., 1., 0.5]
        # id < 0: Onto segment with -id-1, else onto vertex with id
        # Last point projects exactly orthogonally to end of segment, thus -3
        proj_to_exp = [0, -1, 1, -2, -2, -3, -3]

        for i, (pvexp, dexp,
                ptexp) in enumerate(zip(proj_vecs_exp, dists_exp,
                                        proj_to_exp)):
            assert proj_vecs[i, 0] == approx(pvexp[0])
            assert proj_vecs[i, 1] == approx(pvexp[1])
            assert dists[i] == approx(dexp)
            assert proj_to[i] == ptexp

        return