package Current.plot.Dyadic;
import Current.popups.Unfold.*;
import Current.basic.*;
import Current.*;
import java.applet.Applet;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.*;
public class DyadicPlotter {
int mode;
int detail; // detail of the plot to do
int type_of_plot;
int filter;
Color C;
public Complex Z;
//defining functions
int[][][] denominator=new int[3][3][1000];
int[][] numerator=new int[4][1000];
CombinatorialTriangle[] CT;
int[] top;
int[] bot;
int palindrome;
int spine;
String W;
int sign;
VertexPair V;
int[][] record=new int[2][2000];
//lists of dyadic squares
DyadicSquare INIT;
DyadicSquare[] D=new DyadicSquare[10000];
DyadicSquare[] DEF=new DyadicSquare[10000];
DyadicSquare[] IN=new DyadicSquare[10000];
int D_N,IN_N,DEF_N;
//memory
VertexPair[] VP=new VertexPair[5000];
Complex[][] CORNER=new Complex[3][3];
int corner[]=new int[3];
Complex[][] data=new Complex[3][11];
int SMALL;
//billiard like input
Complex[] BL;
Complex BL_CENTER;
int right,obtuse;
DyadicPlotterInit DPI;
//for the zone plotter
VertexPair LEADER;
Interrupter I;
public DyadicPlotter(int mode, int type_of_plot, int detail,int filter,
String word, Color C, Interrupter I) {
this.mode=mode;
this.type_of_plot=type_of_plot;
this.detail=detail;
this.filter=filter;
this.C=C;
this.I=I;
doReset(word);
}
public static DyadicTile zonePlot(int type_of_plot,String word,int detail,Color C,Complex Z, Interrupter I) {
double time1=System.currentTimeMillis();
DyadicTile T=null;
DyadicPlotter PRE=new DyadicPlotter(2,0,1,1,word,C, I);
PRE.doReset(word);
GeneralPath gp=new GeneralPath();
while(PRE.D_N>0) PRE.processSquare();
int[][] y=VertexPairOrganizer.pairSurvivalList(PRE.INIT,PRE.IN,PRE.IN_N,PRE.DEF,PRE.DEF_N);
int[] TOP=PRE.INIT.top;
int[] BOT=PRE.INIT.bot;
int[] top=PRE.top;
int[] bot=PRE.bot;
if(type_of_plot<2) {
for (int i=1; i<=TOP[0]; i++) {
for (int j=1; j<=BOT[0]; j++) {
if(y[i][j]==1) {
DyadicPlotter DP=new DyadicPlotter(4,type_of_plot,detail,1,word, C, I);
DP.doReset(word);
DP.LEADER=new VertexPair(1,top[TOP[i]],2,bot[BOT[j]]);
T=DP.continuePlot(PRE);
if (T!=null) gp.append(new GeneralPath(T.P),false);
}
}
}
}
if(type_of_plot==2) {
DyadicPlotter DP=new DyadicPlotter(4,type_of_plot,detail,1,word, C, I);
DP.Z=Z;
DP.doReset(word);
DP.setLeader();
T=DP.continuePlot(PRE);
if (T!=null) gp.append(new GeneralPath(T.P),false);
}
double time2=System.currentTimeMillis();
double time=time2-time1;
System.out.println("time: "+time);
return(new DyadicTile(word,gp,C));
}
public DyadicTile basicPlot() {
double time1=System.currentTimeMillis();
if (BL==null) return null; // b-like tile is empty
while ((D_N>0)&&(!I.isInterrupted())) // added to check to see if the plot has been interrupted
processSquare();
if (I.isInterrupted())
return null; // if interrupted then return null
DyadicTile DT=plot();
if(type_of_plot==2) {
DT.record=record;
DT.record_active=1;
DT.Z=Z;
if(IN_N>0) DT.Z=IN[0].getCenter();
if(DEF_N>0) DT.dyadic_size=DEF[0].k;
if(IN_N>0) DT.dyadic_size=IN[0].k;
}
double time2=System.currentTimeMillis();
double time=time2-time1;
System.out.println("time: "+time);
return DT;
}
// call only if type of plot is 4 (solid or boxes or find)
public DyadicTile continuePlot(DyadicPlotter PRE) {
//here the the copy part
for(int i=0;i
0) processSquare();
DyadicTile DT=plot();
return DT;
}
public DyadicTile plot() {
if(mode<=2) {
if(type_of_plot==0) return DyadicPlotHandler.plotSolid(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
else return DyadicPlotHandler.plotBoxes(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
}
if(mode==3) {
if(type_of_plot==0) return DyadicPlotHandler.coverPlotSolid(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
else return DyadicPlotHandler.coverPlotBoxes(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
}
if(mode==4) {
if(type_of_plot!=1) return DyadicPlotHandler.medianPlotSolid(W,LEADER,INIT,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
else return DyadicPlotHandler.medianPlotBoxes(W,LEADER,INIT,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
}
return null;
}
//All the stuff above is just wrapping. Here is the real start of the
// plotting algorithm.
public void doReset(String word) {
DPI=new DyadicPlotterInit(word,filter);
BL=DPI.BL;
BL_CENTER=DPI.BL_CENTER;
CORNER=DPI.CORNER;
corner=DPI.corner;
INIT=DPI.INIT;
D[0]=DPI.D;
record=DPI.record;
CT=DPI.CT;
palindrome=DPI.palindrome;
right=DPI.right;
obtuse=DPI.obtuse;
V=new VertexPair();
VP[0]=new VertexPair(0,0,0,0);
VP[0].cert=0;
SMALL=4;
W=word;
top=Spine.completeList(1,CT);
bot=Spine.completeList(2,CT);
D_N=1;
IN_N=0;
DEF_N=0;
denominator[0]=Function.computeDenominator(0,CT);
denominator[1]=Function.computeDenominator(1,CT);
denominator[2]=Function.computeDenominator(2,CT);
}
/**FUNCTION CREATION AND EVALUATION*/
//in the non-palindrome case, this routine just sets the sign and spine number
public int[][] getSignedNumerator() {
int[][]f=new int[0][0];
if(palindrome==0) {
spine=Converter.spineNumber(V,CT);
sign=Spine.getSign(V,CT,denominator[spine]);
}
if(palindrome==1) {
spine=Converter.spineNumber(V,CT);
f=PalindromeFunction.getFunction(denominator[spine],V,CT);
}
return(f);
}
//the basic evaluation routine
public double evaluate(Complex Z) {
if(palindrome==0) {
double val=Spine.evaluate(sign,V,CT,denominator[spine],Z);
return(val);
}
if(palindrome==1) return(PalindromeFunction.evaluate(numerator,Z));
return(0);
}
//this routine uses the function certificates computed below.
public int signEvaluate(int cert) {
DyadicSquare A=D[D_N-1];
if(palindrome==1) return(PalindromeFunction.signEvaluate(numerator,A,cert));
if(palindrome==0) {
int test=0;
int gm=getMatchNumber();
if(gm>SMALL) test=Spine.signEvaluate(sign,V,CT,data[spine],A,cert);
if(gm<=SMALL) test=Spine.signEvaluate(sign,V,CT,denominator[spine],A,cert);
return(test);
}
return(0);
}
public int crudePositiveTest() {
DyadicSquare A=D[D_N-1];
if(palindrome==1) return(PalindromeFunction.crudePositiveTest(numerator,A));
if(palindrome==0) {
int[] a=lookup3();
if(a[0]+a[1]+a[2]==0) {
a=Spine.absSecond(V,CT,denominator[spine]);
++VP[0].cert;
VP[VP[0].cert]=new VertexPair(V.o1,V.e1,V.o2,V.e2,a[0],a[1],a[2]);
}
int test=0;
int gm=getMatchNumber();
if(gm>SMALL) test=Spine.crudePositiveTest(sign,V,CT,data[spine],A,a);
if(gm<=SMALL) test=Spine.crudePositiveTest(sign,V,CT,denominator[spine],A,a);
return(test);
}
return(0);
}
/**FUNCTION CERTIFICATES: These routines are designed to certify that
* a given defining function is quadrantic in a given square. A function
* is quadrantic in a region if its gradient lies in a quadrant throughout
* that region. The first routine does the computations. This routine
* is somewhat costly to compute, and so we store any certificates
* we do compute, for later use. The second and third routines manage
* this storing and looking up of certificates.*/
public int certify() {
DyadicSquare A=D[D_N-1];
if(palindrome==1) {
return(PalindromeFunction.certify(numerator,A));
}
if(palindrome==0) {
int[] a=lookup3();
if(a[0]+a[1]+a[2]==0) {
a=Spine.absSecond(V,CT,denominator[spine]);
++VP[0].cert;
VP[VP[0].cert]=new VertexPair(V.o1,V.e1,V.o2,V.e2,a[0],a[1],a[2]);
}
int test=0;
int test2=0;
int gm=getMatchNumber();
if(gm>SMALL) test=Certify.certify(sign,V,CT,data[spine],A,a);
if(gm<=SMALL) test=Certify.certify(sign,V,CT,denominator[spine],A,a);
return(test);
}
return(0);
}
public int[] lookupCertify(int q) {
DyadicSquare A=D[D_N-1];
int[] cert=new int[2];
cert[0]=0;
cert[1]=0;
if(q==1) cert[1]=lookup1();
if(q==2) cert[1]=lookup2();
if(cert[1]>0) cert[0]=cert[1];
if(cert[1]==0) cert[0]=certify();
return(cert);
}
public void recordCertify(int q,int[] cert) {
DyadicSquare A=D[D_N-1];
if(q==1) {
if((cert[1]==0)&&(cert[0]>0)) { //record certificate for later use
++A.V1[0].cert;
int L=A.V1[0].cert;
A.V1[L]=new VertexPair(V.o1,V.e1,V.o2,V.e2);
A.V1[L].cert=cert[0];
}}
if(q==2) {
if((cert[1]==0)&&(cert[0]>0)) { //record certificate for later use
++A.V2[0].cert;
int L=A.V2[0].cert;
A.V2[L]=new VertexPair(V.o1,V.e1,V.o2,V.e2);
A.V2[L].cert=cert[0];
}}
}
/**LOOKING UP STORED INFORMATION*/
public int compare(VertexPair VV1,VertexPair VV2) {
if(VV1.o1!=VV2.o1) return(0);
if(VV1.e1!=VV2.e1) return(0);
if(VV1.o2!=VV2.o2) return(0);
if(VV1.e2!=VV2.e2) return(0);
return(VV2.cert);
}
public int lookup1() {
int N=D[D_N-1].V1[0].cert;
int cert=0;
for(int i=N;i>=1;--i) {
cert=compare(V,D[D_N-1].V1[i]);
if(cert!=0) return(cert);
}
return(0);
}
public int lookup2() {
int N=D[D_N-1].V2[0].cert;
int cert=0;
for(int i=N;i>=1;--i) {
cert=compare(V,D[D_N-1].V2[i]);
if(cert!=0) return(cert);
}
return(0);
}
public int[] compare3(VertexPair VV1,VertexPair VV2) {
int[] a=new int[3];
a[0]=0;
a[1]=0;
a[2]=0;
int test=1;
if(VV1.o1!=VV2.o1) test=0;
if(VV1.e1!=VV2.e1) test=0;
if(VV1.o2!=VV2.o2) test=0;
if(VV1.e2!=VV2.e2) test=0;
if(test==1) {
a[0]=VV2.a20;
a[1]=VV2.a11;
a[2]=VV2.a02;
}
return(a);
}
public int[] lookup3() {
int N=VP[0].cert;
int[] a=new int[3];
a[0]=0;
a[1]=0;
a[2]=0;
for(int i=N;i>=1;--i) {
a=compare3(V,VP[i]);
if(a[0]!=0) return(a);
}
return(a);
}
public int getMatchNumber() {
return(D[D_N-1].top[0]*D[D_N-1].bot[0]);
}
/**HERE IS THE ALGORITHM*/
public void processSquare() {
int action=determineAction();
if(action==-1) --D_N;
if(action==0) refineList();
if(action==1) addToInsiders();
if(action==2) addToDefiners();
}
public void refineList() {
DyadicSquare A=D[D_N-1];
D[D_N-1]=DyadicSquare.subdivideAndRemember(0,0,A);
D[D_N+0]=DyadicSquare.subdivideAndRemember(0,1,A);
D[D_N+1]=DyadicSquare.subdivideAndRemember(1,1,A);
D[D_N+2]=DyadicSquare.subdivideAndRemember(1,0,A);
D_N=D_N+3;
}
public void addToInsiders() {
DyadicSquare A=D[D_N-1];
IN[IN_N]=new DyadicSquare(A.x,A.y,A.k);
IN[IN_N].top=new int[300];
IN[IN_N].bot=new int[300];
IN[IN_N].top[0]=A.top[0];
IN[IN_N].bot[0]=A.bot[0];
for(int i=1;i<=A.top[0];++i) {
IN[IN_N].top[i]=A.top[i];
}
for(int i=1;i<=A.bot[0];++i) {
IN[IN_N].bot[i]=A.bot[i];
}
if((mode<4)&&(type_of_plot>=2)) {
Z=A.getCenter(); // set Z
D_N=0;
}
++IN_N;
--D_N;
}
public void addToDefiners() {
if(mode>1) {
DyadicSquare A=D[D_N-1];
DEF[DEF_N]=new DyadicSquare(A.x,A.y,A.k);
DEF[DEF_N].top=new int[300];
DEF[DEF_N].bot=new int[300];
DEF[DEF_N].top[0]=A.top[0];
DEF[DEF_N].bot[0]=A.bot[0];
for(int i=1;i<=A.top[0];++i) {
DEF[DEF_N].top[i]=A.top[i];
}
for(int i=1;i<=A.bot[0];++i) {
DEF[DEF_N].bot[i]=A.bot[i];
}
++DEF_N;
}
--D_N;
}
public int determineAction() {
DyadicSquare A=D[D_N-1];
//in box mode, check if box contains point
if((mode<4)&&(type_of_plot==2)) {
int touch=ConvexIntersector.checkTouch(Z,A.toPolygon());
if(touch==0) return(-1);
}
//in general, check if box intersects billiard-like tile
int test=ConvexIntersector.checkDisjoint(A,BL);
if(test==3) return(-1); //does not intersect tile
if(test==2) return(0); //contains tile
//for tiles which might intersect corner of parameter space
for(int ii=0;ii<3;++ii) {
if(corner[ii]!=0) {
int test0=ConvexIntersector.checkNearCorner(A,CORNER[ii]);
if(test0==1) return(-1);
}
}
//if there are many matches to be played we precompute the denominators
int gm=getMatchNumber();
if(gm>SMALL) {
data[0]=Function.assignData(denominator[0],A);
data[1]=Function.assignData(denominator[1],A);
data[2]=Function.assignData(denominator[2],A);
}
//in the zone modes, we see if the vertex pair of interest
//is amongst the list associated to the box
if(mode>=4) {
int a=CT[LEADER.e1].c[1];
int b=CT[LEADER.e2].c[2];
if(VertexPairOrganizer.checkAppears(a,b,A)==0) return(-1);
}
//now for the real action
tournament();
int p=0;
p=playoffs();
if(p==-1) return(-1); //box is outside tile;all modes
if((mode<=3)&&(p==1)) return(1); //box is inside tile;ordinary modes
if((mode>=4)&&(p==1)) { //box is inside tile;zone mode
++D[D_N-1].age[1];
if(2*D[D_N-1].age[1]>detail) return(1);
if(gm==1) return(1); //single leader
if(checkDominant(A)==1) return(1); //last resort for eliminating box
}
//at this point p=0, meaning that the playoffs are inconclusive.
p=checkCertified();
if(p==2) ++D[D_N-1].age[0];
if(D[D_N-1].age[0]>detail) return(2);
return(0);
}
public void tournament() {
int STOP=1;
while(STOP!=0) STOP=round(1);
STOP=1;
while(STOP!=0) STOP=round(2);
}
public int round(int q) {
int match=0;
int count=0;
int previous=0;
int elim=0;
int BEFORE=0;
DyadicSquare A=D[D_N-1];
if(q==1) BEFORE=A.top[0];
if(q==2) BEFORE=A.bot[0];
for(int i=1;i0) return(2);
}
return(0);
}
public int ordinaryMatch() {
numerator=getSignedNumerator();
int match=0;
int[] cert=lookupCertify(1);
recordCertify(1,cert);
//special case for tiles abutting right angle line
if((cert[0]>0)&&(palindrome==1)&&(right==1)&&(obtuse==1)) {
match=rightMatch();
if(V.o1*V.o2==1) match=3-match;
if(match==2) return(2);
if(match==1) return(1);
}
//regular case: do the match
match=signEvaluate(cert[0]);
if(V.o1*V.o2==1) match=3-match;
if(match==1) return(1);
if(match==2) return(2);
return(0);
}
/**this routine is the same as the previous one, except that
* we're more conservative about storing certificates. We
* don't want the list of certificates to blow up.*/
public int playoffMatch() {
int quick=0;
quick=lookup2();
if(quick>10) return(2);
numerator=getSignedNumerator();
quick=crudePositiveTest();
if(quick==1) return(2);
int[] cert=new int[2];
cert=lookupCertify(2);
int match=0;
match=signEvaluate(cert[0]); //do actual match
if(match==2) cert[0]=10+cert[0];
if(getMatchNumber()<25) recordCertify(2,cert);
return(match);
}
//FOR THE ZONE PLOTTER
public double[] getValues(SmallPolygon P) {
double[] x=new double[P.N];
numerator=getSignedNumerator();
for(int i=0;i.000000000001) return(0);
}
return(1);
}
public int checkDominant(DyadicSquare Q) {
Complex[] ZZ=Q.toPolygon();
SmallPolygon P=new SmallPolygon(ZZ,4);
int test=1;
for(int i=1;i<=Q.top[0];++i) {
V=new VertexPair(1,LEADER.e1,1,top[Q.top[i]]);
if(V.e1>V.e2) test=checkPositive(P);
if(V.e1V.e2) test=checkNegative(P);
if(test==0) return(0);
}
return(1);
}
//for the zone plotter
public void setLeader() {
Corridor COR=new Corridor();
LEADER=COR.getLeader(W,Z);
if(palindrome==0) {
int v1=CT[LEADER.e1].c[1];
if(v1>W.length()/2) LEADER.e1=1;
int v2=CT[LEADER.e2].c[2];
if(v2>W.length()/2) LEADER.e2=1;
}
if(palindrome==1) {
int n=W.length();
int a=CT[LEADER.e1].c[1];
int b=CT[LEADER.e2].c[2];
if(a>INIT.top.length) a=n/2+2-a;
if(b>INIT.top.length) b=n/2+2-b;
LEADER.e1=top[a];
LEADER.e2=bot[b];
}
}
}