Four Points Determine A Square
January 2, 2013
We pick one point as the origin and determine the square of the distance to each of the other three points. The smaller two of those distances are the sides of the square, and must be the same; the largest of the distances is the length of the diagonal, and by the Pythagorean theorem must be double the sum of the squares of the distances. Note that there is no need to determine the actual distances involved by taking the square root; we could do that, but why bother?
(define (square? xs)
(define (dist x y)
(+ (square (- (car x) (car y)))
(square (- (cadr x) (cadr y)))))
(let ((xs (sort < (map (lambda (x) (dist (car xs) x)) (cdr xs)))))
(and (= (car xs) (cadr xs)) (= (double (car xs)) (caddr xs)))))
Sorting eliminates any concern about the order in which the points are presented. Here are some examples:
> (square? '((0 0) (0 1) (1 1) (1 0)))
#t
> (square? '((0 0) (2 1) (3 -1) (1 -2)))
#t
> (square? '((0 0) (1 1) (0 1) (1 0)))
#t
> (square? '((0 0) (0 2) (3 2) (3 0)))
#f
> (square? '((0 0) (3 4) (8 4) (5 0)))
#f
> (square? '((0 0) (0 0) (1 1) (0 0)))
#f
> (square? '((0 0) (0 0) (1 0) (0 1)))
#f
> (square? '((0 0) (0 0) (0 0) (0 0)))
#t
We used square
and double
from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/PE47iscx.
The provided solution is incorrect. Take for example the points (0, 0), (1, 0), (0, 1) and (-1, -1). These will pass the test, but they are certainly not a square.
[…] today’s Programming Praxis exercise, our goal is to determine whether four given points in a 2D plane make […]
My Haskell solution (see http://bonsaicode.wordpress.com/2013/01/02/programming-praxis-four-points-determine-a-square/ for a version with comments):
Comparison of the lengths of two adjacent line segments determines the possible sides and diagonals. Checking remains. (Remco’s counterexample caught me, too. Nice.)
[…] Question is from here: […]
My solution in Java is here.
from itertools import groupby, combinations
def dist(v):
(x1, y1), (x2, y2) = v
return (x2 – x1) ** 2 + (y2 – y1) ** 2
def is_square(l):
pts = combinations(l, 2)
dists = sorted([dist(v) for v in pts])
return [4, 2] == [len(list(g[1])) for g in groupby(dists)]
def test(l):
print(“List {l}, is_square={sq}”.format(l=l, sq=is_square(l)))
test([(0,0),(0,1),(1,1),(1,0)])
test([(0,0), (2,1), (3,-1), (1, -2)])
test([(0,0), (0,2), (3,2), (3,0)])
A Python version. This exercise is easy to mess up. Thorough testing is important. The full code including tests is here.
A Python solution very close to Remco’s approach:
Clojure version; works with Remco example:
Some test cases:
My first submission, C#:
I came up with the following, which does not require any multiplication (only “+”, “-“, “4*”=”<<2", "==").
def is_square(zs):
"""test if a list of four complex numbers forms a square"""
# could be implemented without multiplication for points with integer coordinates,
# since times four is a bit shift operation
c = sum(zs) # centre (scaled by 4)
ws = [ 4*z – c for z in zs ] # translate to (0, 0) (and scale by 4)
u = ws[0]
v = u*1j # or: v = complex(-u.imag, u.real)
return set([ -u, v, -v ]) == set(ws[1:]) # could be written using lots of nested conditionals
Test cases from Remco Niemeijer’s post.
It turns out that similar solutions have been found by others, see for example http://codegolf.stackexchange.com/questions/1487/determine-if-4-points-form-a-square.
The function again, I hope with correct layout this time.
Another solution, based on complex algebra.
As Remco Niemeijer said, the current solution is incorrect.
To repair the solution we can do the same check from 3 different points.
Here’s an alternative solution in Python.
It works by checking that two sides are each orthogonal to a third side and that the diagonals are orthogonal.
Throws ValueError if pts does not have four unique points.
Another Java solution.
[…] Question is from here: […]
C# version:
1. Find the two longest lines (between all the points)
2. Confirm that the two longest lines are of equal length
3. Confirm that the angle between the two longest line are 90 degrees
Ah saw the counter example.
Another solution:
Find mid point of all points
Check distance from the midpoint to all the points and confirm that they’re equal.
Python solution:
# n = [(0, 0),(1, 0), (0, 1),(1,1)]
def isSquare(n):
if len(n)!=4:
return False
else:
d=[]
for x in n:
h=[]
for y in n:
h.append(((y[0]-x[0])**2+(y[1]-x[1])**2)**(1.0/2))
d.append(sorted(h))
return d[0]==d[1]==d[2]==d[3]
[/sourcode]
The function also doesn’t need to calculate the square root for the hypotenuse since it’s comparative, but left it in there anyways for math’s sake.
@Brian I think this fails for a rhombus with all internal angles bigger than 60 degrees.
#include
#include
#include
#include
int dist(int x1, int x2, int y1, int y2)
{ int z;
z=(pow((x1-x2),2)+pow((y2-y1),2));
z=sqrt(z);
return z;
}
void main()
{ int x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4;
cout<>x1>>y1;
cout<>x2>>y2;
cout<>x3>>y3;
cout<>x4>>y4;
z1=dist(x1,x2,y1,y2);
z2=dist(x1,x4,y1,y4);
if(z1==z2)
{ cout<<"Checking for rhombus or square";
delay(500);
z3=dist(x1,x3,y1,y3);
z4=dist(x2,x4,y2,y4);
if(z3==z4)
{ cout<<"square";
}
else cout<<"rhombus";
}
else cout<<"Not square";
getch();
}
[…] The task: […]
My unsophisticated C# solution:
public bool IsSquare(Point p1, Point p2, Point p3, Point p4) {
double p1p2 = EuclidianDistance(p1, p2);
double p1p3 = EuclidianDistance(p1, p3);
double p1p4 = EuclidianDistance(p1, p4);
double p2p3 = EuclidianDistance(p2, p3);
double p2p4 = EuclidianDistance(p2, p4);
double p3p4 = EuclidianDistance(p3, p4);
List distances = new List() { p1p2, p1p3, p1p4, p2p3, p2p4, p3p4 };
distances.Sort();
return (distances[0] == distances[3]) && (distances[4] == distances[5]) && (distances[0] <= distances[4]);
}
public double EuclidianDistance(Point p1, Point p2) {
return Math.Sqrt((p2.X – p1.X) * (p2.X – p1.X) + (p2.Y – p1.Y) * (p2.Y – p1.Y));
}
public class Point {
public double X { get; set; }
public double Y { get; set; }
public Point(double x, double y) {
this.X = x;
this.Y = y;
}
}
[…] Can you determine programmatically if four points create a square? This was (essentially) the programming problem posed at Programming Praxis/. […]
If you consider the vectors b – a, c – b, d – c, a – d, in the given order, you can check that they form a square by using the equations bx – ax = cy – by, by – ay = cx – bx, dx – cx = ay – dy, and dy – cy = ax – dx. These vectors form a cycle and the equations can perform a check both on the cycle and the reverse one. There are three pairs of possible permutations for the points a, b, c, d which give a cycle. Each pair consists of a cycle and the reverse one. Thus, to verify that the four points form a square, you have to check only three of the permutations of the points, i.e. (a b c d), (a b d c) and (a c b d). A code in C++ is
..well, the check above is wrong, the right check is
where the first two lines check for a rhombus and the last two lines check the angle abc..
better: the first version of the check works if all the cohordinates are positive while the second one works with both positive and negative cohordinates. The first two lines of code on the second second version of the check verify that the points form a parallelogram (actually the second line is rendundant). The third and the fourth line say that the angle abc is right and that the sides ab and bc are of equal length. I hope that’s all Oo’
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Square
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“Enter the co-ordinates in the order x1, y1, x2, y2, x3, y3, x4, y4”);
int x1 = Int32.Parse(Console.ReadLine());
int y1 = Int32.Parse(Console.ReadLine());
int x2 = Int32.Parse(Console.ReadLine());
int y2 = Int32.Parse(Console.ReadLine());
int x3 = Int32.Parse(Console.ReadLine());
int y3 = Int32.Parse(Console.ReadLine());
int x4 = Int32.Parse(Console.ReadLine());
int y4 = Int32.Parse(Console.ReadLine());
if (x1 == x2 && y2 == y3 && x3 == x4 && y4 == y1)
{
Console.WriteLine(“Its a square”);
}
else
{
Console.WriteLine(“Its a not a square”);
}
Console.ReadKey();
}
}
}
JavaScript version anyone? Happens to test against all four points, but as noted three is sufficient.
function Run(name, poly) {
var total = 0;
for (var i = 0; i < 4; i++) {
total += Test(i, poly);
}
if (total === 4) {
alert(name + " is a square");
}
else { alert(name + " is not a square"); }
}
function Test(i, poly) {
var org = poly[i];
poly.splice(i, 1);
poly.splice(0, 0, org);
var dist = GetAllDistSquared(poly);
var max = Math.max.apply(Math, dist);
var min = Math.min.apply(Math, dist);
var comp = Math.abs(dist[0] – dist[1] – dist[2]);
if (comp === max && max != min && 2 * min === max) {
return 1;
}
else { return 0; }
}
function GetAllDistSquared(poly) {
var d1 = GetDistSquared(poly[0], poly[1]);
var d2 = GetDistSquared(poly[0], poly[2]);
var d3 = GetDistSquared(poly[0], poly[3]);
return [d1, d2, d3];
}
function GetDistSquared(p1, p2) {
var dx = p1.x – p2.x;
var dy = p1.y – p2.y;
return dx * dx + dy * dy;
}
Link to run program: http://jsfiddle.net/cjAX9/2/
A slightly lengthy, detailed alternative solution in Python