From 7e5f6b57947471c0cffb54fa53679c45e40aed1c Mon Sep 17 00:00:00 2001
From: Yuriy Maksymets <iurii.maksymets@gmail.com>
Date: Sat, 23 Nov 2019 12:32:36 +0000
Subject: [PATCH] Fixed tests to match new interfaces, minor refactor

---
 __tests__/shape.test.js | 45 ++++++++++++++---------------------------
 src/app.js              | 33 ++++++++++++++++--------------
 src/shapes.js           | 45 ++++++++++++++++++++++-------------------
 3 files changed, 57 insertions(+), 66 deletions(-)

diff --git a/__tests__/shape.test.js b/__tests__/shape.test.js
index d7f4f36..bca2693 100644
--- a/__tests__/shape.test.js
+++ b/__tests__/shape.test.js
@@ -1,7 +1,4 @@
-import recognizeFromPoints, {
-  Shapes,
-  computeMatrixCoefficients,
-} from "../src/shapes"
+import recognizeFromPoints, { Shapes } from "../src/shapes"
 
 describe("shape recognition", () => {
   describe("general", () => {
@@ -12,41 +9,30 @@ describe("shape recognition", () => {
     })
   })
 
-  describe("matrix coefficients", () => {
-    test("should compute coefficients correctly", () => {
-      const points = [[0, 0], [0, 5], [0, 10], [10, 5]]
-      const coefficients = computeMatrixCoefficients(points)
-      expect(coefficients).toStrictEqual([
-        [1 / 4, 1 / 4, 1 / 4],
-        [0, 0, 0],
-        [0, 1 / 4, 0],
-      ])
-    })
-  })
-
   describe("lines", () => {
     test("should recognize a simple horizontal line", () => {
       const points = [[0, 0], [100, 0]]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBe(0)
+      expect(result.firstPoint).toStrictEqual([0, 0])
+      expect(result.lastPoint).toStrictEqual([100, 0])
     })
 
     test("should recognize a simple vertical line", () => {
       const points = [[0, 50], [0, -100]]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBe(90)
+      expect(result.firstPoint).toStrictEqual([0, 50])
+      expect(result.lastPoint).toStrictEqual([0, -100])
     })
 
     test("should recognize a slightly curve horizontal line", () => {
       const points = [[0, 0], [30, 5], [100, 0]]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBe(0)
     })
 
-    test("should not recognize a really curved horizontal line", () => {
+    test("should not recognize a heavily curved horizontal line", () => {
       const points = [[0, 0], [30, 30], [100, -4]]
       const result = recognizeFromPoints(points)
       expect(result.shape).not.toBe(Shapes.line)
@@ -72,7 +58,6 @@ describe("shape recognition", () => {
       ]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBe(0)
     })
 
     test("should recognize a long vertical line", () => {
@@ -115,7 +100,6 @@ describe("shape recognition", () => {
       ]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBe(90)
     })
 
     test("should recognize a line at 20 degrees", () => {
@@ -192,7 +176,6 @@ describe("shape recognition", () => {
 
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.line)
-      expect(result.angle).toBeGreaterThan(12)
     })
 
     test("should recognize line 1", () => {
@@ -328,12 +311,6 @@ describe("shape recognition", () => {
 
   describe("rectangles", () => {
     test("should recognize simple rectangle", () => {
-      const points = [[-10, -10], [10, -10], [10, 10], [-10, 10]]
-      const result = recognizeFromPoints(points)
-      expect(result.shape).toBe(Shapes.rectangle)
-    })
-
-    test("should recognize rectangle with many points", () => {
       const points = [
         [0, 0],
         [5, 0],
@@ -374,7 +351,15 @@ describe("shape recognition", () => {
     })
 
     test("should recognize almost-closed rectangle", () => {
-      const points = [[-10, -10], [10, -10], [10, 10], [-9, 9]]
+      const points = [
+        [0, 0],
+        [5, 0],
+        [10, 0],
+        [10, 5],
+        [10, 10],
+        [5, 10],
+        [0, 8],
+      ]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.rectangle)
     })
diff --git a/src/app.js b/src/app.js
index 552aebd..876ed05 100644
--- a/src/app.js
+++ b/src/app.js
@@ -33,6 +33,21 @@ const getPressureFactor = (pressure) => {
   return a * pressure ** 2 + b * pressure + c
 }
 
+const PREDICTED_POINT_COLOR = "#00000055"
+
+function faintPoint(x, y) {
+  return [x, y, 1, PREDICTED_POINT_COLOR]
+}
+
+function attributedPoint(x, y, pressure = 0) {
+  return [
+    x,
+    y,
+    toolSelection.getStrokeRadius() * getPressureFactor(pressure),
+    toolSelection.getStrokeColour(),
+  ]
+}
+
 let room = null
 
 const humanHasher = new humanhash()
@@ -148,26 +163,13 @@ const onRoomConnect = (room_) => {
   )
 }
 
-function faintPoint(x, y) {
-  return [x, y, 1, "#00000033"]
-}
-
-function attributedPoint(x, y, pressure = 0) {
-  return [
-    x,
-    y,
-    toolSelection.getStrokeRadius() * getPressureFactor(pressure),
-    toolSelection.getStrokeColour(),
-  ]
-}
-
 function getRecognizedShapePoints(points) {
   const recognizedShape = recognizeFromPoints(points)
   if (!recognizedShape.shape) return undefined
+
   switch (recognizedShape.shape) {
     case Shapes.line: {
-      const [x, y] = points[0]
-      const p1 = [x, y]
+      const p1 = recognizedShape.firstPoint
       const p2 = recognizedShape.lastPoint
       return [p1, p2]
     }
@@ -175,6 +177,7 @@ function getRecognizedShapePoints(points) {
       return recognizedShape.boundingPoints
     }
   }
+
   return undefined
 }
 
diff --git a/src/shapes.js b/src/shapes.js
index 1495ed8..e3fc050 100644
--- a/src/shapes.js
+++ b/src/shapes.js
@@ -7,7 +7,12 @@ const RECT_MATRIX_CENTER_RATIO = 0.65
 const RECT_THRESHOLD_CENTER = 0
 const RECT_THRESHOLD_SIDE_VARIANCE = 0.25
 
-function getDistance([x0, y0], [x1, y1]) {
+const MIN_RECT_POINTS = 4
+const MIN_LINE_POINTS = 2
+
+function getDistance(p1, p2) {
+  if (!(p1 && p2)) return 0
+  const [[x0, y0], [x1, y1]] = [p1, p2]
   return Math.hypot(x1 - x0, y1 - y0)
 }
 
@@ -85,12 +90,13 @@ export function computeMatrixCoefficients(points, boundingRect) {
   const xBounds = matrixBoundsArray(minX, maxX)
   const yBounds = matrixBoundsArray(minY, maxY)
   const clusters = computeClusters(points, xBounds, yBounds)
+  console.log(clusters)
   const coefficients = clusterCoefficients(clusters, points)
   return coefficients
 }
 
 function couldBeRect(points) {
-  if (points.length < 4) return false
+  if (points.length < MIN_RECT_POINTS) return false
 
   const boundingRect = boundingCoords(points)
   const matrixCoefficients = computeMatrixCoefficients(points, boundingRect)
@@ -115,22 +121,23 @@ function couldBeRect(points) {
 }
 
 function couldBeLine(points) {
-  if (points.length < 2) return false
+  if (points.length < MIN_LINE_POINTS) return false
+
   const vectorThreshold = Math.floor(
     points.length * VECTOR_LEN_THRESHOLD_FRACTION,
   )
   const pivot = points[0]
   let cumulativeThreshold = 0
-  for (let i = 2; i < points.length; i++) {
-    const p1 = points[i - 1]
-    const p2 = points[i]
-    const d1 = diffVector(pivot, p1)
-    const d2 = diffVector(p1, p2)
-
-    const d2Len = vectorLength(d2)
 
+  for (let i = 2; i < points.length; i++) {
+    const prev = points[i - 1]
+    const curr = points[i]
+    const d1 = diffVector(pivot, prev)
+    const d2 = diffVector(prev, curr)
     const angle = angleBetweenVectors(d1, d2)
+
     if (Math.abs(angle) > LINE_ANGLE_THRESHOLD) {
+      const d2Len = vectorLength(d2)
       if (cumulativeThreshold < vectorThreshold && d2Len < vectorThreshold) {
         cumulativeThreshold += d2Len
         continue
@@ -141,10 +148,9 @@ function couldBeLine(points) {
   return true
 }
 
-function recognizeRect(points, rectDetectionData) {
+function recognizedRect(_, rectDetectionData) {
   const { minX, minY, maxX, maxY } = rectDetectionData.boundingRect
   return {
-    boundingRect: rectDetectionData.boundingRect,
     boundingPoints: [
       [minX, minY],
       [minX, maxY],
@@ -153,29 +159,26 @@ function recognizeRect(points, rectDetectionData) {
       [minX, minY],
     ],
     shape: Shapes.rectangle,
-    points,
   }
 }
 
-function recognizeLine(points) {
+function recognizedLine(points) {
   const [p1, p2] = [points[0], points[points.length - 1]]
-  const angle =
-    (angleBetweenVectors(diffVector(p2, p1), [1, 0]) / Math.PI) * 180
   return {
     shape: Shapes.line,
-    angle,
-    points,
-    length: getDistance(p1, p2),
+
+    // Take only [x, y] from the whole point tuple
     lastPoint: p2.slice(0, 2),
+    firstPoint: p1.slice(0, 2),
   }
 }
 
 function recognizeFromPoints(points) {
   const rectDetectData = couldBeRect(points)
   if (rectDetectData) {
-    return recognizeRect(points, rectDetectData)
+    return recognizedRect(points, rectDetectData)
   } else if (couldBeLine(points)) {
-    return recognizeLine(points)
+    return recognizedLine(points)
   }
 
   return {}
-- 
GitLab