import java.applet.Applet; import java.awt.event.*; import java.awt.*; import java.awt.geom.*; public class PinwheelMap { double[][] h=new double[5][3]; Complex[] v=new Complex[10]; double A; /**This class is originally designed to work with any kite parameter (A), but we always take the Penrose kite parameter sqrt(5)-2*/ public PinwheelMap() { this.A=Math.sqrt(5)-2; v[0]=new Complex(-2,-2); v[1]=new Complex(0,4); v[2]=new Complex(-2,2); v[3]=new Complex(-2-2*A,0); v[0]=new Complex(-2,-2); h[0][0]=-1; h[0][1]=-1; h[0][2]=+3; h[1][0]=-1; h[1][1]=+1; h[1][2]=+3; h[2][0]= -2/(1+A); h[2][1]= 2*A/(1+A); h[2][2]= 2*A/(1+A); h[3][0]= -2/(1+A); h[3][1]=-2*A/(1+A); h[3][2]= 2*A/(1+A); for(int i=0;i<4;++i) { for(int j=0;j<3;++j) { h[i][j]=.25*h[i][j]; } } } /**THE MAIN MAPS**/ /**Here is the main map, called E_k in the paper**/ public Complex E(int k,Complex z) { int j=k%4; int d=getDepth(j,z); Complex V=new Complex(d*v[j].x,d*v[j].y); Complex w=Complex.plus(V,z); return(w); } /**Here is the map zeta from the paper.*/ public Complex zeta(Complex u) { double d=Math.floor(.25*u.y+.5); Complex v=new Complex(u.x,u.y-4*d); return(v); } /**Here is the first return map**/ public Complex pi(Complex zz) { Complex z=new Complex(zz); for(int j=1;j<=8;++j) { z=E(j%4,z); } z=zeta(z); return(z); } public Complex piInverse(Complex zz) { Complex z=zz.conjugate(); z=pi(z); z=z.conjugate(); return(z); } public Complex piHalf(Complex zz) { Complex z=new Complex(zz); for(int j=1;j<=4;++j) { z=E(j%4,z); } z=zeta(z); return(z); } /**Here is the first return map for polygons. We use the orbit of the center of mass of the polygons. Therefore, this method only works for orbit tiles, or at least for tiles on which the first return map is entirely defined.**/ public PolyWedge pi(PolyWedge P) { Complex z1=P.getCenter(); Complex z2=pi(z1); Complex z3=Complex.minus(z2,z1); return(P.translate(z3)); } public PolyWedge piHalf(PolyWedge P) { Complex z1=P.getCenter(); Complex z2=piHalf(z1); Complex z3=Complex.minus(z2,z1); return(P.translate(z3)); } /**INGREDIENTS IN THE PINWHEEL MAP**/ public double evaluate(int j,Complex z) { Complex V=new Complex(v[j]); double d=h[j][0]*z.x+h[j][1]*z.y+h[j][2]; return(d); } public int getDepth(int j,Complex z) { double d=evaluate(j,z); int n=-(int)(Math.floor(d)); return(n); } public double getStripPosition(int j,Complex z) { double d=evaluate(j,z); return(d-Math.floor(d)); } public int findSector(Complex z) { double d1=evaluate(1,z); double d2=evaluate(2,z); double d3=evaluate(3,z); double d4=evaluate(0,z); if((d4<1)&&(d1<0)) return(1); if((d2<0)&&(d1>0)) return(2); if((d2>0)&&(d3<0)) return(3); if((d4<0)&&(d3>0)) return(4); if((d4>0)&&(d1>1)) return(5); if((d2>1)&&(d1<1)) return(6); if((d2<1)&&(d3>1)) return(7); if((d4>1)&&(d3<1)) return(8); return(0); } /**MAPS ASSOCIATED TO THE INTEGRAL SEQUENCE AND ARITHMETIC GRAPH**/ /**This computes all the integer parts of the basic octagon*/ public int[] mapSpectrum(Complex zz) { int[] n=new int[10]; Complex z=new Complex(zz); for(int j=1;j<=8;++j) { n[j]=getDepth(j%4,z); z=E(j%4,z); } return(n); } /**This computes the basic map spectrum, and also adds a last term, which encodes the action of the map zeta.**/ public int[] mapSpectrumPlus(Complex zz) { int[] n=new int[10]; Complex z=new Complex(zz); for(int j=1;j<=8;++j) { n[j]=getDepth(j%4,z); z=E(j%4,z); } double d=Math.floor(.25*z.y+.5); n[9]=(int)(-d); return(n); } /**Here are the main maps for the arithmetic graphs.*/ public int[] piIntegral(Complex zz) { int[] n=mapSpectrum(zz); int[] s=new int[3]; s[0]=-n[7]-n[3]; s[1]=-n[2]-n[3]-n[4]-n[6]-n[7]-n[8]; int parity=(s[0]+s[1]+4)%2; s[2]=(int)(zz.y); s[2]=1; if(zz.y<0) s[2]=-1; if(parity==1) s[2]=-s[2]; return(s); } /*This second map works because complex conjugatation conjugates the outer billiards map to its inverse.*/ public int[] piInverseIntegral(Complex zz) { Complex z=zz.conjugate(); int[] d=piIntegral(z); return(d); } /**ROUTINES WHICH PRODUCE THE ORBIT TILES**/ /**These routines are used in order to compute the orbit tile based on how close the corresponding orbit point comes to the pinwheel strip boundaries.*/ /*Here is the main routine*/ public PolyWedge createShape(double[][] e,Complex z) { double[][] d=new double[4][2]; for(int i=0;i<4;++i) { d[i][0]=-e[i][0]; d[i][1]=1-e[i][1]; } PolyWedge WEDGE1=rhomb1(d[1][0],d[0][0],d[1][1],d[0][1],z); PolyWedge WEDGE2=rhomb2(d[2][0],d[3][0],d[2][1],d[3][1],z); PolyWedge WEDGE=PolyWedge.merge(WEDGE1,WEDGE2); return(WEDGE); } public PolyWedge createShapeA(double[][] e,Complex z) { double[][] d=new double[4][2]; for(int i=0;i<4;++i) { d[i][0]=-e[i][0]; d[i][1]=1-e[i][1]; } PolyWedge WEDGE1=rhomb1(d[1][0],d[0][0],d[1][1],d[0][1],z); return(WEDGE1); } public PolyWedge createShapeB(double[][] e,Complex z) { double[][] d=new double[4][2]; for(int i=0;i<4;++i) { d[i][0]=-e[i][0]; d[i][1]=1-e[i][1]; } PolyWedge WEDGE2=rhomb2(d[2][0],d[3][0],d[2][1],d[3][1],z); return(WEDGE2); } public Complex[] makeLine0(double d,Complex z) { Complex[] w=new Complex[2]; w[0]=new Complex(z.x+d*v[0].x,z.y+d*v[0].y); w[1]=Complex.plus(w[0],new Complex(1,-1)); return(w); } public Complex[] makeLine1(double d,Complex z) { Complex[] w=new Complex[2]; w[0]=new Complex(z.x+d*v[1].x,z.y+d*v[1].y); w[1]=Complex.plus(w[0],new Complex(1,1)); return(w); } public Complex[] makeLine2(double d,Complex z) { Complex[] w=new Complex[2]; w[0]=new Complex(z.x+d*v[2].x,z.y+d*v[2].y); w[1]=Complex.plus(w[0],new Complex(A,1)); return(w); } public Complex[] makeLine3(double d,Complex z) { Complex[] w=new Complex[2]; w[0]=new Complex(z.x+d*v[3].x,z.y+d*v[3].y); w[1]=Complex.plus(w[0],new Complex(A,-1)); return(w); } public Complex getVertex(Complex[] z1,Complex[] z2) { Vector V1=new Vector(z1[0]); Vector V2=new Vector(z1[1]); Vector V3=new Vector(z2[0]); Vector V4=new Vector(z2[1]); Vector V5=V1.cross(V1,V2); Vector V6=V1.cross(V3,V4); Vector V7=V1.cross(V5,V6); Complex z=V7.toComplex(); return(z); } public PolyWedge rhomb1(double d1,double d2,double d3,double d4,Complex z) { Complex[] w1=makeLine1(d1,z); Complex[] w2=makeLine0(d2,z); Complex[] w3=makeLine1(d3,z); Complex[] w4=makeLine0(d4,z); PolyWedge P=new PolyWedge(); P.count=4; P.z[0]=getVertex(w1,w2); P.z[1]=getVertex(w2,w3); P.z[2]=getVertex(w3,w4); P.z[3]=getVertex(w4,w1); return(P); } public PolyWedge rhomb2(double d1,double d2,double d3,double d4,Complex z) { Complex[] w1=makeLine2(d1,z); Complex[] w2=makeLine3(d2,z); Complex[] w3=makeLine2(d3,z); Complex[] w4=makeLine3(d4,z); PolyWedge P=new PolyWedge(); P.count=4; P.z[0]=getVertex(w1,w2); P.z[1]=getVertex(w2,w3); P.z[2]=getVertex(w3,w4); P.z[3]=getVertex(w4,w1); return(P); } }