+ private static Matrix preMultiplyTranslationalComponentBy(Matrix mthis, Matrix mm) {
+ Vec v = mm.times(mthis.getTranslationalComponent());
+ return new Matrix(mthis.a, mthis.b, mthis.c, v.x,
+ mthis.e, mthis.f, mthis.g, v.y,
+ mthis.i, mthis.j, mthis.k, v.z,
+ mthis.m, mthis.n, mthis.o, 1);
+ }
+
+//////////////////////////////////////////////////////////////////////////////
+ public void breakit() {
+ int oldverts = verts;
+ if (verts > 2000 && !force) return;
+ force = false;
+ System.out.println("doubling vertices.");
+ PriorityQueue<Mesh.E> es = new PriorityQueue<Mesh.E>();
+ for(Mesh.T t : tile) {
+ es.add(t.e1());
+ es.add(t.e2());
+ es.add(t.e3());
+ Thread.yield();
+ repaint();
+ }
+ for(int i=0; i<Math.min(oldverts,50); i++) {
+ Mesh.E e = es.poll();
+ verts++;
+ e.shatter();
+ Thread.yield();
+ repaint();
+ }
+ System.out.println("now have " + verts + " vertices; max is 2000");
+ tile.rebindPoints();
+ }
+
+ public boolean rand(double temp, Mesh.Vertex p) {
+
+ p.reComputeErrorAround();
+ double tile_error = tile.error();
+ double goal_error = goal.error();
+
+ float max = p.averageEdgeLength()/5;
+ Vec v = new Vec(random.nextFloat(), random.nextFloat(), random.nextFloat());
+ v = v.norm().times((random.nextFloat() - 0.5f) * max);
+ Matrix m = Matrix.translate(v);
+ boolean good = p.move(v, false);
+ if (!good) { return false; }
+
+ double new_tile_error = tile.error();
+ double new_goal_error = goal.error();
+ double tile_delta = (new_tile_error - tile_error) / tile_error;
+ double goal_delta = (new_goal_error - goal_error) / goal_error;
+ double delta = tile_delta + goal_delta;
+ double swapProbability = Math.exp((-1 * delta) / temp);
+
+ //boolean doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
+ //boolean doSwap = good && (tile_delta + goal_delta <= 0);
+ //if (temp < 0.000001) doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
+ boolean doSwap = good && (Math.random() < swapProbability);
+
+ // always move uphill if possible -- potential idea
+ if (tile_delta <= 0 && goal_delta <= 0 && good) doSwap = true;
+ if (hillclimb)
+ doSwap = tile_delta <= 0 && goal_delta <= 0 && good;
+
+ if (doSwap) {
+ tile_error = new_tile_error;
+ goal_error = new_goal_error;
+ hits++;
+ p.goodp = p.p;
+ } else {
+ p.move(v.times(-1), true);
+ misses++;
+ }
+ p.reComputeErrorAround();
+ return true;
+ }
+
+ float hits = 0;
+ float misses = 0;
+ public void anneal() throws Exception {
+ double hightemp = 1;
+ temp = hightemp;
+ double last = 10;
+ boolean seek_upward = false;
+ double acceptance = 1;
+ while(true) {
+ synchronized(this) {
+ if (!anneal) { repaint(); Thread.sleep(10); continue; }
+
+ double ratio = (hits+misses==0) ? 1 : (hits / (hits+misses));
+ hits = 0;
+ misses = 0;
+ double gamma = 1;
+ acceptance = (ratio+acceptance)/2;
+ accepts = (int)(Math.ceil(ratio*100));
+ temps = (int)(Math.ceil(temp*1000));
+ vertss = tile.size();
+ if (breaks > 0) {
+ while (breaks>0) {
+ breaks--;
+ breakit();
+ }
+ seek_upward = true;
+ continue;
+ } else if (acceptance > 0.96) gamma = 0.1f;
+ else if (acceptance > 0.9) gamma = 0.2f;
+ else if (acceptance > 0.8) gamma = 0.3f;
+ else if (acceptance > 0.6) gamma = 0.4f;
+ else if (acceptance > 0.3) gamma = 0.8f;
+ else if (acceptance > 0.15) gamma = 0.94f;
+ else if (acceptance > 0.10) gamma = 0.98f;
+
+ else if (acceptance < 0.01) breaks++;
+
+ if (seek_upward) {
+ if (acceptance > 0.25) seek_upward = false;
+ else gamma = 2-gamma;
+ }
+
+ if (anneal)
+ temp = temp * gamma;
+
+
+ HashSet<Mesh.Vertex> hs = new HashSet<Mesh.Vertex>();
+ for(Mesh.Vertex p : tile.vertices()) hs.add(p);
+ Mesh.Vertex[] pts = (Mesh.Vertex[])hs.toArray(new Mesh.Vertex[0]);
+
+ int count = 0;
+ long then = System.currentTimeMillis();
+ for(int i=0; i<300; i++) {
+ if (anneal) {
+ Mesh.Vertex v = pts[Math.abs(random.nextInt()) % pts.length];
+ if (breaks>0) break;
+ if (!rand(temp,v)) { i--; continue; }
+ v.recomputeFundamentalQuadricIfStale();
+ v.recomputeFundamentalQuadricIfNeighborChanged();
+ count++;
+ }
+ Thread.yield();
+ repaint();
+ }
+
+ System.out.println("temp="+temp + " ratio="+(Math.ceil(acceptance*100)) + " " +
+ "points_per_second=" +
+ (count*1000)/((double)(System.currentTimeMillis()-then)));
+ for(Mesh.Vertex p : goal.vertices()) {
+ p.quadricStale = true;
+ p.recomputeFundamentalQuadricIfNeighborChanged();
+ }
+ }
+ }
+ }
+
+
+ public static void main(String[] s) throws Exception {
+ JFrame f = new JFrame();
+ f.setLayout(new BorderLayout());
+ Main main = new Main(f);
+ f.add(main, BorderLayout.CENTER);
+
+ f.addWindowListener(new WindowListener() {
+ public void windowActivated(WindowEvent e) { }
+ public void windowClosed(WindowEvent e) { System.exit(0); }
+ public void windowClosing(WindowEvent e) { System.exit(0); }
+ public void windowDeactivated(WindowEvent e) { }
+ public void windowDeiconified(WindowEvent e) { }
+ public void windowIconified(WindowEvent e) { }
+ public void windowOpened(WindowEvent e) { }
+ });
+
+ f.pack();
+ f.show();
+ f.setSize(900, 900);
+ f.doLayout();
+
+ JFrame f2 = new JFrame();
+ f2.setJMenuBar(main.new MyMenuBar());
+ f2.setSize(100,100);
+ f2.show();
+
+ main.anneal();
+ }
+
+