点が長方形の内側にあるかどうかを調べたいのですが。長方形は任意の方向に向けることができ、軸を揃える必要はありません。
私が考えることができた1つの方法は、長方形と点の座標を回転させて長方形の軸を揃え、次に点の座標が長方形の座標内にあるかどうかをテストすることでした。
上記の方法では、回転が必要であるため、浮動小数点演算が必要です。これを行う他の効率的な方法はありますか?
点が長方形の内側にあるかどうかを調べたいのですが。長方形は任意の方向に向けることができ、軸を揃える必要はありません。
私が考えることができた1つの方法は、長方形と点の座標を回転させて長方形の軸を揃え、次に点の座標が長方形の座標内にあるかどうかをテストすることでした。
上記の方法では、回転が必要であるため、浮動小数点演算が必要です。これを行う他の効率的な方法はありますか?
回答:
長方形はどのように表されますか?3点?4つのポイント?ポイント、サイド、アングル?2点と1面?他に何かありますか?それを知らずに、あなたの質問に答えようとする試みは、純粋に学術的な価値しかありません。
いずれの場合も、凸多角形(長方形を含む)のテストは非常に簡単です。各エッジが反時計回りの方向を向いていると仮定して、ポリゴンの各エッジをチェックし、ポイントがエッジの左側(左側)にあるかどうかをテストします。-ハンドハーフプレーン)。すべてのエッジがテストに合格した場合、ポイントは内側にあります。少なくとも1つが失敗した場合、ポイントは外側にあります。
ポイント(xp, yp)
がエッジの左側にあるかどうかをテストするには、(x1, y1) - (x2, y2)
計算する必要があります
D = (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1)
の場合D > 0
、ポイントは左側にあります。の場合D < 0
、ポイントは右側にあります。の場合D = 0
、ポイントは線上にあります。
この回答の以前のバージョンは、左側のテストの見かけ上異なるバージョンを説明していました(以下を参照)。しかし、同じ値を計算していることは簡単にわかります。
...ポイント(xp, yp)
がエッジの左側にあるかどうかをテストするには、エッジ(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
テストを簡素化するために利用することができる(すなわち、平行)の縁を、対向するために同じ大きさであるが異なる符号を有します。
A'
とはB'
で与えられるA'=B
とB'=-A
。3.A xp + B yp
両方のエッジを計算する意味がないため、それらを1つのテストに結合します。次に、長方形内にあるためのテストはになり(v_min < A xp + B yp < v_max) && ( w_min < B xp - A yp < w_max )
ます。
v_min
ですか?
v_min
は、A x + B y
長方形の内部にあるすべての値の最小値です(これは、コーナーで評価されたときの最小値です)。v_max
対応する最大値です。w_?
値は同じですが、ためBx - A y
。
長方形が3つの点A、B、Cで表され、ABとBCが垂直であると仮定すると、ABとBC上のクエリ点Mの投影を確認するだけで済みます。
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
mouseover
プロジェクトでイベントを使用しているので、長方形の内側にあるはずのポイントの上にマウスを置くと、マウスの周りに黒い円のドットが表示され、長方形の外側には何も表示されません。私はそれを機能させるために助けが必要ですが、私はとても混乱しています。
mouseover
mousemove
、ただのタイプミスである必要があります。
# 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
a
、、b
およびで表されることを前提としていd
ます。理論的には3点が任意の長方形を表す有効な方法ですが、実際には、一般的な場合、インターガー座標で正確に行うことは不可能です。一般的な場合、平行四辺形になります。これは長方形に非常に近いですが、それでも長方形ではありません。
これは古いスレッドだと思いますが、純粋に数学的な観点からこれを見ることに興味がある人のために、数学スタック交換に関する優れたスレッドがここにあります。
/math/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"
以上です。平行四辺形でも機能します。
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 i(P)= 0。
Pはポイントです。ポイントの場合、Lのに属するIは、方程式は真です。
したがって、これを確認する必要があります。
f AB(P)f AB(C)> = 0
f BC(P)f BC(D)> = 0
f CD(P)f CD(A)> = 0
f DA(P)f DA(B)> = 0
点が境界上にある場合、それも長方形に属するため、不等式は厳密ではありません。境界にポイントが必要ない場合は、厳密なものの不等式を変更できます。ただし、浮動小数点演算で作業している間は、選択は関係ありません。
残っているのは、2点を通る直線の方程式を取得することだけです。これはよく知られている線形方程式です。線ABと点Pについて書きましょう。
f AB(P)≡(x A -x B)(y P -y B)-(y A -y B)(x P -x B)
チェックは単純化できます-長方形に沿って時計回りに進みましょう-A、B、C、D、A。そうすると、すべての正しい辺が線の右側になります。したがって、別の頂点がある側と比較する必要はありません。そして、より短い不等式のセットをチェックする必要があります。
f AB(P)> = 0
f BC(P)> = 0
f CD(P)> = 0
f DA(P)> = 0
しかし、これは通常の数学者(学校の数学から)の座標のセットには正しいです。ここで、Xは右に、Yは上にあります。また、GPSで使用されている測地座標では、Xが上、Yが右であるため、不等式を回転させる必要があります。
f AB(P)<= 0
f BC(P)<= 0
f CD(P)<= 0
f DA(P)<= 0
軸の方向がわからない場合は、この簡略化されたチェックに注意してください。正しい不等式を選択した場合は、既知の配置で1つのポイントをチェックしてください。
私が考えた最も簡単な方法は、点を長方形の軸に投影することでした。説明させてください:
長方形の中心から上端または下端、および左端または右端までのベクトルを取得できる場合。また、長方形の中心からポイントまでのベクトルがあり、そのポイントを幅と高さのベクトルに投影できます。
P =点ベクトル、H =高さベクトル、W =幅ベクトル
ベクトルを大きさで割って単位ベクトルW '、H'を取得します
proj_P、H = P-(P.H ')H' proj_P、W = P-(P.W ')W'
私が間違っているとは思わないが、私が間違っているとは思わないが、高さベクトルへの点の投影の大きさが高さベクトルの大きさよりも小さい場合(長方形の高さの半分)と幅ベクトルへの点の投影の大きさはであり、長方形の内側に点があります。
ユニバーサル座標系を使用している場合は、ベクトル減算を使用して高さ/幅/点のベクトルを計算する必要がある場合があります。ベクトルの成分分解は素晴らしいです!それを覚えておいてください。
続けてマットが答えます。それを機能させるには、https://math.stackexchange.com/questions/190111/how-to-check-if-a-point-is-inside-a-rectangle/190373#190373 ソリューションを使用する必要があり ます
以下は機能しません
0 <= dot(AB、AM)<= dot(AB、AB)&& 0 <= dot(BC、BM)<= dot(BC、BC)
以下の作品
0 <= dot(AB、AM)<= dot(AB、AB)&& 0 <= dot(AM、AC)<= dot(AC、AC)
以下をjavascriptコンソールに貼り付けて確認します// Javascriptソリューションと同じ
var screenWidth = 320;
var screenHeight = 568;
var appHeaderWidth = 320;
var AppHeaderHeight = 65;
var regionWidth = 200;
var regionHeight = 200;
this.topLeftBoundary = {
A: {x: 0, y: AppHeaderHeight},
B: {x: regionWidth, y: AppHeaderHeight},
C: {x: 0, y: regionHeight + AppHeaderHeight},
D: {x: regionWidth, y: regionHeight + AppHeaderHeight}
}
this.topRightBoundary = {
A: {x: screenWidth, y: AppHeaderHeight},
B: {x: screenWidth - regionWidth, y: AppHeaderHeight},
C: {x: screenWidth, y: regionHeight + AppHeaderHeight},
D: {x: screenWidth - regionWidth, y: regionHeight + AppHeaderHeight}
}
this.bottomRightBoundary = {
A: {x: screenWidth, y: screenHeight},
B: {x: screenWidth - regionWidth, y: screenHeight},
C: {x: screenWidth, y: screenHeight - regionHeight},
D: {x: screenWidth - regionWidth, y: screenHeight - regionHeight}
}
this.bottomLeftBoundary = {
A: {x: 0, y: screenHeight},
B: {x: regionWidth, y: screenHeight},
C: {x: 0, y: screenHeight - regionHeight},
D: {x: regionWidth, y: screenHeight - regionHeight}
}
console.log(this.topLeftBoundary);
console.log(this.topRightBoundary);
console.log(this.bottomRightBoundary);
console.log(this.bottomLeftBoundary);
checkIfTapFallsInBoundary = function (region, point) {
console.log("region " + JSON.stringify(region));
console.log("point" + JSON.stringify(point));
var r = region;
var m = point;
function vector(p1, p2) {
return {
x: (p2.x - p1.x),
y: (p2.y - p1.y)
};
}
function dot(u, v) {
console.log("DOT " + (u.x * v.x + u.y * v.y));
return u.x * v.x + u.y * v.y;
}
function pointInRectangle(m, r) {
var AB = vector(r.A, r.B);
var AM = vector(r.A, m);
var AC = vector(r.A, r.C);
var BC = vector(r.B, r.C);
var BM = vector(r.B, m);
console.log("AB " + JSON.stringify(AB));
console.log("AM " + JSON.stringify(AM));
console.log("AM " + JSON.stringify(AC));
console.log("BC " + JSON.stringify(BC));
console.log("BM " + JSON.stringify(BM));
var dotABAM = dot(AB, AM);
var dotABAB = dot(AB, AB);
var dotBCBM = dot(BC, BM);
var dotBCBC = dot(BC, BC);
var dotAMAC = dot(AM, AC);
var dotACAC = dot(AC, AC);
console.log("ABAM " + JSON.stringify(dotABAM));
console.log("ABAB " + JSON.stringify(dotABAB));
console.log("BCBM " + JSON.stringify(dotBCBM));
console.log("BCBC " + JSON.stringify(dotBCBC));
console.log("AMAC " + JSON.stringify(dotAMAC));
console.log("ACAC" + JSON.stringify(dotACAC));
var check = ((0 <= dotABAM && dotABAM <= dotABAB) && (0 <= dotBCBM && dotBCBM <= dotBCBC));
console.log(" first check" + check);
var check = ((0 <= dotABAM && dotABAM <= dotABAB) && (0 <= dotAMAC && dotAMAC <= dotACAC));
console.log("second check" + check);
return check;
}
return pointInRectangle(m, r);
}
//var point = {x: 136, y: 342};
checkIfTapFallsInBoundary(topLeftBoundary, {x: 136, y: 342});
checkIfTapFallsInBoundary(topRightBoundary, {x: 136, y: 274});
checkIfTapFallsInBoundary(bottomRightBoundary, {x: 141, y: 475});
checkIfTapFallsInBoundary(bottomRightBoundary, {x: 131, y: 272});
checkIfTapFallsInBoundary(bottomLeftBoundary, {x: 131, y: 272});