从网上搜索这个问题的解决方案,基本上都可以追溯到 Kean Walmsley 的两篇博客:

其中前一篇文章说了如何使用代码执行 XCLIP 命令,后者则说明了如何读取 XCLIP 的相关信息。无论是写入还是读取,这两篇文章都会围绕着扩展字典 (Extension Dictionary)来进行操作。不过,在参考这段代码进行实操的时候一个非常容易忽视的问题是,直接从 Model 空间的 BlockReference 读取扩展字典可能会丢失扩展字典信息,尤其是在涉及 EXPLODE 操作的情况下。

首先我们要明确一下块参照块定义的概念。块定义规定了一个块的所有组成信息,块定义作为块记录(BlockTableRecord)被直接插入块表。而块参照则是对块定义的引用。块参照上定义的可能是块插入时的位移、缩放等信息,或者是对动态块的一些动态属性进行设置。

为了准确地提取块中的 CLIP 信息,我们需要去块表中直接查询块定义的数据。

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
void ExtractClipInfo(BlockTableRecord r, Transaction trans)
{
var layoutId = r.LayoutId;
if (layoutId.IsNull)
{
return null;
}
var layout = (Layout)trans.GetObject(layoutId, OpenMode.ForRead);
if (layout.layoutName != null)
{
// 注意具有布局名的记录不是块定义!
return null;
}

var blockName = r.Name;

int index = -1;
foreach (var objId in r)
{
index += 1;
var entity = trans.GetObject(objId, OpenMode.ForRead) as Entity;
if (entity is BlockReference br)
{
if (br.ExtensionDictionary.IsNull)
{
continue;
}
var extDict = trans.GetObject(
br.ExtensionDictionary, OpenMode.ForRead, true, true) as DBDictionary;
if (!extDict.Contains("ACAD_FILTER"))
{
continue;
}
var filterDictId = extDict.GetAt("ACAD_FILTER");
var filterDict = trans.GetObject(filterDictId, OpenMode.ForRead) as DBDictionary;
if (!filterDict.Contains("SPATIAL"))
{
continue;
}
var filterId = filterDict.GetAt("SPATIAL");
var filterObj = trans.GetObject(filterId, OpenMode.ForRead) as SpatialFilter;
if (filterObj == null)
{
continue;
}
// filterObj 就是当前块 br 的 SpatialFilter 的信息。
}
}
}

通过上面的代码我们可以得到一个块(块名是上面的 blockName 局部变量) 中各个子块的 CLIP 信息(信息以 SpatialFilter 的形式给出)。