简体   繁体   English

在XY平面上找到附近的矩形

[英]Find nearby rectangles on X-Y plane

在此处输入图片说明

I have few rectangles on an xy plane.There is a reference rectangle . 我在xy平面上有几个矩形。有一个参考矩形。 The reference rectangle's position is changeable. 参考矩形的位置是可变的。 I need efficient way to find the 我需要有效的方法来找到

  • first rectangle that is found on the LEFT side of the reference rectangle. 在参考矩形的左侧找到的第一个矩形。
  • first rectangle that is found on the RIGHT side of the reference rectangle. 在参考矩形的右侧找到的第一个矩形。
  • first rectangle that is found on the TOP side of the reference rectangle. 在参考矩形的TOP侧找到的第一个矩形。
  • first rectangle that is found on the BOTTOM side of the reference rectangle. 在参考矩形底部的第一个矩形。

Pseudo-code or Java code is fine. 伪代码或Java代码都可以。 Emphasis is given on the faster code than space consumed . 重点放在比占用空间更快的代码上。
Solving one side will solve the other 3 sides. 解决一侧会解决另一侧。 Let's say, we need to find the list of nearest rectangles that fall on the left side of the "REFERENCE RECT" . 假设, 我们需要找到落在“ REFERENCE RECT”左侧的最近矩形的列表。 The "REFERENCE RECT" is movable. “参考点”是可移动的。 All other rectangles are stationary at the time of calculating. 在计算时,所有其他矩形都是固定的。

PS. PS。 Each box can be the "REFERENCE RECT". 每个框都可以是“ REFERENCE RECT”。 Boxes are added to the XY plane one at a time. 一次将一个框添加到XY平面。

