--- tags: geometry, segments --- # Segmentos ## Definición :::info :information_source: **Definición:** Sean $\vec{a}$ y $\vec{b}$ dos puntos. Definimos al **segmento** de $\vec{a}$ a $\vec{b}$ como $\vec{r} = \vec{a} + t\left(\vec{b} - \vec{a}\right)$, donde $0 \leq t \leq 1$. También podemos escribirlo como $\overrightarrow{ab}$. ::: Básicamente un segmento es el vector de desplazamiento del punto $\vec{a}$ al punto $\vec{b}$, o bien, la recta que pasa por $\vec{a}$ y $\vec{b}$ limitada desde $t=0$ hasta $t=1$. ## Punto pertenece a segmento Sea $\overrightarrow{ab}$ un segmento y $\vec{p}$ un punto. Para verificar si $\vec{p}$ pertenece al segmento, se tienen que cumplir dos condiciones: - Que el punto pertenezca a la recta que pasa por $\vec{a}$ y $\vec{b}$. Ya vimos cómo saber eso: $\overrightarrow{ab} \times \vec{ap} = 0$. - Que el punto esté justamente entre $\vec{a}$ y $\vec{b}$. Para verificar esto vamos a usar el producto punto: de la figura vemos que si $\vec{p}$ está a la izquierda de $\vec{a}$ o a la derecha de $\vec{b}$, entonces $\overrightarrow{pa} \cdot \overrightarrow{pb} > 0$. Por lo tanto, la condición es $\overrightarrow{pa} \cdot \overrightarrow{pb} \leq 0$. ![](https://i.imgur.com/kyyf0Z0.png) Por lo tanto, la función queda como: ```cpp bool pointInSegment(point a, point b, point p){ return (b - a).cross(p - a) == 0 && (a - p).dot(b - p) <= 0; } ``` **Pregunta:** ¿Qué cambio hay que hacer para verificar que $\vec{p}$ esté *estrictamente* en el segmento $\overrightarrow{ab}$, es decir, que no incluya sus extremos? :::spoiler **Respuesta** Cuando $\vec{p}$ coincide con $\vec{a}$ o con $\vec{b}$, se cumple que $\overrightarrow{pa} \cdot \overrightarrow{pb} = 0$. Entonces, hay que cambiar la segunda condición a $\overrightarrow{pa} \cdot \overrightarrow{pb} < 0$. ::: [**Ejemplo interactivo**](https://www.geogebra.org/classic/px4fsnwg) ## Intersección línea-segmento Sea $\vec{r} = \vec{a} + t\vec{v}$ una línea y $\overrightarrow{cd}$ un segmento. Para saber si se intersectan, hay varios casos: - Si ambos son paralelos, es decir, $\vec{v} \times \overrightarrow{cd} = 0$: - El segmento está contenido totalmente en la recta, es decir, $\vec{v} \times \overrightarrow{ac} = 0$. Aquí hay infinitos puntos de intersección. - El segmento no está contenido en la recta, es decir, $\vec{v} \times \overrightarrow{ac} \neq 0$. Aquí no hay puntos de intersección. - Si no son paralelos, es decir, $\vec{v} \times \overrightarrow{cd} \neq 0$, basta ver que $\vec{c}$ esté de un lado de la recta y $\vec{d}$ del otro. O sea, que $\vec{v} \times \overrightarrow{ac}$ y $\vec{v} \times \overrightarrow{ad}$ no tengan el mismo signo. La mplementación queda como: ```cpp int sgn(double x){ if(x > 0) return 1; if(x < 0) return -1; return 0; } int intersectLineSegmentInfo(point a, point v, point c, point d){ point v2 = d - c; double det = v.cross(v2); if(det == 0){ if((c - a).cross(v) == 0){ return -1; //infinity points }else{ return 0; //no point } }else{ return sgn(v.cross(c - a)) != sgn(v.cross(d - a)); // single point (1) or no point (0) } } ``` Notemos que no hace falta una función adicional para obtener el punto de intersección entre la línea y el segmento, pues asumiendo que su intersección es única, la podemos hallar con la función que ya teníamos ``intersectLines()``. [**Ejemplo interactivo**](https://www.geogebra.org/classic/dr7y73fr) ## Intersección de segmentos Sean $\overrightarrow{ab}$ y $\overrightarrow{cd}$ dos segmentos. Para saber si se intersectan hay varios casos: - Si el segmento $\overrightarrow{cd}$ está completamente del mismo lado que $\overrightarrow{ab}$, es decir, $\overrightarrow{ab} \times \overrightarrow{ac}$ y $\overrightarrow{ab} \times \overrightarrow{ad}$ tienen el mismo signo: - Si el signo es cero quiere decir que los dos segmentos son paralelos: hay que revisar si algún segmento contiene un extremo del otro segmento. Si esto ocurre, hay infinitos puntos, si no, no se intersectan. - Si el signo no es cero quiere decir que los segmentos no son paralelos, entonces no hay intersección. - Si el punto $\vec{c}$ está de un lado del segmento $\overrightarrow{ab}$ y el punto $\vec{d}$ está del otro lado, basta con ver lo opuesto: es decir, que el punto $\vec{a}$ esté de un lado del segmento $\overrightarrow{cd}$ y el punto $\vec{b}$ esté del otro lado, o sea, que $\overrightarrow{cd} \times \overrightarrow{ca}$ y $\overrightarrow{cd} \times \overrightarrow{cb}$ no tengan el mismo signo. La implementación queda como: ```cpp int intersectSegmentsInfo(point a, point b, point c, point d){ point v1 = b - a, v2 = d - c; int t = sgn(v1.cross(c - a)), u = sgn(v1.cross(d - a)); if(t == u){ if(t == 0){ if(pointInSegment(a, b, c) || pointInSegment(a, b, d) || pointInSegment(c, d, a) || pointInSegment(c, d, b)){ return -1; //infinity points }else{ return 0; //no point } }else{ return 0; //no point } }else{ return sgn(v2.cross(a - c)) != sgn(v2.cross(b - c)); // single point (1) or no point (0) } } ``` De nuevo, no hace falta una función extra para obtener el punto de intersección entre ambos segmentos, basta con intersectarlos como si fueran líneas en caso de que exista la intersección y sea única. [**Ejemplo interactivo**](https://www.geogebra.org/classic/cmpbw9gt)