Estoy buscando un algoritmo para detectar si dos rectángulos se cruzan (uno en un ángulo arbitrario, el otro con solo líneas verticales / horizontales).
Prueba si una esquina de uno está en el otro casi funciona. Falla si los rectángulos forman una forma de cruz.
Parece una buena idea evitar el uso de pendientes de las líneas, lo que requeriría casos especiales para las líneas verticales.
Respuestas:
El método estándar sería hacer la prueba del eje de separación (hacer una búsqueda en Google sobre eso).
En breve:
Lo divertido es que basta con verificar todos los bordes de los dos rectángulos. Si los rectángulos no se superponen, uno de los bordes será el eje de separación.
En 2D puedes hacer esto sin usar pendientes. Un borde se define simplemente como la diferencia entre dos vértices, p. Ej.
Puede obtener una perpendicular a esto girándola 90 °. En 2D esto es fácil como:
Entonces no hay trigonometría o pendientes involucradas. Tampoco se requiere normalizar el vector a la longitud de la unidad.
Si desea probar si un punto está en uno u otro lado de la línea, puede usar el producto de puntos. el letrero te dirá de qué lado estás:
Ahora pruebe todos los puntos del rectángulo A contra los bordes del rectángulo B y viceversa. Si encuentra un borde de separación, los objetos no se cruzan (siempre y cuando todos los demás puntos en B estén en el otro lado del borde que se está probando, vea el dibujo a continuación). Si no encuentra un borde de separación, los rectángulos se cruzan o un rectángulo está contenido en el otro.
La prueba funciona con cualquier polígono convexo por cierto.
Enmienda: para identificar un borde de separación, no es suficiente probar todos los puntos de un rectángulo contra cada borde del otro. El borde candidato E (abajo) se identificaría como un borde de separación, ya que todos los puntos en A están en el mismo semiplano de E. Sin embargo, no es un borde de separación porque los vértices Vb1 y Vb2 de B también están en ese medio plano. Solo habría sido un borde de separación si ese no hubiera sido el caso http://www.iassess.com/collision.png
fuente
Básicamente mira la siguiente imagen:
Si las dos cajas chocan, las líneas A y B se superpondrán.
Tenga en cuenta que esto tendrá que hacerse tanto en el eje X como en el eje Y, y ambos deben superponerse para que los rectángulos colisionen.
Hay un buen artículo en gamasutra.com que responde a la pregunta (la imagen es del artículo). Hice un algoritmo similar hace 5 años y tengo que encontrar mi fragmento de código para publicarlo aquí más tarde
Enmienda : El teorema del eje de separación establece que dos formas convexas no se superponen si existe un eje de separación (es decir, uno donde las proyecciones como se muestra no se superponen). Entonces "existe un eje de separación" => "Sin superposición". Esto no es una implicación doble, por lo que no puede concluir lo contrario.
fuente
La respuesta de m_pGladiator es correcta y lo prefiero. La prueba de eje de separación es el método más simple y estándar para detectar la superposición de rectángulos. Una línea para la cual los intervalos de proyección no se superponen, llamamos un eje de separación . La solución de Nils Pipenbrinck es demasiado general. Utiliza el producto de puntos para verificar si una forma está totalmente en un lado del borde del otro. Esta solución en realidad podría inducir a polígonos convexos de borde n. Sin embargo, no está optimizado para dos rectángulos.
El punto crítico de la respuesta de m_pGladiator es que debemos verificar la proyección de dos rectángulos en ambos ejes (x e y). Si dos proyecciones se superponen, entonces podríamos decir que estos dos rectángulos se superponen. Entonces, los comentarios anteriores a la respuesta de m_pGladiator son incorrectos.
para la situación simple, si no se giran dos rectángulos, presentamos un rectángulo con estructura:
Nombramos el rectángulo A, B con rectA, rectB.
Si se gira cualquiera de los dos rectángulos, es posible que se necesiten algunos esfuerzos para determinar su proyección en los ejes x e y. Defina la estructura RotatedRect de la siguiente manera:
la diferencia es cómo el ancho 'ahora es un poco diferente: anchoA' para rectA:
Math.sqrt(rectA.width*rectA.width + rectA.height*rectA.height) * Math.cos(rectA.angle)
anchoB 'para rectB:Math.sqrt(rectB.width*rectB.width + rectB.height*rectB.height) * Math.cos(rectB.angle)
Podría referirse a un GDC (Game Development Conference 2007) PPT www.realtimecollisiondetection.net/pubs/GDC07_Ericson_Physics_Tutorial_SAT.ppt
fuente
En Cocoa, podría detectar fácilmente si el área de área seleccionada se cruza con el marco de su NSView girado. Ni siquiera necesita calcular polígonos, normales como tal. Simplemente agregue estos métodos a su subclase NSView. Por ejemplo, el usuario selecciona un área en la supervista de NSView, luego llama al método DoesThisRectSelectMe pasando el área de Área seleccionada. La API convertRect: hará ese trabajo. El mismo truco funciona cuando haces clic en NSView para seleccionarlo. En ese caso, simplemente anule el método hitTest como se muestra a continuación. El API convertPoint: hará ese trabajo ;-)
fuente
Verifique si alguna de las líneas de un rectángulo se cruza con alguna de las líneas del otro. La intersección ingenua de segmentos de línea es fácil de codificar.
Si necesita más velocidad, existen algoritmos avanzados para la intersección del segmento de línea (línea de barrido). Ver http://en.wikipedia.org/wiki/Line_segment_intersection
fuente
Una solución es usar algo llamado un polígono sin ajuste. Este polígono se calcula a partir de los dos polígonos (conceptualmente deslizando uno alrededor del otro) y define el área para la cual los polígonos se superponen dado su desplazamiento relativo. Una vez que tenga este PFN, simplemente tiene que hacer una prueba de inclusión con un punto dado por el desplazamiento relativo de los dos polígonos. Esta prueba de inclusión es rápida y fácil, pero primero debe crear el NFP.
Realice una búsqueda de No Fit Polygon en la web y vea si puede encontrar un algoritmo para polígonos convexos (se vuelve MUCHO más complejo si tiene polígonos cóncavos). Si no puede encontrar nada, envíeme un correo electrónico a howard dot J dot may gmail dot com
fuente
Esto es lo que creo que se ocupará de todos los casos posibles. Haz las siguientes pruebas.
Si las 2 pruebas anteriores devuelven falso, estos 2 rectángulos no se superponen.
fuente
Si está utilizando Java, todas las implementaciones de la interfaz Shape tienen un método de intersección que toma un rectángulo.
fuente
Bueno, el método de fuerza bruta es caminar por los bordes del rectángulo horizontal y verificar cada punto a lo largo del borde para ver si cae sobre el otro rectángulo.
La respuesta matemática es formar ecuaciones que describan cada borde de ambos rectángulos. Ahora simplemente puede encontrar si alguna de las cuatro líneas del rectángulo A se cruza con alguna de las líneas del rectángulo B, que debería ser un simple (rápido) solucionador de ecuaciones lineales.
-Adán
fuente
Puedes encontrar la intersección de cada lado del rectángulo angulado con cada lado del eje alineado. Haga esto encontrando la ecuación de la línea infinita en la que se encuentra cada lado (es decir, v1 + t (v2-v1) y v'1 + t '(v'2-v'1) básicamente), encontrando el punto en el que las líneas se encuentran resolviendo t cuando esas dos ecuaciones son iguales (si son paralelas, puede probarlo) y luego si ese punto se encuentra en el segmento de línea entre los dos vértices, es decir, es cierto que 0 <= t <= 1 y 0 <= t '<= 1.
Sin embargo, esto no cubre el caso cuando un rectángulo cubre completamente el otro. Que puede cubrir probando si los cuatro puntos de cualquiera de los rectángulos se encuentran dentro del otro rectángulo.
fuente
Esto es lo que haría para la versión 3D de este problema:
Modele los 2 rectángulos como planos descritos por la ecuación P1 y P2, luego escriba P1 = P2 y derive de eso la ecuación de línea de intersección, que no existirá si los planos son paralelos (sin intersección) o están en el mismo plano, en cuyo caso obtienes 0 = 0. En ese caso, deberá emplear un algoritmo de intersección de rectángulo 2D.
Entonces vería si esa línea, que está en el plano de ambos rectángulos, pasa a través de ambos rectángulos. Si es así, entonces tiene una intersección de 2 rectángulos, de lo contrario no lo hace (o no debería, podría haber perdido un caso de esquina en mi cabeza).
Para encontrar si una línea pasa a través de un rectángulo en el mismo plano, encontraría los 2 puntos de intersección de la línea y los lados del rectángulo (modelándolos usando ecuaciones de línea), y luego me aseguraría de que los puntos de intersección estén en rango.
Esas son las descripciones matemáticas, desafortunadamente no tengo código para hacer lo anterior.
fuente
Otra forma de hacer la prueba, que es ligeramente más rápida que usar la prueba de eje de separación, es usar el algoritmo de números de bobinado (solo en cuadrantes, no suma de ángulos que es horriblemente lento) en cada vértice de cualquier rectángulo (elegido arbitrariamente). Si alguno de los vértices tiene un número de devanado distinto de cero, los dos rectángulos se superponen.
Este algoritmo es algo más largo que la prueba de eje de separación, pero es más rápido porque solo requiere una prueba de medio plano si los bordes cruzan dos cuadrantes (en oposición a hasta 32 pruebas que utilizan el método de eje de separación)
El algoritmo tiene la ventaja adicional de que puede usarse para probar la superposición de cualquier polígono (convexo o cóncavo). Hasta donde yo sé, el algoritmo solo funciona en el espacio 2D.
fuente
O me falta algo más, ¿por qué hacer esto tan complicado?
si (x1, y1) y (X1, Y1) son esquinas de los rectángulos, entonces para encontrar la intersección haz:
fuente
Lo implementé así:
La matriz mB es cualquier matriz de transformación afín que convierte puntos en el espacio B en puntos en el espacio A. Esto incluye rotación y traslación simples, rotación más escalado y deformaciones afines completas, pero no deformaciones de perspectiva.
Puede que no sea lo más óptimo posible. La velocidad no era una gran preocupación. Sin embargo, parece funcionar bien para mí.
fuente
Aquí hay una implementación matlab de la respuesta aceptada:
fuente
Este es el método convencional, vaya línea por línea y verifique si las líneas se cruzan. Este es el código en MATLAB.
la función InterX se puede descargar desde: https://in.mathworks.com/matlabcentral/fileexchange/22441-curve-intersections?focused=5165138&tab=function
fuente
Tengo un método más simple, si tenemos 2 rectángulos:
R1 = (min_x1, max_x1, min_y1, max_y1)
R2 = (min_x2, max_x2, min_y2, max_y2)
Se superponen si y solo si:
Superposición = (max_x1> min_x2) y (max_x2> min_x1) y (max_y1> min_y2) y (max_y2> min_y1)
También puede hacerlo para cajas 3D, en realidad funciona para cualquier cantidad de dimensiones.
fuente
Ya se ha dicho lo suficiente en otras respuestas, por lo que solo agregaré pseudocódigo one-liner:
fuente