diff --git a/__tests__/shape.test.js b/__tests__/shape.test.js
index 9ce3fa231f777ccd950b0d2ba9cf1ec33be6eecb..06b1ab16a9c8f1687f592021b56b46f8f7253f72 100644
--- a/__tests__/shape.test.js
+++ b/__tests__/shape.test.js
@@ -244,15 +244,15 @@ describe("shape recognition", () => {
     })
 
     test("should recognize almost-closed rectangle", () => {
-      const points = [[-10, -10], [10, -10], [10, 10], [-9, -9]]
+      const points = [[-10, -10], [10, -10], [10, 10], [-9, 9]]
       const result = recognizeFromPoints(points)
       expect(result.shape).toBe(Shapes.rectangle)
     })
 
-    test("should not recognize half-closed rectangle", () => {
+    test("should recognize half-closed rectangle", () => {
       const points = [[-10, -10], [10, -10], [10, 10], [-1, -9]]
       const result = recognizeFromPoints(points)
-      expect(result.shape).not.toBe(Shapes.rectangle)
+      expect(result.shape).toBe(Shapes.rectangle)
     })
   })
 })
diff --git a/src/app.js b/src/app.js
index 9af5845459b9cd9f6acca70028a7cf29f241ff48..318c42576b37cc28f17db85b21306f64c8b66eaa 100644
--- a/src/app.js
+++ b/src/app.js
@@ -7,7 +7,7 @@ import * as canvas from "./canvas.js"
 import * as HTML from "./elements.js"
 import { connect } from "./room.js"
 import * as toolSelection from "./tool-selection.js"
-import recognizeFromPoints from "./shapes.js"
+import recognizeFromPoints, { Shapes } from "./shapes.js"
 
 const TEST_ROOM = "imperial"
 
@@ -107,15 +107,22 @@ const onRoomConnect = (room_) => {
 }
 
 const mp = (x, y) => [x, y, 1, "black", true]
