如何在知道前两个点和到下一个点的距离的情况下获得下一个点的坐标

How to get the coordinates of the following point knowing two previous points and the distance to the following point

我想知道如果我知道前两个点和到下一个点的距离,如何找到下一个点的坐标。例如:

-----P1------P2----d---P3-----

数据:

已搜索:

对于此示例,结果将为 P3:{ x: 4, y: 1 }。这是一个简单的计算。当 P1 和 P2 处于不同的象限时,事情会变得复杂,跟随点的方向正在改变或者线处于某个倾斜角度(为此我还没有任何测试)。

所有这些可能性都可以用下图来描述(不包括那些带有倾斜角度的线):

现在,我最终得到这样的算法:

interface Coordinates {
    x: number,
    y: number,
}

function getCoordinatesOfFollowingPointInDistanceToLastPointOnLine (p1: Coordinates, p2: Coordinates,
    distance: number): Coordinates {
    const lineSlope = (p2.y - p1.y) / (p2.x - p1.x);
    const lineTiltAngle = Math.atan(lineSlope);
    const p3x = Math.abs(p1.x) + Math.abs(p2.x) > Math.abs(p1.x)
        ? p2.x + distance * Math.cos(lineTiltAngle)
        : p2.x - distance * Math.cos(lineTiltAngle);
    const p3y = Math.abs(p1.y) + Math.abs(p2.y) > Math.abs(p1.y)
        ? p2.y + distance * Math.sin(lineTiltAngle)
        : p2.y - distance * Math.sin(lineTiltAngle);

    return {
        x: Number(p3x.toFixed(3)),
        y: Number(p3y.toFixed(3))
    };
}

我已经测试了我的算法,但在某些情况下它不起作用(当线是水平的并且跟随点在-∞方向时)。所有测试如下所示:

  getCoordinatesOfFollowingPointInDistanceToLastPointOnLine
    Orientation Horizontal
      Following point in +∞ direction
        √ should calculate correctly position of P3 if P1 and P2 are in I quadrant (2 ms)
        √ should calculate correctly position of P3 if P1 and P2 are in II quadrant (1 ms)
        √ should calculate correctly position of P3 if P1 and P2 are in III quadrant
        √ should calculate correctly position of P3 if P1 and P2 are in IV quadrant (1 ms)
        √ should calculate correctly position of P3 if P1 in quadrant II and P2 in quadrant I (1 ms)
        √ should calculate correctly position of P3 if P1 in quadrant IV and P2 in quadrant III (4 ms)
      Following point in -∞ direction
        × should calculate correctly position of P3 if P1 and P2 are in I quadrant (4 ms)
        × should calculate correctly position of P3 if P1 and P2 are in II quadrant (1 ms)
        × should calculate correctly position of P3 if P1 and P2 are in III quadrant (1 ms)
        × should calculate correctly position of P3 if P1 and P2 are in IV quadrant
        × should calculate correctly position of P3 if P1 in quadrant I and P2 in quadrant II
        × should calculate correctly position of P3 if P1 in quadrant III and P2 in quadrant IV (1 ms)
    Orientation Vertical
      Following point in +∞ direction
        √ should calculate correctly position of P3 if P1 and P2 are in I quadrant
        √ should calculate correctly position of P3 if P1 and P2 are in II quadrant
        √ should calculate correctly position of P3 if P1 and P2 are in III quadrant (1 ms)
        √ should calculate correctly position of P3 if P1 and P2 are in IV quadrant
        √ should calculate correctly position of P3 if P1 in quadrant IV and P2 in quadrant I
        √ should calculate correctly position of P3 if P1 in quadrant III and P2 in quadrant II (1 ms)
      Following point in -∞ direction
        √ should calculate correctly position of P3 if P1 and P2 are in I quadrant (1 ms)
        √ should calculate correctly position of P3 if P1 and P2 are in II quadrant
        √ should calculate correctly position of P3 if P1 and P2 are in III quadrant
        √ should calculate correctly position of P3 if P1 and P2 are in IV quadrant
        √ should calculate correctly position of P3 if P1 in quadrant I and P2 in quadrant IV (1 ms)
        √ should calculate correctly position of P3 if P1 in quadrant II and P2 in quadrant III

