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