checkpoint
[anneal.git] / src / edu / berkeley / qfat / bind / HasBindingGroup.java
1 package edu.berkeley.qfat.bind;
2 import edu.berkeley.qfat.geom.*;
3
4 /**
5  *  A member of an equivalence class of geometric objects whose
6  *  positions are related by affine transformation matrices and are
7  *  constrained by an affine constraint.
8  *
9  *  Every HasBindingGroup (henceforth, HBG) begins life as a member of
10  *  a singleton binding group consisting only of itself.
11  *
12  *  Invoking bindTo() upon a pair of HBG's that are not part of the
13  *  same BindingGroup will merge the two BG's.  Invoking bindTo() upon
14  *  a pair of HBG's that are already part of the same BG will result
15  *  in the imposition of an AffineConstraint on the BG.
16  */
17 public abstract class HasBindingGroup {
18
19     BindingGroup bindingGroup;
20
21     /**
22      *  Merge the BGs of this and other, ensuring that
23      *  this==bindingMatrix*other, and treating differences of less
24      *  than epsilon as irrelevant for AffineConstraint purposes.
25      */
26     public void bindTo(Matrix bindingMatrix, HasBindingGroup other, float epsilon) {
27         // know:      self   = bindingGroup[self] * master
28         // know:      other  = other.bindingGroup[other] * other.bindingGroup.master
29         // want:      self   = bindingMatrix * other
30         // therefore: master = bindingGroup[self]^-1 * bindingMatrix * other
31         // therefore:        = bindingGroup[self]^-1 * bindingMatrix * other.bindingGroup[other] * other.bindingGroup.master
32         if (bindingGroup == null) bindingGroup = new BindingGroup(this);
33         if (other.bindingGroup == null) other.bindingGroup = new BindingGroup(other);
34
35         //                            this  =                         bg.getMatrix(this)   * bg.master
36         //                            other =                         obg.getMatrix(other) * obg.master
37         //                            this  =                         bindingMatrix        * other
38         //                            this  =                         bindingMatrix        * obg.getMatrix(other) * obg.master
39         // bg.getMatrix(this)  * bg.master  =                         bindingMatrix        * obg.getMatrix(other) * obg.master
40         //                       bg.master  = bg.getMatrix(this)^-1 * bindingMatrix        * obg.getMatrix(other) * obg.master
41         // bg.master = XXX * obg.master
42         Matrix bm = bindingGroup.getMatrix(this);
43         Matrix obm = other.bindingGroup.getMatrix(other);
44         bindingMatrix =
45             bm.inverse()
46             .times(bindingMatrix)
47             .times(obm);
48         other.bindingGroup.merge(bindingGroup, bindingMatrix, epsilon);
49     }
50
51     /** number of distinct HBG's in the binding group */
52     public int bindingGroupSize() {
53         if (bindingGroup == null) return 1;
54         return bindingGroup.size();
55     }
56
57     /** returns the AffineConstraint of this BG, translated into this HBG's space */
58     public AffineConstraint getBindingConstraint() {
59         if (bindingGroup==null) return AffineConstraint.ALL;
60         return bindingGroup.getAffineConstraint(this);
61     }
62
63     /** return the matrix M which relates the position p2 of other to the position p1 of this; p1=M*p2 */
64     public Matrix getBindingMatrix(HasBindingGroup other) {
65         if (other==this) return Matrix.ONE;
66         return bindingGroup.getMatrix(this, other);
67     }
68
69     /** remove this HBG from its BG and place it in its own individual BG */
70     public void unbind() {
71         if (bindingGroup==null) return;
72         bindingGroup.unbind(this);
73         bindingGroup = null;
74         bindingGroupChanged();
75     }
76
77     /** true iff this HBG is in the same BG as the argument */
78     public boolean isBoundTo(HasBindingGroup t) {
79         return t==this || (bindingGroup!=null && bindingGroup.contains(t));
80     }
81
82     /** enumerates all members of this HBG's BG, including this */
83     public Iterable getBoundPeers() {
84         if (bindingGroup==null) bindingGroup = new BindingGroup(this);
85         return bindingGroup;
86     }
87
88     /** invoked after the binding group of this HBG has changed due to bindTo() or unbind() */
89     public void bindingGroupChanged() {
90     }
91
92     public boolean bindingGroupUnconstrained() {
93         if (bindingGroupSize() > 1) return false;
94         if (getBindingConstraint()!=AffineConstraint.ALL) return false;
95         return true;
96     }
97 }