2023年2月

在Visio的二次开发中,当发布图纸的时候,我们往往需要保存图纸和图纸的设备信息到数据库,图纸是将文件以二进制保存到数据库中,设备信息是保存图纸对应的Shape的各种自定义属性。本文主要介绍如何保存图纸背后的设备信息。
这里图纸的设备信息可以通过一个设备表如Device1来放置同一类型的设备信息,如负荷开关存放在Device1,架空线放在Device2等等,Device(n)是我们详细放置某种类型设备的表,其结构如下
VisioEquip_Devicen.jpg

另外主要我们再新建一个表来管理那种类型的设备对应那个表即可。如下图所示:
VisioEquip_DeviceTable.jpg
一旦建立了上表的关系,我们就知道那个类型的设备对应的表名是多少了。我们通过代码


List
<
DeviceTableInfo
>
deviceTables
=
deviceTableDAL.GetDeviceTables();

就可以获取到所有的设备类型表的信息了,这可以为我们下一步保存设备信息做准备。
为了获取到某个设备类型对应的表信息,我们可以这样拿到它的对应信息。



string
deviceType
=
VisioUtility.GetShapeCellValue(shape,
"
设备类型
"
);

DeviceTableInfo tableInfo

=
deviceTableDAL.GetTableNameByDevice(deviceTables, deviceType);


我们知道,图纸有很多信息,我们遍历图纸设备的时候,可以通过遍历其选区实现,如下所示



if
(VisioUtility.HasShapeInWindow(visWindow))



{

visWindow.SelectAll();

foreach
(Visio.Shape shape
in
visWindow.Selection)



{

}



visWindow.DeselectAll();

}


这样,我们有表的信息,又有了图纸设备遍历的方法,那我们就可以根据这些信息,生成保存每个设备的SQL语句了,你说是么?因为每个Shape有很多属性信息,我们把属性信息保存到数据库就可以了啊。

说到这里,我们需要注意一个问题,设备有很多属性列表,数据库也有很多字段属性列表,我们需要以一个为准,作为Sql语句字段列表的标准,否则就会出现问题。由于取本地Shape的属性虽然方便,但是由于其可能因为模具属性变化可能和数据库的字段列表不再一致,因此还是以数据库字段列表为准比较妥当。
为了获取某个表的字段列表信息,我们需要使用下面代码(该代码是我代码生成工具的基本函数来的,呵呵)



private
DataTable GetReaderSchema(
string
tableName)



{

DataTable schemaTable

=

null
;


string
sql
=

string
.Format(
"
select * from [{0}]
"
, tableName);

Database db

=
DatabaseFactory.CreateDatabase();

using
(DbConnection connnection
=
db.CreateConnection())



{

connnection.Open();


DbCommand dbCommand

=
db.GetSqlStringCommand(sql);

dbCommand.Connection

=
connnection;


using
(IDataReader reader
=
dbCommand.ExecuteReader(CommandBehavior.KeyInfo
|
CommandBehavior.SchemaOnly))



{

schemaTable

=
reader.GetSchemaTable();

}



}




return
schemaTable;

}


上面的函数是获取表的Schema信息,通过获取对应的信息,我们就知道一个表有那些字段了,下面的代码是实现把字段信息写到列表中。


DataTable schemaTable
=
GetReaderSchema(tableName);

List

<
string
>
nameList
=

new
List
<
string
>
();

foreach
(DataRow dr
in
schemaTable.Rows)



{

nameList.Add(dr[

"
ColumnName
"
].ToString());

}

然后,通过遍历字段列表,我们就知道Insert语句的字段列表了,为了找到对应某个字段的值,我们可以使用下面代码实现获取Shape属性对应的值(有则拿出来,否则赋给NULL)



string
value
=
VisioUtility.GetShapeCellValue(shape, column.ColumnName);


if
(
!
string
.IsNullOrEmpty(value))



{

sqlValues

+=

string
.Format(
"
'{0}',
"
, value);

}



else




{

sqlValues

+=

"
NULL,
"
;

}


这样我们就可以构造完成一个Shape的Insert语句了,其他的也就如此这般就OK啦。其实就是在刚才的遍历函数中,生成每一条Sql语句,放到列表中,然后统一执行这些Sql语句就实现设备的保存工作了。
VisioEquip_Data.jpg

停电分析,顾名思义,是对图纸进行停电的逻辑分析。在电气化线路中,一条线路是从一个电源出来,连接着很多很多的设备的,进行停电分析,有两个重要的作用:一是看图纸上的Shape元件是否连接正常,二是看哪些设备有电无电。通过给有电的设备一种颜色(如绿色),无电的设备一种颜色(如红色),那么就可以很明显地看到通电的不同变化。
对一张Visio绘制的电气线路图,我们如何进行停电分析呢?下面我们看看相关的序列逻辑先。
PowerCutClass.jpg

