public static Random random = new Random();
private HashMap<P,P> ps = new HashMap<P,P>();
- private HashMap<E,E> es = new HashMap<E,E>();
private HashSet<T> ts = new HashSet<T>();
public Iterator<T> iterator() { return ts.iterator(); }
e23.makeAdjacent(e31);
e31.makeAdjacent(e12);
}
- T ret = e12.newT();
+ T ret = e12.makeT();
if (e12.t == null) throw new Error();
if (e23.t == null) throw new Error();
if (e31.t == null) throw new Error();
} while (p != this);
}
- /** the next edge going around this point [FIXME: direction] */
- /*
- public E nextE(E e) {
- //e.other(this); // sanity check
- if (e.t != null && e.t.nextE(e).has(this)) return e.t.nextE(e);
- if (e.pair.t != null && e.pair.t.nextE(e).has(this)) return e.pair.nextE(e.pair);
- throw new Error();
- }
- */
-
public P(float x, float y, float z) {
this.x = x; this.y = y; this.z = z;
}
Float.floatToIntBits(z);
}
public void glVertex(GL gl) { gl.glVertex3f(x, y, z); }
- //public String toString() { return ""+name; }
public String toString() { return "("+x+","+y+","+z+")"; }
public V norm() {
V norm = new V(0, 0, 0);
public String toString() { return "<"+x+","+y+","+z+">"; }
}
+ public class BindingGroup {
+ public HashSet<E> es = new HashSet<E>();
+ public BindingGroup() { }
+ public merge(E e) {
+ if (e.bg != null) merge(e.bg);
+ else { es.add(e); e.bg = this; }
+ }
+ public merge(BindingGroup bg) {
+ for(E e : bg.es) {
+ e.bg = this;
+ this.bg.add(e);
+ }
+ }
+ }
+
/** [UNIQUE] an edge */
public final class E {
public final P p1, p2;
- T t;
- E prev;
- E next;
- E pair;
+ T t; // triangle to our "left"
+ E prev; // previous half-edge
+ E next; // next half-edge
+ E pair; // partner half-edge
+
+
+ public BindingGroup bg = null;
+
+ public void bind(E e) { bind(e, new M()); }
+ public void bind(E e, M m) {
+ if (e.bg != null) e.bg.merge(this);
+ else if (bg != null) bg.merge(e);
+ else {
+ bg = new BindingGroup();
+ bg.merge(this);
+ bg.merge(e);
+ }
+ }
+
+ public void dobind() {
+ if (bg==null) return;
+ for(E ex : bg.es) {
+ if (ex==this) continue;
+ p1.bind(ex.p1);
+ p2.bind(ex.p2);
+ }
+ }
+
+ public boolean destroyed = false;
+ public void shatter() {
+ if (destroyed) return;
+ /*
+ HashSet<E> eh = new HashSet<E>();
+ eh.add(this);
+ for(E ex = bound_to; ex != this; ex = ex.bound_to) eh.add(ex);
+ E[] es = (E[])eh.toArray(new E[0]);
+ */
+ destroy();
+ pair.shatter();
+ for(E ex = bound_to; ex != this; ex = ex.bound_to) ex.shatter();
+ }
+ public void destroy() {
+ this.destroyed = true;
+ }
private void sync() {
this.prev.next = this;
if (this.p1.e == null) this.p1.e = this;
}
- public T newT() {
- if (t==null) t = new T(this);
- return t;
- }
+ public T makeT() { return t==null ? (t = new T(this)) : t; }
/** angle between this half-edge and the next */
public double angle() {
public boolean has(P p) { return p==p1 || p==p2; }
public float length() { return p1.minus(p2).mag(); }
public String toString() { return p1+"->"+p2; }
- public int hashCode() { return p1.hashCode() ^ p2.hashCode(); }
- public boolean equals(Object o) { return o!=null && o instanceof E && this.p1 == ((E)o).p1 && this.p2 == ((E)o).p2; }
}
/** [UNIQUE] a triangle (face) */
public final E e1;
public final int color;
- public void bind(T t2, int rot) {
- // FIXME
- }
-
T(E e1) {
this.e1 = e1;
E e2 = e1.next;
E e3 = e2.next;
if (e1==e2 || e1==e3) throw new Error();
if (e3.next!=e1) throw new Error();
- if (e1.t!=null || e2.t!=null || e3.t!=null) throw new Error("non-manifold surface");
+ if (e1.t!=null || e2.t!=null || e3.t!=null)
+ throw new Error("non-manifold surface or disagreeing normals");
e1.t = this;
e1.next.t = this;
e1.next.next.t = this;
- /*
- if (e1.pair.t != null && e1.pair.t.nextP(e1) != prevP(e1)) throw new Error("normals disagree!");
- if (e2.pair.t != null && e2.pair.t.nextP(e2) != prevP(e2)) throw new Error("normals disagree!");
- if (e3.pair.t != null && e3.pair.t.nextP(e3) != prevP(e3)) throw new Error("normals disagree!");
- */
+
// FIXME: check for sealed/watertight surface once construction is complete (and infer normal(s)?)
int color = Math.abs(random.nextInt());
-
while(true) {
color = color % 4;
if (e1().pair.t != null && color == e1().pair.t.color) { color++; continue; }
this.color = color;
}
- /*
- public int hashCode() { return e1().hashCode() ^ e2().hashCode() ^ e3.hashCode(); }
- public boolean equals(Object o) {
- if (o==null || !(o instanceof T)) return false;
- T t = (T)o;
- return e1==t.e1() || e1==t.e2() || e1==t.e3();
- }
- */
public P p1() { return e1.p1; }
public P p2() { return e1.p2; }
public P p3() { return e1.next.p2; }
return Math.max(Math.max(e1().length(), e2().length()), e3().length()) / 2;
}
- /** returns the next triangle walking clockwise around the vertex normal */
- /*
- public T nextT(P p) { return prevE(p).pair.t; }
- public T prevT(P p) { return nextE(p).pair.t; }
-
- public E nextE(E e) {
- if (e==e2) return e1;
- if (e==e3) return e2;
- if (e==e1) return e3;
- throw new Error("triangle " + this + " does not own edge " + e);
- }
-
- public E prevE(E e) {
- if (e==e2) return e3;
- if (e==e3) return e1;
- if (e==e1) return e2;
- throw new Error("triangle " + this + " does not own edge " + e);
- }
- // edge "after" this point, moving clockwise around the normal
- public E nextE(P p) {
- if (p == e1.shared(e2)) return e1;
- else if (p == e2.shared(e3)) return e2;
- else if (p == e3.shared(e1)) return e3;
- else throw new Error("triangle " + this + " does not own point " + p);
- }
- // edge "before" this point, moving clockwise around the normal
- public E prevE(P p) {
- if (p == e1.shared(e2)) return e2;
- else if (p == e2.shared(e3)) return e3;
- else if (p == e3.shared(e1)) return e1;
- else throw new Error("triangle " + this + " does not own point " + p);
- }
- */
}