+ T t; // triangle to our "left"
+ E prev; // previous half-edge
+ E next; // next half-edge
+ E pair; // partner half-edge
+
+
+ public BindingGroup bg = new BindingGroup(this);
+
+ public void bind(E e) { bind(e, new M()); }
+ public void bind(E e, M m) { e.bg.add(this); }
+
+ public void dobind() {
+ if (bg==null) return;
+ for(E ex : bg.es) {
+ if (ex==this) continue;
+ p1.bind(ex.p1);
+ p2.bind(ex.p2);
+ }
+ }
+
+ boolean shattered = false;
+ public P shatter() { return shatter(midpoint(), null, null); }
+ public P shatter(P mid, BindingGroup bg1, BindingGroup bg2) {
+ if (shattered) return mid;
+ shattered = true;
+
+ P r = next.p2;
+ E next = this.next;
+ E prev = this.prev;
+
+ if (bg1==null) bg1 = new BindingGroup();
+ if (bg2==null) bg2 = new BindingGroup();
+ for(E e : bg.es) e.shatter(e.midpoint(), bg1, bg2);
+ pair.shatter();
+ destroy();
+
+ newT(r, p1, mid);
+ newT(r, mid, p2);
+ bg1.add(p1.getE(mid));
+ bg2.add(mid.getE(p2));
+ return mid;
+ }
+
+ public boolean destroyed = false;
+ public void destroy() {
+ if (destroyed) return;
+ destroyed = true;
+ pair.destroyed = true;
+ if (next.t != null) ts.remove(next.t);
+ if (prev.t != null) ts.remove(prev.t);
+ if (pair.next.t != null) ts.remove(pair.next.t);
+ if (pair.prev.t != null) ts.remove(pair.prev.t);
+ next.t = null;
+ prev.t = null;
+ pair.next.t = null;
+ pair.prev.t = null;
+ this.bg = null;
+ pair.bg = null;
+ pair.prev.next = next;
+ next.prev = pair.prev;
+ prev.next = pair.next;
+ pair.next = prev;
+ if (p1.e == this) p1.e = prev.next;
+ if (pair.p1.e == pair) pair.p1.e = pair.prev.next;
+ es.remove(this);
+ es.remove(pair);
+ }
+
+ private void sync() {
+ this.prev.next = this;
+ this.next.prev = this;
+ this.pair.pair = this;
+ if (this.next.p1 != p2) throw new Error();
+ if (this.prev.p2 != p1) throw new Error();
+ if (this.p1.e == null) this.p1.e = this;
+ es.add(this);
+ }
+
+ public T makeT() { return t==null ? (t = new T(this)) : t; }
+
+ /** angle between this half-edge and the next */
+ public double angle() {
+ V v1 = next.p2.minus(p2);
+ V v2 = this.p1.minus(p2);
+ return Math.acos(v1.norm().dot(v2.norm()));
+ }
+
+ public void makeAdjacent(E e) {
+ if (this.next == e) return;
+ if (p2 != e.p1) throw new Error("cannot make adjacent -- no shared vertex");
+ if (t != null || e.t != null) throw new Error("cannot make adjacent -- edges not both free");
+
+ E freeIncident = p2.getFreeIncident(e, this);
+
+ e.prev.next = freeIncident.next;
+ freeIncident.next.prev = e.prev;
+
+ freeIncident.next = this.next;
+ this.next.prev = freeIncident;
+
+ this.next = e;
+ e.prev = this;
+
+ sync();
+ freeIncident.sync();
+ }
+
+ /** creates an isolated edge out in the middle of space */