以文本方式查看主题

-  曙海教育集团论坛  (http://sun4.cn/bbs/index.asp)
--  Protel开发  (http://sun4.cn/bbs/list.asp?boardid=41)
----  Protel99原理图显示库的开发  (http://sun4.cn/bbs/dispbbs.asp?boardid=41&id=1856)

--  作者:wangxinxin
--  发布时间:2010-11-29 12:07:12
--  Protel99原理图显示库的开发
摘要:电路原理图的显示是开发电路故障诊断等软件中的关键技术。本文利用Visual C++6.0和面向对象方法开发了Protel99原理图显示库。在分析Protel99原理图文件的格式的基础上,详细描述了显示库的主要的类和方法函数的设计原理。显示库在某电源测试台软件中得到成功的应用,稍作修改,便可用于其它矢量图形的显示,如AutoCAD图形。

关键词: Protel99;原理图;Visual C++;面向对象

 1 引言

在进行电路故障诊断等软件设计时,会遇到电路图的显示、拓扑分析等问题。在自己的程序中,直接实现上述功能是不现实的。Protel99是国内使用非常广泛的电路图的绘制工具,于是笔者开发了Protel99原理图显示库,该显示库读取Protel99生成的原理图文件,完成电路图的显示、拓扑分析等功能,为测试人员提供尽可能多的测试信息,引导测试人员进行故障隔离定位及元件的检测、方便电路的维修。具体如下:①读取Protel99原理图文件,转变为自定义格式的原理图文件,并显示;②实现了电路图的自由缩放、元件和电气节点的点选、定位和属性的设置;③查询和导出电路图的网表。

2 Protel99原理图显示库的开发

Protel99原理图显示库需要把Protel99原理图文件转换成自定义格式的原理图文件,因此先介绍Protel99原理图的文件格式。

2.1  Protel99原理图的文件格式

Protel99原理图文件(SCH)是Protel99存储原理图的格式,存储了许多供Protel99使用的信息,通常是以二进制格式存放的,格式比较复杂,所以首先把SCH格式转换为ASC格式。ASC格式是文本文件,简明易读,包含了构造自定义格式原理图所需的所有信息。文本文件中每一行表达一个确定的信息,对于一行而言,每个字符串之间是用空格隔开的。Protel99原理图文件(ASC)的基本结构如下:

(1)[Font_Table]区段

定义原理图文本显示使用的字体。

(2)Library……EndLibrary区段

定义元件库,每个库用“Component…EndComponent”描述,包含了该元件库的信息:库的描述、库名、库的组成元素(用“Part…EndNormalPart”段描述)。本区段有很多信息仅供Protel99使用的,可以忽略。

(3)[Sheet……EndSheet]区段

原理图中元素的描述。位于紧接Sheet后的一行是描述页面(页面的尺寸,背景颜色,是否显示网格等)的;Template…EndTemplate描述原理图的模板(标签,线条,图标等);位于EndTemplate之后的内容描述原理图的中的元素(元件、导线、总线、网络标签等)。本区段有很多信息仅供Protel99使用的,可以忽略。

2.2  Protel99原理图显示库的类的设计

VisualC++ 是面向对象的程序设计语言,其MFC封装了几乎所有的WINDOWS API函数,提供了完善的图形绘制能力,可以绘制原理图中的各种图形元素,如矩形、点、线等。

分析可知,Protel99原理图是由以下图形元素组成的,直线、连续直线及多边形区域、椭圆及椭圆区域、矩形及矩形区域、圆弧及椭圆弧、文本等,Protel99原理图文件中已包含了各种图形元素的具体参数和组织方式。在了解了Protel99原理图的文件格式之后,就可以进行类的设计。设计的思想是面向对象和Protel99原理图的文件格式相结合的方法。主要设计了如下几个类:

2.2.1  图形元素基类(CDrawElement)

对各类图形元素进行分析,可以发现各类图形元素具有一些相同的属性和操作功能,如图形元素的颜色、线型、线宽等和绘制图形元素等操作。把各类图形元素中共性的属性和操作放在图形元素基类(CDrawElement)中,具体的图形元素类(圆弧类、多边形类等)由这个类派生,不再一一赘述。

class CDrawElement : public CObject 

{  long m_lColorPen;  //笔色                 

short m_sLineWide;          //线宽(像素)

………//其它属性  

void CalNewCoordinate(BOOL bMir, short sOriCom, int nComX, int nComY,

int nX,int nY,int *nNewX, int *nNewY);// 计算绝对坐标函数,参数依次为:元件镜像否、

          //元件的方向、元件的起点坐标XY、原始坐标XY、绝对坐标XY指针

          //根据所属元件的位置属性和本元素的相对坐标计算本元素的绝对坐标

virtual void Draw(CDC *pDC, BOOL bMirrored,       short sOrientation, int nComX, int nComY,)=0;

//绘制元素的纯虚函数,参数依次为:绘图设备上下文指针、元件镜像否、元件的方向、

//元件的起点坐标XY

virtual BOOL ReadWriteFile(CFile *file, BOOL bWrite);

//存储或读取自定义矢量原理图二进制文件

………//其它方法};

说明:①该类是各个具体的图形元素类的基类;②如果该类的派生类元素包含在某一元件库中(如管脚Pin类),该元素的坐标是相对坐标(相对于所属元件起点坐标的坐标),该元素的绝对坐标是根据所属元件的位置属性(起点、方向、是否镜像)和本元素的相对坐标计算得出的;如果该类的派生类元素直接包含在原理图中(如导线Wire类),则该元素的坐标就是绝对坐标;③该类中定义了绘制元素的纯虚函数,以便在其派生类中实现多态,绘制不同的元素,如直线、圆弧等;④ReadWriteFile是存取自定义格式二进制文件,本类仅存取公共属性,而派生类中不仅存取公共属性而且存取各类元素特有的属性。

2.2.2  元件类(CComponentSche)

分析Protel99原理图文件可知,各个元件的信息是这样组织的,元件的绘制信息,即元件的组成元素,如:管脚、直线、多边形等,是存放在元件库中的,其它信息,如元件的起点坐标、元件库的索引、元件名称等是单独存放的。本文设计了元件库类(CComLibSche)和元件类(CComponentSche),元件库类(CComLibSche)见2.2.3。

元件类(CComponentSche)派生于CObject,封装了元件的起点坐标、元件库的索引、元件名称等属性和元件的绘制(结合对应的元件库)、属性的存取、元件的点选、得到元件的边界矩形等操作,类代码从略。下面给出元件的绘制的算法:

void CComponentSche::Draw(CDC *pDC)

{    CComLibSche  *pComLib;// 元件库指针

根据本元件的元件库的索引得到相应的元件库并把地址赋给pComLib;

pComLib->Draw(pDC,m_bMirrored,m_sOrientation,m_nX,m_nY);

//把绘图设备上下文指针、镜像否、方向、起点坐标等参数传递给

//元件库的绘制函数,让元件库完成元件的绘制。

绘制元件名称;       

绘制元件型号;

根据本元件的选中状态,绘制边界矩形;}

2.2.3  元件库类(CComLibSche)

派生于CObject,封装了该类元件的组成元素(如:管脚、直线、多边形等,各类图形对象按照数组的形式组织)、元件库的索引等属性和该类元件的绘制等操作,类代码从略。下面给出该类元件的绘制的算法:

void CComLibSche::Draw(CDC *pDC, BOOL bMirrored, short sOrientation,

int nComX, int nComY)// 参数依次为:绘图设备上下文指针、元件镜像否、

//元件的方向、元件的起点坐标XY

{    n=GetPinNums();//得到管脚对象数组中元素的个数

while(n--){  CPinElement* pPin;//管脚类指针

pPin =GetPin(n)//从管脚对象数组中得到一个管脚对象

pPin ->Draw(pDC,bMirrored,sOrientation,nComX,nComY);

//把绘图设备上下文指针、元件镜像否、元件的方向、元件起点坐标XY等参数

//传递给管脚类的绘制函数,让管脚类完成管脚的绘制。

}

………//完成其它各类图形对象的绘制}

说明:元件库类(CComLibSche)的设计充分体现了面向对象的封装特性。元件库的管理机制体现在分层上,元件库类(CComLibSche)只是封装了各类图形对象,不直接管理到每个图形,各类图形对象的操作(如:绘制、属性的存取等)由各类图形对象类具体负责。这种分层结构带来了程序设计和管理上的便利,分层结构是本显示库设计的特色之一,原理图类(CSCheFigure)的设计也用到了这种结构,见2.2.4的算法示例。

2.2.4  原理图类(CSCheFigure)

派生于CObject,封装了Protel99原理图显示库的所有功能,是该显示库的对外接口,包含了原理图中的相应元素,如:元件库、元件、电气节点、字体表、图纸等。类代码如下:

class __declspec(dllexport) CSCheFigure : public CObject 

{CTypedPtrArray<CObArray,CComLibSche*>m_ComLibArray;//元件库对象指针数组

CTypedPtrArray<CObArray,CComponentSche*>m_ComponentArray; //元件对象指针数组

CTypedPtrArray<CObArray,CNetNodeGroup*>m_NetGroupArray; //电气节点对象指针数组

float m_fScale,; //比例尺

………//其它属性               

BOOL WriteSSS(CString strSSSFile);//把CSCheFigure对象的信息写入自定义矢量原理图二进制文件

BOOL ReadProtel(CString strSchFile);//读取Protel99原理图文本文件ASC,初始化CSCheFigure对象

void Draw(CDC *pDC);//绘制原理图

………//其它方法};

下面给出本类中一些函数的算法:

(1)ReadProtel函数的算法

BOOL CSCheFigure::ReadProtel(CString strSchFile)

{ 打开文件strSchFile;

跳过文件头;

生成字体表;

依次生成各个元件库对象,并添加到元件库对象数组;

生成页面对象;

根据读到的字符串,生成各个对象(如元件、导线、网络标签、标签等),并添加到相应对象数组;

跳过"Version 2.0 Sheet"行及以后内容;

关闭文件strSchFile;

合并各个导线(Wire)、连接点(Junction)和电源端口(PowerObject) 对象,依次生成各个电气节点对象,并添加到电气节点对象数组;

return TRUE;}

(2)原理图绘制函数的算法

void CSCheFigure::Draw(CDC *pDC)

{    m_pSheetType->Draw(pDC);//m_pSheetType为图纸对象指针,绘制图纸

n= GetComponentNums ();//得到元件对象数组中元素的个数

while(n--){    CComponentSche* pCom;// 元件类指针

pCom =GetComponent(n)//从元件对象数组中得到一个元件对象

pCom -> Draw(pDC); //绘制元件对象

}

………//完成其它各类图形对象的绘制}

(3)WriteSSS函数的算法

BOOL WriteSSS(CString strSSSFile)

{    CFile file;

if(!file.Open(strDesFile,CFile::modeCreate|CFile::modeWrite,NULL))

return FALSE;

n= GetComponentNums ();//得到元件对象数组中元素的个数

file.Write((unsigned char *)&n,sizeof(int));

………//把其它对象数组中元素的个数写入file

n= GetComponentNums ();//得到元件对象数组中元素的个数

while(n--){    CComponentSche* pCom;// 元件类指针

pCom =GetComponent(n)//从元件对象数组中得到一个元件对象

pCom -> ReadWriteFile(&file,TRUE); //把元件对象的信息写入file

}

………//把其它各类对象的信息写入file

file.Close();

return TRUE;}

其它类的设计,如:字体类、图纸类等,不再一一赘述。

2.2.5  坐标的转换和图形的缩放

Protel99使用的坐标系是数学坐标系,坐标原点位于原理图的左下角,以像素为单位,向右为X轴正方向,向上为Y轴正方向。为方便起见,本显示库采用的Windows映像方式为MM_TEXT,因为MM_TEXT方式的坐标也是以像素为单位。但是在MM_TEXT方式下,屏幕(窗口)的原点在左上角,而X和Y的正方向分别是向右和向下,所以必须进行坐标的转换。为完成图形的缩放,需要定义一个比例尺m_fScale,该比例尺记录的是一个显示坐标单位所代表的实际坐标数值。

确定比例尺的算法:

float fScale1;

fScale1=(float)(原理图实际宽度/当前视图的宽度);

m_fScale=(float)(原理图实际高度)/(当前视图的高度);

if(fScale1>m_fScale)    m_fScale=fScale1;

实际坐标转变为显示坐标的算法:

显示坐标X=(int)(实际坐标X/m_fScale);

显示坐标Y =(int)( (原理图实际高度-实际坐标Y)/m_fScale);

显示坐标转变为实际坐标的算法(略)

本显示库把上述算法封装在原理图类(CSCheFigure)中,需要坐标转换时只要调用原理图类的函数即可。

 3结论

     本文介绍了Protel99原理图显示库开发中的关键技术。本显示库是使用Visual C++开发的,采用面向对象的设计方法,提高了代码的可重用性;忽略了Protel99原理图文件中一些不必要的信息;能够用于需要显示Protel99原理图的软件中,用户也可以根据功能的需要进行扩充。在某电源测试台软件中Protel99原理图显示库得到成功的应用,取得了满意的效果,如图1所示。本显示库稍作修改,便可用于其它矢量图形的显示,如AutoCAD图形。

  

图1  Protel99原理图显示库在某电源测试台软件中的应用