Math 计算非';不重叠

Math 计算非';不重叠,math,geometry,overlap,Math,Geometry,Overlap,我有两个矩形,由包含x1,y1,x2,y2坐标的结构表示。一个矩形可以视为父矩形,另一个矩形可以视为子矩形 我已经知道如何检测子矩形是否在父矩形内;我现在想找出的是最简单、最快的方法来确定父矩形中没有被子矩形重叠的矩形区域 例如,考虑一个100x100父矩形,一个50x50子矩形正好位于父中心。这意味着将有四个矩形代表父矩形中未被子矩形重叠的四个区域 当然,孩子可能在左上角、右上角、左下角、右下角,或者偏左一点、偏右一点,等等。。。可能有一个、两个、三个或四个矩形表示非重叠区域 我已经有了一些实

我有两个矩形,由包含x1,y1,x2,y2坐标的结构表示。一个矩形可以视为父矩形,另一个矩形可以视为子矩形

我已经知道如何检测子矩形是否在父矩形内;我现在想找出的是最简单、最快的方法来确定父矩形中没有被子矩形重叠的矩形区域

例如,考虑一个100x100父矩形,一个50x50子矩形正好位于父中心。这意味着将有四个矩形代表父矩形中未被子矩形重叠的四个区域

当然,孩子可能在左上角、右上角、左下角、右下角,或者偏左一点、偏右一点,等等。。。可能有一个、两个、三个或四个矩形表示非重叠区域

我已经有了一些实现的想法来解决这个问题,但是所有的想法似乎都过于复杂了。有没有一种简单、快速的方法来解决这个问题?

parent=Rectangle.new(x1、y1、mx1、my1)
parent = Rectangle.new(x1,y1,mx1,my1)
child = Rectangle.new(x2,y2,mx2,my2)

rects = []
if (parent.contains(child))
  rects.push Rectangle.new(parent.x, parent.y, parent.mx, child.y) if child.y>parent.y
  rects.push Rectangle.new(parent.x, child.my, parent.mx, parent.my) if child.my<parent.my
  rects.push Rectangle.new(parent.x, parent.y, child.x, pareny.my) if child.x>parent.x
  rects.push Rectangle.new(child.mx, parent.y, parent.mx, parent.my) if child.mx<parent.mx
end
child=矩形。新建(x2、y2、mx2、my2) rects=[] if(父级包含(子级)) 如果child.y>parent.y,则rects.push Rectangle.new(parent.x、parent.y、parent.mx、child.y) rects.push Rectangle.new(parent.x,child.my,parent.mx,parent.my)if child.myparent.x 如果child.mx
parent=Rectangle.new(x1,y1,mx1,my1),则rects.push Rectangle.new(child.mx,parent.y,parent.mx,parent.my)
child=矩形。新建(x2、y2、mx2、my2)
rects=[]
if(父级包含(子级))
如果child.y>parent.y,则rects.push Rectangle.new(parent.x、parent.y、parent.mx、child.y)
rects.push Rectangle.new(parent.x,child.my,parent.mx,parent.my)if child.myparent.x

rects.push Rectangle.new(child.mx,parent.y,parent.mx,parent.my)如果child.mx这是基本算法:

对于子对象中的每个点,如果该点位于父对象内部,则对应的子对象和父对象点形成矩形的对角线。现在,对于子对象的每一侧,如果两个点位于父对象中,则这两个点和父对象边缘上的匹配点形成一个矩形。如果子对象边上只有一个点位于父对象中,则该点和与不在父对象中的子对象边点对应的父对象点构成矩形的对角线。返回这些矩形


最多可以得到八个矩形(每个角一个,每个边一个)。如果您想要最小可能的矩形,请查看它们是否共享边,如果共享边,请将它们组合起来。

这是基本算法:

对于子对象中的每个点,如果该点位于父对象内部,则对应的子对象和父对象点形成矩形的对角线。现在,对于子对象的每一侧,如果两个点位于父对象中,则这两个点和父对象边缘上的匹配点形成一个矩形。如果子对象边上只有一个点位于父对象中,则该点和与不在父对象中的子对象边点对应的父对象点构成矩形的对角线。返回这些矩形


最多可以得到八个矩形(每个角一个,每个边一个)。如果您想要最小可能的矩形,请查看它们是否共享边,如果共享边,请将它们合并。

这样最多可以有4个非重叠区域的矩形。让我们列一个清单

leftrect = rightrect = toprect = bottomrect = None
trimmedparent = duplicate(parent)

if parent.x1 < child.x1:
    leftrect = duplicate(parent)
    leftrect.x2 = child.x1
    trimmedparent.x1 = child.x1

if parent.x2 > child.x2:
    rightrect = duplicate(parent)
    rightrect.x1 = child.x2
    trimmedparent.x2 = child.x2

if parent.y1 < child.y1:
    toprect = duplicate(trimmedparent)
    toprect.y2 = child.y1

if parent.y2 > child.y2:
    bottomrect = duplicate(trimmedparent)
    bottomrect.y1 = child.y2
leftrect=rightrect=toprect=bottomrect=None
trimmedparent=重复(父项)
如果parent.x1child.x2:
rightrect=重复(父级)
rightrect.x1=child.x2
trimmedparent.x2=child.x2
如果parent.y1child.y2:
bottomrect=重复(trimmedparent)
bottomrect.y1=child.y2

唯一棘手的部分是删除leftrect和toprect可能相交的部分。我使用“trimmedparent”作为中间步骤,从toprect修剪该部分。

