To finish off the last two posts, here is an implementation of the circle sorting algorithm as a Python script. The method, order_circles, accepts as input the x, y and quadrance of two circles, and returns -1 if C1 < C2, or returns 0 if C1 = C2, or returns 1 if C1 > C2. The ordering is based on descending order of the circle bottoms, but the x-coordinate is used as a tiebreaker.
This design is slightly different than a native speaker of Python might design it: they would typically implement the algorithm as a true/false result depending on whether C1 < C2. I implemented the three-return-code result for two reasons: I am a native C# speaker, where the IComparable interface rules, and because I found the Python way to be a bit less elegant when I was implementing the tiebreaker code. It's trivially easy to convert my answer to the Python one, if you are so inclined.
CIRCLE_1_FIRST = -1
CIRCLES_EQUAL = 0
CIRCLE_2_FIRST = 1
def order_circles(x1, y1, q1, x2, y2, q2):
result = order_circle_bottoms(y1, q1, y2, q2)
if result == CIRCLES_EQUAL:
result = order_numbers(x1, x2)
return result
def order_circle_bottoms(y1, q1, y2, q2):
if q1 == q2:
return order_numbers(y2, y1)
if q1 < q2:
yS,qS = y1,q1
yL,qL = y2,q2
invert = 1
else:
yS,qS = y2,q2
yL,qL = y1,q1
invert = -1
if yS >= yL:
return CIRCLE_1_FIRST * invert
elif pow(yL - yS, 2) > qL:
return CIRCLE_2_FIRST * invert
else:
yC = (pow(yS, 2) - pow(yL, 2) + qL - qS) / (2 * (yS - yL))
return order_numbers(qS, pow(yC - yS, 2)) * invert
def order_numbers(a, b):
if a < b:
return CIRCLE_1_FIRST
elif a > b:
return CIRCLE_2_FIRST
else:
return CIRCLES_EQUAL
#------------------------------------------------------------------------------------
def test_case(desc, x1, y1, q1, x2, y2, q2, expected):
if (order_circles(x1, y1, q1, x2, y2, q2) == expected and
order_circles(x2, y2, q2, x1, y1, q1) == -expected):
print('PASS\t' + desc)
else:
print('!FAIL!\t' + desc)
test_case('Equal circles', 0, 0, 4, 0, 0, 4, CIRCLES_EQUAL)
test_case('Same size circles', 0, 1, 4, 0, 0, 4, CIRCLE_1_FIRST)
test_case('Same center circles', 0, 0, 1, 0, 0, 4, CIRCLE_1_FIRST)
test_case('Smaller circle higher', 0, 10, 1, 0, 0, 4, CIRCLE_1_FIRST)
test_case('Smaller circle beneath larger', 0, 0, 4, 0, -10, 1, CIRCLE_1_FIRST)
test_case('Smaller circle inside larger', 0, 0, 1, 0, 5, 100, CIRCLE_1_FIRST)
test_case('Smaller circle poking out of larger', 0, 3, 16, 0, 0, 4, CIRCLE_1_FIRST)
test_case('Unequal circles tangent', 0, 1, 1, 0, 2, 4, CIRCLES_EQUAL)
test_case('Equal circles x order', 0, 0, 4, 1, 0, 4, CIRCLE_1_FIRST)
test_case('Unequal circles tangent x order', 0, 1, 1, 1, 2, 4, CIRCLE_1_FIRST)
No comments:
Post a Comment