Test affidabile per l'intersezione di due curve di Bezier


9

Come scoprire in modo affidabile se due curve planari di Bezier si intersecano? Con "affidabilità" intendo che il test risponderà "sì" solo quando le curve si intersecano e "no" solo quando non si intersecano. Non ho bisogno di sapere a quali parametri è stata trovata l'intersezione. Vorrei anche usare numeri in virgola mobile nell'implementazione.

Ho trovato diverse risposte su StackOverflow che usano i rettangoli delle curve per il test: questo non è ciò che sto cercando in quanto tale test può riportare l'intersezione anche se le curve non si intersecano.

La cosa più vicina che ho trovato finora è il " cuneo di delimitazione " di Sederberg e Meyers ma "solo" distingue tra al massimo uno e due o più intersezioni, mentre voglio sapere se c'è al massimo zero e una o più intersezioni.


Non sono sicuro che esista come tale, determinare se c'è una possibilità per 0-1 o 2 o più è piuttosto banale, ma la formulazione non rende davvero facile assicurarsi che sia 0 o 1 senza effettivamente controllare.
joojaa,

Quali sono i requisiti di runtime? Una soluzione che dovrebbe essere in grado di produrre risultati abbastanza precisi sarebbe quella di approssimare entrambe le curve con un gran numero di brevi segmenti rettilinei e poi intersecarli in modo a coppie. Ma questo costa molto tempo e memoria.
Dragonseel,

@Dragonseel Beh, sarei felice per qualsiasi soluzione, davvero, ma dal momento che hai chiesto a O (1) sarebbe carino. Ma approssimare le curve con segmenti di linea porta agli stessi problemi del test per la sovrapposizione del riquadro di delimitazione ...
Ecir Hana,

Problema interessante. Non credo che ci sia una risposta facile, ma mi piacerebbe sbagliarmi. Hai un link per l'articolo Sederberg e Meyers?
Daniel M Gessel,

@DanielMGessel Sì, vedi la modifica sopra.
Ecir Hana,

Risposte:


6

Un modo alternativo per formulare il problema è definire una funzione che dia la distanza tra i punti sulle due curve, in funzione dei parametri delle curve. Quindi provare a trovare il minimo globale di questa funzione. Se le curve si intersecano, il minimo sarà zero; altrimenti il ​​minimo sarà una certa distanza positiva.

Per essere espliciti, data una coppia di curve 2D definite da , definire il quadrato della distanza comec1,c2:[0,1]R2

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

Per le curve cubiche, la funzione è quindi un polinomio di sesto grado in due variabili. È quindi possibile applicare tecniche di ottimizzazione numerica come il metodo simplex o la discesa del gradiente coniugato . Sfortunatamente la funzione può avere diversi minimi locali (non è convessa), quindi l'ottimizzazione non è facile. Potrebbero esserci metodi di ottimizzazione più specializzati disponibili per i polinomi, ma questa non è un'area di competenza per me.f


Perché è un polinomio di sesto grado, e non un terzo, se parliamo di Beziers cubici? E i due metodi a cui sei collegato, sono suscettibili di trovare soluzioni solo in , al contrario dell'intero ? R 2[0,1]2R2
Ecir Hana,

1
@EcirHana È il 6 ° grado perché è la distanza al quadrato. (Potresti radicarlo quadrato, ma poi non è più polinomiale e non sarà uniforme agli zero.) Nota che è lo spazio dei parametri, non lo spazio in cui vivono le spline, cioè questi sono spline con endpoint. In ogni caso, i metodi funzioneranno bene in , ma "viaggiano in discesa" solo da un'ipotesi iniziale e trovano un minimo locale; è necessario qualcosa in più per esaminare l'intera area dei parametri e trovare il minimo globale . Vincolare lo spazio dei parametri è probabilmente utile lì. R 2[0,1]R2
Nathan Reed,

1
Nathan - bella formulazione! Sono arrugginito, ma: penso che tu possa dividere ogni curva più bezier in al massimo 5 segmenti, per cui o cambiano direzione nella curva. , in funzione di cambia direzione al massimo due volte (radici della derivata) spezzando la curva in 3 segmenti, 2 dei quali possono essere nuovamente divisi da cambiamenti nella direzione di . Ora hai, non segmenti diritti, ma segmenti che "non curvano troppo". Penso che se inizi la tua ricerca da 25 punti, scelti per coppie di segmenti, potresti sempre trovare i minimi globali, ma non riesco proprio a vedere come dimostrarlo (o confutarlo). y x c i yxyxciy
Daniel M Gessel,

@Nathan: lo avevo considerato ma, dopo aver trascorso molto tempo a scrivere codice per trovare minimi nei formati di compressione delle trame, sembrava tutto un po 'orribile.
Simon F,

5

