diff --git a/docs/Basics/Stamp/Stamp.mdx b/docs/Basics/Stamp/Stamp.mdx
index fd0ee74..68c77c2 100644
--- a/docs/Basics/Stamp/Stamp.mdx
+++ b/docs/Basics/Stamp/Stamp.mdx
@@ -117,7 +117,7 @@ $$
Remind that $\cos\theta = (r_0 - r_1)/L$.
Applying the formula for solving quadratic equations,
two roots of the equation are the X value of min and max points of the segment.
-Therefore, we know the range in the fragment shader and pixels only loop through stamps that can cover it.
+Therefore, we know the range in the fragment shader, and pixels only loop through stamps that can cover it.
import StampRound from "./StampRound";
diff --git a/docs/Proportional-Interval-Stamp/Proportional-Interval-Stamp.mdx b/docs/Proportional-Interval-Stamp/Proportional-Interval-Stamp.mdx
index 9478fc4..ae98bd0 100644
--- a/docs/Proportional-Interval-Stamp/Proportional-Interval-Stamp.mdx
+++ b/docs/Proportional-Interval-Stamp/Proportional-Interval-Stamp.mdx
@@ -103,13 +103,13 @@ With varying radius values, which one should be used to calculate the interval?
Perhaps the maximum radius of a stroke?
It's a reasonable compromise.
I did it in Ciallo's paper when conducting performance tests (and it seems I forgot about mentioning it).
-In a paint program like Krita, the user-specified stroke size, as shown in the figure above, is the perfect choice.
+A perfect choice is to use a user-specified stroke size when painting, as shown in the figure above of Krita.
But outside a paint program, it's not easy to get a user-specified radius value.
-A better solution is to let the stamp interval vary along with the stroke radius.
+A once-and-for-all solution is to let the stamp interval vary along with the stroke radius.
### Proportional interval
-We will learn how to render the "Proportional interval" stroke shown in the figure below.
+We will learn how to render a "Proportional interval" stroke shown in the figure below.
Its interval is not fixed but vary along with the stroke radius.
Meanwhile, the interval is always proportional to the radius.
@@ -239,19 +239,23 @@ Additionally, to determine $n_0$ and $n_1$, we can compute the prefix sum of the
Put them into vertex data and pass them into fragment shader, exactly same as the value `length` in the Stamp section.
## Implementation
-You can verify the correctness of code by changing the variable `intervalRatio`:
+You can validate the code by changing the variable `intervalRatio`:
import Stroke from "./ProportionalStampStroke";
**Zero division:**
-It's common for strokes to have zero radii at their starting or ending vertices.
+It's common for a stroke to have zero radii at their starting or ending vertices.
When either $r_0$ or $r_1$ is zero, the value in formula (3) can approach infinity.
This will bring numeric errors, which we surely want to avoid.
-A simple solution is to add a small number to the radii, as shown in the code above.
+A simple solution is to add a small number to the radii, as demoed in the code above.
For a more rigorous approach, you can implement checks to prevent $r_0/r_1$ in the logarithm from becoming zero or excessively large.
+Also, it's worth noting that if calculating the prefix sum value of $n(L)$ with CPU,
+maybe you want to push $\eta$ times $n(L)$, $\eta n(L)$ instead of $n(L)$ itself into vertex buffer.
+Because $\eta$ is a value changed more frequently, you won't want to recompute the prefix sum every time it changes.
+
## 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".
@@ -290,10 +294,10 @@ This explains why we perceive a consistent appearance.
Let's derive these isocolor lines.
In the figure below, draw a radius across $P$ to intersect the edge at the point $Q$.
-We label this radius's length as $r_q$, and define a ratio value $\lambda$ that makes the distance between $P$ and $Q$ is equal to $\lambda r_q$.
+We label this radius's length as $r_p$, and define a ratio value $\lambda$ that makes the distance between $P$ and $Q$ is equal to $\lambda r_p$.
$$
-\lambda \vcentcolon = \frac{|PQ|}{r_q}
+\lambda \vcentcolon = \frac{|PQ|}{r_p}
$$
![proof-number](./proof-number.png)
@@ -309,12 +313,18 @@ n(x_2) - n(x_1)
{1-\cos^2\theta\lambda - \sqrt{(1-\cos^2\theta)(1 - 2\cos^2\theta\lambda + \cos^2\theta\lambda^2)}}
\end{aligned}
$$
-To simplify a little bit:
-$$
- = \frac{1}{\eta \cos\theta} \ln\frac
-{1-\lambda + \tan^2\theta + \tan\theta\sqrt{\tan^2\theta + (1-\lambda)^2}}
-{1-\lambda + \tan^2\theta - \tan\theta\sqrt{\tan^2\theta + (1-\lambda)^2}}
-$$
+
+[//]: # (To simplify a little bit:)
+
+[//]: # ($$)
+
+[//]: # ( = \frac{1}{\eta \cos\theta} \ln\frac)
+
+[//]: # ({1-\lambda + \tan^2\theta + \tan\theta\sqrt{\tan^2\theta + (1-\lambda)^2}})
+
+[//]: # ({1-\lambda + \tan^2\theta - \tan\theta\sqrt{\tan^2\theta + (1-\lambda)^2}})
+
+[//]: # ($$)
While the result may appear complex, it's worth noting that it only depends on $\theta$, $\lambda$, and is inversely proportional to $\eta$.
This suggests that at any point in a given edge, the number of stamps that can cover it only depends on $\lambda$.
@@ -330,22 +340,50 @@ $$
(Directly using $n(x_2) - n(x_1) = \int_{x_1}^{x_2} \frac{dx}{\eta r(x)} $ makes it easier.)
So, we only need to find the value of $\frac{r(x_1)}{r(x_2)}$.
-It would be very tedious to directly compute $x_1$ and $x_2$.
-I will introduce a tricky geometric method (I spent a whole evening to find it):
-
-Refer to the figure "_Radius across point $P$ and $Q$_".
-Notice $|PX_2| = r(x_2)$ and $|QX_2| = \cos\theta(r_q - r(x_2))$.
-Apply the law of cosines on $\angle PQX_2$, we can derive a quadratic equation with variable $\frac{r(x_2)}{r_q}$.
-Also apply the law of cosines on $\angle PQX_1$,
-we can derive an identical quadratic equation with variable $\frac{r(x_1)}{r_q}$.
-Two roots of this quadratic equation are $\frac{r(x_1)}{r_q}$ and $\frac{r(x_2)}{r_q}$,
+It would be very complicated to directly compute $r(x_1)$ and $r(x_2)$.
+I will introduce a geometric method:
+
+![solve](solve.png)
+Notice $|PX_2| = r(x_2)$ and $|QX_2| = \cos\theta(r_p - r(x_2))$.
+Apply the law of cosines on $\angle PQX_2$, we can derive a quadratic equation with variable $\frac{r(x_2)}{r_p}$.
+Also apply law of cosines on $\angle PQX_1$,
+we can derive an identical quadratic equation with variable $\frac{r(x_1)}{r_p}$.
+Two roots of this quadratic equation are $\frac{r(x_1)}{r_p}$ and $\frac{r(x_2)}{r_p}$,
their ratio is $\frac{r(x_1)}{r(x_2)}$.
-Computing the roots of quadratic equation is why we have a big block of sqrt with $\pm$ sign in the result.
+Computing the roots of quadratic equation is the reason we have a big block of sqrt with $\pm$ signs in the result.
If you are interested in more details about the solving process, check the drop-down tab below.
-
-Proof details
+
+ Proof details
+
+ To simplify the notations, set $|QX_1| = l_1$, $|QX_2| = l_2$, $r_{x_1} = r(x_1)$ $r_{x_2} = r(x_2)$.
+ It's easy to get:
+
+ $$
+ l_2 = \frac{r_p - r_{x_2}}{\cos\theta}
+ $$
+
+ Apply the law of cosines to $\angle PQX_2$, we get:
+ $$
+ l_2^2 + \lambda^2r_p^2 - r_{x_2}^2 - 2l_2\lambda r_p \cos\theta = 0
+ $$
+
+ Substitute $l_2$ into it, we will get a quadratic equation with variable $r_p$ and $r_{x_2}$.
+ Additionally, you can verify after applying the law of cosines to $\angle PQX_1$ and substituting $l_1$, we get an identical quadratic equation.
+
+ So, we discard the subscript $_1$ and $_2$ and simplify the quadratic equation:
+ $$
+ \underbrace{(1-\cos^2\theta)}_{a}r_x^2
+ \underbrace{- 2(1-\cos^2\theta\lambda)}_{b}r_xr_p
+ + \underbrace{(1 - 2\cos^2\theta + \cos^2\theta\lambda^2)}_{c}r_p^2 = 0
+ $$
+
+ Divide the equation by $r_p^2$, its two roots are $r_{x_1}/r_p$ and $r_{x_2}/r_p$.
+ We only need to know about $r_{x_1}/r_{x_2}$:
+ $$
+ \frac{r_{x_1}}{r_{x_2}} = \frac{-b + \sqrt{b^2 - 4ac}}{-b - \sqrt{b^2 - 4ac}}
+ $$
-Working in progress. Franky speaking, I'm kind of lazy on this. It's not fun to write.
+ You verify the result after substituting $a, b, c$.
diff --git a/docs/Proportional-Interval-Stamp/solve.png b/docs/Proportional-Interval-Stamp/solve.png
new file mode 100644
index 0000000..a53cea3
Binary files /dev/null and b/docs/Proportional-Interval-Stamp/solve.png differ