1 package edu.berkeley.qfat;
4 import java.awt.event.*;
6 import javax.media.opengl.*;
7 import javax.media.opengl.glu.*;
9 import edu.berkeley.qfat.geom.*;
10 import edu.berkeley.qfat.geom.Point;
11 import edu.berkeley.qfat.geom.Polygon;
15 // - solve self-intersection problem
16 // - get a better test model?
17 // - symmetry constraints withing the tile
18 // - rotation matrices
19 // - overbinding results in forced equational constraints on the leader
20 // - shatter in invertd-triforce pattern brian mentioned
21 // - aspect ratio? non-uniform deformation?
22 // - rotational alignment
24 // - movie-style user interface like
25 // http://www.coleran.com/markcoleranreell.html ?
27 // - consider recasting the Shewchuk predicates in Java?
28 // http://www.cs.cmu.edu/afs/cs/project/quake/public/code/predicates.c
32 - middle mouse = option+click
33 - right mouse = command+click
35 3,7,1 = view along axes (control for opp direction)
36 4, 8, 7, 2 = rotate in discrete increments (+control to translate)
37 middle trag: rotate space
38 shift+middle drag: translate space
40 home: home view: take current angle, zoom to whole scnee
41 5 = ortho vs non-ortho
51 // FIXME: re-orient goal (how?)
53 public class Main extends InteractiveMeshViewer {
55 public Matrix[] transforms;
57 public static int verts = 1;
59 public static final Random random = new Random();
61 /** magnification factor */
62 private static final float MAG = 1;
63 public static final float MATCHING_EPSILON = 0.001f;
65 private static boolean small(float f) { return Math.abs(f) < 0.001; }
66 public void generateTile(Matrix[] matrices, Mesh mesh) {
68 HashSet<HalfSpace> halfSpaces = new HashSet<HalfSpace>();
69 HashSet<Polygon> polygons = new HashSet<Polygon>();
70 for(Matrix m : matrices) {
71 Vec v = m.getTranslationalComponent();
72 if (v.mag() < 0.0001) continue;
75 Point p = Point.ORIGIN.plus(v);
78 //System.out.println(v);
79 HalfSpace hs = new HalfSpace(p, v.norm());
81 polygons.add(new Polygon(hs));
83 for(Polygon p : polygons) {
84 System.out.println(p.plane.norm + " " + p.plane.dvalue);
85 for(HalfSpace hs : halfSpaces) {
86 if (p.plane==hs) continue;
93 private void quad(Mesh mesh, Matrix m, Point p1_, Point p2_, Point p3_, Point p4_) {
94 Point p1 = m.times(p1_);
95 Point p2 = m.times(p2_);
96 Point p3 = m.times(p3_);
97 Point p4 = m.times(p4_);
98 Point c = new Point((p1.x+p2.x+p3.x+p4.x)/4,
99 (p1.y+p2.y+p3.y+p4.y)/4,
100 (p1.z+p2.z+p3.z+p4.z)/4);
101 mesh.newT(p1, p2, c, null, 0);
102 mesh.newT(p2, p3, c, null, 0);
103 mesh.newT(p3, p4, c, null, 0);
104 mesh.newT(p4, p1, c, null, 0);
107 public void loadGoal(String file) {
109 StlFile stlf = new StlFile();
110 InputStream res = this.getClass().getClassLoader().getResourceAsStream(file);
111 stlf.readBinaryFile(file, res);
112 setGoal(new Mesh(false));
113 for(int i=0; i<stlf.coordArray.length; i+=3) {
114 Point p0 = new Point(stlf.coordArray[i+0].x * MAG, stlf.coordArray[i+0].y * MAG, stlf.coordArray[i+0].z * MAG);
115 Point p1 = new Point(stlf.coordArray[i+1].x * MAG, stlf.coordArray[i+1].y * MAG, stlf.coordArray[i+1].z * MAG);
116 Point p2 = new Point(stlf.coordArray[i+2].x * MAG, stlf.coordArray[i+2].y * MAG, stlf.coordArray[i+2].z * MAG);
117 Vec n = new Vec(stlf.normArray[i/3].x * MAG, stlf.normArray[i/3].y * MAG, stlf.normArray[i/3].z * MAG);
118 Mesh.T t = goal.newT(p0, p1, p2, n, 0);
120 float goal_width = goal.diagonal().dot(new Vec(1, 0, 0));
121 float goal_height = goal.diagonal().dot(new Vec(0, 1, 0));
122 float goal_depth = goal.diagonal().dot(new Vec(0, 0, 1));
124 } catch (Exception e) { throw new RuntimeException(e);}
126 public void fixupGoal() { fixupGoal(true, true); }
127 public void fixupGoal(boolean recenter, boolean lock) {
128 // translate to match centroid
130 goal.transform(Matrix.translate(tile.centroid().minus(goal.centroid())));
132 goal.makeVerticesImmutable();
133 tile.error_against = goal;
134 goal.error_against = tile;
138 public Main(JFrame f) { super(f); }
140 public synchronized void fixupTile() {
141 for(Matrix m1 : transforms) {
142 for(Matrix m2 : transforms) {
143 if (m1==m2) continue;
144 for(Mesh.T t1 : tile) {
145 for(Mesh.T t2 : tile) {
147 Matrix m = m1.inverse().times(m2);
148 Point t1v1 = m.times(t1.v1().p);
149 Point t1v2 = m.times(t1.v2().p);
150 Point t1v3 = m.times(t1.v3().p);
151 if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
152 t1v2.distance(t2.v3().p) < MATCHING_EPSILON &&
153 t1v3.distance(t2.v2().p) < MATCHING_EPSILON) {
154 t2.e3().bindEdge(t1.e1(), m);
155 t2.e2().bindEdge(t1.e2(), m);
156 t2.e1().bindEdge(t1.e3(), m);
158 if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
159 t1v3.distance(t2.v3().p) < MATCHING_EPSILON &&
160 t1v1.distance(t2.v2().p) < MATCHING_EPSILON) {
161 t2.e3().bindEdge(t1.e2(), m);
162 t2.e2().bindEdge(t1.e3(), m);
163 t2.e1().bindEdge(t1.e1(), m);
165 if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
166 t1v1.distance(t2.v3().p) < MATCHING_EPSILON &&
167 t1v2.distance(t2.v2().p) < MATCHING_EPSILON) {
168 t2.e3().bindEdge(t1.e3(), m);
169 t2.e2().bindEdge(t1.e1(), m);
170 t2.e1().bindEdge(t1.e2(), m);
172 if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
173 t1v2.distance(t2.v2().p) < MATCHING_EPSILON &&
174 t1v3.distance(t2.v3().p) < MATCHING_EPSILON) {
175 t2.e1().bindEdge(t1.e1().pair, m);
176 t2.e2().bindEdge(t1.e2().pair, m);
177 t2.e3().bindEdge(t1.e3().pair, m);
179 if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
180 t1v3.distance(t2.v2().p) < MATCHING_EPSILON &&
181 t1v1.distance(t2.v3().p) < MATCHING_EPSILON) {
182 t2.e2().bindEdge(t1.e1().pair, m);
183 t2.e3().bindEdge(t1.e2().pair, m);
184 t2.e1().bindEdge(t1.e3().pair, m);
186 if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
187 t1v1.distance(t2.v2().p) < MATCHING_EPSILON &&
188 t1v2.distance(t2.v3().p) < MATCHING_EPSILON) {
189 t2.e3().bindEdge(t1.e1().pair, m);
190 t2.e1().bindEdge(t1.e2().pair, m);
191 t2.e2().bindEdge(t1.e3().pair, m);
198 System.out.println("tile volume: " + tile.volume());
199 System.out.println("goal volume: " + goal.volume());
200 tile.error_against = goal;
201 goal.error_against = tile;
205 public void breakit() {
206 int oldverts = verts;
207 if (verts > 2000 && !force) return;
209 System.out.println("doubling vertices.");
210 PriorityQueue<Mesh.E> es = new PriorityQueue<Mesh.E>();
211 for(Mesh.T t : tile) {
218 for(int i=0; i<Math.min(oldverts,50); i++) {
219 Mesh.E e = es.poll();
225 System.out.println("now have " + verts + " vertices; max is 2000");
229 public boolean rand(double temp, Mesh.Vertex p) {
231 p.reComputeErrorAround();
232 double tile_error = tile.error();
233 double goal_error = goal.error();
235 float max = p.averageEdgeLength()/5;
236 Vec v = new Vec(random.nextFloat(), random.nextFloat(), random.nextFloat());
237 v = v.norm().times((random.nextFloat() - 0.5f) * max);
238 Matrix m = Matrix.translate(v);
239 boolean good = p.move(v, false);
240 if (!good) { return false; }
242 double new_tile_error = tile.error();
243 double new_goal_error = goal.error();
244 double tile_delta = (new_tile_error - tile_error) / tile_error;
245 double goal_delta = (new_goal_error - goal_error) / goal_error;
246 double delta = tile_delta + goal_delta;
247 double swapProbability = Math.exp((-1 * delta) / temp);
249 //boolean doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
250 //boolean doSwap = good && (tile_delta + goal_delta <= 0);
251 //if (temp < 0.000001) doSwap = good && (tile_delta <= 0 && goal_delta <= 0);
252 boolean doSwap = good && (Math.random() < swapProbability);
254 // always move uphill if possible -- potential idea
255 if (tile_delta <= 0 && goal_delta <= 0 && good) doSwap = true;
257 doSwap = tile_delta <= 0 && goal_delta <= 0 && good;
260 tile_error = new_tile_error;
261 goal_error = new_goal_error;
265 p.move(v.times(-1), true);
268 p.reComputeErrorAround();
274 public void anneal() throws Exception {
278 boolean seek_upward = false;
279 double acceptance = 1;
282 if (!anneal) { repaint(); Thread.sleep(10); continue; }
284 double ratio = (hits+misses==0) ? 1 : (hits / (hits+misses));
288 acceptance = (ratio+acceptance)/2;
289 accepts = (int)(Math.ceil(ratio*100));
290 temps = (int)(Math.ceil(temp*1000));
291 vertss = tile.size();
299 } else if (acceptance > 0.96) gamma = 0.1f;
300 else if (acceptance > 0.9) gamma = 0.2f;
301 else if (acceptance > 0.8) gamma = 0.3f;
302 else if (acceptance > 0.6) gamma = 0.4f;
303 else if (acceptance > 0.3) gamma = 0.8f;
304 else if (acceptance > 0.15) gamma = 0.94f;
305 else if (acceptance > 0.10) gamma = 0.98f;
307 else if (acceptance < 0.01) breaks++;
310 if (acceptance > 0.25) seek_upward = false;
311 else gamma = 2-gamma;
318 HashSet<Mesh.Vertex> hs = new HashSet<Mesh.Vertex>();
319 for(Mesh.Vertex p : tile.vertices()) hs.add(p);
320 Mesh.Vertex[] pts = (Mesh.Vertex[])hs.toArray(new Mesh.Vertex[0]);
323 long then = System.currentTimeMillis();
324 for(int i=0; i<300; i++) {
326 Mesh.Vertex v = pts[Math.abs(random.nextInt()) % pts.length];
328 if (!rand(temp,v)) { i--; continue; }
329 v.recomputeFundamentalQuadricIfStale();
330 v.recomputeFundamentalQuadricIfNeighborChanged();
337 System.out.println("temp="+temp + " ratio="+(Math.ceil(acceptance*100)) + " " +
338 "points_per_second=" +
339 (count*1000)/((double)(System.currentTimeMillis()-then)));
340 for(Mesh.Vertex p : goal.vertices()) {
341 p.quadricStale = true;
342 p.recomputeFundamentalQuadricIfNeighborChanged();
349 public static void main(String[] s) throws Exception {
350 JFrame f = new JFrame();
351 f.setLayout(new BorderLayout());
352 Main main = new Main(f);
353 f.setJMenuBar(main.new MyMenuBar());
361 public class MyMenuItem extends JMenuItem implements ActionListener {
362 public MyMenuItem(String s) {
364 this.addActionListener(this);
366 public void actionPerformed(ActionEvent event) {
367 synchronized(Main.this) {
374 public void hexBrick(boolean offset, boolean rotated) {
375 setTile(new Mesh(false));
376 float width = (float)0.8;
377 float depth = (float)0.08;
378 float height = (float)0.4;
379 float rshift = width/2;
380 float lshift = -(width/2);
382 Point ltf = new Point(lshift, (depth/2), (height/2));
383 Point mtf = new Point( 0.0, (depth/2), (height/2));
384 Point rtf = new Point(rshift, (depth/2), (height/2));
385 Point lbf = new Point(lshift, -(depth/2), (height/2));
386 Point mbf = new Point( 0.0, -(depth/2), (height/2));
387 Point rbf = new Point(rshift, -(depth/2), (height/2));
389 Point ltc = new Point(lshift, (depth/2), 0);
390 Point mtc = new Point( 0.0, (depth/2), 0);
391 Point rtc = new Point(rshift, (depth/2), 0);
392 Point lbc = new Point(lshift, -(depth/2), 0);
393 Point mbc = new Point( 0.0, -(depth/2), 0);
394 Point rbc = new Point(rshift, -(depth/2), 0);
396 Point ltn = new Point(lshift, (depth/2), -(height/2));
397 Point mtn = new Point( 0.0, (depth/2), -(height/2));
398 Point rtn = new Point(rshift, (depth/2), -(height/2));
399 Point lbn = new Point(lshift, -(depth/2), -(height/2));
400 Point mbn = new Point( 0.0, -(depth/2), -(height/2));
401 Point rbn = new Point(rshift, -(depth/2), -(height/2));
404 Point[] points = new Point[] {
429 tile.newT(ltf, mtf, mtc, null, 1);
430 tile.newT(mtc, ltc, ltf, null, 1);
431 tile.newT(mtf, rtf, rtc, null, 1);
432 tile.newT(rtc, mtc, mtf, null, 1);
434 tile.newT(ltc, mtc, mtn, null, 1);
435 tile.newT(mtn, ltn, ltc, null, 1);
436 tile.newT(mtc, rtc, rtn, null, 1);
437 tile.newT(rtn, mtn, mtc, null, 1);
439 // bottom (swap normals)
440 tile.newT(mbf, lbf, mbc, null, 2);
441 tile.newT(lbc, mbc, lbf, null, 2);
442 tile.newT(rbf, mbf, rbc, null, 2);
443 tile.newT(mbc, rbc, mbf, null, 2);
445 tile.newT(mbc, lbc, mbn, null, 2);
446 tile.newT(lbn, mbn, lbc, null, 2);
448 tile.newT(rbc, mbc, rbn, null, 2);
449 tile.newT(mbn, rbn, mbc, null, 2);
453 tile.newT(ltf, ltc, lbc, null, 3);
454 tile.newT(lbc, lbf, ltf, null, 3);
455 tile.newT(ltc, ltn, lbn, null, 3);
456 tile.newT(lbn, lbc, ltc, null, 3);
458 // right (swap normals)
459 tile.newT(rtc, rtf, rbc, null, 4);
460 tile.newT(rbf, rbc, rtf, null, 4);
461 tile.newT(rtn, rtc, rbn, null, 4);
462 tile.newT(rbc, rbn, rtc, null, 4);
465 tile.newT(ltn, mtn, mbn, null, 5);
466 tile.newT(ltn, mbn, lbn, null, 5);
467 tile.newT(mtn, rtn, rbn, null, 5);
468 tile.newT(mtn, rbn, mbn, null, 5);
471 tile.newT(mtf, ltf, mbf, null, 6);
472 tile.newT(mbf, ltf, lbf, null, 6);
473 tile.newT(rtf, mtf, rbf, null, 6);
474 tile.newT(rbf, mtf, mbf, null, 6);
477 transforms = new Matrix[] {
478 Matrix.translate(new Vec(lshift, 0, height)),
479 Matrix.translate(new Vec(lshift, 0, -height)),
480 Matrix.translate(new Vec(rshift, 0, height)),
481 Matrix.translate(new Vec(rshift, 0, -height)),
482 Matrix.translate(new Vec( width, 0, 0)),
483 Matrix.translate(new Vec(-width, 0, 0)),
484 Matrix.translate(new Vec(lshift, depth, 0)),
485 Matrix.translate(new Vec(lshift, -depth, 0)),
486 Matrix.translate(new Vec(rshift, depth, 0)),
487 Matrix.translate(new Vec(rshift, -depth, 0)),
490 } else if (rotated) {
491 HashSet<Mesh.E> es = new HashSet<Mesh.E>();
492 for(Mesh.T t : tile) {
498 if (e.p1.p.x == e.p2.p.x && e.p1.p.y == e.p2.p.y) continue;
499 if (e.p1.p.z == e.p2.p.z && e.p1.p.y == e.p2.p.y) continue;
500 if (e.p1.p.x == e.p2.p.x && e.p1.p.z == e.p2.p.z) continue;
503 transforms = new Matrix[] {
504 Matrix.translate(new Vec(0, 0, height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
505 Matrix.translate(new Vec(0, 0, -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
506 Matrix.translate(new Vec(0, depth, 0)),
507 Matrix.translate(new Vec(0, -depth, 0)),
508 Matrix.translate(new Vec( width, 0, 0)),
509 Matrix.translate(new Vec(-width, 0, 0)),
513 transforms = new Matrix[] {
514 Matrix.translate(new Vec(lshift, 0, height)),
515 Matrix.translate(new Vec(lshift, 0, -height)),
516 Matrix.translate(new Vec(rshift, 0, height)),
517 Matrix.translate(new Vec(rshift, 0, -height)),
518 Matrix.translate(new Vec( width, 0, 0)),
519 Matrix.translate(new Vec(-width, 0, 0)),
520 Matrix.translate(new Vec(0, depth, 0)),
521 Matrix.translate(new Vec(0, -depth, 0)),
529 public class MyMenuBar extends JMenuBar {
533 JMenu tileMenu = new JMenu("Tile");
534 JMenu goalMenu = new JMenu("Goal");
535 JMenu hideMenu = new JMenu("Actions");
537 hideMenu.add(new MyMenuItem("Start Anneal") { public void hit() { anneal = true; }});
538 hideMenu.add(new MyMenuItem("Stop Anneal") { public void hit() { anneal = false; }});
539 hideMenu.add(new MyMenuItem("Reset to high temperature") { public void hit() { temp = 1; }});
540 hideMenu.add(new MyMenuItem("Subdivide surface") { public void hit() { breaks++; }});
541 hideMenu.add(new MyMenuItem("Show Goal") { public void hit() { goalon = true; }});
542 hideMenu.add(new MyMenuItem("Hide Goal") { public void hit() { goalon = false; }});
543 hideMenu.add(new MyMenuItem("Show All Neighbors") { public void hit() { neighbors = true; }});
544 hideMenu.add(new MyMenuItem("Show One Neighbor Wireframe") { public void hit() { neighborsWireOne = true; }});
545 hideMenu.add(new MyMenuItem("Show All Neighbors Wireframe") { public void hit() { neighborsWire = true; neighborsWireOne = false;}});
546 hideMenu.add(new MyMenuItem("Hide Neighbors") { public void hit() { neighborsWire = false; neighborsWireOne = false; neighbors = false; }});
548 goalMenu.add(new MyMenuItem("Fish with face") { public void hit() {
549 loadGoal("face.stl");
550 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
551 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
552 //goal.transform(Matrix.scale(1, 2.2f, 1));
553 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
554 //factor = factor * 0.8f;
555 goal.transform(Matrix.scale(0.3f));
556 //goal.transform(Matrix.rotate(new Vec(0,1,0), (float)(Math.PI*1/3)));
557 goal.transform(Matrix.rotate(new Vec(1,0,0), (float)(Math.PI*1/3)));
558 fixupGoal(true, false);
559 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
560 fixupGoal(false, true);
562 goalMenu.add(new MyMenuItem("Fish") { public void hit() {
563 loadGoal("fish.stl");
564 //goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
565 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
566 goal.transform(Matrix.scale(1, 2.2f, 1));
567 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
568 factor = factor * 0.8f;
569 goal.transform(Matrix.scale(factor));
570 fixupGoal(true, false);
571 //goal.transform(Matrix.translate(new Vec(0.145f, 0, 0)));
572 fixupGoal(false, true);
574 goalMenu.add(new MyMenuItem("Hammerhead Fish") { public void hit() {
575 loadGoal("fish.stl");
576 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
577 goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(3*Math.PI/2)));
578 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
580 goal.transform(Matrix.scale(factor));
583 goalMenu.add(new MyMenuItem("Vertical Fish") { public void hit() {
584 loadGoal("fish.stl");
585 //goal.transform(Matrix.rotate(new Vec(0, 0, 1), (float)(Math.PI/2)));
586 //goal.transform(Matrix.rotate(new Vec(1, 0, 0), (float)(Math.PI/2)));
587 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
588 goal.transform(Matrix.scale(factor/1.6f));
591 goalMenu.add(new MyMenuItem("Torus") { public void hit() {
592 loadGoal("torus.stl");
593 float factor = (float)Math.pow(tile.volume() / goal.volume(), 1.0/3.0);
594 goal.transform(Matrix.scale(factor/2.5f));
595 goal.transform(Matrix.rotate(new Vec(0, 1, 0), (float)(Math.PI/2)));
598 tileMenu.add(new MyMenuItem("Hex Brick") { public void hit() {
599 hexBrick(false, false);
601 tileMenu.add(new MyMenuItem("Hex Brick, offset planes") { public void hit() {
602 hexBrick(true, false);
604 tileMenu.add(new MyMenuItem("Hex Brick, rotated") { public void hit() {
605 hexBrick(false, true);
607 tileMenu.add(new MyMenuItem("Temp (do not use)") { public void hit() {
608 setTile(new Mesh(false));
609 float width = (float)0.8;
610 float depth = (float)0.08;
611 float height = (float)0.4;
613 float rshift = width/2;
614 float lshift = -(width/2);
616 //float shift = height/2;
617 //width = (width*2)/3;
619 transforms = new Matrix[] {
621 Matrix.translate(new Vec(lshift/2, depth, -shift)),
622 Matrix.translate(new Vec(rshift/2, depth, -shift)),
623 Matrix.translate(new Vec(lshift/2, -depth, -shift)),
624 Matrix.translate(new Vec(rshift/2, -depth, -shift)),
626 Matrix.translate(new Vec(lshift, depth/2, -shift)),
627 Matrix.translate(new Vec(rshift, depth/2, -shift)),
628 Matrix.translate(new Vec(lshift, -depth/2, -shift)),
629 Matrix.translate(new Vec(rshift, -depth/2, -shift)),
633 Matrix.translate(new Vec(lshift, depth, -shift)),
634 Matrix.translate(new Vec(rshift, depth, -shift)),
635 Matrix.translate(new Vec(lshift, -depth, -shift)),
636 Matrix.translate(new Vec(rshift, -depth, -shift)),
639 Matrix.translate(new Vec(lshift, depth, shift)),
640 Matrix.translate(new Vec(rshift, depth, shift)),
641 Matrix.translate(new Vec(lshift, -depth, shift)),
642 Matrix.translate(new Vec(rshift, -depth, shift)),
644 //Matrix.translate(new Vec(0, depth, 0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
645 //Matrix.translate(new Vec(0, -depth, 0)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
646 //Matrix.translate(new Vec(0, 0, height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
647 //Matrix.translate(new Vec(0, 0, -height)).times(Matrix.rotate(new Vec(0, 0, 1), (float)Math.PI)),
649 //Matrix.translate(new Vec(0, depth, 0)),
650 //Matrix.translate(new Vec(0, -depth, 0)),
651 Matrix.translate(new Vec(0, 0, height)),
652 Matrix.translate(new Vec(0, 0, -height)),
654 //Matrix.translate(new Vec(lshift, depth, height/2)),
655 //Matrix.translate(new Vec(lshift, depth, -height/2)),
656 //Matrix.translate(new Vec(rshift, -depth, height/2)),
657 //Matrix.translate(new Vec(rshift, -depth, -height/2)),
658 //Matrix.translate(new Vec(rshift, 0, height)),
659 //Matrix.translate(new Vec(rshift, 0, -height)),
661 Matrix.translate(new Vec( width, 0, 0)),
662 Matrix.translate(new Vec(-width, 0, 0)),
668 tileMenu.add(new MyMenuItem("Dense Packing (hex)") { public void hit() {
669 setTile(new Mesh(false));
670 float width = (float)3.2;
671 float depth = (float)0.32;
672 float height = (float)1.6;
675 float sin = (float)(unit * Math.sin(Math.PI/3));
676 float cos = (float)(unit * Math.cos(Math.PI/3));
677 float x = (float)(r*Math.tan(Math.PI/6));
678 float z = (float)(r/Math.cos(Math.PI/6));
679 height = 2*r*(float)Math.sqrt(2f/3f);
692 transforms = new Matrix[] {
693 Matrix.translate(new Vec(-unit, 0, 0)),
694 Matrix.translate(new Vec( unit, 0, 0)),
695 Matrix.translate(new Vec(-cos, 0, sin)),
696 Matrix.translate(new Vec( cos, 0, sin)),
697 Matrix.translate(new Vec(-cos, 0, -sin)),
698 Matrix.translate(new Vec( cos, 0, -sin)),
699 Matrix.translate(new Vec( 0, height, z)),
700 Matrix.translate(new Vec(-r, height, -x)),
701 Matrix.translate(new Vec( r, height, -x)),
702 Matrix.translate(new Vec( 0, -height, -z)),
703 Matrix.translate(new Vec(-r, -height, x)),
704 Matrix.translate(new Vec( r, -height, x)),
707 generateTile(transforms, tile);
710 tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
711 setTile(new Mesh(false));
714 float sin = (float)(unit * Math.sin(Math.PI/3));
715 float cos = (float)(unit * Math.cos(Math.PI/3));
716 float x = (float)(r*Math.tan(Math.PI/6));
717 float z = (float)(r/Math.cos(Math.PI/6));
718 float height = 2*r*(float)Math.sqrt(2f/3f);
720 transforms = new Matrix[] {
721 Matrix.translate(new Vec(-unit, 0, 0)),
722 Matrix.translate(new Vec( unit, 0, 0)),
723 Matrix.translate(new Vec(-cos, 0, sin)),
724 Matrix.translate(new Vec( cos, 0, sin)),
725 Matrix.translate(new Vec(-cos, 0, -sin)),
726 Matrix.translate(new Vec( cos, 0, -sin)),
729 Matrix.translate(new Vec( 0, height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
730 Matrix.translate(new Vec(-r, height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
731 Matrix.translate(new Vec( r, height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
732 Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
733 Matrix.translate(new Vec(-r, -height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
734 Matrix.translate(new Vec( r, -height, x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
737 Matrix.translate(new Vec( 0, height, -z)),
738 Matrix.translate(new Vec(-r, height, x)),
739 Matrix.translate(new Vec( r, height, x)),
740 Matrix.translate(new Vec( 0, -height, z)),
741 Matrix.translate(new Vec(-r, -height, -x)),
742 Matrix.translate(new Vec( r, -height, -x)),
743 //Matrix.rotate(new Vec(0,0,1), (float)Math.PI),
746 Matrix.translate(new Vec( 0, height, -z)).times(Matrix.scale(-1,1,-1)),
747 Matrix.translate(new Vec(-r, height, x)).times(Matrix.scale(-1,1,-1)),
748 Matrix.translate(new Vec( r, height, x)).times(Matrix.scale(-1,1,-1)),
749 Matrix.translate(new Vec( 0, -height, -z)).times(Matrix.scale(-1,1,-1)),
750 Matrix.translate(new Vec(-r, -height, x)).times(Matrix.scale(-1,1,-1)),
751 Matrix.translate(new Vec( r, -height, x)).times(Matrix.scale(-1,1,-1)),
755 generateTile(transforms, tile);
756 //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
757 Matrix m = Matrix.scale(1.9f, 1f ,1);
758 //Matrix m = Matrix.scale(1f, 2.1f, 1f);
760 for(int i=0; i<transforms.length; i++)
761 transforms[i] = transforms[i].preMultiplyTranslationalComponentBy(m);
765 tileMenu.add(new MyMenuItem("Genus-1") { public void hit() {
767 setTile(new Mesh(false));
768 Matrix mm = Matrix.scale(0.1f);
775 new Point( 1, 1, -1),
776 new Point(-1, 1, -1),
777 new Point(-2, 2, 0));
782 new Point( 2, 2, 0));
784 new Point( 1, 1, -1),
787 new Point(-1, 1, -1));
791 new Point(-2, -2, 0),
792 new Point(-1, -1, -1),
793 new Point( 1, -1, -1),
794 new Point( 2, -2, 0));
796 new Point( 2, -2, 0),
797 new Point( 1, -1, 1),
798 new Point(-1, -1, 1),
799 new Point(-2, -2, 0));
801 new Point(-1, -1, -1),
802 new Point(-1, -1, 1),
803 new Point( 1, -1, 1),
804 new Point( 1, -1, -1));
808 new Point( 2, -2, 0),
809 new Point( 1, -1, -1),
810 new Point( 1, 1, -1),
811 new Point( 2, 2, 0));
815 new Point( 1, -1, 1),
816 new Point( 2, -2, 0));
818 new Point( 1, -1, -1),
819 new Point( 1, -1, 1),
821 new Point( 1, 1, -1));
826 new Point(-1, 1, -1),
827 new Point(-1, -1, -1),
828 new Point(-2, -2, 0));
830 new Point(-2, -2, 0),
831 new Point(-1, -1, 1),
833 new Point(-2, 2, 0));
835 new Point(-1, 1, -1),
837 new Point(-1, -1, 1),
838 new Point(-1, -1, -1));
845 transforms = new Matrix[] {
846 Matrix.translate(new Vec(0, 0.2f,0))
847 .times(Matrix.rotate(new Vec(0,1,0), (float)(1*Math.PI/2))),
849 Matrix.translate(new Vec(0,-0.2f,0))
850 .times(Matrix.rotate(new Vec(0,1,0), (float)(-1*Math.PI/2))),
852 Matrix.translate(new Vec( 0.2f,0,0))
853 .times(Matrix.rotate(new Vec(1,0,0), (float)(1*Math.PI/2))),
855 Matrix.translate(new Vec(-0.2f,0,0))
856 .times(Matrix.rotate(new Vec(1,0,0), (float)(-1*Math.PI/2))),
859 //Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
862 Matrix.rotate(new Vec(0,0,1), (float)(1*Math.PI/2)),
864 Matrix.rotate(new Vec(0,0,1), (float)(3*Math.PI/2)),
865 Matrix.rotate(new Vec(1,0,0), (float)(2*Math.PI/2)),
868 //Matrix.rotate(new Vec(0,0,1), (float)(2*Math.PI/2)),
869 //Matrix.scale(1,-1,1),
871 //Matrix.translate(new Vec( 0.2f, 0,0))
872 //.times(Matrix.rotate(new Vec(0,0,1), (float)( 1*Math.PI/2)))
873 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*Math.PI/2))),
875 //Matrix.translate(new Vec(-0.2f, 0,0))
876 //.times(Matrix.rotate(new Vec(0,0,1), (float)( 3*Math.PI/2)))
877 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 3*Math.PI/2))),
879 //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
880 //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
881 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
882 //Matrix.rotate(new Vec(0,0,1), (float)( 1*Math.PI/2))
883 //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
884 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
886 //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
887 //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
888 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
889 //Matrix.rotate(new Vec(0,0,1), (float)( 0*Math.PI/2))
890 //.times(Matrix.translate(new Vec(0, -0.2f, 0)))
891 //.times(Matrix.rotate(new Vec(0,1,0), (float)( 1*Math.PI/2))),
897 tileMenu.add(new MyMenuItem("Hammerhead") { public void hit() {
899 setTile(new Mesh(false));
900 Matrix mm = Matrix.ONE;
906 Point a1 = new Point( -width/2, height2/2, -depth/2);
907 Point b1 = new Point( 0, height2/2, -depth/2);
908 Point c1 = new Point( 0, height1+height2/2, -depth/2);
909 Point d1 = new Point( width/2, height1+height2/2, -depth/2);
910 Point e1 = new Point( width/2, height2/2, -depth/2);
911 Point f1 = new Point( width/2, -height2/2, -depth/2);
912 Point g1 = new Point( width/2,-height1-height2/2, -depth/2);
913 Point h1 = new Point( 0,-height1-height2/2, -depth/2);
914 Point i1 = new Point( 0, -height2/2, -depth/2);
915 Point j1 = new Point( -width/2, -height2/2, -depth/2);
916 Point a2 = new Point( -width/2, height2/2, depth/2);
917 Point b2 = new Point( 0, height2/2, depth/2);
918 Point c2 = new Point( 0, height1+height2/2, depth/2);
919 Point d2 = new Point( width/2, height1+height2/2, depth/2);
920 Point e2 = new Point( width/2, height2/2, depth/2);
921 Point f2 = new Point( width/2, -height2/2, depth/2);
922 Point g2 = new Point( width/2,-height1-height2/2, depth/2);
923 Point h2 = new Point( 0,-height1-height2/2, depth/2);
924 Point i2 = new Point( 0, -height2/2, depth/2);
925 Point j2 = new Point( -width/2, -height2/2, depth/2);
927 quad(tile, mm, a1, b1, i1, j1);
928 quad(tile, mm, c1, d1, e1, b1);
929 quad(tile, mm, b1, e1, f1, i1);
930 quad(tile, mm, i1, f1, g1, h1);
932 quad(tile, mm, j2, i2, b2, a2);
933 quad(tile, mm, b2, e2, d2, c2);
934 quad(tile, mm, i2, f2, e2, b2);
935 quad(tile, mm, h2, g2, f2, i2);
937 quad(tile, mm, d1, d2, e2, e1);
938 quad(tile, mm, e1, e2, f2, f1);
939 quad(tile, mm, f1, f2, g2, g1);
940 quad(tile, mm, h1, g1, g2, h2);
941 quad(tile, mm, i2, i1, h1, h2);
942 quad(tile, mm, j1, i1, i2, j2);
943 quad(tile, mm, a2, a1, j1, j2);
944 quad(tile, mm, a1, a2, b2, b1);
945 quad(tile, mm, c2, c1, b1, b2);
946 quad(tile, mm, c1, c2, d2, d1);
948 transforms = new Matrix[] {
950 mm.times(Matrix.translate(new Vec( width, 0, 0))),
951 mm.times(Matrix.translate(new Vec( -width, 0, 0))),
952 mm.times(Matrix.translate(new Vec(-width/2, height1+height2, 0))),
953 mm.times(Matrix.translate(new Vec( width/2, height1+height2, 0))),
954 mm.times(Matrix.translate(new Vec(-width/2,-height1-height2, 0))),
955 mm.times(Matrix.translate(new Vec( width/2,-height1-height2, 0))),
957 mm.times(Matrix.translate(new Vec( width/2, 0, depth))),
958 mm.times(Matrix.translate(new Vec( -width/2, 0, depth))),
959 mm.times(Matrix.translate(new Vec( 0, height1+height2, depth))),
960 mm.times(Matrix.translate(new Vec( 0,-height1-height2, depth))),
962 mm.times(Matrix.translate(new Vec( width/2, 0, -depth))),
963 mm.times(Matrix.translate(new Vec( -width/2, 0, -depth))),
964 mm.times(Matrix.translate(new Vec( 0, height1+height2, -depth))),
965 mm.times(Matrix.translate(new Vec( 0,-height1-height2, -depth))),
972 // Finally, add all the menus to the menu bar.