So I played around in Python (just cause it is easiest for me to quickly prototype the solution) and came up with this:
from collections import namedtuple
from math import sqrt
from statistics import mean
Point = namedtuple('Point', ['x', 'y'])
def length_between_points(a: Point, b: Point):
squared = (pow(a.x - b.x, 2) + pow(a.y - b.y, 2))
return sqrt(squared)
def normalize(raw):
return [float(i)/max(raw) for i in raw]
def is_roughly_circle(x, y, confidence=0.1):
center = Point(x=mean(x), y=mean(y))
points = [Point(x[i], y[i]) for i in range(len(x))]
lengths_from_center = [length_between_points(p, center) for p in points]
normalized = normalize(lengths_from_center)
is_circle = all([length > 1 - confidence for length in normalized])
return is_circle
x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]
print(is_roughly_circle(x, y)) # False
x = [0, 1, 0, -1]
y = [1, 0, -1, 0]
print(is_roughly_circle(x, y)) # True
x = [0, 1.1, 0, -1]
y = [1, 0, -1, 0]
print(is_roughly_circle(x, y)) # True
x = [0, 1.2, 0, -1]
y = [1, 0, -1, 0]
print(is_roughly_circle(x, y)) # False
x = [0, 1.2, 0, -1]
y = [1, 0, -1, 0]
print(is_roughly_circle(x, y, confidence=0.2)) # True
Assumptions:
- It is better to calculate center of all points, not only the first 3. It is not the most optimal, but handles the case, if the first point from input is in the geometrical center.
- Ovals and ellipsis are not a 'roughly circle'
- How 'Rough' the circle can be could be set with confidence parameter [0,1)
Algorithm:
- Calculate the mean of all the points (center)
- Calculate distance from the center for all the points
- Normalize the distances to the range [0,1]
- Are all values in the normalized vector greater than 0.9?
- If so, the set of points is a circle with confidence of 0.1.