js中常用的数学方法-用于测试形状与形状是否相交

测试线段与线段是否相交
/**
 * !#en Test line and line
 * !#zh 测试线段与线段是否相交
 * @method lineLine
 * @param {Vec2} a1 - The start point of the first line
 * @param {Vec2} a2 - The end point of the first line
 * @param {Vec2} b1 - The start point of the second line
 * @param {Vec2} b2 - The end point of the second line
 * @return {boolean}
 */
function lineLine ( a1, a2, b1, b2 ) {
    // b1->b2向量 与 a1->b1向量的向量积
    var ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
    // a1->a2向量 与 a1->b1向量的向量积
    var ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
    // a1->a2向量 与 b1->b2向量的向量积
    var u_b  = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
    // u_b == 0时,角度为0或者180 平行或者共线不属于相交
    if ( u_b !== 0 ) {
        var ua = ua_t / u_b;
        var ub = ub_t / u_b;

        if ( 0 <= ua && ua <= 1 && 0 <= ub && ub <= 1 ) {
            return true;
        }
    }

    return false;
}

测试线段与矩形是否相交

/**
 * !#en Test line and rect
 * !#zh 测试线段与矩形是否相交
 * @method lineRect
 * @param {Vec2} a1 - The start point of the line
 * @param {Vec2} a2 - The end point of the line
 * @param {Rect} b - The rect
 * @return {boolean}
 */
function lineRect ( a1, a2, b ) {
    var r0 = new cc.Vec2( b.x, b.y );
    var r1 = new cc.Vec2( b.x, b.yMax );
    var r2 = new cc.Vec2( b.xMax, b.yMax );
    var r3 = new cc.Vec2( b.xMax, b.y );

    if ( lineLine( a1, a2, r0, r1 ) )
        return true;
    if ( lineLine( a1, a2, r1, r2 ) )
        return true;
    if ( lineLine( a1, a2, r2, r3 ) )
        return true;
    if ( lineLine( a1, a2, r3, r0 ) )
        return true;
    return false;
}

测试线段与多边形是否相交

/**
 * !#en Test line and polygon
 * !#zh 测试线段与多边形是否相交
 * @method linePolygon
 * @param {Vec2} a1 - The start point of the line
 * @param {Vec2} a2 - The end point of the line
 * @param {Vec2[]} b - The polygon, a set of points
 * @return {boolean}
 */
function linePolygon ( a1, a2, b ) {
    var length = b.length;

    for ( var i = 0; i < length; ++i ) {
        var b1 = b[i];
        var b2 = b[(i+1)%length];

        if ( lineLine( a1, a2, b1, b2 ) )
            return true;
    }

    return false;
}

测试矩形与矩形是否相交

/**
 * !#en Test rect and rect
 * !#zh 测试矩形与矩形是否相交
 * @method rectRect
 * @param {Rect} a - The first rect
 * @param {Rect} b - The second rect
 * @return {boolean}
 */
function rectRect ( a, b ) {
    // jshint camelcase:false

    var a_min_x = a.x;
    var a_min_y = a.y;
    var a_max_x = a.x + a.width;
    var a_max_y = a.y + a.height;

    var b_min_x = b.x;
    var b_min_y = b.y;
    var b_max_x = b.x + b.width;
    var b_max_y = b.y + b.height;

    return a_min_x <= b_max_x &&
           a_max_x >= b_min_x &&
           a_min_y <= b_max_y &&
           a_max_y >= b_min_y
           ;
}

测试矩形与多边形是否相交

/**
 * !#en Test rect and polygon
 * !#zh 测试矩形与多边形是否相交
 * @method rectPolygon
 * @param {Rect} a - The rect
 * @param {Vec2[]} b - The polygon, a set of points
 * @return {boolean}
 */
function rectPolygon ( a, b ) {
    var i, l;
    var r0 = new cc.Vec2( a.x, a.y );
    var r1 = new cc.Vec2( a.x, a.yMax );
    var r2 = new cc.Vec2( a.xMax, a.yMax );
    var r3 = new cc.Vec2( a.xMax, a.y );

    // 矩形的每条边与多边形是否相交
    if ( linePolygon( r0, r1, b ) )
        return true;

    if ( linePolygon( r1, r2, b ) )
        return true;

    if ( linePolygon( r2, r3, b ) )
        return true;

    if ( linePolygon( r3, r0, b ) )
        return true;
        
    // 走到这可以检测出两个图形无交点
    // 检测是否矩形包含多边形,如果多边形上存在一个点在矩形内,则相交
    for ( i = 0, l = b.length; i < l; ++i ) {
        if ( pointInPolygon(b[i], a) )
            return true;
    }

    // 检测是否多边形包含矩形,如果矩形上存在一个点在多边形内,则相交
    if ( pointInPolygon(r0, b) )
        return true;

    if ( pointInPolygon(r1, b) )
        return true;

    if ( pointInPolygon(r2, b) )
        return true;

    if ( pointInPolygon(r3, b) )
        return true;

    return false;
}

测试多边形与多边形是否相交

/**
 * !#en Test polygon and polygon
 * !#zh 测试多边形与多边形是否相交
 * @method polygonPolygon
 * @param {Vec2[]} a - The first polygon, a set of points
 * @param {Vec2[]} b - The second polygon, a set of points
 * @return {boolean}
 */
