change MarchingCubes.march() to take a VoxelData rather than a SampledField
[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 VoxelData() {
299                 float radius = 1.0f;
300                 public float getMaxX()        { return  1.0f; }
301                 public float getMinX()        { return -1.0f; }
302                 public int   getNumSamplesX() { return   10; }
303                 public float getMaxY()        { return  1.0f; }
304                 public float getMinY()        { return -1.0f; }
305                 public int   getNumSamplesY() { return   10; }
306                 public float getMaxZ()        { return  1.0f; }
307                 public float getMinZ()        { return -1.0f; }
308                 public int   getNumSamplesZ() { return   10; }
309                 public float getSample(Point p) {
310                     double x = p.x;
311                     double y = p.y;
312                     double z = p.z;
313                     return (float)(radius-Math.sqrt(x*x+y*y+z*z));
314                 }
315             },
316             mesh);
317         setTile(mesh);
318         //fixupTile();
319     }
320
321     public void hexBrick(boolean offset, boolean rotated) {
322         setTile(new Mesh(false));
323                 float width  = (float)0.8;
324                 float depth  = (float)0.08;
325                 float height = (float)0.4;
326                 float rshift =   width/2;
327                 float lshift = -(width/2);
328                 float halfup = 0;
329                 Point ltf = new Point(lshift,  (depth/2),  (height/2));
330                 Point mtf = new Point( 0.0,    (depth/2),  (height/2));
331                 Point rtf = new Point(rshift,  (depth/2),  (height/2));
332                 Point lbf = new Point(lshift, -(depth/2),  (height/2));
333                 Point mbf = new Point( 0.0,   -(depth/2),  (height/2));
334                 Point rbf = new Point(rshift, -(depth/2),  (height/2));
335
336                 Point ltc = new Point(lshift,  (depth/2), 0);
337                 Point mtc = new Point( 0.0,    (depth/2), 0);
338                 Point rtc = new Point(rshift,  (depth/2), 0);
339                 Point lbc = new Point(lshift, -(depth/2), 0);
340                 Point mbc = new Point( 0.0,   -(depth/2), 0);
341                 Point rbc = new Point(rshift, -(depth/2), 0);
342
343                 Point ltn = new Point(lshift,  (depth/2), -(height/2));
344                 Point mtn = new Point( 0.0,    (depth/2), -(height/2));
345                 Point rtn = new Point(rshift,  (depth/2), -(height/2));
346                 Point lbn = new Point(lshift, -(depth/2), -(height/2));
347                 Point mbn = new Point( 0.0,   -(depth/2), -(height/2));
348                 Point rbn = new Point(rshift, -(depth/2), -(height/2));
349
350         
351                 Point[] points = new Point[] {
352                     ltf,
353                     mtf,
354                     rtf,
355                     lbf,
356                     mbf,
357                     rbf,
358
359                     ltc,
360                     mtc,
361                     rtc,
362                     lbc,
363                     mbc,
364                     rbc,
365
366                     ltn,
367                     mtn,
368                     rtn,
369                     lbn,
370                     mbn,
371                     rbn
372                 };
373
374
375                 // top
376                 tile.newT(ltf, mtf, mtc, null, 1);
377                 tile.newT(mtc, ltc, ltf, null, 1);
378                 tile.newT(mtf, rtf, rtc, null, 1);
379                 tile.newT(rtc, mtc, mtf, null, 1);
380
381                 tile.newT(ltc, mtc, mtn, null, 1);
382                 tile.newT(mtn, ltn, ltc, null, 1);
383                 tile.newT(mtc, rtc, rtn, null, 1);
384                 tile.newT(rtn, mtn, mtc, null, 1);
385
386                 // bottom (swap normals)
387                 tile.newT(mbf, lbf, mbc, null, 2);
388                 tile.newT(lbc, mbc, lbf, null, 2);
389                 tile.newT(rbf, mbf, rbc, null, 2);
390                 tile.newT(mbc, rbc, mbf, null, 2);
391
392                 tile.newT(mbc, lbc, mbn, null, 2);
393                 tile.newT(lbn, mbn, lbc, null, 2);
394
395                 tile.newT(rbc, mbc, rbn, null, 2);
396                 tile.newT(mbn, rbn, mbc, null, 2);
397
398
399                 // left
400                 tile.newT(ltf, ltc, lbc, null, 3);
401                 tile.newT(lbc, lbf, ltf, null, 3);
402                 tile.newT(ltc, ltn, lbn, null, 3);
403                 tile.newT(lbn, lbc, ltc, null, 3);
404
405                 // right (swap normals)
406                 tile.newT(rtc, rtf, rbc, null, 4);
407                 tile.newT(rbf, rbc, rtf, null, 4);
408                 tile.newT(rtn, rtc, rbn, null, 4);
409                 tile.newT(rbc, rbn, rtc, null, 4);
410
411                 // front
412                 tile.newT(ltn, mtn, mbn, null, 5);
413                 tile.newT(ltn, mbn, lbn, null, 5);
414                 tile.newT(mtn, rtn, rbn, null, 5);
415                 tile.newT(mtn, rbn, mbn, null, 5);
416
417                 // back
418                 tile.newT(mtf, ltf, mbf, null, 6);
419                 tile.newT(mbf, ltf, lbf, null, 6);
420                 tile.newT(rtf, mtf, rbf, null, 6);
421                 tile.newT(rbf, mtf, mbf, null, 6);
422
423                 if (offset) {
424                   transforms = new Matrix[] {
425                       Matrix.translate(new Vec(lshift,      0,    height)),
426                       Matrix.translate(new Vec(lshift,      0,   -height)),
427                       Matrix.translate(new Vec(rshift,      0,    height)),
428                       Matrix.translate(new Vec(rshift,      0,   -height)),
429                       Matrix.translate(new Vec( width,      0,         0)),
430                       Matrix.translate(new Vec(-width,      0,         0)),
431                       Matrix.translate(new Vec(lshift,  depth, 0)),
432                       Matrix.translate(new Vec(lshift, -depth, 0)),
433                       Matrix.translate(new Vec(rshift,  depth, 0)),
434                       Matrix.translate(new Vec(rshift, -depth, 0)),
435                       Matrix.ONE,
436                   };
437                 } else if (rotated) {
438                     HashSet<Mesh.E> es = new HashSet<Mesh.E>();
439                     for(Mesh.T t : tile) {
440                         es.add(t.e1());
441                         es.add(t.e2());
442                         es.add(t.e3());
443                     }
444                     for(Mesh.E e : es) {
445                         if (e.v1.p.x == e.v2.p.x && e.v1.p.y == e.v2.p.y) continue;
446                         if (e.v1.p.z == e.v2.p.z && e.v1.p.y == e.v2.p.y) continue;
447                         if (e.v1.p.x == e.v2.p.x && e.v1.p.z == e.v2.p.z) continue;
448                         e.shatter();
449                     }
450                     transforms = new Matrix[] {
451                         Matrix.translate(new Vec(0,   0,    height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
452                         Matrix.translate(new Vec(0,   0,   -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
453                         Matrix.translate(new Vec(0,  depth, 0)),
454                         Matrix.translate(new Vec(0, -depth, 0)),
455                         Matrix.translate(new Vec( width,  0,    0)),
456                         Matrix.translate(new Vec(-width,  0,    0)),
457                       Matrix.ONE,
458                   };
459                 } else {
460                   transforms = new Matrix[] {
461                       Matrix.translate(new Vec(lshift,      0,    height)),
462                       Matrix.translate(new Vec(lshift,      0,   -height)),
463                       Matrix.translate(new Vec(rshift,      0,    height)),
464                       Matrix.translate(new Vec(rshift,      0,   -height)),
465                       Matrix.translate(new Vec( width,      0,         0)),
466                       Matrix.translate(new Vec(-width,      0,         0)),
467                       Matrix.translate(new Vec(0,  depth, 0)),
468                       Matrix.translate(new Vec(0, -depth, 0)),
469                       Matrix.ONE,
470                   };
471                 }
472                 
473                 fixupTile();
474     }
475
476     public class MyMenuBar extends JMenuBar {
477
478         public MyMenuBar() {
479
480             JMenu tileMenu = new JMenu("Tile");
481             JMenu goalMenu = new JMenu("Goal");
482             JMenu hideMenu = new JMenu("Actions");
483
484             hideMenu.add(new MyMenuItem("Start Anneal") { public void hit() { anneal = true; }});
485             hideMenu.add(new MyMenuItem("Stop Anneal") { public void hit() { anneal = false; }});
486             hideMenu.add(new MyMenuItem("Reset to high temperature") { public void hit() { temp = 1; }});
487             hideMenu.add(new MyMenuItem("Subdivide surface") { public void hit() { breaks++; }});
488             hideMenu.add(new MyMenuItem("Show Goal") { public void hit() { goalon = true; }});
489             hideMenu.add(new MyMenuItem("Hide Goal") { public void hit() { goalon = false; }});
490             hideMenu.add(new MyMenuItem("Show All Neighbors") { public void hit() { neighbors = true; }});
491             hideMenu.add(new MyMenuItem("Show One Neighbor Wireframe") { public void hit() { neighborsWireOne = true; }});
492             hideMenu.add(new MyMenuItem("Show All Neighbors Wireframe") { public void hit() { neighborsWire = true; neighborsWireOne = false;}});
493             hideMenu.add(new MyMenuItem("Hide Neighbors") { public void hit() { neighborsWire = false; neighborsWireOne = false; neighbors = false; }});
494
495             goalMenu.add(new MyMenuItem("Fish with face") { public void hit() {
496                 loadGoal("face.stl");
497                 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
498                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
499                 //goal.transform(Matrix.scale(1, 2.2f, 1));
500                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
501                 //factor = factor * 0.8f;
502                 goal.transform(Matrix.scale(0.3f));
503                 //goal.transform(Matrix.rotate(new Vec(0,1,0), (float)(Math.PI*1/3)));
504                 goal.transform(Matrix.rotate(new Vec(1,0,0), (float)(Math.PI*1/3)));
505                 fixupGoal(true, false);
506                 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
507                 fixupGoal(false, true);
508             }});
509             goalMenu.add(new MyMenuItem("Fish") { public void hit() {
510                 loadGoal("fish.stl");
511                 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
512                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
513                 goal.transform(Matrix.scale(1, 2.2f, 1));
514                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
515                 factor = factor * 0.8f;
516                 goal.transform(Matrix.scale(factor));
517                 fixupGoal(true, false);
518                 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
519                 fixupGoal(false, true);
520             }});
521             goalMenu.add(new MyMenuItem("Hammerhead Fish") { public void hit() {
522                 loadGoal("fish.stl");
523                 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
524                 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(3*Math.PI/2)));
525                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
526                 factor *= 0.75f;
527                 goal.transform(Matrix.scale(factor));
528                 fixupGoal();
529             }});
530             goalMenu.add(new MyMenuItem("Vertical Fish") { public void hit() {
531                 loadGoal("fish.stl");
532                 //goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
533                 //goal.transform(Matrix.rotate(new Vec(1, 0, 0), (float)(Math.PI/2)));
534                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
535                 goal.transform(Matrix.scale(factor/1.6f));
536                 fixupGoal();
537             }});
538             goalMenu.add(new MyMenuItem("Torus") { public void hit() {
539                 loadGoal("torus.stl");
540                 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
541                 goal.transform(Matrix.scale(factor/2.5f));
542                 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
543                 fixupGoal();
544             }});
545             tileMenu.add(new MyMenuItem("Hex Brick") { public void hit() {
546                 hexBrick(false, false);
547             }});
548             tileMenu.add(new MyMenuItem("Hex Brick, offset planes") { public void hit() {
549                 hexBrick(true, false);
550             }});
551             tileMenu.add(new MyMenuItem("Hex Brick, rotated") { public void hit() {
552                 hexBrick(false, true);
553             }});
554             tileMenu.add(new MyMenuItem("Temp (do not use)") { public void hit() {
555                 setTile(new Mesh(false));
556                 float width  = (float)0.8;
557                 float depth  = (float)0.08;
558                 float height = (float)0.4;
559
560                 float rshift =   width/2;
561                 float lshift = -(width/2);
562                 float halfup = 0;
563                 //float shift = height/2;
564                 //width = (width*2)/3;
565                 float shift = 0;
566                 transforms = new Matrix[] {
567
568                     Matrix.translate(new Vec(lshift/2,  depth,    -shift)),
569                     Matrix.translate(new Vec(rshift/2,  depth,    -shift)),
570                     Matrix.translate(new Vec(lshift/2, -depth,    -shift)),
571                     Matrix.translate(new Vec(rshift/2, -depth,    -shift)),
572
573                     Matrix.translate(new Vec(lshift,  depth/2,    -shift)),
574                     Matrix.translate(new Vec(rshift,  depth/2,    -shift)),
575                     Matrix.translate(new Vec(lshift, -depth/2,    -shift)),
576                     Matrix.translate(new Vec(rshift, -depth/2,    -shift)),
577
578
579                     /*
580                       Matrix.translate(new Vec(lshift,  depth,    -shift)),
581                       Matrix.translate(new Vec(rshift,  depth,    -shift)),
582                       Matrix.translate(new Vec(lshift, -depth,    -shift)),
583                       Matrix.translate(new Vec(rshift, -depth,    -shift)),
584                     */
585                     /*
586                       Matrix.translate(new Vec(lshift,  depth,    shift)),
587                       Matrix.translate(new Vec(rshift,  depth,    shift)),
588                       Matrix.translate(new Vec(lshift, -depth,    shift)),
589                       Matrix.translate(new Vec(rshift, -depth,    shift)),
590                     */
591                     //Matrix.translate(new Vec(0,  depth,    0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
592                     //Matrix.translate(new Vec(0, -depth,    0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
593                     //Matrix.translate(new Vec(0,   0,    height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
594                     //Matrix.translate(new Vec(0,   0,   -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
595
596                     //Matrix.translate(new Vec(0,  depth, 0)),
597                     //Matrix.translate(new Vec(0, -depth, 0)),
598                     Matrix.translate(new Vec(0,      0,  height)),
599                     Matrix.translate(new Vec(0,      0, -height)),
600
601                     //Matrix.translate(new Vec(lshift,        depth,  height/2)),
602                     //Matrix.translate(new Vec(lshift,        depth, -height/2)),
603                     //Matrix.translate(new Vec(rshift,       -depth,  height/2)),
604                     //Matrix.translate(new Vec(rshift,       -depth, -height/2)),
605                     //Matrix.translate(new Vec(rshift,       0,  height)),
606                     //Matrix.translate(new Vec(rshift,       0, -height)),
607
608                     Matrix.translate(new Vec( width,           0,    0)),
609                     Matrix.translate(new Vec(-width,           0,    0)),
610
611                     Matrix.ONE
612                 };
613                 fixupTile();
614             } });
615             tileMenu.add(new MyMenuItem("Dense Packing (hex)") { public void hit() {
616                 setTile(new Mesh(false));
617                 float width  = (float)3.2;
618                 float depth  = (float)0.32;
619                 float height = (float)1.6;
620                 float unit = 0.4f;
621                 float r = unit/2;
622                 float sin = (float)(unit * Math.sin(Math.PI/3));
623                 float cos = (float)(unit * Math.cos(Math.PI/3));
624                 float x = (float)(r*Math.tan(Math.PI/6));
625                 float z = (float)(r/Math.cos(Math.PI/6));
626                 height = 2*r*(float)Math.sqrt(2f/3f);
627
628                 /*
629                 r *= 0.3f;
630                 cos *= 0.3f;
631                 unit *= 0.3f;
632                 */
633
634                 /*
635                   sin *= 0.3f;
636                   x *= 0.3f;
637                   z *= 0.3f;
638                 */
639                 transforms = new Matrix[] {
640                     Matrix.translate(new Vec(-unit, 0, 0)),
641                     Matrix.translate(new Vec( unit, 0, 0)),
642                     Matrix.translate(new Vec(-cos,  0,  sin)),
643                     Matrix.translate(new Vec( cos,  0,  sin)),
644                     Matrix.translate(new Vec(-cos,  0, -sin)),
645                     Matrix.translate(new Vec( cos,  0, -sin)),
646                     Matrix.translate(new Vec( 0,  height, z)),
647                     Matrix.translate(new Vec(-r,  height, -x)),
648                     Matrix.translate(new Vec( r,  height, -x)),
649                     Matrix.translate(new Vec( 0, -height, -z)),
650                     Matrix.translate(new Vec(-r, -height, x)),
651                     Matrix.translate(new Vec( r, -height, x)),
652                     Matrix.ONE,
653                 };
654                 generateTile(transforms, tile);
655                 fixupTile();
656             } });
657
658             tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
659                 setTile(new Mesh(false));
660                 float unit = 0.4f;
661                 float r = unit/2;
662                 float sin = (float)(unit * Math.sin(Math.PI/3));
663                 float cos = (float)(unit * Math.cos(Math.PI/3));
664                 float x = (float)(r*Math.tan(Math.PI/6));
665                 float z = (float)(r/Math.cos(Math.PI/6));
666                 float height = 2*r*(float)Math.sqrt(2f/3f);
667
668                 transforms = new Matrix[] {
669
670                     //Matrix.reflect(new Vec( 0,  height, -z).norm()),
671
672                     Matrix.translate(new Vec(-unit, 0, 0)),
673                     Matrix.translate(new Vec( unit, 0, 0)),
674                     Matrix.translate(new Vec(-cos,  0,  sin)),
675                     Matrix.translate(new Vec( cos,  0,  sin)),
676                     Matrix.translate(new Vec(-cos,  0, -sin)),
677                     Matrix.translate(new Vec( cos,  0, -sin)),
678
679                     Matrix.translate(new Vec( 0,  height, -z)),
680                     Matrix.translate(new Vec(-r,  height,  x)),
681                     Matrix.translate(new Vec( r,  height,  x)),
682                     Matrix.translate(new Vec( 0, -height,  z)),
683                     Matrix.translate(new Vec(-r, -height, -x)),
684                     Matrix.translate(new Vec( r, -height, -x)),
685
686                     /*
687                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
688                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
689                     Matrix.translate(new Vec( r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
690                     Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
691                     Matrix.translate(new Vec(-r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
692                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
693                     */
694
695                     /*
696                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.scale(-1,1,-1)),
697                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.scale(-1,1,-1)),
698                     Matrix.translate(new Vec( r,  height,  x)).times(Matrix.scale(-1,1,-1)),
699                     Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.scale(-1,1,-1)),
700                     Matrix.translate(new Vec(-r, -height,  x)).times(Matrix.scale(-1,1,-1)),
701                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.scale(-1,1,-1)),
702                     */
703                     Matrix.ONE
704                 };
705                 generateTile(transforms, tile);
706
707
708                 transforms = new Matrix[] {
709                     Matrix.reflect(new Vec( 0,  height, -z).norm()),
710                     //Matrix.reflect(new Vec( 0, -height,  z)),
711                     Matrix.ONE,
712                     Matrix.translate(new Vec(-unit, 0, 0)),
713                     Matrix.translate(new Vec( unit, 0, 0)),
714                     /*
715                     Matrix.translate(new Vec(-cos,  0,  sin)),
716                     Matrix.translate(new Vec( cos,  0,  sin)),
717                     Matrix.translate(new Vec(-cos,  0, -sin)),
718                     Matrix.translate(new Vec( cos,  0, -sin)),
719
720                     Matrix.translate(new Vec( 0,  height, -z)),
721                     Matrix.translate(new Vec(-r,  height,  x)),
722                     Matrix.translate(new Vec( r,  height,  x)),
723                     Matrix.translate(new Vec( 0, -height,  z)),
724                     Matrix.translate(new Vec(-r, -height, -x)),
725                     Matrix.translate(new Vec( r, -height, -x)),
726                     */
727                 };
728
729
730                 //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
731
732                 Matrix m = Matrix.scale(1.9f, 1f ,1);
733                 //Matrix m = Matrix.scale(1f, 2.1f, 1f);
734                 tile.transform(m);
735                 for(int i=0; i<transforms.length; i++)
736                     transforms[i] = preMultiplyTranslationalComponentBy(transforms[i], m);
737
738
739                 fixupTile();
740
741             } });
742             tileMenu.add(new MyMenuItem("Genus-1") { public void hit() {
743                 synchronized(this) {
744                     setTile(new Mesh(false));
745                     Matrix mm = Matrix.scale(0.1f);
746                     float height = 4;
747                     float width  = 4;
748                     float depth  = 1;
749                     // top
750                     quad(tile, mm, 
751                          new Point( 2,  2,  0),
752                          new Point( 1,  1, -1),
753                          new Point(-1,  1, -1),
754                          new Point(-2,  2,  0));
755                     quad(tile, mm, 
756                          new Point(-2,  2,  0),
757                          new Point(-1,  1,  1),
758                          new Point( 1,  1,  1),
759                          new Point( 2,  2,  0));
760                     quad(tile, mm, 
761                          new Point( 1,  1, -1),
762                          new Point( 1,  1,  1),
763                          new Point(-1,  1,  1),
764                          new Point(-1,  1, -1));
765
766                     // bottom
767                     quad(tile, mm, 
768                          new Point(-2, -2,  0),
769                          new Point(-1, -1, -1),
770                          new Point( 1, -1, -1),
771                          new Point( 2, -2,  0));
772                     quad(tile, mm, 
773                          new Point( 2, -2,  0),
774                          new Point( 1, -1,  1),
775                          new Point(-1, -1,  1),
776                          new Point(-2, -2,  0));
777                     quad(tile, mm, 
778                          new Point(-1, -1, -1),
779                          new Point(-1, -1,  1),
780                          new Point( 1, -1,  1),
781                          new Point( 1, -1, -1));
782
783                     // left
784                     quad(tile, mm, 
785                          new Point( 2, -2,  0),
786                          new Point( 1, -1, -1),
787                          new Point( 1,  1, -1),
788                          new Point( 2,  2,  0));
789                     quad(tile, mm, 
790                          new Point( 2,  2,  0),
791                          new Point( 1,  1,  1),
792                          new Point( 1, -1,  1),
793                          new Point( 2, -2,  0));
794                     quad(tile, mm, 
795                          new Point( 1, -1, -1),
796                          new Point( 1, -1,  1),
797                          new Point( 1,  1,  1),
798                          new Point( 1,  1, -1));
799
800                     // bottom
801                     quad(tile, mm, 
802                          new Point(-2,  2,  0),
803                          new Point(-1,  1, -1),
804                          new Point(-1, -1, -1),
805                          new Point(-2, -2,  0));
806                     quad(tile, mm, 
807                          new Point(-2, -2,  0),
808                          new Point(-1, -1,  1),
809                          new Point(-1,  1,  1),
810                          new Point(-2,  2,  0));
811                     quad(tile, mm, 
812                          new Point(-1,  1, -1),
813                          new Point(-1,  1,  1),
814                          new Point(-1, -1,  1),
815                          new Point(-1, -1, -1));
816
817                     height = 4;
818                     width  = 4;
819                     depth  = 1;
820
821
822                     transforms = new Matrix[] {
823                         Matrix.translate(new Vec(0, 0.2f,0))
824                         .times(Matrix.rotate(new Vec(0,1,0), (float)(1*Math.PI/2))),
825
826                         Matrix.translate(new Vec(0,-0.2f,0))
827                         .times(Matrix.rotate(new Vec(0,1,0), (float)(-1*Math.PI/2))),
828
829                         Matrix.translate(new Vec( 0.2f,0,0))
830                         .times(Matrix.rotate(new Vec(1,0,0), (float)(1*Math.PI/2))),
831
832                         Matrix.translate(new Vec(-0.2f,0,0))
833                         .times(Matrix.rotate(new Vec(1,0,0), (float)(-1*Math.PI/2))),
834
835
836                         //Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
837
838                         /*
839                           Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
840
841                           Matrix.rotate(new Vec(0,0,1), (float)(3*Math.PI/2)),
842                           Matrix.rotate(new Vec(1,0,0), (float)(2*Math.PI/2)),
843                         */
844
845                         //Matrix.rotate(new Vec(0,0,1), (float)(2*Math.PI/2)),
846                         //Matrix.scale(1,-1,1),
847
848                         //Matrix.translate(new Vec( 0.2f, 0,0))
849                         //.times(Matrix.rotate(new Vec(0,0,1), (float)( 1*Math.PI/2)))
850                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*Math.PI/2))),
851
852                         //Matrix.translate(new Vec(-0.2f, 0,0))
853                         //.times(Matrix.rotate(new Vec(0,0,1), (float)( 3*Math.PI/2)))
854                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*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)( 1*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.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
864                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
865                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
866                         //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
867                         //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
868                         //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
869
870                         Matrix.ONE,
871                     };
872                     fixupTile();
873                 }}});
874             tileMenu.add(new MyMenuItem("Hammerhead") { public void hit() {
875                 synchronized(this) {
876                     setTile(new Mesh(false));
877                     Matrix mm = Matrix.ONE;
878                     float height1 = .1f;
879                     float height2 = .1f;
880                     float width  = .4f;
881                     float depth  = .1f;
882                     // top
883                     Point a1 = new Point( -width/2,         height2/2, -depth/2);
884                     Point b1 = new Point(        0,         height2/2, -depth/2);
885                     Point c1 = new Point(        0, height1+height2/2, -depth/2);
886                     Point d1 = new Point(  width/2, height1+height2/2, -depth/2);
887                     Point e1 = new Point(  width/2,         height2/2, -depth/2);
888                     Point f1 = new Point(  width/2,        -height2/2, -depth/2);
889                     Point g1 = new Point(  width/2,-height1-height2/2, -depth/2);
890                     Point h1 = new Point(        0,-height1-height2/2, -depth/2);
891                     Point i1 = new Point(        0,        -height2/2, -depth/2);
892                     Point j1 = new Point( -width/2,        -height2/2, -depth/2);
893                     Point a2 = new Point( -width/2,         height2/2,  depth/2);
894                     Point b2 = new Point(        0,         height2/2,  depth/2);
895                     Point c2 = new Point(        0, height1+height2/2,  depth/2);
896                     Point d2 = new Point(  width/2, height1+height2/2,  depth/2);
897                     Point e2 = new Point(  width/2,         height2/2,  depth/2);
898                     Point f2 = new Point(  width/2,        -height2/2,  depth/2);
899                     Point g2 = new Point(  width/2,-height1-height2/2,  depth/2);
900                     Point h2 = new Point(        0,-height1-height2/2,  depth/2);
901                     Point i2 = new Point(        0,        -height2/2,  depth/2);
902                     Point j2 = new Point( -width/2,        -height2/2,  depth/2);
903
904                     quad(tile, mm, a1, b1, i1, j1);
905                     quad(tile, mm, c1, d1, e1, b1);
906                     quad(tile, mm, b1, e1, f1, i1);
907                     quad(tile, mm, i1, f1, g1, h1);
908
909                     quad(tile, mm, j2, i2, b2, a2);
910                     quad(tile, mm, b2, e2, d2, c2);
911                     quad(tile, mm, i2, f2, e2, b2);
912                     quad(tile, mm, h2, g2, f2, i2);
913
914                     quad(tile, mm, d1, d2, e2, e1);
915                     quad(tile, mm, e1, e2, f2, f1);
916                     quad(tile, mm, f1, f2, g2, g1);
917                     quad(tile, mm, h1, g1, g2, h2);
918                     quad(tile, mm, i2, i1, h1, h2);
919                     quad(tile, mm, j1, i1, i2, j2);
920                     quad(tile, mm, a2, a1, j1, j2);
921                     quad(tile, mm, a1, a2, b2, b1);
922                     quad(tile, mm, c2, c1, b1, b2);
923                     quad(tile, mm, c1, c2, d2, d1);
924
925                     transforms = new Matrix[] {
926
927                         mm.times(Matrix.translate(new Vec(   width,     0, 0))),
928                         mm.times(Matrix.translate(new Vec(  -width,     0, 0))),
929                         mm.times(Matrix.translate(new Vec(-width/2, height1+height2, 0))),
930                         mm.times(Matrix.translate(new Vec( width/2, height1+height2, 0))),
931                         mm.times(Matrix.translate(new Vec(-width/2,-height1-height2, 0))),
932                         mm.times(Matrix.translate(new Vec( width/2,-height1-height2, 0))),
933
934                         mm.times(Matrix.translate(new Vec(   width/2,     0,  depth))),
935                         mm.times(Matrix.translate(new Vec(  -width/2,     0,  depth))),
936                         mm.times(Matrix.translate(new Vec(         0, height1+height2,  depth))),
937                         mm.times(Matrix.translate(new Vec(         0,-height1-height2,  depth))),
938
939                         mm.times(Matrix.translate(new Vec(   width/2,     0, -depth))),
940                         mm.times(Matrix.translate(new Vec(  -width/2,     0, -depth))),
941                         mm.times(Matrix.translate(new Vec(         0, height1+height2, -depth))),
942                         mm.times(Matrix.translate(new Vec(         0,-height1-height2, -depth))),
943
944                         Matrix.ONE
945                     };
946                     fixupTile();
947                 }}});
948             tileMenu.add(new MyMenuItem("Marching Cubes") { public void hit() {
949                 marchingCubes();
950             }});
951
952             // Finally, add all the menus to the menu bar.
953             add(tileMenu);
954             //add(goalMenu);
955             //add(hideMenu);
956         }
957
958     }
959
960     private static Matrix preMultiplyTranslationalComponentBy(Matrix mthis, Matrix mm) {
961         Vec v = mm.times(mthis.getTranslationalComponent());
962         return new Matrix(mthis.a, mthis.b, mthis.c, v.x,
963                           mthis.e, mthis.f, mthis.g, v.y,
964                           mthis.i, mthis.j, mthis.k, v.z,
965                           mthis.m, mthis.n, mthis.o, 1);
966     }
967
968 //////////////////////////////////////////////////////////////////////////////
969     public void breakit() {
970         int oldverts = verts;
971         if (verts > 2000 && !force) return;
972         force = false;
973         System.out.println("doubling vertices.");
974         PriorityQueue<Mesh.E> es = new PriorityQueue<Mesh.E>();
975         for(Mesh.T t : tile) {
976             es.add(t.e1());
977             es.add(t.e2());
978             es.add(t.e3());
979             Thread.yield();
980             repaint();
981         }
982         for(int i=0; i<Math.min(oldverts,50); i++) {
983             Mesh.E e = es.poll();
984             verts++;
985             e.shatter();
986             Thread.yield();
987             repaint();
988         }
989         System.out.println("now have " + verts + " vertices; max is 2000");
990         tile.rebindPoints();
991     }
992
993     public boolean rand(double temp, Mesh.Vertex p) {
994
995         p.reComputeErrorAround();
996         double tile_error = tile.error();
997         double goal_error = goal.error();
998
999         float max = p.averageEdgeLength()/5;
1000         Vec v = new Vec(random.nextFloat(), random.nextFloat(), random.nextFloat());
1001         v = v.norm().times((random.nextFloat() - 0.5f) * max);
1002         Matrix m = Matrix.translate(v);
1003         boolean good = p.move(v, false);
1004         if (!good) { return false; }
1005
1006         double new_tile_error = tile.error();
1007         double new_goal_error = goal.error();
1008         double tile_delta = (new_tile_error - tile_error) / tile_error;
1009         double goal_delta = (new_goal_error - goal_error) / goal_error;
1010         double delta = tile_delta + goal_delta;
1011         double swapProbability = Math.exp((-1 * delta) / temp);
1012
1013         //boolean doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
1014         //boolean doSwap = good && (tile_delta + goal_delta <= 0);
1015         //if (temp < 0.000001) doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
1016         boolean doSwap = good && (Math.random() < swapProbability);
1017
1018         // always move uphill if possible -- potential idea
1019         if (tile_delta <= 0 && goal_delta <= 0 && good) doSwap = true;
1020         if (hillclimb)
1021             doSwap = tile_delta <= 0 && goal_delta <= 0 && good;
1022
1023         if (doSwap) {
1024             tile_error = new_tile_error;
1025             goal_error = new_goal_error;
1026             hits++;
1027             p.goodp = p.p;
1028         } else {
1029             p.move(v.times(-1), true);
1030             misses++;
1031         }
1032         p.reComputeErrorAround();
1033         return true;
1034     }
1035
1036     float hits = 0;
1037     float misses = 0;
1038     public void anneal() throws Exception {
1039         double hightemp = 1;
1040         temp = hightemp;
1041         double last = 10;
1042         boolean seek_upward = false;
1043         double acceptance = 1;
1044         while(true) {
1045             synchronized(this) {
1046                 if (!anneal) { repaint(); Thread.sleep(10); continue; }
1047
1048             double ratio = (hits+misses==0) ? 1 : (hits / (hits+misses));
1049             hits = 0;
1050             misses = 0;
1051             double gamma = 1;
1052             acceptance = (ratio+acceptance)/2;
1053             accepts = (int)(Math.ceil(ratio*100));
1054             temps = (int)(Math.ceil(temp*1000));
1055             vertss = tile.size();
1056             if (breaks > 0) {
1057                 while (breaks>0) {
1058                     breaks--;
1059                     breakit();
1060                 }
1061                 seek_upward = true;
1062                 continue;
1063             } else if (acceptance > 0.96) gamma = 0.1f;
1064             else if (acceptance > 0.9)    gamma = 0.2f;
1065             else if (acceptance > 0.8)    gamma = 0.3f;
1066             else if (acceptance > 0.6)    gamma = 0.4f;
1067             else if (acceptance > 0.3)    gamma = 0.8f;
1068             else if (acceptance > 0.15)   gamma = 0.94f;
1069             else if (acceptance > 0.10)   gamma = 0.98f;
1070
1071             else if (acceptance < 0.01)   breaks++;
1072
1073             if (seek_upward) {
1074                 if (acceptance > 0.25) seek_upward = false;
1075                 else gamma = 2-gamma;
1076             }
1077
1078             if (anneal)
1079                 temp = temp * gamma;
1080
1081
1082             HashSet<Mesh.Vertex> hs = new HashSet<Mesh.Vertex>();
1083             for(Mesh.Vertex p : tile.vertices()) hs.add(p);
1084             Mesh.Vertex[] pts = (Mesh.Vertex[])hs.toArray(new Mesh.Vertex[0]);
1085
1086             int count = 0;
1087             long then = System.currentTimeMillis();
1088             for(int i=0; i<300; i++) {
1089                 if (anneal) {
1090                     Mesh.Vertex v = pts[Math.abs(random.nextInt()) % pts.length];
1091                     if (breaks>0) break;
1092                     if (!rand(temp,v)) { i--; continue; }
1093                     v.recomputeFundamentalQuadricIfStale();
1094                     v.recomputeFundamentalQuadricIfNeighborChanged();
1095                     count++;
1096                 }
1097                 Thread.yield();
1098                 repaint();
1099             }
1100
1101             System.out.println("temp="+temp + " ratio="+(Math.ceil(acceptance*100)) + " " +
1102                                "points_per_second=" +
1103                                (count*1000)/((double)(System.currentTimeMillis()-then)));
1104             for(Mesh.Vertex p : goal.vertices()) {
1105                 p.quadricStale = true;
1106                 p.recomputeFundamentalQuadricIfNeighborChanged();
1107             }
1108             }
1109         }
1110     }
1111
1112
1113     public static void main(String[] s) throws Exception {
1114         JFrame f = new JFrame();
1115         f.setLayout(new BorderLayout());
1116         Main main = new Main(f);
1117         f.add(main, BorderLayout.CENTER);
1118
1119         f.addWindowListener(new WindowListener() {
1120                 public void windowActivated(WindowEvent e) { }
1121                 public void windowClosed(WindowEvent e) { System.exit(0); }
1122                 public void windowClosing(WindowEvent e) { System.exit(0); }
1123                 public void windowDeactivated(WindowEvent e)  { }
1124                 public void windowDeiconified(WindowEvent e)  { }
1125                 public void windowIconified(WindowEvent e)  { }
1126                 public void windowOpened(WindowEvent e) { }
1127             });
1128
1129         f.pack();
1130         f.show();
1131         f.setSize(900, 900);
1132         f.doLayout();
1133
1134         JFrame f2 = new JFrame();
1135         f2.setJMenuBar(main.new MyMenuBar());
1136         f2.setSize(100,100);
1137         f2.show();
1138
1139         main.anneal();
1140     }
1141
1142
1143 }