checkpoint
[anneal.git] / src / edu / berkeley / qfat / bind / BindingGroup.java
diff --git a/src/edu/berkeley/qfat/bind/BindingGroup.java b/src/edu/berkeley/qfat/bind/BindingGroup.java
new file mode 100644 (file)
index 0000000..0882fa5
--- /dev/null
@@ -0,0 +1,87 @@
+package edu.berkeley.qfat.bind;
+import edu.berkeley.qfat.geom.*;
+import javax.media.opengl.*;
+import java.util.*;
+
+/** tracks an equivalence class of geometric objects which are related to each other by transformation matrices */
+public class BindingGroup<T extends HasBindingGroup> implements Iterable<T> {
+
+    private T                  master     = null;
+    private AffineConstraint   constraint = new AffineConstraint.All();
+    private HashMap<T,Matrix>  matrices   = new HashMap<T,Matrix>();
+
+    public BindingGroup(T master) {
+        this.master = master;
+        matrices.put(master, Matrix.ONE);
+    }
+
+    public int size() { return matrices.size(); }
+
+    public void merge(BindingGroup<T> bg, Matrix m) {
+        if (bg==this) {
+            if (m.equalsModuloEpsilon(Matrix.ONE, 0.001f)) return;
+            constraint = constraint.intersect(m.getAffineConstraint(0.001f), 0.001f);
+            return;
+        }
+
+        for(HasBindingGroup hbg : bg.matrices.keySet()) {
+            matrices.put((T)hbg, bg.matrices.get(hbg).times(m));
+            hbg.bindingGroup = this;
+        }
+
+        // FIXME: what if points do not fall on the merged constraint-line?
+        AffineConstraint ac = bg.constraint.multiply(getMatrix(master, bg.master));
+        constraint = constraint.intersect(ac, 0.001f);
+
+        HashSet<HasBindingGroup> stuff = new HashSet<HasBindingGroup>();
+        for(HasBindingGroup hbg : bg.matrices.keySet())
+            stuff.add(hbg);
+        bg.matrices.clear();
+        bg.master = null;
+        for(HasBindingGroup hbg : stuff)
+            hbg.bindingGroupChanged(this);
+    }
+
+    public Matrix getMatrix(T t) { return matrices.get(t); }
+
+    public Iterator<T> iterator() { return matrices.keySet().iterator(); }
+
+    /** t1 = getMatrix(t1, t2) * t2 */
+    public Matrix getMatrix(T t1, T t2) {
+        //                    t1 = getMatrix(t1) * master
+        // getMatrix(t2)^-1 * t2 =                 master
+        //                    t1 = getMatrix(t1) * getMatrix(t2)^-1 * t2
+        return getMatrix(t1).times(getMatrix(t2).inverse());
+    }
+
+    public AffineConstraint getConstraint(T t) {
+        return constraint.multiply(matrices.get(t));
+    }
+
+    public void unbind(T trem) {
+        if (trem != master) {
+            matrices.remove(trem);
+            return;
+        }
+        if (matrices.size()==1) {
+            master = null;
+            matrices.remove(trem);
+            return;
+        }
+        Iterator<T> it = iterator();
+        T newmaster = it.next();
+        if (newmaster==trem) newmaster = it.next();
+        if (newmaster==trem) throw new Error();
+        HashMap<T,Matrix> newmatrices = new HashMap<T,Matrix>();
+        for(T t : matrices.keySet()) {
+            if (t==trem) continue;
+            newmatrices.put(t, getMatrix(t, newmaster));
+        }
+        master = newmaster;
+        matrices = newmatrices;
+    }
+
+    public boolean contains(HasBindingGroup t) {
+        return matrices.get((T)t) != null;
+    }
+}