交互式图形软件包括图形操作系统Windows,Office, AutoCAD 中的可编辑对象,共同的特点是鼠标交互编辑,一些可编辑图形对象和一些控制实体,例如Windows的窗口,按钮,拖动条,Office中Box,文字块,CAD中的线,圆弧实体,当click时候会显示一些点或者线段,他们是对象的附属对象,叫control component-控制部件,这些是可以被鼠标snap,hover,click, drag这些操作的,交互代码有针对不同控制部件位置修改后间接的对被编辑对象的修改及其它控制部件的修改,从而达到鼠标交互式编辑的目的,CAD 中的Grip Point就是各种CAD几何对象的control component。
一般CAD的具体几何对象类都有个叫Entity的抽象基类, 有一些操作响应接口方法提供给具体派生类去具体实现,包括不同操作下绘制不同的几何对象和夹点的代码实现,例如一般clicked当单击线的时候被调用,hovered和unhovered是鼠标移动晃到线上面或者离开时被调,moving是线被拖动或者夹点(gripId指定夹点)被拖动时候,v为屏幕上的二维移动向量。
鼠标的操作系统消息只有button press, button release,mouse move, wheel,这些OS Message配合snap box对entity的component中的几何体的相交检测断言程序共同产生了对象的事件,例如 鼠标move 时 和obj相交,则 obj.hovered; 鼠标左键释放时距离上次左键按下时间很短且和obj相交,则obj.clicked
class Entity: public Object
{
const AABBox boundingBox(){...};
virtual void recordComponents() = 0;
...
virtual void clicked(Id objId) = 0;
virtual void hovered(Id objId) = 0;
virtual void unhovered(Id objId) = 0;
virtual void beginMove(Id objId) = 0;
virtual void moving(Id objId, vec2 v) = 0;
virtual void endMove(Id objId,vec2 v) = 0;
};
下面实现的具体几何对象是 一个简单的等腰直角三角形v0-v1-v2,点v1是直角,点v0 v2是45度角点,有两个grippoint gpt0 用于移动三角形,位置在v1, gpt1, 用于修改三角形大小,位置在v0-v2边线中点
class DenYaoTriangle: public Enyity
{
...
vec3 v0 v1 v2; // 顶点坐标
enum COMId
{
ID_MAIN,
ID_GPT0,
ID_GPT1
};
Component mainGeo; // 三角形几何对象
map<COMId, Component> gripPoints; // 夹点对象
...
};
当单击三角形,显示夹点,夹点将会被扑捉
void DenYaoTriangle::clicked(Id objId)
{
if (objId.is(ID_MAIN))
{
showGripPoints(true);
}
}
当夹点被单击后移动鼠标,系统将调用moving方法,此时将根据被移动的夹点计算三角形的参数的变化及其它夹点的变化
void DenYaoTriangle::moving(Id objId, vec2 v)
{
// 如果objId是gpt0, 则移动objects的预览,一般移动时并不是最终修改, 这里的preview是临时显示对象
// 如果是gpt1, 则按照下面的解析几何图示
// 计算预览的v0,v2, 然后更新objects的preview
if(obiId.is(ID_GPT0))
{
vec3 v0_=v0+vec3(v,0.0);
vec3 v1_=v1+vec3(v,0.0);
vec3 v2_ =v2+vec3(v,0.0);
mainGeo.preview.update(v0_,v1_,v2_);
gripPoints[ID_GPT1].update((v0_+v2_)*0.5);
}
else if (objId.is(ID_GPT1))
{
// ^ x
// .
// v0*-----g1------*v2 <--y
// .
// .
// * v1(g0)
vec3 x = vec3(v.norm(),0.0);
vec3 y = vec3(-x[1],x[0],0.0);
vec3 g1= gripPoints[ID_GPT1].pos() + vec3(v,0.0);
double l_g01 = (g1-v1).length();
vec3 v0_ = g1+y*l_g01;
vec3 v2_ = g1 - y*l_g01;
mainGeo.preview.update(v0_,v1,v2_);
}
}
当endMove时,代码和moving一样,只是修改修改实际的v0,v1, v2
DenYaoTriangle::endMove(Id objId, vec2 v)
{
if (...ID_GPT0)
{
v0+= vec3(v,0);
v1 += vec3(v,0);
v2+=vec3(v,0);
mainGeo.update(v0,v1,v2);
updateGripPoints();
}
else if (....ID_GPT1)
{
v0 = ...
v2 = ...
mainGeo.update(v0,v1,v2);
updateGripPoints();
}
}
对于操作系统中的GUI,cad中的几何实体是对应他们的是窗口和控件对象,一般是个平面box模型,而grippoint对应一些子控件,例如拖动条对象中的拖动块,checkbox,他们也都是在鼠标click或者double click drag事件下定制的操作响应;对于EDA中,实体主要是各种平面元器件和连线,主要的编辑是对元器件的脚点连线,拖动元件,这些脚点也是grip point的概念,当然CAD CAM EDA 领域包括行业CAD例如BIM GIS SWAT 船舶 航空航天等等业务区别和软件操作习惯及逻辑还是非常大的,还有一大块在行业数值模型或者电路网络的不同业务层面的仿真分析物理上的计算,属于更大的CAE概念,一般我们看到的交互编辑工作,俗话叫画图,属于CAE的前处理和后处理工作,侠义的CAD叫计算机辅助绘图。