在JavaScript中剪切矩形

时间:2013-05-18 01:21:10

标签: javascript math geometry 2d

我正在尝试编写一个带有两个重叠矩形的函数,并返回一个覆盖矩形A区域的矩形数组,但不包括矩形B的区域。我很难弄清楚这个算法的外观就像可能发生的碰撞数量巨大而难以解释一样。

tl; dr我正在尝试使用另一个矩形剪切一个矩形,从而产生一个覆盖剩余区域的矩形集合。

|-------------|                               |-------------|
|A            |                               |R1           |
|     |-------|----|                          |-----|-------|
|     |B      |    |           To             |R2   |
|     |       |    |          ====>           |     |
|     |       |    |                          |     |
|-----|-------|    |                          |-----|
      |            |
      |------------|

POSSIBLE OVERLAP PATTERNS

|-----|          |-----|      |-----|        |-----|
| |---|-|      |-|---| |      | |-| |        | |-| |
|-|---| |      | |---|-|      |-|-|-|        | |-| |
  |-----|      |-----|          |-|          |-----|

  |-|          |-----|          |-----|
|-|-|-|        | |---|-|      |-|---| |
| |-| |        | |---|-|      |-|---| |
|-----|        |-----|          |-----|

请注意,可能的重叠模式是显示的两倍,因为矩形A和B在上面的任何重叠模式中都可以是以下矩形。

3 个答案:

答案 0 :(得分:3)

两个矩形将屏幕划分为9个区域(不是14个)。再想一想您的配置:

 y1 -> |-------------|       
       |A            |        
 y2 -> |     |-------|----|   
       |     |B      |    |   
       |     |       |    |   
       |     |       |    |   
 y3 -> |-----|-------|    |   
             |            |
 y4 ->       |------------|
       ^     ^       ^    ^
       x1    x2      x3   x4

x坐标定义了5个垂直波段,但第一个(左)和最后一个(右)是不感兴趣的,所以你只需要处理从x1到x4的3个波段。 y坐标相同:从y1到y4的三个水平带。

这就是属于A,B,无或两者的9个矩形区域。你的例子是这样划分的:

  |-----|-------|----|       
  |A    |A      |none| 
  |-----|-------|----|   
  |A    |Both   |B   |   
  |     |       |    |   
  |     |       |    |   
  |-----|-------|----|   
  |none |B      |B   |
  |-----|-------|----|

因此,比较A和B的坐标,您会发现9个区域中的哪个区域仅属于A.它们是要保留的区域。

答案 1 :(得分:3)

对于任何特定设置都没有唯一的解决方案,但您可以使用此算法轻松找到其中一个解决方案:

  1. 在A中找到矩形B上方的矩形。如果A的顶部高于B(即在px中具有较低的值),则存在这样的矩形。该矩形由下式定义:( A的左边缘,A的上边缘)到(A的右边缘,B的上边缘)。
  2. 如果B的左边缘位于A的左边缘的右边,则下一个矩形是:( A的左边缘,min(A的上边缘,B的上边缘))到(B的左边缘) ,max(A的下边缘,B的下边缘))
  3. 如果B的右边缘位于B的右边缘的左侧,则类似于上面的
  4. ...以及B
  5. 下方可能的矩形

    总的来说,你会得到0到4个矩形。

    伪代码有点不寻常,但为了这个目的清晰,矩形的定义:

    function getClipped(A, B) {
        var rectangles = []; 
        if (A.top < B.top) {
            rectangles.push({ left: A.left, top: A.top, right: A.right, bottom: B.top }); 
        }
        if (A.left < B.left) {
            rectangles.push({ left: A.left, top: max(A.top, B.top), right: B.left, bottom: min(A.bottom, B.bottom) }); 
        }
        if (A.right > B.right) {
            rectangles.push({ left: B.right, top: max(A.top, B.top), right: A.right, bottom: min(A.bottom, B.bottom) }); 
        }
        if (A.bottom > B.bottom) {
             rectangles.push({ left: A.left, top: B.bottom, right: A.right, bottom. A.bottom }); 
        }
    
        return rectangles; 
    }
    
    var rectA = { left: nn, top: nn, right: nn, bottom: nn}; 
    var rectB = { left: nn, top: nn, right: nn, bottom: nn};
    
    var clipped = getClipped(rectA, rectB) ; 
    

答案 2 :(得分:0)

根据dan.p的代码,使用boisvert的建议,我的例程如下:

  this.clip = function(other) {
    var res = [];
    // Rect has a constructor accepting (left, top, [right, bottom]) for historical reasons
    if (this.top < other.top) {
      res.push(new Rect(Math.max(this.left, other.left), other.top, [Math.min(this.right, other.right), this.top]));
    }
    if (this.left > other.left) {
      res.push(new Rect(other.left, other.top, [this.left, other.bot]));
    }
    if (this.right < other.right) {
      res.push(new Rect(this.right, other.top, [other.right, other.bot]));
    }
    if (this.bot > other.bot) {
      res.push(new Rect(Math.max(this.left, other.left), this.bot, [Math.min(this.right, other.right), other.bot]));
    }
    return res;
  }

我测试了16例(四个独立的if)。