[Dichiarazione di non responsabilità: penso che quanto segue dovrebbe funzionare ma in realtà non l'ho codificato da solo]

Non riuscivo a pensare a un metodo "banale" per produrre una risposta sì / no, ma il seguente sarebbe un approccio ragionevole a una soluzione pratica alla domanda.

Supponiamo che le nostre curve siano A (s) e B (t) con punti di controllo { A0, A1..An } e { B0, .. Bm } rispettivamente.

Mi sembra che, dato un paio di Bezier 2D per i quali desideriamo determinare se fare o non intersecare, ci sono sei casi da considerare:

  1. Caso in cui possiamo "banalmente" determinare che non si intersecano.

  2. Caso in cui si intersecano un numero finito di volte e possiamo "facilmente" determinare che si intersecano sicuramente almeno una volta (ma in realtà non ci interessa dove si verificano tali incroci)

  3. Uno dei Bezier è degenerato, cioè un punto (che si verificherà se tutti i punti di controllo sono identici). Possiamo presumere che abbiamo già gestito il caso in cui entrambi sono punti.

  4. Una o più curve sono chiuse, ad es. A0 == An. Per semplificare la vita, suddivideremo tali curve e ricominceremo.

  5. Esiste un numero infinito di punti di intersezione perché ognuno è un sottoinsieme di un "parent" Bezier e si sovrappongono.

  6. Non siamo sicuri dei casi di cui sopra e abbiamo bisogno di ulteriori indagini

Per il momento ignoreremo 3 e 4, ma torneremo da loro più tardi.

Caso 1

Come suggerisci nella tua domanda, se le rispettive caselle di delimitazione dei punti di controllo di A e B ), non si intersecano, le curve non possono intersecarsi. Ovviamente questo è un test di rifiuto rapido ma è eccessivamente conservativo. Come probabilmente saprai, con una curva di Bezier, lo scafo convesso dei suoi punti di controllo forma un limite (più stretto) sulla curva. Possiamo quindi usare la tecnica dell'asse di separazione per decidere se gli scafi di A e B non si intersecano. (ad es. come mostrato in Wikipedia :)

inserisci qui la descrizione dell'immagine

Caso 2

Se il test del caso 1 fallisce, è possibile verificare l'esistenza "banale" di un incrocio. Ora ci sono probabilmente modi migliori per farlo, ma mi è venuto in mente il seguente approccio, relativamente economico:

Considera solo la curva A:

Limiti della "linea grassa" di un Bezier

Sappiamo che la curva inizia da , termina da e si troverà all'interno dello scafo convesso. Per semplicità, calcoliamo la direzione del segmento di linea e calcoliamo i limiti su entrambi i lati (ovvero prendiamo i prodotti punto dei punti di controllo rimanenti rispetto alla perpendicolare a ).A n ¯ A 0 A n ¯ A 0 A nA0AnA0An¯A0An¯

Se facciamo lo stesso con la curva B, otteniamo il seguente (possibile) caso: inserisci qui la descrizione dell'immagine

Se troviamo e sono fuori dai limiti opposti di B e che e sono le parti esterne dei limiti di A, quindi, dalla continuità di Béziers, ci deve essere almeno un'intersezione.A n B 0 B mA0AnB0Bm

Caso 6

Se non riusciamo a mostrare immediatamente nessuno dei casi precedenti, dividi ciascuno dei Bezier in due "metà", ovvero . Questo è relativamente semplice (lasciato come esercizio al lettore) ma è particolarmente banale per Beziers quadratico :A1,A2,B1,B2

Confronta ricorsivamente le 4 combinazioni: . Chiaramente se tutto passa il caso 1, non c'è intersezione. In caso di esito negativo 1, continuare con il resto dei test con quel sottoinsieme ridotto.(A1,B1),(A2,B1)...(A2,B2)

Casi 3 e 5

È qui che diventa leggermente più noioso.

Se "caso 3" supera il test "caso 1", mi sembra che devi risolvere per un vero incrocio. Dato che esiste un semplice processo per mappare i punti di controllo N di un Bezier, A (s), ai punti N-1 di Bezier, A '(s), che rappresenta il suo primo derivato quindi (a condizione che si prenda cura del relativamente rare, le cosiddette situazioni "degenerate" in cui la prima derivata fa zero), quindi l'iterazione di Newton (su una dimensione) potrebbe essere utilizzata per trovare potenziali soluzioni.
Si noti inoltre che, poiché i punti di controllo di A '(s) sono legati ai valori derivati, esiste la possibilità di eliminare anticipatamente alcuni casi.

Il caso 5 sembra relativamente improbabile, quindi forse solo se dopo alcune ricorsioni non ci sono prove conclusive, si potrebbe provare ogni punto finale di A contro la curva B e viceversa. Ciò darebbe solo una prova dell'intersezione, non una prova della non intersezione.


Sì, ma sono personalmente più interessato al caso in cui riguardo al caso in cui Bm e / o B0 sono entrambi all'interno del volume del limite massimo e minimo di A ma non lo perforano, è necessario suddividere e, nel peggiore dei casi, calcolare l'intersezione punto. Un modo migliore sarebbe quello di utilizzare il riquadro di delimitazione minimo noto anche come approssimazione della linea spessa.
joojaa,

Dato che, con ogni suddivisione binaria, la differenza tra la curva e il segmento che collega i punti finali scende di un fattore ragionevole (e, al di sopra della mia testa, penso che potrebbe essere stato 4x per la quadratica) sicuramente i limiti stanno andando convergere abbastanza rapidamente in un nastro "sottile".
Simon F,

Sì, ma lo scenario peggiore è che l'altro più bezier inizia dall'altro.
joojaa,

Intendi ad esempio An == B0 . Lo definisci come un incrocio o no?
Simon F,

Non più come B0 è Da qualche parte sulla curva. O anche solo una minima traversata
joojaa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.