思维导图之边界回弹

853 阅读4分钟

问题定义:思维导图是由一个个节点组成,这里的节点视为有区域的矩形,然后希望给定思维导图一个边界,当思维导图被移出边界后能够自动回弹到可是区域内。有几点约束:

  1. 思维导图可以缩放位移,缩放位移后边界仍然有效;
  2. 若思维导图放大后,节点之间的空白区域在边界内仍然视为思维导图在边界内;
  3. 回弹后的至少有一个节点要在可视区域内;
  4. 边界范围小于可视区范围,边界范围允许适当调节,没有严格限制;

思路

当矩形边界与任意矩形节点相交时,说明当前的图没有超出边界。边界矩形不包含图的时候,可以获取到带最近节点,计算出所需的x,y偏移量,即是图回弹所需要的偏移量。

由于矩形边界一定在可是区域内,所以矩形边界内的节点一定在可是区域内。

节点与边界矩形的关系

特殊情况:

节点与边界矩形的关系

当图放大后,可能在节点间存在空白区域,这时候也需要判定为包含关系。 由上图可是,如果x轴方向和y轴方向都各自存在节点矩形与边界矩形有重合部分的话,那么也是存在包含关系的。

单向重叠的包含关系

单向重叠的情况下,如果两边都存在节点,那也属于包含关系。所以存在x轴(或y轴)方向包含的时候,需要记录一下节点与边界矩形的位置关系。

节点在边界左边:

rightnode<=left边界right_{node} <= left_{边界}

节点在边界右边:

leftnode>=right边界left_{node} >= right_{边界}

同理,节点与边界矩形的上下位置关系判断也类似。

矩形的包含关系判定

两个矩形存在重叠部分,则:

P1:cxrect1cxrect2(widthrect1+widthrect2)2P1: |cx_{rect1} - cx_{rect2}| \leq \frac{(width_{rect1} + width_{rect2})}{2}

且,

P2:cyrect1cyrect2(heightrect1+heightrect2)2P2:|cy_{rect1} - cy_{rect2}| \leq \frac{(height_{rect1} + height_{rect2})}{2}

其中cx和cy是两个矩形的中心点,width和height分别是矩形的宽高。P1表达式表示x轴方向两个矩形有重叠,P2表示y轴方向两个矩形有重叠。

当两个矩形在x轴方向有重叠部分,且在y轴方向有重叠部分时,那么这两个矩形就重叠了。

同理,当x轴方向和y轴方向都有与边界矩形重叠的部分,那么可以判定图与边界矩形为包含关系。

判断距离边界最近的节点

当图与矩形边界不存在包含关系时,需要知道距离矩形边界最近的节点。

那么只需要定义一个距离公式,遍历所有节点,找出最小的距离所代表的节点即可。

首先定义距离公式:

  • x轴方向偏移量计算

    满足条件P1时,即x轴方向节点与边界有重叠时,x轴方向需要的偏移量为0

    P1,则xnodei=0;若P1,则x_{node_i} = 0;

    否则,需要根据节点与边界的位置关系,计算偏移量。

    节点在边界左边:

    rightnodei<=left边界,则xnodei=left边界rightnodei若right_{node_i} <= left_{边界},则x_{node_i} = left_{边界} - right_{node_i}

    节点在边界右边:

    leftnodei>=right边界,则xnodei=right边界leftnodei若left_{node_i} >= right_{边界},则x_{node_i} = right_{边界} - left_{node_i}
  • 同理,y轴方向偏移量计算

    满足条件P2时,即y轴方向节点与边界有重叠时,y轴方向需要的偏移量为0

    P2,则ynodei=0;若P2,则y_{node_i} = 0;

    否则,需要根据节点与边界的位置关系,计算偏移量。

    节点在边界上边:

    bottomnodei<=top边界,则ynodei=top边界bottomnodei若bottom_{node_i} <= top_{边界},则y_{node_i} = top_{边界} - bottom_{node_i}

    节点在边界下边:

    topnodei>=bottom边界,则ynodei=bottom边界topnodei若top_{node_i} >= bottom_{边界},则y_{node_i} = bottom_{边界} - top_{node_i}

其中,left、right、top和bottom分别表示矩形的左边界、右边界、上边界和下边界。可以通过矩形的坐标和宽高获取到。

左右边界:

leftrect=xrectrightrect=xrect+widthrectleft_{rect} = x_{rect},right_{rect} = x_{rect} + width_{rect}

上下边界:

toprect=yrectbottomrect=yrect+heightrecttop_{rect} = y_{rect},bottom_{rect} = y_{rect} + height_{rect}

获取到偏移量后,就可以计算距离了:

Dnodei=xnodeixnodei+ynodeiynodeiD_{node_i} = \sqrt{x_{node_i} x_{node_i} + y_{node_i} y_{node_i}}

最小距离:

Dmin=Min{Dnode1,Dnode2,Dnode3,...,Dnodei}D_{min} = Min\{ D_{node_1}, D_{node_2}, D_{node_3}, ..., D_{node_i} \}

得到最近节点所需要的偏移量:

(xnodemin,ynodemin)(x_{node_{min}}, y_{node_{min}})

缩放位移转换

在实际操作过程中,需要将边界矩形映射到位移缩放后的图像上,我们可以简化为矩形四个角的坐标点映射到位移缩放后的图像上,其中坐标点的映射公式为:

(x,y)=f(x,y)=(xscaleoffsetX,yscaleoffsetY)(x',y')= f(x,y) = (\frac{x}{scale} - offsetX, \frac{y}{scale} - offsetY)

其中offsetX和offsetY分别为当前图在x轴方向和y轴方向的偏移量,sacle为当前图的缩放比例。

得到上下左右的边界:

(left边界,top边界)=f(x边界,y边界),(left_{边界}',top_{边界}') = f(x_{边界},y_{边界}),
(right边界,bottom边界)=f(x边界+width边界,y边界+height边界)(right_{边界}',bottom_{边界}') = f(x_{边界}+width_{边界},y_{边界}+height_{边界})

最后是利用最近节点与边界的偏移值,将图回弹到边界内:

(offsetX,offsetY)=(offsetX+xnodemin,offsetY+ynodemin)(offsetX',offsetY') = (offsetX + x_{node_{min}}, offsetY + y_{node_{min}})