Find Rectangle Boundary Point At An Angle From Point That Is Not In The Middle Of The Rectangle
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"