96c5c06107d4eb6dd7b7d2cdb4e1813756a88b57
[anneal.git] / src / edu / berkeley / qfat / Main.java
1 package edu.berkeley.qfat;
2 import java.awt.*;
3 import java.awt.event.*;
4 import javax.swing.*;
5 import javax.media.opengl.*;
6 import javax.media.opengl.glu.*;
7 import java.util.*;
8 import edu.berkeley.qfat.geom.*;
9 import edu.berkeley.qfat.geom.Point;
10
11 // TO DO:
12 // - real anneal
13 // - solve self-intersection problem
14 // - get a better test model?
15
16 // FIXME: re-orient goal (how?)
17
18 public class Main extends MeshViewer {
19
20     public static int verts = 0;
21
22     public static final Random random = new Random();
23     
24     /** magnification factor */
25     private static final float MAG = 1;
26
27     public Main(StlFile stlf, Frame f) {
28         super(f);
29
30         for(int i=0; i<stlf.coordArray.length; i+=3) {
31             Point p0 = new Point(stlf.coordArray[i+0].x * MAG, stlf.coordArray[i+0].y * MAG, stlf.coordArray[i+0].z * MAG);
32             Point p1 = new Point(stlf.coordArray[i+1].x * MAG, stlf.coordArray[i+1].y * MAG, stlf.coordArray[i+1].z * MAG);
33             Point p2 = new Point(stlf.coordArray[i+2].x * MAG, stlf.coordArray[i+2].y * MAG, stlf.coordArray[i+2].z * MAG);
34             Vec n  = new Vec(stlf.normArray[i/3].x * MAG, stlf.normArray[i/3].y  * MAG, stlf.normArray[i/3].z * MAG);
35             Mesh.T t  = goal.newT(p0, p1, p2, n, 0);
36         }
37
38         // rotate to align major axis -- this probably needs to be done by a human.
39         goal.transform(new Matrix(new Vec(0, 0, 1), (float)(Math.PI/2)));
40
41         float goal_width  = goal.diagonal().dot(new Vec(1, 0, 0));
42         float goal_height = goal.diagonal().dot(new Vec(0, 1, 0));
43         float goal_depth  = goal.diagonal().dot(new Vec(0, 0, 1));
44
45         /*
46         float width  = (float)0.6;
47         float height = (float)0.08;
48         float depth  = (float)0.3;
49         */
50         float width  = (float)0.6;
51         float depth  = (float)0.08;
52         float height = (float)0.3;
53
54         float rshift = width/2;
55         float lshift = -(width/2);
56
57         translations = new Matrix[] {
58
59             new Matrix(new Vec(lshift,  depth,    0)),
60             new Matrix(new Vec(rshift,  depth,    0)),
61             new Matrix(new Vec(lshift, -depth,    0)),
62             new Matrix(new Vec(rshift, -depth,    0)),
63             new Matrix(new Vec(lshift,       0,  height)),
64             new Matrix(new Vec(rshift,       0,  height)),
65             new Matrix(new Vec(lshift,       0, -height)),
66             new Matrix(new Vec(rshift,       0, -height)),
67
68             new Matrix(new Vec( width,           0,    0)),
69             new Matrix(new Vec(-width,           0,    0)),
70
71             new Matrix(new Vec(     0,           0,    height)),
72             new Matrix(new Vec(     0,           0,   -height)),
73         };
74
75
76         Point ltf = new Point(lshift,  (depth/2),  (height/2));
77         Point mtf = new Point( 0.0,        (depth/2),  (height/2));
78         Point rtf = new Point(rshift,  (depth/2),  (height/2));
79         Point ltn = new Point(lshift,  (depth/2), -(height/2));
80         Point mtn = new Point( 0.0,        (depth/2), -(height/2));
81         Point rtn = new Point(rshift,  (depth/2), -(height/2));
82         Point lbf = new Point(lshift, -(depth/2),  (height/2));
83         Point mbf = new Point( 0.0,       -(depth/2),  (height/2));
84         Point rbf = new Point(rshift, -(depth/2),  (height/2));
85         Point lbn = new Point(lshift, -(depth/2), -(height/2));
86         Point mbn = new Point( 0.0,       -(depth/2), -(height/2));
87         Point rbn = new Point(rshift, -(depth/2), -(height/2));
88         
89         Point[] points = new Point[] {
90             ltf,
91             mtf,
92             rtf,
93             ltn,
94             mtn,
95             rtn,
96             lbf,
97             mbf,
98             rbf,
99             lbn,
100             mbn,
101             rbn
102         };
103
104
105         // top
106         tile.newT(ltf, mtf, mtn, null, 1);
107         tile.newT(mtn, ltn, ltf, null, 1);
108         tile.newT(mtf, rtf, rtn, null, 1);
109         tile.newT(rtn, mtn, mtf, null, 1);
110
111         // bottom (swap normals)
112         tile.newT(mbf, lbf, mbn, null, 2);
113         tile.newT(lbn, mbn, lbf, null, 2);
114         tile.newT(rbf, mbf, rbn, null, 2);
115         tile.newT(mbn, rbn, mbf, null, 2);
116         
117         // left
118         tile.newT(ltf, ltn, lbn, null, 3);
119         tile.newT(lbn, lbf, ltf, null, 3);
120
121         // right (swap normals)
122         tile.newT(rtn, rtf, rbn, null, 4);
123         tile.newT(rbf, rbn, rtf, null, 4);
124
125         // front
126         tile.newT(ltn, mtn, mbn, null, 5);
127         tile.newT(ltn, mbn, lbn, null, 5);
128         tile.newT(mtn, rtn, rbn, null, 5);
129         tile.newT(mtn, rbn, mbn, null, 5);
130
131         // back
132         tile.newT(mtf, ltf, mbf, null, 6);
133         tile.newT(mbf, ltf, lbf, null, 6);
134         tile.newT(rtf, mtf, rbf, null, 6);
135         tile.newT(rbf, mtf, mbf, null, 6);
136
137         for(Matrix m : translations) {
138             for(Mesh.T t1 : tile) {
139                 for(Mesh.T t2 : tile) {
140                     if (t1==t2) continue;
141
142                     if ((t1.v1().p.times(m).minus(t2.v1().p).mag() < Mesh.EPSILON) &&
143                         (t1.v2().p.times(m).minus(t2.v3().p).mag() < Mesh.EPSILON) &&
144                         (t1.v3().p.times(m).minus(t2.v2().p).mag() < Mesh.EPSILON)) {
145                         t1.e1().bindEdge(t2.e3());
146                         t1.e2().bindEdge(t2.e2());
147                         t1.e3().bindEdge(t2.e1());
148                     }
149                     if ((t1.v2().p.times(m).minus(t2.v1().p).mag() < Mesh.EPSILON) &&
150                         (t1.v3().p.times(m).minus(t2.v3().p).mag() < Mesh.EPSILON) &&
151                         (t1.v1().p.times(m).minus(t2.v2().p).mag() < Mesh.EPSILON)) {
152                         t1.e2().bindEdge(t2.e3());
153                         t1.e3().bindEdge(t2.e2());
154                         t1.e1().bindEdge(t2.e1());
155                     }
156                     if ((t1.v3().p.times(m).minus(t2.v1().p).mag() < Mesh.EPSILON) &&
157                         (t1.v1().p.times(m).minus(t2.v3().p).mag() < Mesh.EPSILON) &&
158                         (t1.v2().p.times(m).minus(t2.v2().p).mag() < Mesh.EPSILON)) {
159                         t1.e3().bindEdge(t2.e3());
160                         t1.e1().bindEdge(t2.e2());
161                         t1.e2().bindEdge(t2.e1());
162                     }
163                 }
164             }
165         }
166
167         //xMesh.Vert mid = lbf.getE(mbn).shatter();
168
169         // rescale to match volume
170         float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
171         goal.transform(new Matrix(factor));
172
173         // translate to match centroid
174         goal.transform(new Matrix(tile.centroid().minus(goal.centroid())));
175
176         //tx.e2.shatter();
177         //tx.e3.shatter();
178
179
180         tile.rebindPoints();
181
182         //mid.move(new Vec((float)0,0,(float)-0.05));
183         //ltn.move(new Vec((float)0,0,(float)-0.05));
184
185         //mtf.move(new Vec(0, (float)-0.05, (float)0.05));
186
187
188         System.out.println("tile volume: " + tile.volume());
189         System.out.println("goal volume: " + goal.volume());
190
191         tile.score_against = goal;
192         goal.score_against = tile;
193     }
194
195     public synchronized void breakit() {
196         if (verts > 800) return;
197         //while(verts < 800) {
198         PriorityQueue<Mesh.E> es = new PriorityQueue<Mesh.E>();
199         for(Mesh.E e : tile.edges()) es.add(e);
200         for(int i=0; i<40; i++) {
201             Mesh.E e = es.poll();
202             verts++;
203             //System.out.println("shatter " + e);
204             e.shatter();
205             tile.rebindPoints();
206         }
207         //}
208     }
209
210     public synchronized void rand(double temperature, Mesh.Vert p) {
211         double tile_score = tile.score();
212         double goal_score = goal.score();
213         p.reComputeError();
214
215
216         Vec v = new Vec((random.nextFloat() - (float)0.5) / 1000,
217                         (random.nextFloat() - (float)0.5) / 1000,
218                         (random.nextFloat() - (float)0.5) / 1000);
219         /*
220         Matrix inv = p.errorQuadric();
221         Vec v = new Vec(inv.d, inv.h, inv.l).norm().times(1/(float)1000);
222         */
223         boolean good = p.move(v);
224         double new_tile_score = tile.score();
225         double new_goal_score = goal.score();
226         double tile_delta = new_tile_score - tile_score;
227         double goal_delta = 0;//new_goal_score - goal_score;
228         double delta = tile_delta + goal_delta;
229         //double swapProbability = Math.exp((-1 * delta) / temperature);
230         //boolean doSwap = Math.random() < swapProbability;
231         boolean doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
232         if (doSwap) {
233             tile_score = new_tile_score;
234             goal_score = new_goal_score;
235             //System.out.println("score: " + tile_score + " / " + goal_score);
236         } else {
237             p.move(v.times(-1));
238         }
239     }
240
241     public void anneal() throws Exception {
242         int verts = 0;
243         while(true) {
244             HashSet<Mesh.Vert> hs = new HashSet<Mesh.Vert>();
245             for(Mesh.Vert p : tile.vertices()) hs.add(p);
246             for(int i=0; i<10; i++) {
247                 repaint();
248                 for(Mesh.Vert v : hs) rand(10,v);
249             }
250             tile.rebuildPointSet();
251             repaint();
252             breakit();
253             repaint();
254             goal.unApplyQuadricToNeighborAll();
255             repaint();
256             tile.recomputeAllFundamentalQuadrics();
257             repaint();
258             goal.applyQuadricToNeighborAll();
259        }
260     }
261
262     public static void main(String[] s) throws Exception {
263         StlFile stlf = new StlFile();
264         stlf.load("simplefish.stl");
265         Frame f = new Frame();
266         Main main = new Main(stlf, f);
267         main.anneal();
268     }
269
270 }