checkpoint
[slipway.git] / src / edu / berkeley / obits / gui / Gui.java
1 package edu.berkeley.obits.gui;
2
3 import static edu.berkeley.obits.device.atmel.AtmelDevice.Constants.*;
4 import static edu.berkeley.obits.device.atmel.AtmelDevice.Util.*;
5 import edu.berkeley.obits.*;
6 import edu.berkeley.obits.device.atmel.*;
7 import java.awt.*;
8 import java.awt.geom.*;
9 import java.awt.event.*;
10 import java.awt.color.*;
11 import org.ibex.util.*;
12 import java.io.*;
13 import java.util.*;
14 import javax.swing.*;
15
16 public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListener {
17
18     Graphics2D g;
19     G gg;
20
21     public static int SIZE = 92;
22     public static int RINGS = 3;
23     public static int BEVEL = 5;
24     public static int CORE_SIZE = 64;
25     public static int CORE_OFFSET = 10;
26     public static int HOFF = 52;
27
28     public static int RED  = 0xff0000;
29     public static int BLUE = 0x0000ff;
30
31     public static final P YLUT_OUTPUT_POINT  = new P(SIZE-CORE_OFFSET-CORE_SIZE+51 - 2, CORE_OFFSET + 41 - 3);
32     public static final P XLUT_OUTPUT_POINT  = new P(SIZE-CORE_OFFSET-CORE_SIZE+17 - 2, CORE_OFFSET + 41 - 3);
33
34     At40k at40k;
35
36     private HashSet<Cell> cells = new HashSet<Cell>();
37     private Cell[][] ca = new Cell[128][];
38
39     public static final Color nonselectedcell = new Color(0xcc, 0xcc, 0xcc);
40     public static final Color selectedcell = new Color(0x44, 0x44, 0xff);
41
42     public Gui(At40k at40k) {
43         this.at40k = at40k;
44         for(int i=0; i<ca.length; i++)
45             ca[i] = new Cell[128];
46         for(int x=0; x<7; x++)
47             for(int y=0; y<7; y++)
48                 new Cell(x,y, at40k.cell(x+7, y+7));
49     }
50     
51
52     public class Cell {
53         At40k.Cell cell;
54         boolean in = false;
55         int _x, _y;
56         public Cell(int x, int y, At40k.Cell cell) {
57             _x = x;
58             _y = y;
59             ca[_x][_y] = this;
60             this.cell = cell;
61             cells.add(this);
62         }
63         public void draw() {
64             gg.color(in ? selectedcell : nonselectedcell);
65             g.fillRect(0, 0, SIZE, SIZE);
66
67             drawHwires();
68             drawVwires();
69             drawLocal();
70
71             AffineTransform t = g.getTransform();
72             g.transform(rotateInnerTransform());
73             drawMux();
74             drawRegister();
75             drawInternalRouting();
76             drawBuffer();
77             g.setTransform(t);
78
79             drawGates();
80             drawBorder();
81         }
82         public void drawBuffer() {
83             if (!cell.out_relevant()) return;
84             gg.color(Color.black);
85             gg.line(21, 64, 28, 60);
86             gg.line(21, 64, 28, 68);
87             gg.line(28, 60, 28, 68);
88
89             gg.color(Color.magenta);
90             if (cell.oe() == V4) {
91                 gg.line(16, 53, 25, 53);
92                 gg.line(25, 53, 25, 62);
93             } else if (cell.oe() == H4) {
94                 gg.line(25, 76, 25, 67);
95             }
96             
97         }
98         public void drawHwires() {
99             gg.color(Color.magenta);
100             for(int i=0; i<5; i++)
101                 if (cell.hwire(i).isDriven())
102                     gg.line(0, SIZE-(2*(1+RINGS)+2*i), SIZE, SIZE-(2*(1+RINGS)+2*i));
103             int plane = cell.zi();
104             if (plane >= L0 && plane <= L4 && cell.hx(plane)) {
105                 P p1 = new P(38, 18);
106                 p1 = rotateInner(p1);
107                 if (cell.zi_to_xlut_relevant() && cell.xlut_relevant())
108                     route(new P(84, 84 - 2*(plane-L0)), p1, 3);
109                 p1 = new P(64, 18);
110                 p1 = rotateInner(p1);
111                 if (cell.zi_to_ylut_relevant() && cell.ylut_relevant())
112                     route(new P(84, 84 - 2*(plane-L0)), p1, 3);
113             }
114             plane = cell.wi();
115             if (plane >= L0 && plane <= L4 && cell.hx(plane)) {
116                 P p1 = new P(38, 18);
117                 p1 = rotateInner(p1);
118                 if (cell.zi_to_xlut_relevant() && cell.xlut_relevant())
119                     route(new P(84, 84 - 2*(plane-L0)), p1, 3);
120                 p1 = rotateInner(new P(64, 18));
121                 if (cell.zi_to_ylut_relevant() && cell.ylut_relevant())
122                     route(new P(84, 84 - 2*(plane-L0)), p1, 3);
123             }
124         }
125         public void drawVwires() {
126             gg.color(Color.magenta);
127             for(int i=0; i<5; i++)
128                 if (cell.vwire(i).isDriven())
129                     gg.line(2*(1+RINGS)+2*i, 0, 2*(1+RINGS)+2*i, SIZE);
130             int plane = cell.zi();
131             if (plane >= L0 && plane <= L4 && cell.vx(plane)) {
132                 P p1 = new P(38, 18);
133                 p1 = rotateInner(p1);
134                 if (cell.zi_to_xlut_relevant() && cell.xlut_relevant())
135                     route(new P(17 - 2*(plane-L0), 8), p1, 3);
136                 p1 = new P(64, 18);
137                 p1 = rotateInner(p1);
138                 if (cell.zi_to_ylut_relevant() && cell.ylut_relevant())
139                     route(new P(17 - 2*(plane-L0), 8), p1, 3);
140             }
141             plane = cell.wi();
142             if (plane >= L0 && plane <= L4 && cell.vx(plane)) {
143                 P p1 = new P(38, 18);
144                 p1 = rotateInner(p1);
145                 if (cell.zi_to_xlut_relevant() && cell.xlut_relevant())
146                     route(new P(17 - 2*(plane-L0), 8), p1, 3);
147                 p1 = new P(64, 18);
148                 p1 = rotateInner(p1);
149                 if (cell.zi_to_ylut_relevant() && cell.ylut_relevant())
150                     route(new P(17 - 2*(plane-L0), 8), p1, 3);
151             }
152         }
153         public void drawInternalRouting() {
154             gg.color(new Color(0, 107, 51));
155             if (cell.fb_relevant()) {
156                 if (cell.f()) {
157                     gg.line(51, 74, 37, 74);
158                     gg.line(37, 74, 50, 12);
159                 } else if (cell.c() == XLUT) {
160                     gg.line(32, 52, 50, 52);
161                     gg.line(50, 52, 50, 12);
162                 } else if (cell.c() == YLUT) {
163                     gg.line(68, 52, 50, 52);
164                     gg.line(50, 52, 50, 12);
165                 } else {
166                     gg.line(50, 56, 41, 56);
167                     gg.line(41, 56, 50, 12);
168                 }
169                 if (cell.xlut_relevant()) {
170                     gg.line(52, 12, XLUT_OUTPUT_POINT.getX(), 12);
171                     gg.line(XLUT_OUTPUT_POINT.getX(), 12, XLUT_OUTPUT_POINT.getX(), 32);
172                 }
173                 if (cell.ylut_relevant()) {
174                     gg.line(52, 12, YLUT_OUTPUT_POINT.getX(), 12);
175                     gg.line(YLUT_OUTPUT_POINT.getX(), 12, YLUT_OUTPUT_POINT.getX(), 32);
176                 }
177             }
178         }
179
180         public void drawLocal() {
181             if (!cell.ylut_relevant() && !cell.xlut_relevant()) return;
182             P in   = new P(HOFF, 0);
183             P join = new P(HOFF, CORE_OFFSET);
184             in = rotateOuter(in);
185             join = rotateInner(join);
186             int rot = rot();
187             switch(rot) {
188                 case 0: case 2:
189                     join = new P(in.getX(), join.getY());
190                     break;
191                 case 1: case 3:
192                     join = new P(join.getX(), in.getY());
193                     break;
194             }
195
196             P xi  = null;
197             P xi2 = null;
198             gg.color(new Color(0xff, 0x00, 0x00));
199             int xring = 4;
200             if (cell.xi_relevant() && cell.xlut_relevant())
201                 switch(cell.xi()) {
202                     case NW:
203                         xi = new P(0+2*xring, SIZE-2*xring);
204                         xi2 = new P(-BEVEL, SIZE+BEVEL);
205                         xi = translate(xi, 0, -3);
206                         xi2 = translate(xi2, 0, -3);
207                         gg.line(xi2, xi);
208                         break;
209                         
210                     case SW:
211                         xi = new P(0+2*xring, 0+2*xring);
212                         xi2 = new P(-BEVEL, -BEVEL);
213                         xi = translate(xi, 0, 3);
214                         xi2 = translate(xi2, 0, 3);
215                         gg.line(xi2, xi);
216                         break;
217                         
218                     case NE:
219                         xi = new P(SIZE-2*xring, SIZE-2*xring);
220                         xi2 = new P(SIZE+BEVEL, SIZE+BEVEL);
221                         xi = translate(xi, 0, -3);
222                         xi2 = translate(xi2, 0, -3);
223                         gg.line(xi2, xi);
224                         break;
225                         
226                     case SE:
227                         xi = new P(SIZE-2*xring, 0+2*xring);
228                         xi2 = new P(SIZE+BEVEL, -BEVEL);
229                         xi = translate(xi, 0, 3);
230                         xi2 = translate(xi2, 0, 3);
231                         gg.line(xi2, xi);
232                         break;
233                 }
234
235             if (cell.xlut_relevant()) {
236                 P c;
237                 gg.color(BLUE);
238                 if (cell.yi_to_xlut_relevant())
239                     route(in, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 6, 20)), 5);
240
241                 gg.color(RED);
242                 if (cell.xi_to_xlut_relevant() && xi != null)
243                     route(xi, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 3, 20)), 4);
244
245                 P xo   = XLUT_OUTPUT_POINT;
246                 P xout = new P(SIZE-CORE_OFFSET-CORE_SIZE+17 - 2, CORE_OFFSET + CORE_SIZE - 3);
247                 xo = rotateInner(xo);
248                 xout = rotateInner(xout);
249                 gg.color(new Color(0xff, 0xcc, 0xcc));
250                 xring = 6;
251                 if (cell.ne() != null && cell.ne().xi()==SW && cell.ne().xi_relevant() && cell.ne().xlut_relevant()) {
252                     gg.line(xo, xout);
253                     P xoo = new P(SIZE-2*xring, SIZE-2*xring);
254                     P xoo2 = new P(SIZE, SIZE);
255                     xoo = translate(xoo, -3, 0);
256                     xoo2 = translate(xoo2, -3, 0);
257                     gg.line(xoo2, xoo);
258                     route(xout, xoo, xring);
259                 }
260                 if (cell.nw() != null && cell.nw().xi()==SE && cell.nw().xi_relevant() && cell.nw().xlut_relevant()) {
261                     gg.line(xo, xout);
262                     P xoo = new P(0+2*xring, SIZE-2*xring);
263                     P xoo2 = new P(0, SIZE);
264                     xoo = translate(xoo, 3, 0);
265                     xoo2 = translate(xoo2, 3, 0);
266                     gg.line(xoo2, xoo);
267                     route(xout, xoo, xring);
268                 }
269                 if (cell.se() != null && cell.se().xi()==NW && cell.se().xi_relevant() && cell.se().xlut_relevant()) {
270                     gg.line(xo, xout);
271                     P xoo = new P(SIZE-2*xring, 0+2*xring);
272                     P xoo2 = new P(SIZE, 0);
273                     xoo = translate(xoo, -3, 0);
274                     xoo2 = translate(xoo2, -3, 0);
275                     gg.line(xoo2, xoo);
276                     route(xout, xoo, xring);
277                 }
278                 if (cell.sw() != null && cell.sw().xi()==NE && cell.sw().xi_relevant() && cell.sw().xlut_relevant()) {
279                     gg.line(xo, xout);
280                     P xoo = new P(0+2*xring, 0+2*xring);
281                     P xoo2 = new P(0, 0);
282                     xoo = translate(xoo, 3, 0);
283                     xoo2 = translate(xoo2, 3, 0);
284                     gg.line(xoo2, xoo);
285                     route(xout, xoo, xring);
286                 }
287             }
288
289             if (cell.ylut_relevant()) {
290                 gg.color(new Color(0x00, 0x00, 0xff));
291                 P c;
292                 if (cell.yi_to_ylut_relevant()) {
293                     c   = new P(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 6, 20);
294                     c = rotateInner(c);
295                     route(in, c, 5);
296                 }
297                 gg.color(new Color(0xff, 0x00, 0x00));
298                 if (cell.xi_to_ylut_relevant()) {
299                     c = rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 3, 20));
300                     if (xi != null)
301                         route(xi, c, 4);
302                 }
303
304                 P yo   = rotateInner(YLUT_OUTPUT_POINT);
305                 P yout = rotateInner(new P(SIZE-CORE_OFFSET-CORE_SIZE+51 - 2, CORE_OFFSET + CORE_SIZE - 3));
306                 gg.color(0xbbbbff);
307                 if (cell.north() != null && cell.north().yi()==SOUTH && cell.north().yi_relevant() && cell.north().ylut_relevant()) {
308                     gg.line(yo, yout);
309                     route(yout, new P(SIZE-40, SIZE+ 0), 2);
310                 }
311                 if (cell.east() != null  && cell.east().yi()==WEST && cell.east().yi_relevant() && cell.east().ylut_relevant()) {
312                     gg.line(yo, yout);
313                     route(yout, new P(SIZE+ 0,      40), 2);
314                 }
315                 if (cell.south() != null && cell.south().yi()==NORTH && cell.south().yi_relevant() && cell.south().ylut_relevant()) {
316                     gg.line(yo, yout);
317                     route(yout, new P(     40,       0), 2);
318                 }
319                 if (cell.west() != null  && cell.west().yi()==EAST && cell.west().yi_relevant() && cell.west().ylut_relevant()) {
320                     gg.line(yo, yout);
321                     route(yout, new P(      0, SIZE-40), 2);
322                 }
323             }
324
325         }
326
327
328         private AffineTransform rotateOuterTransform() {
329             int rot = rot();
330             AffineTransform a = new AffineTransform();
331             a.rotate((Math.PI/2) * rot);
332             switch(rot) {
333                 case 0: break;
334                 case 1: a.translate(0,  -SIZE); break;
335                 case 2: a.translate(-SIZE, -SIZE); break;
336                 case 3: a.translate(-SIZE, 0); break;
337             }
338             return a;
339         }
340
341         private P rotateOuter(P p) { return p.transform(rotateOuterTransform()); }
342         private P rotateInner(P p) { return p.transform(rotateInnerTransform()); }
343
344         private AffineTransform rotateInnerTransform() {
345             int rot = rot();            
346             AffineTransform a = new AffineTransform();
347             a.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET);
348             a.rotate((Math.PI/2) * rot);
349             switch(rot) {
350                 case 0: break;
351                 case 1: a.translate(0,  -CORE_SIZE); break;
352                 case 2: a.translate(-CORE_SIZE, -CORE_SIZE); break;
353                 case 3: a.translate(-CORE_SIZE, 0); break;
354             }
355             a.translate(-1 * (SIZE-CORE_SIZE-CORE_OFFSET), -CORE_OFFSET);
356             return a;
357         }
358
359
360         private P project(P p1, int ring) {
361             double north = Math.abs( (SIZE-(ring*2)) - p1.getY() );
362             double south = Math.abs( (     (ring*2)) - p1.getY() );
363             double east  = Math.abs( (SIZE-(ring*2)) - p1.getX() );
364             double west  = Math.abs( (     (ring*2)) - p1.getX() );
365             if (north < south && north < east && north < west) return new P(p1.x,        SIZE-ring*2);
366             else if (south < east && south < west)             return new P(p1.x,        ring*2);
367             else if (east < west)                              return new P(SIZE-ring*2, p1.y);
368             else                                               return new P(ring*2,      p1.y);
369
370         }
371
372         private void route(P p1, P p2, int ring) {
373             int ringpos = ring * 2;
374             P projected = project(p1, ring);
375             gg.line(p1, projected);
376             p1 = projected;
377
378             projected = project(p2, ring);
379             gg.line(p2, projected);
380             p2 = projected;
381
382             double x1 = p1.getX();
383             double y1 = p1.getY();
384             double x2 = p2.getX();
385             double y2 = p2.getY();
386
387             if (x1==x2 || y1==y2) {
388                 gg.line(p1, p2);
389                 return;
390             }
391
392             if ((x1==SIZE-ring*2 || x1==ring*2) && !(y1==SIZE-ring*2 || y1==ring*2)) {
393                 P p3 = new P(x1, y2 > SIZE/2 ? SIZE-ring*2 : ring*2);
394                 gg.line(p1, p3);
395                 route(p3, p2, ring);
396             } else if ((y1==SIZE-ring*2 || y1==ring*2) && !(x1==SIZE-ring*2 || x1==ring*2)) {
397                 P p3 = new P(x2 > SIZE/2 ? SIZE-ring*2 : ring*2, y1);
398                 gg.line(p1, p3);
399                 route(p3, p2, ring);
400             } else
401                 route(p2, p1, ring);
402
403         }
404         
405         private int rot() {
406             int rot = 0;
407             switch(cell.yi()) {
408                 case SOUTH: rot = 0; break;
409                 case NORTH: rot = 2; break;
410                 case EAST: rot = 1; break;
411                 case WEST: rot = 3; break;
412                 default: {
413                     // FIXME: choose based on xin
414                     if (cell.north() != null && cell.north().yi()==SOUTH) { rot = 0; break; }
415                     if (cell.south() != null && cell.south().yi()==NORTH) { rot = 2; break; }
416                     if (cell.east()  != null && cell.east().yi()==WEST) { rot = 3; break; }
417                     if (cell.west()  != null && cell.west().yi()==EAST) { rot = 1; break; }
418                 }
419             }
420             return rot;
421         }
422         
423         public void drawGates() {
424             AffineTransform t = g.getTransform();
425             try {
426                 g.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET);
427                 
428                 int rot = rot();
429                 g.rotate((Math.PI/2) * rot);
430                 switch(rot) {
431                     case 0: break;
432                     case 1: g.translate(0,  -CORE_SIZE); break;
433                     case 2: g.translate(-CORE_SIZE, -CORE_SIZE); break;
434                     case 3: g.translate(-CORE_SIZE, 0); break;
435                 }
436
437                 //gg.color(Color.gray);
438                 //g.drawRect(0, 0, CORE_SIZE, CORE_SIZE);
439                 g.scale(1, -1);
440
441                 GeneralPath p = new GeneralPath();
442                 p.moveTo(29.141f, 36.301f);
443                 p.lineTo(29.141f, 36.301f-7.161f);
444                 p.curveTo(27.71f, 11.24f, 23.413f, 9.45f, 14.82f, 0.5f);
445                 p.curveTo(6.229f, 9.45f, 1.932f, 11.24f, 0.5f, 29.141f);
446                 p.lineTo(0.5f, 29.141f+7.161f);
447                 float x = 0.5f;
448                 float y = 29.141f+7.161f;
449                 p.curveTo(5.729f+x, -1.789f+y,
450                           6.444f+x, -2.686f+y,
451                           14.32f+x, -3.58f+y);
452                 p.curveTo(22.697f, 33.616f, 23.413f, 34.512f, 29.141f, 36.301f);
453                 g.translate(0,   -40f);
454                 if (cell.xlut_relevant()) {
455                     gg.color(Color.white);
456                     g.fill(p);
457                     gg.color(Color.red);
458                     g.draw(p);
459                 }
460                 g.translate(34f, 0f);
461                 if (cell.ylut_relevant()) {
462                     gg.color(Color.white);
463                     g.fill(p);
464                     gg.color(Color.blue);
465                     g.draw(p);
466                 }
467             } finally {
468                 g.setTransform(t);
469             }
470         }
471         public void drawMux() {
472             if (!cell.c_relevant()) return;
473             gg.color(Color.black);
474             if (cell.xlut_relevant() && (cell.c() == ZMUX || cell.c() == XLUT)) {
475                 gg.color(new Color(0xff, 0xbb, 0xbb));
476                 gg.line(XLUT_OUTPUT_POINT, new P(XLUT_OUTPUT_POINT.getX(), 52));
477                 gg.line(new P(XLUT_OUTPUT_POINT.getX(), 52), new P(51, 52));
478             }
479             if (cell.ylut_relevant() && (cell.c() == ZMUX || cell.c() == YLUT)) {
480                 gg.color(new Color(0xbb, 0xbb, 0xff));
481                 gg.line(YLUT_OUTPUT_POINT, new P(YLUT_OUTPUT_POINT.getX(), 52));
482                 gg.line(new P(YLUT_OUTPUT_POINT.getX(), 52), new P(51, 52));
483             }
484             gg.line(51, 52, 51, 51+25);
485             if (cell.c() == ZMUX) {
486                 gg.color(Color.black);
487                 gg.line(51, 52, 51, 51+25);
488                 gg.line(46, 54,     46+2, 54+5);
489                 gg.line(46+2, 54+5, 60-2, 54+5);
490                 gg.line(60-2, 54+5, 60,   54);
491                 gg.line(60,   54,   46, 54);
492             }
493         }
494         public void drawRegister() {
495             if (!cell.register_relevant()) return;
496             gg.color(Color.white);
497             g.fillRect(48, 58, 10, 14);
498             gg.color(Color.black);
499             g.drawRect(48, 58, 10, 14);
500             gg.line(57, 70, 54, 68);
501             gg.line(54, 68, 57, 66);
502         }
503         public void drawBorder() {
504             gg.color(Color.gray);
505             //gg.line(0, BEVEL, BEVEL,    0);
506             gg.line(BEVEL, 0, SIZE-BEVEL, 0);
507             //gg.line(SIZE-BEVEL, 0, SIZE, BEVEL);
508             gg.line(SIZE, BEVEL, SIZE, SIZE-BEVEL);
509             //gg.line(SIZE, SIZE-BEVEL, SIZE-BEVEL, SIZE);
510             gg.line(SIZE-BEVEL, SIZE, BEVEL, SIZE);
511             //gg.line(BEVEL, SIZE, 0, SIZE-BEVEL);
512             gg.line(0, SIZE-BEVEL, 0, BEVEL);
513         }
514     }
515
516     public void _paint(Graphics2D g) {
517
518         this.g = g;
519         this.gg = new G(g);
520         g.setStroke(new BasicStroke((float)0.5));
521
522         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
523         g.setRenderingHint(RenderingHints.KEY_RENDERING,    RenderingHints.VALUE_RENDER_QUALITY);
524
525         AffineTransform t  = g.getTransform();
526         for(Cell c : cells) {
527             g.setTransform(t);
528             g.translate(     c._x * SIZE/* + (10 * (c._x/4))*/,      c._y * SIZE/* + (10 * (c._y/4))*/);
529             c.draw();
530         }
531         g.setTransform(t);
532
533         g.setTransform(new AffineTransform());
534
535         gg.color(selectedcell);
536         g.fillRect(getWidth() - 200, 0, 200, 100);
537         gg.color(Color.white);
538         g.drawRect(getWidth() - 200, 0, 200, 100);
539
540         Cell newcell = whichCell(mousex, mousey);
541         int line = 10;
542         if (newcell != null && newcell.cell != null) {
543             g.drawString("selected: " + newcell._x + ","+newcell._y,
544                          getWidth() - 200 + 10, (line += 15));
545             g.drawString("    xlut: " + AtmelSerial.bin8(newcell.cell.xlut()),
546                          getWidth() - 200 + 10, (line += 15));
547             g.drawString("    ylut: " + AtmelSerial.bin8(newcell.cell.ylut()),
548                          getWidth() - 200 + 10, (line += 15));
549             String xi = "??";
550             switch(newcell.cell.xi()) {
551                 case NW : xi = "NW"; break;
552                 case NE : xi = "NE"; break;
553                 case SW : xi = "SW"; break;
554                 case SE : xi = "SE"; break;
555             }
556             g.drawString("      xi: " + xi, getWidth() - 200 + 10, (line += 15));
557             String yi = "??";
558             switch(newcell.cell.yi()) {
559                 case NORTH : yi = "NORTH"; break;
560                 case SOUTH : yi = "SOUTH"; break;
561                 case EAST  : yi = "EAST"; break;
562                 case WEST  : yi = "WEST"; break;
563             }
564             g.drawString("      yi: " + yi, getWidth() - 200 + 10, (line += 15));
565         }
566         this.g = null;
567         this.gg = null;
568     }
569
570
571     public void clear() {
572         Graphics2D g = (Graphics2D)getGraphics();
573         //gg.color(Color.black);
574         //gg.color(Color.lightGray);
575         g.clearRect(0, 0, getWidth(), getHeight());
576     }
577
578     public static final P translate(P p, int dx, int dy) {
579         return new P(p.getX()+dx, p.getY()+dy);
580     }
581
582     public Cell whichCell(int x, int y) {
583         P p = new P(x,y);
584         try {
585             p = p.inverseTransform(transform);
586         } catch (Exception e) {
587             e.printStackTrace();
588         }
589         int col = ((int)p.getX()) / (SIZE + BEVEL);
590         int row = ((int)p.getY()) / (SIZE + BEVEL);
591         for(Cell c : cells)
592             if (c._x == col && c._y == row)
593                 return c;
594         return null;
595     }
596 }