<p>You can exactly find the distance to a 2D ellipse using the signed distance function of an ellipse. Here is one by iq on shadertoy:</p>
<p><a href="https://www.shadertoy.com/view/4sS3zz" rel="nofollow noreferrer">https://www.shadertoy.com/view/4sS3zz</a></p>
<p>Then a scale invariant way of generating the gradient can be achieved by adding before the last fragColor statement in mainImage():</p>
<pre><code>col = vec3(0.0);
float gradientWidth = 0.1;
if(abs(d) &lt; gradientWidth) {
    //col = vec3(1.0) * (1.0 - smoothstep(0.0, 1.0, abs(d) / gradientWidth)); //use this for smooth gradient
    col = vec3(1.0) * (1.0 - (abs(d) / gradientWidth));
}
</code></pre>

CC BY-SA 4.0
2024-05-07T15:59:56.297Z
wow, what a nice page. And wow that there is actually an analytic solution. Thousand times faster to solutions I found but still using some slow trigonometry and root functions. However there are also links to approximative solutions not using any trigonometry. (Points need to be rotated by $\theta$ and translated by $x_\circ,y_\circ$).
Will need to test which is actually the fastest. Will mark this as answer. Thank you! If someone posts some faster/better way (e.g. some filter?) I can change it again.
UncleBob
CC BY-SA 4.0
2024-05-07T11:59:11.120Z
2024-05-07T17:59:14.153Z
2024-05-07T17:59:14.153Z
Reynolds
<p>The goal is to generate a picture like this:</p>
<p><a href="https://i.sstatic.net/tq85kGyf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/tq85kGyf.png" alt="ellipse with gradient" /></a></p>
<p>A symmetric color gradient around an ellipse which is rotated by <span class="math-container">$\theta$</span>, has <span class="math-container">$(x_\circ,y_\circ)$</span> as center and and major and an minor axis <span class="math-container">$a,b$</span>.<br>
The total line width should be invariant to changes in those parameters.</p>
<p>It was done by using the implicit ellipse equation with different axis offsets <span class="math-container">$h$</span> from <span class="math-container">$-d$</span> to <span class="math-container">$d$</span> with step size of 1 pixel. So total line width is <span class="math-container">$2d$</span>.</p>
<p><span class="math-container">$$L_{h} = A_{h}x^2 + B_{h}xy + C_{h}y^2 + D_{h}x + E_{h}y + F_{h} = 0$$</span></p>
<p>with
<span class="math-container">$$  A_{h} =   (a+h)^2 \sin^2\theta + (b+h)^2 \cos^2\theta $$</span>
<span class="math-container">$$  B_{h} =  2\left((b+h)^2 - (a+h)^2\right) \sin\theta \cos\theta $$</span>
<span class="math-container">$$  C_{h} =   (a+h)^2 \cos^2\theta + (b+h)^2 \sin^2\theta $$</span>
<span class="math-container">$$  D_{h} = -2A_{h} x_\circ   -  B_{h} y_\circ $$</span>
<span class="math-container">$$  E_{h} = - B_{h} x_\circ   - 2C_{h} y_\circ $$</span>
<span class="math-container">$$  F_{h} =   A_{h} x_\circ^2 +  B_{h} x_\circ y_\circ + C_{h} y_\circ^2 - (a+h)^2 (b+h)^2 $$</span></p>
<p>We first check if <span class="math-container">$L_0$</span> is below (means inside the ellipse) or greater (means outside the ellipse) than <span class="math-container">$0$</span>. If greater we check if <span class="math-container">$L_d$</span> is greater or smaller <span class="math-container">$0$</span>. If smaller we check it with <span class="math-container">$h = \frac{d}{2}$</span>. If it is smaller than this we check it for <span class="math-container">$h = \frac{d}{4}$</span>. If bigger we check for <span class="math-container">$h = \frac{d}{2} + \frac{d}{4}$</span>.
And so on.<br></p>
<p>With this we can compute an approximation of the distance with the step size as unit. (note: this is not the shortest point to ellipse edge distance even for very small steps but it's very close to) <br>
This requires <span class="math-container">$O(\log_2(d))$</span> checks per pixel.</p>
<p>Calculating the real distance seems to be require an equation solver for each pixel or solving a quatric equation (degree of 4) with results of thousands of operations.</p>
<hr />
<p><strong>Can we do any quicker?</strong><br>
For example applying a filter on a ellipse without gradient. How would the math about it look like?<br>
Or can we approximate the distance?<br>
Or something else?<br></p>
<hr />
<p><em>More details:</em><br>
Will be used for many ellipses with different arbitrary parameter <span class="math-container">$\theta, (x_\circ,y_\circ), a ,b$</span>.<br>
My related math stack threads: <a href="https://math.stackexchange.com/questions/4904334">about inner and outer boundary</a>, <a href="https://math.stackexchange.com/questions/4905496">about distance point to ellipse</a>, <a href="https://math.stackexchange.com/questions/4911364">about quick calculation of gradient</a></p>

<mathematics><computational-geometry><image-processing><filtering><gradient>
Is there a quicker way to draw a symmetric, scale-invariant (declining color) gradient around an ellipse?
UncleBob
# Is there a quicker way to draw a symmetric, scale-invariant (declining color) gradient around an ellipse?

(Asked by: username_0 on 2024-05-06)

The goal is to generate a picture like this:

[![ellipse with gradient](https://i.sstatic.net/tq85kGyf.png)](https://i.sstatic.net/tq85kGyf.png)

A symmetric color gradient around an ellipse which is rotated by $\theta$, has $(x\_\circ,y\_\circ)$ as center and and major and an minor axis $a,b$.  
The total line width should be invariant to changes in those parameters.

It was done by using the implicit ellipse equation with different axis offsets $h$ from $-d$ to $d$ with step size of 1 pixel. So total line width is $2d$.

$$L\_{h} = A\_{h}x^2 + B\_{h}xy + C\_{h}y^2 + D\_{h}x + E\_{h}y + F\_{h} = 0$$

with
$$ A\_{h} = (a+h)^2 \sin^2\theta + (b+h)^2 \cos^2\theta $$
$$ B\_{h} = 2\left((b+h)^2 - (a+h)^2\right) \sin\theta \cos\theta $$
$$ C\_{h} = (a+h)^2 \cos^2\theta + (b+h)^2 \sin^2\theta $$
$$ D\_{h} = -2A\_{h} x\_\circ - B\_{h} y\_\circ $$
$$ E\_{h} = - B\_{h} x\_\circ - 2C\_{h} y\_\circ $$
$$ F\_{h} = A\_{h} x\_\circ^2 + B\_{h} x\_\circ y\_\circ + C\_{h} y\_\circ^2 - (a+h)^2 (b+h)^2 $$

We first check if $L\_0$ is below (means inside the ellipse) or greater (means outside the ellipse) than $0$. If greater we check if $L\_d$ is greater or smaller $0$. If smaller we check it with $h = \frac{d}{2}$. If it is smaller than this we check it for $h = \frac{d}{4}$. If bigger we check for $h = \frac{d}{2} + \frac{d}{4}$.
And so on.

With this we can compute an approximation of the distance with the step size as unit. (note: this is not the shortest point to ellipse edge distance even for very small steps but it's very close to)   
This requires $O(\log\_2(d))$ checks per pixel.

Calculating the real distance seems to be require an equation solver for each pixel or solving a quatric equation (degree of 4) with results of thousands of operations.

---

**Can we do any quicker?**  
For example applying a filter on a ellipse without gradient. How would the math about it look like?  
Or can we approximate the distance?  
Or something else?

---

*More details:*  
Will be used for many ellipses with different arbitrary parameter $\theta, (x\_\circ,y\_\circ), a ,b$.  
My related math stack threads: [about inner and outer boundary](https://math.stackexchange.com/questions/4904334), [about distance point to ellipse](https://math.stackexchange.com/questions/4905496), [about quick calculation of gradient](https://math.stackexchange.com/questions/4911364)

**Tags:** mathematics, computational-geometry, image-processing, filtering, gradient


---

## 1 answers

### Answer by username_1 on 2024-05-07. Score: 3 | Accepted answer

You can exactly find the distance to a 2D ellipse using the signed distance function of an ellipse. Here is one by iq on shadertoy:

<https://www.shadertoy.com/view/4sS3zz>

Then a scale invariant way of generating the gradient can be achieved by adding before the last fragColor statement in mainImage():

```
col = vec3(0.0);
float gradientWidth = 0.1;
if(abs(d) < gradientWidth) {
    //col = vec3(1.0) * (1.0 - smoothstep(0.0, 1.0, abs(d) / gradientWidth)); //use this for smooth gradient
    col = vec3(1.0) * (1.0 - (abs(d) / gradientWidth));
}

```

> **Comments:**
> **username_0**: wow, what a nice page. And wow that there is actually an analytic solution. Thousand times faster to solutions I found but still using some slow trigonometry and root functions. However there are also links to approximative solutions not using any trigonometry. (Points need to be rotated by $\theta$ and translated by $x_\circ,y_\circ$). Will need to test which is actually the fastest. Will mark this as answer. Thank you! If someone posts some faster/better way (e.g. some filter?) I can change it again.  

---

