import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.applet.*; import java.awt.geom.*; import java.math.*; import java.io.*; /**This class does the 3D polyhedron exchange dynamics.*/ public class PolyhedronExchange { /**This is a simplified version of the main routine, which returns the super tile one gets by doing LIM steps of the iteration**/ public static Polyhedron orbitTilePartial(Vector V,int LIM) { double[] d=orbitGeometryPartial(V,LIM); Polyhedron X=reconstruct(V,d); return(X); } public static Polyhedron orbitTilePartialInverse(Vector V,int LIM) { Vector W=new Vector(2-V.x[0],2-V.x[1],2-V.x[2]); double[] d=orbitGeometryPartial(W,LIM); Polyhedron X=reconstruct(W,d); for(int i=0;i1) high=true; for(int i=0;i1.999999)) P.V[i].x[1]=P.V[i].x[1]-2; } return(P); } /**Here is the basic routine. It works for the modes 0,1,2. The mode-3 case requires the correction mentioned above.*/ public static Polyhedron orbitTileBasic(int mode,double bot,double top,Vector V,int LIM) { double[] d=orbitGeometry(mode,V,LIM); if(d==null) return(null); d[0]=Math.min(d[0],top-V.x[2]); //chop the top d[9]=Math.min(d[9],V.x[2]-bot); //chop the bottom Polyhedron X=reconstruct(V,d); X.orbit=(int)(d[18]); return(X); } /**This routine looks at the orbit and records how far each point in the orbit lies from each of the faces of the polyhedron containing it. For each direction, the minimum over the orbit is computed. These 18 numbers are then used to compute the orbit tile. There are 3 options: mode = 0: straight-up orbit mode = 1: track the orbit until it lies in renorm set A mode = 2: track the orbit until it lies in renorm set B **/ public static double[] orbitGeometry(int mode,Vector V0,int LIM) { double[] d=new double[18]; for(int i=0;i<18;++i) d[i]=100; Vector V=new Vector(V0); int history=-1; int type=-1; int count=0; int periodic=0; boolean test=false; boolean inside=false; while((count0) test=true; } } /**the chopped polyhedra**/ if(mode==2) { int[] q=DataRenorm.indexB(V); if(q!=null) { d=updateSpectrumB(d,V,q); if(count>0) test=true; } } if(test==false) { if(history==-1) type=PolyhedronExchange.classify(V); if(history!=-1) type=PolyhedronExchange.classify(V,history); history=type; d=PolyhedronExchange.updateSpectrum(d,V,type); V=doDynamicsPlus(V,type); if(Vector.dist(V,V0)<.0000001) { test=true; periodic=1; } ++count; } } if(test==false) return(null); double[] e=new double[20]; for(int i=0;i<18;++i) e[i]=d[i]; e[18]=count; //the number of iterates return(e); } /**The vector is supposed to lie inside the qth polyhedron. The list of 18 numbers is the dot product with the outer normals of the polyhedron. Most entries will be 0.**/ public static double[] updateSpectrum(double[] d1,Vector W,int q) { GoldenPolyhedron P=DataPartition.getGoldenPolyhedron(q); int[] N=DataPartitionRaw.polyNormal(q); int[] A=DataPartitionRaw.faceAnchor(q); double[] d2=new double[18]; for(int i=0;i<18;++i) d2[i]=d1[i]; for(int i=0;itest) d2[N[i]]=test; } return(d2); } /**This does the same thing but incorporates the polyhedra from the A renorm set.*/ public static double[] updateSpectrumA(double[] d1,Vector V,int[] q) { Vector W=DataRenorm.AtoB(q[0],q[1],q[2],V); GoldenPolyhedron P=DataRenorm.getGoldenB(q[1],q[2]); int[] N=DataRenormRaw.polyNormal(q[1],q[2]); int[] A=DataRenormRaw.faceAnchor(q[1],q[2]); double[] d2=new double[18]; for(int i=0;i<18;++i) d2[i]=d1[i]; for(int i=0;itest) d2[N[i]]=test; } return(d2); } /**This does the same thing but incorporates the polyhedra from the B renorm set.*/ public static double[] updateSpectrumB(double[] d1,Vector W,int[] q) { GoldenPolyhedron P=DataRenorm.getGoldenB(q[0],q[1]); int[] N=DataRenormRaw.polyNormal(q[0],q[1]); int[] A=DataRenormRaw.faceAnchor(q[0],q[1]); double[] d2=new double[18]; for(int i=0;i<18;++i) d2[i]=d1[i]; for(int i=0;itest) d2[N[i]]=test; } return(d2); } /**DYNAMICS ROUTINES**/ public static Vector doDynamicsPlus(Vector V) { int type=classify(V); return(doDynamicsPlus(V,type)); } public static Vector doDynamicsMinus(Vector V) { int type=classifyInverse(V); return(doDynamicsMinus(V,type)); } public static Vector doDynamicsPlus(Vector V,int type) { Complex z=DataPartition.getMove3D(type); Vector W=Vector.plus(V,new Vector(z.x,z.y,0)); W=TorusMap.fundamentalDomain(W); return(W); } public static Vector doDynamicsMinus(Vector V,int type) { Complex z=DataPartition.getMove3D(type); Vector W=Vector.minus(V,new Vector(z.x,z.y,0)); W=TorusMap.fundamentalDomain(W); return(W); } /**CLASSIFICATION ROUTINES**/ /**This tells which of the 64 regions contains the point W.*/ public static int classify(Vector W) { for(int i=0;i<64;++i) { if(testInside(W,i)==true) return(i); } return(-1); } /**This routine speeds up the preceding one. If we know the history of the map, i.e. the previous iterate, then we can predict the possible indices which will contain the vector.**/ public static int classify(Vector W,int history) { int[] A=DataPartitionRaw.successor(history); for(int i=0;i-.0000000001) test=0; if(test<0) return(false); } return(true); } /**RECONSTRUCTION**/ /**This routine reconstructs the polyhedron from the list of faces.**/ public static Polyhedron reconstruct(Vector V,double[] d) { Vector[] LIST=new Vector[100]; int total=0; for(int i=0;i<18;++i) { for(int j=i+1;j<18;++j) { for(int k=j+1;k<18;++k) { int[] n={i,j,k}; double[] dd={d[i],d[j],d[k]}; if((d[i]<100)&&(d[j]<100)&&(d[k]<100)) { Vector W=intersect(n,dd); boolean test=pass(d,W); if(test==true) { W=Vector.plus(W,V); if(Lists.match(W,LIST,total)==false) { LIST[total]=new Vector(W); ++total; } } } } } } Polyhedron X=new Polyhedron(); X.count=total; for(int i=0;i