关于矩形连线 (rectangle connect)
矩形连线问题,就是在两个矩形之间建立带可曲折的无覆盖的连线(连线不覆盖图形),我的方法是这样的:
CPoint pts[5];//输出连线的点列表
int nPts;//输出点列表中点的数量
void GetRectConnectLines(CPoint * pts,int nPts )
{
CRect recta,rectb;//两个矩形
CPoint ac,bc; //矩形中心
CRect rectc;//中心连线矩形
int aw = recta.Width();
int bw = rectb.Width();
int ah = recta.Height();
int bh = rectb.Height();
ac = recta.CenterPoint();
bc = rectb.CenterPoint();
rectc = CRect( ac,bc );
int cw = rectc.Width();
int ch = rectc.Height();
//(1)当矩形可以找到中心分隔线的时候,并且距离不小于某个限定值(不应该在过小的间隙中连接),矩形靠近中间分隔线的中点就连接到中间分隔线上。
int ld = 50;//限定中分线间隔距离
int td = 0;
td = cw*2-aw-bw;
if( td > ld*2 ) //如果中心连接矩形的宽度比两个矩形的宽度和还要大,则存在竖直的中心分割线(用*2判断防止整数除法丢失精度)
{
if( ac.x < bc.x ) //a矩形的右边和b矩形的左边连接到竖直中分线
{
pts[0] = ac;
pts[0].Offset( aw/2.f,0 );
pts[1] = pts[0];
pts[1].Offset( td/4.f,0 );
pts[3] = bc;
pts[3].Offset( -bw/2.f,0);
pts[2] = pts[3];
pts[2].Offset( -td/4.f,0);
pts[1].x = pts[2].x ;//对齐
}
else //a矩形的左边和b矩形的右边连接到竖直中分线
{
pts[0] = ac;
pts[0].Offset( -aw/2.f,0 );
pts[1] = pts[0];
pts[1].Offset( -td/4.f,0 );
pts[3] = bc;
pts[3].Offset( bw/2.f,0);
pts[2] = pts[3];
pts[2].Offset( td/4.f,0);
pts[1].x = pts[2].x ;//对齐
}
nPts = 4;
return;
}
//同样的方法找到水平中分线,并把边连接上去
td = ch*2-ah-bh;
if( td > ld*2 )
{
if( ac.y < bc.y )
{
pts[0] = ac;
pts[0].Offset( 0,ah/2.f );
pts[1] = pts[0];
pts[1].Offset( 0,td/4.f );
pts[3] = bc;
pts[3].Offset( 0,-bh/2.f);
pts[2] = pts[3];
pts[2].Offset( 0,-td/4.f);
pts[1].y = pts[2].y ;
}
else
{
pts[0] = ac;
pts[0].Offset( 0,-ah/2.f );
pts[1] = pts[0];
pts[1].Offset( 0,-td/4.f );
pts[3] = bc;
pts[3].Offset( 0,bh/2.f);
pts[2] = pts[3];
pts[2].Offset( 0,td/4.f);
pts[1].y = pts[2].y ;
}
nPts = 4;
return;
}
//(2)如果两个矩形找不到中分线,而且都没有互相覆盖边的中点,那么就取最近的垂直边进行连接。
if((cw*2< min(aw , bw) + ld) && (ch*2< max(ah , bh) + ld))
{ pts[0] = ac; pts[0].Offset( aw/2,0); pts[1] = ac; pts[1].Offset( dd.x,0); pts[2] = bc; pts[2].Offset( 0,-bh/2); nPts = 3; return; }
//(3)第三种情况,获得两个矩形的最小外接矩形,把未覆盖的边连接到外接矩形的边上去,优先寻找同侧的可连接边
rectc.UnionRect( recta,rectb );//外接矩形
rectc.InflateRect( ld/2,ld/2 );//外扩一点距离
int ea[4] = {0,0,0,0};
int eb[4] = {0,0,0,0};
//找出没有被覆盖中点的边 ,优先连接可以同侧连接的边,即 (eb[i]&&ea[i]);如果没有同侧可连接边就连接下一条边(ea[i]&&eb[i<3?i:0])
if( recta->left<rectb->left )
{
ea[0] = 1;
if( (bc.y>recta->bottom) || (bc.y < recta->top) )
{
eb[0] = 1;
}
}
else
{
eb[0] =1;
if( (ac.y>rectb->bottom) || (ac.y<recta->top ))
{
ea[0] = 1;
}
}
if( recta->right > rectb->right )
{
ea[1] = 1;
if( (bc.y>recta->bottom) || (bc.y < recta->top) )
{
eb[1] = 1;
}
}
else
{
eb[1] =1;
if( (ac.y>rectb->bottom) || (ac.y<recta->top ))
{
ea[1] = 1;
}
}
if( recta->top<rectb->top )
{
ea[2] = 1;
if( (bc.x>recta->right) || (bc.x < recta->left) )
{
eb[2] = 1;
}
}
else
{
eb[2] =1;
if( (ac.x>rectb->right) || (ac.x<recta->left ))
{
ea[2] = 1;
}
}
if( recta->bottom>rectb->bottom )
{
ea[3] = 1;
if( (bc.x>recta->right) || (bc.x < recta->left) )
{
eb[3] = 1;
}
}
else
{
eb[3] =1;
if( (ac.x>rectb->right) || (ac.x<recta->left ))
{
ea[3] = 1;
}
}
// 连接代码未给出,请读者自行完善。
//(4)第四种情况,一个矩形被另一个矩形包含而不重合,内矩形的边连接到外矩形的边的内侧
//(5)第五种情况,两个矩形完全重叠,连线应该是不可见
}