ポイントが長方形の内側にあるかどうかを知りたい。長方形は任意の方向に向けることができ、軸を揃える必要はありません。
私が考えることができる1つの方法は、長方形と点の座標を回転させて長方形の軸を揃え、それから単純に点の座標を長方形の座標内にあるかどうかをテストすることでした。
上記の方法では回転が必要であるため、浮動小数点演算が必要です。これを行う他の効率的な方法はありますか?
長方形はどのように表されますか?三点? 4点?ポイント、側面、角度? 2つのポイントと1つのサイド?他に何か?それを知らずに、あなたの質問に答えようとしても、純粋に学術的な価値しかありません。
いずれの場合でも、convex polygon(rectangleを含む)のテストは非常に簡単です。各Edgeが反時計回りの方向を向いていると仮定して、ポリゴンの各Edgeをチェックし、ポイントが存在するかどうかをテストします左側エッジの(左側の半平面内)。すべてのエッジがテストに合格した場合-ポイントは内部にあります。少なくとも1つが失敗した場合-ポイントは外側にあります。
ポイント(xp, yp)
はEdgeの左側にあります(x1, y1) - (x2, y2)
、あなたは計算する必要があります
D = (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1)
D > 0
、ポイントは左側にあります。 D < 0
、ポイントは右側にあります。 D = 0
、ポイントは線上にあります。
この回答の以前のバージョンでは、左側のテストの見かけ上は異なるバージョンについて説明しました(以下を参照)。ただし、同じ値を計算することは簡単にわかります。
...ポイント(xp, yp)
はEdgeの左側にあります(x1, y1) - (x2, y2)
、エッジを含む線の直線方程式を作成する必要があります。方程式は次のとおりです
A * x + B * y + C = 0
どこ
A = -(y2 - y1)
B = x2 - x1
C = -(A * x1 + B * y1)
今、あなたがする必要があるのは計算することです
D = A * xp + B * yp + C
D > 0
、ポイントは左側にあります。 D < 0
、ポイントは右側にあります。 D = 0
、ポイントは線上にあります。
ただし、このテストはすべての凸多角形に対して機能します。つまり、長方形に対して一般的すぎる可能性があります。長方形を使用すると、より簡単なテストが可能になります。たとえば、長方形(または他の平行四辺形)では、A
とB
の値は同じ大きさですが、反対の符号は異なります(つまり、平行)エッジ。テストを簡素化するために活用できます。
長方形が3つのポイントA、B、Cで表され、ABとBCが垂直であると仮定すると、クエリポイントMのABとBC上の投影のみをチェックする必要があります。
_0 <= dot(AB,AM) <= dot(AB,AB) &&
0 <= dot(BC,BM) <= dot(BC,BC)
_
AB
は座標(Bx-Ax、By-Ay)を持つベクトルABであり、dot(U,V)
はベクトルUとVのドット積:_Ux*Vx+Uy*Vy
_です。
更新。これを例証してみましょう:A(5,0)B(0,2)C(1,5)およびD(6,3)。ポイント座標から、AB =(-5,2)、BC =(1,3)、dot(AB、AB)= 29、dot(BC、BC)= 10を取得します。
クエリポイントM(4,2)の場合、AM =(-1,2)、BM =(4,0)、dot(AB、AM)= 9、dot(BC、BM)= 4です。 Mは長方形の中にあります。
クエリポイントP(6,1)の場合、AP =(1,1)、BP =(6、-1)、dot(AB、AP)=-3、dot(BC、BP)= 3があります。 Pは、辺AB上の投影がセグメントABの内側にないため、長方形の内側にありません。
私はエリック・ベインビルの答えから借りました:
0 <= dot(AB,AM) <= dot(AB,AB) && 0 <= dot(BC,BM) <= dot(BC,BC)
Javascriptでは次のようになります:
function pointInRectangle(m, r) {
var AB = vector(r.A, r.B);
var AM = vector(r.A, m);
var BC = vector(r.B, r.C);
var BM = vector(r.B, m);
var dotABAM = dot(AB, AM);
var dotABAB = dot(AB, AB);
var dotBCBM = dot(BC, BM);
var dotBCBC = dot(BC, BC);
return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
}
function vector(p1, p2) {
return {
x: (p2.x - p1.x),
y: (p2.y - p1.y)
};
}
function dot(u, v) {
return u.x * v.x + u.y * v.y;
}
例えば:
var r = {
A: {x: 50, y: 0},
B: {x: 0, y: 20},
C: {x: 10, y: 50},
D: {x: 60, y: 30}
};
var m = {x: 40, y: 20};
その後:
pointInRectangle(m, r); // returns true.
視覚的なテストとして出力を描画するためのコードペンがあります:) http://codepen.io/mattburns/pen/jrrprN
# Pseudo code
# Corners in ax,ay,bx,by,dx,dy
# Point in x, y
bax = bx - ax
bay = by - ay
dax = dx - ax
day = dy - ay
if ((x - ax) * bax + (y - ay) * bay < 0.0) return false
if ((x - bx) * bax + (y - by) * bay > 0.0) return false
if ((x - ax) * dax + (y - ay) * day < 0.0) return false
if ((x - dx) * dax + (y - dy) * day > 0.0) return false
return true
私はこれが古いスレッドであることを理解していますが、純粋に数学的な観点からこれを見ることに興味がある人のために、ここに数学スタック交換に関する優れたスレッドがあります:
https://math.stackexchange.com/questions/190111/how-to-check-if-a-point-is-inside-a-rectangle
編集:このスレッドに触発され、私はあなたのポイントがどこにあるかを迅速に決定するための単純なベクトルメソッドをまとめました。
P1 =(x1、y1)、p2 =(x2、y2)、p3 =(x3、y3)、およびp4 =(x4、y4)のポイントを持つ長方形が時計回りにあるとします。点p =(x、y)が長方形の内側にある場合、ドット積(p-p1)。(p2-p1)は0と| p2-p1 | ^ 2、および(p-p1)の間にあります。 (p4-p1)は0と| p4-p1 | ^ 2の間にあります。これは、p1を原点として、長方形の長さと幅に沿ったベクトルp-p1の射影を取ることに相当します。
同等のコードを表示する場合、これはより意味があります。
p21 = (x2 - x1, y2 - y1)
p41 = (x4 - x1, y4 - y1)
p21magnitude_squared = p21[0]^2 + p21[1]^2
p41magnitude_squared = p41[0]^2 + p41[1]^2
for x, y in list_of_points_to_test:
p = (x - x1, y - y1)
if 0 <= p[0] * p21[0] + p[1] * p21[1] <= p21magnitude_squared:
if 0 <= p[0] * p41[0] + p[1] * p41[1]) <= p41magnitude_squared:
return "Inside"
else:
return "Outside"
else:
return "Outside"
以上です。平行四辺形でも機能します。
長方形の問題を解決できない場合は、問題をより簡単な問題に分割してみてください。 here で説明されているように、長方形が2つの三角形に分割され、ポイントがそれらのいずれかの内側にあるかどうかをチェック
本質的に、ポイントから2組のラインごとにエッジを循環します。次に、外積を使用して、外積を使用してポイントが2つのラインの間にあるかどうかを確認します。 3つのポイントすべてについて検証された場合、ポイントは三角形の内側にあります。このメソッドの良い点は、角度をチェックした場合に発生する浮動小数点エラーが発生しないことです。
bool pointInRectangle(Point A, Point B, Point C, Point D, Point m ) {
Point AB = vect2d(A, B); float C1 = -1 * (AB.y*A.x + AB.x*A.y); float D1 = (AB.y*m.x + AB.x*m.y) + C1;
Point AD = vect2d(A, D); float C2 = -1 * (AD.y*A.x + AD.x*A.y); float D2 = (AD.y*m.x + AD.x*m.y) + C2;
Point BC = vect2d(B, C); float C3 = -1 * (BC.y*B.x + BC.x*B.y); float D3 = (BC.y*m.x + BC.x*m.y) + C3;
Point CD = vect2d(C, D); float C4 = -1 * (CD.y*C.x + CD.x*C.y); float D4 = (CD.y*m.x + CD.x*m.y) + C4;
return 0 >= D1 && 0 >= D4 && 0 <= D2 && 0 >= D3;}
Point vect2d(Point p1, Point p2) {
Point temp;
temp.x = (p2.x - p1.x);
temp.y = -1 * (p2.y - p1.y);
return temp;}
C++を使用してAnTのアンサーを実装しました。このコードを使用して、ピクセルの調整(X、Y)が形状内にあるかどうかを確認しました。
Lごとに方程式を作成する私。方程式の種類:
f私(P)= 0。
Pはポイントです。 lに属するポイントの場合私、方程式は真です。
したがって、これを確認する必要があります。
fAB(P)fAB(C)> = 0
f紀元前(P)f紀元前(D)> = 0
fCD(P)fCD(A)> = 0
fDA(P)fDA(B)> = 0
不等式は厳密ではありません。点が境界線上にある場合、それも長方形に属します。境界上のポイントが必要ない場合は、厳密なものの不等式を変更できます。ただし、浮動小数点演算で作業している間は、選択は関係ありません。
残っているのは、2点を通る直線の方程式を取得することだけです。これはよく知られた線形方程式です。ラインABとポイントPについて書きましょう:
fAB(P)≡(xA-バツB)(yP-yB)yA-yB) (バツP-バツB)
チェックを簡略化することができます-長方形に沿って行こう---(時計回り-A、B、C、D、A。その後、すべての正しい辺は行の右側になります。したがって、別の頂点がある側と比較する必要はありません。そして、短い不等式のセットを確認する必要があります。
fAB(P)> = 0
f紀元前(P)> = 0
fCD(P)> = 0
fDA(P)> = 0
しかし、これは通常の数学者(学校の数学から)座標のセットで正しいです。Xは右、Yは上です。そして、GPSで使用されるgeodesy座標では、Xが上、Yが右であるため、不等式を有効にする必要があります。
fAB(P)<= 0
f紀元前(P)<= 0
fCD(P)<= 0
fDA(P)<= 0
軸の方向が不明な場合は、この簡易チェックに注意してください-正しい不等式を選択した場合、既知の配置で1点を確認してください。
私が考えた最も簡単な方法は、ポイントを長方形の軸に投影することでした。説明させてください:
長方形の中心から上端または下端と左端または右端までのベクトルを取得できる場合。また、長方形の中心からポイントまでのベクトルもあり、そのポイントを幅と高さのベクトルに投影できます。
P =ポイントベクトル、H =高さベクトル、W =幅ベクトル
ベクトルを大きさで除算して単位ベクトルW '、H'を取得します
proj_P、H = P-(P.H ')H' proj_P、W = P-(P.W ')W'
私が間違っているとは思わない限り...(間違っている場合は修正してください)が、高さベクトル上のあなたのポイントの投影の大きさが高さベクトルの大きさより小さい場合(これは長方形の高さの半分)と幅ベクトル上のポイントの投影の大きさは、長方形の内側にポイントがあります。
普遍的な座標系がある場合、ベクトル減算を使用して高さ/幅/ポイントベクトルを把握する必要があります。ベクトル投影は素晴らしいです!それを覚えています。