web-dev-qa-db-ja.com

チェックはポイント(x、y)が直線上に描かれた2つのポイントの間にある

2つの点A(x、y)の間に線を引きました--- B(x、y)これで、3番目の点C(x、y)ができました。 CがAとBの間に引かれた線上にある場合、私はそれをJava言語で行いたい。いくつかの問題があり、誰も完璧ではありません。

25
Usman Mahmood
_if (distance(A, C) + distance(B, C) == distance(A, B))
    return true; // C is on the line.
return false;    // C is not on the line.
_

あるいは単に:

_return distance(A, C) + distance(B, C) == distance(A, B);
_

これが機能する方法はかなり単純です。 CがAB行にある場合、次のシナリオが得られます。

_A-C------B
_

そして、その行のどこにあるかに関係なく、dist(AC) + dist(CB) == dist(AB)。その他の場合には、いくつかの説明の三角形と「dist(AC)+ dist(CB)> dist(AB)」があります。

_A-----B
 \   /
  \ /
   C
_

実際、Cが外挿された線上にある場合でも機能します。

_C---A-------B
_

ただし、距離は符号なしに保たれます。距離dist(AB)は次のように計算できます:

_  ___________________________
 /           2              2
V (A.x - B.x)  + (A.y - B.y)
_

浮動小数点演算の固有の制限(精度の制限)に留意してください。平等が正しく機能することを確認するために、「十分に近い」テスト(たとえば、100万分の1未満のエラー)を選択する必要がある場合があります。

74
MrROY

注意!数学のみ!

Try this!

この式を試すことができます。 A(x1, y1)およびB(x2, y2)座標を数式に入力すると、次のような結果が得られます。

_y = k*x + b; // k and b - numbers
_

次に、この方程式を満足させる点は、あなたの線上にあります。 C(x, y)A(x1, y1)B(x2, y2)の間にあることを確認するには、_(x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2)_を確認してください。

_A(2,3) B(6,5)
_

線の方程式:

_(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;
_

C(4,4)がこの行にあるかどうかを確認しましょう。

_2<4<6 & 3<4<5 // C between A and B
_

次に、C座標を方程式に追加します。

_4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB
_

PS: @paxdiabloが書いたように、計算する前に行が水平か垂直かを確認する必要があります。確認するだけ

_y1 == y2 || x1 == x2
_
11
SeniorJD

最も簡単なのは

// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
   // if AC is vertical
   if (A.x == C.x) return B.x == C.x;
   // if AC is horizontal
   if (A.y == C.y) return B.y == C.y;
   // match the gradients
   return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}

X値の差をy値の差で割ることにより、勾配を計算できます。

注:画面に描画した場合、AとBの間の線にCが表示されるかどうかを確認する別のテストがあります。数学では、A、B、Cは無限に小さい点であると想定しています。実際には、表現エラーの範囲内で非常に小さい。

10
Peter Lawrey

上記の答えは不必要に複雑です。最も簡単な方法は次のとおりです。

  1. (x-x1)/(x2-x1)=(y-y1)/(y2-y1)= alpha(定数)の場合、点C(x、y)はpts 1と2の間の線上にあります。

  2. Alpha <0.0の場合、Cはポイント1の外部にあります。

  3. Alpha> 1.0の場合、Cはポイント2の外側にあります。
  4. 最後に、alpha = [0,1.0]の場合、Cは1と2の内部です。

この答えがお役に立てば幸いです。

3
CS Venkat

それを行う簡単な方法は、3つのポイントが形成する角度をチェックすることだと思います。角度ACBが180度(または、精度に応じてそれに近い)の場合、ポイントCはAとBの間にあります。

1
Antoine C

ここでのすべての方法には落とし穴があると思います。なぜなら、丸め誤差をできる限り厳密に処理していないからです。基本的に、説明されている方法は、簡単なアルゴリズムを使用してポイントがラインに十分近いかどうか、および多少正確であることを示します。

精度が重要な理由それは、opが提示するまさに問題だからです。コンピュータープログラムの場合、線上の点のようなものは存在せず、線のイプシロン内には点のみがあり、そのイプシロンは文書化する必要があります。

問題を説明しましょう。距離比較アルゴリズムの使用:

セグメントが(0、0)から(0、2000)になり、アプリケーションで浮動小数点数(小数点以下約7桁の精度)を使用し、(1E-6、1000)上の点が行かどうか。

セグメントの両端からポイントまでの距離は1000.0000000005または1000 + 5E-10であり、したがって、ポイントまでの距離とポイントからの距離の加算との差は約1E-9です。ただし、これらの値はどれも十分な精度でfloatに保存できず、メソッドはtrueを返します。

ラインの最も近いポイントまでの距離を計算するなど、より正確な方法を使用すると、フロートが格納するのに十分な精度を持つ値を返し、許容されるイプシロンに応じてfalseを返すことができます。

例ではフロートを使用しましたが、doubleなどの浮動小数点タイプにも同じことが当てはまります。

1つの解決策は、BigDecimalを使用することです。パフォーマンスとメモリヒットが発生しても問題ない場合は、どちらの方法でも使用できます。

浮動小数点の距離を比較するよりも正確な方法であり、さらに重要なことに、一貫して正確ですが、計算コストは​​高くなりますが、ラインの最も近いポイント。

ポイントとラインセグメント間の最短距離

私は髪を分割しているように見えますが、以前はこの問題に対処しなければなりませんでした。幾何学的な操作を連鎖するときの問題です。どんな種類の精度低下に対処するかを制御しないと、最終的には、それらを修正するためにコードについて厳密に推論することを余儀なくされる難しいバグに遭遇します。

0
DPM