计算不在范围集之间的最小值

时间:2015-04-14 21:32:18

标签: javascript math trigonometry intervals

给定一个圆阵列(x,y,r值),我想放置一个新点,使其具有固定/已知的Y坐标(显示为水平线),并且尽可能接近到中心但不在任何现有的圈子内。在示例图像中,红色的点将是结果。

圆具有已知的半径和Y轴属性,因此很容易计算它们在已知Y值处与水平线相交的点。效率非常重要,我不想尝试一堆X coords并针对circle数组中的每个项目测试它们。有没有办法在数学上计算出这个最佳X坐标?任何帮助非常感谢。顺便说一下,我使用Raphael.js库在javascript中编写它(因为它是唯一一个支持IE8的程序) - 但这更像是一个逻辑问题所以语言并不重要。 enter image description here

3 个答案:

答案 0 :(得分:2)

我按照以下方式处理您的问题:

  1. 初始化一组间隔 S ,按间隔的X坐标排序,为空集
  2. 对于每个圆 c ,使用X轴计算 c 的交点 I c 的间隔。如果 c 不相交,请转到下一个圆圈。否则,测试 I c 是否与 S 中的任何间隔重叠(这很快,因为 S 是排序);如果是这样,从 S 中删除所有相交的间隔,将 I c 和所有删除的间隔折叠到新的间隔 I&#39; < sub> c 并将 I&#39; c 添加到 S 。如果没有交叉点,请将 I c 添加到 S
  3. 检查 S 中的任何间隔是否包含中心(同样,快速因为 S 已排序)。如果是,请选择最靠近中心的间隔终点;如果没有,请选择中心作为最近点。

答案 1 :(得分:1)

基本上圆的方程是(x - c x 2 +(y - c y 2 = r 2 。因此,您可以通过用 0 替换 y ,轻松找到圆和X轴之间的交点。之后你只需要一个简单的quadratic equation来解决: x 2 - 2c x x + c x 2 + c y 2 - r 2 = 0 。为此,您有3种可能的结果:

  • 没有交集 - 行列式将是无理数(JavaScript中的NaN),忽略此结果;
  • 一个交叉点 - 两个解决方案匹配,使用 [value,value] ;
  • 两个交叉点 - 两个解决方案都不同,请使用 [value1,value2]

对新计算的交叉点间隔进行排序,然后尝试将它们合并到可能的位置。但请记住,在每种程序语言中都有近似值,因此您需要为点近似定义delta值,并在合并间隔时将其考虑在内。

合并间隔时,您可以通过将相同的delta值减去/添加到每个间隔的开头/结尾来生成 x 坐标。最后,从所有点来看,最接近零的是你的答案。

以下是 O(n log n)复杂性的一个示例,其面向可读性。我已经使用 1 * 10 -10 获取delta:

var circles = [
    {x:0, y:0, r:1},
    {x:2.5, y:0, r:1},
    {x:-1, y:0.5, r:1},
    {x:2, y:-0.5, r:1},
    {x:-2, y:0, r:1},
    {x:10, y:10, r:1}
];

console.log(getClosestPoint(circles, 1e-10));



function getClosestPoint(circles, delta)
{
    var intervals = [],
        len = circles.length, 
        i, result;
    for (i = 0; i < len; i++)
    {
        result = getXIntersection(circles[i])
        if (result)
        {
            intervals.push(result);
        }
    }

    intervals = intervals.sort(function(a, b){
        return a.from - b.from;
    });
    if (intervals.length <= 0) return 0;
    intervals = mergeIntervals(intervals, delta);

    var points = getClosestPoints(intervals, delta);
    points = points.sort(function(a, b){
        return Math.abs(a) - Math.abs(b);
    });
    return points[0];
}

function getXIntersection(circle)
{
    var d = Math.sqrt(circle.r * circle.r - circle.y * circle.y);
    return isNaN(d) ? null : {from: circle.x - d, to: circle.x + d};
}

function mergeIntervals(intervals, delta)
{
    var curr = intervals[0],
        result = [],
        len = intervals.length, i;
    for (i = 1 ; i < len ; i++)
    {
        if (intervals[i].from <= curr.to + delta)
        {
            curr.to = Math.max(curr.to, intervals[i].to);
        } else {
            result.push(curr);
            curr = intervals[i];
        }
    }
    result.push(curr);
    return result;
}

function getClosestPoints(intervals, delta)
{
    var result = [], 
        len = intervals.length, i;
    for (i = 0 ; i < len ; i++)
    {
        result.push( intervals[i].from - delta );
        result.push( intervals[i].to + delta );
    }
    return result;
}

答案 2 :(得分:0)

  1. 创建intersect_segments数组(在x = 0 y = 0时标准化)

  2. 按上限排序intersectsegments并删除那些上限<0

  3. 初始化point1 = 0和segment = 0

  4. 循环,而point1在intersectsegment [segment]

    4.1。通过交叉段[段]的uppper限制增加point1

    4.2。增量段

  5. 通过lowerlimit对intersectsgments进行排序,并删除那些带有loerlimit&gt; 0

  6. 初始化point2 = 0且segment = 0

  7. 循环,而point2在intersectsegments [segment]

    7.1。按段的下限递减point2

    7.2。减量段

  8. 该点是p1和p2的最小绝对值