Javascript 从不在矩形中间点的角度求矩形边界点

Javascript 从不在矩形中间点的角度求矩形边界点,javascript,algorithm,math,graphics,geometry,Javascript,Algorithm,Math,Graphics,Geometry,我试图在一个矩形中显示玩家在我的游戏中瞄准的位置。他在这样一个广场上: 我找到了一个,应用了它,结果是错误的(真实游戏截图): 我很快意识到这是因为播放器不在矩形的中心。所以我用我的点替换了算法中的中心点。但结果只是将点移动了恒定距离: 所以我想我目前的算法需要不止一次的改变。我的代码: function boudaryatangle(theta, point) { // reduce the theta theta = theta % 360; //

我试图在一个矩形中显示玩家在我的游戏中瞄准的位置。他在这样一个广场上:

我找到了一个,应用了它,结果是错误的(真实游戏截图):

我很快意识到这是因为播放器不在矩形的中心。所以我用我的点替换了算法中的中心点。但结果只是将点移动了恒定距离:

所以我想我目前的算法需要不止一次的改变。我的代码:

  function boudaryatangle(theta, point) {
    // reduce the theta  
    theta =  theta % 360; 
    // force it to be the positive remainder, so that 0 <= theta < 360  
    theta = (theta + 360) % 360;  
    // force into the minimum absolute value residue class, so that -180 < theta <= 180  
    if (theta > 180)  
        theta -= 360;  
    // Convert to radians
    theta = (theta * Math.PI / 180);
    // Get a rectangle that has width and height properties
    var rect = this.game.pixels;
    var width = rect.width;
    var height = rect.height;
    // If refference point wasn't provided as second argument
    //TODO: MAKE IT WORK WITH OTHER THEN RECTANGLE CENTRE POINT!
    if(typeof point=="undefined") {
      point = new Float32Array(2);
      point[0] = width/2;
      point[1] = height/2;
    }
    // Here be mysterious math and stuff - all bellow explained here
    var rectAtan = Math.atan2(height, width);
    var tanTheta = Math.tan(theta);
    // By default, region 1 and 3
    var region = true;

    var xFactor = 1;
    var yFactor = 1;

    if ((theta > -rectAtan) && (theta <= rectAtan)) {
        yFactor = -1;  // REGION 1
    } else if ((theta > rectAtan) && (theta <= (Math.PI - rectAtan))) {
        yFactor = -1;  // REGION 2
        region = false;
    } else if ((theta > (Math.PI - rectAtan)) || (theta <= -(Math.PI - rectAtan))) {
        xFactor = -1;  // REGION 3
    } else {
        xFactor = -1;  // REGION 4
        region = false;
    }

    // If region 1, 3
    if (region) {
      point[0] += xFactor * (width / 2.);                                     // "Z0"
      point[1] += yFactor * (width / 2.) * tanTheta;
    } else {
      point[0] += xFactor * (height / (2. * tanTheta));                        // "Z1"
      point[1] += yFactor * (height /  2.);
    }
    return point;
  }
函数边界角(θ,点){
//减小θ
θ=θ%360;
//强制它为正余数,因此0我们有:
-具有(px,py)坐标的点(相对于矩形角)
-方向向量(dx,dy),其中dx=Cos(θ),dy=Sin(θ)

-矩形的宽度、高度

我们需要找到光线与矩形相交的第一个点。因此,建立一些方程:

if dx = 0 then
  t = Infinity
else 
if dx > 0 then
  px + dx * t = width
else
  px + dx * t = 0

if dy = 0 then
  u = Infinity
else 
if dy > 0 then
  py + dy * u = height
else
  py + dy * u = 0
求解这些t和u的方程。不要忘记从t和u中找到最小值:
v=min(t,u)
-这是第一个交点。它的坐标是:
(px+v*dx,py+v*dy)

范例

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) = 14
Int.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 edge
Int.Y = 20 + 14 * 0.707 = 30
我们有:
-具有(px,py)坐标的点(相对于矩形角)
-方向向量(dx,dy),其中dx=Cos(θ),dy=Sin(θ)
-矩形的宽度、高度

我们需要找到光线与矩形相交的第一个点。因此,建立一些方程:

if dx = 0 then
  t = Infinity
else 
if dx > 0 then
  px + dx * t = width
else
  px + dx * t = 0

if dy = 0 then
  u = Infinity
else 
if dy > 0 then
  py + dy * u = height
else
  py + dy * u = 0
求解这些t和u的方程。不要忘记从t和u中找到最小值:
v=min(t,u)
-这是第一个交点。它的坐标是:
(px+v*dx,py+v*dy)

范例

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) = 14
Int.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 edge
Int.Y = 20 + 14 * 0.707 = 30
我们有:
-具有(px,py)坐标的点(相对于矩形角)
-方向向量(dx,dy),其中dx=Cos(θ),dy=Sin(θ)
-矩形的宽度、高度

