package edu.berkeley.qfat;
import java.awt.*;
+import java.io.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.*;
// FIXME: re-orient goal (how?)
-public class Main extends MeshViewer {
+public class Main extends InteractiveMeshViewer {
+
+ public Matrix[] transforms;
public static int verts = 1;
HashSet<HalfSpace> halfSpaces = new HashSet<HalfSpace>();
HashSet<Polygon> polygons = new HashSet<Polygon>();
for(Matrix m : matrices) {
- Vec v = m.getTranslationalComponent();
- if (v.mag() < 0.0001) continue;
- v = v.times(0.5f);
- Point p = Point.ORIGIN.plus(v);
- Vec v0 = v;
- if (v.dot(Point.ORIGIN.minus(p)) < 0) v = v.times(-1);
-
- System.out.println(v);
- HalfSpace hs = new HalfSpace(p, v.norm());
- halfSpaces.add(hs);
- polygons.add(new Polygon(hs));
+ Vec v = m.getTranslationalComponent();
+ if (v.mag() < 0.0001) continue;
+ v = v.times(-1);
+ v = v.times(0.5f);
+ Point p = Point.ORIGIN.plus(v);
+ v = v.times(-1);
+
+ //System.out.println(v);
+ HalfSpace hs = new HalfSpace(p, v.norm());
+ halfSpaces.add(hs);
+ polygons.add(new Polygon(hs));
}
for(Polygon p : polygons) {
System.out.println(p.plane.norm + " " + p.plane.dvalue);
public void loadGoal(String file) {
try {
StlFile stlf = new StlFile();
- stlf.load(file);
- goal = new Mesh(false);
+ InputStream res = this.getClass().getClassLoader().getResourceAsStream(file);
+ stlf.readBinaryFile(file, res);
+ setGoal(new Mesh(false));
for(int i=0; i<stlf.coordArray.length; i+=3) {
Point p0 = new Point(stlf.coordArray[i+0].x * MAG, stlf.coordArray[i+0].y * MAG, stlf.coordArray[i+0].z * MAG);
Point p1 = new Point(stlf.coordArray[i+1].x * MAG, stlf.coordArray[i+1].y * MAG, stlf.coordArray[i+1].z * MAG);
Point p2 = new Point(stlf.coordArray[i+2].x * MAG, stlf.coordArray[i+2].y * MAG, stlf.coordArray[i+2].z * MAG);
- Vec n = new Vec(stlf.normArray[i/3].x * MAG, stlf.normArray[i/3].y * MAG, stlf.normArray[i/3].z * MAG);
+ Vec n = new Vec(stlf.normArray[i/3].x * MAG, stlf.normArray[i/3].y * MAG, stlf.normArray[i/3].z * MAG);
Mesh.T t = goal.newT(p0, p1, p2, n, 0);
}
float goal_width = goal.diagonal().dot(new Vec(1, 0, 0));
} catch (Exception e) { throw new RuntimeException(e);}
}
- public void fixupGoal() {
+ public void fixupGoal() { fixupGoal(true, true); }
+ public void fixupGoal(boolean recenter, boolean lock) {
// translate to match centroid
- goal.transform(Matrix.translate(tile.centroid().minus(goal.centroid())));
- goal.makeVerticesImmutable();
- tile.error_against = goal;
- goal.error_against = tile;
+ if (recenter)
+ goal.transform(Matrix.translate(tile.centroid().minus(goal.centroid())));
+ if (lock) {
+ goal.makeVerticesImmutable();
+ tile.error_against = goal;
+ goal.error_against = tile;
+ }
}
public Main(JFrame f) { super(f); }
- public void fixupTile() {
- synchronized(safeTriangles) {
+ public synchronized void fixupTile() {
for(Matrix m1 : transforms) {
for(Matrix m2 : transforms) {
if (m1==m2) continue;
for(Mesh.T t2 : tile) {
Matrix m = m1.inverse().times(m2);
- if ((t1.v1().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v2().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON) &&
- (t1.v3().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON)) {
+ Point t1v1 = m.times(t1.v1().p);
+ Point t1v2 = m.times(t1.v2().p);
+ Point t1v3 = m.times(t1.v3().p);
+ if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v2.distance(t2.v3().p) < MATCHING_EPSILON &&
+ t1v3.distance(t2.v2().p) < MATCHING_EPSILON) {
t2.e3().bindEdge(t1.e1(), m);
t2.e2().bindEdge(t1.e2(), m);
t2.e1().bindEdge(t1.e3(), m);
}
- if ((t1.v2().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v3().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON) &&
- (t1.v1().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON)) {
+ if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v3.distance(t2.v3().p) < MATCHING_EPSILON &&
+ t1v1.distance(t2.v2().p) < MATCHING_EPSILON) {
t2.e3().bindEdge(t1.e2(), m);
t2.e2().bindEdge(t1.e3(), m);
t2.e1().bindEdge(t1.e1(), m);
}
- if ((t1.v3().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v1().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON) &&
- (t1.v2().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON)) {
+ if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v1.distance(t2.v3().p) < MATCHING_EPSILON &&
+ t1v2.distance(t2.v2().p) < MATCHING_EPSILON) {
t2.e3().bindEdge(t1.e3(), m);
t2.e2().bindEdge(t1.e1(), m);
t2.e1().bindEdge(t1.e2(), m);
}
-
- if ((t1.v1().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v2().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON) &&
- (t1.v3().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON)) {
+ if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v2.distance(t2.v2().p) < MATCHING_EPSILON &&
+ t1v3.distance(t2.v3().p) < MATCHING_EPSILON) {
t2.e1().bindEdge(t1.e1().pair, m);
t2.e2().bindEdge(t1.e2().pair, m);
t2.e3().bindEdge(t1.e3().pair, m);
}
- if ((t1.v2().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v3().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON) &&
- (t1.v1().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON)) {
+ if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v3.distance(t2.v2().p) < MATCHING_EPSILON &&
+ t1v1.distance(t2.v3().p) < MATCHING_EPSILON) {
t2.e2().bindEdge(t1.e1().pair, m);
t2.e3().bindEdge(t1.e2().pair, m);
t2.e1().bindEdge(t1.e3().pair, m);
}
- if ((t1.v3().p.times(m).distance(t2.v1().p) < MATCHING_EPSILON) &&
- (t1.v1().p.times(m).distance(t2.v2().p) < MATCHING_EPSILON) &&
- (t1.v2().p.times(m).distance(t2.v3().p) < MATCHING_EPSILON)) {
+ if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
+ t1v1.distance(t2.v2().p) < MATCHING_EPSILON &&
+ t1v2.distance(t2.v3().p) < MATCHING_EPSILON) {
t2.e3().bindEdge(t1.e1().pair, m);
t2.e1().bindEdge(t1.e2().pair, m);
t2.e2().bindEdge(t1.e3().pair, m);
}
-
}
}
}
tile.error_against = goal;
goal.error_against = tile;
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) {
Thread.yield();
repaint();
}
+ System.out.println("now have " + verts + " vertices; max is 2000");
tile.rebindPoints();
}
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(m, false);
+ boolean good = p.move(v, false);
if (!good) { return false; }
double new_tile_error = tile.error();
//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(Matrix.translate(v.times(-1)), true);
+ p.move(v.times(-1), true);
misses++;
}
p.reComputeErrorAround();
boolean seek_upward = false;
double acceptance = 1;
while(true) {
- synchronized(safeTriangles) {
- safeTriangles.clear();
- for(Mesh.T t : tile)
- if (t.shouldBeDrawn())
- safeTriangles.add(t);
- }
- if (!anneal) { repaint(); Thread.sleep(10); continue; }
+ synchronized(this) {
+ if (!anneal) { repaint(); Thread.sleep(10); continue; }
double ratio = (hits+misses==0) ? 1 : (hits / (hits+misses));
hits = 0;
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 { breaks++; }
+
+ else if (acceptance < 0.01) breaks++;
if (seek_upward) {
if (acceptance > 0.25) seek_upward = false;
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();
}
public void actionPerformed(ActionEvent event) {
synchronized(Main.this) {
- synchronized(safeTriangles) {
hit();
- }
}
}
public void hit() {}
}
public void hexBrick(boolean offset, boolean rotated) {
- tile = new Mesh(false);
+ setTile(new Mesh(false));
float width = (float)0.8;
float depth = (float)0.08;
float height = (float)0.4;
hideMenu.add(new MyMenuItem("Show All Neighbors Wireframe") { public void hit() { neighborsWire = true; neighborsWireOne = false;}});
hideMenu.add(new MyMenuItem("Hide Neighbors") { public void hit() { neighborsWire = false; neighborsWireOne = false; neighbors = false; }});
+ goalMenu.add(new MyMenuItem("Fish with face") { public void hit() {
+ loadGoal("face.stl");
+ //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
+ goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
+ //goal.transform(Matrix.scale(1, 2.2f, 1));
+ float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
+ //factor = factor * 0.8f;
+ goal.transform(Matrix.scale(0.3f));
+ //goal.transform(Matrix.rotate(new Vec(0,1,0), (float)(Math.PI*1/3)));
+ goal.transform(Matrix.rotate(new Vec(1,0,0), (float)(Math.PI*1/3)));
+ fixupGoal(true, false);
+ //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
+ fixupGoal(false, true);
+ }});
goalMenu.add(new MyMenuItem("Fish") { public void hit() {
loadGoal("fish.stl");
//goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
+ goal.transform(Matrix.scale(1, 2.2f, 1));
float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
+ factor = factor * 0.8f;
+ goal.transform(Matrix.scale(factor));
+ fixupGoal(true, false);
+ //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
+ fixupGoal(false, true);
+ }});
+ goalMenu.add(new MyMenuItem("Hammerhead Fish") { public void hit() {
+ loadGoal("fish.stl");
+ goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
+ goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(3*Math.PI/2)));
+ float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
+ factor *= 0.75f;
goal.transform(Matrix.scale(factor));
fixupGoal();
}});
goalMenu.add(new MyMenuItem("Torus") { public void hit() {
loadGoal("torus.stl");
float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
- goal.transform(Matrix.scale(factor/3.3f));
+ goal.transform(Matrix.scale(factor/2.5f));
goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
fixupGoal();
}});
hexBrick(false, true);
}});
tileMenu.add(new MyMenuItem("Temp (do not use)") { public void hit() {
- tile = new Mesh(false);
+ setTile(new Mesh(false));
float width = (float)0.8;
float depth = (float)0.08;
float height = (float)0.4;
};
fixupTile();
} });
- tileMenu.add(new MyMenuItem("Dense Packing (Hex)") { public void hit() {
- tile = new Mesh(false);
+ tileMenu.add(new MyMenuItem("Dense Packing (hex)") { public void hit() {
+ setTile(new Mesh(false));
float width = (float)3.2;
float depth = (float)0.32;
float height = (float)1.6;
generateTile(transforms, tile);
fixupTile();
} });
- tileMenu.add(new MyMenuItem("Slim Dense Packing (Hex)") { public void hit() {
- tile = new Mesh(false);
- float width = (float)3.2;
- float depth = (float)0.32;
- float height = (float)1.6;
+ tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
+ setTile(new Mesh(false));
float unit = 0.4f;
float r = unit/2;
float sin = (float)(unit * Math.sin(Math.PI/3));
float cos = (float)(unit * Math.cos(Math.PI/3));
float x = (float)(r*Math.tan(Math.PI/6));
float z = (float)(r/Math.cos(Math.PI/6));
- height = 2*r*(float)Math.sqrt(2f/3f);
-
-
- r *= 0.3f;
- cos *= 0.3f;
- unit *= 0.3f;
- height *= 1.5f;
+ float height = 2*r*(float)Math.sqrt(2f/3f);
- /*
- sin *= 0.3f;
- x *= 0.3f;
- z *= 0.3f;
- */
transforms = new Matrix[] {
Matrix.translate(new Vec(-unit, 0, 0)),
Matrix.translate(new Vec( unit, 0, 0)),
Matrix.translate(new Vec( cos, 0, sin)),
Matrix.translate(new Vec(-cos, 0, -sin)),
Matrix.translate(new Vec( cos, 0, -sin)),
- Matrix.translate(new Vec( 0, height, z)),
- Matrix.translate(new Vec(-r, height, -x)),
- Matrix.translate(new Vec( r, height, -x)),
- Matrix.translate(new Vec( 0, -height, -z)),
- Matrix.translate(new Vec(-r, -height, x)),
- Matrix.translate(new Vec( r, -height, x)),
- Matrix.ONE,
+
+ /*
+ Matrix.translate(new Vec( 0, height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ Matrix.translate(new Vec(-r, height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ Matrix.translate(new Vec( r, height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ Matrix.translate(new Vec(-r, -height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ Matrix.translate(new Vec( r, -height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
+ */
+
+ Matrix.translate(new Vec( 0, height, -z)),
+ Matrix.translate(new Vec(-r, height, x)),
+ Matrix.translate(new Vec( r, height, x)),
+ Matrix.translate(new Vec( 0, -height, z)),
+ Matrix.translate(new Vec(-r, -height, -x)),
+ Matrix.translate(new Vec( r, -height, -x)),
+ //Matrix.rotate(new Vec(0,0,1), (float)Math.PI),
+
+ /*
+ Matrix.translate(new Vec( 0, height, -z)).times(Matrix.scale(-1,1,-1)),
+ Matrix.translate(new Vec(-r, height, x)).times(Matrix.scale(-1,1,-1)),
+ Matrix.translate(new Vec( r, height, x)).times(Matrix.scale(-1,1,-1)),
+ Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.scale(-1,1,-1)),
+ Matrix.translate(new Vec(-r, -height, x)).times(Matrix.scale(-1,1,-1)),
+ Matrix.translate(new Vec( r, -height, x)).times(Matrix.scale(-1,1,-1)),
+ */
+ Matrix.ONE
};
generateTile(transforms, tile);
+ //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
+ Matrix m = Matrix.scale(1.9f, 1f ,1);
+ //Matrix m = Matrix.scale(1f, 2.1f, 1f);
+ tile.transform(m);
+ for(int i=0; i<transforms.length; i++)
+ transforms[i] = transforms[i].preMultiplyTranslationalComponentBy(m);
fixupTile();
+
} });
tileMenu.add(new MyMenuItem("Genus-1") { public void hit() {
synchronized(this) {
- tile = new Mesh(false);
+ setTile(new Mesh(false));
+ Matrix mm = Matrix.scale(0.1f);
float height = 4;
float width = 4;
float depth = 1;
- Matrix mm = Matrix.scale(0.1f);
// top
quad(tile, mm,
new Point( 2, 2, 0),
Matrix.translate(new Vec(-0.2f,0,0))
.times(Matrix.rotate(new Vec(1,0,0), (float)(-1*Math.PI/2))),
+
//Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
/*
};
fixupTile();
}}});
+ tileMenu.add(new MyMenuItem("Hammerhead") { public void hit() {
+ synchronized(this) {
+ setTile(new Mesh(false));
+ Matrix mm = Matrix.ONE;
+ float height1 = .1f;
+ float height2 = .1f;
+ float width = .4f;
+ float depth = .1f;
+ // top
+ Point a1 = new Point( -width/2, height2/2, -depth/2);
+ Point b1 = new Point( 0, height2/2, -depth/2);
+ Point c1 = new Point( 0, height1+height2/2, -depth/2);
+ Point d1 = new Point( width/2, height1+height2/2, -depth/2);
+ Point e1 = new Point( width/2, height2/2, -depth/2);
+ Point f1 = new Point( width/2, -height2/2, -depth/2);
+ Point g1 = new Point( width/2,-height1-height2/2, -depth/2);
+ Point h1 = new Point( 0,-height1-height2/2, -depth/2);
+ Point i1 = new Point( 0, -height2/2, -depth/2);
+ Point j1 = new Point( -width/2, -height2/2, -depth/2);
+ Point a2 = new Point( -width/2, height2/2, depth/2);
+ Point b2 = new Point( 0, height2/2, depth/2);
+ Point c2 = new Point( 0, height1+height2/2, depth/2);
+ Point d2 = new Point( width/2, height1+height2/2, depth/2);
+ Point e2 = new Point( width/2, height2/2, depth/2);
+ Point f2 = new Point( width/2, -height2/2, depth/2);
+ Point g2 = new Point( width/2,-height1-height2/2, depth/2);
+ Point h2 = new Point( 0,-height1-height2/2, depth/2);
+ Point i2 = new Point( 0, -height2/2, depth/2);
+ Point j2 = new Point( -width/2, -height2/2, depth/2);
+
+ quad(tile, mm, a1, b1, i1, j1);
+ quad(tile, mm, c1, d1, e1, b1);
+ quad(tile, mm, b1, e1, f1, i1);
+ quad(tile, mm, i1, f1, g1, h1);
+
+ quad(tile, mm, j2, i2, b2, a2);
+ quad(tile, mm, b2, e2, d2, c2);
+ quad(tile, mm, i2, f2, e2, b2);
+ quad(tile, mm, h2, g2, f2, i2);
+
+ quad(tile, mm, d1, d2, e2, e1);
+ quad(tile, mm, e1, e2, f2, f1);
+ quad(tile, mm, f1, f2, g2, g1);
+ quad(tile, mm, h1, g1, g2, h2);
+ quad(tile, mm, i2, i1, h1, h2);
+ quad(tile, mm, j1, i1, i2, j2);
+ quad(tile, mm, a2, a1, j1, j2);
+ quad(tile, mm, a1, a2, b2, b1);
+ quad(tile, mm, c2, c1, b1, b2);
+ quad(tile, mm, c1, c2, d2, d1);
+
+ transforms = new Matrix[] {
+
+ mm.times(Matrix.translate(new Vec( width, 0, 0))),
+ mm.times(Matrix.translate(new Vec( -width, 0, 0))),
+ mm.times(Matrix.translate(new Vec(-width/2, height1+height2, 0))),
+ mm.times(Matrix.translate(new Vec( width/2, height1+height2, 0))),
+ mm.times(Matrix.translate(new Vec(-width/2,-height1-height2, 0))),
+ mm.times(Matrix.translate(new Vec( width/2,-height1-height2, 0))),
+
+ mm.times(Matrix.translate(new Vec( width/2, 0, depth))),
+ mm.times(Matrix.translate(new Vec( -width/2, 0, depth))),
+ mm.times(Matrix.translate(new Vec( 0, height1+height2, depth))),
+ mm.times(Matrix.translate(new Vec( 0,-height1-height2, depth))),
+
+ mm.times(Matrix.translate(new Vec( width/2, 0, -depth))),
+ mm.times(Matrix.translate(new Vec( -width/2, 0, -depth))),
+ mm.times(Matrix.translate(new Vec( 0, height1+height2, -depth))),
+ mm.times(Matrix.translate(new Vec( 0,-height1-height2, -depth))),
+
+ Matrix.ONE
+ };
+ fixupTile();
+ }}});
// Finally, add all the menus to the menu bar.
add(tileMenu);