This pseudo-code may not be fast during setup (O(N^2)), but once NearestBoxes has been built, it will beat anything else (since it won't have to recalculate anything). 此伪代码在设置过程中可能不会很快(O(N ^ 2)),但是一旦建立了NearestBoxes ,它将击败其他任何内容(因为它不必重新计算任何内容)。 Beware of typos - I haven't tested this. 当心错别字-我还没有测试过。

public enum RPos { Up, Down, Left, Right };

public class Box {
    int x1, x2, y1, y2;        
    boolean isRelative(b, RPos rp) {
       // returns true if b can be said to be "rp" 
       // (say, left) of this box
    }
    double dist(Box b, RPos rp) {
       // assumes non-overlapping
       // add some simple trig here:
       //   if boxes adjacent in chosen direction, distance 
       //      (if Right, then x2-p.x1, ...)
       //   if boxes not adjacent, then euclidean distance between 
       //   nearest corners.
    }
}

class NearestBoxes {    

    HashMap<RPos, HashMap<Box, TreeMap<Double, ArrayList<Box>>>> 
        = new HashMap<>();

    public NearestBoxes(List<Box> boxes) {
       for (RPos rp : RPos.values) {
          nearest.put(rp, 
             new HashMap<Box, TreeMap<Double, ArrayList<Box>>>();
          for (Box a : boxes) {
             TreeMap<Double, ArrayList<Box>> n = 
                new TreeMap<Double, ArrayList<Box>>());
             nearest.get(rp).put(a, n);                    
             for (Box b : boxes) {
                 if (a.isRelative(b, rp)) {
                    double d = a.dist(b, rp);                        
                    if (d == n.firstKey()) {
                       n.get(d).add(b);
                    } else if (d < n.firstKey()) {
                       n.put(d, new ArrayList());
                       n.get(d).add(b);
                    }
                 }
             }
          }
       }
    }

    public List<Box> getNearest(Box b, RPos rp) {
       TreeMap<Double, ArrayList<Box>> n = nearest.get(rp).get(b);
       return (n.isEmpty()) ? new ArrayList<Box>() 
                            : n.get(n.firstKey());           
    }
}

Feel free to comment and show logic depicting that it can produce false positive. 随意发表评论并显示逻辑,以表明它可以产生假阳性。

The key concept of searching in Nearest Neighbour Search is to split the domain to minimize searching and quit the search as early as the nearest neighbour is found. 最近邻居搜索中搜索的关键概念是分割域以最小化搜索,并在找到最近邻居时就退出搜索。

Assuming that the boxes have an id and they have x,y coordinates. 假设盒子有一个id,并且它们有x,y坐标。 I want to utilize the xy coordinate information to find the nearest rect. 我想利用xy坐标信息来找到最近的矩形。 This solution initially splits the whole xy plane into considerably smaller domain to search in . 该解决方案最初将整个xy平面拆分为较小的域以进行搜索。 在此处输入图片说明

Solve LEFT: 解决左:

The equation of vertical lines are x=b.Save the right edge of each rectangle as they are added to the xy plane. 垂直线的等式为x = b,将每个矩形的右边缘添加到xy平面中时保存。 TreeMap<Integer x,ArrayList<Integer>> rightEdgeMap; The value ArrayList<Integer> holds ids of boxes, So the search domain is dramatically decreased. ArrayList<Integer>包含box的id,因此搜索域大大减少了。 Now split and search in the decreased XY plane marked with blue color, untill the nearest rect is found. 现在拆分并在标记为蓝色的减小的XY平面中搜索,直到找到最近的rect。

How to search? 如何搜寻?

Make a searching bounding box and consider it to be grow-able on XY plane. 制作一个搜索边界框,并认为它在XY平面上可扩展。 Since any right edge falling within the height of the reference rect is the nearest possibility, start searching there.[ Look at the first searching box in the image ]. 由于落在参考矩形高度内的任何右边缘都是最接近的可能性,因此请从此处开始搜索。[查看图像中的第一个搜索框]。

search only within the new growth of the searching box. 仅在搜索框的新增长范围内进行搜索。 If more than one rect found in searching box, measure distance: 如果在搜索框中找到多个矩形,请测量距离:

  • If the right edge falls within the height of the referenceRect, take horizontal distance from referenceRect or searchingBoxRightEdge. 如果右边缘落在referenceRect的高度内,则与referenceRect或searchBoxRightEdge保持水平距离。

    • Other wise take distance from the bottom of the edge to the nearest corner of the referenceRect. 否则,从边缘的底部到referenceRect的最近拐角之间的距离。

    Alternatively, for simplicity you can accept the highest x valued edge within the the searching box. 另外,为简单起见,您可以在搜索框中接受x值最高的边。 For fine grained solution, use above 2 methods. 对于细颗粒溶液,请使用以上两种方法。

Flatten the searching box by adding 1/5th of smallest box pixels on x axis and y axis until any axis or both of them are reached to the end. 通过在x轴和y轴上添加最小框像素的1/5来平整搜索框,直到到达任一轴或两个轴都到达末端为止。 1/5th is an assumption , it can be solid 20 or 30 pixels . 1/5是一个假设,可以是20或30像素。 The constraint is to add same amount of pixels on both x and y axis in searching box. 限制是要在搜索框中的x和y轴上添加相同数量的像素。 Taking too many pixels will result in searching longer and wait longer to finish calculation. 像素过多会导致搜索时间更长,并且等待更长的时间才能完成计算。 You don't need to flatten the searching box after the first match, since that's the END of searching. 您无需在第一个匹配项后放宽搜索框,因为那是搜索的终点。

When any box is resized or adding a new box, update rightEdgeMap appropriately. 当调整任何框的大小或添加新框时, rightEdgeMap适当更新rightEdgeMap You will need another map<Integer,Integer> boxIdToRightEdgeMap; 您将需要另一个map<Integer,Integer> boxIdToRightEdgeMap; where key is id of box and value is the rightEdge x value. 其中key是box的id,value是rightEdge x值。 Whenever adding a new box/resize is done on any box, use boxIdToRightEdgeMap to locate the rightEdge value in the rightEdgeMap . 每当增加新的箱/调整是在任何盒完成后,使用boxIdToRightEdgeMap定位rightEdge在价值rightEdgeMap

Use case box 4 is resized: 调整了用例框4的大小:

int xValOfRightEdge=boxIdToRightEdgeMap.get(4);

remove 4 from rightEdgeMap's value arrayList using xValOfRightEdge . 使用xValOfRightEdgerightEdgeMap's值arrayList中删除4。 And insert 4 in appropriate rightEdgeMap's value-arryList. 并在适当的rightEdgeMap's value-arryList中插入4。

Query within searching box: 在搜索框中查询:

One way could be, to store the edges in a NavigableMap<Integer,List<Integer>> , where key= Y coordinate of rightEdge , value= list of rightEdges that fall in that Y coordinate. 一种方法是将边缘存储在NavigableMap<Integer,List<Integer>> ,其中key= Y rightEdge key= Y坐标, value= list属于该Y坐标的rightEdges value= list Now get subMap( minY ,MaxY) . 现在获取subMap( minY ,MaxY) minY and MaxY refers to searchingBox's min and max Y values. minY和MaxY是指searchingBox的最小和最大Y值。 Sorting this submap decendingly you get the first entry as answer. 递减排序此子图,您将获得第一个条目作为答案。

Use case box 4 is moved: No need to change in any map. 用例框4已移动:无需在任何地图中进行更改。

Observation: The time complexity is noticeably less. 观察: 时间复杂度明显降低。

Maybe you can store all rectangles in an array and match the nearest coordinates of other rectangles: 也许您可以将所有矩形存储在数组中并匹配其他矩形的最接近坐标:

Suppose array of rectangles is: Rectangle[][4] rectangles = {{left, top, right, bottom}, {left, top, right, bottom}} 假设矩形数组是: Rectangle[][4] rectangles = {{left, top, right, bottom}, {left, top, right, bottom}}

Now if you need to find the first rectangle on the left side, simple compare right of each rectangle in the array with the left of reference rectangle. 现在,如果需要在左侧找到第一个矩形,只需将数组中每个矩形的右侧与参考矩形的左侧比较即可。 Largest value of right of rectangle will give you the first rectangle on left side. 矩形右侧的最大值将为您提供左侧的第一个矩形。

Rectangle referenceRectangle[4] = {rrl, rrt, rrr, rrb}
int max = 0;
for(i = 0 ; i < rectangles.length ; i++)
{
  if(rectangles[0][2] < referenceRectangle[0])
  {
    if(rectangles[0][2] > max)
    {
      max = rectangles[0][2];
      //Note the Index or maintain the list of rectangles.
    }   
  }
}

Similarly, other rectangles can be found out. 同样,可以找到其他矩形。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM