Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
18484 | bpr | 1 | !set slib_header_circlepack=\ |
2 | eps=1e-15;\ |
||
3 | \ |
||
4 | /* Homographies */\ |
||
5 | hom(z,m)=(m[1,1]*z+m[1,2])/(m[2,1]*z+m[2,2]);\ |
||
6 | /* Image du cercle de centre z et rayon r par l'homographie m */\ |
||
7 | homc(z,r,m)={\ |
||
8 | my(zz=norm(z)-norm(r),dc=m[2,2]/m[2,1], cc=(zz+z*conj(dc))/conj(z+dc));\ |
||
9 | cc=hom(cc,m); [cc,sqrt(norm(hom(z+r,m)-cc))]\ |
||
10 | };\ |
||
11 | /* Image de la verticale d'abcisse x0 par m */\ |
||
12 | homv(x0,m)={my(dc=m[2,2]/m[2,1], cc=2*x0+real(dc)-imag(dc)*I);\ |
||
13 | cc=hom(cc,m); [cc,sqrt(norm(hom(x0,m)-cc))]};\ |
||
14 | /* Image de l'horizontale d'ordonnée y0 par m */\ |
||
15 | homh(y0,m)={my(dc=m[2,2]/m[2,1], cc=-real(dc)+(2*y0+imag(dc))*I);\ |
||
16 | cc=hom(cc,m); [cc,sqrt(norm(hom(y0*I,m)-cc))]};\ |
||
17 | /* Homographie qui envoie [u1, u2, u3] sur [v1, v2, v3] */\ |
||
18 | homog(u,v)={my(\ |
||
19 | m1=[v[2]*(v[3]-v[1]),v[1]*(v[2]-v[3]);v[3]-v[1],v[2]-v[3]],\ |
||
20 | m2=[u[2]-u[3],u[1]*(u[3]-u[2]);u[1]-u[3],u[2]*(u[3]-u[1])]);\ |
||
21 | m1*m2};\ |
||
22 | \ |
||
23 | /* somme des demi-angles */\ |
||
24 | sangles(r,flr,lbs)=sum(j=1,#flr,atan(lbs[flr[j]]/r));\ |
||
25 | \ |
||
26 | /* Point à distance r1 de z1 et r2 de z2, sens direct */\ |
||
27 | trois(z1,r1,z2,r2)={\ |
||
28 | my(n=norm(z2-z1),\ |
||
29 | x=(1+(sqr(r1)-sqr(r2))/n)/2,\ |
||
30 | y=sqrt(sqr(r1)/n-sqr(x)));\ |
||
31 | z1+(z2-z1)*(x+y*I)\ |
||
32 | };\ |
||
33 | \ |
||
34 | /* Le fichier off contient la liste ff des fleurs duales.\ |
||
35 | On calcule d'abord la liste ss des fleurs primales.\ |
||
36 | On choisit l'arête 1a et son arête duale bc privilégiées.\ |
||
37 | On applique l'algo pour obtenir les rayons des autres disques.\ |
||
38 | On place les points sur les bords du rectangle.\ |
||
39 | On cherche le sommet (ou la face) de plus grand degré\ |
||
40 | ainsi que le sommet ou la face opposé. Ils sont envoyés sur\ |
||
41 | le cercle unité et un cercle concentrique plus petit.\ |
||
42 | On renvoie les quatre listes (centres et rayons pour sommets et faces) */\ |
||
43 | \ |
||
44 | polycircle(ff)={\ |
||
45 | my(ns=1,nf=#ff,dgs,m,f,ss,i,j,k,l,lbs,lbf,a,b,c,d,u,pts,ptf,cs,cf,\ |
||
46 | f1,fb,fc,fl,sa,ssa,w,h,scale,again,s0,f0,flip,aa,bb,cc,djs,djf,p,ma);\ |
||
47 | \ |
||
48 | /* Dans la version pari, les sommets sont numérotés de 1 à ns */\ |
||
49 | for (i=1, nf, for (j = 1, #ff[i], if((ff[i][j]+=1)>ns,ns=ff[i][j])));\ |
||
50 | \ |
||
51 | /* calcul des fleurs primales */\ |
||
52 | dgs=vector(ns); /* degrés des sommets*/\ |
||
53 | m=matrix(ns,ns);\ |
||
54 | /* m[aa,bb]==i!=0 ssi (aa,bb) fait partie du bord orienté de la face i */\ |
||
55 | for(i=1, nf, f=ff[i]; for(j = 1, #f, dgs[f[j]]+=1; m[f[j],f[1+j%#f]]=i));\ |
||
56 | \ |
||
57 | ma=m;\ |
||
58 | ss=vector(ns);\ |
||
59 | for(i=1, ns,\ |
||
60 | fl=vector(dgs[i]);\ |
||
61 | j=1;while(!m[i,j],j++); /* chercher une pétale */\ |
||
62 | for (l=1, dgs[i],\ |
||
63 | fl[l]=k=m[i,j];\ |
||
64 | j=1;while(m[j,i]!=k,j++)); /* chercher la pétale suivante */\ |
||
65 | ss[i]=fl;\ |
||
66 | );\ |
||
67 | \ |
||
68 | /* Calcul des rayons */\ |
||
69 | lbs=vector(ns,x,1);\ |
||
70 | lbf=vector(nf,x,1);\ |
||
71 | \ |
||
72 | s1=ss[1]; b = s1[1]; c = s1[2];\ |
||
73 | fb=ff[b]; fc=ff[c];\ |
||
74 | for (j = 1, #fc, if (fc[j] == 1, a = fc[1+j%#fc]; break));\ |
||
75 | sa=ss[a];\ |
||
76 | lbs[1]=lbs[a]=lbf[b]=lbf[c]=eps^-2;\ |
||
77 | \ |
||
78 | again = 1;\ |
||
79 | while (again, again=0;\ |
||
80 | for (i=2, ns, if (i != a,\ |
||
81 | ssa=sangles(lbs[i],ss[i],lbf);\ |
||
82 | if (abs(ssa-Pi)> eps,\ |
||
83 | lbs[i]*=tan(ssa/#ss[i])/tan(Pi/#ss[i]); again=1)));\ |
||
84 | for (i=1, nf, if (i != b && i != c,\ |
||
85 | ssa=sangles(lbf[i],ff[i],lbs);\ |
||
86 | if (abs(ssa-Pi)> eps,\ |
||
87 | lbf[i]*=tan(ssa/#ff[i])/tan(Pi/#ff[i]); again=1)))\ |
||
88 | );\ |
||
89 | \ |
||
90 | /* Calcul des positions */\ |
||
91 | \ |
||
92 | pts=vector(ns);\ |
||
93 | ptf=vector(nf);\ |
||
94 | cs=vector(ns);\ |
||
95 | cf=vector(nf);\ |
||
96 | \ |
||
97 | /* Tour du rectangle fondamental, sens horaire! */\ |
||
98 | \ |
||
99 | w = 0; h = 0; k = 0; /* nombre de points calculés */\ |
||
100 | \ |
||
101 | for (i = 3, #s1,\ |
||
102 | d = s1[i]; h += lbf[d]; ptf[d] = w+h*I; cf[d] = 1; k++; h += lbf[d]);\ |
||
103 | i = 1; while (fb[i] != 1, i = 1+i%#fb);\ |
||
104 | while ((d = fb[i = 1+i%#fb]) != a,\ |
||
105 | w += lbs[d]; pts[d] = w+h*I; cs[d] = 1; k++; w += lbs[d]);\ |
||
106 | \ |
||
107 | /* Mise à l'échelle et stockage du rectangle */\ |
||
108 | \ |
||
109 | scale = min (4 / w, 6 / h);\ |
||
110 | for (i = 1, ns, lbs[i] *= scale; pts[i] *= scale);\ |
||
111 | for (i = 1, nf, lbf[i] *= scale; ptf[i] *= scale);\ |
||
112 | w *= scale; h *= scale;\ |
||
113 | \ |
||
114 | lbs[1] = lbf[b] = lbs[a] = lbf[c] = 0;\ |
||
115 | pts[1] = 0; pts[a] = w; ptf[b] = h; ptf[c] = 0;\ |
||
116 | k += 4; /* On connait 1, a, b et c, mais on ne le dit pas dans cs et cf */\ |
||
117 | \ |
||
118 | i = 1; while (sa[i] != b, i = 1+i%#sa);\ |
||
119 | while ((d = sa[i = 1+i%#sa]) != c,\ |
||
120 | h -= lbf[d]; ptf[d] = w+h*I; cf[d] = 1; k++; h -= lbf[d]);\ |
||
121 | i = 1; while (fc[i] != a, i = 1+i%#fc);\ |
||
122 | while ((d = fc[i = 1+i%#fc]) != 1,\ |
||
123 | w -= lbs[d]; pts[d] = w+h*I; cs[d] = 1; k++; w -= lbs[d]);\ |
||
124 | \ |
||
125 | /* Ici, on a fait le tour du rectangle, donc h==w==0 (I hope) */\ |
||
126 | \ |
||
127 | while(k<ns+nf,\ |
||
128 | for(aa=2,ns,if(aa!=a && cs[aa], fl = ss[aa]; for (i=1,#fl, if(cf[fl[i]],\ |
||
129 | bb = fl[i]; cc = fl[1+i%#fl];\ |
||
130 | if(!cf[cc] && cc != b && cc != c,\ |
||
131 | ptf[cc] = trois(pts[aa], sqrt(lbs[aa]^2+lbf[cc]^2),\ |
||
132 | ptf[bb], lbf[bb]+lbf[cc]);\ |
||
133 | cf[cc] = 1; k++)))));\ |
||
134 | for(aa=1,nf,if(aa!=b && aa!= c && cf[aa], fl = ff[aa]; for (i=1,#fl, if(cs[fl[i]],\ |
||
135 | bb = fl[i]; cc = fl[1+i%#fl];\ |
||
136 | if(!cs[cc] && cc != 1 && cc != a,\ |
||
137 | pts[cc] = trois(ptf[aa], sqrt(lbf[aa]^2+lbs[cc]^2),\ |
||
138 | pts[bb], lbs[bb]+lbs[cc]);\ |
||
139 | cs[cc]=1; k++))))));\ |
||
140 | \ |
||
141 | /* return([pts,lbs,ptf,lbf] pour le diagramme avec un rectangle */\ |
||
142 | \ |
||
143 | /* Détermination du point (s0 ou f0) de degré maximal */\ |
||
144 | f0=1; for(i=2,nf,if(#ff[i]>#ff[f0],f0=i));\ |
||
145 | s0=1; for(i=2,ns,if(#ss[i]>#ss[s0],s0=i));\ |
||
146 | flip = #ss[s0] > #ff[f0];\ |
||
147 | /* Détermination du point (s1 ou f1) le plus éloigné de s0 ou f0 */\ |
||
148 | djs = vector(ns,i,-1); djf = vector(nf,i,-1);\ |
||
149 | d = 0; k=1; if (flip,djs[s0]=0,djf[f0]=0);\ |
||
150 | while(k<ns+nf, if((d+flip)%2,\ |
||
151 | for(s = 1, ns, if(djs[s] == d,\ |
||
152 | for(j = 1, #ss[s], if(djf[ss[s][j]] < 0,\ |
||
153 | k += 1; f1 = ss[s][j]; djf[f1] = d+1\ |
||
154 | )))),\ |
||
155 | for(f = 1, nf, if(djf[f] == d,\ |
||
156 | for(j = 1, #ff[f], if(djs[ff[f][j]] < 0,\ |
||
157 | k += 1; s1 = ff[f][j]; djs[s1] = d+1\ |
||
158 | )))));\ |
||
159 | d += 1);\ |
||
160 | \ |
||
161 | /* et parmi ceux-là, celui qui a le plus grand degré ? */\ |
||
162 | if((d+flip)%2,\ |
||
163 | for(s = 1, ns, if(djs[s] == d && #ss[s] > #ss[s1], s1=s)),\ |
||
164 | for(f = 1, nf, if(djf[f] == d && #ff[f] > #ff[f1], f1=f)));\ |
||
165 | \ |
||
166 | d=(d+flip)%2;\ |
||
167 | \ |
||
168 | /* Il faut maintenant trouver l'homographie qui envoie le disque de sf0\ |
||
169 | sur le disque unité et celui de sf1 sur un disque centré en 0\ |
||
170 | de rayon plus petit */\ |
||
171 | \ |
||
172 | if(flip,\ |
||
173 | cc=pts[s0]; rr=lbs[s0];\ |
||
174 | m=homog(if (s0 == 1 || s0 == a,\ |
||
175 | [cc-1.23*I,cc,cc+3.78*I],\ |
||
176 | [cc-rr*exp(I), cc+rr, cc+rr*exp(1.52*I)]),[-I,1,I]),\ |
||
177 | cc=ptf[f0]; rr=lbf[f0];\ |
||
178 | m=homog(if (f0 == b || f0 == c,\ |
||
179 | [cc*I-1.23456789,cc*I,cc*I+3.78243577],\ |
||
180 | [cc-rr*exp(I), cc+rr, cc+rr*exp(1.52*I)]),[-I,1,I]));\ |
||
181 | \ |
||
182 | u=if(d%2,if(s1==1||s1==a, homv(pts[s1],m), homc(pts[s1],lbs[s1],m)),\ |
||
183 | if(f1==b||f1==c, homh(ptf[f1],m), homc(ptf[f1],lbf[f1],m)));\ |
||
184 | \ |
||
185 | if(sqrt(norm(u[1]))+u[2]>1, m=[0,1;1,0]*m; u=homc(u[1],u[2],[0,1;1,0]));\ |
||
186 | \ |
||
187 | r0=sqrt(norm(u[1])); t1=r0-u[2];\ |
||
188 | a1=log((1+t1)/(1-t1));\ |
||
189 | t2=r0+u[2]; a2=log((1+t2)/(1-t2)); aa=exp((a1+a2)/2);\ |
||
190 | t = (aa-1)/(aa+1); u[1]*=t/r0; /* u[1] est maintenant le centre hyper*/\ |
||
191 | \ |
||
192 | m=[1,-u[1];-conj(u[1]),1]*m;\ |
||
193 | for (i=1,ns,u=if(i==1||i==a, homv(pts[i],m),homc(pts[i],lbs[i],m));\ |
||
194 | pts[i]=if(norm(u[1])<eps,0,u[1]);lbs[i]=u[2]);\ |
||
195 | for (i=1,nf,u=if(i==b||i==c, homh(ptf[i],m),homc(ptf[i],lbf[i],m));\ |
||
196 | ptf[i]=if(norm(u[1])<eps,0,u[1]);u[1];lbf[i]=u[2]);\ |
||
197 | \ |
||
198 | /* Une rotation pour faire plus joli */\ |
||
199 | p=if(flip,ptf[ss[s0][1]],pts[ff[f0][1]]);p/=sqrt(norm(p));\ |
||
200 | for (i=1,ns,pts[i]/=p);\ |
||
201 | for (i=1,nf,ptf[i]/=p);\ |
||
202 | \ |
||
203 | /* [pts,lbs,ptf,lbf] */\ |
||
204 | [matrix(#lbs,3,i,j,if(j==1,real(pts[i]),if(j==2,imag(pts[i]),lbs[i]))),\ |
||
205 | matrix(#lbf,3,i,j,if(j==1,real(ptf[i]),if(j==2,imag(ptf[i]),lbf[i]))),ma]\ |
||
206 | };\ |