我们需要找到光线与矩形相交的第一个点。因此,建立一些方程:

if dx = 0 then
  t = Infinity
else 
if dx > 0 then
  px + dx * t = width
else
  px + dx * t = 0

if dy = 0 then
  u = Infinity
else 
if dy > 0 then
  py + dy * u = height
else
  py + dy * u = 0
求解这些t和u的方程。不要忘记从t和u中找到最小值:
v=min(t,u)
-这是第一个交点。它的坐标是:
(px+v*dx,py+v*dy)

范例

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) = 14
Int.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 edge
Int.Y = 20 + 14 * 0.707 = 30
我们有:
-具有(px,py)坐标的点(相对于矩形角)
-方向向量(dx,dy),其中dx=Cos(θ),dy=Sin(θ)
-矩形的宽度、高度

我们需要找到光线与矩形相交的第一个点。因此,建立一些方程:

if dx = 0 then
  t = Infinity
else 
if dx > 0 then
  px + dx * t = width
else
  px + dx * t = 0

if dy = 0 then
  u = Infinity
else 
if dy > 0 then
  py + dy * u = height
else
  py + dy * u = 0
求解这些t和u的方程。不要忘记从t和u中找到最小值:
v=min(t,u)
-这是第一个交点。它的坐标是:
(px+v*dx,py+v*dy)

范例

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) = 14
Int.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 edge
Int.Y = 20 + 14 * 0.707 = 30

算法的许多部分,例如
height/2.
,建议您仍然假设该点位于矩形的中心。如果您的点可以位于矩形中的任何位置,则必须调整所有数字,以便根据光线指向上还是指向下,使用例如
y
height-y
诺沃德

当你的点是任意的时,你不能再做的一个简化是,四个角的角度之间是对称的。这意味着你不能使用你的区域方法;至少它会更复杂

另一种方法是计算光线与四个边界的交点,并查看它们是否位于矩形上:

function borderPoint(rect, pt, angle) {

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

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

    if (dx < 1.0e-16) {         // left border
        var 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 border
        var 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 border
        var 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 border
        var 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};
        }
    }

    return null;
}
函数边界点(矩形、角点、角点){
//捕捉点位于矩形外的情况
if(pt.xrect.left+rect.width)返回null;
if(pt.yrect.top+rect.height)返回null;
var dx=数学cos(角度);
var dy=数学sin(角度);
如果(dx<1.0e-16){//左边框
变量y=(右-右)*dy/dx+pt.y;
如果(y>=rect.top&&y 1.0e-16){//右边框
变量y=(rect.left+rect.width-pt.x)*dy/dx+pt.y;
如果(y>=rect.top&&y=rect.left&&x1.0e-16){//下边框
变量x=(rect.top+rect.height-pt.y)*dx/dy+pt.x;

如果(x>=rect.left&&x算法的许多部分,例如
height/2.
,建议您仍然假设该点位于矩形的中心。如果您的点可以位于矩形中的任何位置,则必须调整所有数字,以便根据光线的不同,使用例如
y
height-y
指向上或向下

当你的点是任意的时,你不能再做的一个简化是,四个角的角度之间是对称的。这意味着你不能使用你的区域方法;至少它会更复杂

另一种方法是计算光线与四个边界的交点,并查看它们是否位于矩形上:

function borderPoint(rect, pt, angle) {

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

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

    if (dx < 1.0e-16) {         // left border
        var 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 border
        var 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 border
        var 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 border
        var 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};
        }
    }

    return null;
}
函数边界点(矩形、角点、角点){
//捕捉点位于矩形外的情况
if(pt.xrect.left+rect.width)返回null;
if(pt.yrect.top+rect.height)返回null;
var dx=数学cos(角度);
var dy=数学sin(角度);
如果(dx<1.0e-16){//左边框
变量y=(右-右)*dy/dx+pt.y;
如果(y>=rect.top&&y 1.0e-16){//右边框
变量y=(rect.left+rect.width-pt.x)*dy/dx+pt.y;
如果(y>=rect.top&&y=rect.left&&x1.0e-16){//下边框
变量x=(rect.top+rect.height-pt.y)*dx/dy+pt.x;

如果(x>=rect.left&&x算法的许多部分,例如
height/2.
,建议您仍然假设该点位于