
/************************************/
/**(28.11.96-07.01.97) by mtsh & pk */
/**         spherical product 		*/
/************************************/

import java.awt.*;
import java.util.*;

import java.applet.Applet;

class Node {
        double x;
        double y;
}

class Point5d{
	double x;
	double y;
	double z;
	int px;
	int py;

	Point5d(){
		x=0.0;y=0.0;z=0.0;px=0;py=0;
	}

	public String toString() {
		return ("[" + x + "," + y + "," + z + "->" + px + ":"
		+ py +"]");
    }

	public void normalize(){
		double sq;
			sq = Math.sqrt(x*x+y*y+z*z);
			x /=sq;
			y /=sq;
			z /=sq;
	}



}

class Plane{
	Point5d p1;
	Point5d p2;
	Point5d p3;
	Point5d p4;
	Point5d norm;
	double zmax;
	Color kolor;

	Plane(){
		p1 = new Point5d();
		p2 = new Point5d();
		p3 = new Point5d();
        p4 = new Point5d();
		norm = new Point5d();
	}

	public String toString() {
		return ("P1 ->" + p1.toString() + "\n" + 
			"P2 ->" + p2.toString() + "\n" +
			"P3 ->" + p3.toString() + "\n" +
			"P4 ->" + p4.toString() + "\n" +
			"No ->" + norm.x +","+ norm.y +","+ norm.z + "\n" );
    }

	public void calcZ(){
		//zmax=Math.max(p1.z,Math.max(p2.z,Math.max(p3.z,p4.z)));
		zmax=(p4.z+p1.z)/2;
	}
					


	public void calcNorm(){
			double vx,vy,vz,ux,uy,uz,x,y,z,sq;

			//counting vectors
			vx = p2.x-p1.x;
			vy = p2.y-p1.y;
			vz = p2.z-p1.z;

			ux = p4.x-p2.x;
			uy = p4.y-p2.y;
			uz = p4.z-p2.z;

			//crossproduct
			x = vy*uz - vz*uy;
			y = vz*ux - vx*uz;
			z = vx*uy - vy*ux;
		
			//normalization
			sq = Math.sqrt(x*x+y*y+z*z);
			x /=sq;
			y /=sq;
			z /=sq;
			
			norm.x = x;norm.y=y;norm.z=z;
		}

	public void calcColor(Point5d p){
			float clr;
			double cos;
			

			// powinien obliczac kat phi miedzy p a norm....
			// chwilowo niech bedzie to tylko kat miedzy x-owymi ...

			cos = norm.x*p.x + norm.y*p.y + norm.z*p.z;

			clr = (float)(Math.abs(cos));

			kolor = new Color(clr,clr,clr);
		}

}

public class Product extends Applet {
        public EditPanel2D panelmer, panelpar;
        public ShowPanel perspview;
        public ControlPanel controls; 
        public Object3D object3D;
        public int editmode;
        
        public void init() {
                setLayout(new GridLayout(2,2,5,5));
                object3D  = new Object3D(this);
                panelmer  = new EditPanel2D(this,0);
                perspview = new ShowPanel(this);
                panelpar  = new EditPanel2D(this,1);
                controls  = new ControlPanel(this);
                editmode  = 1;
                
                add(panelmer);
                add(perspview);
                add(panelpar);
                add(controls);
           
                validate();
                editMode(3);

        }/*end of init*/
        
        public void start() {
                panelpar.start();
                panelmer.start();
        }
        
        public void stop() {
                panelmer.stop();
                panelpar.stop();
        }
        
        public void editMode(int modeno) {
                controls.setMode(modeno);
                editmode = modeno;
        }

}

class Object3D{
        public int pnodeno = 4;
        public int mnodeno = 2;
        public Node pnodes[] = new Node[4];
        public Node mnodes[] = new Node[2];
		public Plane planes[] = null;
        Product mainapp;

        double xtheta;
        double ytheta;
        double xst;
        double xct;
        double yst;
        double yct;     


        Object3D(Product mainapp) {
                super();
                this.mainapp = mainapp;
                
                int i;
                for( i=0 ; i < pnodeno ; i++ ){
                        pnodes[i] = new Node();
                }
                pnodes[0].x = -40;
                pnodes[0].y =  40;
                pnodes[1].x = -40;
                pnodes[1].y = -40;
                pnodes[2].x =  40;
                pnodes[2].y = -40;
                pnodes[3].x =  40;
                pnodes[3].y =  40;
                for( i=0 ; i < mnodeno ; i++ ){
                        mnodes[i] = new Node();
                        mnodes[i].x = 40;
                        mnodes[i].y = -40 + 80 * i;
                }
        }
        
        public synchronized void addParNode( double x, double y, int pos ) {
                // pos - position in array of new node
                Node newnodes[] = new Node[pnodeno+1];
                int i;
                for(i = 0; i < pos; i++ )
                        newnodes[i] = pnodes[i];
                newnodes[pos] = new Node();
                newnodes[pos].x = x;
                newnodes[pos].y = y;
                for(i = pos+1; i <= pnodeno; i++ )
                        newnodes[i] = pnodes[i-1];
                pnodeno++;
                pnodes = newnodes;
        }
        
        public synchronized void deleteParNode( int pos ) {
                // pos - position in array of new node
                if( pnodeno==2 ) return;
                int i;
                for(i = pos+1; i < pnodeno; i++ )
                        pnodes[i-1] = pnodes[i];
                pnodeno--;
        }
        
        public synchronized void addMerNode( double x, double y, int pos ) {
                // pos - position in array of new node
                Node newnodes[] = new Node[mnodeno+1];
                int i;
                for(i = 0; i < pos; i++ )
                        newnodes[i] = mnodes[i];
                newnodes[pos] = new Node();
                newnodes[pos].x = x;
                newnodes[pos].y = y;
                for(i = pos+1; i <= mnodeno; i++ )
                        newnodes[i] = mnodes[i-1];
                mnodeno++;
                mnodes = newnodes;
        }
        
        public synchronized void deleteMerNode( int pos ) {
                // pos - position in array of new node
                if( mnodeno==2 ) return;
                int i;
                for(i = pos+1; i < mnodeno; i++ )
                        mnodes[i-1] = mnodes[i];
                mnodeno--;
        }
        
        public synchronized void makeCube() {
                pnodeno = 4;
                mnodeno = 2;
                int i;
                
                pnodes = new Node[pnodeno];
                mnodes = new Node[mnodeno];

                mainapp.perspview.xtheta = 0;
                mainapp.perspview.ytheta = 0;

                for( i=0 ; i < pnodeno ; i++ ){
                        pnodes[i] = new Node();
                }
                pnodes[0].x = -40;
                pnodes[0].y =  40;
                pnodes[1].x = -40;
                pnodes[1].y = -40;
                pnodes[2].x =  40;
                pnodes[2].y = -40;
                pnodes[3].x =  40;
                pnodes[3].y =  40;
                
                for( i=0 ; i < mnodeno ; i++ ){
                        mnodes[i] = new Node();
                        mnodes[i].x = 40;
                        mnodes[i].y = -40 + 80 * i;
                }
        }

        public synchronized void makeSphere() {
                pnodeno = 12;
                mnodeno = 7;
                double pom = (2*Math.PI)/12;
                Node newpnodes[] = new Node[pnodeno];
                Node newmnodes[] = new Node[mnodeno];

                mainapp.perspview.xtheta = 0;
                mainapp.perspview.ytheta = 0;

                int i;
                for( i=0 ; i < pnodeno ; i++ ){
                        newpnodes[i] = new Node();
                        
                        newpnodes[i].x = 40*Math.cos(pom*i);
                        newpnodes[i].y = 40*Math.sin(pom*i);
                
                
                }
                
                for( i=0 ; i < mnodeno ; i++ ){
                        newmnodes[i] = new Node();
                        
                        newmnodes[i].x = 40*Math.cos((pom*i)-3*pom);
                        newmnodes[i].y = 40*Math.sin((pom*i)-3*pom);
                
                }
                pnodes = newpnodes;
                mnodes = newmnodes;

        }
        

  
                         