测试代码:

// Orientation Horizontal -> Following point in +∞ direction
test('should calculate correctly position of P3 if P1 and P2 are in I quadrant', () => {
    const p1: Coordinates = { x: 0, y: 1 };
    const p2: Coordinates = { x: 2, y: 1 };
    const p3 = getCoordinatesOfFollowingPointInDistanceToLastPointOnLine(p1, p2, 2);

    expect(p3.x).toBe(4);
    expect(p3.y).toBe(1);
});
// Orientation Horizontal -> Following point in -∞ direction
test('should calculate correctly position of P3 if P1 and P2 are in I quadrant', () => {
    const p1: Coordinates = { x: 2, y: 1 };
    const p2: Coordinates = { x: 1, y: 1 };
    const p3 = getCoordinatesOfFollowingPointInDistanceToLastPointOnLine(p1, p2, 2);

    expect(p3.x).toBe(-1);
    expect(p3.y).toBe(1);
});
// Orientation Vertical -> Following point in +∞ direction
test('should calculate correctly position of P3 if P1 and P2 are in I quadrant', () => {
    const p1: Coordinates = { x: 1, y: 1 };
    const p2: Coordinates = { x: 1, y: 2 };
    const p3 = getCoordinatesOfFollowingPointInDistanceToLastPointOnLine(p1, p2, 2);

    expect(p3.x).toBe(1);
    expect(p3.y).toBe(4);
});
// Orientation Vertical -> Following point in +∞ direction
test('should calculate correctly position of P3 if P1 and P2 are in I quadrant', () => {
    const p1: Coordinates = { x: 1, y: 2 };
    const p2: Coordinates = { x: 1, y: 1 };
    const p3 = getCoordinatesOfFollowingPointInDistanceToLastPointOnLine(p1, p2, 2);

    expect(p3.x).toBe(1);
    expect(p3.y).toBe(-1);
});

我可以添加一个 if 来检测这种情况,但是如果线处于某个倾斜角度下怎么办,那么这将很难决定如何计算下一个点的坐标。所以,问题是:我的算法应该如何才能使其始终有效?

更新 1

我已经尝试过@Andreas How to find a third point given both (2 points on a line) and (distance from third point to first point) 链接的算法,但它对我不起作用,除非我做错了什么。您可以在下面找到我是如何实现的:

function getCoordinatesOfFollowingPointInDistanceToLastPointOnLine (p1: Coordinates, p2: Coordinates,
    distance: number): Coordinates {
    const p1P2Distance = Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
    const xDirectionLength = (p2.x - p1.x) / p1P2Distance;
    const yDirectionLength = (p2.y - p1.y) / p1P2Distance;
    const p3x = p1.x + distance * xDirectionLength;
    const p3y = p1.y + distance * yDirectionLength;

    return {
        x: Number(p3x.toFixed(3)),
        y: Number(p3y.toFixed(3))
    };
}

我在评论中提到的 question 中的公式有效。
您的更新从 P1p1.x + ...p1.y + ...)计算 P3,但它应该来自 P2

我已经用数组替换了你的测试和对象,但公式是一样的。
我不得不用“旧”Math.pow() 替换 **,否则第四次测试会失败,因为 (p2.y - p1.y) ** 2 导致 NaN.

~~用于获取整数而不是浮点数)

const testCases = [
  /* P1, P2, distance, P3 */
    [[0, 1], [2, 1], 2, [ 4,  1]],
    [[2, 1], [1, 1], 2, [-1,  1]],
    [[1, 1], [1, 2], 2, [ 1,  4]],
    [[1, 2], [1, 1], 2, [ 1, -1]]
];

function getP3(p1, p2, distance) {
    const p1p2d = Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
    const dx = (p2[0] - p1[0]) / p1p2d;
    const dy = (p2[1] - p1[1]) / p1p2d;
    const p3x = p2[0] + distance * dx;
    const p3y = p2[1] + distance * dy;

    return [~~p3x, ~~p3y];
}

testCases.forEach(({0: p1, 1: p2, 2: d, 3: e}) => {
  const p3 = getP3(p1, p2, d);
  console.log(p3, e, p3[0] == e[0], p3[1] == e[1]);
})