这样最多可以有4个非重叠区域的矩形。让我们列一个清单

leftrect = rightrect = toprect = bottomrect = None
trimmedparent = duplicate(parent)

if parent.x1 < child.x1:
    leftrect = duplicate(parent)
    leftrect.x2 = child.x1
    trimmedparent.x1 = child.x1

if parent.x2 > child.x2:
    rightrect = duplicate(parent)
    rightrect.x1 = child.x2
    trimmedparent.x2 = child.x2

if parent.y1 < child.y1:
    toprect = duplicate(trimmedparent)
    toprect.y2 = child.y1

if parent.y2 > child.y2:
    bottomrect = duplicate(trimmedparent)
    bottomrect.y1 = child.y2
leftrect=rightrect=toprect=bottomrect=None
trimmedparent=重复(父项)
如果parent.x1child.x2:
rightrect=重复(父级)
rightrect.x1=child.x2
trimmedparent.x2=child.x2
如果parent.y1child.y2:
bottomrect=重复(trimmedparent)
bottomrect.y1=child.y2

唯一棘手的部分是删除leftrect和toprect可能相交的部分。我使用“trimmedparent”作为从toprect修剪该部分的中间步骤。

以下是计算父部分非重叠区域的另一种方法:

Function max(ByVal v1 As Double, ByVal v2 As Double) As Double
    If v1 > v2 Then
        Return v1
    Else
        Return v2
    End If
End Function

Function min(ByVal v1 As Double, ByVal v2 As Double) As Double
    If v1 > v2 Then
        Return v2
    Else
        Return v1
    End If
End Function

Function IntervalOverLap(ByVal p1 As Double, ByVal p2 As Double, ByVal c1 As Double, ByVal c2 As Double) As Double
    'determine how much of the parent(p1 to p2) segment '
    ' is overlapped by the child(c1 to c2) segment      '

    'sort to standard direction  '
    Dim ph As Double = max(p1, p2)
    Dim pl As Double = min(p1, p2)
    Dim ch As Double = max(c1, c2)
    Dim cl As Double = min(c1, c2)

    'restrict the child to within the parent '
    ch = min(ph, max(pl, ch))
    cl = max(pl, min(cl, ph))

    'return the overlapped length  '
    Return (ch - cl)
End Function

Function NonOverLappedArea(ByVal parent As Rectangle, ByVal child As Rectangle) As Double
    'return the area of the parent        '
    ' that is not overlapped by the child '
    Return IntervalOverLap(parent.X1, parent.X2, child.X1, child.X2) _
        * IntervalOverLap(parent.Y1, parent.Y2, child.Y1, child.Y2)
End Function

下面是计算父对象的非重叠区域的另一种方法:

Function max(ByVal v1 As Double, ByVal v2 As Double) As Double
    If v1 > v2 Then
        Return v1
    Else
        Return v2
    End If
End Function

Function min(ByVal v1 As Double, ByVal v2 As Double) As Double
    If v1 > v2 Then
        Return v2
    Else
        Return v1
    End If
End Function

Function IntervalOverLap(ByVal p1 As Double, ByVal p2 As Double, ByVal c1 As Double, ByVal c2 As Double) As Double
    'determine how much of the parent(p1 to p2) segment '
    ' is overlapped by the child(c1 to c2) segment      '

    'sort to standard direction  '
    Dim ph As Double = max(p1, p2)
    Dim pl As Double = min(p1, p2)
    Dim ch As Double = max(c1, c2)
    Dim cl As Double = min(c1, c2)

    'restrict the child to within the parent '
    ch = min(ph, max(pl, ch))
    cl = max(pl, min(cl, ph))

    'return the overlapped length  '
    Return (ch - cl)
End Function

Function NonOverLappedArea(ByVal parent As Rectangle, ByVal child As Rectangle) As Double
    'return the area of the parent        '
    ' that is not overlapped by the child '
    Return IntervalOverLap(parent.X1, parent.X2, child.X1, child.X2) _
        * IntervalOverLap(parent.Y1, parent.Y2, child.Y1, child.Y2)
End Function

根据您的描述,孩子始终完全由家长控制。因此,非重叠区域始终是一个矩形圆环,尽管它可以在4条边中的任何一条边上退化,因为子边可以邻接父边,子边的完全退化情况与父边相同

甜甜圈可以分解成4个矩形。分解可能不是唯一的,这意味着您可以根据执行分解的方式获得不同的矩形。 在4个矩形中,丢弃退化的矩形(面积为0的矩形),就完成了

这是一个垂直偏置分解

// assume the child is known to be in the parent bounds at this point
// assume parent and child are normalized
std::vector<CRect> rects;
CRect rect( parent.x1(), parent.y1(), child.x1(), parent.y2() ); // left
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x1(), parent.y1(), child.x2(), child.y1() ); // bottom
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x1(), child.y2(), child.x2(), parent.y2() ) ); // top
if ( rect.area() > 0.0 ) rects.push_back(rect);
rect.set( child.x2(), parent.y1(), parent.x2(), parent.y2() ) ); // right
if ( rect.area() > 0.0 ) rects.push_back(rect);

// yes, this could be written without all the code replication... :)
//假设此时已知子对象在父边界中
//假设父级和子级已规范化
std::向量矩形;
正确的rect(parent.x1(),parent.y1(),child.x1(),parent.y2());//左边
if(rect.are)