Rotazione 3D di una circonferenza
Salve, ho un problema di trigonometria 3d e rotazioni che non riesco a risolvere perchè è passato troppo tempo da quando ho dato Matematica B (a ingegneria).
Sto programmando un app opengl e mi trovo a disegnare una circonferenza con centro in una sfera che deve essere ruotata sugli assi x,y,z in modo che intersechi due punti p,q sulla superficie della sfera.
rotazione_su_z=atan(p.x/p.y)*(180 / pi);
rotazione1_su_y=asin(q.z/q.x)*(180 / pi);
rotazione2_su_y=asin(p.z/p.x)*(180 / pi);
rotazione_su_x=asin(q.x/q.y)*(180 / pi);
procedo in questo ordine:
rotazione_su_z
rotazione1_su_y
rotazione2_su_y
rotazione_su_x
-rotazione2_su_y
E a questo punto mi accorgo di aver sbagliato qualcosa...
Qualche aiuto?
Grazie!
Sto programmando un app opengl e mi trovo a disegnare una circonferenza con centro in una sfera che deve essere ruotata sugli assi x,y,z in modo che intersechi due punti p,q sulla superficie della sfera.
rotazione_su_z=atan(p.x/p.y)*(180 / pi);
rotazione1_su_y=asin(q.z/q.x)*(180 / pi);
rotazione2_su_y=asin(p.z/p.x)*(180 / pi);
rotazione_su_x=asin(q.x/q.y)*(180 / pi);
procedo in questo ordine:
rotazione_su_z
rotazione1_su_y
rotazione2_su_y
rotazione_su_x
-rotazione2_su_y
E a questo punto mi accorgo di aver sbagliato qualcosa...
Qualche aiuto?
Grazie!
Risposte
In linea di massima, se stai lavorando in 3D e usi massicciamente angoli e funzioni trigonometriche stai sbagliando qualcosa. Le operazioni sui vettori sono spesso molto più efficienti dal punto di vista computazionale e le formule ottenute sono spesso più eleganti e semplici. Questo è un esempio abbastanza evidente, per riuscire a comprendere i tuoi calcoli avrei bisogno di mettermi a fare un sacco di disegni e calcoli. E tutto questo solo perché hai deciso di limitarti a rotazioni su assi coordinati invece di chiederti qual'è esattamente la trasformazione che ti porta dalla circonferenza "a riposo" a quella desiderata. Il metodo migliore per risolvere un problema come questo è:
1. Scrivere le equazioni di un riferimento ortonormale centrato nella circonferenza (i primi due assi sono una base del piano che contiene la circonferenza e il terzo è la normale del piano) prima e dopo la trasformazione.
2. Scrivere la matrice del cambio di riferimento tra i due riferimenti trovati nel punto 1.
È un metodo decisamente più semplice di quello basato sulle rotazioni lungo gli assi coordinati.
Ci sono comunque dei punti non completamente chiari nel tuo problema. Immagino che la circonferenza sia contenuta in una display list o un VBO statico e che tu stia cercando di definire la trasformazione dallo spazio locale al modello a quello globale della tua scena. Non mi è però chiaro che cosa rappresenti la sfera e i due punti sulla sua superficie. Inoltre due punti più eventuale raggio non determinano una circonferenza nello spazio. Anche chiedendo che la circonferenza abbia il centro sulla sfera le soluzioni, quando esistono, sono quasi sempre due (simmetriche rispetto al piano passante per i due punti e il centro della sfera). Se fornisci qualche dettaglio e spiegazione in più forse riesco a mostrarti in pratica il metodo che ho spiegato nel capoverso precedente.
1. Scrivere le equazioni di un riferimento ortonormale centrato nella circonferenza (i primi due assi sono una base del piano che contiene la circonferenza e il terzo è la normale del piano) prima e dopo la trasformazione.
2. Scrivere la matrice del cambio di riferimento tra i due riferimenti trovati nel punto 1.
È un metodo decisamente più semplice di quello basato sulle rotazioni lungo gli assi coordinati.
Ci sono comunque dei punti non completamente chiari nel tuo problema. Immagino che la circonferenza sia contenuta in una display list o un VBO statico e che tu stia cercando di definire la trasformazione dallo spazio locale al modello a quello globale della tua scena. Non mi è però chiaro che cosa rappresenti la sfera e i due punti sulla sua superficie. Inoltre due punti più eventuale raggio non determinano una circonferenza nello spazio. Anche chiedendo che la circonferenza abbia il centro sulla sfera le soluzioni, quando esistono, sono quasi sempre due (simmetriche rispetto al piano passante per i due punti e il centro della sfera). Se fornisci qualche dettaglio e spiegazione in più forse riesco a mostrarti in pratica il metodo che ho spiegato nel capoverso precedente.
Intanto ti ringrazio per la tua risposta accurata.
Dato che si tratta solo di una funzione di debug non ho pensato al problema computazionale e ho cercato l'approccio più semplice che mi veniva in mente (e che raramente coincide con il più semplice in assoluto
.
Sto scrivendo un software per il calcolo dell'assetto di un robot tramite tracking dell'optical flow di una telecamera omnidirezionale in c++ e opencv. La funzione di debug in opengl mi plotta sulla sfera unitaria le coppie di punti estratte dal flusso video: il primo punto dal primo frame e il secondo punto dal frame sucessivo.
A questo punto mi serviva plottare i fasci di circonferenze "unitarie" centrate nell'origine che corrispondono alle coppie di punti e verificarne i punti di intersezione che dovrebbero corrispondere ai vanishing point del movimento. Con il centro fissato dovrebbe esserci una sola circonferenza che passa per due punti.
Per plottare la circonferenza uso gluDisk e la ruoto con glRotate.

