'Calculates the illumination intensity for the normal vectors of a
surface using the defined azimuth and elevation for the light source.
Imagine an artificial sun placed at infinity in some azimuth and
elevation position illuminating our surface. The parts of the surface
that slope toward the sun should brighten while those sides facing away
should become darker.
Parameters
fraction : number, optional
Increases or decreases the contrast of the hillshade.  Values
greater than one will cause intermediate values to move closer to
full illumination or shadow (and clipping any values that move
beyond 0 or 1). Note that this is not visually or mathematically
the same as vertical exaggeration.
Returns
intensity : ndarray
A 2d array of illumination values between 0-1, where 0 is
completely in shadow and 1 is completely illuminated.'

def shade_normals(self, normals, fraction=1.0):

    intensity = _vector_dot(normals, self.direction)
    (imin, imax) = (intensity.min(), intensity.max())
    intensity *= fraction
    if ((imax - imin) > 1e-06):
        intensity -= imin
        intensity /= (imax - imin)
    intensity = np.clip(intensity, 0, 1, intensity)
    return intensity
