+ private float oldscore = 0;
+
+ private boolean inserted = false;
+
+ public P register() {
+ P p2 = ps.get(this);
+ if (p2==null) { p2 = this; ps.put(this,this); name = allname++; }
+ return p2;
+ }
+
+ public void kdremove() {
+ if (!inserted) return;
+ inserted = false;
+ P p = this;
+ try { kd.delete(new double[]{p.x,p.y,p.z}); } catch (Exception e) { }
+ }
+ public void kdinsert() {
+ if (inserted) return;
+ inserted = true;
+ P p = this;
+ try { kd.insert(new double[]{p.x,p.y,p.z},this); } catch (Exception e) { throw new Error(e); }
+ }
+
+ public float score() { return oldscore; }
+ public void unscore() {
+ if (watch == null) return;
+ watch.watch_x -= x;
+ watch.watch_y -= y;
+ watch.watch_z -= z;
+ watch.watch_count--;
+ if (watch.watch_count==0) {
+ watch.watch_x = 0;
+ watch.watch_y = 0;
+ watch.watch_z = 0;
+ }
+ watch = null;
+ }
+ public P times(M m) { return m.times(this); }
+ public P partner() {
+ if (watch==null) return this;
+ return watch.times(score_against.aspect).times(invaspect);
+ }
+ public P watchback() {
+ if (watch_count==0) return partner();
+ return newP(watch_x/watch_count, watch_y/watch_count, watch_z/watch_count);
+ }
+ public void rescore() {
+ if (score_against == null) return;
+
+ score -= oldscore;
+ oldscore = 0;
+
+ if (watch != null) unscore();
+ P po = this.times(aspect).times(score_against.invaspect);
+ if (watch == null) {
+ watch = score_against.nearest(po);
+
+ // don't attract to vertices that face the other way
+ if (watch.norm().times(score_against.aspect).times(invaspect).dot(norm()) < 0) {
+ watch = null;
+ } else {
+ watch.watch_x += po.x;
+ watch.watch_y += po.y;
+ watch.watch_z += po.z;
+ watch.watch_count++;
+ }
+ }
+
+ double s1, s2;
+ if (watch_count==0) s1 = 0;
+ else s1 = this.distance(watch_x/watch_count, watch_y/watch_count, watch_z/watch_count);
+ s2 = watch==null ? 0 : po.distance(watch);
+ oldscore = (float)(s1 + s2);
+ score += oldscore;
+ }
+
+ public float distance(P p) { return distance(p.x, p.y, p.z); }
+ public float distance(float ox, float oy, float oz) {
+ return
+ (float)Math.sqrt((x-ox)*(x-ox)+
+ (y-oy)*(y-oy)+
+ (z-oz)*(z-oz));
+ }
+
+ /** does NOT update bound pairs! */
+ public boolean transform(M m) {
+ // FIXME: screws up kdtree
+ // FIXME: screws up hashmap
+ unscore();
+ try {
+ if (ps.get(this)==null) throw new Error();
+ ps.remove(this);
+ float newx = m.a*x + m.b*y + m.c*z + m.d;
+ float newy = m.e*x + m.f*y + m.g*z + m.h;
+ float newz = m.i*x + m.j*y + m.k*z + m.l;
+ this.x = newx;
+ this.y = newy;
+ this.z = newz;
+ // FIXME: what if we move onto exactly where another point is?
+ ps.put(this,this);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ rescore();
+ boolean good = true;
+
+ for(T t : ts) {
+ for(E e = this.e; ;) {
+ if (e.intersects(t)) { good = false; break; }
+ e = e.pair.next;
+ if (e == this.e) break;
+ }
+ }
+ /*
+ if (t==this.t) continue;
+ if (this.intersects(t)) good = false;
+ }
+ */
+ return good;
+ }
+ public boolean move(V v) {
+ M m = new M(v);
+ P p = this;
+ boolean good = true;
+ do {
+ good &= p.transform(m);
+ v = v.times(binding); // bleh wrong
+ p = p.bound_to;
+ } while (p != this);
+ return good;
+ }
+