26

我将如何编写这个函数?任何例子表示赞赏

function isPointBetweenPoints(currPoint, point1, point2):Boolean {

    var currX = currPoint.x;
    var currY = currPoint.y;

    var p1X = point1.x;
    var p1y = point1.y;

    var p2X = point2.x;
    var p2y = point2.y;

    //here I'm stuck
}
4

7 回答 7

61

假设point1point2不同,首先检查点是否在线上。为此,您只需要向量point1 -> currPointpoint1 -> point2.

dxc = currPoint.x - point1.x;
dyc = currPoint.y - point1.y;

dxl = point2.x - point1.x;
dyl = point2.y - point1.y;

cross = dxc * dyl - dyc * dxl;

cross当且仅当等于零时,您的观点才在线。

if (cross != 0)
  return false;

现在,您知道该点确实位于线上,是时候检查它是否位于原始点之间。这可以通过比较x坐标轻松完成,如果线条“比垂直更水平”,或者y坐标其他

if (abs(dxl) >= abs(dyl))
  return dxl > 0 ? 
    point1.x <= currPoint.x && currPoint.x <= point2.x :
    point2.x <= currPoint.x && currPoint.x <= point1.x;
else
  return dyl > 0 ? 
    point1.y <= currPoint.y && currPoint.y <= point2.y :
    point2.y <= currPoint.y && currPoint.y <= point1.y;

请注意,如果输入数据是整数,则上述算法如果完全是整数,即整数输入不需要浮点计算。不过在计算时要小心潜在的溢出cross

PS 这个算法是绝对精确的,这意味着它会拒绝离直线很近但不精确在直线上的点。有时这不是我们所需要的。但这是一个不同的故事。

于 2012-08-10T19:37:36.477 回答
34
   Distance(point1, currPoint)
 + Distance(currPoint, point2)
== Distance(point1, point2)

但要小心,如果你有浮点值,他们的情况会有所不同......

当担心计算“平方根”的计算成本时,不要:
只比较“平方”。

于 2012-08-11T05:24:03.240 回答
4

您想检查从 到 的斜率是否与从到point1currPoint斜率相同,所以:currPointpoint2

m1 = (currY - p1Y) / (currX - p1X);
m2 = (p2Y - currY) / (p2X - currX);

您还想检查是否currPoint在其他两个创建的框内,因此:

return (m1 == m2) && (p1Y <= currY && currY <= p2Y) && (p1X <= currX && currX <= p2X);

编辑:这不是一个很好的方法;查看maxim1000 的解决方案以获得更正确的方法。

于 2012-08-10T19:26:04.983 回答
3

这与 Javascript 无关。尝试以下算法,点 p1=point1 和 p2=point2,第三点是 p3=currPoint:

v1 = p2 - p1
v2 = p3 - p1
v3 = p3 - p2
if (dot(v2,v1)>0 and dot(v3,v1)<0) return between
else return not between

如果您想确保它也在p1 和 p2 之间的线段上:

v1 = normalize(p2 - p1)
v2 = normalize(p3 - p1)
v3 = p3 - p2
if (fabs(dot(v2,v1)-1.0)<EPS and dot(v3,v1)<0) return between
else return not between
于 2012-08-10T19:25:55.800 回答
3

我将使用三角形方法: 三角法

首先,我会检查 Area,如果 Area 接近 0,那么 Point 就在 Line 上。

但是想想AC的长度这么大的情况,那么Area从0增加了很多,但是视觉上,我们仍然看到B在AC上:当我们需要检查三角形的高度时。

为此,我们需要记住我们从一年级学到的公式:Area = Base * Height / 2

这是代码:

    bool Is3PointOn1Line(IList<Vector2> arrVert, int idx1, int idx2, int idx3)
    {
        //check if the area of the ABC triangle is 0:
        float fArea = arrVert[idx1].x * (arrVert[idx2].y - arrVert[idx3].y) +
            arrVert[idx2].x * (arrVert[idx3].y - arrVert[idx1].y) +
            arrVert[idx3].x * (arrVert[idx1].y - arrVert[idx2].y);
        fArea = Mathf.Abs(fArea);
        if (fArea < SS.EPSILON)
        {
            //Area is zero then it's the line
            return true;
        }
        else
        {
            //Check the height, in case the triangle has long base
            float fBase = Vector2.Distance(arrVert[idx1], arrVert[idx3]);
            float height = 2.0f * fArea / fBase;
            return height < SS.EPSILON;
        }
    }

用法:

Vector2[] arrVert = new Vector2[3];

arrVert[0] = //...
arrVert[1] = //...
arrVert[2] = //...

if(Is3PointOn1Line(arrVert, 0, 1, 2))
{
    //Ta-da, they're on same line
}

PS:SS.EPSILON = 0.01f,我使用了 Unity 的一些功能(例如:)Vector2.Distance,但你明白了。

于 2018-12-24T16:01:17.877 回答
1

准备好迎接比其他一些解决方案更简单的方法了吗?

您将三个点传递给它(三个具有 x 和 y 属性的对象)。第 1 点和第 2 点定义您的线,第 3 点是您要测试的点。

function pointOnLine(pt1, pt2, pt3) {
    const dx = (pt3.x - pt1.x) / (pt2.x - pt1.x);
    const dy = (pt3.y - pt1.y) / (pt2.y - pt1.y);
    const onLine = dx === dy

    // Check on or within x and y bounds
    const betweenX = 0 <= dx && dx <= 1;
    const betweenY = 0 <= dy && dy <= 1;

    return onLine && betweenX && betweenY;
}

console.log('pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})');
console.log(pointOnLine({ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 2 }));

console.log('pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})');
console.log(pointOnLine({ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 0.5, y: 0.5 }));

编辑:根据 RBarryYoung 的观察进一步简化。

于 2021-06-24T13:28:50.120 回答
0

这种方法类似于Steve 的方法,只是更短并且经过改进以使用尽可能少的内存和处理能力。但首先是数学思想:

a、b为线的端点,ab为它们之间的差,p为要检查的点。那么p正好在这条线上,如果

a + i * ab = p

i是区间[0;1]中的数字,表示行上的索引。我们可以把它写成两个独立的方程(对于 2D):

ax + i * ab.x = px
ay + i * ab.y = py
⇔<br /> i = (px - ax) / ab.x
i = (py - ay) / ab.y

这给了我们要求pab的要求:

(px - ax) / ab.x = (py - ay) / ab.y

0 ≤ i ≤ 1

在代码中:

function onLine(a, b, p) {
    var i1 = (p.x - a.x) / (b.x - a.x), i2 = (p.y - a.y) / (b.y - a.y);
    return i1 == i2 && i1 <= 0 && i1 >= 1;
}

从技术上讲,您甚至可以内联i2,但这使得它更难阅读。

于 2021-09-10T19:23:59.600 回答