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