---
tags: geometry, circles
---
# Círculos
## Definición
:::info
:information_source: **Definición**: Un **círculo** es el conjunto de puntos que están a la misma distancia de otro punto llamado **centro**. A la distancia común le llamamos **radio**.
:::
- Si $\vec{R}=(x,y)$ es el vector de posición que va dibujando cada punto del círculo, $\vec{c}=(x_0,y_0)$ es el centro y $r > 0$ es el radio, entonces se cumple por definición que $\lVert \vec{R} - \vec{c} \rVert = r$.
- Usando geometría analítica, la ecuación del círculo es $(x-x_0)^2 + (y-y_0)^2 = r^2$.
- De forma paramétrica es $\vec{R} = \vec{c} + r(\cos \theta, \sin \theta) = (x_0 + r\cos \theta, y_0 + r\sin \theta)$, para $0 \leq \theta < 2\pi$.
## Círculo a través de tres puntos
Si tenemos tres puntos no alineados $\vec{M}$, $\vec{N}$ y $\vec{P}$, existe un único círculo que pasa por los tres.

Se puede demostrar que las mediatrices del triángulo $\triangle MNP$ concurren en el centro del círculo. Entonces, para hallarlo:
- El punto medio de $\overrightarrow{MN}$ y un vector perpendicular a $\overrightarrow{MN}$ definen una mediatriz.
- El punto medio de $\overrightarrow{MP}$ y un vector perpendicular a $\overrightarrow{MP}$ definen otra mediatriz.
- La intersección de esas dos líneas es el centro.
- Y para hallar el radio $r$, tomamos la distancia de cualquiera de los puntos $\vec{M}, \vec{N}, \vec{P}$ al centro.
```cpp
pair<point, double> getCircle(point m, point n, point p){
point c = intersectLines((n + m) / 2, (n - m).perp(), (p + m) / 2, (p - m).perp());
double r = (c - m).length();
return {c, r};
}
```
[**Ejemplo interactivo**](https://www.geogebra.org/classic/hmtmez9u)
## Distancia punto-círculo
Si tenemos un círculo con centro en $\vec{C}$ y radio $r$, y un punto $\vec{P}$ afuera del círculo, su mínima distancia al círculo es igual a la distancia al centro menos el radio:

$$
d = \left\lVert \overrightarrow{CP} \right\rVert - r
$$
Lo anterior también nos sirve para determinar si $\vec{P}$ está dentro, fuera o en el perímetro del círculo:
- Si $d > 0$, el punto está afuera.
- Si $d = 0$, el punto está sobre el perímetro del círculo.
- Si $d < 0$, el punto está dentro.
## Tangentes desde punto exterior
Para hallar los puntos de tangencia desde un punto exterior $\vec{P}$ al círculo, hacemos lo siguiente:

- Primero vamos a hallar el vector $\overrightarrow{CP'}$, el cual lleva la misma dirección y sentido que $\overrightarrow{CP}$ pero mide $r$, entonces $\overrightarrow{CP'} = r \hat{CP}$.
- Hallemos el ángulo $\theta$. En la figura se forman dos triángulos rectángulos congruentes, por lo tanto, $\cos \theta = \dfrac{r}{\left\lVert \overrightarrow{CP} \right\rVert }$.
- Finalmente, vemos que si rotamos el vector $\overrightarrow{CP'}$ tanto a la izquierda como a la derecha en un ángulo de $\theta$ alrededor del centro $\vec{C}$, obtenemos los puntos deseados: $\vec{P_1}$ y $\vec{P_2}$.
En código, esto se ve así:
```cpp
pair<point, point> pointsOfTangency(point c, double r, point p){
point v = (p - c).unit() * r;
double cos_theta = r / (p - c).length();
double theta = acos(max(-1.0, min(1.0, cos_theta)));
return {c + v.rotate(-theta), c + v.rotate(theta)};
}
```
[**Ejemplo interactivo**](https://www.geogebra.org/classic/g5v98mcb)
## Intersección círculo-línea
Supongamos que queremos intersectar un círculo con centro $\vec{C}$ y radio $r$ con una línea $\vec{r}=\vec{a}+t\vec{v}$. Hay tres casos posibles: que tengan cero, una o dos intersecciones. En la siguiente figura analizaremos el caso de dos intersecciones en $\vec{P_1}$ y $\vec{P_2}$:

- Primero hallemos el punto $\vec{P}$, que es justamente la proyección de $\vec{C}$ en la recta. El valor de $d$ es la longitud del vector $\overrightarrow{CP}$, es decir, $d = \left\lVert \overrightarrow{CP} \right\rVert$.
- Luego, podemos hallar $h$ con teorema de Pitágoras: $h = \sqrt{r^2-d^2}$.
- Por último, notemos que desde el punto $\vec{P}$ nos podemos mover $h$ unidades hacia abajo o hacia arriba en la dirección de $\vec{v}$ para obtener los puntos deseados $\vec{P_1}$ y $\vec{P_2}$.
```cpp
vector<point> intersectLineCircle(point a, point v, point c, double r){
point p = proj_line(a, v, c);
double d = (p - c).length();
double h = r*r - d*d;
if(h == 0) return {p}; //line tangent to circle
else if(h < 0) return {}; //no intersection
else{
point u = v.unit() * sqrt(h);
return {p - u, p + u}; //two points of intersection (chord)
}
}
```
[**Ejemplo interactivo**](https://www.geogebra.org/classic/uxxwsgae)
## Tangentes comunes entre dos círculos
Tenemos dos círculos $(C_1, r_1)$ y $(C_2, r_2)$ y queremos hallar la(s) línea(s) tangentes a ambos. Hay dos casos:
- Tangentes externas: cuando ambos círculos están del mismo lado de la línea.
- Tangentes internas: cuando ambos círculos están de lados opuestos de la línea.
### Tangentes externas
Consideremos el siguiente diagrama:

Las dos líneas en rojo son las dos tangentes exteriores comunes a ambos círculos, veamos cómo hallarlas (asumiremos por ahora que $r_1 > r_2$):
- Sea $\vec{d}=\overrightarrow{C_1C_2}$ el vector de desplazamiento que une el centro del círculo 1 con el centro del círculo 2. Sea $\vec{d}^\bot$ el vector perpendicular a $\vec{d}$ rotado $90^\circ$ a la izquierda. La idea de esto es formar un sistema de coordenadas ortogonal rotado, cuyos ejes sean $\vec{d}$ y $\vec{d}^\bot$.
- Sean $P_1$ y $P_2$ los puntos de tangencia del círculo 1, y sean $Q_1$ y $Q_2$ los puntos de tangencia del círculo 2. De esta forma, la primer línea está dada al unir $\overline{P_1Q_1}$ y la segunda al unir $\overline{P_2Q_2}$.
- Analicemos la primer línea: desplacémosla hacia abajo en paralelo una distancia $r_2$ hasta que toque $C_2$.
- Vemos que se forma un triángulo rectángulo con vértices en $C_1$, $C_2$ y la proyección de $C_2$ con el segmento $\overrightarrow{C_1P_1}$.
- De ese triángulo ya conocemos la hipotenusa: $\lVert \vec{d} \rVert$, y el cateto de la izquierda: $r_1-r_2$. Sea $h$ el otro cateto, por lo tanto $h=\sqrt{\lVert \vec{d} \rVert^2 - (r_1-r_2)^2}$.
- Para hallar $\theta$ tenemos tres opciones: $\sin \theta = \frac{h}{\lVert \vec{d} \rVert}$, $\cos \theta = \frac{r_1-r_2}{\lVert \vec{d} \rVert}$ y $\tan \theta = \frac{h}{r_1-r_2}$.
- Sea $\hat{v_1}$ el vector unitario que va de $C_1$ a $P_1$. Vemos que forma un ángulo de $\theta$ con el sistema de coordenadas rotado, por lo tanto $\hat{v_1} = \hat{d}\cos\theta + \hat{d}^\bot\sin\theta$. Simplificando: $\displaystyle \hat{v_1} = \frac{\vec{d}}{\lVert \vec{d} \rVert} \left( \frac{r_1-r_2}{\lVert \vec{d} \rVert} \right) + \frac{\vec{d}^\bot}{\lVert \vec{d} \rVert} \left( \dfrac{h}{\lVert \vec{d} \rVert} \right) = \dfrac{(r_1-r_2)\vec{d} + h\vec{d}^\bot}{\left\lVert \vec{d} \right\rVert^2}$
- De esa forma, $P_1=C_1 + r_1\hat{v_1}$. Por simetría en el segundo círculo, $Q_1=C_2+r_2\hat{v_1}$.
- Para hallar la recta tangente de abajo, sea $\hat{v_2}$ el vector unitario que une $C_1$ con $P_2$. Vemos que forma un ángulo de $-\theta$ respecto al sistema de coordenadas rotado, por lo tanto: $\hat{v_2} = \hat{d}\cos(-\theta) + \hat{d}^\bot\sin(-\theta) = \hat{d}\cos\theta - \hat{d}^\bot\sin\theta = \dfrac{(r_1-r_2)\vec{d} - h\vec{d}^\bot}{\left\lVert \vec{d} \right\rVert^2}$.
- Finalmente, $P_2=C_1+r_1\hat{v_2}$ y $Q_2=C_2+r_2\hat{v_2}$.
Preguntas:
- ¿Qué pasa si $r_1 \leq r_2$?
- ¿Qué pasa si $r_2=0$?
:::spoiler **Respuestas**
- El análisis sigue funcionando correctamente, y se ve que $\theta$ formaría un ángulo mayor o igual a $90^\circ$.
- El segundo círculo se reduce a un punto (su centro), por lo tanto se reduce al problema de tangentes desde punto exterior.
:::
### Tangentes internas
Consideremos el siguiente diagrama:

Nombremos de forma similar los puntos y vectores que en el caso anterior.
Consideremos la recta tangente interna que une $\overline{P_1Q_1}$. Vemos ahora que la vamos subir (a diferencia de bajarla en el caso anterior) $r_2$ unidades hacia arriba hasta que toque $C_2$. El triángulo rectángulo que se forma sigue teniendo hipotenusa $\lVert \vec{d} \rVert$, pero ahora el cateto izquierdo mide $r_1+r_2$.
A partir de aquí el resto de los cálculos sigue idéntico que en el caso anterior, con excepción de que ahora tenemos $r_2$ en lugar de $-r_2$. Eso quiere decir que podemos programar la función para hallar tangentes externas, y para las internas, solo seteamos $r_2 := -r_2$ al principio y procedemos de la misma forma.
Casos especiales:
- Si los círculos son concéntricos, es decir, $\vec{d}=\vec{0}$, consideramos que no hay tangentes comunes.
- Si $\left\lVert \vec{d} \right\rVert^2 < (r_1-r_2)^2$:
- Si estamos en el caso de tangentes exteriores quiere decir que el segundo círculo está estrictamente dentro del primero, por lo que no hay tangentes externas comunes.
- Si estamos en el caso de tangentes interiores quiere decir que ambos círculos se intersectan en dos puntos distintos, por lo que no hay tangentes internas comunes.
- Si $\left\lVert \vec{d} \right\rVert^2 = (r_1-r_2)^2$:
- Si estamos en el caso de tangentes exteriores quiere decir que el segundo círculo está dentro del primero y lo toca en un punto, por lo que solo hay una tangente exterior común que justamente pasa por ese punto.
- Si estamos en el caso de tangentes interiores quiere decir que ambos círculos se están *besando* por fuera, o sea, se tocan en un solo punto y ninguno está dentro de otro, por lo que solo hay una tangente interior común que pasa por ese punto.
La implemetación queda como:
```cpp
vector<vector<point>> tangents(point c1, double r1, point c2, double r2, bool inner){
//returns a vector of segments or a single point
if(inner) r2 = -r2;
point d = c2 - c1;
double dr = r1 - r2, d2 = d.norm(), h2 = d2 - dr*dr;
if(d2 == 0 || h2 < 0) return {};
point v = d*dr/d2;
if(h2 == 0) return {{c1 + v*r1}};
else{
point u = d.perp()*sqrt(h2)/d2;
return {{c1 + (v - u)*r1, c2 + (v - u)*r2}, {c1 + (v + u)*r1, c2 + (v + u)*r2}};
}
}
```
[**Ejemplo interactivo**](https://www.geogebra.org/classic/qccdhgwt)
## Intersección círculo-círculo
Sean dos círculos $(C_1, r_1)$ y $(C_2, r_2)$, queremos hallar sus puntos de intersección, que pueden ser 0, 1, o 2. Analicemos el caso cuando hay 2 puntos de intersección:

Sea $\vec{d}=\overrightarrow{C_1C_2}$ el vector de desplazamiento que une ambos centros. De nuevo vamos a construir un sistema de ejes ortogonal a partir de $\vec{d}$ y $\vec{d}^\bot$.
Sean $P_1$ y $P_2$ los dos puntos de intersección, el segmento que los une será perpendicular al vector $\vec{d}$. Veamos el triángulo $\triangle P_1 C_1 C_2$: necesitamos hallar el ángulo $\theta$, el cuál se puede obtener con ley de cosenos: $\cos \theta = \dfrac{\left\lVert \vec{d} \right\rVert^2 + r_1^2 - r_2^2}{2 \left\lVert \vec{d} \right\rVert r_1}$.
Sea $\hat{v_1}$ el vector unitario que va de $C_1$ a $P_1$, vemos que forma un ángulo de $\theta$ con el vector $\vec{d}$ en el sistema de ejes ortogonal, por lo tanto $\hat{v_1} = \hat{d} \cos \theta + \hat{d}^\bot \sin \theta$. De forma similar, el vector unitario $\hat{v_2}$ que va de $C_1$ a $P_2$ se puede expresar como $\hat{v_2}=\hat{d}\cos\theta - \hat{d}^\bot\sin\theta$.
Finalmente, $P_1 = C_1 + r_1\hat{v_1}$ y $P_2 = C_1 + r_1\hat{v_2}$. Para evitar usar funciones trigonométricas, podemos simplificar aún más:
$$
\begin{align}
P_{1,2} &= C_1 + r_1 \dfrac{\vec{d}}{\left\lVert \vec{d} \right\rVert} \left( \dfrac{\left\lVert \vec{d} \right\rVert^2 + r_1^2 - r_2^2}{2 \left\lVert \vec{d} \right\rVert r_1}\right ) \pm r_1 \dfrac{\vec{d}^\bot}{\left\lVert \vec{d} \right\rVert} \left( \dfrac{\sqrt{\left( 2 \left\lVert \vec{d} \right\rVert r_1 \right)^2 - \left( \left\lVert \vec{d} \right\rVert^2 + r_1^2 - r_2^2 \right)^2}}{2 \left\lVert \vec{d} \right\rVert r_1} \right) \\
&= C_1 + \left( \dfrac{\left\lVert \vec{d} \right\rVert^2 + r_1^2 - r_2^2}{2 \left\lVert \vec{d} \right\rVert^2} \right) \vec{d} \pm \left( \dfrac{\sqrt{\left( 2 \left\lVert \vec{d} \right\rVert r_1 \right)^2 - \left( \left\lVert \vec{d} \right\rVert^2 + r_1^2 - r_2^2 \right)^2}}{2 \left\lVert \vec{d} \right\rVert^2} \right) \vec{d}^\bot
\end{align}
$$
La implementación queda como:
```cpp
vector<point> intersectionCircles(point c1, double r1, point c2, double r2){
//circle 1 with center c1 and radius r1
//circle 2 with center c2 and radius r2
point d = c2 - c1;
double d2 = d.norm();
if(d2 == 0) return {}; //concentric circles
double pd = (d2 + r1*r1 - r2*r2) / 2;
double h2 = r1*r1 - pd*pd/d2;
point p = c1 + d*pd/d2;
if(h2 == 0) return {p}; //circles touch at one point
else if(h2 < 0) return {}; //circles don't intersect
else{
point u = d.perp() * sqrt(h2/d2);
return {p - u, p + u};
}
}
```
[**Ejemplo interactivo**](https://www.geogebra.org/classic/t89zuqsw)