checkpoint
authoradam <adam@megacz.com>
Mon, 7 Jul 2008 20:41:38 +0000 (13:41 -0700)
committeradam <adam@megacz.com>
Mon, 7 Jul 2008 20:41:38 +0000 (13:41 -0700)
darcs-hash:20080707204138-5007d-081fd1526ff05363314d982e9dc3674f1e4e442c.gz

src/edu/berkeley/qfat/InteractiveMeshViewer.java
src/edu/berkeley/qfat/Main.java
src/edu/berkeley/qfat/Mesh.java
src/edu/berkeley/qfat/MeshViewer.java

index 068dc56..f87f257 100644 (file)
@@ -66,26 +66,6 @@ public class InteractiveMeshViewer extends JPanel implements KeyListener {
         for(MeshViewer mv : mvs) mv.addMesh(this.goal);
     }
 
-    public synchronized void dump() {
-        try {
-            PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("dump.stl")));
-            pw.println("solid dump");
-            for(Mesh.T t : tile) {
-                Vec normal = t.norm();
-                pw.println("facet normal " + normal.x + " " + normal.y + " " + normal.z);
-                pw.println("  outer loop");
-                for(Mesh.Vertex v : new Mesh.Vertex[] { t.v1(), t.v2(), t.v3() }) {
-                    pw.println("    vertex " + v.p.x + " " + v.p.y + " " + v.p.z);
-                }
-                pw.println("  endloop");
-                pw.println("endfacet");
-            }
-            pw.println("endsolid dump");
-            pw.flush();
-            pw.close();
-        } catch (Exception e) { throw new RuntimeException(e); }
-    }
-
     public int whichNeighbor = 1;
     public double temp;
     public boolean tileon = true;