Grazie ancora!!!
Dato che si tratta solo di una funzione di debug non ho pensato al problema computazionale e ho cercato l'approccio più semplice che mi veniva in mente (e che raramente coincide con il più semplice in assoluto

Sto scrivendo un software per il calcolo dell'assetto di un robot tramite tracking dell'optical flow di una telecamera omnidirezionale in c++ e opencv. La funzione di debug in opengl mi plotta sulla sfera unitaria le coppie di punti estratte dal flusso video: il primo punto dal primo frame e il secondo punto dal frame sucessivo.
A questo punto mi serviva plottare i fasci di circonferenze "unitarie" centrate nell'origine che corrispondono alle coppie di punti e verificarne i punti di intersezione che dovrebbero corrispondere ai vanishing point del movimento. Con il centro fissato dovrebbe esserci una sola circonferenza che passa per due punti.
Per plottare la circonferenza uso gluDisk e la ruoto con glRotate.

Grazie ancora!!!
Si tratta allora della circonferenza data dall’intersezione tra la sfera unitaria e il piano la cui normale è il prodotto vettoriale “dei due punti”. Hai quindi bisogno di una rotazione che mandi \(\boldsymbol{k}\) (il versore corrispondente all'asse \(z\)) in \( \boldsymbol{v} = \frac{\boldsymbol{p} \times \boldsymbol{q}}{|| \boldsymbol{p} \times \boldsymbol{q} ||} \). Qualsiasi rotazione di questo tipo andrebbe bene, per fissarne una decidiamo inoltre che \(\boldsymbol{i} \mapsto \boldsymbol{p}\) (mandiamo cioè l'asse \(x\) nella retta passante per il primo dei due punti). In questo modo abbiamo fissato la nostra rotazione. Ricordandoci infatti che \( \boldsymbol{k} \times \boldsymbol{i} = \boldsymbol{j} \), la nostra rotazione dovrà mandare \( \boldsymbol{j} \) in \( \boldsymbol{w} = \boldsymbol{v} \times \boldsymbol{p} \). La matrice corrispondente alla trasformazione sarà allora la seguente matrice a blocchi (ogni vettore è una colonna):
\[ R = \left(\begin{array}{ccc} \boldsymbol{p} & \boldsymbol{w} & \boldsymbol{v} \end{array}\right) \]
Il codice corrispondente per le OpenGL sarà allora qualcosa come il seguente:
Assumendo ovviamente l'esistenza delle classi di cui sopra (usando per esempio la libreria glm o un'altra libreria matematica o del tuo codice).
\[ R = \left(\begin{array}{ccc} \boldsymbol{p} & \boldsymbol{w} & \boldsymbol{v} \end{array}\right) \]
Il codice corrispondente per le OpenGL sarà allora qualcosa come il seguente:
vec3 v = normalize(cross(p, q)); vec3 w = normalize(cross(v, p)); mat3 R = mat3(p, w, v); glMultMatrixf(R);
Assumendo ovviamente l'esistenza delle classi di cui sopra (usando per esempio la libreria glm o un'altra libreria matematica o del tuo codice).
Installato glm e fatto girare ma il codice così come è dà qualche problema perchè la circonferenza esce dalla sfera e viene stirata 
Comunque mi hai messo sulla strada giusta, domani con calma ci lavoro.
Grazie 10^3!!!
P.S. glMultMatrixf(value_ptr(R)); comunque ho avuto un bel colpo di fortuna a trovare uno preparato come te
O tutti i matematici usano opengl?

