Sperimentazione numerica della libreria
...Javascript non attivato ...La libreria usata qui...
Il documento di wxMaxima realizzato per fare confronti
Questo documento in retePunti di controllo della parabola
I: M: T: Parabola in forma parametrica
Si deduce tramite i punti di Bézier e rappresenta il modo migliore ossia più diretto per calcolare la posizione di un punto posto sulla parabola.
x = x0 + s*( x1 + s*x2 ) ;
y = y0 + s*( y1 + s*y2 ) ;Noti x ed y è possibile determinate il parametro s che avrebbe potuto individuarli :
s = ( x2*( y − y0 ) − y2*(x − x0 ) )/ ( x2*y1 − y2*x1 ) ; Questa equazione evidenzia una condizione vincolante per la definizione della parabola in forma parametrica ossia x2*y1 NON DEVE ESSERE UGUALE A y2*x1.
Legame tra la parabola in forma parametrica desunta dai tre punti di Bézier e in forma Tradizionale ossia polinomiale
Si ottiene utilizzando l'espressione di s in funzione di x ed y indifferentemente in una o l'altra equazione che, fissato s, consente di determinare il valore di x e di y.
Dato che s dipende sia da x che da y, sostituendolo in una o l'altra equazione , produce una equazione in cui sono presenti sia x che y ma, essendo s espresso da una combinazione lineare di x con y ed essendo elevato al quadrato sia nella prima che nella seconda equazione, la conseguenza è sempre una equazione tipica di una parabola ossia con il termine di secondo grado costituito dal quadrato di una combinazione lineare delle due coordinate.rd = 1/(x2*x2+y2*y2);
cs = y2*sqrt(rd);
sn = − x2*sqrt(rd);
a = rd*(( x2*y0 − y2*x0 )*( x2*y0 − y2*x0 ) + ( x0*y1 − x1*y0 )*( y1*x2 − x1*y2 ));
b = rd*(2*y2*( x2*y0 − y2*x0 ) − y1*( x2*y1 − y2*x1 ));
c = rd*(2*x2*( y2*x0 − x2*y0 ) − x1*( y2*x1 − x2*y1 ));
Quindi la parabola è questa:
( cs*x + sn*y )2 + a + b*x + c*y = 0 ;Parabola NON ruotata ossia ad asse verticale
Data la parabola scritta nella forma NON ruotata ossia ad asse verticale:
Y = X*(A*X + B) + C il vertice sta nel punto in cui la derivata della y(x) vale zero ossia:
2*A*X + B = 0 dunque [Vx,Vy] ha queste componenti:
Vx = −B/(2*A);
Vy = C − B*B/(4*A);Il Fuoco ha la stessa ascissa del vertice ma ha una diversa ordinata ossia:
Fx = −B/(2*A);
Fy = C + (1 − B*B)/(4*A);Il Negafuoco ( punto di incontro dell'asse della parabola con la direttrice della parabola, ha la stessa ascissa del vertice ma ha una diversa ordinata:
Nx = −B/(2*A);
Ny = C − (1 + B*B)/(4*A);Tra il Fuoco, il Negafuoco e il Vertice vale la relazione:
Fy + Ny = 2*Vy Alla parabola con asse verticale, oltre al vertice, appartengono sicuramente altri due punti ossia due punti che hanno la stessa ordinata del Fuoco ma hanno come ascissa in più e in meno di quella del Fuoco il doppio della differenza tra l'ordinata del Fuoco e quella del Vertice.
Ux = −B/(2*A) + 1/(2*A);
Uy = C + (1 − B*B)/(4*A);
Wx = −B/(2*A) − 1/(2*A);
Wy = C + (1 − B*B)/(4*A);Parabola in forma generale ossia eventualmente ruotata
In pratica, generati dall'algoritmo di Bézier, la parabola non ha il suo asse verticale e la direttrice orizzontale ma li ha ruotati di vari gradi. Per avere formule concise ed anche per ottenere maggiore efficienza numerica, non uso esplicitamente funzioni trigonometriche dell'angolo di rotazione dell'asse della parabola ma pongo:
Cs = cos(θ) ;
Sn = sin(θ) ;
Cs*Cs + Sn*Sn = 1 ;Uso come forma generale della parabola arbitrariamente ruotata questa espressione:
( Cs*x + Sn*y )*( Cs*x + Sn*y ) + a + b*x + c*y = 0 ;
ossia :
Cs*Cs*x*x + 2*Cs*Sn*x*y + Sn*Sn*y*y + a + b*x + c*y = 0 ;È immediato dedurre i vincoli che il polinomio della parabola deve rispettare:
- I due coefficienti dei termini di secondo grado ossia x2 e y2 debbono avere lo stesso segno e, per convenzione ( basta moltiplicare l'intera espressione per uno stesso fattore opportuno ), devono essere entrambi positivi.
- Il termine misto ossia il fattore che moltiplica x*y non è arbitrario ma deve valere 2*Cs*Sn posto che i due termini di secondo grado valgano, l'uno Cs*Cs e l'altro Sn*Sn.
- Deve valere la relazione trigonometrica Cs*Cs+Sn*Sn = 1 e per fare rispettare questo vincolo basta moltiplicare l'intera espressione per un opportuno fattore.
- I valori di a, b e c devono essere tali da non produrre una conica degenere ( per esempio non devono essere tutti e tre contemporaneamente nulli ) invece che una parabola... ma questo rischio è trascurabile se i coefficienti del polinomio sono ottenuti tramite l'algoritmo di Bézier.
Per raddrizzare la parabola
Bisogna fare questo cambiamento di coordinate:
x = X*Cs − Y*Sn ;
y = X*Sn + Y*Cs ;
inversa :
X = x*Cs + y*Sn ;
Y = y*Cs − x*Sn ;
e il risultato che si ottiene è questa espressione:
(c*Cs − b*Sn)*Y + X*X + (c*Sn + b*Cn)*X + a = 0 Quindi per ottenere la parabola dritta in forma canonica bisogna definire A, B e C in questo modo:
A = 1/(b*Sn − c*Cs ) ;
B = ( b*Cs + c*Sn )/(b*Sn − c*Cs ) ;
C = a/(b*Sn − c*Cs ) ;
Nella parabola raddrizzata i punti qualificanti hanno le seguenti coordinate. Il Vertice :
Vx = −( b*Cs + C*Sn )/2 ;
Vy = ( 4*a − ( b*Cs + c*Sn )*( b*Cs + c*Sn ))/ ( 4*b*Sn − 4*c*Cs ) ;Il Fuoco
Fx = −( b*Cs + c*Sn )/2 ;
Fy = ( 4*a + b*b − c*c + 2*( c*c − b*b )*Cs*Cs − 4*b*c*Sn*Cs )/ ( 4*b*Sn − 4*c*Cs ) ;Il Negafuoco
Nx = −( b*Cs + c*Sn )/2 ;
Ny = ( 4*a − b*b − c*c )/( 4*b*Sn − 4*c*Cs ) ;Un punto della parabola con la stessa ordinata del fuoco
Ux = ( ( b − c )*Sn − ( b + c )*Cs )/2 ;
Uy = ( 4*a + b*b − c*c + 2*( c*c − b*b )*Cs*Cs − 4*b*c*Sn*Cs )/ ( 4*b*Sn − 4*c*Cs ) ;Un altro punto della parabola con la stessa ordinata del fuoco
Wx = ( ( b − c )*Cs − ( b + c )*Sn )/2 ;
Wy = ( 4*a + b*b − c*c + 2*( c*c − b*b )*Cs*Cs − 4*b*c*Sn*Cs )/ ( 4*b*Sn − 4*c*Cs ) ;Direttamente a proposito della parabola non raddrizzata
Uso gli stessi nomi ma con l'iniziale minuscola
Vertice
vx = ((( c*c − b*b )*Cs*Cs + c*c − 4*a )*Sn + 2*b*c*Cs*Cs*Cs )/ ( 4*b*Sn − 4*c*Cs);
vy = −( 2*b*c*Sn*Sn*Sn + ( bb − cc )*Cs*Sn*Sn + ( b*b − 4*a )*Cn )/ ( 4*b*Sn − 4*c*Cs );Punto u
ux = −(( 4*b*c*Cs*Cs − c*c + b*b + 4*a )*Sn + ( 2*b*b − 2*c*c )*Cs*Cs*Cs − ( 2*b*c + 2*b*b )*Cs )/ ( 4*b*Sn − 4*c*Cs );
uy = −( ( 2*c*c − 2*b*b )*Sn*Sn*Sn + 4*b*c*Cs*Sn*Sn + ( 2*b*c − 2*c*c )*Sn + (−c*c + b*b − 4*a )*Cs )/ ( 4*b*Sn − 4*c*Cs );Punto w
wx = ( ( 4*b*c*Cs*Cs + c*c − b*b −4*a )*Sn + ( 2*b*b − 2*c*c )*Cs*Cs*Cs + ( 2*b*c − 2*b*b )*Cs )/ ( 4*b*Sn − 4*c*Cs );
wy = ( ( 2*c*c − 2*b*b )*Sn*Sn*Sn + 4*b*c*Cs*Sn*Sn + ( −2*c*c − 2*b*c )*Sn + ( c*c − b*b + 4*a)*Cs ) )/ ( 4*b*Sn − 4*c*Cs );Fuoco
fx = (( c*c − b*b − 4*a )*Sn + 2*b*c*Cs )/( 4*b*Sn − 4*c*Cs );
fy = (( c*c − b*b + 4*a )*Cs − 2*b*c*Sn )/( 4*b*Sn − 4*c*Cs );Negafuoco
nx = ((( 2*c*c − 2*b*b )*Cs*Cs + c*c +b*b − 4*a )*Sn + 4*b*c*Cs*Cs*Cs − 2*b*c*Cs )/ ( 4*b*Sn − 4*c*Cs );
ny = (( 4*b*c*Cs*Cs − 2*b*c )*Sn + ( 2*b*b − 2*c*c )*Cs*Cs*Cs + ( c*c − b*b + 4*a )*Cs )/ ( 4*b*Sn − 4*c*Cs );
La libreria
La duplico qui per facilitarne la lettura
// // Dati i tre punti di controllo di Bézier // determina i coefficienti della parabola // espressa in forma parametrica, funzione // di un parametro che quando vale zero // specifica il punto Iniziale e quando // vale 1 specifica il punto Terminale. // function faparametrica(I,M,T){ var Ix,Iy,Mx,My,Tx,Ty,para; Ix=I[1];Iy=I[2];Mx=M[1];My=M[2];Tx=T[1];Ty=T[2]; para=["Parabola parametrica ", ["Ascissa ",Ix,2*(Mx-Ix),(Ix-2*Mx+Tx)], ["Ordinata ",Iy,2*(My-Iy),(Iy-2*My+Ty)]]; return para; } // // Coordinate del punto in funzione del parametro: // function puntopara(para,p){ return [p,para[1][1]+p*(para[1][2]+p*para[1][3]), para[2][1]+p*(para[2][2]+p*para[2][3])]; } // // Lunghezza dell'arco di parabola da un valore // all'altro del parametro calcolata in modo // numerico effettuando np passi: // function lungarcoparanum(para,p1,p2,np){ var j,pp,Pa,Pb,dx,dy,dista=0; Pa=puntopara(para,p1); for(j=1;np>=j;j++){ pp=p1+(p2-p1)*j/np; Pb=puntopara(para,pp); dx=Pb[1]-Pa[1]; dy=Pb[2]-Pa[2]; dista+=Math.sqrt(dx*dx+dy*dy); Pa=Pb;} return dista; } // // Lunghezza dell'arco di parabola calcolata con una // formula matematica analitica... // function lindef(x,b2,aq){ // Dai libri... var b,sq,ii; b=b2/2; sq=Math.sqrt(x*x+2*b*x+aq); ii=((aq-b*b)*Math.log(sq+x+b)+(x+b)*sq)/2; return ii; } // // Fa tutto... // function lungarcopara(para,p1,p2){ var x1,x2,y1,y2; var rq,aq,b2,b,sq,x,i1,i2; x1=para[1][2];x2=para[1][3]; y1=para[2][2];y2=para[2][3]; rq=4*(x2*x2+y2*y2); aq=(x1*x1+y1*y1)/rq; b2=4*(x1*x2+y1*y2)/rq; b=b2/2; x=p2; sq=Math.sqrt(x*x+2*b*x+aq); i2=((aq-b*b)*Math.log(sq+x+b)+(x+b)*sq)/2; x=p1; sq=Math.sqrt(x*x+2*b*x+aq); i1=((aq-b*b)*Math.log(sq+x+b)+(x+b)*sq)/2; id=Math.sqrt(rq)*(i2-i1); return id; } // //Per trovare i punti notevoli della parabola
// // Costruisce la parabola polinomiale // usando i dati della parabola parametrica. // Fornisce anche i coefficienti per calcolare // il parametro che, usato nella espressione // parametrica, darebbe l'ascissa e l'ordinata // del punto specificato, posto sulla // parabola polinomiale. // La parabola polinomiale viene memorizzata // come una qualsiasi conica ma per essere una // parabola la conica deve avere il termine // misto legato in modo esatto ai due termini // di secondo grado. // Come terzo dato fornisce il coseno ed il // seno della rotazione della parabola. // function faparabola(para){ var x0,x1,x2,y0,y1,y2,rd,ta,tb; var cs,sn,a,b,c,p0=0,px=0,py=0; x0=para[1][1];x1=para[1][2];x2=para[1][3]; y0=para[2][1];y1=para[2][2];y2=para[2][3]; rd = 1/( 1.0e-100 + x2*x2 + y2*y2); ta = x2*y0 - y2*x0; tb = x2*y1 - y2*x1; a = rd*(ta*ta - tb*( x1*y0 - y1*x0 )); b = rd*(2*y2*ta - y1*tb ); c = rd*(x1*tb - 2*x2*ta ); rd = Math.sqrt(rd); cs = y2*rd; sn = -x2*rd; if(tb*tb>0){ p0 = -ta/tb; px = -y2/tb; py = x2/tb;} return ["Parabola polinomiale", ["Coefficienti ",a,b,c,cs*cs,2*sn*cs,sn*sn], ["Parametro ",p0,px,py], ["Rotazione ",cs,sn,false]]; } // function mostraparabola(para){ var ss="Parabola polinomiale", xbr="\u003cbr/\u003e"; ss+=xbr+"a = "+para[1][1]+xbr; ss+="b = "+para[1][2]+xbr; ss+="c = "+para[1][3]+xbr; ss+="d = "+para[1][4]+xbr; ss+="e = "+para[1][5]+xbr; ss+="f = "+para[1][6]+xbr; ss+="Coef.Parametro: p0 = "+para[2][1]+xbr; ss+="Coef.Parametro: px = "+para[2][2]+xbr; ss+="Coef.Parametro: py = "+para[2][3]+xbr; ss+="Rotazione: cs = "+para[3][1]+xbr; ss+="Rotazione: sn = "+para[3][2]+xbr; if(para[3][3]) ss+="Parabola RADDRIZZATA"+xbr; else ss+="Parabola NON raddrizzata"+xbr; return ss; } // function faparadritta(gpara){ var A,B,C,a,b,c,sn,cs; var dpara=["Parabola raddrizzata", ["Coefficienti ",0,0,1,0,0,0], ["Parametro ",0,0,0], ["Rotazprima ",0,0,true]]; a=gpara[1][1]; b=gpara[1][2]; c=gpara[1][3]; sn=gpara[3][2]; cs=gpara[3][1]; A=1/(b*sn-c*cs); B=(c*sn+b*cs)/(b*sn-c*cs); C=a/(b*sn-c*cs); dpara[1][1]=C; dpara[1][2]=B; dpara[1][4]=A; dpara[3][1]=cs; dpara[3][2]=sn; return dpara; } // function puntiparadritta(dp){ var dpara; var A,B,C,V,F,N,U,W; if(dp[3][3]) dpara=dp; else dpara=faparadritta(dp); A=dpara[1][4]; B=dpara[1][2]; C=dpara[1][1]; V=["V ",-B/(2*A),C-B*B/(4*A)]; F=["F ",-B/(2*A),C+(1-B*B)/(4*A)]; N=["N ",-B/(2*A),C-(1+B*B)/(4*A)]; U=["U ",-B/(2*A)+1/(2*A),C+(1-B*B)/(4*A)]; W=["W ",-B/(2*A)-1/(2*A),C+(1-B*B)/(4*A)]; return ["Xpraddrizzata ",V,F,N,U,W]; } // function mostrapunti(xpara){ var ss="Punti importanti della parabola ", xbr="\u003cbr/\u003e"; ss+=xpara[0]+xbr+xpara[1]+xbr; ss+=xpara[2]+xbr; ss+=xpara[3]+xbr; ss+=xpara[4]+xbr; ss+=xpara[5]+xbr; return ss; } // // Punti notevoli della parabola // function puntipara(gpara){ var j,cs,sn,pd=puntiparadritta(gpara); var punti=["PuntImportanti ", ["v "],["f "],["n "],["u "],["w "]]; cs=gpara[3][1]; sn=gpara[3][2]; for(j=1;6>j;j++){ punti[j][1]=pd[j][1]*cs-pd[j][2]*sn; punti[j][2]=pd[j][2]*cs+pd[j][1]*sn; } return punti; } // function saluto(){ // alert("Ciao !"); kontatore=0; } // //Pilota la sperimentazione di questa libreria
// function calcola(assegna,risultati){ var j,Ix,Iy,Mx,My,Tx,Ty; var I,M,T,ppara,polpar,paradri,pundri,punt; var np=100,arcopan,arcopa; if(!Array.isArray(promemoria) ){ // alert("Inizializzo"); promemoria=[0]; listainput=document.getElementsByName(assegna);} if(!Array.isArray(promemorisulta) ){ // alert("Prima registrazione dei risultati"); promemorisulta=[0]; listarisultati=document.getElementsByName(risultati);} with(Math){ Ix=eval(listainput[0].value); Iy=eval(listainput[1].value); I=["Iniziale",Ix,Iy]; Mx=eval(listainput[2].value); My=eval(listainput[3].value); M=["Medio",Mx,My]; Tx=eval(listainput[4].value); Ty=eval(listainput[5].value); T=["Terminale",Tx,Ty]; } listarisultati[0].innerHTML="Marche da usare "+ listainput.length+" ("+kontatore+")\u003cbr/\u003eValori: I=["+ Ix+","+Iy+"] M=["+Mx+","+My+"] T=["+Tx+","+Ty+"] "; ppara=faparametrica(I,M,T); listarisultati[1].innerHTML=ppara; polpar=faparabola(ppara); listarisultati[2].innerHTML=mostraparabola(polpar); paradri=faparadritta(polpar); listarisultati[3].innerHTML=mostraparabola(paradri); pundri=puntiparadritta(paradri); listarisultati[4].innerHTML=mostrapunti(pundri); punt=puntipara(polpar); listarisultati[5].innerHTML=mostrapunti(punt); arcopan=lungarcoparanum(ppara,0,1,np); listarisultati[6].innerHTML= "Lunghezza dell'arco di parabola calcolato\u003cbr/\u003e"+ "numericamente facendo "+np+" passi = "+arcopan; arcopa=lungarcopara(ppara,0,1); listarisultati[7].innerHTML= "Esatta lunghezza dell' arco di parabola = "+arcopa; kontatore++; }