+
 function drawRecognized(points) {
   const recognizedShape = recognizeFromPoints(points)
-  if (recognizedShape.shape) {
+  if (recognizedShape.shape === Shapes.line) {
     console.log(recognizedShape)
     const [x, y] = points[0]
     const a = (recognizedShape.angle * Math.PI) / 180
     const [x0, y0] = [x - 2000 * Math.cos(a), y + 2000 * Math.sin(a)]
     const [x1, y1] = [x + 2000 * Math.cos(a), y - 2000 * Math.sin(a)]
     canvas.renderPath("lastRecognizedLine", [mp(x0, y0), mp(x1, y1)])
+  } else if (recognizedShape.shape === Shapes.rectangle) {
+    console.log(recognizedShape)
+    canvas.renderPath(
+      "lastRecognizedLine",
+      recognizedShape.boundingPoints.map((x) => mp(...x)),
+    )
   } else {
     canvas.renderPath("lastRecognizedLine", [])
   }
diff --git a/src/shapes.js b/src/shapes.js
index 4941821d82726881d2ed791ffb066585a71cddfc..fb4105ad2dd5167f2ab2937a916ccf39232239db 100644
--- a/src/shapes.js
+++ b/src/shapes.js
@@ -12,6 +12,13 @@ const angleStep = 10
 const numAngleCells = 180 / angleStep
 const rhoMax = 1000
 
+const getDistance = (a, b) => {
+  if (!(a & b)) return 0
+  return Math.sqrt(
+    (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]),
+  )
+}
+
 function findMaxInHough(accum, threshold) {
   let max = 0
   //   let bestRho = 0
@@ -67,12 +74,14 @@ function boundingCoords(points) {
 }
 
 const MATRIX_SIZE = 3
+const MATRIX_CENTER_RATIO = 0.65
 
 function mArray(min, max) {
-  const step = (max - min) / MATRIX_SIZE
-  return Array(MATRIX_SIZE)
-    .fill(min)
-    .map((x, i) => x + step * (i + 1))
+  const d = max - min
+  const centerSegmentSize = d * MATRIX_CENTER_RATIO
+  const smallStep = (d - centerSegmentSize) / 2
+  const p = [min + smallStep, min + smallStep + centerSegmentSize, max]
+  return p
 }
 
 function getCluster([x, y], xBounds, yBounds) {
@@ -90,10 +99,16 @@ function computeClusters(points, xBounds, yBounds) {
         .fill()
         .map(() => []),
     )
-  points.forEach((point) => {
-    const { x, y } = getCluster(point, xBounds, yBounds)
-    clusters[x][y].push(point)
+  const intervals = points.map((point, i) => ({
+    point,
+    dist: getDistance(point, points[i + 1]),
+  }))
+
+  intervals.forEach((interval) => {
+    const { x, y } = getCluster(interval.point, xBounds, yBounds)
+    clusters[x][y].push(interval)
   })
+
   return clusters
 }
 
@@ -103,8 +118,8 @@ function clusterCoefficients(clusters, points) {
   )
 }
 
-export function computeMatrixCoefficients(points) {
-  const { maxX, minX, maxY, minY } = boundingCoords(points)
+export function computeMatrixCoefficients(points, boundingRect) {
+  const { maxX, minX, maxY, minY } = boundingRect
   const xBounds = mArray(minX, maxX)
   const yBounds = mArray(minY, maxY)
   const clusters = computeClusters(points, xBounds, yBounds)
@@ -112,16 +127,22 @@ export function computeMatrixCoefficients(points) {
   return coefficients
 }
 
+const LINE_Q = 10
+
 function couldBeLine(points) {
-  return points.length >= 2
+  const { maxX, minX, maxY, minY } = boundingCoords(points)
+  const [dx, dy] = [maxX - minX, maxY - minY].map((x) => x + 0.00001)
+  return dy / dx > LINE_Q || dx / dy > LINE_Q
 }
 
 const RECT_THRESHOLD_CENTER = 0.05
-const RECT_THRESHOLD_SIDE_VARIANCE = 0.2
+const RECT_THRESHOLD_SIDE_VARIANCE = 0.12
 
 function couldBeRect(points) {
   if (points.length < 4) return false
-  const matrixCoefficients = computeMatrixCoefficients(points)
+
+  const boundingRect = boundingCoords(points)
+  const matrixCoefficients = computeMatrixCoefficients(points, boundingRect)
 
   let [maxC, minC] = [0, 1]
   for (let i = 0; i < 3; i++) {
@@ -133,24 +154,40 @@ function couldBeRect(points) {
     }
   }
 
+  console.log(matrixCoefficients)
+
   if (
-    matrixCoefficients[1][1] < RECT_THRESHOLD_CENTER &&
-    maxC - minC < RECT_THRESHOLD_SIDE_VARIANCE
+    (matrixCoefficients[1][1] < RECT_THRESHOLD_CENTER &&
+      maxC - minC < RECT_THRESHOLD_SIDE_VARIANCE) ||
+    (maxC - minC < RECT_THRESHOLD_SIDE_VARIANCE * 2 &&
+      matrixCoefficients[1][1] === 0)
   ) {
-    return true
+    return { coefficients: matrixCoefficients, boundingRect }
   }
-  return false
+  return undefined
 }
 
-function recognizeRect(points) {
-  return { points }
+function recognizeRect(points, rectDetectionData) {
+  const { minX, minY, maxX, maxY } = rectDetectionData.boundingRect
+  return {
+    boundingRect: rectDetectionData.boundingRect,
+    boundingPoints: [
+      [minX, minY],
+      [minX, maxY],
+      [maxX, maxY],
+      [maxX, minY],
+      [minX, minY],
+    ],
+    shape: Shapes.rectangle,
+    points,
+  }
 }
 
 function recognizeLine(points) {
   if (!(points && points.length)) return {}
   const accum = Array(numAngleCells)
   const houghConfig = {
-    rhoStep: points.length > 100 ? 50 : 5,
+    rhoStep: points.length > 50 ? 50 : 5,
   }
   points.forEach((x) => constructHoughAccumulator(houghConfig, accum, ...x))
   const angle = findMaxInHough(accum, points.length - 1)
@@ -168,8 +205,9 @@ function recognizeLine(points) {
 }
 
 function recognizeFromPoints(points) {
-  if (couldBeRect(points)) {
-    return recognizeRect(points)
+  const rectDetectData = couldBeRect(points)
+  if (rectDetectData) {
+    return recognizeRect(points, rectDetectData)
   } else if (couldBeLine(points)) {
     return recognizeLine(points)
   }