Skip to content

Commit

Permalink
Ratio interval half way 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
ShenCiao committed Sep 1, 2024
1 parent ab1bb0c commit 4692c68
Showing 1 changed file with 63 additions and 17 deletions.
80 changes: 63 additions & 17 deletions docs/Proportional-Interval-Stamp/Proportional-Interval-Stamp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -175,28 +175,28 @@ and we already know the radius at a segment $r(x) = r_0 - \cos\theta x$.

We need the stamp interval to be proportional to radius.
Therefore, for each segment, define the stamp interval as $\eta r(x)$.
To find the number of stamps $\Delta N$ in a segment, divide the length by the interval:
To find the number of stamps $\Delta n$ in a segment, divide the length by the interval:

$$
\Delta n = \frac{\Delta x}{\eta r(x)}
$$

To find the number of stamps $\Delta n$ over the edge, we need to integrate $\Delta n$ from 0 to x.
To find the number of stamps $\Delta n$ over the edge, integrate $\Delta n$ from 0 to x.

$$
n(x) = \int_0^{x} \frac{dx}{\eta r(x)}
$$

Given $r(x) = r_0 - \cos\theta x$, we substitute this into the integral and get:
Given $r(x) = r_0 - \cos\theta x$, substitute it into the integral and get:

$$
\tag{1} n(x) = \frac{1}{\eta \cos\theta} \ln(r_0 - \cos\theta x) \bigg|_0^x = \frac{1}{\eta \cos\theta} \ln (1 - \frac{\cos\theta x}{r_0})
\tag{1} n(x) = -\frac{1}{\eta \cos\theta} \ln(r_0 - \cos\theta x) \bigg|_0^x = -\frac{1}{\eta \cos\theta} \ln (1 - \frac{\cos\theta x}{r_0})
$$

Exchange the dependent and independent variable in formula (1) and get:

$$
\tag{2} x(n) = \frac{r_0}{\cos\theta}(1 - e^{\eta\cos\theta n})
\tag{2} x(n) = \frac{r_0}{\cos\theta}(1 - e^{-\eta\cos\theta n})
$$

As $x = L$, we know the total stamp number on the edge, remind that $\cos\theta L = r_0-r_1$:
Expand All @@ -205,21 +205,67 @@ $$
\tag{3} n(L) = \frac{1}{\eta \cos\theta}\ln \frac{r_0}{r_1}
$$

Soon we will use the formula (1)(2)(3) in our code.
We will soon use the formula (1)(2)(3) in our code.

![store](store-n.png)

How do we place footprint on the polyline?
How do we place footprints?
Imagine a point starts from the first vertex and moves along the polyline.
The stamp number to the first vertex grows with its movement.
Every time the number hits an integer, we place a footprint at this point.
Its stamp index (number of stamps from the first vertex) $n$ grows with its movement.
Each time this index hits an integer, place a footprint at that point.

Remind the figure below in the Stamp section.
Given a point or pixel, we calculate a range on the edge that can cover the point.
We label the two roots with $x_1$ and $x_2$.
Remind the below figure in the Stamp section.
Given a point, we calculate a range on the edge that can cover the point by solving a quadratic equation.
Label the two roots with $x_1$ and $x_2$.

![locate stamp](./locate-stamp.png)

With the stamp number of each edge $n(L)$, we can prefix sum $n(L)$ the number of stamps from each vertex to the first vertex.
We will store the number into each vertex.
For the current edge, we use $n_0$ and $n_1$ to indicate the stamp number at vertex0 and vertex1.
To calculate the nearest stamp point (the black dot in the figure) between $x_1$ and $x_2$,
we need to compute the number of stamps from $x_1$ to the polyline's first vertex, which is also called stamp index at $x_1$.
According to formula (1), on the current edge, the number of stamps from vertex0 to $x_1$ is $n(x_1)$.
Label the stamp index of vertex0 as $n_0$, and label vertex1's as $n_1$.

![store](./store-n.png)

Therefore, the stamp index of $x_1$ is $n_0 + n(x_1)$.
Because we place footprints at the points with integer stamp index,
the ceiling of $n_0 + n(x_1)$ is the nearest stamp's index,
denoted as $n_\mathrm{nearest} = \lceil n_0 + n(x_1) \rceil$.
Replace it into the formula (2) to get its position $x_{\mathrm{nearest}} = x(\lceil n_0 + n(x_1) \rceil)$,
and all other positions $x(n_\mathrm{nearest} + 1)$, $x(n_\mathrm{nearest} + 2) \dots$

Additionally, to determine $n_0$ and $n_1$, we can compute the prefix sum of the $n(L)$ in formula (3) over all edges.
Put them into vertex data and pass them into fragment shader, exactly same as the value `length` in the Stamp section.

## Implementation

## Corner case

## Proof of properties
In the Stamp Pattern subsection, we claim that "stamp interval is always proportional to radius of stroke" and
"proportional interval has more consistent appearance".
Though they are intuitively correct, it's time to prove them mathematically!

### Proportional interval
**Conclusion:**
Pick two consecutive footprints on an edge.
Label their stamp indices as $n$ and $n+1$, positions as $x(n)$ and $x(n+1)$, radii as $r(n)$ and $r(n+1)$.
Their interval $x(n+1) - x(n)$ is proportional to both $r(n)$ and $r(n+1)$:
$$
\begin{aligned}
\frac{x(n+1) - x(n)}{r(n)} &= \frac{1 - e^{-\eta\cos\theta}}{\cos\theta}\\
\frac{x(n+1) - x(n)}{r(n+1)} &= \frac{e^{\eta\cos\theta} - 1}{\cos\theta}
\end{aligned}
$$

**Proof:**
Take the formula (3) into $r(x) = r_0 - \cos\theta x$ to get $r(n) = r_0e^{-\eta\cos\theta n}$.
The rest of proof is straightforward.

Notice the ratios do not depend on variable $n$.
I was amazed by this result.
Even now, it still fascinates me that how a naive rule (interval is proportional to the radius continuously) can produce an elegant result.

### Consistent appearance
**Conclusion:**
For points that have the same stamp number that can cover it (i.e., $n(x_2) - n(x_1)$ value is the same),
they form a straight line.
I call this line "isocolor" line (analogy to "isoheight" line).

0 comments on commit 4692c68

Please sign in to comment.