Subversion Repositories wimsdev

Rev

Rev 18502 | Rev 18513 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18506 bpr 1
!set slib_header_hyptiling=\
18430 bpr 2
\\ -----------------------------------------------------------------------------------\
3
\\ Action du groupe de Moebius etendu sur le disque de Poincare\
4
\\ -----------------------------------------------------------------------------------\
5
\\ Homographie ou antihomographie selon que g[3] vaut 0 ou 1.\
6
mob(g,z)=if(g[3],z=conj(z));(g[1]*z+g[2])/(conj(g[2])*z+conj(g[1]));\
7
\\ Produit et inverse dans le groupe de Moebius etendu\
8
mobx(g)=[g[1],g[2];conj(g[2]),conj(g[1])];\
9
mob_mul(g1,g2)=my(m=mobx(g1)*mobx(if(g1[3],conj(g2),g2)));[m[1,1],m[1,2],g1[3]!=g2[3]];\
10
mob_inv(g)=if(g[3],[g[1],-conj(g[2]),1],[conj(g[1]),-g[2],0]);\
18502 bpr 11
\\ Homographie (et anti) qui envoient (0,1) sur (a,b), ou a est un point du disque et b a l'horizon\
12
mob_ori(a,b,c)=my(e=sqrt(b),g1=(e-conj(e)*a)/(1-norm(a)));[g1,a*conj(g1),c];\
13
\\ Point d'intersection de la demi-geodesique de a vers b avec l'horizon\
14
hor(a,b)=my(z=mob([1,-a,0],b));mob([1,a,0],z/sqrt(norm(z)));\
15
\\ Homographie (et anti) qui envoient (a,b) sur (c,d), sous l'hypothèse d(a,b)=d(c,d)\
16
mob_abcd(a,b,c,d,e)=mob_mul(mob_ori(c,hor(c,d),e),mob_inv(mob_ori(a,hor(a,b))));\
18430 bpr 17
\\ Homographie qui echange a et b\
18
mob_exg(a,b)={my(h=[1,a,0],h1=mob_inv(h),c=mob(h1,b));\
19
  mob_mul(h,mob_mul([I,-I*c,0],h1))};\
20
\\ Reflection par rapport à la geodesique qui joint a et b\
21
mob_ref(a,b)={\
22
  my(num=a*b*conj(a-b)+b-a,den=conj(a)*b-conj(b)*a,c,d,h);\
23
  d=if(norm(den)*1e8<norm(num),\
24
    if (norm(b)<norm(a),sqrt(a/conj(a)),sqrt(b/conj(b))),\
25
    c=num/den;(1+sqrt(1-norm(c)))/conj(c));\
18502 bpr 26
  h=mob_ori(a,d);\
18430 bpr 27
  mob_mul(h,mob_mul([1,0,1],mob_inv(h)))\
28
  };\
