. ( ). , . ( , a, b, c, d, - c, d, a, b.) , , . (. . A, b, c, d vs. -d, -c, -b, -a 2π-d, 2π-c, 2π-b, 2π-a.)
. , . (, l_shape 3π/2,3π/2, π/2,3π/2,3π/2,3π/2. π/2: π/2,3π/2,3π/2,3π/2,3π/2,3π/2.)
, , , . .
-, , :
import math
def anglesForPoints(points):
def vector(tail, head):
return tuple(h - t for h, t in zip(head, tail))
points = points[:] + points[0:2]
angles = []
for p0, p1, p2 in zip(points, points[1:], points[2:]):
v0 = vector(tail=p0, head=p1)
a0 = math.atan2(v0[1], v0[0])
v1 = vector(tail=p1, head=p2)
a1 = math.atan2(v1[1], v1[0])
angle = a1 - a0
if angle < 0:
angle += 2 * math.pi
angles.append(angle)
return angles
(, , , cos(a) == cos(-a).)
, , :
def allRotationsOfList(items):
for i in xrange(len(items)):
yield items[i:] + items[:i]
, , :
def shapesMatch(shape0, shape1):
if len(shape0) != len(shape1):
return False
def closeEnough(a0, a1):
return abs(a0 - a1) < 0.000001
angles0 = anglesForPoints(shape0)
reversedAngles0 = list(2 * math.pi - a for a in reversed(angles0))
angles1 = anglesForPoints(shape1)
for rotatedAngles1 in allRotationsOfList(angles1):
if all(closeEnough(a0, a1) for a0, a1 in zip(angles0, rotatedAngles1)):
return True
if all(closeEnough(a0, a1) for a0, a1 in zip(reversedAngles0, rotatedAngles1)):
return True
return False
( , - . , 0... 2π, .)
>>> shapesMatch([(0,0),(1,1),(0,2),(-1,1)], rectangle)
True
>>> shapesMatch([(0,0),(1,1),(0,2),(-1,1)], l_shape)
False
>>> shapesMatch([(0,0), (1,0), (1,1), (2,1), (2,2), (0,2)], l_shape)
True
, . , . .