Prueba confiable para la intersección de dos curvas de Bezier

9

¿Cómo averiguar de manera confiable si dos curvas planas de Bezier se cruzan? Por "confiablemente" quiero decir que la prueba responderá "sí" solo cuando las curvas se crucen, y "no" solo cuando no se crucen. No necesito saber en qué parámetros se encontró la intersección. También me gustaría usar números de punto flotante en la implementación.

Encontré varias respuestas en StackOverflow que usan los cuadros delimitadores de las curvas para la prueba: esto no es lo que busco, ya que tal prueba puede informar la intersección, incluso si las curvas no se cruzan.

Lo más cercano que encontré hasta ahora es la " cuña delimitadora " de Sederberg y Meyers, pero "solo" distingue entre la intersección de uno o dos y más, mientras que quiero saber si hay cero. y una o más intersecciones.

Ecir Hana
fuente
No estoy seguro de que exista como tal, determinar el tiempo o la posibilidad de 0-1 o 2 o más es bastante trivial, pero la formulación realmente no hace que sea fácil asegurarse de que sea 0 o 1 sin verificarlo.
joojaa
¿Cuáles son los requisitos de tiempo de ejecución? Una solución que debería ser capaz de producir resultados bastante precisos sería aproximar ambas curvas por un gran número de segmentos rectos cortos y luego intersecarlos en pares. Pero eso cuesta mucho tiempo y memoria.
Dragonseel
@Dragonseel Bueno, estaría feliz por cualquier solución, de verdad, pero desde que le preguntaste a O (1) sería bueno. Pero aproximar las curvas con segmentos de línea conduce a los mismos problemas que la prueba para la superposición del cuadro delimitador ...
Ecir Hana
Interesante problema No creo que haya una respuesta fácil, pero me gustaría estar equivocado. ¿Tiene un enlace para el periódico Sederberg y Meyers?
Daniel M Gessel
@DanielMGessel Sí, vea la edición anterior.
Ecir Hana

Respuestas:

6

Una forma alternativa de formular el problema es definir una función que proporcione la distancia entre puntos en las dos curvas, en función de los parámetros de las curvas. Luego intente encontrar el mínimo global de esta función. Si las curvas se cruzan, el mínimo será cero; de lo contrario, el mínimo será una distancia positiva.

Para ser explícito, dado un par de curvas 2D definidas por , defina la distancia al cuadrado comoc1,c2:[0,1]R2

f(u,v):[0,1]2R0|c2(v)c1(u)|2

Para curvas cúbicas, la función es entonces un polinomio de sexto grado en dos variables. Luego puede aplicar técnicas de optimización numérica como el método simplex o el descenso de gradiente conjugado . Desafortunadamente, la función puede tener varios mínimos locales (no es convexa), por lo que la optimización no es fácil. Puede que haya métodos de optimización más especializados disponibles para polinomios, pero esta no es un área de especialización para mí.f

Nathan Reed
fuente
¿Por qué es un polinomio de sexto grado, y no un tercero, si hablamos de Beziers cúbicos? Y los dos métodos con los que se vinculó, ¿son susceptibles de encontrar soluciones solo en , en oposición a completo ? [0,1]2R2
Ecir Hana
1
@EcirHana Es sexto grado porque es la distancia al cuadrado. (Podría enraizarlo de raíz cuadrada, pero ya no es polinomial y no será uniforme en los ceros). Tenga en cuenta que es el espacio de parámetros, no el espacio en el que viven las splines, es decir, estos son splines con puntos finales. En cualquier caso, los métodos funcionarán bien en , pero solo "viajarán cuesta abajo" desde una suposición inicial y encontrarán un mínimo local; Se necesita algo más para examinar toda la región de parámetros y encontrar el mínimo global . Restringir el espacio de parámetros probablemente sea útil allí. [0,1]R2
Nathan Reed
1
Nathan - buena formulación! Estoy oxidado, pero: creo que puedes dividir cada curva bezier en un máximo de 5 segmentos, por donde o cambian de dirección en la curva. , en función de cambia la dirección como máximo dos veces (raíces de la derivada) rompiendo la curva en 3 segmentos, 2 de los cuales pueden dividirse nuevamente por cambios en la dirección de . Ahora tiene, no segmentos rectos, sino segmentos que "no se curvan demasiado". Creo que si comienzas tu búsqueda en 25 puntos, elegidos por pares de segmentos, siempre podrías encontrar los mínimos globales, pero no puedo ver cómo probarlos (o refutarlos). xyxciy
Daniel M Gessel
@Nathan: Lo había considerado pero, después de pasar mucho tiempo escribiendo código para encontrar mínimos en formatos de compresión de texturas, todo parecía un poco horrible.
Simon F
5

[Descargo de responsabilidad: creo que lo siguiente debería funcionar, pero en realidad no lo he codificado yo mismo]

No podía pensar en un método "trivial" para producir una respuesta sí / no, pero lo siguiente sería un enfoque razonable para una solución práctica a la pregunta.

Supongamos que nuestras curvas son A (s) y B (t) con los puntos de control { A0, A1..An } y { B0, .. Bm } respectivamente.

