Javascript 检查矢量/角度是否与区域相交
我想做的是: 我有两个x,y点,p1和p2,以及以弧度表示的p1角度的旋转值。 P2还有另外两个变量,一个宽度和高度,我称之为p2w和p2h。我想检查p1的角度是否与p2的边界相交,半径为宽度和/或高度 换句话说,如果角度穿过中心p2、宽度p2w和高度p2h的平方 以下是一个图表,以便于更好地理解: 我一直想做的是:Javascript 检查矢量/角度是否与区域相交,javascript,canvas,Javascript,Canvas,我想做的是: 我有两个x,y点,p1和p2,以及以弧度表示的p1角度的旋转值。 P2还有另外两个变量,一个宽度和高度,我称之为p2w和p2h。我想检查p1的角度是否与p2的边界相交,半径为宽度和/或高度 换句话说,如果角度穿过中心p2、宽度p2w和高度p2h的平方 以下是一个图表,以便于更好地理解: 我一直想做的是: if( p1.rot > (Math.atan2(p2.y-p2h, p2.x-p2w)) && p1.rot < (Math.atan2(p2.y
if( p1.rot > (Math.atan2(p2.y-p2h, p2.x-p2w))
&& p1.rot < (Math.atan2(p2.y+p2h, p2.x+p2w)) )
//There's an intersection
但正如你所猜测的,它并没有按预期的那样工作;还有其他方法吗?这里有一种方法可以测试线段是否为光线?和矩形相交
只需测试线段/光线是否与矩形的两条对角线相交
示例代码和演示:
var canvas=document.getElementByIdcanvas;
var ctx=canvas.getContext2d;
var cw=画布宽度;
var ch=画布高度;
ctx.线宽=3;
函数重偏移{
var BB=canvas.getBoundingClientRect;
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
再抵消;
window.onscroll=function{reOffset;}
var ray1={x:30,y:250,角度:-Math.PI/3.5};
var ray2={x:30,y:250,角度:-Math.PI/6};
var r={x:100,y:100,w:40,h:40};
ctx.strokeStyle='black';
ctx.strokeRectr.x,r.y,r.w,r.h;
//此光线与矩形相交
Drawray1,r;
//此光线与矩形不相交
Drawray2,r;
函数drawRayray,rect{
var intersects=光线矩形相交光线,矩形;
ctx.beginPath;
ctx.moveToray.x,ray.y;
ctx.lineToray.x+1000*数学.cosray.angle,ray.y+1000*数学.sinray.angle;
ctx.strokeStyle=相交?'red':'green';
ctx.stroke;
}
函数rayrectray,rect{
d0={x:rect.x,y:rect.y};
d1={x:rect.x+rect.w,y:rect.y+rect.h};
d2={x:rect.x,y:rect.y+rect.h};
d3={x:rect.x+rect.w,y:rect.y};
ray0={x:ray.x,y:ray.y};
ray1={x:ray.x+1000*Math.cosray.angle,y:ray.y+1000*Math.sinray.angle};
var diag1Test=line2lineIntersectionray0、ray1、d0、d1;
var diag2Test=line2lineIntersectionray0、ray1、d2、d3;
返回诊断1测试| |诊断2测试;
}
//获取两条线段的中间点(如果有)
//归属:http://paulbourke.net/geometry/pointlineplane/
功能线2直线相交P0、p1、p2、p3{
var unknownA=p3.x-p2.x*p0.y-p2.y-p3.y-p2.y*p0.x-p2.x;
var unknownB=p1.x-p0.x*p0.y-p2.y-p1.y-p0.y*p0.x-p2.x;
var分母=p3.y-p2.y*p1.x-p0.x-p3.x-p2.x*p1.y-p0.y;
//测试是否一致
//如果ua和ub的分母和分子为0
//那么这两条线是重合的。
ifunknownA==0&&unknownB==0&&denominator==0{returntrue;}
//测试是否并行
//如果ua和ub方程的分母为0
//那么这两条线是平行的。
如果分母==0,则返回false;
//如果需要线段的交点
//然后只需要测试ua和ub是否介于0和1之间。
//无论哪一个在该范围内,则对应的
//线段包含交点。
//如果两者都在0到1的范围内,则
//交点位于两条线段内。
未知数a/=分母;
未知nb/=分母;
var isIntersecting=unknownA>=0&&unknownA=0&&unknownB这里有一种方法可以测试线段光线和矩形是否相交
只需测试线段/光线是否与矩形的两条对角线相交
示例代码和演示:
var canvas=document.getElementByIdcanvas;
var ctx=canvas.getContext2d;
var cw=画布宽度;
var ch=画布高度;
ctx.线宽=3;
函数重偏移{
var BB=canvas.getBoundingClientRect;
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
再抵消;
window.onscroll=function{reOffset;}
var ray1={x:30,y:250,角度:-Math.PI/3.5};
var ray2={x:30,y:250,角度:-Math.PI/6};
var r={x:100,y:100,w:40,h:40};
ctx.strokeStyle='black';
ctx.strokeRectr.x,r.y,r.w,r.h;
//此光线与矩形相交
Drawray1,r;
//此光线与矩形不相交
Drawray2,r;
函数drawRayray,rect{
var intersects=光线矩形相交光线,矩形;
ctx.beginPath;
ctx.moveToray.x,ray.y;
ctx.lineToray.x+1000*数学.cosray.angle,ray.y+1000*数学.sinray.angle;
ctx.strokeStyle=相交?'red':'green';
ctx.stroke;
}
函数rayrectray,rect{
d0={x:rect.x,y:rect.y};
d1={x:rect.x+rect.w,y:rect.y+rect.h};
d2={x:rect.x,y:rect.y+rect.h};
d3={x:rect.x+rect.w,y:rect.y};
ray0={x:ray.x,y:ray.y};
ray1={x:ray.x+1000*Math.cosray.angle,y:ray.y+1000*Math.sinray.angle};
var diag1Test=line2lineIntersectionray0、ray1、d0、d1;
var diag2Test=line2lineIntersectionray0、ray1、d2、d3;
返回诊断1测试| |诊断2测试;
}
//获取两条线段的中间点(如果有)
//归属:http://paulbourke.net/geometry/pointlineplane/
功能线2直线相交P0、p1、p2、p3{
var unknownA=p3.x-p2.x*p0.y-p2.y-p3.y-p2.y*p0.x-p2.x;
var unknownB=p1.x-p0.x*p0.y-p2.y-p1.y-p0.y*p0.x-p2.x;
德诺明
ator=p3.y-p2.y*p1.x-p0.x-p3.x-p2.x*p1.y-p0.y;
//测试是否一致
//如果ua和ub的分母和分子为0
//那么这两条线是重合的。
ifunknownA==0&&unknownB==0&&denominator==0{returntrue;}
//测试是否并行
//如果ua和ub方程的分母为0
//那么这两条线是平行的。
如果分母==0,则返回false;
//如果需要线段的交点
//然后只需要测试ua和ub是否介于0和1之间。
//无论哪一个在该范围内,则对应的
//线段包含交点。
//如果两者都在0到1的范围内,则
//交点位于两条线段内。
未知数a/=分母;
未知nb/=分母;
var isIntersecting=unknownA>=0&&unknownA=0&&unknownB船长,请救命 您正在询问光线是否与矩形相交。这是我们需要做的 首先,使用点和向量或点和角度定义光线。因为使用向量更容易,所以让我们将角度转换为向量。使用勾股定理,角度φ与向量n={x:Math.cosphi,y:Math.sinphi}相同 我将重命名您的变量,以使标记更容易。我将用p表示p1,用r表示隐式定义的矩形 现在,对于射线上的任意随机点M,下列方程必须成立:
M.x = p.x + n.x * alpha (1)
M.y = p.y + n.y * alpha
M.x >= r.x
M.x <= r.x + r.w
M.y >= r.y
M.y <= r.y + r.h
为了一些真正的阿尔法。类似地,对于矩形内的任意随机点M,以下不等式必须成立:
M.x = p.x + n.x * alpha (1)
M.y = p.y + n.y * alpha
M.x >= r.x
M.x <= r.x + r.w
M.y >= r.y
M.y <= r.y + r.h
对于同时位于光线上和矩形内的点,方程和不等式都必须成立。替换上述值,我们得到:
p.x + n.x * alpha >= r.x
p.x + n.x * alpha <= r.x + r.w
p.y + n.y * alpha >= r.y
p.y + n.y * alpha <= r.y + r.h
求解alpha,我们得到:
alpha >= (r.x - p.x) / n.x
alpha <= (r.x + r.w - p.x) / n.x
alpha >= (r.y - p.y) / n.y
alpha <= (r.y + r.h - p.y) / n.y
当且仅当满足以下条件时,上述系统才有解决方案:
var lowerLimitX = (r.x - p.x) / n.x;
var lowerLimitY = (r.y - p.y) / n.y;
var upperLimitX = (r.x + r.w - p.x) / n.x;
var upperLimitY = (r.y + r.h - p.y) / n.y;
var minAlpha = Math.max(lowerLimitX, lowerLimitY);
var maxAlpha = Math.min(upperLimitX, upperLimitY);
var hasSolution = minAlpha<= maxAlpha;
现在,如果上面的系统有一个解决方案,那么必须至少有一个点位于光线和矩形上,换句话说,它们相交
编辑:这里有一个例子。移动鼠标以查看结果。注意,由于Y轴在HTML画布API中向下生长,因此必须交换Y轴的下限和上限
编辑2:如果您关心@pfannkuchen_gesicht建议的交点,请注意,通常,交点将是线段,而不是点,这也很简单。我们已经知道,对于交点上的点,光线方程必须成立。要查找点本身,只需用1中[minAlpha;maxAlpha]范围内的值替换alpha即可。例如,最近的点是p+minAlpha*n,最远的点是p+maxAlpha*n,中间的一个随机点是p+minAlpha+Math.random*maxAlpha-minAlpha*n.数学队长救命 您正在询问光线是否与矩形相交。这是我们需要做的 首先,使用点和向量或点和角度定义光线。因为使用向量更容易,所以让我们将角度转换为向量。使用勾股定理,角度φ与向量n={x:Math.cosphi,y:Math.sinphi}相同 我将重命名您的变量,以使标记更容易。我将用p表示p1,用r表示隐式定义的矩形 现在,对于射线上的任意随机点M,下列方程必须成立:
M.x = p.x + n.x * alpha (1)
M.y = p.y + n.y * alpha
M.x >= r.x
M.x <= r.x + r.w
M.y >= r.y
M.y <= r.y + r.h
为了一些真正的阿尔法。类似地,对于矩形内的任意随机点M,以下不等式必须成立:
M.x = p.x + n.x * alpha (1)
M.y = p.y + n.y * alpha
M.x >= r.x
M.x <= r.x + r.w
M.y >= r.y
M.y <= r.y + r.h
对于同时位于光线上和矩形内的点,方程和不等式都必须成立。替换上述值,我们得到:
p.x + n.x * alpha >= r.x
p.x + n.x * alpha <= r.x + r.w
p.y + n.y * alpha >= r.y
p.y + n.y * alpha <= r.y + r.h
求解alpha,我们得到:
alpha >= (r.x - p.x) / n.x
alpha <= (r.x + r.w - p.x) / n.x
alpha >= (r.y - p.y) / n.y
alpha <= (r.y + r.h - p.y) / n.y
当且仅当满足以下条件时,上述系统才有解决方案:
var lowerLimitX = (r.x - p.x) / n.x;
var lowerLimitY = (r.y - p.y) / n.y;
var upperLimitX = (r.x + r.w - p.x) / n.x;
var upperLimitY = (r.y + r.h - p.y) / n.y;
var minAlpha = Math.max(lowerLimitX, lowerLimitY);
var maxAlpha = Math.min(upperLimitX, upperLimitY);
var hasSolution = minAlpha<= maxAlpha;
现在,如果上面的系统有一个解决方案,那么必须至少有一个点位于光线和矩形上,换句话说,它们相交
编辑:这里有一个例子。移动鼠标以查看结果。注意,由于Y轴在HTML画布API中向下生长,因此必须交换Y轴的下限和上限
编辑2:如果您关心@pfannkuchen_gesicht建议的交点,请注意,通常,交点将是线段,而不是点,这也很简单。我们已经知道,对于交点上的点,光线方程必须成立。要查找点本身,只需用1中[minAlpha;maxAlpha]范围内的值替换alpha即可。例如,最近的点是p+minAlpha*n,最远的点是p+maxAlpha*n,中间的一个随机点是p+minAlpha+Math.random*maxAlpha-minAlpha*n。非常好的方法!我唯一缺少的是一个交叉点OP并没有要求这样做,但对于一些应用程序来说可能会很有趣,但我认为这是一个很好的快速预测试方法。这是一个很好的解释,t
谢谢你!我会看看这对我的案子是否有效,但你是最好的答案anyway@pfannkuchen_gesicht请参见编辑2.0嘿,最近我再次查看了您的答案,想知道是否也可以在3D中使用此选项。但显然它不起作用。你知道3D AABBs是否有比全面测试更好的射线测试方法吗?因此,在仔细考虑并询问他人后,问题现在其实相当明显。所以它可以归结为不等式和与负数相乘,从而改变它,从而使上界变为下界。所以本质上你必须根据n.{x,y,z}符号交换边界。此外,您还必须引入一个检查,检查最小/最大alpha是否为正,然后才是有效的解决方案。看:真的很好的方法!我唯一缺少的是一个交叉点OP没有要求这样做,但是对于一些应用程序来说会很有趣,但是我认为这是一个很好的快速预测试方法。这是一个很好的解释,谢谢!我会看看这对我的案子是否有效,但你是最好的答案anyway@pfannkuchen_gesicht请参见编辑2.0嘿,最近我再次查看了您的答案,想知道是否也可以在3D中使用此选项。但显然它不起作用。你知道3D AABBs是否有比全面测试更好的射线测试方法吗?因此,在仔细考虑并询问他人后,问题现在其实相当明显。所以它可以归结为不等式和与负数相乘,从而改变它,从而使上界变为下界。所以本质上你必须根据n.{x,y,z}符号交换边界。此外,您还必须引入一个检查,检查最小/最大alpha是否为正,然后才是有效的解决方案。见: