【问题标题】:How to approach recursive function for overlapping rectangles如何处理重叠矩形的递归函数
【发布时间】:2014-07-14 16:33:51
【问题描述】:

我有一个名为myRects 的矩形数组,如下所示:

const 
    r1 = {x1: 10, x2: 80, y1: 10, y2: 80},
    r2 = {x1: 60, x2: 100, y1: 60, y2: 100},
    r3 = {x1: 90, x2: 180, y1: 90, y2: 140},
    r4 = {x1: 120, x2: 140, y1: 130, y2: 160},
    r5 = {x1: 160, x2: 210, y1: 80, y2: 110},
    myRects = {r1: r1, r2: r2, r3: r3, r4: r4, r5: r5};

这是它们的绘制方式:

我还有一个方便的函数叫做doRectanglesIntersect(r1, r2)

function doRectanglesIntersect(r1, r2) {
  return (r1.x1 <= r2.x2 &&
          r2.x1 <= r1.x2 &&
          r1.y1  <= r2.y2 &&
          r2.y1  <= r1.y2)
}

我想要的是一个名为 recursivelyGetIntersectingRects(rect) 的函数,它将返回一个矩形数组,该数组与给定的矩形或其相交的矩形相交无限

所以如果我将r1 传递给这个函数,我应该得到[r2,r3,r4,r5] 作为返回值,因为它们都已连接。我不介意这个函数是否返回对象字面量或键,但它应该尽可能高效并且不返回重复值。

我能够制定这个问题,但我没有找到解决方案。我的思维不会递归地工作。

这是我制作的小提琴,其中包含上面的代码和作为视觉辅助的画布绘图:http://jsfiddle.net/b3jX6/5/

【问题讨论】:

  • 你有什么尝试解决这个问题?另外,你为什么要解决这个问题?对我来说闻起来像家庭作业。
  • 另外:请参阅使用 c# 的相关帖子(但想法相同)。 stackoverflow.com/questions/12260491/…
  • 这不是家庭作业,我希望我还年轻到还在上学!我试图通过脏矩形检查使画布库更有效。但是,对于重叠的对象,事情会变得乱七八糟。因此我需要一个合适的算法来解决这个问题。
  • 很公平!我不得不问。 ;) 如果你试图让 JavaScript 库“更高效”,我建议你迭代而不是递归。 JS 中的迭代速度更快,并且不会最大化递归深度:stackoverflow.com/questions/9474465/…
  • 没问题。 :) 查看这篇文章了解更多...stackoverflow.com/questions/2752349/…

标签: javascript recursion


【解决方案1】:

我认为这样的事情可以做到:

iterativelyGetIntersectingRects(r, rects) {
 var inter = [];  // resulting intersecting rects
 var found = [r]; // found intersecting rects in last round (to be checked for subseq intersections)
 while(found.length) {   // while new ones found
  var a = found.shift(); // check this
  inter.push(a);         // also store to results
  var remain = [];
  while(rects.length) {      // while remaining for check
   var test = rects.shift(); // check next
   if( doIntersect(a, test))
    found.push(test);        // gotcha!
   else
    remain.push(test);       // not yet
  }
  rects = remain;            // remaining for check with next found
 }
 return inter;     
}

【讨论】:

  • 谢谢你,你真的帮了大忙。我使用已使用的已完成功能添加了另一个答案,但我会将其标记为已接受。
【解决方案2】:

编辑:从 cmets 抽象成完整的答案。

由于您正在尝试“使画布库更高效”,我建议您迭代而不是递归; JS 中的迭代速度更快,您不必担心递归深度。 More

然后问题就变成了,“我怎样才能快速检查矩形相交?”有关更多信息,请参阅this SO post,但目前评价最高的答案描述了以下Daniel Vassalo 的功能:

function intersectRect(r1, r2) {
  return !(r2.left > r1.right || 
           r2.right < r1.left || 
           r2.top > r1.bottom ||
           r2.bottom < r1.top);
}

...当给定一个矩形时:

var sampleRectangle = {
  left:   10,
  top:    10,
  right:  30,
  bottom: 30
};

(对于那些寻求递归矩形重叠的人,请参阅related C# SO question。)

【讨论】:

  • 我在doRectanglesIntersect() 上面的函数会不会更快,因为它会在其中一个比较失败时立即返回,而这会检查所有比较?
  • 我相信 AND (&&) 和 OR (||) 语句都是短路的; true 语句上的 OR 短路,而 false 语句上的 AND 短路。在这方面,唯一的区别是否定。我会投票使用你的,因为避免否定通常有助于清理代码。来源:stackoverflow.com/questions/5891754/…
【解决方案3】:

我选择了以下功能,该功能深受 fast 的回答的启发。

我做了一些修改,所以没有修改底层集合,而是克隆了矩形数组。

function iterativelyGetIntersectingRects(r) {
    var intersectingRects = [],
        allRects = myRects.slice(0)
        foundStack = [r],
        foundRect, 
        i, 
        rectToTest, 
        remainingRectsToTest;

    while (foundStack.length > 0) {
        foundRect = foundStack.shift();
        intersectingRects.push(foundRect);
        remainingRectsToTest = [];
        for (i = 0; i < allRects.length; i++) {
            rectToTest = allRects[i];
            if (doRectanglesIntersect(foundRect, rectToTest)) {
                foundStack.push(rectToTest);
            } else {
                remainingRectsToTest.push(rectToTest)
            }
        }
        allRects = remainingRectsToTest;
    }

    intersectingRects.shift(); // This is our original rectangle

    return intersectingRects;
}

【讨论】:

    猜你喜欢
    • 2019-07-02
    • 1970-01-01
    • 2020-09-07
    • 2013-03-09
    • 2010-10-27
    • 2020-03-22
    • 2018-11-02
    • 1970-01-01
    • 2014-09-05
    相关资源
    最近更新 更多