在上面的序列图中,主要实现了这样的思路:
停电分析是通过保存设备相关连接信息到数据库,以电源(如飞达)为起点,对设备信息进行线路的拓扑分析,把分析保存到数据库中,然后获得拓扑模型中有电的设备,对图纸的设备颜色进行更新(有电为绿色,无电为红色),如果撞电,则恢复所选开关的颜色。

PowerCutEquipment.jpg

由于以上的关系表,只是对一个飞达进行了线损模型分析,因此只会存在一个
-1
即飞达的情况,其他
ID
都是和该飞达相关联的下游设备
ID
;如果我们找到每一个的设备
ID
和其父
ID
(上游设备
ID
)即满足要求。

Equipment
为设备的
ID

ConnectionShapes
为关联的设备
ID
集合



1、

先在
ConnectionShapes
寻找有
-1

Equipment

得到下列模型:




ID

PID

1

-1




2、

下面再找
1
下游设备;在关系表中寻找
Equipment=1

ConnectionShapes
有那些关联设备,发现有
-1

2

-1

1
的上游设备,不能使用,因此剩下
2
,得到如下表。


ID

PID

1

-1

2

1




3、

继续找
2
的下游设备;发现
2

1

3

8

7

10
和其关联,
1

2
的上游设备,不能使用,剩下的列出来。


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2




4、

依次对
3

8

7

10
进行分析,得到以下数据,下面先对
3
下游设备进行分析


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3




继续对
4

11
进行分析,先对
11
进行分析,发现
11
只有
3
相连,
3
为上游设备,结束;

再对
4
进行分析,如下。


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3

5

4

12

4




继续对
5
、和
12
进行分析,先对
12
进行分析,发现
12
只有
4
相连,
4
为上游设备,结束;对
5
进行分析,如下。


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3

5

4

12

4

6

5




继续对
6
进行分析,有
13
相连;继续分析
13
下游设备没有,结束,得到如下。


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3

5

4

12

4

6

5

13

6




5、

继续第上面步骤的分析,上面说到
2
下游设备有
3

8

7

10
,还有
8

7

10
没有分析,对
8
下游设备继续分析。


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3

5

4

12

4

6

5

13

6

9

8





9
继续分析


ID

PID

1

-1

2

1

3

2

8

2

7

2

10

2

4

3

11

3

5

4

12

4

6

5

13

6

9

8

15

9

16

9

17

9

18

9


继续分析
15

16

17

18
发现没有下游设备,结束。

根据上面的分析结果,我们就
可以得到线路的拓扑树状图,即一个倒立的树,分析的存储结果为下图所示。
PowerCutModel.jpg

其中关键的ID、PID是用来在树之间漫游的,LoginIP用来区分不同用户的分析结果,BelongTo在多个电源通电的时候,区分不同的电源(即构造几颗倒立的树),其他信息用作辅助。注意:断开的开关,看成是树的分支终点。构造模型的时候不会记录该开关设备的信息,分析的时候会自动断层。

最后附上分析的结果,红的红,绿的绿,多好看,哈哈
PowerCutResult.jpg

有一项研究,需要计算导线的弧垂, 网上搜索,发现这方面的资料很少,贡献出来大家分享:

c#架空输电线路设计系统(1)

c#架空输电线路设计系统(2)

c#架空输电线路设计系统(3)

c#架空输电线路设计系统(6) -斜抛物线公式全集

35kV线路弧垂计算与观测

另外还有两个文档,一个是Word文件,一个是Excel文档,Excel中包含了各种比载及弧垂的计算实例和公式.
该文件包含了两个文件:导线应力弧垂计算的BASIC程序.doc 和应力弧垂计算表.xls


架空线路架设时,其线路形成的形状为“悬链线”,当线路的挡距足够大,电线材料的刚性影响可以忽略,电线的荷载沿线长均匀分布。悬链线方程包含双曲线函数,计算复杂不便使用,一般将其简化为斜抛物线公式或平抛物线公式。在一般情况下,当
h/L > 0.15
时(两悬挂点高差和档距的比值),应考虑使用斜抛物线公式进行计算弧垂,斜抛物线是比较精确的,且随着
h/L
增大反而误差更小。本研究采用斜抛物线进行弧垂计算。
采用的坐标原点位于悬挂点
A
,如下图所示
弧垂2.jpg

最后附上我研究做出的一个弧垂计算程序的图
LineSag.jpg

图中标记红色的部分为需要输入的参数,其他输入框的值为计算的输出值。

Alexa 是以发布世界网站排名而引人注目的一个网站。其实,此网站的搜索引擎也很好用,但是“网站排名”却是它吸引眼球的最主要原因。

以网站导航起家的Alexa创建于1996年4月,他们的目的是让Internet冲浪者在分享虚拟世界资源的同时,更多地参与Internet资源的组织。2002年5月Alexa放弃了自己的搜索引擎与Google合作。他们每天在网上搜集超过1,000GB的信息,然后进行整合发布。现在他们搜集的URL数量已经超过了Google。下图是他们自己给出的一个信息量比较图。纵轴为已有的URL地址的量,以十亿为单位。也就是说在量上,Alexa位居世界四大名搜索引擎第一位,已经超过了350亿。焦点在于,Alexa不仅给出这350多亿网址的链接,而且为其中的每一个网站进行了排名。可以说,Alexa是当前拥有URL数量最庞大,排名信息发布最详尽的网站。

