0
$\begingroup$

I am working on a geometric problem involving a line defined by:

  • A midpoint (X,Y),
  • A directional vector (Nx,Ny),
  • An image of dimensions (width,height).

[![enter image description here][1]][1]

My goal is to compute the two points where this line intersects the borders of the image, defined by:

  • $x_{start}$=0 (left border),
  • $x_{end}$=width (right border),
  • $y_{start}$= ? (left border),
  • $y_{end}$= ? (right border).

Current Calculations

I use the following formulas to compute the intersections:

Left border (x=0):

  • yleft=Y−XNx⋅Ny

If yleft is within the bounds of the image (0≤yleft≤height), I retain the point (0,yleft).

Right border (x=width):

  • yright=Y+width−XNx⋅Ny

If yright is within the bounds of the image (0≤yright≤height), I retain the point (width,yright).

Top border (y=0y=0):

  • xtop=X−YNy⋅Nx

If xtop​ is within the bounds of the image (0≤xtop≤width0≤xtop​≤width), I retain the point (xtop,0)(xtop​,0).

Bottom border (y=heighty=height):

  • xbottom=X+height−YNy⋅Nx

If xbottom is within the bounds of the image (0≤xbottom≤width), I retain the point (xbottom,height).

Problem

Using the following input values:

  • X=1000, Y=500,
  • Nx=0.866 (cos⁡(30∘)
  • Ny=0.5 (sin(30∘)),
  • width=1920
  • height=1080,

I get the following result: Intersection points: [(134.0,0),(1920,1031.18)]

I expected the first point to lie exactly on the left border (x=0), but instead, the line intersects the top border (y=0) at x=134.0.

Code

import math def get_horizon_line(X, Y, Nx, Ny, width, height): """ Computes the two points where the horizon line intersects the image borders. Args: X (float): X-coordinate of the midpoint on the horizon line. Y (float): Y-coordinate of the midpoint on the horizon line. Nx (float): Cosine of the direction of the line. Ny (float): Sine of the direction of the line. width (int): Width of the image. height (int): Height of the image. Returns: list: [(x_start, y_start), (x_end, y_end)] Points where the line intersects the borders. """ intersections = [] # Intersection with the left border (x = 0) if Nx != 0: # Avoid division by zero y_left = Y - (X / Nx) * Ny if 0 <= y_left <= height: # Check if the intersection is within bounds intersections.append((0, y_left)) # Intersection with the right border (x = width) if Nx != 0: y_right = Y + ((width - X) / Nx) * Ny if 0 <= y_right <= height: intersections.append((width, y_right)) # Intersection with the top border (y = 0) if Ny != 0: x_top = X - (Y / Ny) * Nx if 0 <= x_top <= width: intersections.append((x_top, 0)) # Intersection with the bottom border (y = height) if Ny != 0: x_bottom = X + ((height - Y) / Ny) * Nx if 0 <= x_bottom <= width: intersections.append((x_bottom, height)) # Ensure exactly two points are returned: one for x = 0 and one for x = width if len(intersections) >= 2: intersections = sorted(intersections, key=lambda p: p[0]) # Sort by x-coordinate return [intersections[0], intersections[-1]] # Leftmost and rightmost points else: raise ValueError("Line does not intersect enough borders within the image.") # Example usage X = 1000 # Midpoint x-coordinate Y = 500 # Midpoint y-coordinate Nx = math.cos(math.radians(30)) # Directional cosine Ny = math.sin(math.radians(30)) # Directional sine width = 1920 height = 1080 points = get_horizon_line(X, Y, Nx, Ny, width, height) print(f"Points of intersection: {points}") 

Which returns:

Points of intersection: [(133.97459621556118, 0), (1920, 1031.1622476544555)] 

which is odd for 133.97 as I was expecting 0 ? [1]: https://i.sstatic.net/fzSHoY16.png

$\endgroup$

1 Answer 1

1
$\begingroup$

If $(N_x, N_y)$ points in the direction of the line, then the vectors $(N_y, -N_x)$ is perpendicular, which means an equation for the line is

$$N_yx - N_xy = D$$ for some constant $D$. Since you know one point $(X,Y)$ on the line, you can find $D$ by $D = N_yX - N_xY$.

Assuming $N_y$ is not $0$, you can solve this for $y$ in terms of $x$: $$y = \frac{N_yx - D}{N_x} = Y + \frac{N_y}{N_x}(x - X)$$ similarly assuming $N_x$ is not $0$, you can solve it for $x$ in terms of $y$:

$$x = \frac{D + N_xy}{N_y} = X + \frac{N_x}{N_y}(y-Y)$$

So you can calculate the intersections with the four sides (or their extensions beyond the image rectangle).

  • The left side has $x_\text{left} = 0$, so $y_\text{left} = Y - \frac{N_y}{N_x}X$.
  • The right side has $x_\text{right} = \text{width}$, so $y_\text{right} = Y - \frac{N_y}{N_x}(X - \text{width}) = Y + \frac{N_y}{N_x}(\text{width} - X)$.
  • The top has $y_\text{top} = 0$, so $x_\text{top} = X - \frac{N_x}{N_y}Y$.
  • The bottom has $y_\text{bottom} = \text{height}$, so $x_\text{bottom} = X - \frac{N_x}{N_y}(Y - \text{height}) = X + \frac{N_x}{N_y}(\text{height} - Y)$.

For your example $(X,Y) = (1000,500); (N_x, N_y) = (0.866, 0.5); (w,h) = (1920,1080)$ these are:

  • Left: $(0, -77)$
  • Right: $(1920,1031)$
  • Top: $(134, 0)$
  • Bottom: $(2005, 1080)$

If you had used the actual center of the image $(960,540)$ as $(X,Y)$ the values would be symmetric about it.

$\endgroup$
1
  • 1
    $\begingroup$ I went through all this (and made a serious error in interpretation that I had to correct) because your original formulas didn't make sense. But then I realized I got the same results as you and discovered that in your code, the formulas are correct, But when you put them in the post, you changed the divisions into multiplications. Still, I will leave it up in case it clarifies your own thoughts. So instead the question is, why did you expect different results? Nothing I see in your post explains this expectation, but apparently it was wrong, not the calculation. $\endgroup$ Commented Dec 12, 2024 at 20:23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.