        public synchronized void makeCyl(){
                pnodeno = 12;
                mnodeno = 2;
                double pom = (2*Math.PI)/12;


                Node newpnodes[] = new Node[pnodeno];
                Node newmnodes[] = new Node[mnodeno];

                mainapp.perspview.xtheta = 0;
                mainapp.perspview.ytheta = 0;

                int i;
                for( i=0 ; i < pnodeno ; i++ ){
                        newpnodes[i] = new Node();
                        
                        newpnodes[i].x = 40*Math.cos(pom*i);
                        newpnodes[i].y = 40*Math.sin(pom*i);
                }
                
                for( i=0 ; i < mnodeno ; i++ ){
                        newmnodes[i] = new Node();
                }
                newmnodes[0].x =  40;
                newmnodes[0].y = -40;
                newmnodes[1].x =  40;
                newmnodes[1].y =  40;

                pnodes = newpnodes;
                mnodes = newmnodes;

        
        
        }
                         

        
        Node projectPoint(double x, double y, double z) {
                Node n=new Node();
                double x1,y1,z1,z2;

                x1 = x/40;
                y1 = y/40 * xct + z * xst;
                z1 = -y/40 * xst + z * xct;

                
                n.x= x1 * yct + y1 * yst;
                n.y= z1;
                z2 = (-x1 * yst + y1 * yct+300)/300;
				
				n.x /= z2;
                n.y /= z2;
				
				return n;
        }
        
        public synchronized void drawObject(Panel view, Graphics g) {
                int i,k;
                Node n1,n2;
                Dimension d = view.size();

                xtheta = mainapp.perspview.xtheta*(Math.PI/180);
                ytheta = mainapp.perspview.ytheta*(Math.PI/180);
                xst = Math.sin(xtheta);
                xct = Math.cos(xtheta);
                yst = Math.sin(ytheta);
                yct = Math.cos(ytheta);
                
                //draw meridians
				for( i=0; i<mnodeno; i++) {
                        n1 = projectPoint(pnodes[pnodeno-1].x*mnodes[i].x,
                                pnodes[pnodeno-1].y*mnodes[i].x,mnodes[i].y);
                        for( k=0; k<pnodeno;k++) {
                                n2 = n1;
                                n1 = projectPoint(pnodes[k].x*mnodes[i].x,
                                        pnodes[k].y*mnodes[i].x,mnodes[i].y);
                                        //System.out.println(n1.x);
                                g.drawLine((int)n1.x+d.width/2,(int)n1.y+d.height/2,
                                        (int)n2.x+d.width/2,(int)n2.y+d.height/2);
                        }
                }

				//draw parallel
                for( k=0; k<pnodeno;k++) {
                        n1 = projectPoint(pnodes[k].x*mnodes[0].x,
                                pnodes[k].y*mnodes[0].x,mnodes[0].y);
                        for( i=1; i<mnodeno; i++) {
                                n2 = n1;
                                n1 = projectPoint(pnodes[k].x*mnodes[i].x,
                                        pnodes[k].y*mnodes[i].x,mnodes[i].y);
                                
                                g.drawLine((int)n1.x+d.width/2,(int)n1.y+d.height/2,
                                        (int)n2.x+d.width/2,(int)n2.y+d.height/2);
                        }
                }
        }

