Shade *color* using normal vectors given by *normals*, assuming a *lightsource* (using default position if not given). *color* can also be an array of the same length as *normals*.
(color, normals, lightsource=None)
| 1720 | |
| 1721 | |
| 1722 | def _shade_colors(color, normals, lightsource=None): |
| 1723 | """ |
| 1724 | Shade *color* using normal vectors given by *normals*, |
| 1725 | assuming a *lightsource* (using default position if not given). |
| 1726 | *color* can also be an array of the same length as *normals*. |
| 1727 | """ |
| 1728 | if lightsource is None: |
| 1729 | # chosen for backwards-compatibility |
| 1730 | lightsource = mcolors.LightSource(azdeg=225, altdeg=19.4712) |
| 1731 | |
| 1732 | with np.errstate(invalid="ignore"): |
| 1733 | shade = ((normals / np.linalg.norm(normals, axis=1, keepdims=True)) |
| 1734 | @ lightsource.direction) |
| 1735 | mask = ~np.isnan(shade) |
| 1736 | |
| 1737 | if mask.any(): |
| 1738 | # convert dot product to allowed shading fractions |
| 1739 | in_norm = mcolors.Normalize(-1, 1) |
| 1740 | out_norm = mcolors.Normalize(0.3, 1).inverse |
| 1741 | |
| 1742 | def norm(x): |
| 1743 | return out_norm(in_norm(x)) |
| 1744 | |
| 1745 | shade[~mask] = 0 |
| 1746 | |
| 1747 | color = mcolors.to_rgba_array(color) |
| 1748 | # shape of color should be (M, 4) (where M is number of faces) |
| 1749 | # shape of shade should be (M,) |
| 1750 | # colors should have final shape of (M, 4) |
| 1751 | alpha = color[:, 3] |
| 1752 | colors = norm(shade)[:, np.newaxis] * color |
| 1753 | colors[:, 3] = alpha |
| 1754 | else: |
| 1755 | colors = np.asanyarray(color).copy() |
| 1756 | |
| 1757 | return colors |