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

point1それとが異なると仮定してpoint2、最初にポイントが線上にあるかどうかを確認します。point1 -> currPointそのためには、ベクトルとの「外積」が必要ですpoint1 -> 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

point1からの勾配がからへcurrPointの勾配と同じであるかどうかを確認する必要があるcurrPointためpoint2、次のようになります。

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

currPointまた、他の2つによって作成されたボックス内にあるかどうかを確認する必要があるため、次のようにします。

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

編集:これはあまり良い方法ではありません。より正確な方法については、maxim1000のソリューションをご覧ください。

于 2012-08-10T19:26:04.983 に答える
3

これはJavascriptから独立しています。次のアルゴリズムを試してください。ポイントはp1=point1とp2=point2で、3番目のポイントは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

トライアングルアプローチを使用します: トライアングルアプローチ

まず、エリアを確認します。エリアが0に近い場合、ポイントはライン上にあります。

しかし、ACの長さが非常に長い場合、面積は0から大きく増加しますが、視覚的には、BがAC上にあることがわかります。つまり、三角形の高さを確認する必要がある場合です。

これを行うには、1年生から学んだ式を覚えておく必要があります。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

これらの他のソリューションのいくつかよりも無限に単純に見えるものの準備はできていますか?

3つのポイント(xおよびyプロパティを持つ3つのオブジェクト)を渡します。ポイント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]の数値です。これを2つの別々の方程式(2Dの場合)として書くことができます。

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

これにより、pがaからbまでの線上にある必要があります。

(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 に答える