Reputation: 246
In a game I'm writing with Pygame, I have a 2D point (x,y)
in a box from (0,0)
to (1,1)
(perfect square with side length 1).
I want to calculate the euclidean distance from the point to the box boundary in a direction alpha
, where alpha
is an azimuth direction measured in radians counter-clockwise, starting from alpha=0
as the x-axis direction.
I wrote a python code that calculates this distance, but I'm not sure it's the most efficient/cleanest way:
import numpy as np
def get_distance_to_boundary(x, y, angle):
cos_angle, sin_angle = np.cos(angle), np.sin(angle)
if cos_angle == 0:
return y if sin_angle < 0 else 1 - y
if sin_angle == 0:
return x if cos_angle < 0 else 1 - x
x_target = 1 if cos_angle > 0 else 0
y_target = y + (x_target - x) * np.tan(angle)
if y_target > 1:
return np.fabs((1 - y) / sin_angle)
if y_target < 0:
return np.fabs(y / sin_angle)
return np.sqrt((x_target - x) ** 2 + (y_target - y) ** 2)
Any idea for a better approach?
Illustration:
Upvotes: 1
Views: 482
Reputation: 548
This method is a little more efficient/cleaner because you don't need tan
, fabs
, sqrt
or **2
:
def distance(x,y,angle):
cos_angle, sin_angle = np.cos(angle), np.sin(angle)
if cos_angle == 0:
return y if sin_angle < 0 else 1 - y
if sin_angle == 0:
return x if cos_angle < 0 else 1 - x
distance_EW = (1-x)/cos_angle if cos_angle>0 else -x/cos_angle
distance_NS = (1-y)/sin_angle if sin_angle>0 else -y/sin_angle
return min(distance_EW, distance_NS)
I define distance_EW
as the distance in the case where the target is on the East wall (if cos_angle>0) or on the West wall (if cos_angle<0). Similarly, define distance_NS
for the North or South wall.
...
WARNING: My distance function will sometimes produce different results than your function because of rounding errors!! This is especially problematic when your starting point is at the border of the box and angle
is close to a multiple of π/2.
I would suggest you set some sort of tolerance like if abs(sin_angle) < 1e-12:
, instead of if sin_angle == 0:
. That way, sin_angle = np.sin(np.pi)
will be accepted in the if
condition, even though it is not exactly equal to 0 (because np.sin(np.pi)
is 1.2e-16
with python).
Upvotes: 1