1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
#!/usr/bin/python2.4
#
# 20,000 Light Years Into Space
# This game is licensed under GPL v2, and copyright (C) Jack Whitham 2006-07.
#
# Line intersection algorithm. Thanks to page 113 of
# Computer Graphics Principles and Practice (2nd. Ed), Foley et al.
#
# Note 1: it's not an intersection if the two lines share an endpoint.
# Note 2: Can't detect overlapping parallel lines.
def Intersect(((xa1,ya1),(xa2,ya2)),((xb1,yb1),(xb2,yb2))):
xa = xa2 - xa1
ya = ya2 - ya1
xb = xb2 - xb1
yb = yb2 - yb1
a = ( xa * yb ) - ( xb * ya )
if ( a == 0 ):
return None
b = ((( xa * ya1 ) + ( xb1 * ya ) - ( xa1 * ya )) - ( xa * yb1 ))
tb = float(b) / float(a)
if (( tb <= 0 ) or ( tb >= 1 )):
return None # doesn't intersect
if ( xa == 0 ):
if ( ya == 0 ):
return None # you've confused a line with a point.
ta = ( yb1 + ( yb * tb ) - ya1 ) / float(ya)
else:
ta = ( xb1 + ( xb * tb ) - xa1 ) / float(xa)
if (( ta <= 0 ) or ( ta >= 1 )):
return None # doesn't intersect
x = xb1 + ( xb * tb )
y = yb1 + ( yb * tb )
return (x,y)
def Test():
import random , math
def BT(xp, line1, line2):
assert Intersect(line1, line2) == xp
assert Intersect(line2, line1) == xp
def Rnd():
def RP():
return (random.random(), random.random())
(x,y) = RP() # choose intersection point.
(xa1,ya1) = RP() # line 1 source
(xb1,yb1) = RP() # line 2 source
aang = math.atan2( y - ya1 , x - xa1 ) # line 1 angle
bang = math.atan2( y - yb1 , x - xb1 ) # line 2 angle
xa2 = xa1 + ( math.cos(aang) * 10.0 )
xb2 = xb1 + ( math.cos(bang) * 10.0 )
ya2 = ya1 + ( math.sin(aang) * 10.0 )
yb2 = yb1 + ( math.sin(bang) * 10.0 )
z = Intersect(((xa1,ya1),(xa2,ya2)),((xb1,yb1),(xb2,yb2)))
(xi, yi) = z
assert math.hypot(xi - x, yi - y) < 0.0001
BT((3,2),((3,1),(3,5)),((2,2),(4,2))) # cross
BT(None,((3,1),(3,5)),((1,1),(1,5))) # parallel lines
BT((2,2),((1,1),(3,3)),((1,3),(3,1))) # X
BT(None,((1,1),(3,3)),((2,2),(4,4))) # parallel lines, on top of each other
for i in xrange(10000):
Rnd()
if ( __name__ == "__main__" ):
Test()
|