Alexa的世界网站排名主要分两种:综合排名,可以叫做绝对排名,即特定的一个网站在所有350多亿网站中的名次。Alexa每三个月公布一次新的网站综合排名。此排名的依据是用户链接数(Users Reach)和页面浏览数(Page Views)三个月累积的几何平均值。分类排名一是按主题分类,比如新闻、娱乐、购物等,Alexa给出某个特定网站在同一类网站中的名次。Alexa将其收集到的网站共分了16个大类,每个类下又分为多个主题。

阿里妈妈的网站也有Alexa网站排名(
http://tool.alimama.com/site.php
)、中国站长网站(
http://alexa.chinaz.com/Index.asp
)也提供Alexa排名查询,还有很多网站也提供了它们的Alexa排名,这些排名的数据都是通过调用称为
Alexa Web Information Service (AWIS)
的服务,地址是
http://awis.amazonaws.com/doc/2005-07-11/AWSAlexa.wsdl

那么我们如何才能使用这些服务,以便创建我们的Alexa排名查询操作呢?
1. 首先你通过网站连接
http://www.amazon.com/gp/browse.html?node=12782661
,了解它是做什么的,收费如何(1000次约人民币1元左右)。

2. 注册一个帐号,绑定您的银行卡或者信用卡

3. 成功后会给你一个发送一个邮件,并可以登录查看你的专用公钥私钥字符串。
awiskey.jpg


4. 根据这些你就可以访问它的AWIS访问了,如果你要了解进一步的开发的话,请参考这里的文档:
http://docs.amazonwebservices.com/AlexaWebInfoService/2005-07-11/

5. 如果你有疑问,可以在论坛中询问,当然都是老外的了。
http://developer.amazonwebservices.com/connect/forum.jspa?forumID=14

6.   AWIS有很多Response,如UrlInfoResponseResponse、CategoryBrowseResponseResponse、SitesLinkingInResponseResponse、TrafficHistoryResponseResponse、CategoryListingsResponseResponse、CrawlResponseResponse等,这些包含了各类排名等数据。

7. 我调用了AWIS做了一个小的测试应用,程序界面如下:
awisProgram.jpg


8. 最后贴一些代码辅助大家




获取Response的信息

我们知道,Visio菜单【视图】中有一个缩放的菜单项目,如下所示,选择响应的选项会对图纸进行缩放。
Visio_Zoom1.jpg

另外,它的工具条中也有一个下拉列表框,除了可以选择现有的那些选项外,还可以输入自定义的值,达到自定义缩放比例的功能。
Visio_Zoom2.jpg

本文介绍如何使用C#和Visio的SDK函数,实现Visio中的图纸各种缩放操作。
首先我们建立一个缩放菜单项和一个各种缩放比例的子菜单项,如第一个图形所示;然后将所有的子菜单项的事件处理指向同一个函数,如下所示



private

void
menu_View_Zoom_Click(
object
sender, EventArgs e)



{

ToolStripMenuItem item

=
(ToolStripMenuItem)sender;

SetZoom(item.Text);

}


然后添加下拉列表框,如第二个图形所示,并添加它的处理函数。



private

void
tsStandard_Zoom_KeyUp(
object
sender, KeyEventArgs e)



{

if
(e.KeyCode
==
Keys.Enter)



{

SetZoom(tsStandard_Zoom.Text);

}



}


接着我们实现SetZoom函数,该函数除了接收各种缩放比例外,还可以接收自定义的比例处理。
具体逻辑,看代码后就一目了然



private

void
SetZoom(
string
zoomText)



{



switch
(zoomText)



{

case

"
400%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView400);

break
;

case

"
200%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView200);

break
;

case

"
150%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView150);

break
;

case

"
100%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView100);

break
;

case

"
75%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView75);

break
;

case

"
50%
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdView50);

break
;

case

"
上次
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdZoomLast);

break
;

case

"
宽度
"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdZoomSingleTile);

break
;

case

"

"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdZoomPageWidth);

break
;

case

"
缩放

"
:

VisApplication.DoCmd((

short
)VisUICmds.visCmdViewCustom);

break
;

default
:

CustomedSize(zoomText);

break
;

}



}




private

void
CustomedSize(
string
zoomText)



{

try




{

double
zoomSize
=
Convert.ToDouble(zoomText.Replace(
"
%
"
,
""
));

this
.VisWindow.Zoom
=
zoomSize
/

100
;

this
.tsStandard_Zoom.Text
=
zoomSize
+

"
%
"
;

}



catch




{ }


}


这样就可以完整实现Visio中的缩放、自定义缩放等功能了。