function polygonPolygon ( a, b ) {
    var i, l;

    // a的每条边与b的每条边做相交检测
    for ( i = 0, l = a.length; i < l; ++i ) {
        var a1 = a[i];
        var a2 = a[(i+1)%l];

        if ( linePolygon( a1, a2, b ) )
            return true;
    }

    // 判断两个多边形的包含关系
    for ( i = 0, l = b.length; i < l; ++i ) {
        if ( pointInPolygon(b[i], a) )
            return true;
    }

    // 判断两个多边形的包含关系
    for ( i = 0, l = a.length; i < l; ++i ) {
        if ( pointInPolygon( a[i], b ) )
            return true;
    }

    return false;
}

测试圆形与圆形是否相交

/**
 * !#en Test circle and circle
 * !#zh 测试圆形与圆形是否相交
 * @method circleCircle
 * @param {Object} a - Object contains position and radius
 * @param {Object} b - Object contains position and radius
 * @return {boolean}
 * @typescript circleCircle(a: {position: Vec2, radius: number}, b: {position: Vec2, radius: number}): boolean
 */
function circleCircle (a, b) {
    var distance = a.position.sub(b.position).mag(); // 这里用到了内部方法,写在下面了,就是在求a与b之间的距离
    // let sub = function (vector, out) {
    // 向量减法,并返回新结果。因为引擎是3d的所以是Vec3,大家可以直接用Vec2
    // out = out || new Vec3();
    // out.x = this.x - vector.x;
    // out.y = this.y - vector.y;
    // out.z = this.z - vector.z;
    // return out;
    //};
    // mag() {
    // 返回一个距离
    //  return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    //}
     // function Vec2(x, y) {
    //    this.x = x;
    //    this.y = y;
    // }

    return distance < (a.radius + b.radius);
}

多边形与圆形是否相交

/**
 * !#en Test polygon and circle
 * !#zh 多边形与圆形是否相交
 * @method polygonCircle
 * @param {Vec2[]} polygon - The Polygon, a set of points
 * @param {Object} circle - Object contains position and radius
 * @return {boolean}
 * @typescript polygonCircle(polygon: Vec2[], circle: {position: Vec2, radius: number}): boolean
 */
function polygonCircle (polygon, circle) {
    //先判断圆心有没有在多边形内,如果在,一定相交
    var position = circle.position;
    if (pointInPolygon(position, polygon)) {
        return true;
    }
    // 否则遍历多边形的每一条边,如果圆形到边的距离小于圆的半径,则相交
    // 为什么不用点到圆心的距离?我也不清楚。。。望大佬解答
    for (var i = 0, l = polygon.length; i < l; i++) {
        var start = i === 0 ? polygon[polygon.length - 1] : polygon[i- 1];
        var end = polygon[i];

        if (pointLineDistance(position, start, end, true) < circle.radius) {
            return true;
        }
    }

    return false;
}

测试一个点是否在一个多边形中

/**
 * !#en Test whether the point is in the polygon
 * !#zh 测试一个点是否在一个多边形中
 * @method pointInPolygon
 * @param {Vec2} point - The point
 * @param {Vec2[]} polygon - The polygon, a set of points
 * @return {boolean}
 */
function pointInPolygon (point, polygon) {
    //* 射线法判断点是否在多边形内
    //* 点射线(向右水平)与多边形相交点的个数为奇数则认为该点在多边形内
    //* 点射线(向右水平)与多边形相交点的个数为偶数则认为该点不在多边形内
    var inside = false;
    var x = point.x;
    var y = point.y;

    // use some raycasting to test hits
    // https://github.com/substack/point-in-polygon/blob/master/index.js
    var length = polygon.length;

    for ( var i = 0, j = length-1; i < length; j = i++ ) {
        var xi = polygon[i].x, yi = polygon[i].y,
            xj = polygon[j].x, yj = polygon[j].y,
            intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
            // (yi > y) !== (yj > y)表示此条边的两个端点的y值一个大于这个点的y一个小于这个点的y
            //  (x < (xj - xi) * (y - yi) / (yj - yi) + xi) 这个看起来像是求投影呢,还没搞明白
        if ( intersect ) inside = !inside;
    }

    return inside;
}

计算点到直线的距离。如果这是一条线段并且垂足不在线段内,则会计算点到线段端点的距离

/**
 * !#en Calculate the distance of point to line.
 * !#zh 计算点到直线的距离。如果这是一条线段并且垂足不在线段内,则会计算点到线段端点的距离。
 * @method pointLineDistance
 * @param {Vec2} point - The point
 * @param {Vec2} start - The start point of line
 * @param {Vec2} end - The end point of line
 * @param {boolean} isSegment - whether this line is a segment
 * @return {number}
 */
function pointLineDistance(point, start, end, isSegment) {
    var dx = end.x - start.x;
    var dy = end.y - start.y;
    var d = dx*dx + dy*dy;
    var t = ((point.x - start.x) * dx + (point.y - start.y) * dy) / d;
    var p;

    if (!isSegment) {
        p = cc.v2(start.x + t * dx, start.y + t * dy);
    }
    else {
        if (d) {
            if (t < 0) p = start;
            else if (t > 1) p = end;
            else p = cc.v2(start.x + t * dx, start.y + t * dy);
        }
        else {
            p = start;
        }
    }
        
    dx = point.x - p.x;
    dy = point.y - p.y;
    return Math.sqrt(dx*dx + dy*dy);
}

推荐大家还是看原文,解释的更加清楚,此代码只是记录一下笔记

作者:靳国强
链接:https://juejin.cn/post/6844904025587105800
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值