Me parece que, dados un par de Béziers 2D para los que deseamos determinar si se cruzan o no, hay seis casos a considerar:

  1. Caso en el que podemos determinar "trivialmente" que no se cruzan.

  2. Caso en el que se cruzan un número finito de veces y podemos determinar "fácilmente" que definitivamente se cruzan al menos una vez (pero en realidad no nos importa dónde ocurren esas intersecciones)

  3. Uno de los Beziers es degenerado, es decir, un punto (que ocurrirá si todos los puntos de control son idénticos). Podemos suponer que ya hemos manejado el caso donde ambos son puntos.

  4. Una o más de las curvas están cerradas, por ejemplo. A0 == An. Para simplificar la vida, subdividiremos tales curvas y comenzaremos nuevamente.

  5. Hay un número infinito de puntos de intersección porque cada uno es un subconjunto de un Bézier "padre" y se superponen.

  6. No estamos seguros de los casos anteriores y necesitamos más investigación

Por el momento ignoraremos 3 y 4, pero volveremos a ellos más tarde.

Caso 1

Como insinúa en su pregunta, si los cuadros delimitadores respectivos de los puntos de control de A y B ), no se cruzan, entonces las curvas no pueden cruzarse. Obviamente, esta es una prueba de rechazo rápido, pero es demasiado conservadora. Como probablemente sepa, con una curva de Bezier, el casco convexo de sus puntos de control forma un límite (más apretado) en la curva. Por lo tanto, podemos usar la técnica de eje de separación para decidir si los cascos de A y B no se cruzan. (por ejemplo, como se muestra en Wikipedia :)

ingrese la descripción de la imagen aquí

Caso 2

Si la prueba del caso 1 falla, puede verificar la existencia "trivial" de una intersección. Ahora hay probablemente mejores formas de hacer esto, pero se me ocurrió el siguiente enfoque, relativamente barato:

Considere solo la curva A:

Límites de "línea gorda" de un Bezier

Sabemos que la curva comienza en , termina en y se ubicará dentro del casco convexo. Para simplificar, calculemos la dirección del segmento de línea y los límites a cada lado (es decir, tome los productos de puntos de los puntos de control restantes contra la perpendicular a ).A n ¯ A 0 A n ¯ A 0 A nA0AnA0An¯A0An¯

Si hacemos lo mismo con la curva B, obtenemos el siguiente (posible) caso: ingrese la descripción de la imagen aquí

Si encontramos que y están fuera de los límites opuestos de B y que y están fuera de los límites de A, entonces, por la continuidad de Béziers, debe haber al menos una intersección.A n B 0 B mA0AnB0Bm

Caso 6

Si no podemos mostrar inmediatamente ninguno de los casos anteriores, divida cada uno de los Béziers en dos "mitades", es decir, . Esto es relativamente sencillo (dejado como un ejercicio para el lector) pero es particularmente trivial para Beziers cuadráticos :A1,A2,B1,B2

Compare recursivamente las 4 combinaciones: . Claramente, si todos pasan el caso 1, no hay intersección. Si alguno falla 1, continúe con el resto de las pruebas con ese subconjunto reducido.(A1,B1),(A2,B1)...(A2,B2)

Caso 3 y 5

Aquí es donde se vuelve un poco más tedioso.

Si el "caso 3" supera la prueba del "caso 1", me parece que necesita resolver una intersección real. Dado que hay un proceso simple para mapear los N puntos de control de un Bézier, A (s), a los puntos N-1 del Bézier, A '(s), que representa su primera derivada entonces (siempre que se tenga cuidado con el situaciones relativamente raras, llamadas "degeneradas", donde la primera derivada llega a cero), entonces la iteración de Newton (en una dimensión) podría usarse para encontrar soluciones potenciales.
Tenga en cuenta también que, dado que los puntos de control de A '(s) están vinculados a los valores derivados, existe la posibilidad de eliminar rápidamente algunos casos.

El caso 5 parece relativamente improbable, por lo que tal vez solo si después de algunas recursiones no hay pruebas concluyentes, se podría probar cada punto final de A contra la curva B y viceversa. Esto solo daría una prueba de intersección, no una prueba de no intersección.

Simon F
fuente
Sí, pero personalmente estoy más interesado en el caso en el que Bm y / o B0 están dentro del volumen del límite máximo y mínimo de A pero no lo perfora, entonces debe subdividir y, en el peor de los casos, calcular la intersección punto. Las mejores formas serían usar el cuadro delimitador mínimo, también conocido como aproximación de línea gruesa.
joojaa
Dado que, con cada subdivisión binaria, la diferencia entre la curva y el segmento que conecta los puntos finales disminuye por un factor razonable (y, desde la parte superior de mi cabeza, creo que podría haber sido 4x para las cuadráticas) seguramente los límites van converger a una cinta "delgada" con bastante rapidez.
Simon F
Sí, pero el peor de los casos es que el otro bezier comience por el otro.
joojaa
Te refieres, por ejemplo, An == B0 . ¿Lo define como una intersección o no?
Simon F
No más como B0 está en algún lugar de la curva. O incluso un cruce mínimo
joojaa