一、问题背景
在 Alias 中,.wire 模型常通过图层控制元素显隐。
当模型导出为 STEP 后,如果在 OCCT 中直接导入,常见问题是:Alias 中已隐藏的元素被重新显示。
目标是:在 OCCT 导入 STEP 时,尽可能保持 Alias 原有隐藏状态,避免错误渲染。
二、STEP 中隐藏语义的来源
Alias 导出的 STEP 一般通过以下实体表达"隐藏图层":
INVISIBILITY((#...))- 这里列出的通常是图层分配实体(layer assignment)的 id。
PRESENTATION_LAYER_ASSIGNMENT('id', 'layerName', (#item1,#item2,...))- 把几何/表示项分配到具体图层。
- 如果该图层在
INVISIBILITY中,则其 item 应视为隐藏。
换句话说:
先找"哪些图层隐藏",再找"这些图层下有哪些 item"。
三、为什么 OCCT 直接导入后还会显示隐藏元素
即使启用 SetLayerMode(true),仍可能出现隐藏元素可见,主要原因:
- 图层信息并不总是自动转为"最终渲染剔除"。
- OCCT 在 transfer 时可能把多个 item 合并为 compound。
- 某些场景下不能只靠 label 过滤,需要同时处理 shape 子项。
IdentLabel(ent)在部分路径下不稳定,需要名称映射兜底。
四、推荐实现方案
1)数据结构先定好(建议)
建议在导入流程里维护以下结构:
invisibleItemIds: set<int>- STEP 实体 id 级别的"应隐藏"集合。
invisibleNames: set<string>- 由
invisibleItemIds反查得到的名称集合,作为兜底。
- 由
invisibleLabels: TDF_LabelMap- XCAF label 级别隐藏集合(O(1) 查询)。
invisibleShapes: TopTools_MapOfShape- shape 级别隐藏集合(覆盖 compound 子项)。
nameToId: map<string, int>- 名称到 STEP id 的映射,用于
IdentLabel失效场景。
- 名称到 STEP id 的映射,用于
representationItemListCache: map<int, vector<int>>- 缓存
SHAPE_REPRESENTATION/GEOMETRIC_SET的 item 列表,避免重复解析。
- 缓存
2)文本解析阶段(导入前)
按以下顺序解析 STEP 文本(只构造一次 stepText):
INVISIBILITY -> invisibleLayerIdsPRESENTATION_LAYER_ASSIGNMENT -> invisibleItemIds- 扩展引用(可选但推荐)
- 例如
SHELL_BASED_SURFACE_MODEL('x',(#openShellId)),把openShellId也加入隐藏集合。
- 例如
- 反查名称
- 根据
invisibleItemIds解析出invisibleNames。
- 根据
- 快速路径
- 若
invisibleItemIds为空,直接关闭后续隐藏逻辑。
- 若
实务建议:列表解析时注意
",(#"的游标偏移,漏首项会导致关键元素无法隐藏。
3)transfer 阶段(OCCT -> XCAF)
遍历 model->NbEntities(),按实体处理:
- 先补全 id(兜底)
- 若
IdentLabel(ent) == 0且实体有名称,则用nameToId回填。
- 若
- 取 transfer 结果
- 通过
Transfer_TransientProcess找 binder,拿ShapeResult。
- 通过
- 判定该实体是否隐藏
isInvisibleById:stepEntityNumber in invisibleItemIdsisInvisibleByName:reprName in invisibleNames
- 命中隐藏则写入两层索引
invisibleLabels.Add(label)(如果能搜索到 label)TopExp::MapShapes(shape, invisibleShapes)(shape + 子形状)
- 处理 compound 聚合场景
- 对
COMPOUND/COMPSOLID,根据stepEntityNumber解析 item 列表。 - 将"列表中命中隐藏 id 的子项 shape"写入
invisibleShapes。 - 该步骤用于解决"上层 representation 合并 transfer,子项丢失独立 label"的问题。
- 对
4)构树/渲染前统一过滤(必须双层)
建议统一使用两个判定函数:
isLabelInvisible(label)- 先按名称判定(
invisibleNames) - 再按
invisibleLabels.Contains(label)判定
- 先按名称判定(
isShapeInvisible(shape)- 先按
invisibleShapes.Contains(shape)判定 - 再按名称 / label 做补充判定(按你项目需要)
- 先按
在 parseRootLabelToNode -> parseLabelToNode -> parseShape 全链路都调用,确保:
- 根节点过滤生效
- 子节点过滤生效
- compound 子形状过滤生效
5)伪代码(可直接对照实现)
latex
read stepText
read occt model + transfer
invisibleItemIds = parseInvisibilityAndLayerAssignments(stepText)
if invisibleItemIds is empty:
return buildNodeTreeWithoutVisibilityFilter()
expandInvisibleItemIdsByReferences(stepText, invisibleItemIds)
invisibleNames = parseInvisibleNames(stepText, invisibleItemIds)
nameToId = parseNameToId(stepText)
for each entity in model:
ensure IdentLabel by nameToId if needed
shape = transferResult(entity)
if no shape: continue
hiddenById = entityId in invisibleItemIds
hiddenByName = entityName in invisibleNames
if hiddenById or hiddenByName:
add label to invisibleLabels
add shape + subshapes to invisibleShapes
if shape is compound:
itemList = getOrCacheRepresentationItemList(entityId)
map hidden item index -> compound child shape
add mapped child shape to invisibleShapes
return buildNodeTreeWithFilters(invisibleLabels, invisibleNames, invisibleShapes)
五、性能优化建议(强烈推荐)
1)无 INVISIBILITY 快速路径
如果文件中没有 INVISIBILITY,直接跳过隐藏逻辑(引用扩展、隐藏集合构建、过滤判定等),减少不必要开销。
2)STEP 文本只构建一次
避免在多个解析函数里重复 vector<uint8_t> -> string 拷贝。
3)使用哈希容器做 O(1) 查找
- Label 集合:
TDF_LabelMap - Shape 集合:
TopTools_MapOfShape
替换线性遍历结构,降低大模型导入成本。
4)缓存 representation item 列表
缓存 entityId -> itemList,避免同一实体反复解析文本。
六、常见坑位(实战高频)
- 解析
",(#"时偏移错误,导致漏掉列表首项(极易漏判隐藏)。 - 只过滤根 label,不过滤 compound 子形状。
- 只按 id 过滤,不做 name 兜底。
- 每次判断都做全量扫描,导致大文件导入变慢明显。
七、验收建议
建议准备 2 组测试:
- 有隐藏图层的 STEP
- 抽查若干已知隐藏元素(例如
cyl_body#82、rail_surf#161)是否确实不渲染。
- 抽查若干已知隐藏元素(例如
- 无隐藏图层的 STEP
- 验证快速路径是否生效,导入耗时是否明显下降。
八、结论
要在 OCCT 中保持 Alias 隐藏状态,关键不是单点配置,而是完整链路:
- 正确解析 STEP 隐藏语义(图层 + item);
- 在 transfer 与渲染构树阶段双重过滤;
- 用名称兜底提高稳定性;
- 用快速路径和哈希容器保障性能。
这样可以在复杂 Alias 模型导入时同时做到:
- 隐藏结果正确
- 大模型性能可控