		public void drawShadedObject(Panel view, Graphics g) {
                int i,k;
                Node n1,n2;
                Dimension d = view.size();
			

				//System.out.println("am here ..");


				double px,py,pz,x1,x2,y1,y2,z1,z2,persp;
				Point5d points[][] = new Point5d[mnodeno][pnodeno];
                Plane pom[] = new Plane[ ((mnodeno-1)*pnodeno) ];
				planes = pom;
				Point5d light = new Point5d();
				
				int xpoints[] = new int[4];
				int ypoints[] = new int[4];
				int p;
				
                xtheta = mainapp.perspview.xtheta*(Math.PI/180);
                ytheta = mainapp.perspview.ytheta*(Math.PI/180);
                
				xst = Math.sin(xtheta);
                xct = Math.cos(xtheta);
                yst = Math.sin(ytheta);
                yct = Math.cos(ytheta);

				light.x = 1.0;
				light.y = 1.0;
				light.z = 1.0;
				light.normalize();
			
				for( i=0; i<mnodeno; i++) {
					for( k=0; k<pnodeno;k++) {
					
						points[i][k] = new Point5d();
							
							px = pnodes[k].x*mnodes[i].x;
							py = pnodes[k].y*mnodes[i].x;
							pz =             mnodes[i].y;
							
							x1 =  px/40;
							y1 =  py/40 * xct + pz * xst;
							z1 = -py/40 * xst + pz * xct;
							x2 = x1 * yct + y1 * yst;
							y2 = z1;
							z2 = -x1 * yst + y1 * yct;
							persp = (-x1 * yst + y1 * yct+300)/300;


							points[i][k].x = x2;
							points[i][k].y = y2;
							points[i][k].z = z2;
							
							points[i][k].px = (int)(x2/persp + d.width/2);
							points[i][k].py = (int)(y2/persp + d.height/2);

							}
                }

				for( i=0; i<(mnodeno-1); i++) {
					for( k=0; k<(pnodeno-1);k++) {
						p = i*(pnodeno)+k;
						planes[p]= new Plane();
						planes[p].p1 = points[i  ][k  ];
						planes[p].p2 = points[i+1][k  ];
						planes[p].p3 = points[i  ][k+1];
						planes[p].p4 = points[i+1][k+1];

						planes[p].calcZ();
						planes[p].calcNorm();
						planes[p].calcColor(light);
					}
					p = (i+1)*(pnodeno)-1;
					
					planes[p]= new Plane();
					planes[p].p1 = points[i  ][pnodeno-1];
					planes[p].p2 = points[i+1][pnodeno-1];
					planes[p].p3 = points[i  ][0];
					planes[p].p4 = points[i+1][0];
					
					planes[p].calcZ();
					planes[p].calcNorm();
					planes[p].calcColor(light);

				}

				qsort(0,((mnodeno-1)*(pnodeno)-1));

				for( i=0; i<((mnodeno-1)*pnodeno); i++) {

					g.setColor(planes[i].kolor);
					xpoints[0]=planes[i].p1.px;ypoints[0]=planes[i].p1.py;
					xpoints[1]=planes[i].p2.px;ypoints[1]=planes[i].p2.py;
					xpoints[3]=planes[i].p3.px;ypoints[3]=planes[i].p3.py;
					xpoints[2]=planes[i].p4.px;ypoints[2]=planes[i].p4.py;
					
					g.fillPolygon(xpoints,ypoints,4);
				}
				


				
        }

		private void qsort(int left, int right) {
			int	i, j;
			int mid;
			Plane  tmp;
			i = left; j = right;
			mid = (left+right)/2;
			do {
				//nothing intelligent...
				//only comparison between z values
				while ((planes[mid].zmax < planes[i].zmax) && i < right) i++;
				while ((planes[j].zmax   < planes[mid].zmax) && j > left) j--;
				/* switch planes*/
				if (i <= j) {
					tmp = planes[i];
					planes[i] = planes[j];
					planes[j] = tmp;
					i++; j--;
				}
			} while (i <= j);

			if (left < j) qsort(left, j);
			if (i < right) qsort(i, right);
  }


	




} /* Object3D */


