|
|
Cominciamo con il codice. Anzitutto la struttura dati 'minimale' che definisce il poligono:
CODICE struct poligono_sezione { float x[100]; float y[100]; int numv; };
Ovvero l'insieme di un vettore coordinate x e di un vettore coordinate y dei vertici che, nello stesso ordine dei vettori, via via uniti generano il poligono. Infine il numero totale dei vertici di cui il poligono è costituito. Per definizione il poligono è chiuso. Ovvero un segmento unisce sempre il primo vertice con l'ultimo. Ancora: il poligono 'gira' in senso orario, non presenta vertici doppioni, non presenta 'peduncoli', non presenta malcostituzioni di sorta. (Solito mio problema, al massimo il poligono potrà possedere 100 vertici).
Prima della funzione vera e propria che riesce a 'smussare' i singoli vertici due funzioni di 'servizio'.
CODICE float somma_azimuth(float azm1,float azm2) { float azm,pi;
pi=4*atan(1);
azm=azm1+azm2;
/* La somma può essere algebrica (quindi anche sottrazione se uno dei due termini è negativo) */ if (azm>2*pi) azm-=2*pi; if (azm<0.0) azm+=2*pi;
return (azm); }
Non fa altro che sommare due azimuth, restituendo, sempre, un valore compreso tra 0 e 6.28 rad. All'occorrenza il secondo parametro passato alla funzione potrebbe essere negativo, generando quindi una sottrazione tra gli azimuth e non una somma come 'letteralmente' farebbe pensare il nome della funzione. In realtà nella funzione principale alla fine non sfrutto mai tale evenienza.
La seconda:
CODICE /* -------------------------------------------------------------------------- */ /* Scopo funzione : Inserisce un numero 'n_vrt' di vertici subito dopo il */ /* vertice di numero 'index' */ /* Parametri formali: polic=puntatore alla geometria della sezione */ /* index=vertice oltre il quale inserire n_vrt vertici */ /* n_vrt=numero di vertici da inserire */ /* Valore restituito: struttura poligono_sezione in cui sono contenute le */ /* coordinate del poligono 'rinumerato' */ /* Implementazione : 20/12/2013 */ /* Autore : Zax2013 */ /* -------------------------------------------------------------------------- */ struct poligono_sezione poli_insert_vertex(struct poligono_sezione polic,int index,int n_vrt) { int register k;
polic.numv+=n_vrt;
for (k=polic.numv-1-n_vrt;k>=index+1;k--) { polic.x[k+n_vrt]=polic.x[k]; polic.y[k+n_vrt]=polic.y[k]; }
return (polic); }
Questa non fa altro che 'traslare' i vertici del poligono successivi al vertice di numerazione index della quantità n_vrt. Questa funzione mi serve poichè al posto del singolo vertice l'operazione di smusso genererà 3-4-5-ecc. vertici, quindi i vertici successivi al vertice smussato cambieranno numerazione. Come vedete la funzione accetta in input una struttura dati poligono_sezione, e restituisce la stessa struttura con n_vrt vertici in più, avendo provveduto a 'creare' spazio subito dopo il vertice index. I vertici in più, quelli nuovi tra index e index+n_vrt rimangono con le stesse vecchie coordinate dei vertici index+1, index+2, ecc., in attesa che qualche altra funzione li utilizzi per definirne le coordinate effettive (la nostra funzione principale, dunque).
Ecco infine la funzione vera e propria:
CODICE struct poligono_sezione raccorda_vertici(struct poligono_sezione poli,int vrt,float r,int npunti) { int register k; int prec,succ; float azm1,azm2,azmb,alfa,azmini,azmfin,angradius,azmstep; float pi; float d1,t,l1,l2,xc,yc,xt1,yt1;
/* Controlla la congruenza dei dati di input */ if (r<=0 || npunti<=1) { /* Inserire qui eventuale avvertimento per l'utente */ return (poli); }
pi=4*atan(1);
/* Definisce i vertici precedenti e successivi al vertice da smussare */ prec=vrt-1; succ=vrt+1;
if (prec<0) prec=poli.numv-1; if (succ>poli.numv-1) succ=0;
/* Determina azimuth del lato precedente al vertice */ azm1=azimuth_segmento(poli.x[vrt],poli.y[vrt],poli.x[prec],poli.y[prec]); /* Determina azimuth del lato successivo al vertice */ azm2=azimuth_segmento(poli.x[vrt],poli.y[vrt],poli.x[succ],poli.y[succ]);
/* Controlla per angolo piatto onde evitare incongruenze */ if (fabs(azm2-azm1)==pi) { /* Inserire qui eventuale avvertimento per l'utente */ return(poli); } /* Non controllo per angolo tra segmenti=0 poichè possibilità eliminata a monte */
/* Determina azimuth bisettrice */ azmb=(azm1+azm2)/2; if (fabs(azm2-azm1)>pi) azmb=somma_azimuth(azmb,pi);
/* Angolo della bisettrice con uno dei segmenti */ alfa=fabs(angolo_tra(azmb,azm2)); d1=r/sin(alfa); t=r/tan(alfa);
l1=sqrt(pow(poli.x[vrt]-poli.x[prec],2)+pow(poli.y[vrt]-poli.y[prec],2)); l2=sqrt(pow(poli.x[vrt]-poli.x[succ],2)+pow(poli.y[vrt]-poli.y[succ],2));
/* Controlla che la tangente non sia superiore alla lunghezza dei due segmenti da raccordare */ if (t>l1 || t>l2) { /* Inserire qui eventuale avvertimento per l'utente */ return(poli); }
/* Controlla che il poligono non superi 100 vertici */ if (poli.numv+npunti>99) { /* Inserire qui eventuale avvertimento per l'utente */ return(poli); }
/* A questo punto tutti i controlli hanno dato esito positivo, il raccordo è possibile */
/* Coordinate centro del raccordo */ xc=poli.x[vrt]+d1*sin(azmb); yc=poli.y[vrt]+d1*cos(azmb);
/* Inserisce nel poligono i vertici necessari, a seguire vrt */ poli=poli_insert_vertex(poli,vrt,npunti-1);
/* Primo punto del raccordo su azm1 tangenza - sostituisce il vertice */ xt1=poli.x[vrt]+t*sin(azm1); yt1=poli.y[vrt]+t*cos(azm1); /* Ultimo punto del raccordo su azm2 tangenza */ poli.x[vrt+npunti-1]=poli.x[vrt]+t*sin(azm2); poli.y[vrt+npunti-1]=poli.y[vrt]+t*cos(azm2);
poli.x[vrt]=xt1; poli.y[vrt]=yt1;
azmini=azimuth_segmento(xc,yc,poli.x[vrt],poli.y[vrt]); azmfin=azimuth_segmento(xc,yc,poli.x[vrt+npunti-1],poli.y[vrt+npunti-1]);
angradius=angolo_tra(azmini,azmfin);
azmstep=angradius/(npunti-1);
/* Determina le coordinate dei vertici seguenti vrt */ for (k=1;k<=npunti-2;k++) { azmini=somma_azimuth(azmini,azmstep);
poli.x[vrt+k]=xc+r*sin(azmini); poli.y[vrt+k]=yc+r*cos(azmini); }
return(poli); }
La funzione accetta in input una struttura dati poligono_sezione e restituisce lo stesso poligono ricevuto. All'occorrenza il poligono ricevuto viene restituito pari pari, se qualche 'evento' impedisce di poter procedere al raccordo. Questi eventi sono stati individuati essere: 1) raggio di raccordo nullo; 2) numero di suddivisioni del raccordo inferiore a 2 (vuol dire che nemmeno i punti di tangenza farebbero parte del raccordo); 3) Angolo piatto tra vertice precedente-vertice-vertice successivo; 4) Raggio di raccordo troppo elevato; 5) NUmero di vertici finali superiori a 100.
L'input della funzione è anche il numero del vertice da raccordare, il suo raggio di raccordo, ed in quanti vertici si vuol discretizzarlo.
Per prima cosa vengono definiti i punti precedenti e successivi al vertice da smussare. E calcolati gli azimuth dei segmenti: vertice-punto precedente, vertice-punto successivo. Da questi si ricava l'azimuth della bisettrice, e i parametri geometrici per la determinazione del centro del raccordo. Quindi si calcolano le coordinate dei punti di tangenza del raccordo sul primo e sul secondo segmento (avendo provveduto a fare spazio nel poligono). Queste coordinate consentono di poter definire correttamente gli azimuth iniziali e finali dei vari raggi 'vettori' che via via consentono di definire i vari punti del raccordo. Infine con la funzione descritta nel post precedente si definisce correttamente l'angolo tra questi due azimuth (può essere sia positivo che negativo), e da questo lo step con cui il raggio vettore deve muoversi angolarmente per la definizione di ogni singolo punto del raccordo. Operazione questa che viene svolta dal ciclo for posto alla fine dalla funzione. Fine.
|
|