+ char name;
+
+ float x, y, z;
+
+ private E e; // some edge *leaving* this point
+ private M binding = new M();
+ private P bound_to = this;
+
+ public E makeE(P p2) {
+ E e = getE(p2);
+ if (e != null) return e;
+ e = p2.getE(this);
+ if (this.e == null && p2.e == null) return this.e = new E(this, p2);
+ if (this.e == null && p2.e != null) return p2.makeE(this).pair;
+ return new E(getFreeIncident(), p2);
+ }
+
+ public E getFreeIncident() {
+ E ret = getFreeIncident(e, e);
+ if (ret != null) return ret;
+ ret = getFreeIncident(e.pair.next, e.pair.next);
+ if (ret == null) throw new Error("unable to find free incident to " + this);
+ return ret;
+ }
+
+ public E getFreeIncident(E start, E before) {
+ E e = start;
+ do {
+ if (e.pair.p2 == this && e.pair.t == null && e.pair.next.t == null) return e.pair;
+ e = e.pair.next;
+ } while(e != before);
+ return null;
+ }
+
+ public E getE(P p2) {
+ E e = this.e;
+ do {
+ if (e==null) return null;
+ if (e.p1 == this && e.p2 == p2) return e;
+ e = e.pair.next;
+ } while (e!=this.e);
+ return null;
+ }
+
+ public boolean isBoundTo(P p) {
+ P px = p;
+ do {
+ if (px==this) return true;
+ px = px.bound_to;
+ } while(px != p);
+ return false;
+ }
+
+ public void unbind() { bound_to = null; binding = null; }
+ public void bind(P p) { bind(p, new M()); }
+ public void bind(P p, M binding) {
+ if (isBoundTo(p)) return;
+ P temp_bound_to = p.bound_to;
+ M temp_binding = p.binding;
+ p.bound_to = this.bound_to;
+ p.binding = binding.times(this.binding); // FIXME: may have order wrong here
+ this.bound_to = temp_bound_to;
+ this.binding = temp_binding.times(temp_binding); // FIXME: may have order wrong here
+ }
+
+ public void move(V v) {
+ P p = this;
+ do {
+ p.x = p.x+v.x;
+ p.y = p.y+v.y;
+ p.z = p.z+v.z;
+ v = v.times(binding);
+ p = p.bound_to;
+ } while (p != this);
+ }
+
+ public P(float x, float y, float z) {
+ this.x = x; this.y = y; this.z = z;
+ }
+
+ public P nearest() {
+ Object[] results;
+ try { results = kd.nearest(new double[]{x,y,z},2); } catch (Exception e) { throw new Error(e); }
+ if (results[0] != this) throw new Error();
+ return (P)results[1];
+ }
+