Sagi Buchbinder Shadur
Sagi Buchbinder Shadur

Reputation: 246

Distance from point to box boundary

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:

enter image description here

Upvotes: 1

Views: 482

Answers (1)

Alexander S. Brunmayr
Alexander S. Brunmayr

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

Related Questions