// // LIBRERIA PER LA GRAFICA SVG // Quadriche e cubiche di Bezier // // Ora una funzione di t variabile tra Ta e Tb // usando normali polinomi. // Da e' il valore iniziale del polinomio. // Va e' la velocita' iniziale. // Db e' il valore finale del polinomio. // Vb e' la velocita' finale. // var $bpol={versione:"20170219"}; // // Lavora con parabole usando due diversi polinomi // in base al valore di t nell'intervallo da Ta a Tb. // $bpol["popara"]=function(t,Ta,Tb,Da,Db,Va,Vb){ var Ga,Gb,Tbma,poval; Tbma=Tb-Ta; if(2*t>(Ta+Tb)){Gb=(4*(Da-Db)+ Tbma*(Va+3*Vb))/(2*Tbma*Tbma); poval=Db+(t-Tb)*(Vb+Gb*(t-Tb));} else{Ga=(4*(Db-Da)-Tbma*(Vb+3*Va))/ (2*Tbma*Tbma); poval=Da+(t-Ta)*(Va+Ga*(t-Ta));} return poval; } // // Fa una spezzata di segmenti rettilinei e di Nk // tratti usando la funzione popara(t,Ta,Tb,Da,Db,Va,Vb) // $bpol["linpopara"]=function(Nk,Ta,Tb,Da,Db,Va,Vb){ var k,t,pv,vlin=[]; for(k=0;Nk>=k;k++){ t=Ta+(Tb-Ta)*k/Nk; pv=$bpol.popara(t,Ta,Tb,Da,Db,Va,Vb); vlin=vlin.concat(["L",pv,t]);} return vlin;} // // Ora ecco una funzione di t variabile tra Ta e Tb // usando una coppia di polinomi di Bezier // quadratici ossa una coppia di parabole. // $bpol["bepara"]=function(t,Ta,Tb,Da,Db,Va,Vb){ var Pia,Pca,Pfa,Pib,Pcb,Pfb,Tbma,beval; Tbma=Tb-Ta; if(2*t>Ta+Tb){ Pib= -(Tbma*Vb-Tbma*Va-4*Db-4*Da)/8; Pcb= -(Tbma*Vb-4*Db)/4; Pfb= Db; ub=(2*t-Ta-Tb)/Tbma; beval=(Pib*(1-ub)+2*Pcb*ub)*(1-ub)+Pfb*ub*ub;} else{ Pia= Da; ua=2*(t-Ta)/Tbma; Pca= (Tbma*Va+4*Da)/4; Pfa= -(Tbma*Vb-Tbma*Va-4*Db-4*Da)/8; beval=(Pia*(1-ua)+2*Pca*ua)*(1-ua)+Pfa*ua*ua;} return beval; } // // Fa una spezzata di segmenti rettilinei e di Nk // tratti usando la funzione bepara(t,Ta,Tb,Da,Db,Va,Vb) // $bpol["linbepara"]=function(Nk,Ta,Tb,Da,Db,Va,Vb){ var k,t,pv,vlin=[]; for(k=0;Nk>=k;k++){ t=Ta+(Tb-Ta)*k/Nk; pv=$bpol.bepara(t,Ta,Tb,Da,Db,Va,Vb); vlin=vlin.concat(["L",pv,t]);} return vlin;} // // Ora calcola e fornisce i punti di Bezier delle // curve quadratiche: // $bpol["bezquad"]=function(Ta,Tb,Da,Db,Va,Vb){ var Pca,Pfa,Pcb,Tbma; Tbma=Tb-Ta; Pca= (Tbma*Va+4*Da)/4; Pfa= -(Tbma*Vb-Tbma*Va-4*Db-4*Da)/8; Pcb= -(Tbma*Vb-4*Db)/4; return [" Q ",Pca,(3*Ta+Tb)/4,Pfa,(Tb+Ta)/2, " Q ",Pcb,(Ta+3*Tb)/4,Db,Tb]; } // // Ora verifico che le due funzioni bezquad e // le meno precise linpopara e linbepara diano // in pratica lo stesso risultato: // $bpol["tbezier"]=function(miasvg,tt1,tt2,Mm){ var lpath=miasvg.getElementsByTagName("path"); var t,Ta,Tb,Tc,Da,Db,Dc,Va,Vb,Vc,bzq,dbzq,dbzi; var circ="m 0 10 a 10 10 0 0 0 0 -20 "+ " a 10 10 0 0 0 0 20 m 0 -10 "; var cirg="m 0 15 a 15 15 0 0 0 0 -30 "+ " a 15 15 0 0 0 0 30 m 0 -15 "; // Ta=30+Math.round(10*Math.random()); Tb=Ta+tt1+Math.round(100*Math.random()); Tc=Tb+tt2+Math.round(100*Math.random()); Da=Math.round(200*Math.random())+100; Db=Math.round(600*Math.random())+400; Dc=Math.round(300*Math.random())+200; Va=2; if(Math.random()>0.5){Vb=-1;} else{Vb=1;} if(Math.random()>0.5){Vc=-1;} else{Vc=2;} nk=3; dbzi=[" M ",Da,Ta,circ]; dbzq=dbzi.concat($bpol.bezquad(Ta,Tb,Da,Db,Va,Vb)); dbzi=dbzq.concat([circ]); dbzq=dbzi.concat($bpol.bezquad(Tb,Tc,Db,Dc,Vb,Vc)); lpath[0].setAttribute("d",dbzq.join(" ")+circ); // dbzi=[" M ",Da,Ta,cirg]; dbzq=dbzi.concat($bpol.linpopara(Mm,Ta,Tb,Da,Db,Va,Vb)); dbzi=dbzq.concat([cirg]); dbzq=dbzi.concat($bpol.linbepara(Mm,Tb,Tc,Db,Dc,Vb,Vc)); lpath[1].setAttribute("d",dbzq.join(" ")+cirg); return true; } // // Note le velocita' Va e Vb con t che varia da // Ta a Tb, calcola il valore del polinomio cubico. // $bpol["polcub"]=function(t,Ta,Tb,Da,Db,Va,Vb){ var pos,Tbma=Tb-Ta,r=(t-Ta)/Tbma; var r2=r*r,r3=r2*r,Umr=1-r; var Umr2=Umr*Umr,Umr3=Umr2*Umr; pos=Da*Umr3+(3*Da+Va*Tbma)*r*Umr2+ (3*Db-Vb*Tbma)*r2*Umr+Db*r3; return pos;} // // Fa una spezzata rettilinea di Nk tratti usando la // funzione polcub(t,Ta,Tb,Da,Db,Va,Vb) // $bpol["linpolcub"]=function(Nk,Ta,Tb,Da,Db,Va,Vb){ var k,t,pv,vlin=[]; for(k=0;Nk>=k;k++){ t=Ta+(Tb-Ta)*k/Nk; pv=$bpol.polcub(t,Ta,Tb,Da,Db,Va,Vb); vlin=vlin.concat(["L",pv,t]);} return vlin;} // // Noti i punti di controllo Pa e Pb con t che // varia da Ta a Tb, calcola il valore della // curva di Bezier cubica. // $bpol["bezcub"]=function(t,Ta,Tb,Da,Db,Pa,Pb){ var pos,r=(t-Ta)/(Tb-Ta); var r2=r*r,r3=r2*r,Umr=1-r; var Umr2=Umr*Umr,Umr3=Umr2*Umr; pos=Da*Umr3+3*Pa*r*Umr2+ 3*Pb*r2*Umr+Db*r3; return pos;} // // Trova i punti di controllo dalle due velocita' // della curva di Bezier cubica: // $bpol["bezcubdav"]=function(Ta,Tb,Da,Db,Va,Vb){ var Pa,Pb,Tbma=(Tb-Ta)/3; Pa=Da+Va*Tbma; Pb=Db-Vb*Tbma; return ["C",Pa,Ta+Tbma,Pb,Ta+2*Tbma,Db,Tb];} // // Fa una spezzata di Nk tratti usando la // funzione bezcubdav e la bezub(t,Ta,Tb,Da,Db,Va,Vb) // $bpol["linbezcub"]=function(Nk,Ta,Tb,Da,Db,Va,Vb){ var k,t,pv,vpapb,Pa,Pb,vlin=[]; var vpapb=$bpol.bezcubdav(Ta,Tb,Da,Db,Va,Vb); Pa=vpapb[1]; Pb=vpapb[3]; for(k=0;Nk>=k;k++){ t=Ta+(Tb-Ta)*k/Nk; pv=$bpol.bezcub(t,Ta,Tb,Da,Db,Pa,Pb); vlin=vlin.concat(["L",pv,t]);} return vlin;} // // Trova le due velocita' dai due punti di // controllo della curva di Bezier cubica. // $bpol["vdabezcub"]=function(Ta,Tb,Da,Db,Pa,Pb){ var Tbma=(Tb-Ta)/3; return [(Pa-Da)/Tbma,(Db-Pb)/Tbma]} // // Ora verifico che le due funzioni cubiche diano // lo stesso risultato: // $bpol["tbezcub"]=function(miasvg,tt1,tt2,Mm){ var lpath=miasvg.getElementsByTagName("path"); var t,Ta,Tb,Tc,Da,Db,Dc,Va,Vb,Vc,bzq,dbzq,dbzi; var circ="m 0 10 a 10 10 0 0 0 0 -20 "+ " a 10 10 0 0 0 0 20 m 0 -10 "; var cirg="m 0 15 a 15 15 0 0 0 0 -30 "+ " a 15 15 0 0 0 0 30 m 0 -15 "; // Ta=30+Math.round(10*Math.random()); Tb=Ta+tt1+Math.round(100*Math.random()); Tc=Tb+tt2+Math.round(100*Math.random()); Da=Math.round(200*Math.random())+100; Db=Math.round(600*Math.random())+400; Dc=Math.round(300*Math.random())+200; Va=2; if(Math.random()>0.5){Vb=-1;} else{Vb=1;} if(Math.random()>0.5){Vc=-1;} else{Vc=2;} // dbzi=[" M ",Da,Ta,circ]; dbzq=dbzi.concat($bpol.bezcubdav(Ta,Tb,Da,Db,Va,Vb)); dbzi=dbzq.concat([circ]); dbzq=dbzi.concat($bpol.bezcubdav(Tb,Tc,Db,Dc,Vb,Vc)); lpath[0].setAttribute("d",dbzq.join(" ")+circ); // dbzi=[" M ",Da,Ta,cirg]; dbzq=dbzi.concat($bpol.linpolcub(Mm,Ta,Tb,Da,Db,Va,Vb)); dbzi=dbzq.concat([cirg]); dbzq=dbzi.concat($bpol.linbezcub(Mm,Tb,Tc,Db,Dc,Vb,Vc)); // lpath[1].setAttribute("d",dbzq.join(" ")+cirg); // return true; } // // Data due funzioni della posizione ossia della ascissa // funx(t) e della ordinata del punto, funy(t), genera la // array dei punti e delle loro velocita' gestibile poi // dalle funzioni che trovano i punti di controllo. // L'intero np rappresenta il numero di passettini // da fare ed eps e' lo spostamento piccolo da fare // per calcolare le derivate... // $bpol["fatraiettoria"]=function(funx,funy,np,da,ad,eps){ var k,kp,t,sp,vx,vy,vtras=[]; // kp=Math.max(2,Math.round(np)); sp=(ad-da)/(kp-1); for(k=0;kp>k;k++){t=da+k*sp; vx=((27*funx(t+eps)+funx(t-3*eps))- (27*funx(t-eps)+funx(t+3*eps)))/(48*eps); vy=((27*funy(t+eps)+funy(t-3*eps))- (27*funy(t-eps)+funy(t+3*eps)))/(48*eps); vtras[k]=[t,funx(t),vx,funy(t),vy]; } // return vtras;} // // Per verificare come funziona il calcolo della // derivata prima in modo approssimato. // Il dato eps rappresenta il piccolo spostamento // rispetto al valore assegnato, t, della variabile // indipendente. // $bpol["derprima"]=function(funx,t,eps){var vx; vx=((27*funx(t+eps)+funx(t-3*eps))- (27*funx(t-eps)+funx(t+3*eps)))/(48*eps); return(vx);} // // Estrae i dati per una spezzata lineare // usando un passo fisso ossia np=10 // per una quadrica e np=7 per una cubica. // $bpol["lineare"]=function(vpc,np){ var k,nn=np-1,n=vpc.length,vlin; vlin=[" M ",vpc[nn-1],vpc[nn]]; for(k=1;n>k;k++){ nn+=np vlin=vlin.concat([" L ",vpc[nn-1],vpc[nn]]); } return vlin; } // // Esempio di applicazione in due dimensioni // oltre alla variabile indipentente della // quadrica di Bezier. // vquas e' un vettore di spezzoni quadrici che // costituiscono la traiettoria. // $bpol["fapunticontq"]=function(vquas){ var k,km,n=vquas.length,vpc,vpk; var vprox,vproy; var S,T,Dx,Dy,Vx,Vy,Fx,Fy,Wx,Wy; T=vquas[0][0]; Fx=vquas[0][1]; Fy=vquas[0][3]; Wx=vquas[0][2]; Wy=vquas[0][4]; vpc=[["M"," "," "," "," ", " "," "," ",Fx,Fy], [T],[Wx,Wy]]; for(k=1;n>k;k++){km=k-1; T=vquas[k][0]; S=vquas[km][0]; Dx=vquas[km][1]; Dy=vquas[km][3]; Vx=vquas[km][2]; Vy=vquas[km][4]; Fx=vquas[k][1]; Fy=vquas[k][3]; Wx=vquas[k][2]; Wy=vquas[k][4]; vprox=$bpol.bezquad(S,T,Dx,Fx,Vx,Wx); vproy=$bpol.bezquad(S,T,Dy,Fy,Vy,Wy); vpk=[" Q ",vprox[1],vproy[1],vprox[3],vproy[3], " Q ",vprox[6],vproy[6],vprox[8],vproy[8]]; vpc[0]=vpc[0].concat(vpk); vpc[1]=vpc[1].concat([T]);} return vpc; } // // Un esempio di applicazione delle precedenti funzioni // quadriche ossia paraboliche. // Contiene la definizione della funzione delle ascisse // e della funzione delle ordinate. Queste funzioni // vengono usate per fare la traiettoria suddivisa in npu // spezzoni e poi la traiettoria viene disegnata. // $bpol["xdisegnoq"]=function(lsvg,kpath,npu,rgx,rgy,cicli){ var dd,vtr,attrid,xlin; var asc=function(t){ var orx=500,rs=75; var gr=Math.PI/180; return (orx+(rgx)*Math.cos(gr*t)+ rs*Math.cos(cicli*gr*t));} var ord=function(t){ var ory=630,rs=75; var gr=Math.PI/180; return (ory+(rgy)*Math.sin(gr*t)+ rs*Math.sin(cicli*gr*t));} var lpath=lsvg.getElementsByTagName("path"); // alert("In xdisegnoq"); vtr=$bpol.fatraiettoria(asc,ord,npu,0,360,1.0e-5); attrid=$bpol.fapunticontq(vtr); dd=lpath[kpath].setAttribute("d",attrid[0].join(" ")); if(lpath.length>2){ xlin=$bpol.lineare(attrid[0],10); dd=lpath[lpath.length-1].setAttribute("d",xlin.join(" ")); } // alert("Disegnoq: "+lpath.length+"\n qui"); return attrid[0]; } // // Esempio di applicazione della cubica di Bezier. // vcubs e' un vettore di spezzoni cubici che // costituiscono la traiettoria. // $bpol["fapunticontc"]=function(vcubs){ var k,km,n=vcubs.length,vpc,vpk; var vprox,vproy; var S,T,Dx,Dy,Vx,Vy,Fx,Fy,Wx,Wy; T=vcubs[0][0]; Fx=vcubs[0][1]; Fy=vcubs[0][3]; Wx=vcubs[0][2]; Wy=vcubs[0][4]; vpc=[["M"," "," "," "," ",Fx,Fy], [T],[Wx,Wy]]; for(k=1;n>k;k++){km=k-1; T=vcubs[k][0]; S=vcubs[km][0]; Dx=vcubs[km][1]; Dy=vcubs[km][3]; Vx=vcubs[km][2]; Vy=vcubs[km][4]; Fx=vcubs[k][1]; Fy=vcubs[k][3]; Wx=vcubs[k][2]; Wy=vcubs[k][4]; vprox=$bpol.bezcubdav(S,T,Dx,Fx,Vx,Wx); vproy=$bpol.bezcubdav(S,T,Dy,Fy,Vy,Wy); vpk=["C",vprox[1],vproy[1],vprox[3],vproy[3], vprox[5],vproy[5]]; vpc[0]=vpc[0].concat(vpk); vpc[1]=vpc[1].concat([T]);} return vpc; } // // Qui fa lo stesso della fapunticontc ma senza // usare la bezcubdav. In pratica verifica il // funzionamento della bezcubdav. // $bpol["fapunticontcv"]=function(vcubs){ var k,km,u,n=vcubs.length,vpc,vpk; var S,T,Dx,Dy,Vx,Vy,Fx,Fy,Wx,Wy,Hx,Hy,Kx,Ky; T=vcubs[0][0]; Fx=vcubs[0][1]; Fy=vcubs[0][3]; Wx=vcubs[0][2]; Wy=vcubs[0][4]; vpc=[["M"," "," "," "," ",Fx,Fy], [T],[Wx,Wy]]; for(k=1;n>k;k++){km=k-1; T=vcubs[k][0]; S=vcubs[km][0]; Dx=vcubs[km][1]; Dy=vcubs[km][3]; Vx=vcubs[km][2]; Vy=vcubs[km][4]; Fx=vcubs[k][1]; Fy=vcubs[k][3]; Wx=vcubs[k][2]; Wy=vcubs[k][4]; u=(T-S)/3; Hx=Dx+u*Vx; Hy=Dy+u*Vy; Kx=Fx-u*Wx; Ky=Fy-u*Wy; vpk=["C",Hx,Hy,Kx,Ky,Fx,Fy]; vpc[0]=vpc[0].concat(vpk); vpc[1]=vpc[1].concat([T]);} return vpc; } // // Un esempio di applicazione delle precedenti funzioni // cubiche. // Contiene la definizione della funzione delle ascisse // e della funzione delle ordinate. Queste funzioni // vengono usate per fare la traiettoria suddivisa in npu // spezzoni e poi la traiettoria viene disegnata. // $bpol["xdisegnoc"]=function(lsvg,kpath,npu,rgx,rgy,cicli){ var dd,vtr,attrid; var asc=function(t){ var orx=500,rs=75; var gr=Math.PI/180; return (orx+(rgx)*Math.cos(gr*t)+ rs*Math.cos(cicli*gr*t));} var ord=function(t){ var ory=630,rs=75; var gr=Math.PI/180; return (ory+(rgy)*Math.sin(gr*t)+ rs*Math.sin(cicli*gr*t));} var lpath=lsvg.getElementsByTagName("path"); // alert("In xdisegnoc"); vtr=$bpol.fatraiettoria(asc,ord,npu,0,360,1.0e-5); attrid=$bpol.fapunticontc(vtr); dd=lpath[kpath].setAttribute("d",attrid[0].join(" ")); // alert("Disegnoc: "+lpath.length+"\n qui"); return attrid[0]; } // // Qui invece di usare la fapunticontc usa la fapunticontcv. // Variante dell'esempio delle curve cubiche. // $bpol["xdisegnocv"]=function(lsvg,kpath,npu,rgx,rgy,cicli){ var dd,vtr,attrid,xlin; var asc=function(t){ var orx=500,rs=75; var gr=Math.PI/180; return (orx+(rgx)*Math.cos(gr*t)+ rs*Math.cos(cicli*gr*t));} var ord=function(t){ var ory=630,rs=75; var gr=Math.PI/180; return (ory+(rgy)*Math.sin(gr*t)+ rs*Math.sin(cicli*gr*t));} var lpath=lsvg.getElementsByTagName("path"); // alert("In xdisegnocv"); vtr=$bpol.fatraiettoria(asc,ord,npu,0,360,1.0e-5); attrid=$bpol.fapunticontcv(vtr); dd=lpath[kpath].setAttribute("d",attrid[0].join(" ")); if(lpath.length>2){ xlin=$bpol.lineare(attrid[0],7); dd=lpath[lpath.length-1].setAttribute("d",xlin.join(" ")); } // alert("Disegnocv: "+lpath.length+"\n qui"); return attrid[0]; } // // Arrotondamento dei numeri in virgola mobile // per facilitare la loro stampa. // $bpol["arrotonda"]=function(vdati){ var k,ton,n=vdati.length,vt=[]; for(k=0;n>k;k++){ ton=vdati[k]; if(typeof ton === "number"){ vt[k]=Math.round(ton)} else{vt[k]=ton;}} return vt;} //