import java.applet.Applet;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.*;
import java.math.*;

public class Deg100IntegerPolygon {
    BigInteger[] K1=new BigInteger[8];
    BigInteger[] K2=new BigInteger[8];
    int n;
    int age;

    public Deg100IntegerPolygon() {}

    public Deg100IntegerPolygon(int nn,int[] n1,int[] k1,int[] n2,int[] k2) {
	this.n=nn;
	for(int i=0;i<n;++i) {
	    K1[i]=amplify(k1[i],n1[i]);
	    K2[i]=amplify(k2[i],n2[i]);
	}
    }

    public Deg100IntegerPolygon(Deg100Polygon P) {
	this.n=P.n;
	for(int i=0;i<P.n;++i) {
	    K1[i]=amplify(P.k1[i],P.n1[i]);
	    K2[i]=amplify(P.k2[i],P.n2[i]);
	}
    }


    //this produces a line segment
    public Deg100IntegerPolygon(Deg100Polygon P,int k) {
	int i=k;
	int j=k+1;
	if(j==P.n) j=0;
	K1[0]=amplify(P.k1[i],P.n1[i]);
	K2[0]=amplify(P.k2[i],P.n2[i]);
	K1[1]=amplify(P.k1[j],P.n1[j]);
	K2[1]=amplify(P.k2[j],P.n2[j]);
	n=2;
	age=0;
    }

    public BigInteger amplify(int k,int n) {
	Integer K=new Integer(k);
	BigInteger X=new BigInteger(K.toString());
	for(int i=1;i<=27-n;++i) X=X.add(X);
	return(X);
    }




    public static int orientation(BigInteger x1,BigInteger y1,BigInteger x2,BigInteger y2,BigInteger x3,BigInteger y3)
{

    BigInteger X1=BigInteger.ZERO;
    X1=X1.add(x1.multiply(y2));
    X1=X1.add(x2.multiply(y3));
    X1=X1.add(x3.multiply(y1));

    BigInteger X2=BigInteger.ZERO;
    X2=X2.add(y1.multiply(x2));
    X2=X2.add(y2.multiply(x3));
    X2=X2.add(y3.multiply(x1));
    return(X1.compareTo(X2));
}



    //checks if the point (x,y) is inside the polygon

public int checkInside(BigInteger x,BigInteger y) {
  int total,local;
  total=0;
  local=0;
  for(int i=0;i<n;++i) {
      int j=i+1;
      if(j==n) j=0;
      local=orientation(x,y,K1[i],K2[i],K1[j],K2[j]);
      total=total+local;
  }
  if (total<0) total=-total;
  if(total<n) return(0);
  return(1);
}



    //checks if a segment X is contained in one of the polygons

    public int checkInside(Deg100Data D,Deg100IntegerPolygon X,int omit) {
	int test=0;
	for(int i=1;i<=221;++i) {
	  if(i!=omit) {
	    Deg100IntegerPolygon Y=new Deg100IntegerPolygon(D.P[i]);
	    if((Y.checkInside(X.K1[0],X.K2[0])==1)&&(Y.checkInside(X.K1[1],X.K2[1])==1)) return(i);
	  }
	}
	return(0);
    }


    //subdivides a segment in half

    public Deg100IntegerPolygon subdivide1() {
	Deg100IntegerPolygon P=new Deg100IntegerPolygon();
	P.K1[0]=this.K1[0];
	P.K2[0]=this.K2[0];
	P.K1[1]=this.K1[0].add(this.K1[1]);
	P.K1[1]=P.K1[1].divide(new BigInteger("2"));
	P.K2[1]=this.K2[0].add(this.K2[1]);
	P.K2[1]=P.K2[1].divide(new BigInteger("2"));
	P.n=2;
	P.age=this.age+1;
	return(P);
    }

    public Deg100IntegerPolygon subdivide2() {
	Deg100IntegerPolygon P=new Deg100IntegerPolygon();
	P.K1[1]=this.K1[1];
	P.K2[1]=this.K2[1];
	P.K1[0]=this.K1[0].add(this.K1[1]);
	P.K1[0]=P.K1[0].divide(new BigInteger("2"));
	P.K2[0]=this.K2[0].add(this.K2[1]);
	P.K2[0]=P.K2[0].divide(new BigInteger("2"));
	P.n=2;
	P.age=this.age+1;
	return(P);
    }



    /*goes through a list of polygons and decides if the jth edge of the ith
      polygon in the list is covered by the other polygons on the list*/

    public int[] subdivisionAlgorithm(Deg100Data D,int i,int j) {
	int[] record=new int[30];
	record[0]=0;
	Deg100IntegerPolygon X0=new Deg100IntegerPolygon(D.P[i],j);
	Deg100IntegerPolygon[] X=new Deg100IntegerPolygon[30];
	int X_N=1;
	X[0]=X0;
	while(X_N>0) {
	    Deg100IntegerPolygon A=X[X_N-1];
	    int test=checkInside(D,A,i);
	    if(test>0) {
		int match=0;
 		for(int jj=0;jj<record[0];++jj) if(test==record[jj]) match=1;
		if(match==0) {
                    record[record[0]+1]=test;
		    ++record[0];
		}
                --X_N;
	    }
	    if(test==0) {
		X[X_N-1]=A.subdivide1();
		X[X_N-0]=A.subdivide2();
		++X_N;
		if(A.age>8) {record[0]=0;return(record);}
	    }
	}
	return(record);
    }


    /*applies the above algorithm to each of the edges of the polygon*/
        public int[][] subdivisionAlgorithm(Deg100Data D,int i) {
        int[][] record=new int[10][30];
	for(int ii=0;ii<D.P[i].n;++ii) {
            record[ii+1]=subdivisionAlgorithm(D,i,ii);
	    if(record[ii+1][0]==0) {record[0][0]=0;return(record);}
	}
	record[0][0]=D.P[i].n;
	return(record);
    }

}