class EditPanel2D extends Panel implements Runnable {
        Product mainapp;
        Thread ourThread;
        Node pick;
        boolean pickfixed;
        Image offscreen;
        Dimension offscreensize;
        Graphics offgraphics;
        int type; /* 0 - meridian, 1 - parallel */
        
        final Color selectColor = Color.blue;
        final Color edgeColor = Color.black;
        final Color nodeColor = Color.green;
        final Color stressColor = Color.gray;
        final Color arcColor1 = Color.black;
        final Color arcColor2 = Color.pink;
        final Color arcColor3 = Color.red;
        final int w = 10;
        final int h = 10;
        
        public void init(){
        }
        
        EditPanel2D(Product mainapp, int type) {
                super();
                this.mainapp = mainapp;
                this.type = type;
        }
   
        public void paint(Graphics g) {
                update(g);
        }/*paint*/
        
        public void run() {
                while (true) {
                        try {
                                Thread.sleep(100);
                        } catch (InterruptedException e) {
                                break;
                        }
                }
        }
        
        public void paintNode(Graphics g, Node n) {
                int x = (int)n.x;
                int y = (int)n.y;
                
                g.setColor((n == pick) ? selectColor: nodeColor);
                g.fillOval(size().width / 2 + x - w/2, size().height / 2 + y - h / 2, w, h);
                g.setColor(Color.black);
        }
        
        public synchronized void update(Graphics g) {
                Dimension d = size();
                if ((offscreen == null) || (d.width != offscreensize.width)
                        || (d.height != offscreensize.height)) {
                                offscreen = createImage(d.width, d.height);
                                offscreensize = d;
                                offgraphics = offscreen.getGraphics();
                }
                offgraphics.setColor(Color.lightGray);
                offgraphics.fillRect(0, 0, d.width, d.height);
                offgraphics.setColor(Color.black);
                offgraphics.drawRect(0,0, d.width - 1, d.height - 1);
                offgraphics.setFont(new Font("Helvetica",0,12));
                if( type == 0 ) {
                        offgraphics.drawString("Meridian",5,15);
                } else offgraphics.drawString("Parallel",5,15);
                
                offgraphics.setColor(Color.gray);
                offgraphics.drawLine(0, d.height / 2, d.width ,d.height /2 );
                offgraphics.drawLine(d.width / 2,0, d.width/2 ,d.height );
                offgraphics.setColor(edgeColor);
                
                if( type == 1 ) {
                        for (int i = 0 ; i < mainapp.object3D.pnodeno ; i++) {
                                offgraphics.drawLine((int)(size().width / 2 + mainapp.object3D.pnodes[i].x),
                                        (int)(size().height / 2 + mainapp.object3D.pnodes[i].y),
                                        (int)(size().width / 2 + mainapp.object3D.pnodes[(i + 1)%mainapp.object3D.pnodeno].x),
                                        (int)(size().height / 2 + mainapp.object3D.pnodes[(i + 1)%mainapp.object3D.pnodeno].y));
                        }
                        for (int i = 0 ; i < mainapp.object3D.pnodeno ; i++) {
                                offgraphics.setColor((mainapp.object3D.pnodes[i] == pick) ? selectColor: nodeColor);
                                offgraphics.fillOval((int)(size().width / 2 + mainapp.object3D.pnodes[i].x - w/2),
                                        (int)(size().height / 2 + mainapp.object3D.pnodes[i].y - h / 2), w, h);
                        }
                } else  {
                        for (int i = 0 ; i < mainapp.object3D.mnodeno - 1; i++) {
                                offgraphics.drawLine((int)(size().width / 2 + mainapp.object3D.mnodes[i].x),
                                        (int)(size().height / 2 + mainapp.object3D.mnodes[i].y),
                                        (int)(size().width / 2 + mainapp.object3D.mnodes[i + 1].x),
                                        (int)(size().height / 2 + mainapp.object3D.mnodes[i + 1].y));
                        }
                        for (int i = 0 ; i < mainapp.object3D.mnodeno ; i++) {
                                offgraphics.setColor((mainapp.object3D.mnodes[i] == pick) ? selectColor: nodeColor);
                                offgraphics.fillOval((int)(size().width / 2 + mainapp.object3D.mnodes[i].x - w/2),
                                        (int)(size().height / 2 + mainapp.object3D.mnodes[i].y - h / 2), w, h);
                        }
                } 
                g.drawImage(offscreen, 0, 0, null);
        }/* end of update */
        
