实现任意形状连接关系

2008-11-20, 研究实现任意形状连接关系

一直以来,我画连接关系主要是处理电路之间的连接关系,还比较简单,原因在于以下几点:
1.        能画得横平竖直,交叉点能正确显示,母线馈线部分能规范表示就行
2.        各种编辑操作后,连接关系能够保持
最主要是横平竖直,使得处理起来方便得多,上述功能早就实现了。下面这张图就是一个典型的电路之间的连接关系的展现。

但需求越来越多,已有不少用户提出能否处理弯曲的连接关系,归纳起来,有以下几点:
1.        能弯曲显示连接关系
2.        能编辑形状
3.        各种相关对象编辑操作后,连接关系能够保持
这个问题,我放了一段时间,主要是没有时间来做,还有一个主要原因是没有考虑成熟。
今天,不用上班,就在家里,仔细琢磨了一下这个问题,初步设计出以下思路
1.        这种关系有两个外连接点
2.        可以和两个相关对象建立关系
3.        表现形式可以借用现有的线段、曲线、箭头等基本图元
4.        连接关系的形状编辑直接用基本图元的编辑
在以前软件的基础上,可以采用一个复合图元来实现,设计两个TPad表示两个外连接点,两个TCbwObject表示两个相关对象,再用一个TCbwObject表示关系的样子,先支持线段、圆弧、箭头、连接普通曲线、连续贝塞尔曲线等几个基本图元。

首先是设计界面,当然,通过代码是最快的。[code]  AddItemToMenu(MenuItem_Relation,  "线段",   cctLine,    10,   MenuItem_Relation_LineClick); // 线段
   AddItemToMenu(MenuItem_Relation,  "圆弧",   cctArc,    11,   MenuItem_Relation_LineClick); // 圆弧
   AddItemToMenu(MenuItem_Relation,  "箭头",   cctArrow,    11,   MenuItem_Relation_LineClick); // 箭头
   AddItemToMenu(MenuItem_Relation,  "连续普通曲线",   cctCurve,    2,    MenuItem_Relation_LineClick); // 连续普通曲线
   AddItemToMenu(MenuItem_Relation,  "连续贝塞尔曲线",   cctBezier,    13,   MenuItem_Relation_LineClick); // 连续贝塞尔曲线[/code]语言切换稍后完成。
运行后界面效果如下

其次,需要处理这些菜单的响应事件,即将这些菜单项的Tag值作为参数传递给画图过程[code]void __fastcall TCbwGraphBaseForm::MenuItem_Relation_LineClick(
      TObject *Sender)
{ //
   SpecialContent = AnsiString(GetTag(Sender));
   OperateType = cotDraw;
   cClassType = cctRelationShip;
}[/code]下来就该设计关系类了,这个简单[code]class TCbwRelationShip : public TCompoundMeta
{
   typedef TCompoundMeta inherited;
   TCbwObject * FDisplayObject;        // 关系图元,动态创建
   CBW_PUBLIC(TCbwObject *, BeginObject, FBeginObject)        // 相关对象一
   CBW_PUBLIC(TCbwObject *, EndObject, FEndObject)                // 相关对象二
   CBW_PUBLIC(TPad *, BeginPad, FBeginPad)                                // 外连接点一
   CBW_PUBLIC(TPad *, EndPad, FEndPad)                                        // 外连接点二
public:
   CBW_DEFINE_OBJECT(TCbwRelationShip)

        void __fastcall SetSpecialContent(AnsiString content);
void __fastcall SetAllDoneFlag(bool s);
};[/code]需根据特定内容动态创建关系显示图元[code]void __fastcall TCbwRelationShip::SetSpecialContent(AnsiString content)
{
   int tag = content.ToInt();
   FDisplayObject = (TCbwObject *)(*CbwBuildObjectMap)[tag]();
   AddObject(FDisplayObject);
   CloneUIProperties(this, FDisplayObject);
   CloneUIProperties(this, FBeginPad);
   CloneUIProperties(this, FEndPad);
}[/code]关系对象构造完成后,设置相关的对象与外连接点[code]void __fastcall TCbwRelationShip::SetAllDoneFlag(bool s)
{
   if(s)
   {
      FBeginPad->AddPoint(FDisplayObject->BeginPoint);
      FEndPad->AddPoint(FDisplayObject->EndPoint);
      if(!AllDoneFlag)
      {
         PointNumber = FDisplayObject->PointNumber;
         AllocatePoints();
         for(int i = 0; i < PointNumber; ++i)
            Points[i] = FDisplayObject->Points[i];
         inherited::AllDoneFlag = s;
         Compose();
         if(FBeginObject)
         {
            TCbwFloatPoint distance = TCbwFloatPoint(FBeginPad->CentralPoint.x - FBeginObject->CentralPoint.x,
                     FBeginPad->CentralPoint.y - FBeginObject->CentralPoint.y);
            FBeginObject->Relations[FBeginPad] = distance;
         }
         if(FEndObject)
         {
            TCbwFloatPoint distance = TCbwFloatPoint(FEndPad->CentralPoint.x - FEndObject->CentralPoint.x,
                     FEndPad->CentralPoint.y - FEndObject->CentralPoint.y);
            FEndObject->Relations[FEndPad] = distance;
         }
      }
   }
}[/code]剩下的就是在TCbwObject类中加上相应的支持,首先是变量
std::map<TPad *, TCbwFloatPoint> Relations;             // 关系点集合,加上相对位置,便于后续调整
然后是需要在编辑操作之后的调整工作[code]void __fastcall TCbwObject::RefreshRelations(double xRatio, double yRatio, double angle)
{
   CBW_ITERATOR_MAP(TPad *, TCbwFloatPoint, Relations)
   {
      TPad * pad = it->first;
      TCbwRelationShip * relation = dynamic_cast<TCbwRelationShip *>(pad->;ParentObject);
      if(!relation)  continue;
      relation->RefreshPosition(this, it->second, xRatio, yRatio, angle);
   }
}[/code]其实交由关系类完成。[code]void __fastcall TCbwRelationShip::RefreshPosition(
         TCbwObject * object,
         TCbwFloatPoint distancePoint,
         double xRatio, double yRatio, double angle)
{
   if(Selected)   return;
   double dx = distancePoint.x * xRatio;
   double dy = distancePoint.y * yRatio;
   if(angle == 90)
   {
      double t = dx;
      dx = dy;
      dy = t;
   }
   dx += object->CentralPoint.x;
   dy += object->CentralPoint.y;
   if(FBeginObject == object)
      BeginPoint = TCbwFloatPoint(dx, dy);
   else
      EndPoint = TCbwFloatPoint(dx, dy);
}[/code]最后分别针对各种编辑操作进行处理:[code]DragBy: RefreshRelations(1, 1, 0);
FlipHorzOnPoint: RefreshRelations(-1, 1, 0);
FlipVertOnPoint: RefreshRelations(1, -1, 0);
Rotate: RefreshRelations(1, 1, 90);
Zoom: RefreshRelations(horzRatio, vertRatio, 0);[/code]最后,在主窗口中处理一下关系对象的创建与点添加过程的相关操作,即鼠标点下的对象将绑定到关系对象中。
运行结果令我满意。

拖动控点以编辑形状

拖动相关对象,测试连接关系是否保持

也可以通过对象浏览器进行编辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值