//
//  Need to have window of size 840x502 for program
//

import java.text.DecimalFormat;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class compare extends Applet implements MouseListener, MouseMotionListener {
	int BUFFER=20, T_WIDTH=800, T_HEIGHT=462;  // constants used for size of triangle

	String[] centerTypes = { "", "bisectors", "medians", "Lemoine point", "Gergonne point",  "Spieker center"};
	int methodA=1, methodB=0;  //used to keep track of type of center used in the calculations

	Point notDraggingPoint = new Point(500,300);
	Point lastPushed = new Point(500,300);

	boolean inTriangle=true;
	boolean isDragging=false;
	boolean notDraggingInside=false;
	
	Image backbuffer;
	Graphics backg;

	public void init() {
		backbuffer = createImage( 2*BUFFER+T_WIDTH, 2*BUFFER+T_HEIGHT );
		backg = backbuffer.getGraphics();
		newCoat();
		
		addMouseListener( this );
		addMouseMotionListener( this );
	}

	public void mouseEntered( MouseEvent e ) { }
	public void mouseExited( MouseEvent e ) { }
	public void mouseClicked( MouseEvent e ) { 
		Point test = new Point (e.getX(),e.getY());
		if(testInTriangle(test)==false){
			if(test.x>2*BUFFER && test.x<2*BUFFER+15){  //in the x-strip with the buttons
				if(test.y>220 && test.y<235){  //pushed up button for methodA
					if(methodA==5){ methodA=1; } else { methodA++; }
				}
				if(test.y>235 && test.y<250){  //pushed down button for methodA
					if(methodA==1){ methodA=5; } else { methodA--; }
				}
				if(test.y>270 && test.y<285){  //pushed up button for methodB
					if(methodB==5){ methodB=0; } else { methodB++; }
				}
				if(test.y>285 && test.y<300){  //pushed down button for methodB
					if(methodB==0){ methodB=5; } else { methodB--; }
				}
			}
			newCoat();
		}
		e.consume();
	}
	public void mousePressed( MouseEvent e ) {
		Point test = new Point (e.getX(),e.getY());

		if(testInTriangle(test)==true){
			inTriangle=true; isDragging=true;
			lastPushed = test;
		}
		else{ inTriangle=false; }
		newCoat();
		e.consume();
	}
	public void mouseReleased( MouseEvent e ) {
		isDragging = false;
		e.consume();
	}
	public void mouseMoved( MouseEvent e ) { 
		Point test = new Point (e.getX(),e.getY());
		if(testInTriangle(test)==true)
		{
			notDraggingInside=true;
			notDraggingPoint=test;
		}
		else
		{
			notDraggingInside=false;
		}
		newCoat();
		e.consume();
	}
	public void mouseDragged( MouseEvent e ) {
		Point test = new Point(e.getX(),e.getY());
		if(testInTriangle(test)==true && isDragging==true){
			lastPushed = test;
			newCoat();
			e.consume();
		}
		else if(testInTriangle(test)==false && isDragging==true){
			lastPushed = nearestInTriangle(test);
			newCoat();
			e.consume();
		}
	}

	public void update( Graphics g ) {
		g.drawImage( backbuffer, 0, 0, this );
	}

	public void paint( Graphics g ) {
		update( g );
	}
	
	public void newCoat(){
		backg.setColor(Color.black);
		backg.fillRect(0,0,2*BUFFER+T_WIDTH,2*BUFFER+T_HEIGHT);
		
		DecimalFormat df = new DecimalFormat("##0.0");
// draw the large white triangle
		int[] XArray={BUFFER,T_WIDTH+BUFFER,T_WIDTH+BUFFER};
		int[] YArray={BUFFER+T_HEIGHT,BUFFER+T_HEIGHT,BUFFER};
		backg.setColor( Color.white );
		backg.fillPolygon(XArray,YArray,3);
//draw blue cross indicating current location of starting triangle
		backg.setColor( Color.blue );
		backg.drawLine( lastPushed.x-5, lastPushed.y+5,  lastPushed.x+5, lastPushed.y-5);
		backg.drawLine( lastPushed.x+5, lastPushed.y+5,  lastPushed.x-5, lastPushed.y-5);
		backg.drawLine( lastPushed.x-5, lastPushed.y+4,  lastPushed.x+4, lastPushed.y-5);
		backg.drawLine( lastPushed.x+5, lastPushed.y+4,  lastPushed.x-4, lastPushed.y-5);
		backg.drawLine( lastPushed.x-4, lastPushed.y+5,  lastPushed.x+5, lastPushed.y-4);
		backg.drawLine( lastPushed.x+4, lastPushed.y+5,  lastPushed.x-5, lastPushed.y-4);
//draw "gui"
		backg.setColor( Color.white );
		backg.drawRect( 2*BUFFER,220,15,15);
		int[] UpTriangleX1 = {2*BUFFER+3,2*BUFFER+11,2*BUFFER+7};
		int[] UpTriangleY1 = {220+12,220+12,220+3};
		backg.fillPolygon( UpTriangleX1, UpTriangleY1, 3 );
		backg.drawRect( 2*BUFFER,235,15,15);
		int[] DownTriangleX1 = {2*BUFFER+3,2*BUFFER+11,2*BUFFER+7};
		int[] DownTriangleY1 = {235+3,235+3,235+12};
		backg.fillPolygon( DownTriangleX1, DownTriangleY1, 3 );
		backg.drawRect(2*BUFFER+15,220,150,30);
		backg.setColor( Color.red );
		backg.fillOval(30-4,235-4,9,9);
		backg.setColor( Color.white );
		
		backg.drawRect( 2*BUFFER,270,15,15);
		int[] UpTriangleX2 = {2*BUFFER+3,2*BUFFER+11,2*BUFFER+7};
		int[] UpTriangleY2 = {270+12,270+12,270+3};
		backg.fillPolygon( UpTriangleX2, UpTriangleY2, 3 );
		backg.drawRect( 2*BUFFER,285,15,15);
		int[] DownTriangleX2 = {2*BUFFER+3,2*BUFFER+11,2*BUFFER+7};
		int[] DownTriangleY2 = {285+3,285+3,285+12};
		backg.fillPolygon( DownTriangleX2, DownTriangleY2, 3 );
		backg.drawRect(2*BUFFER+15,270,150,30);
		backg.setColor( Color.green );
		backg.fillRect(30-4,285-1,9,3);
		backg.fillRect(30-1,285-4,3,9);
		backg.setColor( Color.white );
		
		backg.drawString(centerTypes[methodA], 2*BUFFER+30, 240);
		backg.drawString(centerTypes[methodB], 2*BUFFER+30, 290);

		
		triangle lastPushedTriangle = findTriangle(lastPushed);
// draw the triangle that corresponds to the recursion
		Point currentShape=findVertex(lastPushedTriangle);
		int[] XArrayCurrent={BUFFER,BUFFER+150,BUFFER+currentShape.x};
		int[] YArrayCurrent={BUFFER+150,BUFFER+150,BUFFER+150-currentShape.y};
		backg.setColor( Color.yellow );
		backg.fillPolygon(XArrayCurrent,YArrayCurrent,3);
		double a=lastPushedTriangle.X(), b=lastPushedTriangle.Y(), c=lastPushedTriangle.Z(), min, mid, max;
		if		(a<=b && b<=c)	{ min=a; mid=b; max=c; }
		else if	(a<=c && c<=b)	{ min=a; mid=c; max=b; }
		else if	(b<=a && a<=c)	{ min=b; mid=a; max=c; }
		else if	(b<=c && c<=a)	{ min=b; mid=c; max=a; }
		else if	(c<=a && a<=b)	{ min=c; mid=a; max=b; }
		else					{ min=c; mid=b; max=a; }
		backg.drawString(df.format(min*180.0/Math.PI)+" -- "+df.format(mid*180.0/Math.PI)+" -- "+df.format(max*180.0/Math.PI), BUFFER,BUFFER+175);
//draw the triangle that corresponds to the current location of the cursor (if applicable)
		if(notDraggingInside==true)// && isDragging==false)
		{
			backg.setColor(Color.orange);
			if(isDragging==false){
				currentShape=findVertex(findTriangle(notDraggingPoint));
				a=findTriangle(notDraggingPoint).X();  b=findTriangle(notDraggingPoint).Y();  c=findTriangle(notDraggingPoint).Z();
			}
			else{
				currentShape=findVertex(lastPushedTriangle);
				a=lastPushedTriangle.X();  b=lastPushedTriangle.Y();  c=lastPushedTriangle.Z();
			}
			int[] XArrayDrag={BUFFER+200,BUFFER+350,BUFFER+200+currentShape.x};
			int[] YArrayDrag={BUFFER+150,BUFFER+150,BUFFER+150-currentShape.y};
			backg.fillPolygon(XArrayDrag,YArrayDrag,3);
//			a=findTriangle(notDraggingPoint).X();  b=findTriangle(notDraggingPoint).Y();  c=findTriangle(notDraggingPoint).Z();
			if		(a<=b && b<=c)	{ min=a; mid=b; max=c; }
			else if	(a<=c && c<=b)	{ min=a; mid=c; max=b; }
			else if	(b<=a && a<=c)	{ min=b; mid=a; max=c; }
			else if	(b<=c && c<=a)	{ min=b; mid=c; max=a; }
			else if	(c<=a && a<=b)	{ min=c; mid=a; max=b; }
			else					{ min=c; mid=b; max=a; }
			backg.drawString(df.format(min*180.0/Math.PI)+" -- "+df.format(mid*180.0/Math.PI)+" -- "+df.format(max*180.0/Math.PI), BUFFER+200,BUFFER+175);
		}

//mark the points used by method A
		backg.setColor( Color.red );
		Point AA,AB,AC,AD,AE,AF;
		if(methodA==1) {
			AA=findPoint(bisector(pA(lastPushedTriangle)));
			AB=findPoint(bisector(pB(lastPushedTriangle)));
			AC=findPoint(bisector(pC(lastPushedTriangle)));
			AD=findPoint(bisector(pD(lastPushedTriangle)));
			AE=findPoint(bisector(pE(lastPushedTriangle)));
			AF=findPoint(bisector(pF(lastPushedTriangle)));
		}
		else if(methodA==2) {
			AA=findPoint(median(pA(lastPushedTriangle)));
			AB=findPoint(median(pB(lastPushedTriangle)));
			AC=findPoint(median(pC(lastPushedTriangle)));
			AD=findPoint(median(pD(lastPushedTriangle)));
			AE=findPoint(median(pE(lastPushedTriangle)));
			AF=findPoint(median(pF(lastPushedTriangle)));
		}
		else if(methodA==3) {
			AA=findPoint(Lemoine(pA(lastPushedTriangle)));
			AB=findPoint(Lemoine(pB(lastPushedTriangle)));
			AC=findPoint(Lemoine(pC(lastPushedTriangle)));
			AD=findPoint(Lemoine(pD(lastPushedTriangle)));
			AE=findPoint(Lemoine(pE(lastPushedTriangle)));
			AF=findPoint(Lemoine(pF(lastPushedTriangle)));
		}
		else if(methodA==4) {
			AA=findPoint(Gergonne(pA(lastPushedTriangle)));
			AB=findPoint(Gergonne(pB(lastPushedTriangle)));
			AC=findPoint(Gergonne(pC(lastPushedTriangle)));
			AD=findPoint(Gergonne(pD(lastPushedTriangle)));
			AE=findPoint(Gergonne(pE(lastPushedTriangle)));
			AF=findPoint(Gergonne(pF(lastPushedTriangle)));
		}
		else  {
			AA=findPoint(Spieker(pA(lastPushedTriangle)));
			AB=findPoint(Spieker(pB(lastPushedTriangle)));
			AC=findPoint(Spieker(pC(lastPushedTriangle)));
			AD=findPoint(Spieker(pD(lastPushedTriangle)));
			AE=findPoint(Spieker(pE(lastPushedTriangle)));
			AF=findPoint(Spieker(pF(lastPushedTriangle)));
		}
		backg.fillOval(AA.x-4,AA.y-4,9,9);
		backg.fillOval(AB.x-4,AB.y-4,9,9);
		backg.fillOval(AC.x-4,AC.y-4,9,9);
		backg.fillOval(AD.x-4,AD.y-4,9,9);
		backg.fillOval(AE.x-4,AE.y-4,9,9);
		backg.fillOval(AF.x-4,AF.y-4,9,9);

//mark the points used by method B
		if(methodB > 0){
			backg.setColor (Color.green );
			Point BA, BB, BC, BD, BE, BF;
			if(methodB==1) {
				BA=findPoint(bisector(pA(lastPushedTriangle)));
				BB=findPoint(bisector(pB(lastPushedTriangle)));
				BC=findPoint(bisector(pC(lastPushedTriangle)));
				BD=findPoint(bisector(pD(lastPushedTriangle)));
				BE=findPoint(bisector(pE(lastPushedTriangle)));
				BF=findPoint(bisector(pF(lastPushedTriangle)));
			}
			else if(methodB==2) {
				BA=findPoint(median(pA(lastPushedTriangle)));
				BB=findPoint(median(pB(lastPushedTriangle)));
				BC=findPoint(median(pC(lastPushedTriangle)));
				BD=findPoint(median(pD(lastPushedTriangle)));
				BE=findPoint(median(pE(lastPushedTriangle)));
				BF=findPoint(median(pF(lastPushedTriangle)));
			}
			else if(methodB==3) {
				BA=findPoint(Lemoine(pA(lastPushedTriangle)));
				BB=findPoint(Lemoine(pB(lastPushedTriangle)));
				BC=findPoint(Lemoine(pC(lastPushedTriangle)));
				BD=findPoint(Lemoine(pD(lastPushedTriangle)));
				BE=findPoint(Lemoine(pE(lastPushedTriangle)));
				BF=findPoint(Lemoine(pF(lastPushedTriangle)));
			}
			else if(methodB==4) {
				BA=findPoint(Gergonne(pA(lastPushedTriangle)));
				BB=findPoint(Gergonne(pB(lastPushedTriangle)));
				BC=findPoint(Gergonne(pC(lastPushedTriangle)));
				BD=findPoint(Gergonne(pD(lastPushedTriangle)));
				BE=findPoint(Gergonne(pE(lastPushedTriangle)));
				BF=findPoint(Gergonne(pF(lastPushedTriangle)));
			}
			else  {
				BA=findPoint(Spieker(pA(lastPushedTriangle)));
				BB=findPoint(Spieker(pB(lastPushedTriangle)));
				BC=findPoint(Spieker(pC(lastPushedTriangle)));
				BD=findPoint(Spieker(pD(lastPushedTriangle)));
				BE=findPoint(Spieker(pE(lastPushedTriangle)));
				BF=findPoint(Spieker(pF(lastPushedTriangle)));
			}
			backg.fillRect(BA.x-4,BA.y-1,9,3);
			backg.fillRect(BA.x-1,BA.y-4,3,9);
			backg.fillRect(BB.x-4,BB.y-1,9,3);
			backg.fillRect(BB.x-1,BB.y-4,3,9);
			backg.fillRect(BC.x-4,BC.y-1,9,3);
			backg.fillRect(BC.x-1,BC.y-4,3,9);
			backg.fillRect(BD.x-4,BD.y-1,9,3);
			backg.fillRect(BD.x-1,BD.y-4,3,9);
			backg.fillRect(BE.x-4,BE.y-1,9,3);
			backg.fillRect(BE.x-1,BE.y-4,3,9);
			backg.fillRect(BF.x-4,BF.y-1,9,3);
			backg.fillRect(BF.x-1,BF.y-4,3,9);
		}

//output the picture
		repaint();
	}
//
//  The following function is to test if a point is in the triangle
//
	public boolean testInTriangle (Point P) {
		if(P.y>BUFFER+T_HEIGHT){ return false; }
		else if(P.x>T_WIDTH+BUFFER){ return false; }
		else if(T_WIDTH*P.y<-T_HEIGHT*P.x+(BUFFER+T_HEIGHT)*(T_WIDTH+BUFFER)-BUFFER*BUFFER){ return false; }
		else{ return true; }
	}

//
//  The following function projects to a point in the triangle
//  assumes you are outside the triangle (!!)
//
	public Point nearestInTriangle(Point P) {
		int xSlot, ySlot;
		if(P.y>BUFFER+T_HEIGHT) { //below the triangle
			ySlot=BUFFER+T_HEIGHT;
			if		(P.x<BUFFER)  xSlot=BUFFER; 
			else if	(P.x>BUFFER+T_WIDTH)  xSlot=BUFFER+T_WIDTH; 
			else	xSlot=P.x;
		}
		else if(P.x>BUFFER+T_WIDTH) { //to the right of the triangle
			xSlot=BUFFER+T_WIDTH;
			if		(P.y<BUFFER)  ySlot=BUFFER; 
			else if	(P.y>BUFFER+T_HEIGHT)  ySlot=BUFFER+T_HEIGHT; 
			else	ySlot=P.y;
		}
		else { // above the slanty part of the triangle
			double m=-(double)(T_HEIGHT)/(double)(T_WIDTH);
			double b=(double)(BUFFER+T_HEIGHT)+(double)(T_HEIGHT*BUFFER)/(double)(T_WIDTH);
			double q=(double)(P.x)+m*(double)(P.y);
			xSlot = (int)((q-b*m)/(m*m+1));
			ySlot = (int)((m*q+b)/(m*m+1));
			if(xSlot<BUFFER) { xSlot=BUFFER; ySlot=BUFFER+T_HEIGHT; }
			else if(xSlot>BUFFER+T_WIDTH) { xSlot=BUFFER+T_WIDTH; ySlot=BUFFER; }
		}
		return new Point(xSlot,ySlot);
	}

//
//  The following function returns the vertex of the triangle with base at (0,0)---(150,0)
//  (the largest vertex is put on the top)
//
	public Point findVertex(triangle T) {
		double a=T.X(), b=T.Y(), c=T.Z(), min, mid, max;
		if		(a<=b && b<=c)	{ min=a; mid=b; max=c; }
		else if	(a<=c && c<=b)	{ min=a; mid=c; max=b; }
		else if	(b<=a && a<=c)	{ min=b; mid=a; max=c; }
		else if	(b<=c && c<=a)	{ min=b; mid=c; max=a; }
		else if	(c<=a && a<=b)	{ min=c; mid=a; max=b; }
		else					{ min=c; mid=b; max=a; }
		int xSlot=(int)(150.0*Math.cos(min)*Math.sin(mid)/Math.sin(max));
		int ySlot=(int)(150.0*Math.sin(min)*Math.sin(mid)/Math.sin(max));
		return new Point(xSlot,ySlot);
	}

//
//  The following two functions translate back and forth between points on the screen and triangles
//
	public Point findPoint(triangle T) { 
		double a=T.X(), b=T.Y(), c=T.Z(), min, mid, max;
		if		(a<=b && b<=c)	{ min=a; mid=b; max=c; }
		else if	(a<=c && c<=b)	{ min=a; mid=c; max=b; }
		else if	(b<=a && a<=c)	{ min=b; mid=a; max=c; }
		else if	(b<=c && c<=a)	{ min=b; mid=c; max=a; }
		else if	(c<=a && a<=b)	{ min=c; mid=a; max=b; }
		else					{ min=c; mid=b; max=a; }
		int x=BUFFER+(int)((min+2.0*mid)*(double)(T_WIDTH)/Math.PI);
		int y=BUFFER+(int)((-2.0*min+mid+max)*(double)(T_HEIGHT)/Math.PI);
		Point P = new Point(x,y);
		return P;
	}

	public triangle findTriangle(Point P) { 
		double a=1.0-((double)(P.x-BUFFER)/(double)(T_WIDTH));
		double b=((double)(P.y-BUFFER)/(double)(T_HEIGHT))-a;
		double angleX=Math.PI*(1.0-a-b)/3.0;
		double angleY=Math.PI*(2.0-2.0*a+b)/6.0;
		double angleZ=Math.PI*(2.0+4.0*a+b)/6.0;
//  if "close" to the edge push back a little bit
		if( angleX < 0.005 ) { angleX = 0.005; }
		if( angleY < 0.005 ) { angleY = 0.005; }
		triangle S = new triangle(angleX,angleY,angleZ);
		return S;
	}

//
//  Given an initial triangle the following functions return one of the six triangles
//  formed under their respective method of splitting up the triangle
//
	public static triangle bisector(triangle T) {
		triangle S = new triangle(0.5*T.X(),0.5*T.X()+0.5*T.Y(),0.5*T.Y()+T.Z());
		return S;
	}

	public static  triangle median(triangle T) {
		double p,q,r,s,t;
		p=Math.sin(T.Y())/(3.0*Math.sin(T.Z()));
		q=(1.0/3.0)+Math.cos(T.X())*p;
		r=p*Math.sin(T.X());
		s=Math.sqrt((q-0.5)*(q-0.5)+r*r);
		t=Math.sqrt(q*q+r*r);
		triangle S = new triangle(Math.acos((s*s+t*t-0.25)/(2.0*s*t)),Math.acos((0.25+s*s-t*t)/s),Math.acos((0.25+t*t-s*s)/t));
		return S;
	}
	
	public static triangle Lemoine(triangle T) {
		double p,q,r,s,t,u,v;
		p=Math.sin(T.Y())/Math.sin(T.Z());
		q=Math.cos(T.X())*p;
		r=Math.sin(T.X())*p;
		s=(1.0+q)*(1.0+q)+r*r;
		t=(q-0.5)*(q-0.5)+r*r;
		u=Math.acos((1.0+q)/Math.sqrt(s));
		v=Math.acos((p*p+t-0.25)/(2.0*p*Math.sqrt(t)));
		triangle S = new triangle(T.X()-u,Math.PI-T.X()-T.Z()+v,T.Z()+u-v);
		return S;
	}

	public static triangle Gergonne(triangle T) {
		double p,q,r,s,t,u,v;
		p=Math.sin(T.Y())/Math.sin(T.Z());
		q=Math.cos(T.X())*p;
		r=Math.sin(T.X())*p;
		s=Math.cos(0.5*T.X())*Math.sin(0.5*T.Y())/Math.sin(0.5*(T.X()+T.Y()));
		t=(q-s)*(q-s)+r*r;
		u=Math.acos((p*p+t-s*s)/(2.0*p*Math.sqrt(t)));

		p=Math.sin(T.Z())/Math.sin(T.X());
		q=Math.cos(T.Y())*p;
		r=Math.sin(T.Y())*p;
		s=Math.cos(0.5*T.Y())*Math.sin(0.5*T.Z())/Math.sin(0.5*(T.Y()+T.Z()));
		t=(q-s)*(q-s)+r*r;
		v=Math.acos((p*p+t-s*s)/(2.0*p*Math.sqrt(t)));

		return new triangle (v,Math.PI-T.X()-u,T.X()-v+u);
	}

	public static triangle Nagel(triangle T) {
		double p,q,r,s,t,u,v;
		p=Math.sin(T.Y())/Math.sin(T.Z());
		q=Math.cos(T.X())*p;
		r=Math.sin(T.X())*p;
		s=0.5-(0.5*p)+((0.5*Math.sin(T.X()))/Math.sin(T.Z()));
		t=(q-s)*(q-s)+r*r;
		u=Math.acos((p*p+t-s*s)/(2.0*p*Math.sqrt(t)));

		p=Math.sin(T.Z())/Math.sin(T.X());
		q=Math.cos(T.Y())*p;
		r=Math.sin(T.Y())*p;
		s=0.5-(0.5*p)+((0.5*Math.sin(T.Y()))/Math.sin(T.X()));
		t=(q-s)*(q-s)+r*r;
		v=Math.acos((p*p+t-s*s)/(2.0*p*Math.sqrt(t)));

		return new triangle (v,Math.PI-T.X()-u,T.X()-v+u);
	}

	public static triangle Spieker(triangle T) {
		double p,q,r,s,t,u,v,w,x,y,z;
		double SpiekerX,SpiekerY;
		
		p=Math.sin(T.Y())/Math.sin(T.X()+T.Y());
		q=Math.cos(T.X())*p;
		r=Math.sin(T.X())*p;
		s=Math.sin(0.5*T.Y())/Math.sin(0.5*T.X()+0.5*T.Y());
		t=Math.cos(0.5*T.X())*s;
		u=Math.sin(0.5*T.X())*s;
		SpiekerX=0.5*(1.0+q-t);
		SpiekerY=0.5*(r-u);
		v=SpiekerX*SpiekerX+SpiekerY*SpiekerY;
		w=(SpiekerX-q)*(SpiekerX-q)+(SpiekerY-r)*(SpiekerY-r);
		x=(1.0-SpiekerX)*(1.0-SpiekerX)+SpiekerY*SpiekerY;

		y=Math.acos((v+1.0-x)/(2.0*Math.sqrt(v)));
		z=Math.acos((p*p+w-v)/(2.0*p*Math.sqrt(w)));
		
		return new triangle (y,Math.PI-T.X()-z,T.X()-y+z);
	}

//
//  The following functions permute the triangle and allows us to easily set up recursions
//
	public static  triangle pA(triangle T) {
		return new triangle(T.X(),T.Y(),T.Z());
	}

	public static  triangle pB(triangle T) {
		return new triangle(T.X(),T.Z(),T.Y());
	}

	public static  triangle pC(triangle T) {
		return new triangle(T.Y(),T.X(),T.Z());
	}

	public static  triangle pD(triangle T) {
		return new triangle(T.Y(),T.Z(),T.X());
	}

	public static  triangle pE(triangle T) {
		return new triangle(T.Z(),T.X(),T.Y());
	}

	public static  triangle pF(triangle T) {
		return new triangle(T.Z(),T.Y(),T.X());
	}
}