        public synchronized boolean mouseDown(Event evt, int x, int y) {
                Dimension d = size();
                double bestdist = Double.MAX_VALUE;
                int nodeno = -1;
                if( type == 1 ) {
                        for (int i = 0 ; i < mainapp.object3D.pnodeno ; i++) {
                                Node n =  mainapp.object3D.pnodes[i];
                                double dist = (n.x + d.width/2  - x) * (n.x + d.width/2 - x) + 
                                        (n.y +d.height/2- y) * (n.y  +d.height/2- y);
                                if (dist < bestdist && dist < w*w) {
                                        pick = n;
                                        nodeno = i;
                                        bestdist = dist;
                                }
                        }
                } else {
                        for (int i = 0 ; i < mainapp.object3D.mnodeno ; i++) {
                                Node n =  mainapp.object3D.mnodes[i];
                                double dist = (n.x + d.width/2 - x) * (n.x + d.width/2 - x) 
                                        + (n.y +d.height/2 - y) * (n.y  +d.height/2- y);
                                if (dist < bestdist && dist < 2*w) {
                                        pick = n;
                                        nodeno = i;
                                        bestdist = dist;
                                }
                        }
                }
                if( pick == null ){ 
                        return true; 
                }
                if( mainapp.editmode == 2 ) {
                        pick = null;
                        if(type==1)
                                mainapp.object3D.deleteParNode(nodeno);
                        else
                                mainapp.object3D.deleteMerNode(nodeno);
                        mainapp.editMode(3);
                        repaint();
                        mainapp.controls.setLabels();
                        mainapp.perspview.repaint();
                        return true;
                }
                if( mainapp.editmode == 1 ) {
                        if(type==1) {
                                mainapp.object3D.addParNode(x - d.width/2,y-d.height/2,nodeno);
                                pick = mainapp.object3D.pnodes[nodeno];
                        } else {
                                mainapp.object3D.addMerNode(x - d.width/2,y-d.height/2,nodeno);
                                pick = mainapp.object3D.mnodes[nodeno];
                        }
                        mainapp.editMode(3);
                        mainapp.controls.setLabels();
                }
                pick.x = x-d.width/2;
                pick.y = y-d.height/2;
                repaint();
                return true;
        }
        
        public synchronized boolean mouseDrag(Event evt, int x, int y) {
                if( mainapp.editmode == 2 ) return true;
                Dimension d = size();
                if( pick == null ){ 
                        return true; 
                }
                
                pick.x = x-d.width/2;
                pick.y = y-d.height/2;
                if( pick.x < -d.width/2 )
                        pick.x = -d.width/2;
                if( pick.x >= d.width/2)
                        pick.x = d.width/2-1;
                if( pick.y < -d.height/2 )
                        pick.y = -d.height/2;
                if( pick.y >= d.height/2)
                        pick.y = d.height/2-1;
                repaint();
                return true;
        }
        