29
\\ "Distance" entre a et b, comprise entre 0 et 1. La vraie est log((1+d)/(1-d))\
30
dist(a,b)=sqrt(norm(mob([1,-a,0],b)));\
31
\\ Angle abc, compris entre -Pi et Pi\
32
angle(a,b,c)=my(g=[1,-b,0]); arg(mob(g,c)/mob(g,a));\
33
\
34
\\ ------------------------------------------------------------------------------------\
35
\\ Dessin d'arcs et de polygones\
36
\\ ------------------------------------------------------------------------------------\
37
\\ Trace (en tikz) la geodesique entre a et b\
18451 bpr 38
tikz_arc(o,a,b)={\
18430 bpr 39
  my(num=a*b*conj(a-b)+b-a,den=conj(a)*b-conj(b)*a,c,t,arga,argb);\
18457 bpr 40
  if(norm(den)*1e8<=norm(num),\
18451 bpr 41
    filewrite1(o,strprintf("--(%.4f,%.4f)",real(b),imag(b))),\
18430 bpr 42
    c=num/den;\
43
    arga=arg(a-c)/Pi*180;\
44
    argb=arg(b-c)/Pi*180;\
45
    if (abs(arga-argb)>180,if(arga<argb,arga+=360,argb+=360));\
18451 bpr 46
    filewrite1(o,strprintf("arc(%.4f:%.4f:%.4f)",arga,argb,sqrt(norm(c)-1))))\
18430 bpr 47
};\
48
\\ Trace un polygone hyperbolique, rempli ou non, etiquete ou non\
18451 bpr 49
tikz_poly(o,v,label,fill)={\
18449 bpr 50
  my(n=#v,z);\
51
  if (label > 0,\
18451 bpr 52
    z=vecsum(v)/n;filewrite1(o,strprintf("\\%s(%.4f,%.4f)node{\\tiny$%d$}(%.4f,%.4f)",\
53
      if(fill,"fill","draw"),real(z),imag(z),label,real(v[1]),imag(v[1]))),\
54
    filewrite1(o,strprintf("\\%s(%.4f,%.4f)",\
55
      if(fill,"fill","draw"),real(v[1]),imag(v[1]))));\
56
  for(i=1,n,tikz_arc(o,v[i],v[i%n+1]));\
57
  filewrite(o,";")\
18430 bpr 58
};\
59
\
60
\\ ------------------------------------------------------------------------------\
61
\\ Pavage obtenu a partir d'un polygone convexe pavant\
62
\\ ------------------------------------------------------------------------------\
63
\\ Entree:  v_i, points du disque de Poincare et d_i>2 des entiers\
64
\\ On suppose que les v_i forment le bord oriente d'un polygone convexe (pave) P0\
65
\\ dont l'angle intérieur au point v_i est  2Pi/d_i\
66
\\ Si deux cotes consecutifs sont inegaux, le d_i entre eux est suppose pair\
18449 bpr 67
\\ Renvoie sous forme de fichier off\
18430 bpr 68
\\ tous les paves dont au moins un sommet est dans le disque euclidien D(0,1-eps)\
18449 bpr 69
\\ Si eps>=1, on s'en sert comme limite sur le nombre de paves.\
18502 bpr 70
\\ Si z0 est présent, c'est un point du pavé de base dont les transformés seront calculés\
71
\\ Comme base du pavage dual\
18430 bpr 72
\
18502 bpr 73
hyp_pav(v,d,eps,z0)={\
18451 bpr 74
  my(n=#v,a,b,s,s1,s2,t,t1,t2,g,gg,cd0,cd1,cd2,r2,f1,v1,w0,z,limit);\
75
  if(eps>=1,limit=eps;eps=0,limit=1000);\
18430 bpr 76
  r2=(1-eps)^2;\
18449 bpr 77
  if(!v,return(0));\
18430 bpr 78
\
79
\\ Les reflexions qui engendrent W\
80
  g=vector(n,i,mob_ref(v[i],v[i%n+1]));\
81
\
82
\\ Creation du premier polygone et de son squelette\
83
  \\ Pour chaque sommet, [arite restante, derniere arete cree, affixe, dans le disque?]\
84
  cd2=List(vector(n,s,[d[s]-2,if(s==1,n,s),v[s],norm(v[s])<r2]));\
85
  \\ Pour chaque arete, [origine, extremite, type, premier polygone borde, active]\
86
  cd1=List(vector(n,a,[a,a%n+1,a,1,cd2[a][4]||cd2[a%n+1][4]]));\
87
  \\ Pour chaque polygone, ses aretes et l'élément du groupe\
88
  cd0=List([vector(n+1,a,if(a>n,[1,0,0],a))]);\
89
\
18449 bpr 90
  while(#cd0<limit&&f1<#cd1, f1+=1; v1=cd1[f1]; if(v1[5],\
18430 bpr 91
    s=v1[3]; \\ type de l'arete (ambigu)\
92
\\  Nouveau pave et ses aretes, manquantes ou pas\
93
    w0=vector(n+1);\
94
    w0[n+1]=gg=mob_mul(cd0[v1[4]][n+1],g[s]);\
95
    w0[s]=a=f1; cd1[a][5]=0;\
96
    s1=cd1[a][1]; s2=cd1[a][2];\
97
    b=cd0[v1[4]][s%n+1];\
98
    if(s2!=cd1[b][1]&&s2!=cd1[b][2],t=s1;s1=s2;s2=t); \\ arete mal orientee\
18457 bpr 99
    t1=(s-2)%n+1;\
100
    while(!cd2[s1][1]&&!w0[t1], \\ aretes precedent f1 qui sont deja la\
18451 bpr 101
      w0[t1]=a=cd2[s1][2]; cd1[a][5]=0;\
18457 bpr 102
      s1=cd1[a][1]+cd1[a][2]-s1; t1=(t1-2)%n+1);\
103
    t2=s%n+1;\
104
    while(!cd2[s2][1]&&!w0[t2], \\ aretes suivant f1 qui sont deja la\
18451 bpr 105
      w0[t2]=a=cd2[s2][2]; cd1[a][5]=0;\
18457 bpr 106
      s2=cd1[a][1]+cd1[a][2]-s2; t2=t2%n+1);\
107
    while(t1!=t2, \\ Il y a au moins deux aretes a creer\
108
      if(s1<s2,\
109
        z=mob(gg,v[t1]);\
110
        listput(cd2,[d[t1]-1,#cd1+1,z,norm(z)<r2]);\
111
        listput(cd1,[s1,#cd2,t1,#cd0+1,cd2[s1][4]||cd2[#cd2][4]]); w0[t1]=#cd1;\
112
        cd2[s1][1]-=1; cd2[s1][2]=#cd1; s1=#cd2; t1=(t1-2)%n+1,\
113
        z=mob(gg,v[t2%n+1]);\
114
        listput(cd2,[d[t2%n+1]-1,#cd1+1,z,norm(z)<r2]);\
115
        listput(cd1,[s2,#cd2,t2,#cd0+1,cd2[s2][4]||cd2[#cd2][4]]); w0[t2]=#cd1;\
116
        cd2[s2][1]-=1; cd2[s2][2]=#cd1; s2=#cd2; t2=t2%n+1));\
117
      listput(cd1,[s1,s2,t1,#cd0+1,cd2[s1][4]||cd2[s2][4]]); w0[t1]=#cd1;\
118
      cd2[s1][1]-=1; cd2[s1][2]=#cd1; cd2[s2][1]-=1; cd2[s2][2]=#cd1;\
119
      listput(cd0,w0)));\
18430 bpr 120
  for(f=1,#cd0,\
121
    w=cd0[f];a=cd1[w[1]];b=cd1[w[n]];\
122
    s=a[1];if(s!=b[1]&&s!=b[2],s=a[2]);\
123
    for(i=1,n,a=cd1[w[i]];w[i]=s;s=a[1]+a[2]-s);\
124
    cd0[f]=w);\
18457 bpr 125
 \\ Si les d_i ne sont pas tous pairs, la derniere colonne n'a pas de sens\
18502 bpr 126
  res=vector(if(z0,4,2));\
127
  res[1]=matrix(#cd2,2,i,j,if(j==1,real(cd2[i][3]),imag(cd2[i][3])));\
128
  res[2]=matrix(#cd0,n+2,i,j,if(j==1,n,if(j<=n+1,cd0[i][j-1],cd0[i][n+1][3])));\
129
  res\
18430 bpr 130
};\
131
\
18457 bpr 132
\\ Dessine le pavage en tikz. r est un vecteur a deux composantes "off"\
133
tikz_off(fname,r,rayon,fill,labels)={\
134
  my(pts=r[1],pvs=r[2],n=#pvs[1,]-2,o=fileopen(fname,"w"));\
18451 bpr 135
  filewrite(o,strprintf("\\begin{tikzpicture}[scale=5]\n\\draw(0,0)circle(1);\n"));\
136
  if(rayon,filewrite(o,strprintf("\\draw(0,0)circle(%.4f);\n",rayon)));\
18449 bpr 137
  for(i=1,#pvs[,1],\
18457 bpr 138
    tikz_poly(o,vector(n,j,pts[pvs[i,j+1],1]+I*pts[pvs[i,j+1],2]),if(labels,i),fill&&pvs[i,n+2]));\
18502 bpr 139
  if (#r>2, pts=r[3]; pvs=r[4]; for(i=1,#pvs[,1],\
140
    tikz_poly(o,vector(pts[i,1],j,pts[pvs[i,j+1],1]+I*pts[pvs[i,j+1],2]),if(labels,i))));\
141
filewrite(o,strprintf("\\end{tikzpicture}"));\
18451 bpr 142
  fileclose(o);\
143
};\
18449 bpr 144
\
18430 bpr 145
\\ -----------------------------------------------------------------------------------\
146
\\ Creation de polygones convexes d'angles et longueurs donnees\
147
\\ -----------------------------------------------------------------------------------\
148
\\ S'il existe un triangle de côtés a,b,c et angles A,B,C, les fonctions suivantes\
149
\\ renvoient les paramètres manquants. Sinon, elles renvoient 0\
150
abc(A,B,C)={\
151
  if (A+B+C >= Pi, return(0));\
152
  my(cha=(cos(A)+cos(B)*cos(C))/(sin(B)*sin(C)),\
153
    chb=(cos(B)+cos(A)*cos(C))/(sin(A)*sin(C)),\
154
    chc=(cos(C)+cos(B)*cos(A))/(sin(B)*sin(A)));\
155
  [sqrt((cha-1)/(cha+1)),sqrt((chb-1)/(chb+1)),sqrt((chc-1)/(chc+1))]\
156
};\
157
ABC(a,b,c)={\
158
  if(c>=a+b-a*b || b>=a+c-a*c || a>=b+c-b*c, return (0));\
159
  my(cha=(1+a^2)/(1-a^2),chb=(1+b^2)/(1-b^2),chc=(1+c^2)/(1-c^2),\
160
     sha=2*a/(1-a^2),shb=2*b/(1-b^2),shc=2*c/(1-c^2));\
161
  [acos((chb*chc-cha)/(shb*shc)),\
162
   acos((cha*chc-chb)/(sha*shb)),\
163
   acos((chb*cha-chc)/(shb*sha))]\
164
};\
165
AbC(a,B,c)={\
166
  my(cha=(1+a^2)/(1-a^2),chc=(1+c^2)/(1-c^2),sha=2*a/(1-a^2),shc=2*c/(1-c^2),\
167
     chb=cha*chc-sha*shc*cos(B),shb=sqrt(chb^2-1));\
168
  [acos((chb*chc-cha)/(shb*shc)),sqrt((chb-1)/(chb+1)),acos((chb*cha-chc)/(shb*sha))]\
169
};\
170
aBc(A,b,C)={\
171
  my(chb=(1+b^2)/(1-b^2),cB=sin(A)*sin(C)*chb-cos(A)*cos(C),sB,cha,chc);\
172
  if (abs(cB)>=1,return(0),sB=sqrt(1-cB^2));\
173
  cha=(cos(A)+cB*cos(C))/(sB*sin(C));\
174
  chc=(cos(C)+cB*cos(A))/(sB*sin(A));\
175
  if(cha>1 && chc>1,[sqrt((cha-1)/(cha+1)),acos(cB),sqrt((chc-1)/(chc+1))],0)\
176
};\
177
\
178
\\ S'il existe, renvoie le quadrilatère convexe [0,l,z3,z4]\
179
\\ d'angles alpha,beta,gamma,delta et longueur(AB)=l, sinon renvoie 0\
180
quad(al,be,ga,de,l)={\
181
  my(eps=1e-10,g=[1,l,0],t=aBc(al,l,be),eA=exp(I*al),eB=-exp(-I*be),\
182
      u,v,lC,lD,minC,maxC=1.);\
183
  if(t, u=abc(Pi-ga,t[2],Pi-de);\
184
    if(!u||u[1]>=t[3]||u[3]>=t[1], return(0));\
185
    lD=(t[3]-u[1])/(1-u[1]); lC=(t[1]-u[3])/(1-u[3]),\
186
    while(maxC-minC>eps, lC=(maxC+minC)/2; u=AbC(l,be,lC);\
187
      if(u[1]>=ga, minC=lC, v=aBc(al-u[3],u[2],ga-u[1]);\
188
      if(!v,maxC=lC, lD=v[3]; if(v[2]<de, maxC=lC, minC=lC)))));\
189
  [0,l,mob(g,lC*eB),lD*eA]\
190
};\
191
\
192
\\ La tortue hyperbolique, turn left beta, then forward l\
193
lft_fwd(g,beta,l)=my(e=exp(I*beta/2));mob_mul(g,[e,e*l,0]);\
194
\
195
\\ Entree: n angles et n-3 longueurs\
196
\\ Sortie: [z1=0,z2=l1,z3,....,zn] n points du disque de Poincare qui forment le bord\
197
\\ oriente d'un polygone convexe tel que... s'il existe. Sinon, 0.\
18457 bpr 198
polygone(a,l)={\
18449 bpr 199
  my(n=#a,res=vector(n),theta,phi,v,g,z,eth,w);\
18457 bpr 200
  if(n==3,v=abc(a[1],a[2],a[3]); return(if(v,[0,v[3],v[2]*exp(I*a[1])])));\
18430 bpr 201
  g=[1,l[1],0]; res[2]=z=l[1];\
202
  for(i=2,n-3, g=lft_fwd(g,Pi-a[i],l[i]); z=mob(g,0);\
203
    if(arg(z)<=theta,return(0),theta=arg(z));\
204
    res[i+1]=z);\
205
  phi=Pi-angle(mob(g,1),z,0);\
206
  if(theta>=a[1]||phi>=a[n-2], return(0));\
207
  v=quad(a[1]-theta,a[n-2]-phi,a[n-1],a[n],sqrt(norm(z)));\
208
  if(!v,return(0));\
18449 bpr 209
  eth=exp(I*theta); res[n-1]=eth*v[3]; res[n]=eth*v[4];\
18457 bpr 210
  return(res)\
18430 bpr 211
};\
212
\
18502 bpr 213
\\ Entree: n angles entre 0 et Pi, dont la somme est inferieure a (n-2)*Pi\
214
\\ Sortie: L'unique polygone convexe dont tous les cotes sont tangents a un meme cercle\
215
\\   de centre 0,  d'angles interieurs a_i et dont le premier sommet est un reel positif.\
216
\
217
tangentiel(a)={\
218
  my(l,cs=apply(x->cos(x/2),a),\
219
    k=solve(t=0,1,vecsum(apply(x->asin(t*x),cs))-Pi),\
220
    R=sqrt(2/(1+k)-1),\
221
    g=lft_fwd(lft_fwd([1,0,0],-asin(k*cs[1]),R),Pi/2,0),\
222
\\    g=lft_fwd(lft_fwd([1,0,0],0,R),Pi/2,0),\
223
    res=vector(#a));\
224
  for(i=1,#a,\
225
    l=abc(Pi/2,a[i]/2,asin(k*cs[i]))[3];\
226
    g=lft_fwd(g,0,l);\
227
    res[i]=mob(g,0);\
228
    g=lft_fwd(g,Pi-a[i],l));\
229
    res\
230
};\
231
\
18430 bpr 232
\\ ----------------------------------------------------------------------------\
233
\\ Quelques paves simples\
234
\\ ----------------------------------------------------------------------------\
18449 bpr 235
\
18457 bpr 236
\\ Construit un cerf-volant [0,z2,z3,z4] d'angles [a1,a2,a3,a4==a2]\
237
build_kite(a1,a2,a3)={my(tr=polygone([a1/2,a2,a3/2]));\
238
  if(tr,[tr[1],tr[2],tr[3],mob(mob_ref(tr[1],tr[3]),tr[2])])};\
239
\
240
\\  d2 doit etre pair et 1/d1+2/d2+1/d3 < 1\
241
kite(d1,d2,d3,eps,depl)={\
242
  my(p=build_kite(2*Pi/d1,2*Pi/d2,2*Pi/d3));\
243
  if(!p,return(0));\
244
  if(depl,p=vector(4,i,mob(depl,p[i])));\
245
  hyp_pav(p,[d1,d2,d3,d2],eps)};\
246
\
18430 bpr 247
\\ Polygone a n cotes tous egaux, avec angles tous egaux a 2Pi/d\
248
\\ On suppose donc (d-2)(n-2)>4\
18457 bpr 249
regular(n,d,eps,depl=[1,0,0])={\
250
  my(t=polygone([2*Pi/n,Pi/d,Pi/d]));\
18459 bpr 251
  if(t,hyp_pav(vector(n,k,mob(depl,exp(2*I*k*Pi/n)*t[2])),vector(n,k,d),eps))};\
18451 bpr 252
\
18457 bpr 253
\\ 1/d1 + 1/d2+ 1/d3 < 1/2\
254
\\ Si un des trois est impair, les autres sont supposes egaux\
255
triangle(d1,d2,d3,eps,depl=[1,0,0])={\
256
  my(t=polygone([2*Pi/d1,2*Pi/d2,2*Pi/d3]));\
257
  if(t&&depl,t=vector(3,i,mob(depl,t[i])));\
258
  if(t,hyp_pav(t,[d1,d2,d3],eps))};\
259
\
18451 bpr 260
\\ genre de parallelogramme: deux angles distincts\
261
\\ depend d'un parametre mu continu compris entre 0 et 1\
18457 bpr 262
\\ On doit avoir 1/d1 + 1/d2 < 1/2\
263
\\ Si d1 ou d2 est impair, on doit aussi avoir mu=1/2.\
18451 bpr 264
parallelogram(d1,d2,mu,eps,depl)={\
18457 bpr 265
  my(t=polygone([2*Pi/d1,2*mu*Pi/d2,2*Pi*(1-mu)/d2]));\
266
  if(!t,return(0));\
267
  if(depl,t=vector(3,i,mob(depl,t[i])));\
268
  hyp_pav([t[1],t[2],mob(mob_exg(t[2],t[3]),t[1]),t[3]],[d1,d2,d1,d2],eps)};\
269
\
18502 bpr 270
\\ Etant donnes le centre et le rayon (<1) d'un disque hyperbolique,\
271
\\ renvoie le centre et le rayon du meme disque considere comme euclidien.\
272
hyp_cercle(c, r)=my(R2=norm(c),den=1-r^2*R2);[(1-r^2)*c/den,(1-R2)*r/den];\
273
\
274
\\ On se donne n entiers d[i] >= 3, avec la convention d[] périodique modulo n\
275
\\ On suppose que si d[i] est impair, alors on a d[i-1]=d[i+1]\
18506 bpr 276
\\ Calcule le pavage associé au polygone tangentiel d'angles interieurs 2*Pi/d[i]\
18502 bpr 277
\\ On peut afficher le pavage dual et les cercles inscrits /* TO DO */\
278
catalan(d,eps,depl)={\
279
  my(h=tangentiel(apply(x->2*Pi/x,d)));\
280
  if(depl,h=apply(x->mob(depl,x),h));\
281
  hyp_pav(h,d,eps);\
282
}\
283
\
284
\\ Etant donne le "fichier off" d'un pavage issu de catalan\
285
\\ Calcule un "fichier off dual" dont le premier sommet est 0\
286
cat_dual(off)={\
287
  my(cts=vector(#off[2]),fls=vector(#off[1]));\
288
  for(i=1,#off[2],0);\
289
/* TO DO */\
290
\
291
  [cts,fls]\
292
};\
293
\
18430 bpr 294
/*\
18502 bpr 295
tikz_off("8_3_5.tex",kite(8,3,5,0.01))\
18430 bpr 296
regular(7,3,0.1);\
297
parallelogram(4,6,3,0.1);\
298
*/\