import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.applet.*; import java.awt.geom.*; import java.math.*; public class ArithmeticGraphBox { int p,q; /*This class computes some quantities associated to the arithmetic graph and the hexagrid theorem. These quantities are discussed in chapter 3 of the monograph*/ public ArithmeticGraphBox(int pp,int qq) { p=pp; q=qq; } public GeneralPath arithmeticKite() { GeneralPath gp=new GeneralPath(); float x1=0; float y1=0; float x2=0; float y2=(float)(.5*(p+q)); float x3=(float)(p); float y3=(float)(((p+q)*(p+q)-2.0*p*p)/(2.0*q)); float x4=(float)(2.0*p*q/(p+q)); float y4=(float)(((p+q)*(p+q)-4.0*p*p)/(2.0*(p+q))); gp.moveTo(x1,y1); gp.lineTo(x2,y2); gp.lineTo(x3,y3); gp.lineTo(x4,y4); gp.closePath(); return(gp); } /* These are the same 2 vectors as in the monograph - V and W. The vector V is the fundamental symmetry of the graph, and the vector W is parallel to the walls of the room grid.*/ public double[] VectorV() { double[] X=new double[2]; X[0]=1.0*q; X[1]=-1.0*p; return(X); } public double[] VectorW() { double[] X=new double[2]; X[0]=1.0*(p*q)/(p+q); X[1]=X[0]+(q-p)/2.0; return(X); } public double[] VectorVprime() { double[] X=new double[2]; X[0]=0; int test=(p*q)%2; X[1]=(p+q)*(p+q); if(test==1) X[1]=X[1]/4; return(X); } /*slope of the W vector. The slope is defined even in the irrational case, while the vector itself is not defined.*/ public static double slopeW(double A) { double s=1+0.5*(1+A)*(1-A)/A; return(s); } /*These routines are used for rotations*/ public AffineTransform AFF1() { double[] m1=VectorV(); double[] m2=VectorW(); double a=m1[0]; double b=m1[1]; double c=m2[0]; double d=m2[1]; AffineTransform A=new AffineTransform(a,b,c,d,0,0); return(A); } public AffineTransform AFF2() { double[] m1=VectorV(); double[] m2=VectorW(); double a=-m1[0]; double b=-m1[1]; double c=m2[0]; double d=m2[1]; AffineTransform A=new AffineTransform(a,b,c,d,0,0); try {A=A.createInverse();} catch(Exception e) {} return(A); } public AffineTransform AFF3() { int[] x=MathRational.RPLUS(p,q); double x0=1.0*x[0]; double x1=1.0*x[1]; x0=x1*p/q; AffineTransform A=AffineTransform.getTranslateInstance(x1,-x0); return(A); } public AffineTransform AFF4() { double xx=2.0; double[] m1=VectorV(); double[] m2=VectorW(); double a=m1[0]; double b=m1[1]; double c=xx*m2[0]; double d=xx*m2[1]; AffineTransform A=new AffineTransform(a,b,c,d,0,0); try {A=A.createInverse();} catch(Exception e) {} return(A); } public AffineTransform AFF5() { int[] x=MathRational.pivot(p,q); double xx=1.0*(x[0]+x[2])/2.0; double yy=1.0*(x[1]+x[3])/2.0; AffineTransform B=AffineTransform.getTranslateInstance(-xx,-yy); return(B); } public GeneralPath pureReflect(GeneralPath gp1) { GeneralPath gp2=new GeneralPath(gp1); gp2.transform(AFF2()); gp2.transform(AFF1()); return(gp2); } public GeneralPath reflect(GeneralPath gp1) { GeneralPath gp2=new GeneralPath(gp1); gp2.transform(AFF2()); gp2.transform(AFF1()); gp2.transform(AFF3()); return(gp2); } public GeneralPath straighten(GeneralPath gp1) { AffineTransform A1=AFF4(); AffineTransform A2=AFF5(); GeneralPath gp2=new GeneralPath(gp1); gp2.transform(A2); gp2.transform(A1); return(gp2); } /* Here is the period box */ public GeneralPath periodBox() { double[] V=VectorV(); double[] W=VectorVprime(); double a0=V[0]; double a1=V[1]; double c0=W[0]; double c1=W[1]; double d0=a0+c0; double d1=a1+c1; GeneralPath gp=new GeneralPath(); gp.moveTo(0,0); gp.lineTo((float)(a0),(float)(a1)); gp.lineTo((float)(d0),(float)(d1)); gp.lineTo((float)(c0),(float)(c1)); gp.closePath(); return(gp); } /* Here is a general parallogram whose sides are parallel to V and W.*/ public GeneralPath parallelogram(double x1,double x2,double y) { double[] V=VectorV(); double[] W=VectorW(); double a0=V[0]*x1; double a1=V[1]*x1; double b0=V[0]*x2; double b1=V[1]*x2; double c0=W[0]*y; double c1=W[1]*y; double d0=a0+c0; double d1=a1+c1; double e0=b0+c0; double e1=b1+c1; GeneralPath gp=new GeneralPath(); gp.moveTo((float)(a0),(float)(a1)); gp.lineTo((float)(b0),(float)(b1)); gp.lineTo((float)(e0),(float)(e1)); gp.lineTo((float)(d0),(float)(d1)); gp.closePath(); return(gp); } /*This is the room, from the Room Lemma*/ public GeneralPath basicBox() { GeneralPath gp=new GeneralPath(); if((p*q)%2==1) return(parallelogram(0,1,1)); return(parallelogram(-1,1,2)); } /*These boxes are from the Decomposition Theorem */ public GeneralPath sonBox1() { int[] c=MathRational.superiorPredecessor(p,q); int[] a=MathRational.RPLUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(0,w,h)); } public GeneralPath fatherBox1() { int[] a=MathRational.RMINUS(p,q); double w=1.0*a[1]/q; return(parallelogram(-w,0,1)); } public GeneralPath sonBox2() { int[] c=MathRational.superiorPredecessor(p,q); int[] a=MathRational.RMINUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(-w,0,h)); } public GeneralPath fatherBox2() { int[] a=MathRational.RPLUS(p,q); double w=1.0*a[1]/q; return(parallelogram(0,w,1)); } /*These parallelograms are part of the TRAPS defined in Part VI of the monograph*/ public GeneralPath OddEvenBox1() { int[] c=MathRational.RPLUS(p,q); c=MathRational.oddPredecessor(c[0],c[1]); int[] a=MathRational.RMINUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(-w,0,h)); } public GeneralPath OddEvenBox2() { int[] c=MathRational.RMINUS(p,q); c=MathRational.oddPredecessor(c[0],c[1]); int[] a=MathRational.RPLUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(0,w,h)); } public GeneralPath EvenEvenBox1() { int[] c=MathRational.RMINUS(p,q); c=MathRational.oddPredecessor(c[0],c[1]); int[] a=MathRational.RPLUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(0,w,h)); } public GeneralPath EvenOddBox1() { int[] c=MathRational.RPLUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); int[] a=MathRational.RMINUS(p,q); double w=1.0*a[1]/q; return(parallelogram(-w,0,h)); } public GeneralPath EvenEvenBox2() { int[] c=MathRational.RPLUS(p,q); c=MathRational.oddPredecessor(c[0],c[1]); int[] a=MathRational.RMINUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); double w=1.0*a[1]/q; return(parallelogram(-w,0,h)); } public GeneralPath EvenOddBox2() { int[] c=MathRational.RMINUS(p,q); double h=(1.0*c[0]+1.0*c[1])/(p+q); int[] a=MathRational.RPLUS(p,q); double w=1.0*a[1]/q; return(parallelogram(0,w,h)); } /*Here are two special families of lines, both parallel to the walls*/ public GeneralPath iotaWall() { GeneralPath gp=new GeneralPath(); int[] a=MathRational.RPLUS(p,q); double x1=1.0*(p*q)/(p+q); double y1=x1+(q-p)/2.0; x1=x1*20; y1=y1*20; gp.moveTo((float)(a[1]-x1),(float)(-a[0]-y1)); gp.lineTo((float)(a[1]+x1),(float)(-a[0]+y1)); gp.closePath(); return(gp); } public GeneralPath symmLine() { GeneralPath gp=new GeneralPath(); int[] a=MathRational.RPLUS(p,q); double x1=1.0*(p*q)/(p+q); double y1=x1+(q-p)/2.0; x1=x1*20; y1=y1*20; gp.moveTo((float)(.5*a[1]-x1),(float)(-.5*a[0]-y1)); gp.lineTo((float)(.5*a[1]+x1),(float)(-.5*a[0]+y1)); gp.closePath(); return(gp); } }