Filter features to ones from specific matches.

Change-Id: I292314f58ce803ad7a0a06d11061970eebc9a1fb
diff --git a/y2020/www/image_handler.ts b/y2020/www/image_handler.ts
index a44156a..1ab2ba3 100644
--- a/y2020/www/image_handler.ts
+++ b/y2020/www/image_handler.ts
@@ -53,6 +53,8 @@
 
 export class ImageHandler {
   private canvas = document.createElement('canvas');
+  private select = document.createElement('select');
+
   private imageBuffer: Uint8ClampedArray|null = null;
   private image: CameraImage|null = null;
   private imageTimestamp: flatbuffers.Long|null = null;
@@ -60,9 +62,15 @@
   private resultTimestamp: flatbuffers.Long|null = null;
   private width = 0;
   private height = 0;
+  private selectedIndex = 0;
   private imageSkipCount = 3;
 
   constructor(private readonly connection: Connection) {
+    document.body.appendChild(this.select);
+    const defaultOption = document.createElement('option');
+    defaultOption.innerText = 'Show all features';
+    this.select.appendChild(defaultOption);
+    this.select.addEventListener('change', (ev) => this.handleSelect(ev));
     document.body.appendChild(this.canvas);
 
     this.connection.addConfigHandler(() => {
@@ -97,6 +105,10 @@
     this.connection.sendConnectMessage(builder);
   }
 
+  handleSelect(ev: Event) {
+    this.selectedIndex = ev.target.selectedIndex;
+  }
+
   handleImage(data: Uint8Array): void {
     console.log('got an image to process');
     if (this.imageSkipCount != 0) {
@@ -136,13 +148,19 @@
         const d = u - 128;
         const e = v - 128;
 
-        this.imageBuffer[(j * this.width + i) * 4 + 0] = (298 * c1 + 409 * e + 128) >> 8;
-        this.imageBuffer[(j * this.width + i) * 4 + 1] = (298 * c1 - 100 * d - 208 * e + 128) >> 8;
-        this.imageBuffer[(j * this.width + i) * 4 + 2] = (298 * c1 + 516 * d + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 0] =
+            (298 * c1 + 409 * e + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 1] =
+            (298 * c1 - 100 * d - 208 * e + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 2] =
+            (298 * c1 + 516 * d + 128) >> 8;
         this.imageBuffer[(j * this.width + i) * 4 + 3] = 255;
-        this.imageBuffer[(j * this.width + i) * 4 + 4] = (298 * c2 + 409 * e + 128) >> 8;
-        this.imageBuffer[(j * this.width + i) * 4 + 5] = (298 * c2 - 100 * d - 208 * e + 128) >> 8;
-        this.imageBuffer[(j * this.width + i) * 4 + 6] = (298 * c2 + 516 * d + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 4] =
+            (298 * c2 + 409 * e + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 5] =
+            (298 * c2 - 100 * d - 208 * e + 128) >> 8;
+        this.imageBuffer[(j * this.width + i) * 4 + 6] =
+            (298 * c2 + 516 * d + 128) >> 8;
         this.imageBuffer[(j * this.width + i) * 4 + 7] = 255;
       }
     }
@@ -157,7 +175,7 @@
   }
 
   draw(): void {
-  if (!this.imageTimestamp || !this.resultTimestamp ||
+    if (!this.imageTimestamp || !this.resultTimestamp ||
         this.imageTimestamp.low !== this.resultTimestamp.low ||
         this.imageTimestamp.high !== this.resultTimestamp.high) {
       console.log('image and result do not match');
@@ -173,20 +191,60 @@
     const idata = ctx.createImageData(this.width, this.height);
     idata.data.set(this.imageBuffer);
     ctx.putImageData(idata, 0, 0);
-    for (const i = 0; i < this.result.featuresLength(); i++) {
-      const feature = this.result.features(i);
-      // Based on OpenCV drawKeypoint.
-      ctx.beginPath();
-      ctx.arc(feature.x(), feature.y(), feature.size(), 0, 2 * Math.PI);
-      ctx.stroke();
-
-      ctx.beginPath();
-      ctx.moveTo(feature.x(), feature.y());
-      const angle = feature.angle() * Math.PI / 180;
-      ctx.lineTo(
-          feature.x() + feature.size() * Math.cos(angle),
-          feature.y() + feature.size() * Math.sin(angle));
-      ctx.stroke();
+    console.log('features: ', this.result.featuresLength();
+    if (this.selectedIndex === 0) {
+      for (const i = 0; i < this.result.featuresLength(); i++) {
+        const feature = this.result.features(i);
+        this.drawFeature(feature);
+      }
+    } else {
+      const imageMatch = this.result.imageMatches(this.selectedIndex - 1);
+      for (const i = 0; i < imageMatch.matchesLength(); i++) {
+        const featureIndex = imageMatch.matches(i).queryFeature();
+        this.drawFeature(this.result.features(featureIndex));
+      }
     }
+
+    // Draw 'center' of target.
+    // TODO(alex) adjust to new location in flatbuffer for these fields
+    //ctx.strokeStyle = 'red';
+    //ctx.beginPath();
+    //ctx.arc(
+    //    this.result.targetPointX(), this.result.targetPointY(), 20, 0,
+    //    2 * Math.PI);
+    //ctx.stroke();
+
+    while (this.select.lastChild) {
+      this.select.removeChild(this.select.lastChild);
+    }
+    const defaultOption = document.createElement('option');
+    defaultOption.innerText = 'Show all features';
+    defaultOption.setAttribute('value', 0);
+    this.select.appendChild(defaultOption);
+    for (const i = 0; i < this.result.imageMatchesLength(); i++) {
+      const imageMatch = this.result.imageMatches(i);
+      const option = document.createElement('option');
+      option.setAttribute('value', i + 1);
+      option.innerText =
+          `Show image ${i} features (${imageMatch.matchesLength()})`;
+      this.select.appendChild(option);
+    }
+    this.select.selectedIndex = this.selectedIndex;
+  }
+
+  // Based on OpenCV drawKeypoint.
+  private drawFeature(feature: Feature) {
+    const ctx = this.canvas.getContext('2d');
+    ctx.beginPath();
+    ctx.arc(feature.x(), feature.y(), feature.size(), 0, 2 * Math.PI);
+    ctx.stroke();
+
+    ctx.beginPath();
+    ctx.moveTo(feature.x(), feature.y());
+    const angle = feature.angle() * Math.PI / 180;
+    ctx.lineTo(
+        feature.x() + feature.size() * Math.cos(angle),
+        feature.y() + feature.size() * Math.sin(angle));
+    ctx.stroke();
   }
 }