Reputation: 54
I am working on a python method with is supposed to return the coordinates of interception (the point of collision) for two touching circles. The method works as expected but it seems to be overtly expensive for its purpose.
There should only ever be one point of interception and the sizes of these circles can vary.
def getPointOfContact(self, body):
a1 = min(self.pos.x, body.pos.x) # The x value of the centre of the left-most circle
b1 = min(self.pos.y, body.pos.y) # The y value of the up-most circle
a2 = max(self.pos.x, body.pos.x) # The x value of the right-most circle
b2 = max(self.pos.y, body.pos.y) # The y value of the down-most circle
dx = a2-a1 # (Delta x) The difference in x positions
dy = b2-b1 # (Delta y) The difference in y positions
if dy == 0: # In case of no difference in y,
m = 0 # Gradient is "zero"
elif dx == 0: # In case of no difference in x,
m = float("inf") # Gradient is "infinity"
else:
m = dy/dx # Gradient
if a1 == self.pos.x: # Such that left-most circle's radius is used
r1 = (self.size.x)/2
else:
r1 = (body.size.x)/2
# Calculates the x position of intersection using trig
x = a1+(r1*math.cos(math.atan(m)))
if b1 == self.pos.y: # Such that up-most circle's radius is used
r1 = (self.size.x)/2
else:
r1 = (body.size.x)/2
# Calculates the y position of intersection using trig
y = b1+(r1*math.sin(math.atan(m)))
return (int(x), int(y)) # Returns the coordinates as a tuple of integers
The actual calculation is actually fairly straight forward. It simply adds the x and y components of the radii displacement to the coordinate of the centre of the circle.
The problem is that a lot has to be in place in order from the calculation to be valid, ie the circle used must have the smallest component and the radius (r1) much match to the circle.
Would there be a way of simplifying the method, or even less expensive technique altogether?
Thanks in advance.
Upvotes: 1
Views: 105
Reputation: 3647
I'm not sure I get it. You have the radius of the first circle and you assume they are exactly tangent, right? Then just get rid of your cos
, sin
and atan
:
d = sqrt(d1**2 + d2**2)
x = a1 + dx * r1 / d
y = b1 + dy * r1 / d
Look at this triangle where the +
are the centers and *
the intersection:
0<-dx->|
0 +
^ \ r1
| \
| * d = r1+r2 = sqrt(dx**2 + dy**2)
dy \
| \ r2
v \
- +
Note 1: if m=dy/dx
and you try to compute atan(m)
then you'd better udirectly use atan2(dy, dx)
which will take care of the annoying zeroes and infinity.
Note 2: cos(atan(dy/dx))==dx/R
with R=sqrt(dx**2+dy**2)
and same with sin
and dy
since atan(dy/dx)
is the angle such that dx = R*cos(theta)
and dy = R*sin(theta)
.
Note 3: you're casting things into int
so your circles and intersections might be a bit off.
Upvotes: 1