I'm currently writing a program in Python to model projective geometry, and the congruence function for a projective point is looking rather nasty.
(for anyone interested, two projective points are congruent if they both lie on a single line passing through the origin.)
class Point(object):
def __init__(self, a, b, c):
self.coords = [ a, b, c ]
def congruent(self, other):
ratio = 0
for i in range(3):
if self.coords[i] != 0 and other.coords[i] != 0:
if ratio is 0:
ratio = other.coords[i] / self.coords[i]
elif ratio != other.coords[i] / self.coords[i]:
return False
elif self.coords[i] != 0 or other.coords[i] != 0:
return False
return True
I'm new to Python, but I know that there's generally a "Pythonic" way to do everything. With that in mind, how would I go about making this more readable?
How about this:
def congruent(self, other, eps=0.001):
ratios = (c1 / c2 for c1, c2 in zip(self.coords, other.coords) if c1 or c2)
try:
first = next(ratios)
return all(abs(ratio - first) < eps for ratio in ratios)
except ZeroDivisionError:
return False
zip
is handy).c1
is nonzero and c2
is zero, so that's a fail.Note: If you're not using Python 3, you should add from __future__ import division
to the top of your file so that you don't get incorrect results for integer coordinate values.
Edit: added short-circuiting and epsilon-comparison for float ratios per @JoranBeasley.