1  // (c) NPAC
  2  // Author: Mehmet Sen at NPAC
  3  // Note :    This applet is written based on the first version which is
  4  //           implemented by Ozgur Balsoy and Mehmet Sen.
  5  //
  6  import java.applet.*;
  7  import java.awt.*;
  8  import java.util.*;
  9  //*******************************************************************//
 10  // APPLET                                                           *//
 11  //*******************************************************************//
 12  
 13  public class GridApplet extends Applet {
 14    ControlPanel cp;
 15  public void init() {
 16    Label status = new Label("Welcome!", Label.CENTER);
 17    status.setBackground(Color.pink);
 18    GridCanvas canvas = new GridCanvas(status,getImage(getDocumentBase(),"grenbull.gif"),getImage(getDocumentBase(),"redbull.gif"));
 19    cp= new ControlPanel(canvas, status);
 20  
 21    setLayout(new BorderLayout());
 22  
 23    add("North", cp);
 24    add("Center", canvas);
 25    add("South", status);
 26  }
 27  public void start()
 28    {
 29      cp.cellMode.showUp();
 30    }
 31  }
 32  //************************************************************************
 33  // Control Panel
 34  //*******************************************************************/
 35  
 36  class ControlPanel extends Panel {
 37  
 38    int MAXLINES=20;
 39  public choiceCanvas cellMode ;
 40    GridCanvas canvas;
 41    Label statusLine;
 42    Choice rows, cols;
 43    //    Choice cellMode;
 44  public ControlPanel(GridCanvas canvas, Label statusLine) {
 45    //setBackground(Color.gray);
 46    //setForeground(Color.yellow);
 47  
 48    this.canvas = canvas;
 49    this.statusLine = statusLine;
 50    this.cellMode=new choiceCanvas(canvas);
 51  
 52    rows=new Choice();
 53    cols=new Choice();
 54    for(int i=1; i<MAXLINES; i++) {
 55      rows.addItem(Integer.toString(i));
 56      cols.addItem(Integer.toString(i));
 57    }
 58    //cellMode =new Choice();
 59    //cellMode.addItem("Brick");
 60    //cellMode.addItem("Left Brace");
 61    //cellMode.addItem("Right Brace");
 62  
 63    setLayout(new GridLayout(2,5));
 64  
 65    add(new Label("Rows:  ", Label.RIGHT));
 66    add(rows);
 67    add(new Label(" CELL MODE ", Label.LEFT));
 68    //add(cellMode,Label.CENTER);
 69    //add(canvas);
 70  
 71    add(new Button("New"));
 72    add(new Button("Graph"));
 73  
 74    add(new Label("Columns:  ", Label.RIGHT));
 75    add(cols);
 76    add(cellMode);
 77  
 78    //add(mymenu);
 79  
 80  
 81    add(new Button("Check"));
 82    add(new Button("Back"));
 83  }
 84  
 85  public boolean action(Event evt, Object what) {
 86    if(evt.target instanceof Button) {
 87      String s=(String)what;
 88      statusLine.setText(s);
 89      if(s.equals("New")) {
 90        canvas.draw(rows.getSelectedIndex()+1,
 91  		  cols.getSelectedIndex()+1);
 92      } else if(s.equals("Check")) {
 93        canvas.check();
 94      } else if(s.equals("Back")) {
 95        canvas.back();
 96      }else if(s.equals("Graph")) {
 97        canvas.graph();
 98      }
 99      return true;
100    }
101    //else if ( evt.target instanceof Choice) {
102    //   String s=(String) what;
103    //canvas.setCellMode(s);
104    // return true;
105    //}
106    return false;
107  }
108  
109  }
110  //************************************************************************
111  // CANVAS
112  //*******************************************************************/
113  class GridCanvas extends Canvas {
114    int WHITE=0,GRAY=2,BLACK=5,CYAN=34;
115    int LEFT=1,RIGHT=2,BOTH=3,NONE=0;
116    int UNDEFINED=-111;
117  
118    int visits=0;
119    int sccvisits=0;
120    int component=0;
121    int dir=1;
122  
123    GraphComponent[] finish;
124    GraphComponent[] strongConnComp;
125  
126    int  GRID=1;
127    int GRAPH=0;
128    int BRICK=0,LEFT_BRACE=1,RIGHT_BRACE=2;
129    int displayMode=GRID;
130    int cellMode=BRICK;
131    Label statusLine;
132    double MARGINS = 0.15;
133    Image ballg;
134    Image ballr;
135    boolean rigid=false;
136    int rows, cols, length;
137    Point gridCorner;
138    GraphComponent[] rowComps, colComps;
139    GridCell[][] cells;
140    boolean gridExist = false;
141  
142    int startRow,startCol; //internal usage, no meaning
143  
144  public GridCanvas(Label statusLine,Image ballg,Image ballr) {
145    this.ballg=ballg;
146    this.ballr=ballr;
147    this.statusLine = statusLine;
148  }
149  
150  public void setCellMode(int mode) { //String mode){
151    this.cellMode=mode;
152    //if(mode.equals("Brick"))
153    //	cellMode=BRICK;
154    //else if (mode.equals("Left Brace"))
155    //	cellMode=LEFT_BRACE;
156    //else if (mode.equals("Right Brace"))
157    //	cellMode=RIGHT_BRACE;
158  }
159  public void draw(int rows, int cols) {
160    Graphics g=getGraphics();
161    g.drawImage(ballg,-30,-30,null);
162    g.drawImage(ballr,-60,-60,null);
163    g.dispose();
164    // asctual statrt
165  
166    displayMode=GRID;
167    statusLine.setText("Drawing " + rows + " by " + cols + " grid.");
168    cells=new GridCell[rows][cols];
169  
170  
171    rowComps = new GraphComponent[rows];
172    for(int i=0; i<rows; i++) {
173      rowComps[i] = new GraphComponent( i );
174      rowComps[i].setRowType();
175    }
176  
177    colComps = new GraphComponent[cols];
178    for(int i=0; i<cols; i++){
179      colComps[i] = new GraphComponent( i );
180      colComps[i].setColType();
181    }
182  
183    int width = (int)(size().width * (1.0 - MARGINS * 2.0));
184    int height = (int)(size().height * (1.0 - MARGINS * 2.0));
185    length = Math.min( width / cols, height / rows);
186  
187    gridCorner=new Point((size().width - length * cols) / 2,
188  		       (size().height - length * rows) / 2);
189  
190    for(int r=0; r<rows; r++)
191      for(int c=0; c<cols; c++)
192        cells[r][c] = new GridCell(gridCorner.x + c * length,
193  				 gridCorner.y + r * length,
194  				 length, r, c );
195    this.rows = rows;
196    this.cols = cols;
197    gridExist = true;
198    repaint();
199  }
200  
201  public GraphComponent calculateComponentOLD(){
202    GraphComponent[] comp=new GraphComponent[cols];
203    for(int c=0; c<cols; c++) {
204      comp[c]=new GraphComponent(colComps[c]);
205    }
206    for(int r=0; r<rows; r++) {   // finds individual components
207      Vector v=rowComps[r].getCells();
208      if(!v.isEmpty()) {
209        GridCell c=(GridCell)(v.firstElement());
210        for(Enumeration e=rowComps[r].getCells().elements(); e.hasMoreElements(); ) {
211  
212  	GridCell cell= (GridCell)(e.nextElement());
213  
214  	int firstElementID = comp[c.colIndex].ID;
215  	int currentCellID = comp[cell.colIndex].ID;
216  
217  	comp[c.colIndex].merge(comp[cell.colIndex]);
218  
219  	int greatID = Math.max(firstElementID, currentCellID  );
220  
221  	for(int j=0; j<cols; j++)
222  	  if(comp[j].ID == greatID)
223  	    if( firstElementID < currentCellID )
224  	      comp[j] = comp[c.colIndex];
225  	    else
226  	      comp[j] = comp[cell.colIndex];
227        }
228      }
229    }
230    for(int i=0;i<cols;i++)
231      if ( !comp[i].getCells().isEmpty()) {
232        return comp[i];
233      }
234    return null;
235  }
236    //***************************************************************//
237    //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
238  public void  calculateComponent(){
239  
240    /// .... initialize for the Depth First Search .... /////
241  
242    for(int c=0; c<cols; c++) {
243      colComps[c].color=WHITE;
244      colComps[c].rigid=false;
245      colComps[c].rotation=null;
246    }
247    for(int r=0; r<rows; r++) {
248      rowComps[r].color=WHITE;
249      rowComps[r].rigid=false;
250      rowComps[r].rotation=null;
251    }
252  
253    strongConnComp= new GraphComponent[cols+rows];
254    finish= new GraphComponent[cols+rows];
255    component=0;
256    visits=0;
257  
258    /// do Depth First Search
259    for(int c=0; c<cols; c++)
260      if (colComps[c].color==WHITE) {
261        visits=0;
262        DFSforward(colComps[c]);
263        findStrCCs();
264      }
265    for(int r=0; r<rows; r++)
266      if (rowComps[r].color==WHITE){
267        DFSforward(rowComps[r]);
268        findStrCCs();
269      }
270  } //calculateComponent()
271  
272  
273  
274  public void  findStrCCs()
275    {
276      /// .... initialize for the Depth First Search .... /////
277      for(int i=0; i<visits; i++) {
278        finish[i].color=WHITE;
279      }
280  
281      for(int i=visits-1;i>=0;i--) {
282        if (finish[i].color==WHITE) {
283  	sccvisits=0;
284  	//System.out.println("-bc--------->"+(1+finish[i].ID)+finish[i].colType() );
285  	DFSbackward(finish[i]);
286  	if (sccvisits > 1) {
287  	  //  System.out.println("OLAY");
288  	  Rotate rot=new Rotate(UNDEFINED);
289  	  rot.id=component++;
290  	  for (int a=0;a<sccvisits;a++) {
291  	    strongConnComp[a].rigid=true;
292  	    strongConnComp[a].rotation=rot;
293  	  }
294  	}
295        }
296      }
297      if (sccvisits==rows+cols)
298        rigid=true;
299      else   rigid=false;
300    }
301  public void DFSforward(GraphComponent gc)
302    {
303      gc.color=GRAY;
304      Vector v=gc.getCells();
305      for(Enumeration e=v.elements(); e.hasMoreElements(); ) {
306        GridCell cell= (GridCell)(e.nextElement());
307        if (gc.rowType() && cell.rightBrace() && colComps[cell.colIndex].color==WHITE )
308  	DFSforward(colComps[cell.colIndex]);
309        else if (gc.colType() && cell.leftBrace() && rowComps[cell.rowIndex].color==WHITE )
310  	DFSforward(rowComps[cell.rowIndex]);
311      }
312      gc.color=BLACK;
313      gc.cmpcolor=GRAY;
314      finish[visits]=gc;
315      visits++;
316    }
317  
318  public void DFSbackward(GraphComponent gc)
319    {
320      gc.color=GRAY;
321      Vector v=gc.getCells();
322      for(Enumeration e=v.elements(); e.hasMoreElements(); ) {
323        GridCell cell= (GridCell)(e.nextElement());
324        if (gc.rowType()&&cell.leftBrace() && colComps[cell.colIndex].color==WHITE&& colComps[cell.colIndex].cmpcolor==GRAY )
325  	DFSbackward(colComps[cell.colIndex]);
326        else if (gc.colType() && cell.rightBrace() && rowComps[cell.rowIndex].color==WHITE && rowComps[cell.rowIndex].cmpcolor==GRAY )
327  	DFSbackward(rowComps[cell.rowIndex]);
328      }
329      gc.color=BLACK;
330      gc.cmpcolor=BLACK;
331      strongConnComp[sccvisits]=gc;
332      sccvisits++;
333    }
334    //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
335    // assume only strong conn. comp  are checked ,i.e., coming in the parameter
336  public void   find_pzf_ngf(GraphComponent gc)
337    {
338      //if (gc.rotation==null) {
339      //  Rotate rt=new Rotate(UNDEFINED);
340      //  gc.rotation=rt;
341      //}
342  
343      Vector v=gc.getCells();
344      for(Enumeration e=v.elements(); e.hasMoreElements(); ) {
345        GridCell cell= (GridCell)(e.nextElement());
346  
347        if ( gc.rotation.negatif&&gc.rotation.pozitif)   /// break the loop
348  	return;
349        
350        if (rowComps[cell.rowIndex].rotation!=gc.rotation) {
351  	if (cell.leftBrace() )
352  	  gc.rotation.negatif=true;
353  	else
354  	  gc.rotation.pozitif=true;
355        }
356        else if (colComps[cell.colIndex].rotation!=gc.rotation){
357  	if (cell.leftBrace() )
358  	  gc.rotation.pozitif=true;
359  	else
360  	  gc.rotation.negatif=true;
361        }
362      }
363    }
364  
365  public void   pzf_2_my_followers(GraphComponent gc)
366    {
367      gc.color=CYAN;
368      if (gc.rotation==null) {
369        Rotate rt=new Rotate(UNDEFINED);
370        gc.rotation=rt;
371      }
372      gc.rotation.pozitif=true;   // THINK ABOUT LATER
373      gc.rotation.negatif=false;   // THINK ABOUT LATER
374  
375      Vector v=gc.getCells();
376      for(Enumeration e=v.elements(); e.hasMoreElements(); ) {
377        GridCell cell= (GridCell)(e.nextElement());
378        if (gc.rowType() && cell.rightBrace() && colComps[cell.colIndex].color!=CYAN )
379  	pzf_2_my_followers(colComps[cell.colIndex]);
380        else if (gc.colType() && cell.leftBrace() && rowComps[cell.rowIndex].color!=CYAN )
381  	pzf_2_my_followers(rowComps[cell.rowIndex]);
382      }
383    }
384  public void   find_simple_pzf_ngf(GraphComponent gc)
385    {
386      if (gc.rotation==null) {
387        Rotate rt=new Rotate(UNDEFINED);
388        gc.rotation=rt;
389      }
390  
391      Vector v=gc.getCells();
392      for(Enumeration e=v.elements(); e.hasMoreElements(); ) {
393        GridCell cell= (GridCell)(e.nextElement());
394  
395        if ( gc.rotation.negatif&&gc.rotation.pozitif)   /// break the loop
396  	return;
397        if ( gc.colType() ) {
398  	if (cell.leftBrace() )
399  	  gc.rotation.negatif=true;
400  	else
401  	  gc.rotation.pozitif=true;
402        }
403        else {
404  	if (cell.leftBrace() )
405  	  gc.rotation.pozitif=true;
406  	else
407  	  gc.rotation.negatif=true;
408        }
409  	
410        
411      }
412    }
413  
414  public void  calculateDirections(){
415    boolean alternated=true;
416  
417    for(int c=0; c<cols; c++) {
418      if (!colComps[c].rigid )
419        find_simple_pzf_ngf(colComps[c]);
420    }
421    for(int r=0; r<rows; r++) {
422      if (!rowComps[r].rigid )
423        find_simple_pzf_ngf(rowComps[r]);
424    }
425  
426    // **********
427    for(int r=0; r<rows; r++) {
428      if (rowComps[r].rigid &&  !(rowComps[r].rotation.pozitif && rowComps[r].rotation.negatif)) {
429        find_pzf_ngf(rowComps[r]);
430        ///System.out.println(rowComps[r].rotation.pozitif+"   "+rowComps[r].rotation.negatif);
431        
432      }
433    }
434    for(int c=0; c<cols; c++) {
435      if (colComps[c].rigid && ! (colComps[c].rotation.pozitif && colComps[c].rotation.negatif)) {
436        find_pzf_ngf(colComps[c]);
437      }
438      ///System.out.println(colComps[c].rotation.pozitif+" + -  "+colComps[c].rotation.negatif);
439      
440    }
441    
442  
443    for(int c=0; c<cols; c++) {   
444      if (colComps[c].rigid &&!colComps[c].rotation.pozitif && !colComps[c].rotation.negatif) {
445        colComps[c].rotation.pozitif=alternated;
446        colComps[c].rotation.negatif=!alternated;
447        alternated=!alternated;
448      }
449      ///    System.out.println("--->"+colComps[c].rotation.pozitif+" + -  "+colComps[c].rotation.negatif);
450    }
451  
452    // **********
453    for(int c=0; c<cols; c++) {
454       if (colComps[c].rigid &&colComps[c].rotation.pozitif && colComps[c].rotation.negatif)
455     {    pzf_2_my_followers(colComps[c]);
456       colComps[c].rotation.negatif=false;
457     }
458    }
459     for(int r=0; r<rows; r++) {
460       if (rowComps[r].rigid && rowComps[r].rotation.pozitif && rowComps[r].rotation.negatif)
461      {   pzf_2_my_followers(rowComps[r]);
462       rowComps[r].rotation.negatif=false;
463      }
464    }
465  /*
466    for(int c=0; c<cols; c++) {
467      if (colComps[c].rotation.pozitif && colComps[c].rotation.negatif)
468        System.out.println("col +-"+(c+1));
469    }
470    for(int r=0; r<rows; r++) {
471      if ( rowComps[r].rotation.pozitif && rowComps[r].rotation.negatif)
472        System.out.println("row +-"+(r+1));
473    }
474  */
475  }
476  
477  
478  public void check(){
479    if ( !gridExist ) {
480      statusLine.setText("Check :    Please define the grid first!");
481      return;
482    }
483    displayMode=GRID;
484    calculateComponent();
485    calculateDirections();
486  
487    Graphics g=getGraphics();
488    for(int k=0; k<5; k++) {
489      animate(k*3);
490      paint(g);
491      //    try {
492      //Thread.sleep(200);
493      //    }
494      //  catch(InterruptedException e) {};
495    }
496    g.dispose();
497  
498    // check the rigidity
499    if (rigid)
500      statusLine.setText("RIGID");
501    else statusLine.setText("NOT rigid");
502  }
503  
504  
505  public int getMyDirection(GraphComponent gc,int defaultd) {
506    if (gc.rotation==null)
507      System.out.println("BIG MISTAKE");
508    else if (gc.rotation.pozitif&&gc.rotation.negatif)
509       return 0;
510    else if (!gc.rotation.pozitif&&!gc.rotation.negatif)
511      return defaultd; 
512    else if (gc.rotation.pozitif)
513      return -1;
514    else if (gc.rotation.negatif)
515      return 1;
516    return 0;
517  }
518  
519  
520  public void animate(int angle){
521    int direction=-1;
522  
523    cells[0][0].updateAngle(angle);
524    cells[0][0].place(gridCorner);
525  
526    direction=getMyDirection(colComps[0],direction*-1);
527    if (   direction !=0  )
528      cells[0][0].rotateTop(null,direction);
529    direction=getMyDirection(rowComps[0],direction*-1);
530    if (   direction !=0  )
531      cells[0][0].rotateLeft(null,direction);
532  
533  
534    for(int i=1; i<cols; i++) {
535      direction=getMyDirection(colComps[i],direction*-1);
536      if (   direction !=0  )
537        cells[0][i].rotateTop(cells[0][i-1],direction);
538      else cells[0][i].translateTop(cells[0][i-1]);
539    }
540  
541    for(int i=1; i<rows; i++){
542      direction=getMyDirection(rowComps[i],direction*-1);
543      if (  direction !=0   )
544        cells[i][0].rotateLeft(cells[i-1][0],direction);
545      else cells[i][0].translateLeft(cells[i-1][0]);
546    }
547  
548    GridCell below, corner, right;
549    for(int m=0; m<rows; m++)
550      for(int n=0; n<cols; n++) {
551        if( m < rows-1) below=cells[m+1][n];
552        else  below=null;
553  
554        if( n < cols-1) right=cells[m][n+1];
555        else  right=null;
556  
557        if ( below==null || right == null ) corner = null;
558        else corner=cells[m+1][n+1];
559  
560        cells[m][n].finish(below,right,corner);
561      }
562    cells[0][0].findShifting(size().height/2,rows*cols);
563    for(int m=0; m<rows; m++)
564      for(int n=0; n<cols; n++)
565        cells[m][n].shift();
566  }
567  
568    //*********************************************************************//
569  
570  public void back()
571    {  	if ( !gridExist ) {
572      statusLine.setText("Back :   Please define the grid first!");
573      return;
574    }
575    displayMode=GRID;
576    Graphics g=getGraphics();
577    for(int k=4; k>-1; k--) {
578      animate(k*3);
579      paint(g);
580      //    try {
581      //Thread.sleep(200);
582      //    }
583      //  catch(InterruptedException e) {};
584    }
585    g.dispose();
586    }
587  
588  
589  public boolean mouseDown(Event evt, int x, int y) {
590    if ( !gridExist || displayMode==GRAPH)
591      return true;
592    //x -= gridCorner.x;
593    //y -= gridCorner.y;
594    //if(x<(gridCorner.x+length*cols) && y<(gridCorner.y+length*rows)
595    //   && x>gridCorner.x && y>gridCorner.y ) {
596    int i,c=-1; //= x / length;
597    int j,r=-1;//= y / length;
598  
599    for (i=0;i<rows;i++)
600      for (j=0;j<cols;j++)
601        if ( cells[i][j].myframe().inside(x,y)) {
602  	r=i;
603  	c=j;
604  	break;
605        }
606    if ( r==-1 ) return true;
607  
608    cells[r][c].toggleRigid(cellMode);
609    Graphics g=getGraphics();
610    cells[r][c].paint(g);
611    g.dispose();
612  
613    if(cells[r][c].rigid) {
614      rowComps[r].addCell(cells[r][c]);
615      colComps[c].addCell(cells[r][c]);
616  
617    } else {
618      rowComps[r].removeCell(cells[r][c]);
619      colComps[c].removeCell(cells[r][c]);
620    }
621  
622    return true;
623  }
624  public void graph()    {
625    displayMode=GRAPH;
626    calculateComponent();
627    repaint();
628    repaint();
629  }
630  public void plotGraph(Graphics g)
631    {
632      int [] tx=new int[3];
633      int [] ty=new int[3];
634  
635  
636      int colonsY = (int)(size().height * ( MARGINS ));
637      int rowsY = (int)(size().height * (1.0 - MARGINS ));
638      int stepY = (int)(size().height * ( .08 ));
639      int stepX = (int)(size().width * ( .05 ));
640      int X = (int)(size().width/2);
641      if ( rows > cols )  X -=stepX*rows/2;
642      else X -=stepX*cols/2;
643      double SIN=0.42261826, COS=0.90630779;
644  
645  
646      for (int i=0;i<rows;i++)
647        for (int j=0;j<cols;j++)
648  	if ( rowComps[i].getCells().contains( cells[i][j] ) &&
649  	     colComps[j].getCells().contains( cells[i][j] ) )  {
650  	  if ( rowComps[i].rigid&&colComps[j].rigid)
651  	    g.setColor(Color.red);
652  	  else g.setColor(Color.black);
653  	  int x1=X+i*stepX+8,  y1=rowsY-3*stepY+8;
654  	  int x2=X + j*stepX+8, y2=colonsY+2*stepY+8;
655  	  double alfa=-Math.atan( (double)(x2-x1)/(double)(y2-y1));
656  
657  	  if (cells[i][j].rightBrace() )
658  	    {
659  	      tx[0]=x2;
660  	      ty[0]=y2;
661  	      tx[1]=(int) (x2- 15*Math.sin(alfa-0.230)+1);
662  	      ty[1]=(int) (y2+15*Math.cos(alfa-0.230));
663  	      tx[2]=(int) (x2- 15*Math.sin(alfa+0.230));
664  	      ty[2]=(int) (y2+15*Math.cos(alfa+0.230));
665  	      g.fillPolygon(tx,ty,3);
666  	    }
667  	  if (cells[i][j].leftBrace() )
668  	    {
669  	      tx[0]=x1;
670  	      ty[0]=y1;
671  	      tx[1]=(int) (x1+ 15*Math.sin(alfa-0.230)+1);
672  	      ty[1]=(int) (y1-15*Math.cos(alfa-0.230));
673  	      tx[2]=(int) (x1+ 15*Math.sin(alfa+0.230));
674  	      ty[2]=(int) (y1-15*Math.cos(alfa+0.230));
675  	      g.fillPolygon(tx,ty,3);
676  	    }
677  
678  	  g.drawLine(x1,y1,x2,y2);
679  	}
680      g.setColor(Color.black);
681      g.drawString ("COLUMNS",X+stepX*cols/2 -40,colonsY);
682      for (int j=0; j < cols ;j++) {
683        g.drawString(Integer.toString(j+1),X + j*stepX,colonsY+stepY);
684        g.drawImage(ballg,X + j*stepX,colonsY+2*stepY-3,null);
685      }
686  
687      for (int i=0; i < rows ;i++){
688        g.drawString(Integer.toString(i+1),X + i*stepX,rowsY-stepY);
689        g.drawImage(ballr,X + i*stepX,rowsY-3*stepY,null);
690      }
691      g.drawString ("ROWS",X+stepX*rows/2 -15,rowsY);
692  
693    }
694  
695  
696  public void update(Graphics g) {
697    paint(g);
698  }
699  
700  public void paint(Graphics g) {
701  
702    // draw a rectangle inside canvas to separate canvas from buttons.
703  
704    
705    g.clearRect(6, 6, size().width-6, size().height-6);
706    g.setColor(Color.yellow);
707    g.fillRect(0,0,size().width-1,4);
708    g.fillRect(0,0,4,size().height-1);
709    g.fillRect(size().width-4,0,4,size().height-1);
710    g.fillRect(0,size().height-4,size().width-1,4);
711    g.setColor(Color.black);
712    g.drawRect(5,5,size().width-11, size().height-11);
713    if(gridExist)
714      if ( displayMode == GRID )
715        for(int m=0; m<rows; m++)
716  	for(int n=0; n<cols; n++)
717  	  cells[m][n].paint(g);
718      else if ( displayMode == GRAPH ) plotGraph(g);
719    
720  }
721    
722  } //canvas
723  
724  /*
725    for (int i=0;i<255;i++)
726      {
727        g.setColor(new Color((int)(Math.random()*100+100)));
728        g.drawLine(0,0,300,i);
729        g.setColor(new Color((float)Math.random(),(float)Math.random(),(float)Math.random()));
730        g.drawLine(600,0,300,i);
731      
732      }
733  */
734  
735  
736  // canvas ends here
737  //****************************************************************************
738  //CELL
739  //****************************************************************************/
740  class GridCell {
741  
742      public Point topLeft;
743      Point topRight, bottomLeft, bottomRight;
744      public int rowIndex, colIndex;
745      public boolean rigid = false;
746      int BRICK=0, LEFT_BRACE=1, RIGHT_BRACE=2;
747      public int rigidType = BRICK;
748  
749       int length;
750       double diagonal;
751      static double COS= 0.9961947, SIN = 0.087155743; // cos(5) , sin(5)
752      static double angle =0.0;
753      static int centery,deltay=0;
754  
755      public GridCell(int x, int y, int length, int rowIndex, int colIndex) {
756  
757  	  topLeft  = new Point(x, y);
758  	  topRight = new Point(x + length, y);
759  
760  	  bottomLeft  = new Point(x, y + length);
761  	  bottomRight = new Point(x + length, y + length);
762  
763  	  this.length=length;
764  	  this.diagonal=Math.sqrt(2*length*length);
765  	  this.rowIndex = rowIndex;
766  	  this.colIndex = colIndex;
767        }
768      public void place(Point p)
769        {
770  	  topLeft.x=p.x;
771  	  topLeft.y=p.y;
772  	  topRight.x=p.x+length;
773  	  topRight.y=p.y;
774  	  bottomLeft.x =p.x;
775  	  bottomLeft.y =p.y+length;
776  	  bottomRight.x = p.x+length;
777  	  bottomRight.y = p.y+length;
778  	  centery=0;
779  	  deltay=0;
780  
781        }
782  
783  
784      public void updateAngle(int angle){
785  	//if ( angle >= 15.0 )
786  	//  angle=0.0;
787  	//angle +=3.0;
788  	this.angle=angle;
789  
790  	COS= Math.cos((angle*Math.PI)/180.0);
791  	SIN= Math.sin((angle*Math.PI)/180.0);
792        }
793  
794      public void toggleRigid(int type) {
795  	rigid = !rigid;
796  	rigidType = type;
797        }
798      public boolean leftBrace() {
799  	return rigid&&(LEFT_BRACE==rigidType||BRICK==rigidType);
800      }
801       public boolean rightBrace() {
802  	return rigid&&(RIGHT_BRACE==rigidType||BRICK==rigidType);
803      }
804  
805      public void rotateTop(GridCell neighbor,int direction){
806         	if (neighbor!=null) {
807  	    topLeft.x=neighbor.topRight.x;
808  	    topLeft.y=neighbor.topRight.y;
809  	}
810  
811  	topRight.x =(int)(topLeft.x +(double)length*COS);
812  	topRight.y =(int)(topLeft.y -(double)length*SIN*direction);
813        }
814      public void rotateLeft(GridCell neighbor,int direction){
815         	if (neighbor!=null) {
816  	    topLeft.x=neighbor.bottomLeft.x;
817  	    topLeft.y=neighbor.bottomLeft.y;
818  	}
819  
820  	bottomLeft.x = (int) (topLeft.x +(double)length*SIN*direction);
821  	bottomLeft.y = (int) (topLeft.y +(double)length*COS);
822        }
823      public void translateTop(GridCell neighbor){
824         	if (neighbor!=null) {
825  	    topLeft.x=neighbor.topRight.x;
826  	    topLeft.y=neighbor.topRight.y;
827  	}
828  
829  	topRight.x =topLeft.x +length;
830  	topRight.y =topLeft.y;
831        }
832      public void translateLeft(GridCell neighbor){
833         	if (neighbor!=null) {
834  	   topLeft.x=neighbor.bottomLeft.x;
835  	   topLeft.y=neighbor.bottomLeft.y;
836  	}
837  
838  	bottomLeft.x =topLeft.x ;
839  	bottomLeft.y =topLeft.y +length;
840        }
841  
842      public void finish(GridCell below,GridCell right, GridCell corner){
843  	bottomRight.x= bottomLeft.x + (topRight.x-topLeft.x);
844  	bottomRight.y= bottomLeft.y + (topRight.y-topLeft.y);
845  
846  	if ( below != null ) {
847  	    below.topRight.x = this.bottomRight.x;
848  	    below.topRight.y = this.bottomRight.y;
849  	}
850  	if ( right != null ){
851  	    right.bottomLeft.x = this.bottomRight.x;
852  	    right.bottomLeft.y = this.bottomRight.y;
853  	}
854  
855  	if ( corner != null ) {
856  	    corner.topLeft.x= this.bottomRight.x;
857  	    corner.topLeft.y= this.bottomRight.y;
858  	}
859  
860  	centery += bottomRight.y+bottomLeft.y+topRight.y +topLeft.y;
861  
862  
863        }
864      public void shift(){
865  	topLeft.y += deltay;
866  	bottomLeft.y += deltay;
867  	bottomRight.y += deltay;
868  	topRight.y += deltay;
869      }
870      public void findShifting(int originy,int n )  // how many cells
871       {
872  	 centery =centery/( 4*n);
873  	 deltay=originy-centery;
874      }
875      public Polygon myframe()
876      {
877  	Polygon frame=new Polygon();
878  	frame.addPoint(topLeft.x,topLeft.y);
879  	frame.addPoint(bottomLeft.x,bottomLeft.y);
880  	frame.addPoint(bottomRight.x,bottomRight.y);
881  	frame.addPoint(topRight.x,topRight.y);
882  	frame.addPoint(topLeft.x,topLeft.y);
883  	return frame;
884      }
885  
886  
887  
888      public void paint(Graphics g) {
889        Polygon frame=myframe();
890  
891  	if(rigid) {
892  	  if (rigidType==BRICK) {
893  	    //g.setColor(Color.red);
894  	    /// g.fillPolygon(frame);
895  	    //BrickMe(g);
896  	    BraceMeFromRight(g);
897  	    BraceMeFromLeft(g);
898  	  }
899  	  else if(rigidType==LEFT_BRACE)
900  	    BraceMeFromLeft(g);
901  	  else BraceMeFromRight(g);
902  	} else {
903  	  g.setColor(Color.lightGray);
904  	  g.fillPolygon(frame);
905  	}
906  	g.setColor(Color.black);
907  	g.drawPolygon(frame);
908        }
909      public void BraceMeFromLeft(Graphics g){
910        int[] x=new int[4];
911        int[] y=new int[4];
912        g.setColor(Color.black);
913        g.drawLine(topLeft.x,topLeft.y,bottomRight.x,bottomRight.y);
914        double longDiagonal=Math.sqrt( (topLeft.x- bottomRight.x) *  (topLeft.x-bottomRight.x) +
915                                     (topLeft.y- bottomRight.y)*(topLeft.y-bottomRight.y));
916        double rate=1.0 - (double)(diagonal)*.90/(double)longDiagonal ;
917        rate/=2.0;
918  
919        if (rate < 0.0) rate=0.0;
920  
921  
922        int x1= (int)  (topLeft.x +(-topLeft.x+ bottomRight.x)*rate);
923        int y1= (int)  (topLeft.y + (-topLeft.y+ bottomRight.y)*rate);
924        int x2= (int)  (bottomRight.x +  ( topLeft.x- bottomRight.x)*rate);
925        int y2= (int)  (bottomRight.y +  ( topLeft.y-bottomRight.y)*rate);
926        g.setColor(Color.yellow);
927        x[0]=x1+2; y[0]=y1;
928        x[1]=x2; y[1]=y2-3;
929        x[2]=x2-2; y[2]=y2;
930        x[3]=x1; y[3]=y1+3;
931        g.fillPolygon(x,y,4);
932        //      g.drawLine(x1,y1,x2,y2);
933  //      g.drawLine(x1+1,y1,x2+1,y2);g.drawLine(x1,y1+1,x2,y2+1);
934  
935      }
936      public void BraceMeFromRight(Graphics g){
937  	int[] x=new int[4];
938  	int[] y=new int[4];
939  
940  	g.setColor(Color.black);
941  	g.drawLine(topRight.x,topRight.y,bottomLeft.x,bottomLeft.y);
942  
943  	double longDiagonal=Math.sqrt( (bottomLeft.x- topRight.x) *  (bottomLeft.x-topRight.x) +
944                                        (bottomLeft.y- topRight.y)*(bottomLeft.y-topRight.y));
945  	double rate=1.0 - (double)diagonal*.90/(double)longDiagonal ;
946  	rate/=2.0;
947  	if (rate < 0.0) rate=0.0;
948  	int x1= (int)  (bottomLeft.x +(-bottomLeft.x+ topRight.x)*rate);
949  	int y1= (int)   (bottomLeft.y + (-bottomLeft.y+ topRight.y)*rate);
950  	int x2= (int)  (topRight.x +  ( bottomLeft.x- topRight.x)*rate);
951  	int y2=  (int)  (topRight.y +  ( bottomLeft.y-topRight.y)*rate);
952  	x[0]=x1+3; y[0]=y1;
953  	x[1]=x2; y[1]=y2+3;
954  	x[2]=x2-2; y[2]=y2;
955  	x[3]=x1; y[3]=y1-2;
956  
957  	g.setColor(Color.cyan);
958  	g.fillPolygon(x,y,4);
959  
960  /*      g.drawLine(x1,y1,x2,y2);
961        g.drawLine(x1+1,y1,x2+1,y2);g.drawLine(x1,y1+1,x2,y2+1);
962        */
963      }
964      public void BrickMe(Graphics g){
965       
966      g.setColor(Color.black);
967  
968      Point topMid = new Point((topRight.x+topLeft.x)/2,(topRight.y+topLeft.y)/2);
969      Point bottomMid = new Point((bottomRight.x+bottomLeft.x)/2,(bottomRight.y+bottomLeft.y)/2);
970      Point leftMid = new Point((topLeft.x+bottomLeft.x)/2,(bottomLeft.y+topLeft.y)/2);
971      Point rightMid = new Point((bottomRight.x+topRight.x)/2,(bottomRight.y+topRight.y)/2);
972      Point mid =new Point((leftMid.x+rightMid.x)/2, (rightMid.y+leftMid.y)/2);
973  
974      Point closeTopLeft = new Point((topLeft.x+leftMid.x)/2,(topLeft.y+leftMid.y)/2);
975      Point closeBottomLeft = new Point((leftMid.x+bottomLeft.x)/2,(leftMid.y+bottomLeft.y)/2);
976      Point closeTopRight = new Point((topRight.x+rightMid.x)/2,(topRight.y+rightMid.y)/2);
977      Point closeBottomRight = new Point((rightMid.x+bottomRight.x)/2,(rightMid.y+bottomRight.y)/2);
978  
979      Point closeTopMid = new Point ( (closeTopLeft.x + closeTopRight.x)/2, (closeTopLeft.y + closeTopRight.y)/2);
980      Point closeBottomMid= new Point ( (closeBottomLeft.x + closeBottomRight.x)/2, (closeBottomLeft.y + closeBottomRight.y)/2);
981  
982      Point closeTopCloseLeft  = new Point( (closeTopLeft.x+closeTopMid.x)/2, (closeTopLeft.y+closeTopMid.y)/2);
983      Point closeTopCloseRight = new Point( (closeTopRight.x+closeTopMid.x)/2, (closeTopRight.y+closeTopMid.y)/2);
984      Point closeBottomCloseLeft = new Point( (closeBottomLeft.x+closeBottomMid.x)/2, (closeBottomLeft.y+closeBottomMid.y)/2);
985      Point closeBottomCloseRight = new Point( (closeBottomRight.x+closeBottomMid.x)/2, (closeBottomRight.y+closeBottomMid.y)/2);
986  
987      Point closeLeftMid =new Point ( (leftMid.x+mid.x)/2, (leftMid.y+mid.y)/2);
988      Point closeRightMid =new Point ( (rightMid.x+mid.x)/2, (rightMid.y+mid.y)/2);
989  
990      Point bottomCloseLeft = new Point ( (bottomLeft.x+bottomMid.x)/2 , (bottomLeft.y+bottomMid.y)/2);
991      Point bottomCloseRight= new Point ( (bottomRight.x+bottomMid.x)/2 , (bottomRight.y+bottomMid.y)/2);
992  
993      g.drawLine ( closeTopLeft.x,closeTopLeft.y,closeTopRight.x,closeTopRight.y);
994      g.drawLine ( closeBottomLeft.x,closeBottomLeft.y,closeBottomRight.x,closeBottomRight.y );
995      g.drawLine ( leftMid.x,leftMid.y,rightMid.x,rightMid.y);
996  
997      g.drawLine ( topMid.x,topMid.y,closeTopMid.x,closeTopMid.y );
998  
999      g.drawLine ( closeTopCloseLeft.x,closeTopCloseLeft.y,closeLeftMid.x,closeLeftMid.y );
1000      g.drawLine ( closeTopCloseRight.x,closeTopCloseRight.y,closeRightMid.x,closeRightMid.y );
1001  
1002      g.drawLine ( mid.x,mid.y,closeBottomMid.x,closeBottomMid.y);
1003  
1004      g.drawLine ( bottomCloseLeft.x,bottomCloseLeft.y,closeBottomCloseLeft.x,closeBottomCloseLeft.y );
1005      g.drawLine ( bottomCloseRight.x,bottomCloseRight.y,closeBottomCloseRight.x,closeBottomCloseRight.y );
1006  
1007    }
1008  } // cell ends here
1009    class Rotate
1010    {
1011      int id;
1012  
1013      int direction;
1014      boolean pozitif;
1015      boolean negatif;
1016  
1017      Rotate(int dir)
1018      {
1019        direction=dir;
1020        pozitif=false;
1021        negatif=false;
1022        
1023      }
1024    }
1025  
1026  //****************************************************************************
1027  // COMPONENT
1028  //****************************************************************************
1029  class GraphComponent {
1030      int color;
1031    int cmpcolor;
1032  
1033      int type=0;
1034      boolean rigid=false;
1035      Vector cells;
1036      public int ID;
1037      Rotate  rotation;
1038  
1039      public GraphComponent(int ID) {
1040  	this.ID = ID;
1041  	cells = new Vector();
1042        }
1043  
1044      public GraphComponent(GraphComponent gc) {
1045  	this.ID = gc.ID;
1046  	cells = new Vector();
1047  	for(Enumeration e=gc.getCells().elements(); e.hasMoreElements(); )
1048  	          addCell((GridCell)(e.nextElement()));
1049        }
1050  
1051      public void addCell(GridCell cell) {
1052  	cells.addElement(cell);
1053        }
1054  
1055      public void removeCell(GridCell cell) {
1056  	cells.removeElement(cell);
1057        }
1058  
1059      public Vector getCells() {
1060  	return cells;
1061        }
1062  
1063      public void listCells() {
1064  	for(Enumeration e=cells.elements(); e.hasMoreElements(); ) {
1065  	    GridCell cell=(GridCell)(e.nextElement());
1066  	    System.out.print("("+cell.rowIndex + "," + cell.colIndex + ")");
1067  	  }
1068  	System.out.println(" ");
1069        }
1070  
1071      public void merge(GraphComponent comp) {
1072  	if(comp.ID == this.ID) return;
1073  	if(comp.ID < this.ID) comp.merge(this);
1074  	else for(Enumeration e=comp.getCells().elements(); e.hasMoreElements(); )
1075  	          addCell((GridCell)(e.nextElement()));
1076        }
1077      public void print(String s) {
1078  	System.out.println(s);
1079  
1080        for(Enumeration e=getCells().elements(); e.hasMoreElements(); ){
1081  	GridCell cell =(GridCell)(e.nextElement());
1082  	int r=cell.rowIndex+1;
1083  	int c=cell.colIndex+1 ;
1084  	if(cell.leftBrace())
1085  	  System.out.println(c + " --> " + r);
1086  	else if (cell.rightBrace())
1087  	  System.out.println(c + " <-- " + r);
1088  	  else System.out.println("ERROR");
1089  
1090        }
1091      }
1092     public void setRowType() {type=0;   }
1093     public void setColType() {type=1;   }
1094     public boolean colType() {return type==1;}
1095     public boolean rowType() {return type==0;}
1096    }
1097  //****************************************************************************
1098  // selection buttons
1099  //****************************************************************************
1100  
1101  class choiceCanvas extends Canvas
1102  {
1103      GridCell[] cells;
1104      boolean[] selection;
1105      GridCanvas canvas;
1106      int length;
1107      choiceCanvas(GridCanvas canvas)
1108      {
1109  	cells=new GridCell[3];
1110          selection=new boolean[3];
1111  	this.canvas=canvas;
1112      }
1113      public void showUp()
1114      {
1115  	int width = size().width ;
1116  	int height = size().height ;
1117  
1118  //	height=width=20;
1119  	length = Math.min( width, height);
1120  	//System.out.println(width + " showup  "+height);
1121  
1122  
1123  	for(int n=0; n<3; n++) {
1124  	    cells[n] = new GridCell(n * length,
1125  				    0 ,
1126  				    length, 0, n );
1127  	    cells[n].toggleRigid(n);
1128  	    selection[n]=false;
1129  	}
1130  	selection[0]=true;
1131  	canvas.setCellMode(0);
1132  	repaint();
1133      }
1134  
1135  
1136      public void update(Graphics g) {
1137  	paint(g);
1138        }
1139  
1140      public void paint(Graphics g) {
1141  	g.clearRect(0,0,size().width,size().height);
1142    
1143  
1144  	for(int n=0; n<3; n++) {
1145  	    cells[n].paint(g);
1146  	    //if(selection[n]) {
1147  		g.setColor(Color.white);
1148  		g.draw3DRect(cells[n].topLeft.x+2,cells[n].topLeft.y+2,
1149  			     length-4,length-4,!selection[n]);
1150  		g.draw3DRect(cells[n].topLeft.x+1,cells[n].topLeft.y+1,
1151  			     length-2,length-2,!selection[n]);
1152  	    // }
1153  
1154  
1155  	}
1156      }
1157  
1158      public boolean mouseDown(Event evt, int x, int y) {
1159  	for (int j=0;j<3;j++)
1160  	    if ( cells[j].myframe().inside(x,y)) {
1161  		selection[j]=true;
1162  		canvas.setCellMode(j);
1163  	    }  else selection[j]=false;
1164  	Graphics g=getGraphics();
1165  	paint(g);
1166  	g.dispose();
1167  	return true;
1168      }
1169  }
1170