【问题标题】:How to insert a point in the correct location of an array of points (polyline)如何在点数组的正确位置插入一个点(折线)
【发布时间】:2014-03-19 02:30:36
【问题描述】:

假设我有一组用于绘制折线的点。当我点击折线时,我想在点击发生的线上添加一个新点。我需要弄清楚在数组中插入新点的位置,以便正确绘制线。一条线可以向任何方向走:上、下、左、右、上和左、下和右等,所以我最初的想法是弄清楚线的方向和斜率,然后从那里进行比较。考虑到这一点,我想出了这个代码:

 /**
 * Determines direction line is traveling in
 * @param {Object} point1 - starting point
 * @param {Object} point2 - ending point
 * @param {Object} offset - position offset
 * @return {Number} direction traveling (0 - straight up, 1 - up & right, 2 - straight right, 3 - down & right, etc.)
 */
getLineDirection: function(point1, point2, offset){
    var rise, run, abs1, abs2, dirX, dirY,
        slope, direction, ceil = {}, floor = {};

    //get normalized positions
    abs1 = this.getPointPosition(null,offset,point1);
    abs2 = this.getPointPosition(null,offset,point2);

    dirX = abs1.x > abs2.x ? -1 : 1;
    dirY = abs1.y > abs2.y ? 1 : -1;

    ceil.x = abs2.x > abs1.x ? abs2.x : abs1.x;
    ceil.y = abs2.y > abs1.y ? abs2.y : abs1.y;

    floor.x = abs2.x > abs1.x ? abs1.x : abs2.x;
    floor.y = abs2.y > abs1.y ? abs1.y : abs2.y;

    run = ceil.x - floor.x;
    rise = ceil.y - floor.y

    if(abs2.y > abs1.y){
        rise = -rise;
    }

    if(abs2.x < abs1.x){
        run = -run;
    }

    if(rise !== 0){
        slope = rise/run;
        if(slope === 0){
            //horizontal
            direction = dirX > 0 ? 2 : 6;
        } else {
            //angle
            if(dirX === 1){
                direction = dirY === 1 ? 1 : 3;
            } else {
                direction = dirY === -1 ? 5 : 7;
            }
        }
    } else {
        //vertical
        direction = dirY > 0 ? 0 : 4;
    }

    return direction;
}

有了这个,我想我可以遍历构成线的点,然后确定是否应该在相应的点之前插入新点。这几乎可以正常工作,但是有些问题。

findInsertionIndex : function(x,y){
    var count = this.points.length-1;
    var p1 = this.points[0];
    var p2 = { x : p1.x, y : p1.y };
    var offset = this.offset();
    var direction, pos;

    for(i = 1; i < count;i++){
        p2.x += this.points[i].x;
        p2.y += this.points[i].y;
        direction = this.getLineDirection(p1,p2,offset);
        pos = this.getPointPosition(null,offset,p2);

        //TODO: handle vertical lines
        if(direction > 0 && direction < 4){
            if(x < pos.x){
                break;
            }
        } else if (direction > 4){
            if(x > pos.x){
                break;
            }
        }

        p1 = p2;
    }

    return i;
}

我数学很烂,但这似乎是一种合乎逻辑的方法。我在想可能有更好的方法来做到这一点。如果有人能指出我正确的方向,我将不胜感激。

好的,不要再廉价双关语了:)

编辑

感谢@MvG,这里是完整的 findInsertionIndex 块供参考:

findInsertionIndex : function(x,y){
    var count = this.points.length;
    var offset = this.offset();
    var p1 = this.getPointPosition(0,offset), p2;
    var direction, pos, ox, oy, dx, dy, t, ex, ey, errSq,best,bestIndex = count-1;

    for(var i = 1; i < count;i++){
        p2 = this.getPointPosition(i,offset);
        ox = x - p1.x;
        oy = y - p1.y;
        dx = p2.x - p1.x;
        dy = p2.y - p1.y;

        t = (ox*dx + oy*dy)/(dx*dx + dy*dy);
        if (t < 0) t = 0;
        if (t > 1) t = 1;
        ex = t*dx - ox;
        ey = t*dy - oy;
        errSq = ex*ex + ey*ey;
        if (!best || errSq < best) {
          best = errSq;
          bestIndex = i;
        }

        p1 = p2;
    }

    return bestIndex;

}

【问题讨论】:

    标签: vector geometry 2d lines polyline


    【解决方案1】:

    放弃斜率概念,因为它会迫使您对垂直线进行特殊处理。相反,您可以计算如下:

    ox = x - p1.x;
    oy = y - p1.y;
    dx = p2.x - p1.x;
    dy = p2.y - p1.y;
    t = (ox*dx + oy*dy)/(dx*dx + dy*dy);
    if (t < 0) t = 0;
    if (t > 1) t = 1;
    ex = t*dx - ox;
    ey = t*dy - oy;
    errSq = ex*ex + ey*ey;
    if (errSq < best) {
      best = errSq;
      bestIndex = i;
    }
    

    这会查看每个段上最接近您的输入点的点。它首先确定一个参数 t,该参数告诉您该最近点出现在沿线段的哪个位置。这是线(dx,dy)的方向向量与起点到鼠标点(ox,oy)的向量的点积,除以方向向量的平方范数。将此 t 限制在 [0,1] 范围内,您将自己重构为段而不是整行。然后你可以计算这个最近点和你的输入点之间的差向量(ex,ey),并把它的平方范数作为输入点实际上离当前段有多近的度量。遍历所有线段并记住最好的,你就完成了。

    【讨论】:

    • 感谢您的回复。我正在验证这个解决方案。一旦我能够完全验证,将相应地标记答案,但到目前为止它看起来不错!再次感谢:)
    猜你喜欢
    • 2012-09-17
    • 2013-10-03
    • 1970-01-01
    • 2019-02-24
    • 2019-02-06
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多