簡體   English   中英

測試點是否在某個矩形中

[英]Test if point is in some rectangle

我有一大堆矩形,大小都相同。 我正在生成不應該落在這些矩形中的隨機點,所以我想做的是測試生成的點是否位於其中一個矩形中,如果是,則生成一個新點。

使用R-tree似乎可行,但它們實際上是用於矩形而不是點。 我可以使用R-tree算法的修改版本,它也適用於點,但如果已經有一些更好的解決方案,我寧願不重新發明輪子。 我對數據結構不是很熟悉,所以也許已經存在一些適用於我的問題的結構?

總之,基本上我要問的是,如果有人知道一個好的算法,在Python中工作,可以用來檢查一個點是否位於給定矩形集中的任何矩形。

編輯:這是2D,矩形不旋轉。

這個Reddit線程解決了你的問題:

我有一組矩形,需要確定一個點是否包含在任何一個中。 有什么好的數據結構可以做到這一點,快速查找很重要?

如果您的Universe是整數,或者精度水平是眾所周知的並且不是太高,您可以使用來自線程的abelsson建議,使用着色使用O(1)查找:

像往常一樣,你可以換空間。這里是一個O(1)查找具有非常低的常數。 init:創建一個足夠大的位圖,以足夠的精度包圍所有矩形,將其初始化為黑色。 將包含任何矩形白色的所有像素着色 O(1)查找:點(x,y)是白色嗎? 如果是這樣,就會出現一個矩形。

我建議你去那篇文章並完全閱讀ModernRonin的答案,這是最受歡迎的答案。 我把它貼在這里:

一,微觀問題。 你有一個任意旋轉的矩形和一個點。 矩形內的點是?

有很多方法可以做到這一點。 但我認為最好的是使用2D矢量交叉產品。 首先,確保矩形的點以順時針順序存儲。 然后做矢量交叉乘積,其中1)由側面的兩個點形成的矢量和2)從側面的第一點到測試點的矢量。 檢查結果的符號 - 正面在(在右側)側面,負面在外面。 如果它在所有四個邊內,它在矩形內。 或者等效地,如果它在任何一側之外,它就在矩形之外。 這里有更多解釋

該方法每個矢量需要3次減法*每側2個矢量加上每側加一個交叉乘積,即三次乘法和兩次加法。 每邊11個人,每個矩形44個人。

如果您不喜歡十字架產品,那么您可以執行以下操作:找出每個矩形的內切圓和外接圓,檢查內切圓中的點是否正確。 如果是這樣,它也在矩形中。 如果沒有,請檢查它是否在外接矩形之外。 如果是這樣,它也在矩形之外。 如果它落在兩個圓圈之間,你就是f **** d,你必須以艱難的方式檢查它。

在2d中找到一個點是否在圓內,需要兩個減法和兩個平方(=乘法),然后比較距離平方以避免必須做平方根。 這是4次失敗,兩次循環是8次失敗 - 但有時你仍然不會知道。 此外,假設您沒有花費任何CPU時間來計算外接圓或內切圓,這可能會或可能不會成立,這取決於您願意對矩形集進行多少預計算。

無論如何,對每個矩形測試點可能不是一個好主意,特別是如果你有一億個矩形。

這給我們帶來了宏觀問題。 如何避免針對集合中的每個矩形測試點? 在2D中,這可能是四叉樹問題。 在3d中,generic_handle說的是 - 八叉樹。 在我的頭頂,我可能會把它實現為B +樹 使用d = 5是很誘人的,因此每個節點最多可以有4個子節點,因為它可以很好地映射到四叉樹抽象上。 但是如果這組矩形太大而不適合主內存(這些天不太可能),那么擁有與磁盤塊大小相同的節點可能就是要走的路。

注意惱人的退化情況,比如一些具有一萬個幾乎相同的矩形的數據集,其中心位於相同的精確點。 :P

為什么這個問題很重要? 它在計算機圖形中很有用,可以檢查光線是否與多邊形相交。 也就是說,狙擊步槍射擊你剛剛擊中你射擊的那個人? 它也用於實時地圖軟件,比如GPS單位。 GPS會告訴您所處的坐標,但地圖軟件必須找到該點在大量地圖數據中的位置,並且每秒執行幾次。

同樣,歸功於ModernRonin ......

對於與軸對齊的矩形,您只需要兩個點(四個數字)來標識矩形 - 通常是左下角和右上角。 通過測試兩者來確定給定點(X 測試 ,Y 測試 )是否與矩形(​​X BL ,Y BL ,X TR ,Y TR )重疊:

  • X test > = X BL && X test <= X TR
  • Y test > = Y BL && Y test <= Y TR

顯然,對於要測試的足夠大的一組點,這可能相當耗時。 那么問題是如何優化測試。

顯然,一個優化是為所有矩形(邊界框)周圍的框建立最小和最大X和Y值:對此的快速測試顯示是否需要進一步查看。

  • X test > = X min && X test <= X max
  • Y test > = Y min && Y test <= Y max

根據矩形覆蓋的總表面積的多少,您可能能夠找到包含矩形的非重疊子區域,然后您可以避免搜索那些不包含與該點重疊的矩形的子區域在搜索期間以預先計算合適的數據結構為代價來保存比較。 如果矩形集足夠稀疏,則可能沒有重疊,在這種情況下,這會退化為強力搜索。 同樣,如果矩形集非常密集,則邊界框中沒有子范圍可以在不破壞矩形的情況下拆分。

但是,您也可以隨意將邊界區域划分為四分之一(每個方向的一半)。 然后,您將使用一個框列表,其中包含的框比原始框中的框多(每個框的兩個或四個框與任意邊界之一重疊)。 這樣做的好處是,您可以從搜索中消除四個季度中的三個,從而減少總共進行的搜索量 - 以輔助存儲為代價。

因此,與以往一樣,存在時空權衡。 並且預先計算與搜索權衡。 如果你運氣不好,預計算什么都沒有(例如,只有兩個盒子,並且它們在任一軸上都不重疊)。 另一方面,它可以獲得相當大的搜索時間效益。

我建議你看看BSP樹 (以及可能的四叉樹或八叉樹,也可以在該頁面上找到鏈接)。 它們用於遞歸地划分整個空間,並允許您快速檢查您需要檢查的矩形點。

至少你只有一個巨大的分區,需要檢查所有矩形,最大的分區變得如此之小,以至於它們可以達到單個矩形的大小。 當然,分區越精細,您需要走下樹以找到要檢查的矩形的時間越長。

但是,您可以自由決定適合檢查一個點的矩形數量,然后創建相應的結構。

但要注意重疊的矩形。 由於BSP樹無論如何都需要預先計算,因此您可以在此期間刪除重疊,這樣您就可以獲得清晰的分區。

你的R樹方法是我所知道的最好的方法(這是我選擇的四叉樹,B +樹或BSP樹的方法,因為在你的情況下R樹看起來很方便)。 警告:我不是專家,盡管我記得高年級大學課程中的一些東西!

為什么不嘗試這個。 計算和內存似乎都很輕松。

考慮將所有矩形投影到空間的基線上。 將該行間隔表示為

 {[Rl1, Rr1], [Rl2, Rr2],..., [Rln, Rrn]}, ordered by increasing left coordinates. 

現在假設你的點是(x,y),在這個集合的左邊開始搜索,直到你到達包含點x的行間隔。

如果沒有,你的點(x,y)在所有矩形之外。

如果有人這樣做,比如說[Rlk,Rrk],......,[Rlh,Rrh],(k <= h),那么只需檢查y是否在任何這些矩形的垂直范圍內。

完成。

祝好運。

約翰多納

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM