Move SSD detector merge wrapper to typed Kotlin

ober

2dc5b26635415b8c8b0f3f422ae9913a48def139

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index a0a0c8e..7ba146a 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -185,7 +185,7 @@
                 rectOverlapArea rectCenterInside iou adjacent
                 maxFloat32 minFloat32
                 bboxForCells ssdCellsSortedByYThenX
-                mergeDuplicateCellsSorted)
+                mergeDuplicateCellsSorted mergeDuplicateCells)
         (type Float32)
         (type FloatArray)
         (type Int32)
@@ -419,7 +419,27 @@
                             (mutable-list-set! merged duplicateIndex existing)))
                         (mutable-list-add! merged cell))
                       ignored))))
-              (renumberCells merged))))))
+              (renumberCells merged))))
+        (def (mergeDuplicateCells (cells : (MutableList SsdCell))) : (MutableList SsdCell)
+          (let ((sorted
+                  (for/fold ((out (mutable-list-empty SsdCell)))
+                            ((i (in-range (int32 0) (list-size cells))))
+                    (ssdCellsInsertSorted out (list-ref cells i)))))
+            (let ((merged (mutable-list-empty SsdCell)))
+              (begin
+                (for/fold ((ignored (int32 0)))
+                          ((i (in-range (int32 0) (list-size sorted))))
+                  (let ((cell (list-ref sorted i)))
+                    (let ((duplicateIndex (duplicateCellIndex merged cell)))
+                      (begin
+                        (if (>= duplicateIndex (int32 0))
+                          (let ((existing (list-ref merged duplicateIndex)))
+                            (if (preferReplacementCell existing cell)
+                              (mutable-list-set! merged duplicateIndex cell)
+                              (mutable-list-set! merged duplicateIndex existing)))
+                          (mutable-list-add! merged cell))
+                        ignored))))
+                (renumberCells merged)))))))
 
     (typed-kotlin-file "com/sfb/ssdreview/Component.kt"
       (typed-library (com sfb ssdreview)
@@ -5848,10 +5868,10 @@
        "            height"
        "        )"
        ""
-       "        var merged = mergeDuplicateCellsSorted(ssdCellsSortedByYThenX(cells))"
+       "        var merged = mergeDuplicateCells(cells)"
        "        if (merged.size < 50) {"
        "            merged += contourCells(width, height, gray)"
-       "            merged = mergeDuplicateCellsSorted(ssdCellsSortedByYThenX(merged))"
+       "            merged = mergeDuplicateCells(merged)"
        "        }"
        "        return merged"
        "    }"