本文管什么:M-List 影像版新增与扩展的全部字段,逐字段标 owner / consumer / 必填性。
不管什么:两个接口签名(GeometryService/MetusAPI)与跨方失败码映射表——那是另外两份文档。
| 结构 | 位置 | owner | 本文 |
|---|---|---|---|
$type / VersionId / SchemaVersion / GeneratedAt |
每个实例顶层 | 各产出方 / Frontier | 3.1 |
BasedOn[] 本次融合基于哪些上游实例 |
融合实例顶层 | Frontier | 3.1 |
Info |
每个实例 | Frontier / M.AI | 3.2 |
Features[] 影像扩展 |
每个实例 | Frontier / M.AI | 4.1–4.3 |
跨源对齐锚点 Datums[].GDTLabel |
图纸基准标签,两侧同名 | M.AI / ORCA | 2.2 |
失败态 Status / FailureCode |
只在 GDTs[] |
Frontier 落盘 / 四方判定 | 4.6 |
VisionHits[] 抓边段落 |
挂 Feature 下 | Frontier | 五 |
| 机台与抓边参数(倍率 / 取点 / 密度 / 出图 / 人工定位) | 只在段级 | Frontier | 4.3 段自足原则 |
VisionProbes[] 相机与机台能力 |
每个实例(上游实例为 []) |
Metus | 六 |
VisionAlignments[] 影像建系 |
每个实例 | Frontier / ORCA | 七 |
| 校验规则 23 条 | — | — | 9.2 |
| 覆盖率口径 | — | — | 9.3 |
三条最容易踩的约定
{} [] "" = 本来源确实没有 | null = 占位待填(9.1)Metus 只读 Externals[] 里 …FromFrontierVision 的最新实例,上游实例是存档、不校验(2.1 / 9.2)影像版 = 不新增任何顶层 key,我方内容全部作为 Externals[] 的实例存在,靠原生 $type 判别。
Externals 本来就是「一个元素对应一个来源」的 list,我方沿用这个机制加三类实例:
$type(末段) |
谁写 | 装什么 |
|---|---|---|
ExternalMeasurementListFromMAI |
M.AI | DXF / STEP 解析结果 |
ExternalMeasurementListFromOrcaAI |
ORCA | MSOP 解析结果 + Internal 里 PRG 内容的副本(补上影像字段) |
ExternalMeasurementListFromFrontierVision |
Frontier | 融合结果 + 影像参数 + 失败态 |
$type值目前是占位,实际开发时按 Hexagon 侧的类型注册结果调整(命名空间与程序集待定)。
一个实例 = 一个来源的一个版本。 同来源多版本就是 Externals[] 里多个同 $type 的实例,
按 GeneratedAt 追加、只增不删、不设上限;
某个 $type 里 GeneratedAt 最大的那个实例 = 当前生效版本。
Metus 只读 …FromFrontierVision 的最新实例。历史实例原样留存,用于改版增量重算与回溯。分工见 2.1。
为什么版本不做成实例内部的
Versions[]:原生实例本身就直接挂GDTs/Features,
它是数据集不是版本容器;套一层会导致顶层数组要么空着、要么与历史重复。
而Externals本来就是 list,多加元素完全合乎原生语义。
| 定位 | 说明 |
|---|---|
| 同构 + 加字段 | 三类实例的 Features / GDTs / Datums 沿用 Externals 的 schema,字段名、层级、枚举照抄,只在末尾追加影像字段。不新增中间格式 |
Internal / Construct 只读;内容复制进 ORCA 实例 |
PC-DMIS 程序(.PRG)转成 M-List 的结果放在 Internal / Construct 里,由 Metrology.AI 产出(见 2.1 术语框)。我方不解析 PRG、也不改这两个容器;ORCA 把其中内容复制进自己的 Externals 实例,在副本上补影像字段——原生容器不能加字段,副本可以 |
| 单一写入方 | M.AI 与 ORCA 只返回数据,由 Frontier 唯一写入 Externals[](含把两个上游的原始返回追加成实例)。两个上游是无状态服务,不互相调用、不感知 Metus。Metus 不持有也不写 |
命名约定:影像相关的新增结构一律 Vision 前缀——VisionProbes ·
VisionAlignments · VisionHits · VisionProbeId · VisionAlignmentId。
顶层不再有 VisionExternals_*(已并入 Externals[])。
{
"Unit": "CU_MM", "GDTStandard": "ASME_Y14_5",
"Internal": {...}, "Construct": {...}, // ★ Metrology.AI 的 PRG 转换结果,我方【只读】
"Externals": [ // ★ 我方全部内容都在这里,按 GeneratedAt 追加
{ ...MAI-001 }, // $type = …FromMAI
{ ...FRT-001 }, // $type = …FromFrontierVision
{ ...ORCA-001 }, // $type = …FromOrcaAI(MSOP + PRG 副本)
{ ...MAI-002 }, // M.AI 的第二版(DXF 改版)
{ // ★ …FromFrontierVision 的最新实例 = 当前生效,Metus 只读它
"$type": "….ExternalMeasurementListFromFrontierVision, …", // 【原生机制】来源判别
"VersionId": "FRT-002", // 【新增】本版本唯一标识(全局唯一)
"SchemaVersion": "0.6", // 【新增】本版本遵循的 schema 版本
"GeneratedAt": "...", // 【新增】产出时间,同容器内严格升序
"BasedOn": ["MAI-002", "ORCA-001"], // 【新增】基于哪些上游实例(VersionId 全局唯一)
"Info": {...}, // 坐标基准 / CAD 比例 / 视图(融合实例 SourceFiles 恒空)
"Features": [...], // 沿用 external schema + 影像扩展字段
"GDTs": [...], // 沿用 + 2 个失败态字段(见 4.6)
"Datums": [...], // 沿用,不改
"Alignments": [...], // 沿用 string[],三容器一律保持空
"VisionAlignments": [...], // 【新增】影像建系动作
"VisionProbes": [...], // 【新增】相机与机台能力
"Probes": [...] // 沿用,保持空
}
]
}
(三类实例的内部结构相同,此处只在最新融合实例上展开。
历史实例是完整快照不是摘要——校验规则对每一个实例都成立。)
术语:本文「实例」与「版本」同义——
Externals[]的一个元素就是某个来源的某一个版本。
Externals 的每个元素对应一个来源,$type 说明是谁。 我方三类实例与原生实例平级共存;
同来源的多个版本就是多个同 $type 的实例。来源文件在各实例的 Info.SourceFiles[] 里登记。
实例 $type(末段) |
内容 | 有什么 | 没有什么 |
|---|---|---|---|
…FromMAI |
M.AI 解析 DXF / STEP 的原始返回 | Features + GDTs + Datums 都有——图上的几何、标注与公差、气泡、基准符号,以及 CadIDs / CadScale / ViewId |
全部影像参数 · 测量策略 |
…FromOrcaAI |
ORCA 的原始返回:一个 MSOP 的解析结果 + Internal 里 PRG 内容的副本 |
Features + GDTs + Datums + VisionAlignments 都有——PRG 侧的显式元素与完整几何、MSOP 侧命名反推的元素、评价语句与公差、工程师验证过的策略(Probe / 扎点)、坐标系与建系步骤原文 |
全部影像参数 · CadIDs(见下) |
…FromFrontierVision |
融合结果 | 全部,含影像参数与失败态 | — |
Internal / Construct(原生容器,只读) |
Metrology.AI 把 PRG 转成 M-List 的结果 |
Features + GDTs + Datums + Alignments——显式元素定义、完整公称几何、取点策略、6 数扎点 |
建系动作(原生 Alignments 是 string[],只有名字)· 全部影像参数 |
PRG 内容为什么要复制一份到 ORCA 实例
Internal / Construct 是原生容器,我方不能往里加字段。而 PRG 解析出来的元素需要补上
影像相关字段才能参与融合(VisionAlignments 等 Vision 前缀结构在原生容器里不存在)。
所以 ORCA 把 Internal 的内容复制进自己的实例,在副本上补——原件保持原生、干净。
Internal 原件 |
ORCA 实例里的副本 | |
|---|---|---|
| 字段集 | 原生 27 字段(ClearancePlane / Colors / AngleVector …) |
本文的 Externals 格式,与 …FromMAI 实例同构 |
ID |
数值哈希("16398924430394702697") |
原生元素名(CIR1 / LIN1),Name 同值 |
CadIDs |
PC-DMIS CAD 模型 ID | 置空——它与 …FromMAI 的 DXF handle 是两个 ID 空间,混在同一字段里会误导 |
Vision* 结构 |
没有 | 补上(坐标系名进本实例的 VisionAlignments) |
| 谁写 | Metrology.AI |
ORCA |
来源文件登记:
…FromMAI实例一个Dxf(或Step);
…FromOrcaAI实例 1–2 个(Msop必有,另有 PRG 副本时加一个PcDmis);
融合实例恒为[]——它等于上游并集、是派生值,靠BasedOn一跳追溯(规则 22)。PRG 与 MSOP 不二选一,可以同时在一个 ORCA 实例里,两者互补不冗余:
PRG 给显式元素、完整几何、取点策略与 6 数扎点;MSOP 给建系步骤原文——
原生Alignments只有名字、装不下建系动作(见下表「建系动作」行)。
有 PRG 时几何与策略优先取 PRG;建系仍然只能靠 MSOP 的Description。
⚠ 术语:
Metrology.AI与M.AI是两个不同的东西,不要混。
是谁 在本项目里做什么 产出落在哪 M.AI四方之一( M.AI/ORCA/Frontier/Metus),接口人周胜仁解析 DXF / STEP:几何、标注与公差、气泡、基准符号、 CadIDsExternals[]里…FromMAI实例ORCA四方之一 解析 MSOP(评价项与公差、扎点、建系原文)+ 复制 Internal的 PRG 内容并补影像字段Externals[]里…FromOrcaAI实例Metrology.AI另一个产品/团队,不在四方之列 PRG → M-List 转换(已有成熟能力,我方不重复实现) Internal/Construct我方不解析 PRG,也不写
Internal/Construct——Frontier 只读取。
这样 PRG 路径不占我方排期,且复用已验证的转换器而非从零实装受控文法。
两条输入路径产出能力不同,必须分开对待
PC-DMIS 程序(.PRG)Metrology.AI 转换 → Internal,ORCA 复制进自己实例 |
MSOP(PDF) ORCA 直接解析 |
|
|---|---|---|
| 元素定义 | 显式:Internal.Features[] 里就是 CIR1 / LIN1,类型确定、ID 是工程师起的原生元素名 |
没有。只有点与向量两种条目 |
| 几何参数 | 有:公称 Center / Radius / StartPoint 等 |
完全没有。字段只到 X/Y/Z/I/J/K |
| 元素类型 | 显式声明 | 只能从命名约定反推:FAI7_CIR1_PNT3 表示「为拟合 FAI 第 7 项的圆 1 而扎的第 3 点」 |
| 法向 | 元素自带 | 表组级的向量行 → 落 Feature.Normal,不下发到点级 |
| 建系动作 | 原生容器装不下——Internal.Alignments 是 string[],只有坐标系名,没有 level / rotate / zero / offset。只能从 Features[].Alignment 看出「这个元素在哪个系下测」 |
受控文法的自然语言(Use X to set as Y axis zero / YPLUS rotate to X around ZPLUS),实测 118/118 条全有、平均 148 字符。尽力提取结构化字段,原文一律留在 Description 里 |
| 父系链 | 拿不到(原生容器无父系字段) | Measured System 字段就是父系(实测链:START_UP → ALI_MAN → ALI_ITER → ALI_DAT_A → ALI_ABC → 各局部系),但须先归一化(规则 21) |
| 扎点 | 有,每条「坐标 + 矢量」(原生容器的 Hits[]) |
有,这是它的主要内容——但 90.3% 的点只有坐标,方向多数是单独一行挂在表组上(227/251 组),另有 6 组完全没有方向 |
| 取点策略 | 有,原生容器的 MeasurementMethod 里 |
只有 Hits / Depth / Pitch——Depth / Pitch 在 schema 里无处安放,点数又是 Hits[] 长度的派生值,所以 MeasurementMethod 置空 {},与 …FromMAI 实例一致 |
| 归影像的项 | — | Method 字段已标明(VISION / Master_P5/VISION 等),是筛选影像项的现成输入 |
由此两条约定:
null,此时几何须由 Hits[] 拟合。Radius == null 且 Hits[] 非空 = 「MSOP 只给了点,半径要算」,不是解析失败FeatureType 由命名反推,可信度低于 PC-DMIS 的显式声明。Point 落地,由 Frontier 在融合时决定是否标 Ambiguous
…FromOrcaAI实例要产出Features,这是对现有输出的扩展。 实测原生 ORCA 只出GDTs+Datums、
Features为空(它解析图纸,图纸里没有元素定义)。本方案要求它解析 MSOP 时
同时产出源文件里定义的元素(靠命名反推)。排期与接口签名按扩展算,不能按现状算。这块扩展只覆盖 MSOP 一条路径:PRG 的元素提取由
Metrology.AI的转换器承担、
结果直接落在Internal/Construct,不占 ORCA 排期,也不占我方排期。
Internal / Construct 的 Info 是原生类型,不要往里塞我方字段
实测(04_参考资料/PCDIMS/HexMI_DemoBlock_Small4.orca):
| 容器 | Info.$type |
字段 |
|---|---|---|
Internal |
InternalMeasurementListInfo |
CadFileName · CadFileType(如 CAD_FILE_FORMAT_PCDMIS)· CadInfo(单位与零件名的文本块)· CadBoundingBoxMin / CadBoundingBoxMax · DisplayName |
Construct |
ConstructMeasurementListInfo |
CadFileName · CadInfo · DisplayName;另有一个 ConstructInfo 字段,内容与 Info 重复 |
Externals[] |
元素级 $type = ExternalMeasurementListFromOrcaAI,Info.$type = ExternalMeasurementListInfo |
TargetCadFileName · TargetCadInfo · FileName(被解析的文件)· DisplayName;元素上还有 OrcaTaskId 与 ExternalPmiFileType(int 枚举) |
这里没有 SourceFiles——那是本文给 Externals[] 实例定义的字段(3.2),
不得写进原生容器。PRG 用了哪一版,记在融合实例的 Info.SourceFiles 里(规则 22)。
⚠
$type是原生格式的一部分,实测全文 104 处、11 种类型——Externals[]的元素本身
就带$type(实测ExternalMeasurementListFromOrcaAI)。我方三类实例正是复用这个机制,
不新增顶层 key,因此不再存在「新增容器会不会被反序列化拒收」的风险。
剩下要确认的只是新$type值的命名空间与程序集(周胜仁 / 陈皇星,见 README 7.5)。
Frontier 能从 Internal / Construct 读到什么
原生字段由 Hexagon 定义、本文不复述全表(骨架里给了真实形状可照抄),按用途分四组:
| 组 | 字段 | 融合时用来做什么 |
|---|---|---|
| 几何 | FeatureType · Center · Normal · Radius · IsInside · StartPoint / EndPoint · Length · StartAngle / EndAngle · TopCenter / BottomCenter · Boundaries · AngleVector |
公称几何的首选来源(比 DXF 的 2D 投影完整,见「融合时谁的字段说话」) |
| 测量策略 | Hits[](6 数:坐标 + 矢量)· Probe · Alignment · PrehitDistance / RetractDistance · ClearancePlane · FeatureHitsGenerationStrategy |
推影像取点策略的依据——工程师验证过的扎几点、扎哪里、在哪个系下测 |
| 对齐锚点 | Datums[].GDTLabel · CadIDs(int[]) |
跨源对齐(2.2)。Alignments 是 string[],只有坐标系名、没有建系动作 |
| 评价项 | GDTs[](含多态 MeasurementMethod)· Probes[](原生测头定义:HeadType / FilePathName / Styluses / Tips / 转台角度范围) |
公差与取点策略;Probes 是接触式测头,影像侧不用(相机走 VisionProbes) |
只读、只取值、不建引用(见 2.2)。原生字段不进我方必填校验——
它由Metrology.AI保证,我方读不到就按 4.6 报FRT-码。
四条硬约定
| # | 约定 |
|---|---|
| 1 | …FromFrontierVision 的最新实例是唯一权威。Metus 只读它,不读历史实例、也不需要知道其他 $type 的实例 |
| 2 | 上游两类实例原样存档、不做 schema 校验。 校验规则 1–16 只约束融合实例,见 9.2 |
| 3 | 只有 Frontier 写文件。 M.AI / ORCA 只返回数据,由 Frontier 追加进各自容器 |
| 4 | 影像参数只出现在融合实例。 倍率、ROI、光照、对焦由 Frontier 算,上游实例里这些字段缺失即可 |
| 5 | 历史实例是完整快照不是摘要。 每个实例当时都是生效版本,校验规则对每一个实例都成立——不允许为了省体积写成残缺的实例 |
融合时谁的字段说话
| 内容 | 取自 | 冲突时 |
|---|---|---|
形状参数(FeatureType / Radius / Boundaries / IsInside) |
MAI(它有完整几何) |
— |
坐标值(Center / Normal / StartPoint / EndPoint) |
按 CoordinateBasis 优先级取:Model3D > Msop3D > Cad2D |
有 PRG 时取 Internal 里的 3D 公称坐标,DXF 只提供 2D 投影 |
上游实例几何参数为 null 时 |
由该实例的 Hits[] 拟合 |
MSOP 路径的常态——它只给扎点不给圆心半径(见上表)。拟合结果写进融合实例,上游实例保持 null 不回填(原始存档不加工) |
评价项与公差(GDTs / Datums) |
ORCA |
— |
| 影像参数(倍率 / ROI / 光照 / 对焦 / 抓边) | Frontier 算 |
— |
| 跨源冲突(PRG 说这里有孔、DXF 说没有) | — | 融合实例该 GDT 标 InputInvalid + FRT- 码,见 4.6 |
改版增量重算的入口:某一路输入改版后,在对应容器里追加一个新版本(不覆盖旧的),
与该容器的上一版逐字段 diff,得出哪些 Feature 的上游输入变了,写入 UpstreamChangedAt
驱动三态判定;随后追加一个新的融合版本,其 BasedOn 指向新的上游版本。
这样做的收益:改版不需要重新解析历史源文件。 顺着
BasedOn就能取到当时用的上游版本,
两版逐字段比对即可定位受影响项。骨架里 DXF 从V4改到V5,
MAI_F001.Radius由4.9变5.0,于是融合实例FRT-002的CR_001.UpstreamChangedAt
填的就是MAI-002的ParsedAt——这个值是算出来的,不是重新解析 DXF 得来的。
各实例内部自洽,各用自己源文件的标识做内部关联。
LinkedCadFeatures / Datums[].LinkedCadFeatures 一律指向本实例的 Features[].ID,不跨份引用(规则 18)。
ORCA 从不读 DXF,不可能产出 DXF 侧标识;让它引用 M.AI 的 ID 就等于要求它先知道
M.AI 的解析结果,破坏「两个上游互不调用、互不感知」。实测:原生文件里根本没有跨容器引用。 真实
.orca(04_参考资料/PCDIMS/HexMI_DemoBlock_Small4.orca)
的Externals[0].GDTs[].LinkedCadFeatures与LinkedCadIDs100/100 全为[],
Datums[].LinkedCadFeatures11/11 也全为[]。「要求→特征」这条链在原生输出里是断的——
ORCA 只给评价项与公差,不负责把它挂到几何上,挂接是融合方的活。我方三个 Vision 容器一律不引用
Internal/Construct。
它由Metrology.AI产出、ID 空间是 PRG 的原生元素名,自身内部自洽由它保证;
我方引用进去就把自己的 ID 空间耦合到了另一个团队的产出上。
Frontier 读它是取值(几何、策略、扎点),不是建引用。
哪些标识从文件读,哪些是内部命名
| 份 | 标识 | 来源 |
|---|---|---|
MAI |
CadIDs |
从文件读:CAD 实体句柄。类型是 int[] 不是 string[]——实测 Internal.Features[].CadIDs 是 [1099511628148, …] 这类 int64。DXF 的十六进制 handle(如 2F3A)须转成整数存(2F3A → 12090)。⚠ 需 M.AI 确认转换口径 |
MAI |
Bubbles · 标注文本 · ViewId / ViewName |
从文件读 |
MAI |
Features[].ID(如 MAI_F001) |
M.AI 内部命名。 DXF 只有几何实体、没有「测量特征」这一层;且一个特征可能由多个实体拼成(圆弧组成的槽),所以只能内部命名,组成它的全部 handle 记在 CadIDs |
MAI |
CharacteristicID(如 MAI_C001) |
M.AI 内部命名(图纸上一般没有 FAI 编号) |
ORCA |
Features[].ID(如 FAI7_CIR1) |
从 MSOP 命名反推:FAI7_CIR1_PNT3 = 「为拟合 FAI 第 7 项的圆 1 而扎的第 3 点」。不是原生元素名——MSOP 里没有元素定义 |
ORCA |
CharacteristicID(如 FAI7) |
从文件读:MSOP 的 FAI 号 |
ORCA |
VisionAlignments[].ID |
从文件读:MSOP 里的坐标系名(须先归一化,规则 21) |
ORCA |
Probe / Alignment(Feature 级)· GDTs[].MeasurementMethod |
从文件读:工程师验证过的策略,原样留存供融合参考。MSOP 路径下 MeasurementMethod 置 {}(见 4.1) |
ORCA |
CadIDs |
恒为空——它读不到 DXF |
Internal / Construct |
Features[].ID 是数值哈希字符串(实测 "16398924430394702697");Name 才是原生元素名(CIR1);CharacteristicID 如 DIM_DIA1 |
从 PRG 读(Metrology.AI 转换):工程师起的、已跑通验证过。Frontier 只读不改。⚠ 程序元素的 ID 究竟是哈希还是元素名,待 PRG 样本确认——本样本的 CAD 几何用的是哈希 |
Frontier |
Features[].ID · CharacteristicID · VisionAlignments[].ID |
融合时新分配 |
跨源对齐靠图纸基准标签,不靠逐条 ID 配对
不设 SourceRefs。 各路来源独立编号——MAI 的 MAI_F001 是内部命名、
ORCA 的 FAI7_CIR1 是 MSOP 命名反推、Internal 里是 PRG 原生元素名 CIR1——
要求 Frontier 逐条给出「这个圆 = 那个圆」的配对表在工程上做不出来,
而且配错了不报错,比不做更危险。
改为两级对齐,锚点是图纸基准标签 Datums[].GDTLabel(A / B / C):
| 级 | 靠什么对齐 | 为什么可靠 |
|---|---|---|
| ① 基准级 | Datums[].GDTLabel 精确匹配(A ↔ A) |
基准标签是图纸语言,不是任何一方的内部编号。M.AI 从图纸基准符号读、MSOP 从基准建系读,两侧必然同名。一个零件通常只有 2–4 个,人工核对成本极低,且规则 9 已在挡它的 OCR 噪声 |
| ② 元素级 | 归一到基准系后按坐标 + FeatureType 就近匹配 |
基准系一旦对齐,两侧坐标就可比(Info.CoordinateBasis 定坐标基准,VisionAlignments 定变换链) |
匹配不上不猜。 就近匹配不唯一、或某一侧找不到对应物 → 该 GDT 标 Ambiguous + FRT- 码
进人工清单(硬规则②「不降级输出」)。
为什么锚点不用气泡号 / FAI 号。 看着像天然主键,实际两侧都立不住:
M.AI 侧的CharacteristicID是内部命名(图纸上一般没有 FAI 编号,见上表);
DisplayBubble实测 100 条只 6 条非空、其中 5 条还是 OCR 噪声CF。
拿它当唯一锚点等于没有锚点。 基准标签是少而准,气泡号是多而脏——要少而准的那个。
基准锚点天然支持多来源,这是它比 ID 配对强的地方。 现在同时有三路输入
(DXF / MSOP / PRG),若走两两 ID 配对要维护 3 对映射,加一路就变 6 对;
而基准标签是「星型」——每一方各自挂到同一组图纸基准上,加一路只多一条挂接。
王敬夫说的「各个功能关联一个基准最好」就是这个意思。
代价要写明。 没有
SourceRefs,就没有「这条自动生成项能溯回哪个上游条目」的逐条机器校验。
替代护栏是规则 19 改判基准一致性:融合实例不得凭空造出上游没有的基准。
基准是整条坐标链的根,基准错了下游全歪,护栏放这一层性价比最高。
| 字段 | 类型 | 必填 | owner | 说明 |
|---|---|---|---|---|
$type |
string | ✔ | 各产出方 | 原生来源判别机制,取三个值之一(见 2.1)。不另设 Source 字段 |
VersionId |
string | ✔ | Frontier | 本实例唯一标识,建议 MAI-001 / ORCA-001 / FRT-001 递增。全文件唯一(规则 17),是 BasedOn 的引用目标 |
SchemaVersion / GeneratedAt |
string / datetime | ✔ | Frontier | 本版本遵循的 schema 版本(上游接口改版后历史存档靠它迁移)· 本实例产出时间(改版 diff 的基准,同 $type 内严格升序) |
BasedOn[] |
string[] | ✔ | Frontier | 本次融合基于哪些上游实例,直接放 VersionId(全局唯一,查到实例即可从 $type 读出是谁,不必再存一遍来源)。上游实例恒为 [];融合实例必须非空、每项命中真实实例、且被引实例的 GeneratedAt 必须早于本实例(规则 23) |
不存
Source,也不存IsAuthoritative。 前者就是原生$type,后者由「是否本$type里
GeneratedAt最大的实例」派生。派生值一律不单独存,否则两处会不一致。
BasedOn 让改版不必重新解析历史源文件——顺着它就能取到当时用的上游版本做逐字段 diff。
Info —— 本实例的来源与坐标基准
| 字段 | 类型 | 必填 | owner | 说明 |
|---|---|---|---|---|
SourceFiles[] |
object[] | ✔ | Frontier | 输入文件登记。每项:Type(Dxf/PcDmis/Msop/Step)· Path · Revision(该输入文件自己的版本,如 DXF V5 / PC-DMIS R3) · ParsedAt。…FromMAI 恰好 1 个 Dxf/Step;…FromOrcaAI 为 1–2 个(Msop 必有,有 PRG 副本时加一个 PcDmis);融合实例恒为 []——它等于上游并集、是派生值,靠 BasedOn 一跳追溯(规则 22) |
CoordinateBasis |
enum | ✔ | Frontier | Model3D / Msop3D / Cad2D。有 3D 模型取 Model3D,有 MSOP 取 Msop3D,只有 DXF 取 Cad2D |
CadScale |
number | ✔ | M.AI | 图纸比例系数。1:1 → 1.0,1:2 → 2.0。DXF 解析时识别比例尺并自动缩放到 1:1,此处记录原始比例供追溯。每个实例唯一一处——Feature 与段级都不带 |
IsScaledToOneToOne |
bool | ✔ | M.AI | 几何坐标是否已缩放。为 false 时下游一律不得直接使用坐标 |
ViewId / ViewName |
string | ✔ | M.AI | 当前视图标识。本期只处理单视图,多视图关联后续支持。…FromOrcaAI 实例为 ""(它读不到图纸视图) |
PartMatchFeatureId |
string | ✔ | Frontier | 指向 FeatureType == PartMatch 的那条 Feature,整条坐标链的根。上游实例为 ""(它们不产出 PartMatch) |
ProgramRevision |
int | nullable | Frontier | 我方生成的这份测量程序是第几版,改版增量重生成的 diff 基准与对客口径(「你现在跑的是第 3 版」)。只在融合实例有意义,上游实例恒为 null(它们不产出程序;int 无空值可表达,故用 null)。注意与 SourceFiles[].Revision 区分:后者是输入文件各自的版本,可以有多个;本字段是输出的版本,只有一个 |
视图局部坐标约定
CoordinateBasis == "Cad2D" 时,所有几何坐标是该视图的局部坐标,跨视图不可比
(CAD 图没有统一原点,不同视图坐标差异极大,一律以视图坐标为准)。三条硬约束:
ViewId 只放在 Info 上、Feature 不带,本期由结构保证。Feature 上加 ViewId,否则规则 14 不可机器校验Cad2D 下不得跨视图建 VisionAlignments——两个视图的元素之间没有可用的空间关系Model3D > Msop3D > Cad2D(前两者有统一原点、跨视图可比)比例系数只存 Info.CadScale 一处。 一个实例只装一个视图(见上),
一个视图只有一个比例尺,所以 Feature 级与段级的副本是可推导的冗余,不设。
多视图上线时比例尺随 ViewId 一起下移到 Feature 级。
Feature 的影像扩展公共字段全部沿用:ID Name FeatureType Center Normal Boundaries CadIDs Colors
DependentFeatures StartPoint EndPoint StartPointNormal EndPointNormal AngleVector
IsReferencePoint ReferencePointIDs;按类型带的:Radius Length IsInside
StartAngle EndAngle,Cylinder 加 TopCenter BottomCenter,Cone 加 SmallCenter
LargeCenter SmallRadius LargeRadius HalfAngle,Sphere 加 StartAngle2 EndAngle2。
Boundaries实测是每 3 个数一组的纯 3D 点、无法向,环首尾点相同表示闭合
(规范标它为VectorPoint3Array但与实现不符,见第五节Hits[]一段)。
沿用字段按需出现,不做必填校验。 「沿用」的含义是不改其名称、层级与语义,
不是「每条都必须写出来」。9.1① 的「字段缺失 = 拒收」只管本文标 ✔ 或
required-but-nullable的字段(即影像新增字段与Info各项)。原因是原生 schema 的字段本身就按类型分化,强制全带只能塞一堆恒空值:
层 按什么分化 例 FeatureFeatureTypeCircle带Radius/IsInside,Line带StartPoint/EndPoint,Point两者都不带GDTsGDTTypeDimension带DimensionValue/PlusToleranceValue/MinusToleranceValue,Tolerance不带(它的公差在Specifications[]里)所以
Colors/DependentFeatures/StartPointNormal/EndPointNormal/AngleVector/
IsReferencePoint/ReferencePointIDs这些用到才写,骨架里不出现不算违规。
接触式执行字段:融合实例恒为空,上游实例原样留存。
| 字段 | 融合实例 | …FromOrcaAI 实例 |
|---|---|---|
Hits[] |
[](影像不扎点) |
原样留存,长度按源文件实际有的来:只给坐标就 [x, y, z],给了点级方向才 6 个数。见下 |
Probe / Alignment |
"" / "" |
原样留存:测头(实测 MASTER_P5 / TSTAR_15MM_X TIP2 / VISION)· 坐标系名(须指向本实例 VisionAlignments[].ID) |
PrehitDistance / RetractDistance / ClearancePlane / FeatureHitsGenerationStrategy |
null 或不带 |
原样留存,源文件没有就不带 |
上游实例留住这些是因为它们是推影像取点策略的依据——工程师验证过的扎几点、扎哪里、
用哪个坐标系,直接决定影像侧抓几段;声明成恒空等于把 ORCA 份最有价值的内容扔掉。
Hits[]原则:源文件有什么就写什么,不补齐、不推导。
来源 每条几个数 MSOP 3( [x, y, z])——实测点位 1763/1953 条(90.3%)只有 XYZMSOP(少数自带点级方向的 190 条) 6 PC-DMIS 程序(在 Internal/Construct,只读)6—— HIT语句本身是「坐标 + 矢量」表组级方向不下发到点级(实测 227/251 组的方向是单独一行挂在表组上)——复制到每个点是加工不是原始数据。
它的落点是Feature.Normal:那本来就是「特征朝哪个方向」,且是Unreachable的判据(见 4.5)。
Hits[]的形状是我方约定,规范里没有,以联调实测为准。
不要照Boundaries反推——规范标它为VectorPoint3Array(每点 6 数),
实测环长 15/21/51/99/123/195/285 一个都不能被 6 整除,按 3 分组则 2634 点零越界,
它实际是每 3 数一组的纯 3D 点。规范的类型标注不可作为实现依据。
MeasurementMethod是GDTs[]层的字段,不在Feature层。
实测Internal.Features21/21 没有这个字段,而Externals[0].GDTs100/100 都有。
语义上也应如此——「这个评价项取几点」是评价项的属性,不是几何的属性。它是按评价类型分化的多态对象,带
$type,实测 7 种(DiameterMeasurementMethod_Default/
DistanceMeasurementMethod_Default/SurfaceProfileMeasurementMethod_Default/ … /
通用MeasurementMethod_Default)。共有字段 4 个不是 2 个:
ConvertHitsToPoints·MaxNumberOfPoints·MaxNumberOfPointsVisibility·VerifiedErrorIgnoredByUser
(实测全为默认值,不承载真实策略)。按来源填:PRG 侧(
Internal/Construct)由Metrology.AI写、Frontier 只读;
_ORCA(MSOP)与_MAI(DXF)一律置空{}——MSOP 只给Hits/Depth/Pitch,
其中Depth/Pitch无处安放、点数又是Hits[]长度的派生值;图纸则不含取点策略。
不填我方拿不到的东西:空对象表示「此来源无策略信息」,比凑一个数诚实。
融合实例必须带$type与 4 个共有字段(骨架已按真实形状给)。
FeatureType 枚举扩展原枚举 11 种:Plane Circle Cylinder Cone Sphere Line Point SlotRound SlotSquare Ellipse ScanFreeform
新增 1 种:PartMatch(focusPoint 本期不进枚举)
PartMatch 的特殊规则 |
|
|---|---|
| 无公称几何 | 它不是被测对象,是一个「找工件」的动作,产出是一个坐标变换 |
| 是坐标链的根 | 它产出的实测系 = VisionAlignments 链的根节点(根节点 ParentIds 为空数组,SourceFeatureId 指向它) |
| GDT 不得指向它 | GDTs[].LinkedCadFeatures 不允许包含 FeatureType == PartMatch 的 ID(规则 1,违反即拒收) |
| 每个实例唯一 | 每个融合实例里有且只有一条,ID 记在 Info.PartMatchFeatureId(规则 2 按实例校验) |
| 字段 | 类型 | 必填 | owner | consumer | 说明 |
|---|---|---|---|---|---|
VisionHits[] |
object[] | ✔ | Frontier | Metus | 与 Hits[] 并排。抓边段落,见第五节。PartMatch 的 VisionHits 装工件识别用的模板特征 |
VisionProbeId |
string | ✔ | Frontier | Metus | 用哪台相机,指向 VisionProbes[].ID(对应接触式的 Probe) |
VisionAlignmentId |
string | ✔ | Frontier | Metus | 在哪个影像坐标系下测(对应接触式的 Alignment,即元素必填项里的 csId) |
Skip |
bool | ✔ | Frontier | Metus | 是否跳过这个元素。段级不设 Skip——某段不抓就直接不生成那段 |
Owner |
enum | ✔ | Frontier | Frontier | Auto / Manual——这个元素是谁创建的 |
LockedFields |
string[] | ✔ | Frontier | Frontier | 哪些字段被人工改过,空数组表示全自动。改版时这些字段不被覆盖,其余照重算 |
UpstreamChangedAt |
datetime | nullable | Frontier | Frontier | 上游变更时间戳 |
ProducesVisionAlignmentId |
string | ✔ | Frontier | Metus | 仅 PartMatch 用:本 feature 产出哪个坐标系。其余 feature 为 "" |
段自足原则:机台参数与抓边参数一律放段级——Magnification · AcquisitionMode ·
EdgeDensity · OutputImage · NeedsManualPosition 都在 VisionHits[] 上,不在 Feature 上。
判据是「Metus 拿到一条 VisionHit 就能执行,不必回查父级」。
元素级只留身份与归属类字段(见上表);相机与坐标系不下放——一个元素不会中途换相机,也不会跨坐标系测。比例尺不下放——它是整份元素的属性,只在 Info 里。
改版四类标记:Owner(谁创建)· LockedFields(哪些字段被人工改过)·
UpstreamChangedAt(上游变更时间戳)· DependentFeatures(依赖关系,沿用)。
锁定是字段级不是行级——整行锁定会让改版后 ROI 无法重算,留下位置过期的框。
冲突提示取 LockedFields 与本次变化字段的交集,可精确到哪几个字段。
Locked 布尔值可由 Owner == Manual || LockedFields 非空 派生,不单独存。
Feature 层不放 Status / FailureCode——失败态只放 GDTs[] 一层,见 4.6。
| 参数 | 怎么来 |
|---|---|
倍率 Magnification |
Frontier 按 ORCA 返回的公差带宽 + 机台倍率档位 + 视野尺寸逐段反推,结果落到离散档位。禁止取机台当前值 |
抓边方式 EdgeMethod.Mode |
显式设置(决定测哪条边,不能猜) |
打光 Light |
读机台当前状态(接口已存在)或写 null。不做自动推荐 |
对焦 Focus |
同上 |
| 极性 / 匹配规则 / 门限 / 强度 / 平滑 / 亚像素 | 默认值。残留风险见本节 EdgeMethod |
Plane 的处理规则Plane 是合法可执行的,不必强制降维。 影像设备除了朝下的镜头,还有点激光(可直接测面)
与对焦面(多点对焦拟合平面)两条手段。
但本期主路径仍是降维成 Line——边界轮廓抓边是最成熟、精度最可控的做法。
点激光与对焦面本期不建模(不新增 VisionProbes 能力位、不扩 TargetType),
留到二期真要用时再加;现在加了不实现等于留坑。
按这个面被哪种 GDT 引用来分流:
该 Plane 被引用的方式 |
降维成 | 怎么做 | 输出 |
|---|---|---|---|
| 被平面度 / 平行度 / 轮廓度等形状类形位公差引用 | Line × N |
取 Boundaries 的边界环,投影到 XY,切成 N 段直线,每段一个 VisionHit |
N 条 Line feature,各自带 VisionHits |
| 被距离 / 位置等尺寸当 Z 基准引用 | 只当 Z 参考,不生成元素 | 用该面的 Center[2] 作为引用它的那些元素的 Focus.MachineZ |
无 feature,只写进下游元素的 MachineZ |
| 两种都被引用 | 两条都走 | 既建边界线,又供 Z 参考 | N 条 Line + 下游 MachineZ |
| 法向不朝 ±Z(侧立面) | 不降维,直接失败 | 镜头与点激光都朝下,侧立面拍不到也打不到 | Status = Unreachable |
判定依据:先看 Normal 与 Z 轴夹角,|Normal[2]| > 0.9 才算朝 Z、可俯视拍;
再查 GDTs[].LinkedCadFeatures 里引用了这个 Plane.ID 的那些 GDT 的 SubType。
保留
Plane本身不影响上表。 上游实例原样留存Planefeature、融合实例也可以留,
只是本期不给它生成VisionHits——执行落在降维出来的Line上。
二期支持点激光 / 对焦面时,直接给Plane挂VisionHits即可,上表第 1、2 行不必推翻。
GDTs[] 上 2 个字段失败态只放 GDTs[] 一层——覆盖率与人工清单的计量单位就是 GDT。
算不出来的项必须打标输出,不得靠「这一行不输出」表示(那等于静默丢数据)。
| 字段 | 类型 | 必填 | owner | consumer | 说明 |
|---|---|---|---|---|---|
Status |
enum | ✔ | Frontier | UI / 清单 / 评测集 | 6 值,见下。按「处置动作」分,不按「失败原因」分 |
FailureCode |
string | ✔ | Frontier 落盘(判定方见 4.6) | UI / 清单 | Status == "Ok" 时为 ""(不是 null——「没有失败码」是事实不是占位,规则 10),否则 <域>-<序号>:ORCA-013 / MAI-004 / FRT-021 / MTS-007。与跨方失败码映射表同一套 |
Status 的 6 个取值,一一对应处置动作与责任方
| 值 | 什么情形 | 谁来解决 |
|---|---|---|
Ok |
正常生成 | — |
NeedsManual |
粗基准要在影像上确认位置、无清晰对焦平面 | 操作员确认 |
Ambiguous |
气泡归属不唯一、双主键都不可用、基准标签是 OCR 噪声 | 工程师现场选 |
NotSupported |
轮廓度、弧到弧距离、Sphere——能力未覆盖 |
我方研发 |
InputInvalid |
DXF 炸开 / 图层混乱 / GD&T 非标 / STEP 拓扑破损 | 客户改图 |
Unreachable |
超行程、倍率不够、侧立面拍不到 | 换机型或换装夹 |
最后两类必须分开:「这台机做不到」(
Unreachable,换更高配的机器可能行)与
「我们软件不支持」(NotSupported,换机型也不行)是两回事。
partMatch 失败是唯一例外:它是全局失败、不属于任何单个 GDT。
约定 partMatch 失败时所有 GDT 标 Unreachable + 同一个码(规则 13),保持只有一层。
Feature 层失败向上传播:元素建不出来 → 引用它的每条 GDT 标失败,码写「所依赖的特征建不出」。
谁判、谁写、谁维护码表
FailureCode 的 owner 是 Frontier,那说的是「谁写进文件」,不是「谁判定失败」。
| 环节 | 谁 |
|---|---|
| 写进 M-List | Frontier 唯一 |
| 判定失败并产出码 | 四方各判自己那段 |
| 维护码表 | Frontier 牵头汇总,各方对自己前缀段有定义权 |
失败的判定方分布
Status |
典型情形 | 谁发现的 | 码前缀 |
|---|---|---|---|
InputInvalid |
DXF 炸开、图层混乱、STEP 拓扑破损 | M.AI | MAI- |
InputInvalid |
MSOP 版式未命中 | ORCA | ORCA- |
InputInvalid |
Internal / Construct 内容缺失或不合规(PRG 未转换、转换结果不完整) |
Frontier(读取时发现;Metrology.AI 不在四方之列、无对我方的失败通道) |
FRT- ⚠ 见下 |
InputInvalid |
跨源冲突(PRG 说这里有孔、DXF 说没有) | Frontier | FRT- |
Ambiguous |
气泡归属不唯一、基准标签是 OCR 噪声 | M.AI / ORCA | 各自前缀 |
NotSupported |
同心度、轮廓度、Sphere |
Frontier | FRT- |
Unreachable |
超行程、倍率不够、侧立面拍不到 | Frontier 用 VisionProbes 判 |
FRT- |
NeedsManual |
粗基准要在影像上确认位置 | Frontier | FRT- |
| (创建时被拒) | Metus 侧拒收 | Metus | MTS- |
⚠ 待定:
Metrology.AI要不要独立域前缀。 它产出Internal/Construct但不在四方之列,
目前约定「Frontier 读取时发现问题就报FRT-」。代价是分不清「PRG 本身有问题」和「转换器有问题」。
若后续给它分配前缀(如MET-),此处改为 Frontier 透传。
跨方失败码映射表尚未冻结,这条在那份文档里定。
两条约定
| # | 约定 |
|---|---|
| 1 | Frontier 不得改写上游码,只能透传,或在自己判定时追加自己的码。否则 MAI-004 到 UI 变成 FRT-xxx,按方分组与对账就断了 |
| 2 | 上游接口必须有失败通道——对 GeometryService 与 MetusAPI 两份签名的硬约束。若接口只返回几何、不带失败信息,Frontier 只看到「几何是空的」,分不清「图上确实没这个特征」和「解析失败」 |
多重失败的单码优先级
FailureCode 是单个字符串,一条 GDT 同时命中两种失败时必须定报哪一个。
按流水线顺序判,第一个命中即终止,不再往下判:
InputInvalid → NotSupported → Unreachable → Ambiguous → NeedsManual
(输入坏了) (软件不支持) (机台做不到) (需人选) (需人确认)
| 这一步在前 | 因为 |
|---|---|
InputInvalid 最前 |
输入坏了,后面全部无从判断——几何都没解析出来,谈不上支持不支持、拍不拍得到 |
NotSupported 在 Unreachable 前 |
软件都不支持这个 GDT,就不必再问机台能不能拍到 |
Ambiguous / NeedsManual 最后 |
这两类是「能做,但要人参与」,最轻的一档 |
状态跳变是预期行为:客户修好 DXF 后,这条从 InputInvalid 变成 NotSupported。
人工清单上它会重新出现一次、原因换了,UI 需说明「上一轮原因已解决,暴露出新原因」。
Status 与空值的分工
null 本身不区分「留空」与「失败」,区分靠 Status:
| 情形 | 字段值 | Status |
|---|---|---|
| 算出来了 | 有值 | Ok |
| 故意留空,现场调 | null |
Ok ← 注意也是 Ok |
| 算不出来 | null |
NeedsManual / Ambiguous |
| 本来源确实没有这个东西 | 空值 {} / [] / "" |
Ok(不是缺陷,见 9.1①) |
| 根本不该缺 | 字段缺失 | schema 挡掉,拒收 |
Status == "Ok"时FailureCode写""而不是null——「没有失败码」是确定的事实,
不是待填的占位(规则 10)。
Status 也参与改版判定,不只给 UI 看:
上次 Status |
改版时 |
|---|---|
NotSupported |
输入没变不用重算,还是不支持 |
Ambiguous → 工程师选过 |
已变成 Ok 且 LockedFields 非空 → 按人工锁定处理,不被覆盖 |
InputInvalid → 客户改了图 |
必须重算 |
VisionHit —— 抓边段落(挂在 Feature 下)一个 feature 可以有多段(一个圆抓四个方向 = 4 段),每段自带一整套完整属性——
倍率、取点方式、抓边密度、光照、对焦、是否人工定位、是否出图,全部段级。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Index |
int | ✔ | 段序号 |
TargetType |
enum | ✔ | Point / Line / Circle / Arc —— 抓什么 |
ROI |
object | ✔ | 框在哪,见本节 ROI |
EdgeMethod |
object | ✔ | 怎么抓,见本节 EdgeMethod |
Light |
object | required-but-nullable | 本段的光照,见本节 Light |
Focus |
object | required-but-nullable | 本段的对焦,见本节 Focus |
Geometry |
object | 按 TargetType |
拟合参数,见本节 Geometry |
Magnification |
number | ✔ | 本段倍率,按公差算并落离散档位(见 4.4) |
AcquisitionMode |
enum | ✔ | Auto / SemiAuto / Manual(取点方式) |
EdgeDensity |
number | required-but-nullable | 本段抓边密度 |
NeedsManualPosition |
bool | ✔ | 本段执行前需人工把框放对位置。Frontier 算不准或算不出 ROI 位置时置 true(工件被夹具遮挡、特征太小、粗基准尚未建立),Metus 执行到此段停下让操作员挪框。段级:四段抓圆里一段被遮挡要人工挪、另三段照常自动,这是常态 |
OutputImage |
bool | ✔ | 本段是否输出图片(每段一个视野一张图) |
Owner |
enum | ✔ | Auto / Manual —— 该段是谁创建的 |
LockedFields |
string[] | ✔ | 该段哪些字段被人工改过,空数组表示全自动 |
三个「要人介入」的字段区别在时间点,都留着不冗余:
NeedsManualPosition(段级,执行时要人把框放对)·GDTs[].Status = NeedsManual(GDT 层,生成时就算不出来,进人工清单)·LockedFields(三层,过去被人工改过,改版时别覆盖)。骨架里
PM_001(PartMatch)段 1 是唯一的true——工件匹配是整条链第一步,此时还不知道工件摆在哪,必须人工先框一下。这也是 4.6 里NeedsManual第一条情形「粗基准要在影像上确认位置」与第七节「两阶段生成」的落点。
本层不放
Status:M-List 只声明「怎么抓」,抓不抓得到不是它该管的——
它是程序的原料不是执行日志,运行结果走 Metus 接口返回、不回写文件。
LockedFields用法同 4.3,粒度是本段字段(自动生成的段被改过光源 → 记["Light"],
改版时该字段不覆盖、ROI 仍重算)。同元素各段倍率不同会触发变倍 + 重新对焦,
格式允许但应尽量落同一档位。
ROI —— 框在哪
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
Center |
number[2] | ✔ | 毫米,机台坐标 |
Size |
number[2] | ✔ | 毫米(宽 × 高)。点特征高度取固定像素的等效毫米值 |
AngleDeg |
number | ✔ | 框的旋转角,必填。没有它斜边测不了——轴对齐的框里斜边是对角线,扫描方向不对边缘检测直接失效 |
ScanDirectionDeg |
number | ✔ | 扫描方向,定义为「相对 AngleDeg 的偏移角」,默认 90(永远垂直于框的长边) |
AngleDeg + ScanDirectionDeg。 定成相对偏移,AngleDeg 一设好扫描方向自动就对VisionProbes.Camera.PixelSizeUm 与当前倍率——EdgeMethod —— 怎么抓
| 字段 | 类型 | 必填 | 本期取值 |
|---|---|---|---|
Mode |
enum | ✔ | MatchEdge(匹配棱)/ SpecifiedEdge(指定棱)。唯一显式设置的一项 |
MatchRule EdgeIndex Polarity Threshold Strength Smooth SubPixel |
enum / int / number / bool | 均 ✔ | 本期全部走默认值。MatchRule = Strongest/First/Last;Polarity = DarkToLight/LightToDark;其余为第几道棱 / 门限 / 强度 / 平滑 / 亚像素 |
走默认值的残留风险:一个 ROI 里常有多道棱——工件真边 + 倒角 + 阴影。
极性或序号错就抓到倒角上,尺寸系统性偏一个倒角宽度,而且不报错。
Light —— 光照
机台是 4 环 8 区,6 种模式全部建模:Coaxial(同轴)· Ring(环形)· DualRing(双环)·
Quad(4 分区)· Octa(8 分区)· Off(关闭)。
"Light": {
"Mode": "Quad",
"ZoneMask": 5, // 位掩码:4 分区用低 4 位,8 分区用低 8 位。5 = 第 1、3 区亮
"Brightness": [80, 0, 80, 0] // 逐区亮度 0–100;长度随 Mode 变
}
| 字段 | 类型 | 说明 |
|---|---|---|
Mode |
enum | 6 种模式之一 |
ZoneMask |
int | 位掩码。Quad 用低 4 位,Octa 用低 8 位;非分区模式恒为 0 |
Brightness |
number[] | 逐区亮度 0–100。数组长度必须与 Mode 匹配(规则 8) |
Brightness 长度随 Mode:Coaxial / Off / Ring = 1(Off 恒为 [0])·
DualRing = 2(内外环独立)· Quad = 4 · Octa = 8,逐区一个值。
分区必须建模:测一条棱时只点亮垂直于该棱的两个分区,对比度最高,这是测薄壁与斜面的主要手段。
Focus —— 对焦
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
DoFocus |
bool | ✔ | 是否对焦 |
MachineZ |
number | required-but-nullable | 机台 Z(成像高度)。null = 留空由现场调 |
Geometry —— 按 TargetType 分
Point / Line 无额外字段;Circle 带 MaxRadius / MinRadius(搜索环);
Arc 再加 StartAngleDeg / EndAngleDeg。
VisionProbes —— 相机与机台能力独立数组,不复用 Probes——Probes 的字段全是为测针设计的,相机需要的一个都没有。
全部字段 owner 均为 Metus,全部必填。只在融合实例出现,上游两类实例一律 []——机台能力与解析图纸、解析程序无关。
| 字段 | 类型 | 说明 |
|---|---|---|
ID / Name |
string | |
ProbeType |
enum | 固定 Vision(保留 Contact 以备将来混用) |
Camera.Model / Camera.ResolutionPx / Camera.WorkingDistanceMm |
string / int[2] / number | 型号 / 分辨率 / 工作距 |
Camera.PixelSizeUm |
number | 像元尺寸(μm),传感器常量,毫米↔像素换算的根 |
Magnification.ContinuousRange |
number[2] | 连续变倍范围,如 [0.6, 19.0] |
Magnification.DiscreteSteps |
number[] | 离散档位如 [0.6, 1, 2, 3, 4, 5]。标定过、精度可保证,倍率推荐必须落在这里面 |
Magnification.PixelEquivalentTable |
object[] | 离散档位的像素当量标定表,每项 { Mag, MmPerPx }。见 6.1 |
Light.SupportedModes / Light.RingCount / Light.ZoneCount |
enum[] / int / int | 6 种模式 / 4 / 8 |
Axes.TravelXYZ / Axes.HasRotaryAxis / Axes.HasAngleMirror |
number[3] / bool / bool | 行程 / 旋转轴 / 角度镜 |
VisionProbes全部由 Metus 的机台能力模型提供(配置驱动,换机型改配置不改代码),
Frontier 读它来算倍率与可达性。
像元尺寸是传感器常量,像素当量不是——它等于 像元尺寸 ÷ 光学放大倍率,随倍率变,
存单值必然在其他倍率下全错。
| 倍率类型 | 怎么取当量 | 为什么 |
|---|---|---|
| 离散档位(0.6 / 1 / 2 / 3 / 4 / 5) | 查 PixelEquivalentTable |
这些档位标定过,实测值比理论计算准(含镜头畸变与装配误差) |
| 连续变倍段(0.6–19.0 之间任意值) | 现算:MmPerPx = PixelSizeUm / 1000 / Mag |
连续段没有标定表可依 |
"PixelEquivalentTable": [ // 标定实测值,优先于计算值;每个离散档位一项
{ "Mag": 0.6, "MmPerPx": 0.005750 }, { "Mag": 1, "MmPerPx": 0.003450 },
{ "Mag": 2, "MmPerPx": 0.001725 }, { "Mag": 3, "MmPerPx": 0.001150 },
{ "Mag": 4, "MmPerPx": 0.000863 }, { "Mag": 5, "MmPerPx": 0.000690 }
]
先查表,表里没有再算;倍率推荐必须落离散档位(规则 5),所以正常路径永远走查表。
上表数值按PixelSizeUm = 3.45推的,是示例不是实测值,实机标定后由 Metus 替换。
VisionAlignments —— 影像建系独立数组。原 Alignments 是 string[](只有名字),装不进影像建系动作;
用另开一层平级数组绕开,原 Alignments 一个字不改。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ID / Name |
string | ✔ | |
ParentIds[] |
string[] | ✔ | 父坐标系,数组。空数组表示根节点。上游实例可有多个(源文件的 Measured System 常写成 A & B);融合实例长度必须 ≤ 1——变换要能沿链累乘,多父无法确定累乘顺序 |
SourceFeatureId |
string | ✔ | 仅融合实例根节点用:指向 PartMatch feature。非根节点与上游实例一律 ""(上游实例不产出 PartMatch) |
BuildMethod |
enum | ✔ | LineCircle(一线一圆)/ TwoLines(两线)/ TwoCircles(两圆) |
Inputs[] |
string[] | ✔ | 参与建系的 Feature ID,顺序有意义 |
Origin.X / .Y / .Z |
object | ✔ | 每项:Source(取自哪个 Input)· Value(偏置量,可为 0) |
Rotation.Source |
string | ✔ | 定方向的 Input |
Rotation.AxisTo |
enum | ✔ | 转到哪个轴:XPlus / XMinus / YPlus / YMinus |
AxisFlip |
object | ✔ | FlipX / FlipY / FlipZ,各 bool |
Description |
string | nullable | 源文件里这个系的建系步骤原文,人可读。只用于 UI 提示,任何算法不得解析它(见下)。融合实例为 ""(它不是从源文件来的,本来就没有原文) |
RotaryAngle |
number | nullable | 建系时的转台角度。源文件实测有 0 / 90 / 180 / 17 / -15.8 / -106.526。机台无转台而源程序依赖它 → 该系不可复现,相关 GDT 标 Unreachable |
Owner / LockedFields / UpstreamChangedAt |
✔ | 改版标记,与 Feature 同(见 4.3)。只在融合实例,上游实例不带(见下) |
必填 ✔ 指「字段必须在」,不保证「有内容」。
BuildMethod/Origin/Rotation/AxisFlip
这四项在上游实例提取不出时写空值(""/{})——MSOP 路径是常态,它的建系步骤是自然语言,
只有Description原文一定有。空值 = 本来源确实没提取出来,不是缺陷(9.1①);
融合实例必须有真实内容,否则变换算不出来。上游实例不带改版标记。
Owner/LockedFields/UpstreamChangedAt三项
只在融合实例出现:上游实例是一次性存档,没人会去编辑它——
带着这三个字段只会让人误以为上游实例也参与改版合并。与上游实例的Features处理一致。
链式约束按份不同
| 上游实例 | 融合实例 | |
|---|---|---|
ParentIds 长度 |
可多个(源文件的 Measured System 写作 A & B) |
≤ 1 |
| 根的数量 | 可多个——源文件里的顶层系会各自成根:Measured System 指向 START_UP 这类非坐标系的伪值时(实测 ALI_MAN 就是这种),或父系提取不出来时 |
恰好 1 个 |
| 图结构 | 有向无环图(DAG) | 一棵树 |
根节点 SourceFeatureId |
""(上游实例不产出 PartMatch) |
必须指向 PartMatch |
融合实例收紧到单父单根,是因为 Frontier 要按拓扑序把每个节点译成变换矩阵并累乘,
求出各自的 T_machine←cs;多父无法确定累乘顺序。
Description只给人看,任何算法不得解析它。源文件的建系步骤是受控文法、可提取(
YPLUS rotate to DAT_B_MIDLIN around ZPLUS
直接对应Rotation.Source+AxisTo),但提取必须在 ORCA 侧一次做完,
结果落进BuildMethod/Inputs/Origin/Rotation;Description只是原文存档。
这段文本来自 OCR、噪声已被证实(系名有ALI_ITER/ALI_IIER/ALI_TIER三种写法),
下游再解析它等于把 OCR 噪声静默引进执行链。
提取不出的字段留空值(对象{}/ 字符串"",见 9.1①)——留空是可见的,猜错不可见。
配套要求:两阶段生成。 链上任一环变换译错会沿链静默传导,下游几十个尺寸全歪且不报错。
对策是先只下发粗基准元素跑一遍让用户确认圆和线的位置,确认了再生成其余全部——
装错件、装错朝向、抓错边在这一步就暴露。
| 结构 | 处理 |
|---|---|
GDTs[] |
沿用 external schema,只加 2 个失败态字段(Status / FailureCode,见 4.6)。原有 GDTType / SubType / CharacteristicID / GDTName / GDTLabels / LinkedCadFeatures / LinkedCadIDs / Bubbles / DisplayBubble / MeasurementMethod / DimensionValue / PlusToleranceValue / MinusToleranceValue / CadID(int) / Quantity / BubbleNumber / RefFeatureCountPerInstance / IsUserCreated / Specifications[](实测 5 个字段:ToleranceValue · UnequalToleranceValue · ProjectedToleranceZoneValue · Modifiers[] · Datums[]{ Label, Modifiers[] },材料条件修饰符 MMC / LMC / RFS 落在 Modifiers 里) 全部照原样。GDTName 是人可读的分类编号(实测 MA_DIAM1 / MA_FCFPERP6,100/100 非空),人工清单靠它标识评价项;DisplayBubble 实测 100/100 全是同一个 OCR 噪声值 "CF"(Bubbles 也 100/100 是 ["CF"],BubbleNumber 100/100 是 null),保留为同构、绝不作为定位依据 |
Datums[] |
完全沿用,实测 8 个字段:GDTLabel(基准标签,跨源对齐锚点,见 2.2)· LinkedCadFeatures · LinkedCadIDs · Type(int,实测恒 0)· ReferenceDatums[] · CharacteristicID(实测恒 null)· CadID(int,实测恒 0)· Tags(实测恒 null) |
Alignments[] |
保留 string[] 以保持同构,我方三类实例一律保持空。源程序的坐标系不写在这里——只有名字没有建系动作,等于什么都没说;它们连同建系步骤一起进本实例的 VisionAlignments[](见第七节) |
Probes[] |
保留,保持空,相机一律走 VisionProbes |
| 钥匙字段 | 全部沿用,不额外新增一层对应关系:CadIDs(连回图纸与数模,值是 CAD 实体句柄)· CharacteristicID(评价项唯一 ID)· LinkedCadFeatures(要求→特征,值是 Features[].ID)· LinkedCadIDs(要求→CAD 句柄,与 LinkedCadFeatures 并列的平行通道) · DependentFeatures(特征→特征,依赖 DAG 由此派生) |
① 空值三档,含义各不相同。
| 写法 | 含义 |
|---|---|
| 字段缺失 | 拒收。不能靠「字段不存在」表达任何语义。范围:本文标 ✔ 或 required-but-nullable 的字段;Externals 原生沿用字段按需出现(见 4.1) |
空值 {} / [] / "" |
本来源确实没有(已经查过、确认没有)。不是缺陷 |
null |
占位,等后续填。「这里应该有值,现在还没有」 |
number / bool 没有空值可表达,只能用 null;因此上游实例里的 null 一律读作「本来源没有」,
占位语义只在融合实例成立(上游实例没有「后续填」这回事,它是一次性存档)。
所以 Light / Focus.MachineZ 这类必须是 required-but-nullable:字段必须在,值可以是 null
表示留空由现场调。「上游没算出来」是缺陷,「工程师故意留白让现场定」是设计;
分不清,改版三态判定就判不了。
② 不降级输出。 未命中 / 不合规 / 归属不唯一 / 无清晰对焦面 → 一律打标转人工,
绝不猜测补全,绝不静默取近似值。
③ 关键数值一律由确定性算法产出。 坐标、公差、拟合结果、关联关系全部算出来;
智能体只能选策略、调有界参数,不得直接给数值。
适用范围:第 1–16 条约束
…FromFrontierVision的每一个实例——历史实例是完整快照,
当时都是生效版本,规则同样成立,不允许写成残缺的实例。
…FromMAI/…FromOrcaAI是上游返回体的原样存档,不做 schema 校验
(它们本来就没有影像参数、没有影像坐标系)。
上游实例只校验:三个元字段齐备 · 本实例内部自洽 · 本方应产出的内容非空 ·
BasedOn与Alignments为[]·PartMatchFeatureId为""·ProgramRevision为null。
第 17–23 条是容器层规则,跨容器、跨版本校验。
Internal/Construct不校验——由Metrology.AI产出、Frontier 只读,内容缺失或不合规按 4.6 报FRT-码。
| # | 规则 | 违反后果 |
|---|---|---|
| 1 | GDTs[].LinkedCadFeatures 不得包含 FeatureType == PartMatch 的 ID |
拒收 |
| 2 | PartMatch feature 有且只有一条,且 ID 与 Info.PartMatchFeatureId 一致 |
拒收 |
| 3 | VisionAlignments 的 ParentIds 构成一棵树:每节点长度 ≤ 1、无环、恰好一个根 |
拒收 |
| 4 | 根节点(ParentIds 为空数组)的 SourceFeatureId 必须指向 PartMatch |
拒收 |
| 5 | VisionHits[].Magnification 必须落在 VisionProbes.Magnification.DiscreteSteps 之内 |
拒收 |
| 6 | Info.IsScaledToOneToOne == false 时,下游不得使用任何几何坐标 |
阻断 |
| 7 | Feature.VisionAlignmentId 必须存在于 VisionAlignments[],或为 ""(该 Feature 不挂坐标系) |
拒收 |
| 8 | Light.Brightness 数组长度必须与 Light.Mode 匹配 |
拒收 |
| 9 | Datums[].GDTLabel 必须是单个大写字母(挡图纸 OCR 把公差项误识别成基准的脏数据。实测 11 条基准里有 position 与 Ø0.2 两条噪声,9/11 合规——这条规则就是为它们设的) |
打 Ambiguous 转人工 |
| 10 | GDTs[].Status == "Ok" 时 FailureCode 必须为 ""(不是 null——「没有失败码」是事实不是占位);!= "Ok" 时必须非空 |
拒收 |
| 11 | Feature / VisionHit / VisionAlignments 上不得出现 Status / FailureCode 字段 |
拒收(失败态只允许在 GDT 层) |
| 12 | LockedFields[] 里的每个字符串必须是本层真实存在的字段名 |
拒收 |
| 13 | partMatch 失败时,全部 GDT 的 Status 必须都是 Unreachable 且码一致 |
拒收 |
| 14 | Cad2D 下 VisionAlignments[].Inputs 引用的 Feature 不得跨视图。本期由结构保证(Info.ViewId 唯一、Feature 不带 ViewId)。多视图上线前必须先在 Feature 上加 ViewId,否则本规则不可机器校验 |
拒收 |
| 15 | Status 与 FailureCode 域前缀相容:NotSupported / Unreachable / NeedsManual 不得用 MAI- / ORCA- 前缀(上游解析方不知道我方能力与机台行程);NeedsManual 只允许 FRT- |
拒收 |
| 16 | 多重失败时 Status 必须取优先级最高的一个(见 4.6) |
拒收 |
容器层规则(跨容器、跨版本校验)
| # | 规则 | 违反后果 |
|---|---|---|
| 17 | Externals[] 里每个实例的 $type / VersionId / SchemaVersion / GeneratedAt 必须齐备;$type 取 2.1 三值之一;VersionId 全文件唯一;同 $type 内 GeneratedAt 严格升序(最大者即当前生效版本);…FromFrontierVision 至少一个实例 |
拒收 |
| 18 | 各实例内部自洽:任一实例的 GDTs[].LinkedCadFeatures 与 Datums[].LinkedCadFeatures 必须全部指向本实例的 Features[].ID,不得跨实例引用,也不得引用 Internal / Construct(那会把我方 ID 空间耦合到 Metrology.AI 的产出上)。附带:…FromOrcaAI 的 CadIDs 必须为空(含 PRG 副本,见 2.1) |
拒收 |
| 19 | 基准一致性:融合实例 Datums[].GDTLabel 的集合必须是 BasedOn 指向的各上游实例并集的子集——不得出现任何上游都没有的基准标签。附带:融合实例每条 Datums[].LinkedCadFeatures 必须指向本版本存在的 Features[].ID |
拒收 |
| 20 | 上游实例的父系图:ParentIds 引用的 ID 必须存在于本实例 VisionAlignments[],且图无环。允许多根(每条输入路径一条链)与多父 |
拒收 |
| 21 | 上游实例的坐标系名须先归一化再入库:去首尾与内部多余空格、收敛已知 OCR 变体(如 ALI_IIER / ALI_TIER → ALI_ITER)。归一化后 ParentIds 必须全部命中,不得因拼写差异出现悬挂引用 |
拒收 |
| 22 | Info.SourceFiles 内容:…FromMAI 恰好 1 个 Dxf 或 Step;…FromOrcaAI 为 1–2 个且必含 Msop(另一个只能是 PcDmis);融合实例必须为 [](派生值,靠 BasedOn 追溯) |
拒收 |
| 23 | BasedOn 可解析且时序自洽:上游实例必须为 [];融合实例必须非空,每个 VersionId 命中 Externals[] 里真实存在的实例、同一 $type 不重复出现、且被引实例的 GeneratedAt 严格早于本实例(挡「基于一个还没产生的版本」) |
拒收 |
规则 21 挡的是父系链被 OCR 拼错切断:不归一化,56 个系的链会断成几段,
而断链不报错——有些系找不到父、被当成新的根,变换从错误的起点累乘。
规则 19 挡的是「融合凭空造基准」:基准是整条坐标链的根,
造出一个上游没有的基准 = 后面所有变换都从错误的起点累乘,而这种错不报错。
删掉SourceRefs后它是唯一还能机器校验的溯源护栏,所以卡在基准这一层(见 2.2)。
规则 22 + 23 一起挡的是「来源说不清」:融合实例不再自存来源文件,
所以BasedOn必须能一路解析到上游版本、再到SourceFiles。
断了这条链,「这份程序是拿哪个 DXF 和哪个 MSOP 生成的」就无法回答——
而 GRR / 相关性追溯全靠这个问题有答案。
覆盖率 = count(GDTs where Status == "Ok") / count(GDTs)
分母是 GDT 数(评价项 / FAI),不是元素数。
人工清单 = Status != "Ok" 的 GDT 行。
文件:01_排期与计划/M-List影像版_骨架示例.json(合法 JSON,可直接当 mock 喂给四方联调)
顶层只有 4 个 key(Unit / GDTStandard / Internal / Construct / Externals),
没有任何 VisionExternals_*——我方内容全在 Externals[] 里,共 5 个实例,
按 GeneratedAt 追加:MAI-001 → FRT-001 → ORCA-001 → MAI-002 → FRT-002。
外加 Internal 里一份 Metrology.AI 的 PRG 转换结果(只读输入,见 2.1)。
已通过本文全部 23 条校验规则自检(规则 1–16 在 …FromFrontierVision 的每一个实例上各跑一遍)。
完全自洽:所有引用(LinkedCadFeatures / VisionAlignments.Inputs / Origin.Source /
Datums / BasedOn)都指向实际存在的条目,可直接用作校验用例。
骨架刻意示范的十二件事
| # | 要点 |
|---|---|
| 1 | $type 判别来源,同 $type 多实例 = 多版本:Externals[] 里两个 …FromMAI(MAI-001 / MAI-002)、一个 …FromOrcaAI、两个 …FromFrontierVision。当前生效版 = …FromFrontierVision 里 GeneratedAt 最大的 FRT-002 |
| 1b | 四套 ID 并存,靠基准标签对齐:同一个孔 = MAI_F001(CadIDs 记 12090)= FAI7_CIR1(MSOP 命名反推)= CIR1(PRG 原生名)= CR_001(Frontier 分配)。没有 ID 配对表——四侧都有基准 A,星型挂接后按坐标就近匹配(2.2) |
| 2 | MSOP 给不出几何:FAI7_CIR1 的 Center / Radius 全 null、扎点每条 3 个数、MeasurementMethod 为 {};融合实例 CR_001 的 Radius: 5.0 是拟合出来的,上游实例不回填。坐标取 Msop3D 的 Z = -2.0,DXF 的 Z = 0.0 不参与 |
| 3 | 建系动作带原文:ALI_MAN → ALI_ITER → ALI_DAT_A → ALI_ABC 是真实父系链,4 条都带 Description;ALI_ABC 示范多父与归一化(源文件写的是 ALI_TIER) |
| 4 | 段级参数、字段级锁定、失败态只在 GDT 层:CR_001 两段 ZoneMask 与倍率都不同、段 2 锁 ["Light","Magnification"];同一个 CR_001 被两条 GDT 引用,CH_0007 Ok 而 CH_0031 NotSupported + FRT-014,覆盖率 1/2 |
| 5 | 历史版本 + BasedOn 追溯:DXF 从 V4(MAI-001)改到 V5(MAI-002),MAI_F001.Radius 由 4.9 变 5.0;FRT-002.BasedOn 指向 MAI-002 + ORCA-001,其 CR_001.UpstreamChangedAt 等于 MAI-002 的 ParsedAt——算出来的,没有重新解析 DXF。DXF 与 MSOP 不在融合实例 SourceFiles 里重复登记,靠 BasedOn 一跳取到 |
| 6 | 两阶段生成:FRT-001 是第一阶段快照——只有 PM_001 + AV_ROOT、0 条 GDT(粗基准刚建好、还没排测量项),它本身完整合法;FRT-002 才是完整程序。对应第七节的两阶段流程 |
| 7 | Internal 字段照真实 .orca 抄:Info 是原生 InternalMeasurementListInfo(带 $type / CadFileType / CadBoundingBox*,没有 SourceFiles);CIR1 / LIN1 是 27 字段的原生 Feature(ClearancePlane / Colors / AngleVector 全带、不带 MeasurementMethod);Probes 放一条原生测头定义 |
| 7b | PRG 副本进 ORCA 实例:ORCA-001 的 5 条 Feature = PRG 副本 2 条(CIR1 / LIN1,完整几何 + 6 数扎点 + Probe/Alignment 已填、CadIDs 置空)+ MSOP 3 条(FAI7_CIR1 等,无几何、3 数扎点)。同一个实例里两条路径的能力差一眼可见;SourceFiles 登记 PcDmis + Msop 两个文件(规则 22) |
| 8 | 原生 Alignments 装不下建系动作:Internal.Alignments 只有 ["ALI_MAN", "ALI_ABC"] 两个名字,没有 level / rotate / zero / offset——这正是「有 PRG 也仍然需要 MSOP 补建系原文」的实物依据(2.1) |
| 9 | 基准标签是跨源锚点:基准 A 在 Internal / MAI-002 / ORCA-001 / FRT-002 四侧同名(ORCA-001 另有 B)——没有任何 ID 配对表,对齐全靠它(2.2 / 规则 19) |
| 10 | BasedOn 时序自洽:FRT-001 只 BasedOn: ["MAI-001"](那时 ORCA 还没产出),FRT-002 才 BasedOn: ["MAI-002", "ORCA-001"]。被引实例的 GeneratedAt 一律早于本实例(规则 23)——挡「基于一个还没产生的版本」 |