# 2D morphology
Morphing 2D shapes is conceptually simple. We can imagine it as a function that
takes two SVG images and produces the intermediate steps that smoothly
transforms the source image to the target image. If the SVG images are simple
shapes then it looks like this:
Often it is quite easy for a human to tell if a morph looks right or not. This,
unfortunately, does not mean the problem is easy to solve for a computer. As
it turns out, there is not a single, perfect algorithm for morphing between 2D
shapes. Instead, there are many different algorithms that each have their own
benefits and trade-offs. This article will specify the details of the
morphology-problem and show a handful of different solutions.
# Breaking it down
Conceptually, a morphing function should take two SVG images and give a new
SVG image over time. In Haskell, it would look like this:
```haskell
morph :: SVG → SVG → (Time → SVG)
```
However, morphing has several sub-problems, each of which that can be solved
indepently in a variety of ways. These solutions have different benefits and
drawbacks, and wildly different performance. Since no single morphing algorithm
is obviously superior in all cases, let's identify the othogonal sub-problems
and use their solutions as parameters to our morphing function.
## 1. Point correspondence
```haskell
type PointCorrespondence = Polygon → Polygon → (Polygon, Polygon)
```
SVG images can be simplified to polygons which are made out of points. To morph
between two shapes, we somehow have to transform the points in a source
polygon into the points in a target polygon. Finding a good point correspondence
between two polygons is a tricky thing, though, and it can have a huge impact
on the quality of the morph as seen in this illustration:
Point correspondence algorithms take two polygons (which may have a different
number of points) and align their points so there's an exact one-to-one
correspondence. This may require shuffling, adding, splitting, or merging points.
## 2. Point trajectory
```haskell
type Trajectory = (Polygon, Polygon) → (Double → Polygon)
```
Once the points in the source and target polygons have been aligned, the next
step is to figure out which path they should take. The simplest approach would
be to move the points in a straight line but this doesn't always look right.
The points in the leftmost figure of the following illustration moves in a
straight line while the points in the rightmost figure take a curved path
designed to avoid self-intersections:
The design space for trajectory algorithms is quite large and this article
will cover five different approaches in addition to the simplest straight-line
path.
## 3. Object correspondence
```haskell
type ObjectCorrespondence = [Polygon] → [Polygon] → [(Polygon, Polygon)]
```
## 4. Color interpolation
Morphing between colors is something many libraries don't pay a lot of attention
but there is a fair amount of complexity here and it does deserve consideration.
In short, humans (usually) have three types light sensitive cells that respond
to different ranges of light wavelengths. So, even though the light we see may
contain hundreds of different wavelengths, the eye only notices how much each
of the three types of cells are stimulated and will therefore always reduce
colors to just three numbers.
So far, so good. With three coordinates necessary to specify a color, each color
has a position in a three dimensional space and we can morph between two colors
by going in a straight line. This is where things get tricky, though, because
going in a straight line in the XYZ space (the 3D colorspace defined by the
sensitivity of a typical human's eye) is physically correct but often a bit
counter intuitive. For example, morphing between **blue** and **yellow** will go
through **grey**. Also, the XYZ doesn't take into account how humans perceive
colors (ie. what happens in the brain rather than the eye) and
morphing between two colors with the same perceived brightness will not keep the
brightness a constant. These concerns, and many more, have lead to the
development of different 3D colorspaces, such as CIE LAB, which take human color perception into
account. **Reanimate** has built-in support for several spaces and this
illustration shows how they stack up against each other:
By default, **reanimate** uses the LAB colorspace for morphing colors.
# Linear interpolation
TBD.
# Rotational interpolation
```haskell
rotationalTrajectory :: Origin -> Trajectory
```
# Edge+angle interpolation
```haskell
lineBend :: Trajectory
```
TBD.
# Least-work correspondence
$$
work_{stretch} = k_s\frac{\delta^2}{2L_0}
$$
$$
work_{bend} =
\left\{
\begin{array}{ll}
k_b(\Delta \theta + m_b \Delta \theta^\star)^{e_b}
& \text{if $\theta(t)$ never goes to zero} \\
k_b(\Delta \theta + m_b \Delta \theta^\star)^{e_b} + p_b
& \text{if $\theta(t)$ does go to zero}
\end{array}
\right.
$$
TBD.
# Skeleton
TBD.
# As-rigid-as-possible
TBD.
# Guaranteed intersection-free
TBD.
# Related work
* Flubber
* Polymorph
* raphael
* Kute
* svg_morph
* D3