Javascript 圆线段碰撞

Javascript 圆线段碰撞,javascript,canvas,html5-canvas,Javascript,Canvas,Html5 Canvas,我需要检测任何直线的碰撞圆。我有一个多边形(x,y)的垂直线阵列,并在循环中绘制这个多边形。对于检测,我使用计算三角形高度的算法。然后我检查这个高度是否小于0,然后圆与直线碰撞 描述此方法的图片: 但我有一个意想不到的结果。我的圆圈与透明线碰撞(什么?)。我无法解释它是如何发生的 在JSFIDLE上演示: 函数,用于检查碰撞并对其进行响应: var p = polygonPoints; for (var i = 0, n = p.length; i < n; i++) { va

我需要检测任何直线的碰撞圆。我有一个多边形(x,y)的垂直线阵列,并在循环中绘制这个多边形。对于检测,我使用计算三角形高度的算法。然后我检查这个高度是否小于0,然后圆与直线碰撞

描述此方法的图片:

但我有一个意想不到的结果。我的圆圈与透明线碰撞(什么?)。我无法解释它是如何发生的

在JSFIDLE上演示:

函数,用于检查碰撞并对其进行响应:

var p = polygonPoints;

for (var i = 0, n = p.length; i < n; i++) {
    var start = i;
    var end = (i + 1) % n;

    var x0 = p[start].x;
    var y0 = p[start].y;
    var x1 = p[end].x;
    var y1 = p[end].y;

    // detection collision
    var dx = x1 - x0;
    var dy = y1 - y0;

    var len = Math.sqrt(dx * dx + dy * dy);
    var dist = (dx * (this.y - y0) - dy * (this.x - x0)) / len;

    if (dist < this.radius) {
        continue;
    }

    // calculate reflection, because collided
    var wallAngle = Math.atan2(dy, dx);
    var wallNormalX = Math.sin(wallAngle);
    var wallNormalY = -Math.cos(wallAngle);

    var d = 2 * (this.velocityX * wallNormalX + this.velocityY * wallNormalY);
    this.x -= d * wallNormalX;
    this.y -= d * wallNormalY;
}
圆线段截距 更新

此答案包括直线截距、沿法线移动直线、点(圆)到直线的距离以及圆线截距

圆圈是

var circle = {
    radius : 500,
    center : point(1000,1000),
}
线段是

var line = {
    p1 : point(500,500),
    p2 : point(2000,1000),
}
一点是

var point = {
    x : 100,
    y : 100,
}
因此,该函数可以找到一条线段的截距,宽度为一个圆

该函数返回线段上最多两个点的数组。如果未找到点,则返回空数组

function inteceptCircleLineSeg(circle, line){
    var a, b, c, d, u1, u2, ret, retP1, retP2, v1, v2;
    v1 = {};
    v2 = {};
    v1.x = line.p2.x - line.p1.x;
    v1.y = line.p2.y - line.p1.y;
    v2.x = line.p1.x - circle.center.x;
    v2.y = line.p1.y - circle.center.y;
    b = (v1.x * v2.x + v1.y * v2.y);
    c = 2 * (v1.x * v1.x + v1.y * v1.y);
    b *= -2;
    d = Math.sqrt(b * b - 2 * c * (v2.x * v2.x + v2.y * v2.y - circle.radius * circle.radius));
    if(isNaN(d)){ // no intercept
        return [];
    }
    u1 = (b - d) / c;  // these represent the unit distance of point one and two on the line
    u2 = (b + d) / c;    
    retP1 = {};   // return points
    retP2 = {}  
    ret = []; // return array
    if(u1 <= 1 && u1 >= 0){  // add point if on the line segment
        retP1.x = line.p1.x + v1.x * u1;
        retP1.y = line.p1.y + v1.y * u1;
        ret[0] = retP1;
    }
    if(u2 <= 1 && u2 >= 0){  // second add point if on the line segment
        retP2.x = line.p1.x + v1.x * u2;
        retP2.y = line.p1.y + v1.y * u2;
        ret[ret.length] = retP2;
    }       
    return ret;
}
提升线

沿其法线移动直线

function liftLine(line,dist){
    var v1,l
    v1 = {};
    v1.x = line.p2.x - line.p1.x; // convert line to vector
    v1.y = line.p2.y - line.p1.y;
    l = Math.sqrt(v1.x * v1.x + v1.y * v1.y); // get length;
    v1.x /= l;  // Assuming you never pass zero length lines
    v1.y /= l;
    v1.x *= dist; // set the length
    v1.y *= dist;
    // move the line along its normal the required distance
    line.p1.x -= v1.y;
    line.p1.y += v1.x;
    line.p2.x -= v1.y;
    line.p2.y += v1.x;

    return line; // if needed 
}
圆(或点)到线段的距离

返回到线段的最近距离。我用的就是圆心。所以你可以用点代替圆

function circleDistFromLineSeg(circle,line){
    var v1, v2, v3, u;
    v1 = {};
    v2 = {};
    v3 = {};
    v1.x = line.p2.x - line.p1.x;
    v1.y = line.p2.y - line.p1.y;
    v2.x = circle.center.x - line.p1.x;
    v2.y = circle.center.y - line.p1.y;
    u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x); // unit dist of point on line
    if(u >= 0 && u <= 1){
        v3.x = (v1.x * u + line.p1.x) - circle.center.x;
        v3.y = (v1.y * u + line.p1.y) - circle.center.y;
        v3.x *= v3.x;
        v3.y *= v3.y;
        return Math.sqrt(v3.y + v3.x); // return distance from line
    } 
    // get distance from end points
    v3.x = circle.center.x - line.p2.x;
    v3.y = circle.center.y - line.p2.y;
    v3.x *= v3.x;  // square vectors
    v3.y *= v3.y;    
    v2.x *= v2.x;
    v2.y *= v2.y;
    return Math.min(Math.sqrt(v2.y + v2.x), Math.sqrt(v3.y + v3.x)); // return smaller of two distances as the result
}
函数circleDistFromLineSeg(圆,线){
变量v1、v2、v3、u;
v1={};
v2={};
v3={};
v1.x=line.p2.x-line.p1.x;
v1.y=line.p2.y-line.p1.y;
v2.x=圆.center.x-线.p1.x;
v2.y=圆.中心.y-线.p1.y;
u=(v2.x*v1.x+v2.y*v1.y)/(v1.y*v1.y+v1.x*v1.x);//线上点的单位距离

如果(u>=0&&u如果球的速度较低,则此方法有效,但如果速度较高,则功能不起作用。请参阅控制台,如果圆圈相交,则应用程序应打印交点数组,但圆圈的速度较高,且控制台日志清除。@rmpstmp使用直线截距,使用球的轨迹作为第二条直线。沿其正常拖曳移动直线按球的半径旋转球。如果线相交,则使用该点测试球与原始线段的距离。如果在半径处(添加ε)从直线上的任何点,或你击球的端点。叉积将给出点到直线的哪一侧+右-左,点积div line leng squared将给出直线上沿其法线到该点的单位距离。点和直线需要转换以使直线开始zero@rmpstmp看着小提琴,把所有的东西都挪动由球半径向内的线段(沿线法线)。将球的轨迹用作直线,并进行直线/直线截取。找到离球的当前位置最近的截取点,您就有了截取点,不需要圆线段截取。好的,您能描述一下,我应该发送哪些线到函数
截取线(直线,直线1)
?其中一条线应该是墙线,但第二条?我认为是从球的中心开始的线
(b.x,b.y)
例如,第二点应该是什么?谢谢。@rmpstmp我已经添加了您需要的函数。第二点是球的x,y加上球的速度。您将得到几次拦截。您需要知道它们离当前球的位置有多远。如果它们比球的速度远,则什么都没有发生。我忘了您有ir常规多边形需要做一个沿直线的距离测试。将添加最后的函数来回答
function circleDistFromLineSeg(circle,line){
    var v1, v2, v3, u;
    v1 = {};
    v2 = {};
    v3 = {};
    v1.x = line.p2.x - line.p1.x;
    v1.y = line.p2.y - line.p1.y;
    v2.x = circle.center.x - line.p1.x;
    v2.y = circle.center.y - line.p1.y;
    u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x); // unit dist of point on line
    if(u >= 0 && u <= 1){
        v3.x = (v1.x * u + line.p1.x) - circle.center.x;
        v3.y = (v1.y * u + line.p1.y) - circle.center.y;
        v3.x *= v3.x;
        v3.y *= v3.y;
        return Math.sqrt(v3.y + v3.x); // return distance from line
    } 
    // get distance from end points
    v3.x = circle.center.x - line.p2.x;
    v3.y = circle.center.y - line.p2.y;
    v3.x *= v3.x;  // square vectors
    v3.y *= v3.y;    
    v2.x *= v2.x;
    v2.y *= v2.y;
    return Math.min(Math.sqrt(v2.y + v2.x), Math.sqrt(v3.y + v3.x)); // return smaller of two distances as the result
}