remove two menus, get app to quit when window closes
[anneal.git] / src / edu / berkeley / qfat / Main.java
1 package edu.berkeley.qfat;
2 import java.awt.*;
3 import java.io.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6 import javax.media.opengl.*;
7 import javax.media.opengl.glu.*;
8 import java.util.*;
9 import edu.berkeley.qfat.bind.*;
10 import edu.berkeley.qfat.geom.*;
11 import edu.berkeley.qfat.stl.*;
12 import edu.berkeley.qfat.geom.Point;
13 import edu.berkeley.qfat.geom.Polygon;
14
15 /*
16
17
18 Todo
19 - review catmull-clark; move vertex points?
20 - re-anneal fish
21
22 - show constraints (?)
23 - show in red if user tries to move a point to an illegal location
24
25 - eliminate use of bindinggroupschanged()
26
27 - post qfat on my software page
28
29
30 With Sequin
31 - constraints admit intersections (lattice)
32 - constraints may be transformed linearly
33
34
35
36
37 Log console
38   - blend-shaded overlay?  slick.
39
40 face/vertex count
41 rendering FPS
42 ability to not draw edges between faces
43
44
45 three circumcircles showing crystal ball -- these don't get scaled
46 axes?
47
48 drawing modes:
49   - bounding box
50   - vertices
51   - edges
52   - visible-edges
53   - flat with or without edges
54   - shaded with or without edges
55   * contrasting-faces
56
57
58 quadric decimation?
59
60 show normals
61 show bounding box
62 show axes (big+fat)
63  */
64
65 // TO DO:
66 //
67 // - Ability to snap three views to orthgonal
68 // - SLIDE UI
69 //     - left button -> crystal ball
70 //     - translate
71 //     - rightbutton/mousewheel zoom
72 // - v+click to select vertex
73 // - show: constraints, bindings, faces
74 //
75 // Editing:
76 //  - fracture edge, face
77 //  - change aspect ratio
78 //  - translate, rotate goal mesh
79 //  - ability to select a point, rotate the model, then move the point
80 //  - when moving a vertex in one window, show that window's axes in all other windows
81 //
82
83 /*
84   blender keys
85   - middle mouse = option+click
86   - right mouse = command+click
87
88   3,7,1 = view along axes (control for opp direction)
89   4, 8, 7, 2 = rotate in discrete increments (+control to translate)
90   middle trag: rotate space
91   shift+middle drag: translate space
92   wheel: zoom
93   home: home view: take current angle, zoom to whole scnee
94   5 = ortho vs non-ortho
95 */
96
97 /*
98 Meshlab Notes:
99 Log console
100   - blend-shaded overlay?  slick.
101
102 face/vertex count
103 rendering FPS
104 ability to not draw edges between faces
105
106
107 three circumcircles showing crystal ball -- these don't get scaled
108 axes?
109
110 drawing modes:
111   - bounding box
112   - vertices
113   - edges
114   - visible-edges
115   - flat with or without edges
116   - shaded with or without edges
117   * contrasting-faces
118
119
120 quadric decimation?
121
122 show normals
123 show bounding box
124 show axes (big+fat)
125  */
126
127 public class Main extends InteractiveMeshViewer {
128
129     public static int verts = 1;
130
131     public static final Random random = new Random();
132     
133     /** magnification factor */
134     private static final float MAG = 1;
135     public static final float MATCHING_EPSILON = 0.001f;
136
137     private static boolean small(float f) { return Math.abs(f) < 0.001; }
138     public void generateTile(Matrix[] matrices, Mesh mesh) {
139         mesh.coalesce = true;
140         HashSet<HalfSpace> halfSpaces = new HashSet<HalfSpace>();
141         HashSet<Polygon> polygons = new HashSet<Polygon>();
142         for(Matrix m : matrices) {
143                 Vec v = m.getTranslationalComponent();
144                 if (v.mag() < 0.0001) continue;
145                 v = v.times(-1);
146                 v = v.times(0.5f);
147                 Point p = Point.ZERO.plus(v);
148                 v = v.times(-1);
149                 
150                 //System.out.println(v);
151                 HalfSpace hs = new HalfSpace(p, v.norm());
152                 halfSpaces.add(hs);
153                 polygons.add(new Polygon(hs));
154         }
155         for(Polygon p : polygons) {
156             System.out.println(p.plane.norm() + " " + p.plane.d);
157             for(HalfSpace hs : halfSpaces) {
158                 if (p.plane==hs) continue;
159                 p = p.intersect(hs);
160             }
161             p.tesselate(mesh);
162         }
163     }
164
165     private void quad(Mesh mesh, Matrix m, Point p1_, Point p2_, Point p3_, Point p4_) {
166         Point p1 = m.times(p1_);
167         Point p2 = m.times(p2_);
168         Point p3 = m.times(p3_);
169         Point p4 = m.times(p4_);
170         Point c  = new Point((p1.x+p2.x+p3.x+p4.x)/4,
171                              (p1.y+p2.y+p3.y+p4.y)/4,
172                              (p1.z+p2.z+p3.z+p4.z)/4);
173         mesh.newT(p1, p2, c, null, 0);
174         mesh.newT(p2, p3, c, null, 0);
175         mesh.newT(p3, p4, c, null, 0);
176         mesh.newT(p4, p1, c, null, 0);
177     }
178
179     public void loadGoal(String file) {
180         try {
181             StlFile stlf = new StlFile();
182             InputStream res = this.getClass().getClassLoader().getResourceAsStream(file);
183             stlf.readBinaryFile(file, res);
184             setGoal(new Mesh(false));
185             for(int i=0; i<stlf.coordArray.length; i+=3) {
186                 Point p0 = new Point(stlf.coordArray[i+0].x * MAG, stlf.coordArray[i+0].y * MAG, stlf.coordArray[i+0].z * MAG);
187                 Point p1 = new Point(stlf.coordArray[i+1].x * MAG, stlf.coordArray[i+1].y * MAG, stlf.coordArray[i+1].z * MAG);
188                 Point p2 = new Point(stlf.coordArray[i+2].x * MAG, stlf.coordArray[i+2].y * MAG, stlf.coordArray[i+2].z * MAG);
189                 Vec n    = new Vec(stlf.normArray[i/3].x * MAG, stlf.normArray[i/3].y  * MAG, stlf.normArray[i/3].z * MAG);
190                 Mesh.T t  = goal.newT(p0, p1, p2, n, 0);
191             }
192             float goal_width  = goal.diagonal().dot(new Vec(1, 0, 0));
193             float goal_height = goal.diagonal().dot(new Vec(0, 1, 0));
194             float goal_depth  = goal.diagonal().dot(new Vec(0, 0, 1));
195             
196         } catch (Exception e) { throw new RuntimeException(e);}
197     }
198     public void fixupGoal() { fixupGoal(true, true); }
199     public void fixupGoal(boolean recenter, boolean lock) {
200         // translate to match centroid
201         if (recenter)
202             goal.transform(Matrix.translate(tile.centroid().minus(goal.centroid())));
203         if (lock) {
204             goal.makeVerticesImmutable();
205             tile.error_against = goal;
206             goal.error_against = tile;
207         }
208     }
209
210     public Main(JFrame f) { super(f); }
211
212     public synchronized void fixupTile() { 
213         for(Matrix m1 : transforms) {
214             for(Matrix m2 : transforms) {
215                 if (m1==m2) continue;
216                 for(Mesh.T t1 : tile) {
217                     for(Mesh.T t2 : tile) {
218
219                         Matrix m = m1.inverse().times(m2);
220                         Point t1v1 = m.times(t1.v1().p);
221                         Point t1v2 = m.times(t1.v2().p);
222                         Point t1v3 = m.times(t1.v3().p);
223
224                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
225                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON &&
226                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON) {
227                             t2.e3().bindEdge(t1.e1().pair, m);
228                             t2.e2().bindEdge(t1.e2().pair, m);
229                             t2.e1().bindEdge(t1.e3().pair, m);
230                         }
231                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
232                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON &&
233                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON) {
234                             t2.e3().bindEdge(t1.e2().pair, m);
235                             t2.e2().bindEdge(t1.e3().pair, m);
236                             t2.e1().bindEdge(t1.e1().pair, m);
237                         }
238                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
239                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON &&
240                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON) {
241                             t2.e3().bindEdge(t1.e3().pair, m);
242                             t2.e2().bindEdge(t1.e1().pair, m);
243                             t2.e1().bindEdge(t1.e2().pair, m);
244                         }
245
246                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
247                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON &&
248                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON) {
249                             t2.e1().bindEdge(t1.e1(), m);
250                             t2.e2().bindEdge(t1.e2(), m);
251                             t2.e3().bindEdge(t1.e3(), m);
252                         }
253                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
254                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON &&
255                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON) {
256                             t2.e2().bindEdge(t1.e1(), m);
257                             t2.e3().bindEdge(t1.e2(), m);
258                             t2.e1().bindEdge(t1.e3(), m);
259                         }
260                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
261                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON &&
262                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON) {
263                             t2.e3().bindEdge(t1.e1(), m);
264                             t2.e1().bindEdge(t1.e2(), m);
265                             t2.e2().bindEdge(t1.e3(), m);
266                         }
267
268                     }
269                 }
270             }
271         }
272         tile.rebindPoints();
273         System.out.println("tile volume: " + tile.volume());
274         System.out.println("goal volume: " + goal.volume());
275         tile.error_against = goal;
276         goal.error_against = tile;
277         fixupGoal();
278     }
279
280
281     public class MyMenuItem extends JMenuItem implements ActionListener {
282         public MyMenuItem(String s) {
283             super(s);
284             this.addActionListener(this);
285         }
286         public void actionPerformed(ActionEvent event) {
287             synchronized(Main.this) {
288                     hit();
289             }
290         }
291         public void hit() {}
292     }
293
294     public void hexBrick(boolean offset, boolean rotated) {
295         setTile(new Mesh(false));
296                 float width  = (float)0.8;
297                 float depth  = (float)0.08;
298                 float height = (float)0.4;
299                 float rshift =   width/2;
300                 float lshift = -(width/2);
301                 float halfup = 0;
302                 Point ltf = new Point(lshift,  (depth/2),  (height/2));
303                 Point mtf = new Point( 0.0,    (depth/2),  (height/2));
304                 Point rtf = new Point(rshift,  (depth/2),  (height/2));
305                 Point lbf = new Point(lshift, -(depth/2),  (height/2));
306                 Point mbf = new Point( 0.0,   -(depth/2),  (height/2));
307                 Point rbf = new Point(rshift, -(depth/2),  (height/2));
308
309                 Point ltc = new Point(lshift,  (depth/2), 0);
310                 Point mtc = new Point( 0.0,    (depth/2), 0);
311                 Point rtc = new Point(rshift,  (depth/2), 0);
312                 Point lbc = new Point(lshift, -(depth/2), 0);
313                 Point mbc = new Point( 0.0,   -(depth/2), 0);
314                 Point rbc = new Point(rshift, -(depth/2), 0);
315
316                 Point ltn = new Point(lshift,  (depth/2), -(height/2));
317                 Point mtn = new Point( 0.0,    (depth/2), -(height/2));
318                 Point rtn = new Point(rshift,  (depth/2), -(height/2));
319                 Point lbn = new Point(lshift, -(depth/2), -(height/2));
320                 Point mbn = new Point( 0.0,   -(depth/2), -(height/2));
321                 Point rbn = new Point(rshift, -(depth/2), -(height/2));
322
323         
324                 Point[] points = new Point[] {
325                     ltf,
326                     mtf,
327                     rtf,
328                     lbf,
329                     mbf,
330                     rbf,
331
332                     ltc,
333                     mtc,
334                     rtc,
335                     lbc,
336                     mbc,
337                     rbc,
338
339                     ltn,
340                     mtn,
341                     rtn,
342                     lbn,
343                     mbn,
344                     rbn
345                 };
346
347
348                 // top
349                 tile.newT(ltf, mtf, mtc, null, 1);
350                 tile.newT(mtc, ltc, ltf, null, 1);
351                 tile.newT(mtf, rtf, rtc, null, 1);
352                 tile.newT(rtc, mtc, mtf, null, 1);
353
354                 tile.newT(ltc, mtc, mtn, null, 1);
355                 tile.newT(mtn, ltn, ltc, null, 1);
356                 tile.newT(mtc, rtc, rtn, null, 1);
357                 tile.newT(rtn, mtn, mtc, null, 1);
358
359                 // bottom (swap normals)
360                 tile.newT(mbf, lbf, mbc, null, 2);
361                 tile.newT(lbc, mbc, lbf, null, 2);
362                 tile.newT(rbf, mbf, rbc, null, 2);
363                 tile.newT(mbc, rbc, mbf, null, 2);
364
365                 tile.newT(mbc, lbc, mbn, null, 2);
366                 tile.newT(lbn, mbn, lbc, null, 2);
367
368                 tile.newT(rbc, mbc, rbn, null, 2);
369                 tile.newT(mbn, rbn, mbc, null, 2);
370
371
372                 // left
373                 tile.newT(ltf, ltc, lbc, null, 3);
374                 tile.newT(lbc, lbf, ltf, null, 3);
375                 tile.newT(ltc, ltn, lbn, null, 3);
376                 tile.newT(lbn, lbc, ltc, null, 3);
377
378                 // right (swap normals)
379                 tile.newT(rtc, rtf, rbc, null, 4);
380                 tile.newT(rbf, rbc, rtf, null, 4);
381                 tile.newT(rtn, rtc, rbn, null, 4);
382                 tile.newT(rbc, rbn, rtc, null, 4);
383
384                 // front
385                 tile.newT(ltn, mtn, mbn, null, 5);
386                 tile.newT(ltn, mbn, lbn, null, 5);
387                 tile.newT(mtn, rtn, rbn, null, 5);
388                 tile.newT(mtn, rbn, mbn, null, 5);
389
390                 // back
391                 tile.newT(mtf, ltf, mbf, null, 6);
392                 tile.newT(mbf, ltf, lbf, null, 6);
393                 tile.newT(rtf, mtf, rbf, null, 6);
394                 tile.newT(rbf, mtf, mbf, null, 6);
395
396                 if (offset) {
397                   transforms = new Matrix[] {
398                       Matrix.translate(new Vec(lshift,      0,    height)),
399                       Matrix.translate(new Vec(lshift,      0,   -height)),
400                       Matrix.translate(new Vec(rshift,      0,    height)),
401                       Matrix.translate(new Vec(rshift,      0,   -height)),
402                       Matrix.translate(new Vec( width,      0,         0)),
403                       Matrix.translate(new Vec(-width,      0,         0)),
404                       Matrix.translate(new Vec(lshift,  depth, 0)),
405                       Matrix.translate(new Vec(lshift, -depth, 0)),
406                       Matrix.translate(new Vec(rshift,  depth, 0)),
407                       Matrix.translate(new Vec(rshift, -depth, 0)),
408                       Matrix.ONE,
409                   };
410                 } else if (rotated) {
411                     HashSet<Mesh.E> es = new HashSet<Mesh.E>();
412                     for(Mesh.T t : tile) {
413                         es.add(t.e1());
414                         es.add(t.e2());
415                         es.add(t.e3());
416                     }
417                     for(Mesh.E e : es) {
418                         if (e.v1.p.x == e.v2.p.x && e.v1.p.y == e.v2.p.y) continue;
419                         if (e.v1.p.z == e.v2.p.z && e.v1.p.y == e.v2.p.y) continue;
420                         if (e.v1.p.x == e.v2.p.x && e.v1.p.z == e.v2.p.z) continue;
421                         e.shatter();
422                     }
423                     transforms = new Matrix[] {
424                         Matrix.translate(new Vec(0,   0,    height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
425                         Matrix.translate(new Vec(0,   0,   -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
426                         Matrix.translate(new Vec(0,  depth, 0)),
427                         Matrix.translate(new Vec(0, -depth, 0)),
428                         Matrix.translate(new Vec( width,  0,    0)),
429                         Matrix.translate(new Vec(-width,  0,    0)),
430                       Matrix.ONE,
431                   };
432                 } else {
433                   transforms = new Matrix[] {
434                       Matrix.translate(new Vec(lshift,      0,    height)),
435                       Matrix.translate(new Vec(lshift,      0,   -height)),
436                       Matrix.translate(new Vec(rshift,      0,    height)),
437                       Matrix.translate(new Vec(rshift,      0,   -height)),
438                       Matrix.translate(new Vec( width,      0,         0)),
439                       Matrix.translate(new Vec(-width,      0,         0)),
440                       Matrix.translate(new Vec(0,  depth, 0)),
441                       Matrix.translate(new Vec(0, -depth, 0)),
442                       Matrix.ONE,
443                   };
444                 }
445                 
446                 fixupTile();
447     }
448
449     public class MyMenuBar extends JMenuBar {
450
451         public MyMenuBar() {
452
453             JMenu tileMenu = new JMenu("Tile");
454             JMenu goalMenu = new JMenu("Goal");
455             JMenu hideMenu = new JMenu("Actions");
456
457             hideMenu.add(new MyMenuItem("Start Anneal") { public void hit() { anneal = true; }});
458             hideMenu.add(new MyMenuItem("Stop Anneal") { public void hit() { anneal = false; }});
459             hideMenu.add(new MyMenuItem("Reset to high temperature") { public void hit() { temp = 1; }});
460             hideMenu.add(new MyMenuItem("Subdivide surface") { public void hit() { breaks++; }});
461             hideMenu.add(new MyMenuItem("Show Goal") { public void hit() { goalon = true; }});
462             hideMenu.add(new MyMenuItem("Hide Goal") { public void hit() { goalon = false; }});
463             hideMenu.add(new MyMenuItem("Show All Neighbors") { public void hit() { neighbors = true; }});
464             hideMenu.add(new MyMenuItem("Show One Neighbor Wireframe") { public void hit() { neighborsWireOne = true; }});
465             hideMenu.add(new MyMenuItem("Show All Neighbors Wireframe") { public void hit() { neighborsWire = true; neighborsWireOne = false;}});
466             hideMenu.add(new MyMenuItem("Hide Neighbors") { public void hit() { neighborsWire = false; neighborsWireOne = false; neighbors = false; }});
467
468             goalMenu.add(new MyMenuItem("Fish with face") { public void hit() {
469                 loadGoal("face.stl");
470                 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
471                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
472                 //goal.transform(Matrix.scale(1, 2.2f, 1));
473                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
474                 //factor = factor * 0.8f;
475                 goal.transform(Matrix.scale(0.3f));
476                 //goal.transform(Matrix.rotate(new Vec(0,1,0), (float)(Math.PI*1/3)));
477                 goal.transform(Matrix.rotate(new Vec(1,0,0), (float)(Math.PI*1/3)));
478                 fixupGoal(true, false);
479                 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
480                 fixupGoal(false, true);
481             }});
482             goalMenu.add(new MyMenuItem("Fish") { public void hit() {
483                 loadGoal("fish.stl");
484                 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
485                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
486                 goal.transform(Matrix.scale(1, 2.2f, 1));
487                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
488                 factor = factor * 0.8f;
489                 goal.transform(Matrix.scale(factor));
490                 fixupGoal(true, false);
491                 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
492                 fixupGoal(false, true);
493             }});
494             goalMenu.add(new MyMenuItem("Hammerhead Fish") { public void hit() {
495                 loadGoal("fish.stl");
496                 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
497                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(3*Math.PI/2)));
498                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
499                 factor *= 0.75f;
500                 goal.transform(Matrix.scale(factor));
501                 fixupGoal();
502             }});
503             goalMenu.add(new MyMenuItem("Vertical Fish") { public void hit() {
504                 loadGoal("fish.stl");
505                 //goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
506                 //goal.transform(Matrix.rotate(new Vec(1, 0, 0), (float)(Math.PI/2)));
507                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
508                 goal.transform(Matrix.scale(factor/1.6f));
509                 fixupGoal();
510             }});
511             goalMenu.add(new MyMenuItem("Torus") { public void hit() {
512                 loadGoal("torus.stl");
513                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
514                 goal.transform(Matrix.scale(factor/2.5f));
515                 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
516                 fixupGoal();
517             }});
518             tileMenu.add(new MyMenuItem("Hex Brick") { public void hit() {
519                 hexBrick(false, false);
520             }});
521             tileMenu.add(new MyMenuItem("Hex Brick, offset planes") { public void hit() {
522                 hexBrick(true, false);
523             }});
524             tileMenu.add(new MyMenuItem("Hex Brick, rotated") { public void hit() {
525                 hexBrick(false, true);
526             }});
527             tileMenu.add(new MyMenuItem("Temp (do not use)") { public void hit() {
528                 setTile(new Mesh(false));
529                 float width  = (float)0.8;
530                 float depth  = (float)0.08;
531                 float height = (float)0.4;
532
533                 float rshift =   width/2;
534                 float lshift = -(width/2);
535                 float halfup = 0;
536                 //float shift = height/2;
537                 //width = (width*2)/3;
538                 float shift = 0;
539                 transforms = new Matrix[] {
540
541                     Matrix.translate(new Vec(lshift/2,  depth,    -shift)),
542                     Matrix.translate(new Vec(rshift/2,  depth,    -shift)),
543                     Matrix.translate(new Vec(lshift/2, -depth,    -shift)),
544                     Matrix.translate(new Vec(rshift/2, -depth,    -shift)),
545
546                     Matrix.translate(new Vec(lshift,  depth/2,    -shift)),
547                     Matrix.translate(new Vec(rshift,  depth/2,    -shift)),
548                     Matrix.translate(new Vec(lshift, -depth/2,    -shift)),
549                     Matrix.translate(new Vec(rshift, -depth/2,    -shift)),
550
551
552                     /*
553                       Matrix.translate(new Vec(lshift,  depth,    -shift)),
554                       Matrix.translate(new Vec(rshift,  depth,    -shift)),
555                       Matrix.translate(new Vec(lshift, -depth,    -shift)),
556                       Matrix.translate(new Vec(rshift, -depth,    -shift)),
557                     */
558                     /*
559                       Matrix.translate(new Vec(lshift,  depth,    shift)),
560                       Matrix.translate(new Vec(rshift,  depth,    shift)),
561                       Matrix.translate(new Vec(lshift, -depth,    shift)),
562                       Matrix.translate(new Vec(rshift, -depth,    shift)),
563                     */
564                     //Matrix.translate(new Vec(0,  depth,    0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
565                     //Matrix.translate(new Vec(0, -depth,    0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
566                     //Matrix.translate(new Vec(0,   0,    height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
567                     //Matrix.translate(new Vec(0,   0,   -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
568
569                     //Matrix.translate(new Vec(0,  depth, 0)),
570                     //Matrix.translate(new Vec(0, -depth, 0)),
571                     Matrix.translate(new Vec(0,      0,  height)),
572                     Matrix.translate(new Vec(0,      0, -height)),
573
574                     //Matrix.translate(new Vec(lshift,        depth,  height/2)),
575                     //Matrix.translate(new Vec(lshift,        depth, -height/2)),
576                     //Matrix.translate(new Vec(rshift,       -depth,  height/2)),
577                     //Matrix.translate(new Vec(rshift,       -depth, -height/2)),
578                     //Matrix.translate(new Vec(rshift,       0,  height)),
579                     //Matrix.translate(new Vec(rshift,       0, -height)),
580
581                     Matrix.translate(new Vec( width,           0,    0)),
582                     Matrix.translate(new Vec(-width,           0,    0)),
583
584                     Matrix.ONE
585                 };
586                 fixupTile();
587             } });
588             tileMenu.add(new MyMenuItem("Dense Packing (hex)") { public void hit() {
589                 setTile(new Mesh(false));
590                 float width  = (float)3.2;
591                 float depth  = (float)0.32;
592                 float height = (float)1.6;
593                 float unit = 0.4f;
594                 float r = unit/2;
595                 float sin = (float)(unit * Math.sin(Math.PI/3));
596                 float cos = (float)(unit * Math.cos(Math.PI/3));
597                 float x = (float)(r*Math.tan(Math.PI/6));
598                 float z = (float)(r/Math.cos(Math.PI/6));
599                 height = 2*r*(float)Math.sqrt(2f/3f);
600
601                 /*
602                 r *= 0.3f;
603                 cos *= 0.3f;
604                 unit *= 0.3f;
605                 */
606
607                 /*
608                   sin *= 0.3f;
609                   x *= 0.3f;
610                   z *= 0.3f;
611                 */
612                 transforms = new Matrix[] {
613                     Matrix.translate(new Vec(-unit, 0, 0)),
614                     Matrix.translate(new Vec( unit, 0, 0)),
615                     Matrix.translate(new Vec(-cos,  0,  sin)),
616                     Matrix.translate(new Vec( cos,  0,  sin)),
617                     Matrix.translate(new Vec(-cos,  0, -sin)),
618                     Matrix.translate(new Vec( cos,  0, -sin)),
619                     Matrix.translate(new Vec( 0,  height, z)),
620                     Matrix.translate(new Vec(-r,  height, -x)),
621                     Matrix.translate(new Vec( r,  height, -x)),
622                     Matrix.translate(new Vec( 0, -height, -z)),
623                     Matrix.translate(new Vec(-r, -height, x)),
624                     Matrix.translate(new Vec( r, -height, x)),
625                     Matrix.ONE,
626                 };
627                 generateTile(transforms, tile);
628                 fixupTile();
629             } });
630
631             tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
632                 setTile(new Mesh(false));
633                 float unit = 0.4f;
634                 float r = unit/2;
635                 float sin = (float)(unit * Math.sin(Math.PI/3));
636                 float cos = (float)(unit * Math.cos(Math.PI/3));
637                 float x = (float)(r*Math.tan(Math.PI/6));
638                 float z = (float)(r/Math.cos(Math.PI/6));
639                 float height = 2*r*(float)Math.sqrt(2f/3f);
640
641                 transforms = new Matrix[] {
642
643                     //Matrix.reflect(new Vec( 0,  height, -z).norm()),
644
645                     Matrix.translate(new Vec(-unit, 0, 0)),
646                     Matrix.translate(new Vec( unit, 0, 0)),
647                     Matrix.translate(new Vec(-cos,  0,  sin)),
648                     Matrix.translate(new Vec( cos,  0,  sin)),
649                     Matrix.translate(new Vec(-cos,  0, -sin)),
650                     Matrix.translate(new Vec( cos,  0, -sin)),
651
652                     Matrix.translate(new Vec( 0,  height, -z)),
653                     Matrix.translate(new Vec(-r,  height,  x)),
654                     Matrix.translate(new Vec( r,  height,  x)),
655                     Matrix.translate(new Vec( 0, -height,  z)),
656                     Matrix.translate(new Vec(-r, -height, -x)),
657                     Matrix.translate(new Vec( r, -height, -x)),
658
659                     /*
660                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
661                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
662                     Matrix.translate(new Vec( r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
663                     Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
664                     Matrix.translate(new Vec(-r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
665                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
666                     */
667
668                     /*
669                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.scale(-1,1,-1)),
670                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.scale(-1,1,-1)),
671                     Matrix.translate(new Vec( r,  height,  x)).times(Matrix.scale(-1,1,-1)),
672                     Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.scale(-1,1,-1)),
673                     Matrix.translate(new Vec(-r, -height,  x)).times(Matrix.scale(-1,1,-1)),
674                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.scale(-1,1,-1)),
675                     */
676                     Matrix.ONE
677                 };
678                 generateTile(transforms, tile);
679
680
681                 transforms = new Matrix[] {
682                     Matrix.reflect(new Vec( 0,  height, -z).norm()),
683                     //Matrix.reflect(new Vec( 0, -height,  z)),
684                     Matrix.ONE,
685                     Matrix.translate(new Vec(-unit, 0, 0)),
686                     Matrix.translate(new Vec( unit, 0, 0)),
687                     /*
688                     Matrix.translate(new Vec(-cos,  0,  sin)),
689                     Matrix.translate(new Vec( cos,  0,  sin)),
690                     Matrix.translate(new Vec(-cos,  0, -sin)),
691                     Matrix.translate(new Vec( cos,  0, -sin)),
692
693                     Matrix.translate(new Vec( 0,  height, -z)),
694                     Matrix.translate(new Vec(-r,  height,  x)),
695                     Matrix.translate(new Vec( r,  height,  x)),
696                     Matrix.translate(new Vec( 0, -height,  z)),
697                     Matrix.translate(new Vec(-r, -height, -x)),
698                     Matrix.translate(new Vec( r, -height, -x)),
699                     */
700                 };
701
702
703                 //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
704
705                 Matrix m = Matrix.scale(1.9f, 1f ,1);
706                 //Matrix m = Matrix.scale(1f, 2.1f, 1f);
707                 tile.transform(m);
708                 for(int i=0; i<transforms.length; i++)
709                     transforms[i] = preMultiplyTranslationalComponentBy(transforms[i], m);
710
711
712                 fixupTile();
713
714             } });
715             tileMenu.add(new MyMenuItem("Genus-1") { public void hit() {
716                 synchronized(this) {
717                     setTile(new Mesh(false));
718                     Matrix mm = Matrix.scale(0.1f);
719                     float height = 4;
720                     float width  = 4;
721                     float depth  = 1;
722                     // top
723                     quad(tile, mm, 
724                          new Point( 2,  2,  0),
725                          new Point( 1,  1, -1),
726                          new Point(-1,  1, -1),
727                          new Point(-2,  2,  0));
728                     quad(tile, mm, 
729                          new Point(-2,  2,  0),
730                          new Point(-1,  1,  1),
731                          new Point( 1,  1,  1),
732                          new Point( 2,  2,  0));
733                     quad(tile, mm, 
734                          new Point( 1,  1, -1),
735                          new Point( 1,  1,  1),
736                          new Point(-1,  1,  1),
737                          new Point(-1,  1, -1));
738
739                     // bottom
740                     quad(tile, mm, 
741                          new Point(-2, -2,  0),
742                          new Point(-1, -1, -1),
743                          new Point( 1, -1, -1),
744                          new Point( 2, -2,  0));
745                     quad(tile, mm, 
746                          new Point( 2, -2,  0),
747                          new Point( 1, -1,  1),
748                          new Point(-1, -1,  1),
749                          new Point(-2, -2,  0));
750                     quad(tile, mm, 
751                          new Point(-1, -1, -1),
752                          new Point(-1, -1,  1),
753                          new Point( 1, -1,  1),
754                          new Point( 1, -1, -1));
755
756                     // left
757                     quad(tile, mm, 
758                          new Point( 2, -2,  0),
759                          new Point( 1, -1, -1),
760                          new Point( 1,  1, -1),
761                          new Point( 2,  2,  0));
762                     quad(tile, mm, 
763                          new Point( 2,  2,  0),
764                          new Point( 1,  1,  1),
765                          new Point( 1, -1,  1),
766                          new Point( 2, -2,  0));
767                     quad(tile, mm, 
768                          new Point( 1, -1, -1),
769                          new Point( 1, -1,  1),
770                          new Point( 1,  1,  1),
771                          new Point( 1,  1, -1));
772
773                     // bottom
774                     quad(tile, mm, 
775                          new Point(-2,  2,  0),
776                          new Point(-1,  1, -1),
777                          new Point(-1, -1, -1),
778                          new Point(-2, -2,  0));
779                     quad(tile, mm, 
780                          new Point(-2, -2,  0),
781                          new Point(-1, -1,  1),
782                          new Point(-1,  1,  1),
783                          new Point(-2,  2,  0));
784                     quad(tile, mm, 
785                          new Point(-1,  1, -1),
786                          new Point(-1,  1,  1),
787                          new Point(-1, -1,  1),
788                          new Point(-1, -1, -1));
789
790                     height = 4;
791                     width  = 4;
792                     depth  = 1;
793
794
795                     transforms = new Matrix[] {
796                         Matrix.translate(new Vec(0, 0.2f,0))
797                         .times(Matrix.rotate(new Vec(0,1,0), (float)(1*Math.PI/2))),
798
799                         Matrix.translate(new Vec(0,-0.2f,0))
800                         .times(Matrix.rotate(new Vec(0,1,0), (float)(-1*Math.PI/2))),
801
802                         Matrix.translate(new Vec( 0.2f,0,0))
803                         .times(Matrix.rotate(new Vec(1,0,0), (float)(1*Math.PI/2))),
804
805                         Matrix.translate(new Vec(-0.2f,0,0))
806                         .times(Matrix.rotate(new Vec(1,0,0), (float)(-1*Math.PI/2))),
807
808
809                         //Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
810
811                         /*
812                           Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
813
814                           Matrix.rotate(new Vec(0,0,1), (float)(3*Math.PI/2)),
815                           Matrix.rotate(new Vec(1,0,0), (float)(2*Math.PI/2)),
816                         */
817
818                         //Matrix.rotate(new Vec(0,0,1), (float)(2*Math.PI/2)),
819                         //Matrix.scale(1,-1,1),
820
821                         //Matrix.translate(new Vec( 0.2f, 0,0))
822                         //.times(Matrix.rotate(new Vec(0,0,1), (float)( 1*Math.PI/2)))
823                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*Math.PI/2))),
824
825                         //Matrix.translate(new Vec(-0.2f, 0,0))
826                         //.times(Matrix.rotate(new Vec(0,0,1), (float)( 3*Math.PI/2)))
827                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*Math.PI/2))),
828             
829                         //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
830                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
831                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
832                         //Matrix.rotate(new Vec(0,0,1), (float)( 1*Math.PI/2))
833                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
834                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
835
836                         //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
837                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
838                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
839                         //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
840                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
841                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
842
843                         Matrix.ONE,
844                     };
845                     fixupTile();
846                 }}});
847             tileMenu.add(new MyMenuItem("Hammerhead") { public void hit() {
848                 synchronized(this) {
849                     setTile(new Mesh(false));
850                     Matrix mm = Matrix.ONE;
851                     float height1 = .1f;
852                     float height2 = .1f;
853                     float width  = .4f;
854                     float depth  = .1f;
855                     // top
856                     Point a1 = new Point( -width/2,         height2/2, -depth/2);
857                     Point b1 = new Point(        0,         height2/2, -depth/2);
858                     Point c1 = new Point(        0, height1+height2/2, -depth/2);
859                     Point d1 = new Point(  width/2, height1+height2/2, -depth/2);
860                     Point e1 = new Point(  width/2,         height2/2, -depth/2);
861                     Point f1 = new Point(  width/2,        -height2/2, -depth/2);
862                     Point g1 = new Point(  width/2,-height1-height2/2, -depth/2);
863                     Point h1 = new Point(        0,-height1-height2/2, -depth/2);
864                     Point i1 = new Point(        0,        -height2/2, -depth/2);
865                     Point j1 = new Point( -width/2,        -height2/2, -depth/2);
866                     Point a2 = new Point( -width/2,         height2/2,  depth/2);
867                     Point b2 = new Point(        0,         height2/2,  depth/2);
868                     Point c2 = new Point(        0, height1+height2/2,  depth/2);
869                     Point d2 = new Point(  width/2, height1+height2/2,  depth/2);
870                     Point e2 = new Point(  width/2,         height2/2,  depth/2);
871                     Point f2 = new Point(  width/2,        -height2/2,  depth/2);
872                     Point g2 = new Point(  width/2,-height1-height2/2,  depth/2);
873                     Point h2 = new Point(        0,-height1-height2/2,  depth/2);
874                     Point i2 = new Point(        0,        -height2/2,  depth/2);
875                     Point j2 = new Point( -width/2,        -height2/2,  depth/2);
876
877                     quad(tile, mm, a1, b1, i1, j1);
878                     quad(tile, mm, c1, d1, e1, b1);
879                     quad(tile, mm, b1, e1, f1, i1);
880                     quad(tile, mm, i1, f1, g1, h1);
881
882                     quad(tile, mm, j2, i2, b2, a2);
883                     quad(tile, mm, b2, e2, d2, c2);
884                     quad(tile, mm, i2, f2, e2, b2);
885                     quad(tile, mm, h2, g2, f2, i2);
886
887                     quad(tile, mm, d1, d2, e2, e1);
888                     quad(tile, mm, e1, e2, f2, f1);
889                     quad(tile, mm, f1, f2, g2, g1);
890                     quad(tile, mm, h1, g1, g2, h2);
891                     quad(tile, mm, i2, i1, h1, h2);
892                     quad(tile, mm, j1, i1, i2, j2);
893                     quad(tile, mm, a2, a1, j1, j2);
894                     quad(tile, mm, a1, a2, b2, b1);
895                     quad(tile, mm, c2, c1, b1, b2);
896                     quad(tile, mm, c1, c2, d2, d1);
897
898                     transforms = new Matrix[] {
899
900                         mm.times(Matrix.translate(new Vec(   width,     0, 0))),
901                         mm.times(Matrix.translate(new Vec(  -width,     0, 0))),
902                         mm.times(Matrix.translate(new Vec(-width/2, height1+height2, 0))),
903                         mm.times(Matrix.translate(new Vec( width/2, height1+height2, 0))),
904                         mm.times(Matrix.translate(new Vec(-width/2,-height1-height2, 0))),
905                         mm.times(Matrix.translate(new Vec( width/2,-height1-height2, 0))),
906
907                         mm.times(Matrix.translate(new Vec(   width/2,     0,  depth))),
908                         mm.times(Matrix.translate(new Vec(  -width/2,     0,  depth))),
909                         mm.times(Matrix.translate(new Vec(         0, height1+height2,  depth))),
910                         mm.times(Matrix.translate(new Vec(         0,-height1-height2,  depth))),
911
912                         mm.times(Matrix.translate(new Vec(   width/2,     0, -depth))),
913                         mm.times(Matrix.translate(new Vec(  -width/2,     0, -depth))),
914                         mm.times(Matrix.translate(new Vec(         0, height1+height2, -depth))),
915                         mm.times(Matrix.translate(new Vec(         0,-height1-height2, -depth))),
916
917                         Matrix.ONE
918                     };
919                     fixupTile();
920                 }}});
921
922             // Finally, add all the menus to the menu bar.
923             add(tileMenu);
924             //add(goalMenu);
925             //add(hideMenu);
926         }
927
928     }
929
930     private static Matrix preMultiplyTranslationalComponentBy(Matrix mthis, Matrix mm) {
931         Vec v = mm.times(mthis.getTranslationalComponent());
932         return new Matrix(mthis.a, mthis.b, mthis.c, v.x,
933                           mthis.e, mthis.f, mthis.g, v.y,
934                           mthis.i, mthis.j, mthis.k, v.z,
935                           mthis.m, mthis.n, mthis.o, 1);
936     }
937
938 //////////////////////////////////////////////////////////////////////////////
939     public void breakit() {
940         int oldverts = verts;
941         if (verts > 2000 && !force) return;
942         force = false;
943         System.out.println("doubling vertices.");
944         PriorityQueue<Mesh.E> es = new PriorityQueue<Mesh.E>();
945         for(Mesh.T t : tile) {
946             es.add(t.e1());
947             es.add(t.e2());
948             es.add(t.e3());
949             Thread.yield();
950             repaint();
951         }
952         for(int i=0; i<Math.min(oldverts,50); i++) {
953             Mesh.E e = es.poll();
954             verts++;
955             e.shatter();
956             Thread.yield();
957             repaint();
958         }
959         System.out.println("now have " + verts + " vertices; max is 2000");
960         tile.rebindPoints();
961     }
962
963     public boolean rand(double temp, Mesh.Vertex p) {
964
965         p.reComputeErrorAround();
966         double tile_error = tile.error();
967         double goal_error = goal.error();
968
969         float max = p.averageEdgeLength()/5;
970         Vec v = new Vec(random.nextFloat(), random.nextFloat(), random.nextFloat());
971         v = v.norm().times((random.nextFloat() - 0.5f) * max);
972         Matrix m = Matrix.translate(v);
973         boolean good = p.move(v, false);
974         if (!good) { return false; }
975
976         double new_tile_error = tile.error();
977         double new_goal_error = goal.error();
978         double tile_delta = (new_tile_error - tile_error) / tile_error;
979         double goal_delta = (new_goal_error - goal_error) / goal_error;
980         double delta = tile_delta + goal_delta;
981         double swapProbability = Math.exp((-1 * delta) / temp);
982
983         //boolean doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
984         //boolean doSwap = good && (tile_delta + goal_delta <= 0);
985         //if (temp < 0.000001) doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
986         boolean doSwap = good && (Math.random() < swapProbability);
987
988         // always move uphill if possible -- potential idea
989         if (tile_delta <= 0 && goal_delta <= 0 && good) doSwap = true;
990         if (hillclimb)
991             doSwap = tile_delta <= 0 && goal_delta <= 0 && good;
992
993         if (doSwap) {
994             tile_error = new_tile_error;
995             goal_error = new_goal_error;
996             hits++;
997             p.goodp = p.p;
998         } else {
999             p.move(v.times(-1), true);
1000             misses++;
1001         }
1002         p.reComputeErrorAround();
1003         return true;
1004     }
1005
1006     float hits = 0;
1007     float misses = 0;
1008     public void anneal() throws Exception {
1009         double hightemp = 1;
1010         temp = hightemp;
1011         double last = 10;
1012         boolean seek_upward = false;
1013         double acceptance = 1;
1014         while(true) {
1015             synchronized(this) {
1016                 if (!anneal) { repaint(); Thread.sleep(10); continue; }
1017
1018             double ratio = (hits+misses==0) ? 1 : (hits / (hits+misses));
1019             hits = 0;
1020             misses = 0;
1021             double gamma = 1;
1022             acceptance = (ratio+acceptance)/2;
1023             accepts = (int)(Math.ceil(ratio*100));
1024             temps = (int)(Math.ceil(temp*1000));
1025             vertss = tile.size();
1026             if (breaks > 0) {
1027                 while (breaks>0) {
1028                     breaks--;
1029                     breakit();
1030                 }
1031                 seek_upward = true;
1032                 continue;
1033             } else if (acceptance > 0.96) gamma = 0.1f;
1034             else if (acceptance > 0.9)    gamma = 0.2f;
1035             else if (acceptance > 0.8)    gamma = 0.3f;
1036             else if (acceptance > 0.6)    gamma = 0.4f;
1037             else if (acceptance > 0.3)    gamma = 0.8f;
1038             else if (acceptance > 0.15)   gamma = 0.94f;
1039             else if (acceptance > 0.10)   gamma = 0.98f;
1040
1041             else if (acceptance < 0.01)   breaks++;
1042
1043             if (seek_upward) {
1044                 if (acceptance > 0.25) seek_upward = false;
1045                 else gamma = 2-gamma;
1046             }
1047
1048             if (anneal)
1049                 temp = temp * gamma;
1050
1051
1052             HashSet<Mesh.Vertex> hs = new HashSet<Mesh.Vertex>();
1053             for(Mesh.Vertex p : tile.vertices()) hs.add(p);
1054             Mesh.Vertex[] pts = (Mesh.Vertex[])hs.toArray(new Mesh.Vertex[0]);
1055
1056             int count = 0;
1057             long then = System.currentTimeMillis();
1058             for(int i=0; i<300; i++) {
1059                 if (anneal) {
1060                     Mesh.Vertex v = pts[Math.abs(random.nextInt()) % pts.length];
1061                     if (breaks>0) break;
1062                     if (!rand(temp,v)) { i--; continue; }
1063                     v.recomputeFundamentalQuadricIfStale();
1064                     v.recomputeFundamentalQuadricIfNeighborChanged();
1065                     count++;
1066                 }
1067                 Thread.yield();
1068                 repaint();
1069             }
1070
1071             System.out.println("temp="+temp + " ratio="+(Math.ceil(acceptance*100)) + " " +
1072                                "points_per_second=" +
1073                                (count*1000)/((double)(System.currentTimeMillis()-then)));
1074             for(Mesh.Vertex p : goal.vertices()) {
1075                 p.quadricStale = true;
1076                 p.recomputeFundamentalQuadricIfNeighborChanged();
1077             }
1078             }
1079         }
1080     }
1081
1082
1083     public static void main(String[] s) throws Exception {
1084         JFrame f = new JFrame();
1085         f.setLayout(new BorderLayout());
1086         Main main = new Main(f);
1087         f.add(main, BorderLayout.CENTER);
1088
1089         f.addWindowListener(new WindowListener() {
1090                 public void windowActivated(WindowEvent e) { }
1091                 public void windowClosed(WindowEvent e) { System.exit(0); }
1092                 public void windowClosing(WindowEvent e) { System.exit(0); }
1093                 public void windowDeactivated(WindowEvent e)  { }
1094                 public void windowDeiconified(WindowEvent e)  { }
1095                 public void windowIconified(WindowEvent e)  { }
1096                 public void windowOpened(WindowEvent e) { }
1097             });
1098
1099         f.pack();
1100         f.show();
1101         f.setSize(900, 900);
1102         f.doLayout();
1103
1104         JFrame f2 = new JFrame();
1105         f2.setJMenuBar(main.new MyMenuBar());
1106         f2.setSize(100,100);
1107         f2.show();
1108
1109         main.anneal();
1110     }
1111
1112
1113 }