Skip to content Skip to sidebar Skip to footer

Find Rectangle Boundary Point At An Angle From Point That Is Not In The Middle Of The Rectangle

I am trying to display where, in a rectangle, is player aiming in my game. He's in such a square: I found an algorithm to find rectangle point by angle, applied it and the results

Solution 1:

Many parts of your algorithm, for example height / 2., suggest that you still assume that the point is in the centre of the rectangle. If your point can be anywhere in the rectangle you must adapt all numbers, so that you use, for example, y or height - y, depending on wether your ray pointes upward or downward.

A simplification that you can't do anymore when your points are arbitrary is that there is a symmetry between the angles to the four corners. That means you can't use your region approach; at least it will be more complicated.

Another approach is to calculate the intersections of the ray with the four borders and see whether they lie on the rectangle:

function borderPoint(rect, pt, angle) {

    // catch cases where point is outside rectangleif (pt.x < rect.left) returnnull;
    if (pt.x > rect.left + rect.width) returnnull;
    if (pt.y < rect.top) returnnull;
    if (pt.y > rect.top + rect.height) returnnull;

    var dx = Math.cos(angle);
    var dy = Math.sin(angle);

    if (dx < 1.0e-16) {         // left bordervar y = (rect.left - pt.x) * dy / dx + pt.y;

        if (y >= rect.top && y <= rect.top + rect.height) {
            return {x: rect.left, y: y};
        }
    }

    if (dx > 1.0e-16) {         // right bordervar y = (rect.left + rect.width - pt.x) * dy / dx + pt.y;

        if (y >= rect.top && y <= rect.top + rect.height) {
            return {x: rect.left + rect.width, y: y};
        }
    }

    if (dy < 1.0e-16) {         // top bordervar x = (rect.top - pt.y) * dx / dy + pt.x;

        if (x >= rect.left && x <= rect.left + rect.width) {
            return {x: x, y: rect.top};
        }
    }

    if (dy > 1.0e-16) {         // bottom bordervar x = (rect.top + rect.height - pt.y) * dx / dy + pt.x;

        if (x >= rect.left && x <= rect.left + rect.width) {
            return {x: x, y: rect.top + rect.height};
        }
    }

    returnnull;
}

This code uses the mathematical definition of an angle, that is 0 is east, π/2 is north, π is west and 3·π/2 is south. If you use other definitions, you should adapt the code.

The code returns null when the point lies outside the rectangle or when no solution can be found.

Solution 2:

We have: - point with (px, py) coordinates (relative to the rectangle corner) - direction vector (dx, dy) where dx = Cos(theta), dy = Sin(theta) - width, height of rectangle.

We need to find the first point of ray intersection with rectangle. So make some equations:

ifdx=0thent= Infinity
elseif dx > 0 then
  px + dx * t = width
else
  px + dx * t = 0ifdy=0thenu= Infinity
elseif dy > 0 then
  py + dy * u = height
else
  py + dy * u = 0

Solve these equations for t and u. Don't forget Find min value from t and u: v = Min(t, u) - this is the first intersection point. It's coordinates are: (px + v * dx, py + v * dy)

Example

P = (10, 20) 
theta = 135deg = 3 * Pi/4 => D = (-0.707, 0.707)
W = 40, H = 50

t ~ 14
u ~ 42
v = Min(t,u) = 14Int.X = 10 - 14 * 0.707 = 0// really there is is not need to calculate this value, //because we determined that the first intersection occurs for left edgeInt.Y = 20 + 14 * 0.707 = 30

Solution 3:

The player "sees" on of the corners, and depending on which side of the corner he is aiming at, the collision occurs on the vertical or horizontal side.

Let us denote c = cos Θ, s = sin Θ. The equation of the line from (x, y) in the direction (c, s) is (X - x) s - (Y - y) c = 0. The expression on the left-hand side is positive on a side of the line and negative on the other side.

In the first quadrant (c, s > 0), the corner is (w, h), and the V/H decision depends on the sign of (w - x) s - (h - y) c. If the intersection is with the vertical side, we have

X = w, (w - x) s - (Y - y) c = 0, or Y = y + (w - x) s / c.

For the horizontal side,

Y = h, (X - x) s - (h - y) c = 0, or X = x + (h - y) c / s.

We can write

Corner (w, h):if(w - x) s <(h - y)c:
        X= w; Y= y +(w - x) s /celse:
        X= x +(h - y)c/ s; Y= h

Notice that if c==0 or s==0, the solution is still valid because the branch that will be taken is such that no division by zero can arise. Whether < or <= is used in the comparison makes no difference (in case of equality the corner itself is found, both ways).

This can be micro-optimized as

Corner (w, h):
    S=(w - x) s; C=(h - y)cif S < C:
        X= w; Y= y + S /celse:
        X= x + C / s; Y= h

The same discussion can be repeated for the four quadrants, replacing w and/or h by 0. The final code structure is

ifs>=0:ifc>=0:Corner(w,h)else:Corner(0,h)else:ifc>=0:Corner(w,0)else:Corner(0,0)

Take care to adjust the direction of the comparison correctly for the four quadrants.

This formulation was chosen to try to reach a minimum amount of computation, while remaining numerically reliable. We list

  • two sign tests for the selection of the quadrants,
  • one comparison involving two products and two additions,
  • one addition and one division for the intersection computation.

Post a Comment for "Find Rectangle Boundary Point At An Angle From Point That Is Not In The Middle Of The Rectangle"