        public synchronized boolean mouseUp(Event evt, int x, int y) {
                if( mainapp.editmode == 2 ) return true;
                Dimension d = size();
                if( pick == null ){
                        return true; 
                }
                pick.x = x-d.width/2;
                pick.y = y-d.height/2;
                if( pick.x < -d.width/2 )
                        pick.x = -d.width/2;
                if( pick.x >= d.width/2)
                        pick.x = d.width/2-1;
                if( pick.y < -d.height/2 )
                        pick.y = -d.height/2;
                if( pick.y >= d.height/2)
                        pick.y = d.height/2-1;
                pick = null;
                repaint();
                mainapp.perspview.repaint();
                return true;
        }
        
        public void start() {
                init();
                ourThread = new Thread(this);
                ourThread.start();
        }
        
        public void stop() {
                ourThread.stop();
        }
}/*end of Edit2D class*/


class ShowPanel extends Panel implements Runnable {
  Product mainapp;
  int prevx = 0;
  int prevy = 0;
  float xtheta = 0;
  float ytheta = 0;
  
  Thread ourThread;
  Image offscreen;
  Dimension offscreensize;
  Graphics offgraphics;
  
  
  ShowPanel(Product mainapp) {
    super();
    this.mainapp = mainapp;
  }
  
  public boolean mouseDown(Event e, int x, int y) {

	prevx = x;
    prevy = y;
	
    return true;
  }

  public boolean mouseUp(Event e, int x, int y) {
	mainapp.perspview.repaint();
    return true;
  }


  public boolean mouseDrag(Event e, int x, int y) {

    xtheta += (y - prevy) * 360.0f / size().width;
    ytheta -= (x - prevx) * 360.0f / size().height;
    
    mainapp.perspview.repaint();
    
    prevx = x;
    prevy = y;
    return true;
  }


  
  public void run() {
    while (true) {
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        break;
      }
    }
  }

  public void init(){
  }
  
  public void paint(Graphics g) {
    update(g);
  }/*paint*/
        
  public void update(Graphics g) {
    Dimension d = size();
	boolean st = mainapp.controls.sh.getState();

    if ((offscreen == null) || (d.width != offscreensize.width)
        || (d.height != offscreensize.height)) {
      offscreen = createImage(d.width, d.height);
      offscreensize = d;
      offgraphics = offscreen.getGraphics();
    }
    offgraphics.setColor(Color.lightGray);
    offgraphics.fillRect(1, 1, d.width-1, d.height-1);
    offgraphics.setColor(Color.black);
    offgraphics.drawRect(0,0, d.width - 1, d.height - 1);
	if (st) {
		mainapp.object3D.drawShadedObject(this,offgraphics);
	} else {
		mainapp.object3D.drawObject(this,offgraphics);
	}
    g.drawImage(offscreen, 0, 0, null);
  }/*paint*/

  


  public void start() {
    init();
    ourThread = new Thread(this);
    ourThread.start();
  }
  
  public void stop() {
    ourThread.stop();
  }
}


