东方锅炉图纸清洗项目总结

引言

去东方电气集团旗下的东方锅炉做图纸清洗驻场开发,抽出时间总结一下。

达梦数据库调用

数据库连接

与 MySQL 类似的调用方法,但是似乎 Nuget 上面的包有些问题,我是直接调用本地的 DmProvider.dll 添加引用:

1
2
3
var connection = new DmConnection();
connection.ConnectionString = $"Server={server}; Port={port}; User Id={user}; PWD={password}";
connection.Open();

SQL语句调用

1
2
3
4
5
6
7
8
9
using (var command = new DmCommand("sql语句", connection))
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var ret = reader.GetString(0);
......
}
}

S3DownLoader

与数据对接的图纸对象存储容器是 document-bucket,我们可以通过 s3browser-cli.exe 将图纸下载下来。

首先通过s3文件对象模型 S3FileModel 将下载图纸所需信息导入,包括文件的 uid、名称、哈希路径等等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// <summary>
/// s3文件对象模型
/// </summary>
public class S3FileModel
{
/// <summary>
/// 文件在服务器的唯一id
/// </summary>
public string FileUid { get; set; }

/// <summary>
/// 文件名称
/// </summary>
public string FileName { get; set; }

/// <summary>
/// 服务器的源哈希路径
/// </summary>
public string BucketHashPath { get; set; }

/// <summary>
/// 下载至本地的目标路径
/// </summary>
public string TargetPath { get; set; }
}

查阅资料得知,在已经登录s3客户端的情况下直接调用方式如下:

1
s3browser-cli.exe /file download {账户} {服务器文件路径} {下载到本地的路径}

调用这个进程即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
using (Process process = new Process())
{
FileModel.BucketHashPath = Path.Combine("document-bucket/root/STORE", FileModel.BucketHashPath).Replace("\\", "/");
FileModel.TargetPath = Path.Combine(_downloadPath, GetBucketPathDirectories());

process.StartInfo = new ProcessStartInfo(Path.Combine(_installPath, "s3browser-cli.exe"),
$"/file download {_account} {FileModel.BucketHashPath} {Path.Combine(_downloadPath, "document-bucket")}")
{
CreateNoWindow = true
};
process.Start();
process.WaitForExit();
}

CAD相关

由于图纸数量很多,所以需要通过后台打开的方式打开图纸并操作:

1
2
3
4
5
using (Database db = new Database(false, false))
{
db.ReadDwgFile(PaperPath, FileOpenMode.OpenForReadAndWriteNoShare, true, null, true);
......
}

而后台打开不能使用选择集,只能通过遍历的方式查找标题栏(dbcplm_btl)和明细表(DBCXH)。

更改标题栏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private bool UpdateTitleData(Dictionary<string, string> titleMap, Database db)
{
using (var trans = db.TransactionManager.StartTransaction())
{
var blockTable = db.BlockTableId.GetObject<BlockTable>();
var modelSpace = blockTable[BlockTableRecord.ModelSpace].GetObject<BlockTableRecord>();
foreach (var id in modelSpace)
{
var titleBlock = id.GetObject<BlockReference>();
if (string.Compare(titleBlock.Name, DGTitleBlockNameString, StringComparison.OrdinalIgnoreCase) != 0)
continue;

foreach (ObjectId attId in titleBlock.AttributeCollection)
{
var attRef = attId.GetObject<AttributeReference>();
if (attRef == null || !titleMap.TryGetValue(attRef.Tag, out var value))
continue;

......
}
}
}
}

更改明细表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private bool UpdateBomData(List<Dictionary<string, string>> bomData, Database db)
{
using (var trans = db.TransactionManager.StartTransaction())
{
Dictionary<string, ObjectId> idMap = new Dictionary<string, ObjectId>();
var blockTable = db.BlockTableId.GetObject<BlockTable>();
var modelSpace = blockTable[BlockTableRecord.ModelSpace].GetObject<BlockTableRecord>();
foreach (var id in modelSpace)
{
var bomBlock = id.GetObject<BlockReference>();

bool isBomBlock = false;
foreach (var name in _bomBlockNames)
isBomBlock &= string.Compare(bomBlock.Name, name, StringComparison.OrdinalIgnoreCase) != 0;
if (isBomBlock) continue;

foreach (ObjectId attId in bomBlock.AttributeCollection)
{
AttributeReference attRef = attId.GetObject<AttributeReference>();
if (String.Compare(attRef.Tag, DGBomXuHaoNameString, StringComparison.OrdinalIgnoreCase) != 0)
continue;

idMap[attRef.TextString] = id;
break;
}
}

foreach (var bomRowData in bomData)
{
if (!idMap.ContainsKey(bomRowData[DGBomXuHaoNameString]))
continue;

var bomRowBlock = trans.GetObject(idMap[bomRowData[DGBomXuHaoNameString]], OpenMode.ForRead) as BlockReference;
foreach (ObjectId attId in bomRowBlock.AttributeCollection)
{
var attRef = attId.GetObject<AttributeReference>();
if (!bomRowData.TryGetValue(attRef.Tag, out var value))
continue;

attRef.TextString = value;
......
}
}

trans.Commit();
}

return true;
}

图纸另存为指定版本

由于客户大部分图纸都是 AutoCAD 2010 绘制的,默认的保存会变为 2018 版本,而官方 API 没有找到直接指定版本的保存,所以只能曲线救国,通过另存为的方式指定版本:

1
db.SaveAs($"{Path.Combine(Path.GetDirectoryName(db.Filename), Path.GetFileNameWithoutExtension(db.Filename))}-temp.dwg", DwgVersion.AC1024);

这里的 DwgVersion.AC1024 引出了一个之前不知道的知识点,可以通过记事本直接打开 .dwg 文件查看图纸的版本,找到文件的首行,通常会包含类似于“AC****”的字样,这一AC代码即为文件格式版本的标识。通过对应AC代码,就可以获取到 .dwg 文件的版本信息:

1
2
3
4
5
6
* AC1015:CAD2000版
* AC1018:CAD2004版
* AC1021:CAD2007版
* AC1024:CAD2010版
* AC1027:CAD2013版
* AC1032:CAD2018版