Comunque mi hai messo sulla strada giusta, domani con calma ci lavoro.
Grazie 10^3!!!

P.S. glMultMatrixf(value_ptr(R)); comunque ho avuto un bel colpo di fortuna a trovare uno preparato come te

Credo che il problema possa essere che glMultMatrix richiede una matrice \(4 \times 4 \), mentre io avevo usato nello pseudo-codice precedente una matrice \(3 \times 3\). Prova ad usare il seguente codice in C++ che fa uso di glm. Si usano matrici di questa dimensione per poter lavorare anche su trasformazione proiettive e in modo da includere nella matrice anche la traslazione (la quarta colonna rappresenta la traslazione).
P.S. La computer grafica non fa parte del curriculum di un matematico, ma le trasformazioni affini ne fanno certamente parte. Le OpenGL le conosco per interesse personale (e lavorativo). Ma uso in realtà molto raramente le funzioni per la gestione delle matrici nelle OpenGL. La funzionalità è infatti stata eliminata nelle ultime versioni e per progetti un po’ complessi è più facile utilizzare una libreria matematica specifica.
glm::vec3 v = glm::normalize(glm::cross(p, q)); glm::vec3 w = glm::normalize(glm::cross(v, p)); glm::mat4 R = glm::mat4(p.x, w.x, v.x, 0.0f, p.y, w.y, v.y, 0.0f, p.z, w.z, v.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); glMultMatrixf(glm::value_ptr(R));
P.S. La computer grafica non fa parte del curriculum di un matematico, ma le trasformazioni affini ne fanno certamente parte. Le OpenGL le conosco per interesse personale (e lavorativo). Ma uso in realtà molto raramente le funzioni per la gestione delle matrici nelle OpenGL. La funzionalità è infatti stata eliminata nelle ultime versioni e per progetti un po’ complessi è più facile utilizzare una libreria matematica specifica.
Funziona!!
Ho dovuto mettere:
Forse perchè ho fatto casini io con le impostazioni del viewport.
Grazie, mi hai salvato!
Ho dovuto mettere:
mat4 R = mat4(p.x, p.y, p.z, 0.0f, w.x, w.y, w.z, 0.0f, v.x, v.y, v.x, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
Forse perchè ho fatto casini io con le impostazioni del viewport.
Grazie, mi hai salvato!
Il costruttore di mat4 è definito nel modo seguente:
A quanto pare i valori sono inseriti per colonna nel costruttore e non per riga come pensavo. Per cui ogni riga nel codice che hai scritto corrisponde ad una colonna della matrice. Non mi ricordavo questa strana definizione.
L'importante è che funzioni comunque.
template <typename T> GLM_FUNC_QUALIFIER tmat4x4<T>::tmat4x4 ( value_type const & x0, value_type const & y0, value_type const & z0, value_type const & w0, value_type const & x1, value_type const & y1, value_type const & z1, value_type const & w1, value_type const & x2, value_type const & y2, value_type const & z2, value_type const & w2, value_type const & x3, value_type const & y3, value_type const & z3, value_type const & w3 ) { this->value[0] = col_type(x0, y0, z0, w0); this->value[1] = col_type(x1, y1, z1, w1); this->value[2] = col_type(x2, y2, z2, w2); this->value[3] = col_type(x3, y3, z3, w3); }
A quanto pare i valori sono inseriti per colonna nel costruttore e non per riga come pensavo. Per cui ogni riga nel codice che hai scritto corrisponde ad una colonna della matrice. Non mi ricordavo questa strana definizione.