class ControlPanel extends Panel {
        Label topNodes;
        Label frontNodes;
        Button addB, delB, movB, sphB, cubB, cylB;
		Checkbox sh;
        Font fb, ft;
        Choice viewType;
        Product mainapp;
        
        
        ControlPanel(Product mainapp) {
                super();
                this.mainapp = mainapp;
                Component comp;
                GridBagLayout  gridbag  =  new  GridBagLayout();
                GridBagConstraints  c  =  new  GridBagConstraints();
                
                setLayout(gridbag);
                
                fb = new Font("Helvetica",Font.BOLD,12);
                setFont(ft = new Font("Helvetica",0,12));
                
                c.fill = GridBagConstraints.BOTH;
                c.gridwidth = GridBagConstraints.REMAINDER;
                gridbag.setConstraints( comp = new Label("Spherical Product",Label.CENTER),c);
                add( comp );
                comp.setFont(new Font("Helvetica",Font.BOLD,16));
                gridbag.setConstraints( comp = new Label("(C) 1996 P. Kozankiewicz and M. Truszel",Label.CENTER),c);
                add( comp );                                                                                                      
                gridbag.setConstraints( comp = new Label(""),c); // How can I create one empty line?
                add( comp );

                topNodes = new Label("Parallel points no.: 4"); 
                gridbag.setConstraints( topNodes , c );
                add( topNodes );
                
                frontNodes = new Label("Meridian points no.: 2" );
                gridbag.setConstraints( frontNodes , c );
                add( frontNodes );
                
                c.gridwidth = 1;
                c.gridx=-1;
                Label l1;
                gridbag.setConstraints( l1= new Label("Points:") , c );
                add( l1 );
                gridbag.setConstraints( movB = new Button("Move") , c );
                add( movB );
                gridbag.setConstraints( addB = new Button("Add") , c );
                add( addB );
                c.gridwidth = GridBagConstraints.REMAINDER;
                gridbag.setConstraints( delB = new Button("Delete") , c );
                add( delB );
                
                c.gridwidth = 1;
                c.gridx=-1;
				
				Label l2;
                gridbag.setConstraints( l2= new Label("Objects:") , c );
                add( l2 );

                gridbag.setConstraints( sphB = new Button("Sphere") , c );
                add( sphB );
                gridbag.setConstraints( cubB = new Button("Cube") , c );
                add( cubB );
				c.gridwidth = GridBagConstraints.REMAINDER;
                gridbag.setConstraints( cylB = new Button("Cylinder") , c );
                add( cylB );
                
				c.gridwidth = 1;
                c.gridx=-1;
				Label l3;
                gridbag.setConstraints( l3= new Label("         ") , c );
                add( l3 );

				gridbag.setConstraints( sh = new Checkbox("Shaded") , c );
				add( sh );
				c.gridwidth = GridBagConstraints.REMAINDER;
				
				addB.setFont(fb);
				sh.setState(true);
        }
        
        public void setLabels(){
                topNodes.setText("Parallel points no.: "+mainapp.object3D.pnodeno);
                frontNodes.setText("Meridian points no.: "+mainapp.object3D.mnodeno);
        }
        
        public boolean handleEvent( Event e ) {
                if( e.id == Event.ACTION_EVENT ) {
                        if( e.target == addB ) { 
                                mainapp.editMode(1);
                                return true;
                        } else if( e.target == delB ) { 
                                mainapp.editMode(2);
                                return true;
                        } else if( e.target == movB ) { 
                                mainapp.editMode(3);
                                return true;
						} else if( e.target == sh ) { 
                                mainapp.perspview.repaint();
                                return true;
						} else if( e.target == cubB ) { 
                                mainapp.object3D.makeCube();
                                mainapp.panelmer.repaint();
                                mainapp.panelpar.repaint();
                                mainapp.perspview.repaint();
                                mainapp.controls.setLabels();
                                return true;
                        } else if( e.target == sphB ) {
                                mainapp.object3D.makeSphere();
                                mainapp.panelmer.repaint();
                                mainapp.panelpar.repaint();
                                mainapp.perspview.repaint();
                                mainapp.controls.setLabels();
                                return true;
                        } else if( e.target == cylB ) {
                                mainapp.object3D.makeCyl();
                                mainapp.panelmer.repaint();
                                mainapp.panelpar.repaint();
                                mainapp.perspview.repaint();
                                mainapp.controls.setLabels();
                                return true;
                        }



                }
                
                return super.handleEvent( e );
        }
        
        public void setMode(int m) {
                if( m == 1 ) {
                        addB.setFont(fb);
                        delB.setFont(ft);
                        movB.setFont(ft);
                } else  if( m == 2 ) {
                        addB.setFont(ft);
                        delB.setFont(fb);
                        movB.setFont(ft);
                } else  if( m == 3 ) {
                        addB.setFont(ft);
                        delB.setFont(ft);
                        movB.setFont(fb);
                }
        }
}/*end of ControlPanel class */
