From: adam Date: Sun, 29 Jun 2008 04:47:27 +0000 (-0700) Subject: checkpoint X-Git-Url: http://git.megacz.com/?p=anneal.git;a=commitdiff_plain;h=42acb5af8ff15b7af9fa8f34c071ee58e24faf98 checkpoint darcs-hash:20080629044727-5007d-82e649c22f31951011423bd8123d5cafcfb6a538.gz --- diff --git a/Makefile b/Makefile index d42a2b7..c9c0295 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,13 @@ -jars = lib/kd.jar:lib/trove-0.1.8.jar:lib/sil-0.43b-am1.jar +jars = lib/kd.jar:lib/trove-0.1.8.jar:lib/sil-0.43b-am1.jar:lib/jogl/jogl.jar:lib/jogl/gluegen-rt.jar all: mkdir -p build + cp *.stl build javac -cp $(jars) -d build `find src -name \*.java` - java -server -cp $(jars):build edu.berkeley.qfat.Main + nice -n 19 java -Xmx1200m -server -Djava.library.path=lib/jogl -cp $(jars):build edu.berkeley.qfat.Main + +dist: + rm -f space-sculptor.jar + cd build; for A in ../lib/*.jar; do jar xvf $$A; done + echo 'Main-Class: edu.berkeley.qfat.Main' > build/manifest + cp *.stl build + cd build; jar cvmf manifest ../space-sculptor.jar . diff --git a/src/edu/berkeley/qfat/Main.java b/src/edu/berkeley/qfat/Main.java index 50f44c0..95cd989 100644 --- a/src/edu/berkeley/qfat/Main.java +++ b/src/edu/berkeley/qfat/Main.java @@ -1,5 +1,6 @@ package edu.berkeley.qfat; import java.awt.*; +import java.io.*; import java.awt.event.*; import javax.swing.*; import javax.media.opengl.*; @@ -65,17 +66,17 @@ public class Main extends MeshViewer { HashSet halfSpaces = new HashSet(); HashSet polygons = new HashSet(); 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); @@ -104,13 +105,14 @@ public class Main extends MeshViewer { public void loadGoal(String file) { try { StlFile stlf = new StlFile(); - stlf.load(file); + InputStream res = this.getClass().getClassLoader().getResourceAsStream(file); + stlf.readBinaryFile(file, res); goal = new Mesh(false); for(int i=0; i 2000 && !force) return; + force = false; System.out.println("doubling vertices."); PriorityQueue es = new PriorityQueue(); for(Mesh.T t : tile) { @@ -213,6 +222,7 @@ public class Main extends MeshViewer { Thread.yield(); repaint(); } + System.out.println("now have " + verts + " vertices; max is 2000"); tile.rebindPoints(); } @@ -241,6 +251,12 @@ public class Main extends MeshViewer { //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; @@ -263,6 +279,7 @@ public class Main extends MeshViewer { boolean seek_upward = false; double acceptance = 1; while(true) { + synchronized(this) { synchronized(safeTriangles) { safeTriangles.clear(); for(Mesh.T t : tile) @@ -293,7 +310,8 @@ public class Main extends MeshViewer { 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; @@ -330,6 +348,7 @@ public class Main extends MeshViewer { p.quadricStale = true; p.recomputeFundamentalQuadricIfNeighborChanged(); } + } } } @@ -534,11 +553,38 @@ public class Main extends MeshViewer { 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(); }}); @@ -553,7 +599,7 @@ public class Main extends MeshViewer { 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(); }}); @@ -627,7 +673,7 @@ public class Main extends MeshViewer { }; fixupTile(); } }); - tileMenu.add(new MyMenuItem("Dense Packing (Hex)") { public void hit() { + tileMenu.add(new MyMenuItem("Dense Packing (hex)") { public void hit() { tile = new Mesh(false); float width = (float)3.2; float depth = (float)0.32; @@ -669,30 +715,16 @@ public class Main extends MeshViewer { generateTile(transforms, tile); fixupTile(); } }); - tileMenu.add(new MyMenuItem("Slim Dense Packing (Hex)") { public void hit() { + tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() { tile = new Mesh(false); - float width = (float)3.2; - float depth = (float)0.32; - float height = (float)1.6; 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); - + float height = 2*r*(float)Math.sqrt(2f/3f); - r *= 0.3f; - cos *= 0.3f; - unit *= 0.3f; - height *= 1.5f; - - /* - 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)), @@ -700,24 +732,51 @@ public class Main extends MeshViewer { 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 { m = m.plus(e.t.norm().fundamentalQuadric(e.t.centroid())); count++; } + if (count > 0) { + m = m.plus(norm().fundamentalQuadric(this.p).times(count)); + count *= 2; + } return m.times(1/(float)count); } @@ -147,28 +151,45 @@ public class Mesh implements Iterable { if (quadric_count != 0) nerror = (nerror + quadric.preAndPostMultiply(p))/(quadric_count+1); - if (!immutableVertices && quadric_count == 0) - nerror *= 2; + if (!immutableVertices && quadric_count == 0) { + //nerror = Math.max(nerror, 0.4f); + //nerror *= 2; + } //System.out.println(nerror); for(E e = this.e; e!=null; e=e.pair.next==this.e?null:e.pair.next) { double ang = e.dihedralAngle(); if (ang > Math.PI) throw new Error(); if (ang < -Math.PI) throw new Error(); - //float minangle = (float)(Math.PI * 0.8); - nerror += ((ang / Math.PI)*(ang/Math.PI)) * e.length() * 0.05; + float minangle = (float)(Math.PI * 0.8); + //nerror += ((ang / Math.PI)*(ang/Math.PI)) * e.length() * 0.05; + + nerror += (1-e.t.quality())*0.0001; + if (ang > minangle) nerror += (ang - minangle); + //System.out.println(((ang / Math.PI)*(ang/Math.PI)) * 0.000001); - //if (ang > minangle) nerror += (ang - minangle); /* if (e.t.aspect() < 0.2) { nerror += (0.2-e.t.aspect()) * 10; } */ } + if (!immutableVertices) { + Vertex n = (Vertex)nearest(); + float d = norm().dot(n.norm()); + if (d > 1 || d < -1) throw new Error(); + if (d >= 0) { + nerror *= (2.0f - d); + } else { + nerror += 0.0003 * (2.0f + d); + nerror *= (2.0f + d); + } + } setError(nerror); } public boolean move(Matrix m, boolean ignoreProblems) { + boolean good = true; // t1' = M * t1 @@ -190,7 +211,7 @@ public class Mesh implements Iterable { } if (!m.equals(m2)) return true; } - + ok = false; Point op = this.p; Point pt = m.times(this.p); for(Vertex v : (Iterable)getBoundPeers()) { @@ -212,8 +233,10 @@ public class Mesh implements Iterable { v.recomputeFundamentalQuadricIfNeighborChanged(); for(Vertex v : (Iterable)getBoundPeers()) v.reComputeErrorAround(); + ok = true; return good; } + public boolean ok = true; /** does NOT update bound pairs! */ private boolean transform(Point newp, boolean ignoreProblems, Matrix yes) { @@ -354,6 +377,12 @@ public class Mesh implements Iterable { if (!next.isBoundTo(eother.pair.prev.pair) && prev.isBoundTo(eother.pair.next.pair)) next.bindTo(prev.getBindingMatrix(eother.pair.next.pair), eother.pair.prev.pair); + /* + if (next.isBoundTo(eother.prev) && !prev.isBoundTo(eother.next)) + prev.bindTo(next.getBindingMatrix(eother.prev), eother.next); + if (!next.isBoundTo(eother.prev) && prev.isBoundTo(eother.next)) + next.bindTo(prev.getBindingMatrix(eother.next), eother.prev); + */ if (next.isBoundTo(eother.next) && !prev.isBoundTo(eother.prev)) prev.bindTo(next.getBindingMatrix(eother.next), eother.prev); if (!next.isBoundTo(eother.next) && prev.isBoundTo(eother.prev)) @@ -372,7 +401,6 @@ public class Mesh implements Iterable { } public float comparator() { return length(); - //return t==null?0:(1/t.aspect()); } public int compareTo(E e) { return e.comparator() > comparator() ? 1 : -1; @@ -401,8 +429,10 @@ public class Mesh implements Iterable { System.out.println(" " + p1.p + " " + m.times(e.p1.p)); System.out.println(" " + p2.p + " " + m.times(e.p2.p)); */ + /* if (m.times(e.p1.p).minus(p1.p).mag() > EPSILON) throw new Error(); if (m.times(e.p2.p).minus(p2.p).mag() > EPSILON) throw new Error(); + */ this.bindTo(m, e); } diff --git a/src/edu/berkeley/qfat/MeshViewer.java b/src/edu/berkeley/qfat/MeshViewer.java index c5c6a3b..cc05e86 100644 --- a/src/edu/berkeley/qfat/MeshViewer.java +++ b/src/edu/berkeley/qfat/MeshViewer.java @@ -12,19 +12,24 @@ import edu.berkeley.qfat.geom.Point; public class MeshViewer implements GLEventListener, MouseListener, MouseMotionListener, KeyListener, MouseWheelListener { + public boolean force = false; public Mesh tile = new Mesh(false); public Mesh goal = new Mesh(false); public Matrix[] transforms; public Mesh.Vertex[] points; + public int whichNeighbor = 1; + public double temp; public boolean tileon = true; public boolean tilemeshon = false; public boolean goalon = true; public boolean anneal = false; + public boolean hillclimb = false; public boolean neighbors = false; public boolean neighborsWire = false; public boolean neighborsWireOne = false; + public boolean errorNormals = false; public int breaks = 0; boolean alt = false; @@ -41,11 +46,15 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi case KeyEvent.VK_CONTROL: control = true; break; case KeyEvent.VK_ALT: alt = true; break; case KeyEvent.VK_SHIFT: shift = true; break; - case KeyEvent.VK_SPACE: breaks++; break; + case KeyEvent.VK_SPACE: breaks++; force = true; break; case KeyEvent.VK_UP: temp = temp * 2; break; case KeyEvent.VK_ENTER: temp = 10; break; + case KeyEvent.VK_LEFT: whichNeighbor--; break; + case KeyEvent.VK_RIGHT: whichNeighbor++; break; case KeyEvent.VK_D: dump(); break; - case KeyEvent.VK_A: anneal = !anneal; 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; case KeyEvent.VK_N: neighbors = !neighbors; break; case KeyEvent.VK_T: tileon = !tileon; break; case KeyEvent.VK_G: goalon = !goalon; break; @@ -156,7 +165,7 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi public int vertss; public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { } - public synchronized void display(GLAutoDrawable drawable) { + public void display(GLAutoDrawable drawable) { if (transforms==null) return; @@ -180,9 +189,29 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi gl.glPointSize(5.0f); gl.glLoadIdentity(); glu.gluPerspective(50, ((float)drawable.getWidth())/drawable.getHeight(), 0.5, 10); - glu.gluLookAt(0, 0, (tz/10)-1, 0, 0, 0, 0, 1, 0); + glu.gluLookAt(0, 0, -((tz/10)-1), 0, 0, 0, 0, 1, 0); gl.glRotatef(anglex/3, 0, 1, 0); - gl.glRotatef(angley/3, 1, 0, 0); + gl.glRotatef(-(angley/3), 1, 0, 0); + + + gl.glDisable(GL.GL_LIGHTING); + gl.glColor4f(1, 0, 0, 1); + gl.glBegin(GL.GL_LINES); + gl.glVertex3f(0,0,0); + gl.glVertex3f(.3f,0,0); + gl.glEnd(); + gl.glColor4f(0, 1, 0, 1); + gl.glBegin(GL.GL_LINES); + gl.glVertex3f(0,0,0); + gl.glVertex3f(0,.3f,0); + gl.glEnd(); + gl.glColor4f(0, 0, 1, 1); + gl.glBegin(GL.GL_LINES); + gl.glVertex3f(0,0,0); + gl.glVertex3f(0,0,.3f); + gl.glEnd(); + gl.glEnable(GL.GL_LIGHTING); + gl.glBegin(GL.GL_TRIANGLES); if (tileon) @@ -204,9 +233,17 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi //gl.glDisable(GL.GL_DEPTH_TEST); gl.glColor4f(1,1,1,1); for(Matrix m : transforms) { + /* + gl.glColor4f(0, 1, 1, 1); + gl.glBegin(GL.GL_LINES); + new Point(0,0,0).glVertex(gl); + new Point(0,0,0).plus(m.getTranslationalComponent()).glVertex(gl); + gl.glEnd(); + gl.glEnable(GL.GL_LIGHTING); + */ //if (v1.z==0 && v1.y==0) continue; i++; - if (neighborsWireOne && i>1) continue; + if (neighborsWireOne && i!=whichNeighbor) continue; //if (i>4) continue; /* Point p = new Point(0, 0, 0).times(m); @@ -285,25 +322,23 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi Point centroid = t.centroid(); gl.glBegin(GL.GL_LINES); gl.glColor3f(1, 1, 1); - /* - centroid.glVertex(gl); - centroid.plus(t.norm().times(t.diameter())).glVertex(gl); - */ - /* - if (mesh==goal) + + if (triangles && errorNormals) for(Mesh.Vertex p : new Mesh.Vertex[] { t.v1(), t.v2(), t.v3() }) { - gl.glDisable(GL.GL_LIGHTING); - gl.glBegin(GL.GL_LINES); - gl.glColor3f(1, 1, 1); - p.p.glVertex(gl); - //p.p.plus(p.norm().times(p.score())).glVertex(gl); - if (p.nearest_in_other_mesh != null) p.nearest_in_other_mesh.p.glVertex(gl); - //tile.nearest(p).centroid().glVertex(gl); - gl.glEnd(); - gl.glEnable(GL.GL_LIGHTING); + if (p.ok) { + //gl.glDisable(GL.GL_LIGHTING); + gl.glBegin(GL.GL_LINES); + gl.glColor3f(1, 1, 1); + p.p.glVertex(gl); + p.p.plus(p.norm().times((float)p.error()*10)).glVertex(gl); + //if (p.nearest_in_other_mesh != null) p.nearest_in_other_mesh.p.glVertex(gl); + //tile.nearest(p).centroid().glVertex(gl); + gl.glEnd(); + //gl.glEnable(GL.GL_LIGHTING); + } } - */ gl.glEnd(); + } } } @@ -314,7 +349,8 @@ public class MeshViewer implements GLEventListener, MouseListener, MouseMotionLi private GLCanvas glcanvas; public MeshViewer(JFrame f) { this.f = f; - GLCapabilities glcaps = new GLCapabilities(); + + GLCapabilities glcaps = new GLCapabilities(); glcanvas = new GLCanvas(); glcanvas.addGLEventListener(this); f.add(glcanvas, BorderLayout.CENTER); diff --git a/src/edu/berkeley/qfat/StlFile.java b/src/edu/berkeley/qfat/StlFile.java index b1eaca6..5a283c9 100644 --- a/src/edu/berkeley/qfat/StlFile.java +++ b/src/edu/berkeley/qfat/StlFile.java @@ -14,6 +14,7 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.InputStreamReader; import java.io.FileInputStream; +import java.io.InputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -426,9 +427,8 @@ public class StlFile implements Loader * * @throws IOException */ - private void readBinaryFile(String file) throws IOException + public void readBinaryFile(String file, InputStream data) throws IOException { - FileInputStream data; // For reading the file ByteBuffer dataBuffer; // For reading in the correct endian byte[] Info=new byte[80]; // Header data byte[] Array_number= new byte[4]; // Holds the number of faces @@ -447,7 +447,6 @@ public class StlFile implements Loader } else { // It's a local file - data = new FileInputStream(file); // First 80 bytes aren't important if(80 != data.read(Info)) @@ -571,7 +570,7 @@ public class StlFile implements Loader else { // Binary file try{ - readBinaryFile(getFileName()); + readBinaryFile(getFileName(), new FileInputStream(getFileName())); } catch(IOException e) { diff --git a/src/edu/berkeley/qfat/geom/Matrix.java b/src/edu/berkeley/qfat/geom/Matrix.java index eeeb68f..31fe6e0 100644 --- a/src/edu/berkeley/qfat/geom/Matrix.java +++ b/src/edu/berkeley/qfat/geom/Matrix.java @@ -122,6 +122,14 @@ public class Matrix { i*p.x + j*p.y + k*p.z + l); } + public Matrix preMultiplyTranslationalComponentBy(Matrix mm) { + Vec v = mm.times(getTranslationalComponent()); + return new Matrix(a, b, c, v.x, + e, f, g, v.y, + i, j, k, v.z, + m, n, o, 1); + } + /** multiply by another matrix */ public Matrix times(Matrix z) { float t00 = a; diff --git a/src/edu/berkeley/qfat/geom/Point.java b/src/edu/berkeley/qfat/geom/Point.java index fdef5e6..61fa603 100644 --- a/src/edu/berkeley/qfat/geom/Point.java +++ b/src/edu/berkeley/qfat/geom/Point.java @@ -11,9 +11,6 @@ public final class Point implements HasBoundingBox { public float distance(Point p) { return (float)Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z)); } - // FIXME: this should be eliminated; wrong order - public Point times(Matrix m) { return m.times(this); } - public Vec minus(Point p) { return new Vec(x-p.x, y-p.y, z-p.z); } public Point plus(Vec v) { return new Point(x+v.x, y+v.y, z+v.z); } diff --git a/src/edu/berkeley/qfat/geom/Triangle.java b/src/edu/berkeley/qfat/geom/Triangle.java index 9d16661..fece872 100644 --- a/src/edu/berkeley/qfat/geom/Triangle.java +++ b/src/edu/berkeley/qfat/geom/Triangle.java @@ -44,13 +44,40 @@ public abstract class Triangle implements HasBoundingBox { } /** ratio of the area of the triangle to that of the square formed from its longest edge */ + /* public float aspect() { float max = Math.max(Math.max(p1().distance(p2()), p2().distance(p3())), p3().distance(p1())) / 2; return 1/(1+area()/(max*max)); } + */ + public float circumcircleRadius() { + double a = p1().distance(p2()); + double b = p2().distance(p3()); + double c = p3().distance(p1()); + return (float)((a*b*c)/Math.sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c))); + } + + public float shortestEdgeLength() { + float a = p1().distance(p2()); + float b = p2().distance(p3()); + float c = p3().distance(p1()); + return Math.min(a, Math.min(b,c)); + } + + /** a number ranging from 0..1 with 0 being lower quality */ + public float quality() { + float d = shortestEdgeLength(); + float r = circumcircleRadius(); + if (r==0) throw new Error(); + float ret = (float)((d*Math.cos(Math.PI/6))/(r*2)); + if (ret < 0 || ret > 1) throw new Error("ret="+ret); + return ret; + } + + // FIXME: I stole this off the net, and I need to credit whoever wrote it /** decide if the segment from p1-p2 intersects this triangle */ public boolean intersects(Point p1, Point p2) { double A0=p1().x, A1=p1().y, A2=p1().z;