@@ -99,7 +79,6 @@ public class InteractiveMeshViewer extends JPanel implements KeyListener {
     public boolean errorNormals = false;
 
     public boolean force = false;
-    public Mesh.Vertex[] points;
     public int breaks = 0;
 
     public int temps;
@@ -112,7 +91,6 @@ public class InteractiveMeshViewer extends JPanel implements KeyListener {
         //super.keyPressed(e);
         switch(e.getKeyCode()) {
             case KeyEvent.VK_SPACE:
-                System.err.println("hak");
                 synchronized(this) {
                     tile.subdivide();
                     tile.rebindPoints();
@@ -123,7 +101,13 @@ public class InteractiveMeshViewer extends JPanel implements KeyListener {
             case KeyEvent.VK_ENTER: temp = 10; break;
             case KeyEvent.VK_N: whichNeighbor++; break;
             case KeyEvent.VK_RIGHT: whichNeighbor++; break;
-            case KeyEvent.VK_D: dump(); break;
+            case KeyEvent.VK_D:
+                try {
+                    tile.dump(new FileOutputStream("dump.stl"));
+                } catch (Exception ee) {
+                    throw new RuntimeException(ee);
+                }
+                break;
             case KeyEvent.VK_E: errorNormals = !errorNormals; break;
             case KeyEvent.VK_A: hillclimb = false; anneal = !anneal; break;
             case KeyEvent.VK_H: anneal = true; hillclimb = !hillclimb; break;
index 237266b..b7df3d4 100644 (file)
@@ -14,13 +14,6 @@ import edu.berkeley.qfat.geom.Polygon;
 
 // TO DO:
 //
-// - Implement "real" constraints (plane, line, point)
-//
-// - Constrained surface subdivision
-//     - Edge.flip() gets us the triforce subdivision
-//     - Edge.delete() gets us the catmull-clark subdivision
-//     - Catmull-Clark: just don't move points if we can't.  Need to average the influence of the points on a binding group.
-//
 // - Ability to snap three views to orthgonal
 // - SLIDE UI
 //     - left button -> crystal ball
@@ -32,28 +25,11 @@ import edu.berkeley.qfat.geom.Polygon;
 // Editing:
 //  - fracture edge, face
 //  - change aspect ratio
+//  - translate, rotate goal mesh
 //  - ability to select a point, rotate the model, then move the point
 //  - when moving a vertex in one window, show that window's axes in all other windows
 //
 
-
-// TO DO:
-// - real anneal
-// - solve self-intersection problem
-// - get a better test model?
-// - symmetry constraints withing the tile
-// - rotation matrices
-// - overbinding results in forced equational constraints on the leader
-// - shatter in invertd-triforce pattern brian mentioned
-// - aspect ratio?  non-uniform deformation?
-// - rotational alignment
-
-// - movie-style user interface like
-//      http://www.coleran.com/markcoleranreell.html ?
-
-// - consider recasting the Shewchuk predicates in Java?
-//    http://www.cs.cmu.edu/afs/cs/project/quake/public/code/predicates.c
-
 /*
   blender keys
   - middle mouse = option+click
@@ -66,20 +42,39 @@ import edu.berkeley.qfat.geom.Polygon;
   wheel: zoom
   home: home view: take current angle, zoom to whole scnee
   5 = ortho vs non-ortho
-
 */
 
 /*
+Meshlab Notes:
+Log console
+  - blend-shaded overlay?  slick.
 
+face/vertex count
+rendering FPS
+ability to not draw edges between faces
 
- */
 
+three circumcircles showing crystal ball -- these don't get scaled
+axes?
 
-// FIXME: re-orient goal (how?)
+drawing modes:
+  - bounding box
+  - vertices
+  - edges
+  - visible-edges
+  - flat with or without edges
+  - shaded with or without edges
+  * contrasting-faces
 
-public class Main extends InteractiveMeshViewer {
 
+quadric decimation?
 
+show normals
+show bounding box
+show axes (big+fat)
+ */
+
+public class Main extends InteractiveMeshViewer {
 
     public static int verts = 1;
 
@@ -229,162 +224,6 @@ public class Main extends InteractiveMeshViewer {
         fixupGoal();
     }
 
-    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.setJMenuBar(main.new MyMenuBar());
-        f.pack();
-        f.show();
-        f.setSize(900, 900);
-        f.doLayout();
-        main.anneal();
-    }
 
     public class MyMenuItem extends JMenuItem implements ActionListener {
         public MyMenuItem(String s) {
@@ -1013,4 +852,163 @@ public class Main extends InteractiveMeshViewer {
                           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.setJMenuBar(main.new MyMenuBar());
+        f.pack();
+        f.show();
+        f.setSize(900, 900);
+        f.doLayout();
+        main.anneal();
+    }
+
+
 }
\ No newline at end of file
index 926a5b7..cca7321 100644 (file)
@@ -1,6 +1,7 @@
 package edu.berkeley.qfat;
 import java.awt.*;
 import java.util.*;
+import java.io.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.media.opengl.*;
@@ -1171,4 +1172,24 @@ public class Mesh implements Iterable<Mesh.T> {
             super.glVertices(gl, m);
         }
     }
+
+    // Dump /////////////////////////////////////////////////////////////////////////////
+
+    public void dump(OutputStream os) throws IOException {
+        PrintWriter pw = new PrintWriter(new OutputStreamWriter(os));
+        pw.println("solid dump");
+        for(Mesh.T t : this) {
+            Vec normal = t.norm();
+            pw.println("facet normal " + normal.x + " " + normal.y + " " + normal.z);
+            pw.println("  outer loop");
+            for(Mesh.Vertex v : new Mesh.Vertex[] { t.v1(), t.v2(), t.v3() }) {
+                pw.println("    vertex " + v.p.x + " " + v.p.y + " " + v.p.z);
+            }
+            pw.println("  endloop");
+            pw.println("endfacet");
+        }
+        pw.println("endsolid dump");
+        pw.flush();
+    }
+
 }
index d02470c..d7481e5 100644 (file)
@@ -12,11 +12,14 @@ import edu.berkeley.qfat.bind.*;
 import edu.berkeley.qfat.geom.*;
 import edu.berkeley.qfat.geom.Point;
 
+/**
+ *  A basic MeshViewer displays zero or more meshes to the user, in
+ *  wireframe or shaded panels.
+ */
 public class MeshViewer extends JPanel implements GLEventListener, MouseListener, MouseMotionListener, KeyListener, MouseWheelListener {
 
     Main main;
 
-
     private float tz = 0;
     private float anglex = 0;
     private float angley = 0;
@@ -55,10 +58,6 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
         float mat_specular[] = { 0.5f, 0.5f, 0.5f, 0.5f };
         float mat_shininess[] = { 50.0f };
         gl.glShadeModel(GL.GL_SMOOTH);
-        //gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat_specular, 0);
-        //gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular, 0);  
-        //gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, new float[] { 0.3f, 0.3f, 0.3f, 0.3f }, 0);  
-        //gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess, 0);
         gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, new float[] { 1.0f,    4.0f,  -10.0f, 0.0f }, 0);
         gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, new float[] { -10.0f, 10.0f,   10.0f, 0.0f }, 0);
         gl.glLightfv(GL.GL_LIGHT2, GL.GL_POSITION, new float[] { 10.0f, -10.0f,   10.0f, 0.0f }, 0);