--- 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. ![](https://i.imgur.com/kmGCh9v.png) 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: ![](https://i.imgur.com/qyoOvuw.png) $$ 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: ![](https://i.imgur.com/IodCaQh.png) - 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}$: ![](https://i.imgur.com/bfgF8vl.png) - 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: ![](https://i.imgur.com/2TwtjYB.png) 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: ![](https://i.imgur.com/6ZiJFxP.png) 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: ![](https://i.imgur.com/hTjBTzF.png) 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)