1 
  2 # More Complex Interface Mapping Example - The Cascade
  3 
  4 ----
  5 
  6 * [Contents](hat-00.md)
  7 * House Keeping
  8     * [Project Layout](hat-01-01-project-layout.md)
  9     * [Building Babylon](hat-01-02-building-babylon.md)
 10     * [Building HAT](hat-01-03-building-hat.md)
 11 * Programming Model
 12     * [Programming Model](hat-03-programming-model.md)
 13 * Interface Mapping
 14     * [Interface Mapping Overview](hat-04-01-interface-mapping.md)
 15     * [Cascade Interface Mapping](hat-04-02-cascade-interface-mapping.md)
 16 * Implementation Detail
 17     * [Walkthrough Of Accelerator.compute()](hat-accelerator-compute.md)
 18 
 19 ----
 20 
 21 # More Complex Interface Mapping Example - The Cascade
 22 
 23 Previously we showed probably the minimal useful mapping with S32Array
 24 
 25 The HaarCascade example has multiple nested interfaces representing data
 26 structures involving various nested structs and unions
 27 
 28 ```java
 29 public interface Cascade extends Buffer {
 30     int width();
 31     void width(int width);
 32     int height();
 33     void height(int height);
 34     interface Feature extends Buffer.StructChild {
 35         int id();
 36         float threshold();
 37         void id(int id);
 38         void threshold(float threshold);
 39         interface LinkOrValue extends Buffer.StructChild {
 40             interface Anon extends Buffer.UnionChild {
 41                 int featureId();
 42                 void featureId(int featureId);
 43                 float value();
 44                 void value(float value);
 45             }
 46             boolean hasValue();
 47             void hasValue(boolean hasValue);
 48             Anon anon();
 49         }
 50         LinkOrValue left();
 51         LinkOrValue right();
 52         interface Rect extends Buffer.StructChild {
 53             byte x();
 54             byte y();
 55             byte width();
 56             byte height();
 57             float weight();
 58             void x(byte x);
 59             void y(byte y);
 60             void width(byte width);
 61             void height(byte height);
 62             void weight(float height);
 63         }
 64         Rect rect(long idx);
 65     }
 66     int featureCount();
 67     void featureCount(int featureCount);
 68     Feature feature(long idx);
 69     interface Stage extends Buffer.StructChild {
 70         float threshold();
 71         short firstTreeId();
 72         short treeCount();
 73         int id();
 74         void id(int id);
 75         void threshold(float threshold);
 76         void firstTreeId(short firstTreeId);
 77         void treeCount(short treeCount);
 78     }
 79 
 80     int stageCount();
 81     void stageCount(int stageCount);
 82     Stage stage(long idx);
 83     interface Tree extends Buffer.StructChild {
 84         void id(int id);
 85         void firstFeatureId(short firstFeatureId);
 86         void featureCount(short featureCount);
 87         int id();
 88         short firstFeatureId();
 89         short featureCount();
 90     }
 91     int treeCount();
 92     void treeCount(int treeCount);
 93     Tree tree(long idx);
 94     Schema<Cascade> schema = Schema.of(Cascade.class, cascade -> cascade
 95             .fields("width", "height")
 96             .arrayLen("featureCount")
 97                 .array("feature", feature -> feature
 98                     .field("id")
 99                     .field("threshold")
100                     .fields("left", "right", linkOrValue -> linkOrValue
101                             .field("hasValue")
102                             .pad(3)
103                             .field("anon", anon -> anon
104                                .field("featureId")
105                                .field("value")
106                             )
107                     )
108                     .array("rect", 3, rect -> rect
109                        .field("x")
110                        .field("y")
111                        .field("width")
112                        .field("height").
113                        .field("weight"))
114             )
115             .arrayLen("treeCount")
116                 .array("tree", tree -> tree
117                    .field("id")
118                    .field("featureCount")
119                    .field("firstFeatureId")
120                 )
121             .arrayLen("stageCount")
122                 .array("stage", stage -> stage
123                    .field("id")
124                    .field("threshold")
125                    .field("treeCount")
126                    .field("firstTreeId"))
127     );
128 }
129 ```
130 
131 Another great advantage of using interfaces is that we can choose
132 to re implement the interface in any was we see fit.
133 
134 For example we load  HaarCascades from XML files.
135 We therefore can create an implementation of the Cascade interface which just
136 loads the XML DOM... stores them in arrays and the interface methods just delegate to
137 the appropriately wrapped  w3c.Node tree nodes ;)
138 
139 If we know we are using Java backend we can actually
140 just pass the XMLCascade implementation directly to the backend...
141 
142 Actually the Cascade `create` method takes an existing
143 implementation of a Cascade and clones it.
144 So we can just pass it an XMLHaarCascade ;)
145 
146 So we build an XMLCascade then pass it to the `create` method of the iface
147 mapped Cascade
148 
149 ```java
150    XMLHaarCascadeModel haarCascade = XMLHaarCascadeModel.load(
151         ViolaJonesRaw.class.getResourceAsStream("haarcascade_frontalface_default.xml"));
152 
153    assert haarCascade instanceof Cascade; // Here it is just an interface
154 
155    Cascade cascade = Cascade.create(accelerator, haarCascade);
156 
157    // Now it can be used on the GPU
158 ```
159 
160 The implementation is currently hand crafted, but this could easily be automated.
161 
162 ```java
163  import java.lang.invoke.MethodHandles;
164 
165 static Cascade create(MethodHandles.Lookup lookup,BufferAllocator bufferAllocator, XMLHaarCascadeModel haarCascade) {
166 
167   Cascade cascade = bufferAllocator.allocate(SegmentMapper.of(lookup, Cascade.class,
168           JAVA_INT.withName("width"),
169           JAVA_INT.withName("height"),
170           JAVA_INT.withName("featureCount"),
171           sequenceLayout(haarCascade.features.size(), Feature.layout.withName(Feature.class.getSimpleName())).withName("feature"),
172           JAVA_INT.withName("stageCount"),
173           sequenceLayout(haarCascade.stages.size(), Stage.layout.withName(Stage.class.getSimpleName())).withName("stage"),
174           JAVA_INT.withName("treeCount"),
175           sequenceLayout(haarCascade.trees.size(), Tree.layout.withName(Tree.class.getSimpleName())).withName("tree")
176   ));
177   cascade.width(haarCascade.width());
178   cascade.height(haarCascade.height());
179   cascade.featureCount(haarCascade.features.size());
180   cascade.stageCount(haarCascade.stages.size());
181   cascade.treeCount(haarCascade.trees.size());
182   for (int idx = 0; idx < haarCascade.features.size(); idx++) {
183     Cascade.Feature cascadeFeature = cascade.feature(idx);
184     var haarfeature = haarCascade.features.get(idx);
185     cascadeFeature.id(haarfeature.id());
186     cascadeFeature.threshold(haarfeature.threshold());
187     Cascade.Feature.LinkOrValue cascadeLeft = cascadeFeature.left();
188     cascadeLeft.hasValue(haarfeature.left.hasValue());
189     if (haarfeature.left.hasValue()) {
190       cascadeLeft.anon().value(haarfeature.left.value());
191     } else {
192       cascadeLeft.anon().value(haarfeature.left.featureId());
193     }
194     Cascade.Feature.LinkOrValue cascadeRight = cascadeFeature.right();
195     cascadeRight.hasValue(haarfeature.right.hasValue());
196     if (haarfeature.right.hasValue()) {
197       cascadeRight.anon().value(haarfeature.right.value());
198     } else {
199       cascadeRight.anon().featureId(haarfeature.right.featureId());
200     }
201     for (int r = 0; r < 3; r++) {
202       var haarrect = haarfeature.rects[r];
203       if (haarrect != null) {
204         Cascade.Feature.Rect cascadeRect = cascadeFeature.rect(r);
205         cascadeRect.x(haarrect.x());
206         cascadeRect.y(haarrect.y());
207         cascadeRect.width(haarrect.width());
208         cascadeRect.height(haarrect.height());
209         cascadeRect.weight(haarrect.weight());
210       }
211     }
212   }
213   for (XMLHaarCascadeModel.Stage haarstage : haarCascade.stages) {
214     Cascade.Stage cascadeStage = cascade.stage(haarstage.id);
215     cascadeStage.id(haarstage.id());
216     cascadeStage.threshold(haarstage.threshold());
217     cascadeStage.firstTreeId(haarstage.firstTreeId());
218     cascadeStage.treeCount(haarstage.treeCount());
219   }
220 
221   for (XMLHaarCascadeModel.Tree haarTree : haarCascade.trees) {
222     Cascade.Tree cascadeTree = cascade.tree(haarTree.id());
223     cascadeTree.id(haarTree.id());
224     cascadeTree.firstFeatureId(haarTree.firstFeatureId());
225     cascadeTree.featureCount(haarTree.featureCount());
226   }
227   return cascade;
228 }
229 ```
230