跳转到内容

材质库来源与设计:工程材料与显示外观的统一身份:数据计划与首批接入

主文档与完整目录。本分篇保留原调查日期的依据与实测记录;其中的当前状态、建议和授权仅属于历史快照,不是执行队列。

10. 数据全面性与合规的执行计划

Section titled “10. 数据全面性与合规的执行计划”

目标是同时成立的两句话:发布物里的每一行都能说清来源与许可,且覆盖足够真实产品使用。 两者不是取舍关系——把许可变成数据的字段,就能在同一张表里并存。

10.1 合规机制:许可是数据的一等字段,闸门在打包期

Section titled “10.1 合规机制:许可是数据的一等字段,闸门在打包期”
  • 规范化后的每一行携带 sourceId / license / citedSource / basis / verifiedBy, 不是整库一个许可,而是逐行可判定。
  • 定义发布允许集:public-domain、CC0-1.0、CC-BY-3.0、CC-BY-4.0。
  • 转换脚本产出两张表:开发表(含只读校核源)与发布表(只含允许集)。
  • 闸门是一条会失败的检查,不是治理文档:发布表生成时遇到允许集之外的 license 值即非零退出, 接进现有 build,不新建 Gate 命令、收据目录或报告树(AGENTS.md)。
  • 署名产物由同一脚本生成:CC-BY 行按 citedSource 聚合成署名段落,写入现有 THIRD-PARTY-LICENSES.md 流程(§6 已指出该生成器只扫依赖树,需要显式加入这一段)。

这条机制的意义:LGPL / CC-BY-SA 数据可以留在开发期做交叉核对,而永远进不了发布物, 且这一点由构建证明,不靠人记住。

不追求牌号数量,追求族覆盖 + 常用牌号覆盖。参照商业 CAD 内置库规模(Fusion/Onshape 量级约 100–200 条):

族 目标条数 主来源 许可等级
碳钢 / 合金钢 ~45 MIL-HDBK-5J ch.2;EN 牌号名编码屈服值 S
不锈钢 ~15 MIL-HDBK-5J ch.2;NIST S
铝合金 ~30 MIL-HDBK-5J ch.3;FreeCAD 6061-T6 / 7075-T6 S + A
铜 / 黄铜 / 青铜 ~20 族常量 + ASTM 牌号编码;physically-based 密度核对 S
钛 / 镁 / 镍基 ~15 MIL-HDBK-5J ch.4/5/6 S
铸铁 ~8 EN-GJL/GJS 牌号编码 + NIST S
工程塑料 ~30 FreeCAD CC-BY 9 张 + 厂商 TDS 逐条 A
弹性体 ~8 厂商 TDS 逐条 A
木材 / 玻璃 / 混凝土 / 复合 ~15 FreeCAD CC-BY 7 张 + 公有领域 A + S
合计 ~186

验收标准(可机检,不靠主观判断):

  1. 发布表 100% 有 density(mass 派生对全库成立)。
  2. 金属族 ≥95% 有 YoungsModulus、PoissonRatio、YieldStrength、UltimateTensileStrength。
  3. 发布表 0 行落在允许集之外。
  4. 发布表 0 行触发 §4.3 的语义矛盾规则。
  5. 每行 citedSource 可解析为具体文档与位置,不是“来自某数据库”。
级 来源 许可 用法
S MIL-HDBK-5J(DoD,Distribution Statement A,US Gov work → 17 U.S.C. §105 公有领域);NIST 材料数据;physically-based-api(CC0);Wikidata(CC0) 公有领域 / CC0 直接进发布表,无署名义务
A FreeCAD 21 张 CC-BY 卡(§4.1);厂商公开 TDS(逐条判定可引用性) CC-BY-3.0/4.0 进发布表,必须署名
B FreeCAD 115 张 LGPL 卡、4 张 CC-BY-SA 卡;Supplemental-Materials(CC-BY-SA-4.0) 传染性 只读校核源,进开发表,被 §10.1 闸门挡在发布物外
C MatWeb / ASM / Total Materia / AZoM / MakeItFrom;OrcaSlicer / PrusaSlicer 配置(AGPL-3.0) 专有 / AGPL 禁用,不抓取、不导入、不作校核

关于 MIL-HDBK-5J 的两点如实说明:

  • 它给的是统计设计许用值(A/B basis),不是 MatWeb 风格的“典型值”。对 CAD 材料库这通常更合适, 但必须把 basis 作为字段带上,不能与典型值混排。
  • 17 U.S.C. §105 的公有领域效力在美国境内明确;美国政府在境外主张著作权的理论可能性存在。 结合 Distribution Statement A,实务上按可自由复用处理,但仍须法务确认。[待验证]

发布表的每一行必须满足:

  • ≥2 个独立来源,其中至少一个是 S 或 A 级,且作为 citedSource;
  • 数值分歧超阈值(密度 1%、模量 5%、强度 10%)→ 不发布,进 conflicts 清单人工裁决;
  • B 级只能出现在 verifiedBy,不能出现在 citedSource。

这条规则同时解决两件事:合规上让引用链干净;质量上直接拦掉 §4.3 那 6 行强度矛盾值。

产品轨(不依赖数据全量,用 §4.1 的 21 张 CC-BY + 86 条 CC0 就能全程跑通):

阶段 产出 验收
P0 契约与闸门 contracts schema(含许可字段)、转换脚本、发布/开发双表、许可闸门接进 build 闸门能对故意注入的 LGPL 行失败退出
P1 身份与绑定 materialId(class + grade)挂到 body,进 AMIR 文档 撤销/重做、保存重开、守恒与 patch 原子性全部保持
P2 派生与校验 ExactCadExpectation.mass,host 用 GProp 体积独立测量 声明错误质量的 plan 被否决
P3 外观投影 class → PBR,MaterialSlot 扩 PBR 字段,viewer 升 MeshPhysicalMaterial 指定材料后显示随之改变,且外观不进文档
P4 交换 3MF <basematerials>;STEP 维持名称+颜色,损失按 RFC-0005 申报 导回比较不新增静默丢失

数据轨(可与产品轨并行,产物是同一张发布表的行数增长):

阶段 产出 备注
D0 基线 21 张 CC-BY + 86 条 CC0 归一入表,跑通双源规则与闸门 无法务依赖,可立即开始
D1 金属主体 从 MIL-HDBK-5J 提取铝/钢/不锈钢/钛/镁/镍基 本计划最贵的一步:约 1700 页 PDF,表格密集且按温度/条件分栏,需人工核对而非自动抓取
D2 族常量与牌号编码 铜合金族常量、EN/GB 牌号编码屈服值、铸铁 便宜,覆盖增量大
D3 塑料与其余 FreeCAD CC-BY 9 张 + 厂商 TDS 逐条补齐 逐条判定 TDS 可引用性

依赖关系只有一条:P0 必须先于 D0——没有闸门和许可字段就开始导数据,等于在制造后面要返工的债。

向 FreeCAD 提出把 115 张 LGPL 材料数据卡(非代码)重许可为 CC-BY 的请求。 成本极低(一个 issue),收益是直接解锁 DIN/EN 钢与铜牌号这块 S 级来源覆盖不到的部分; 上游本身正在把新卡按 CC-BY-4.0 发布,方向一致。不阻塞任何阶段,成了就并入 A 级,不成也不影响 §10.2 的目标。

  • 不抓取 C 级来源,不用它们做校核。
  • 不把 B 级数据“改写一下”后当作自有数据——改写不改变来源事实,verifiedBy 如实记录。
  • 不做成本估算(§4.2:上游没有价格数据)。
  • 不为材料库新建 Gate 命令、收据目录、治理清单或平行报告树。
  • 不在本轮改 sealed WASM 绑定(STEP 物性推迟到有真实交换需求)。
  1. 发布允许集是否就是 public-domain / CC0 / CC-BY-3.0 / CC-BY-4.0——是否接受 CC-BY 的署名义务 (代价:THIRD-PARTY-LICENSES.md 增加一段材料署名)。若只接受 PD/CC0,塑料族要重做来源,覆盖会掉一档。
  2. D1 是否投入——MIL-HDBK-5J 的表格提取是本计划唯一的重成本项,也是金属覆盖的唯一 S 级来源。 不投入则金属只能停在族常量 + 牌号编码水平(约 40 条,够用但不“全面”)。
  3. A/B-basis 与典型值是否共存——共存则 basis 是必填字段且 UI 要显示它;只留一种则要选定哪一种。

P0 已完成:契约、转换产物与打包期许可闸门,并用真实数据端到端跑通。

文件 职责
packages/aira-contracts/src/material-library.ts 契约:SI 基本单位的物性行、外观行、逐行 citation 与 corroboration、扣留原因
packages/aira-contracts/scripts/material-library-policy.mjs 政策与闸门的唯一实现:允许集、逐类容差、物理量程、语义校验
packages/aira-contracts/scripts/generate-material-library.mjs 读 fixtures、过闸门、生成发布表与署名清单
packages/aira-contracts/fixtures/materials/ 种子数据:CC0 外观 11 条、CC-BY 物性 10 条
packages/aira-contracts/src/generated/material-library-data.ts 生成物(14 KB):发布表 + 闸门实际使用的政策常量 + MATERIAL_LIBRARY_ATTRIBUTIONS

闸门挂在 generate.mjs 内,而 generate 是 @aira/contracts 的 build 第一步—— 任何一次构建都不可能产出未过闸门的表,不需要额外的 Gate 命令或收据目录。 署名清单由决定“这行能发”的同一步生成,不另行手工维护。

注入一行 LGPL-2.0-or-later 的合成材料后运行构建:

Error: The material library gate rejected 1 row(s):
material metal.steel.gate-probe: licence "LGPL-2.0-or-later" may not ship.
Publishable licences are public-domain, CC0-1.0, CC-BY-3.0, CC-BY-4.0; a source under
any other terms may corroborate a value under verifiedBy, where only the agreement is recorded.

退出码 1,构建中止。移除该行后恢复正常,探针未留在仓库中。 本批验证:contracts 生成、tsc -p tsconfig.build.json、apps/web typecheck、 eslint(--max-warnings 0)与 prettier 全部通过。

11.3 种子结果:发布 5 行,扣留 4 行

Section titled “11.3 种子结果:发布 5 行,扣留 4 行”
结果 材料 说明
发布 metal.steel.generic、polymer.pc.generic、polymer.pet.generic、polymer.pp.generic、polymer.pmma.generic 密度经 CC0 源交叉核对,其余属性逐条声明为单源
扣留 source-disagreement polymer.pvc.generic 密度 1380 vs CC0 源 1300,差 6.15% 超 generic 容差 5%(增塑与硬质 PVC 的真实差异)
扣留 no-corroboration metal.aluminum.6061-t6 CC0 源的 Aluminum 是纯元素,不能给一个牌号做同精度核对;grade 级第二来源等 D1
扣留 unknown-appearance-class + no-corroboration polymer.pla/pa6/ptfe.generic CC0 外观库没有对应条目

四种扣留路径都由真实数据触发,不是构造出来的示例。

11.4 对已批准计划的两处调整(附理由)

Section titled “11.4 对已批准计划的两处调整(附理由)”
  1. §10.4 的容差按 specificity 分档,不再是单一的 1%/5%/10%。 证据:CC-BY 与 CC0 两个诚实来源在通用塑料密度上的实测差为 0–6.15% (PC 0%、PET 0%、PMMA 1.69%、PP 1.78%、PVC 6.15%)。通用行按定义是族代表,两个来源合法地 选了不同代表;用 1% 卡它只会否掉“作为通用值正确”的数值,而不是抓出错误。 牌号行保持 1%/5%/10% 不变,因为牌号指的是同一个确定的东西。密度在两档里都是最严的一档。
  2. strengthBasis 增加 unstated。FreeCAD 通用卡不声明基准;把它记成 typical 是我替来源 做断言。unstated 是诚实答案,并且明确不可作为设计许用值。

规范化不是搬运。以下值有来源但没有进表,理由逐条记录在 fixture 的 note 里:

  • 4 处 YieldStrength > UltimateTensileStrength(PC、PET、PMMA、PLA):丢弃 yield。 对塑料这可能是“屈服应力 vs 断裂应力”的语义差异,但消费方无从判断来源指哪一个, 当作许用上界用就是错的。
  • PET 的 ShearModulus 0.0385 GPa:与该卡自身的 E=3150 MPa、ν=0.36 推出的 ≈1.16 GPa 差 30 倍,丢弃。
  • PP 的强度对(UTS 79.7 MPa、yield 32.8 MPa):顺序虽然合法,但 79.7 MPa 超出聚丙烯的族范围, 两个值都丢弃。闸门只能查顺序,查不出标签互换——这是当前规则的已知边界,需要 D3 的第二来源解决。

材料尚未挂到 body、未进 AMIR 文档、未参与撤销/重做与守恒(P1);没有 expect.mass(P2); viewer 仍是 MeshStandardMaterial,未消费外观表(P3);未新增 AI 检索工具;未改 3MF 与 sealed WASM。

12. D0 与 P1 执行记录(2026-09-09)

Section titled “12. D0 与 P1 执行记录(2026-09-09)”

新增 scripts/import-material-sources.mjs:手工运行、不进构建, 读取 materialize 后的参考克隆,产出已审阅的 fixtures。单位换算、佐证偏差、被丢弃的属性全部由脚本推导, fixtures 里没有一个手敲的数字。许可过滤出现两次且共用同一个 MATERIAL_PUBLISH_LICENSES: 导入期决定值不值得写下来,闸门期决定能不能发——一份政策,两个执行点。

两个来源已按仓库既有机制固定到 SOURCES.lock.json: FreeCAD 82c7a09b(140 张标准卡,逐卡许可与 §4.1 实测一致)、 physically-based-api eb4408aa(deploy/materials.json,86 条,CC0-1.0)。

结果:外观类 43 条、物性行导入 20 条、发布 14 行、扣留 6 个材料共 11 条原因。

结果 材料
发布(14) 6061-T6、7075-T6、steel.generic、steel.calculix、钢筋 B500、混凝土通用与 EN C35/45、玻璃通用与 E/S-2 玻纤、PC、PET、PMMA、PP
扣留 source-disagreement(1) PVC(密度差 6.15%,增塑与硬质 PVC 的真实差异)
扣留 unknown-appearance-class(5) 木材、ABS、PA6、PLA、PTFE——CC0 外观库没有这些条目
扣留 no-corroboration(5) 与上面 5 条同一批:它们同时缺第二来源

当前唯一的结构性缺口是外观,不是物性:5 个材料的物性都齐备且许可干净,只是没有可发布的外观类。 补齐需要一个 PD/CC0 的聚合物与木材外观来源,或者接受一个通用介电类(本文不采用后者,因为那等于编造数值)。

导入期自动丢弃的属性(日志逐条给出理由):

  • ABS、PMMA、PC、PET、PLA 的 YieldStrength 高于同卡的抗拉强度 → 丢弃 yield。
  • PET 的 ShearModulus 只有该卡 E 与 ν 推出的各向同性值的 0.033 倍 → 丢弃。
  • PP 的强度对由显式覆盖丢弃(抗拉 79.7 MPa 超出聚丙烯族范围),理由写在脚本里而不是藏在规则里。

12.2 本批的两处政策调整(附证据)

Section titled “12.2 本批的两处政策调整(附证据)”
  1. 线性颜色分量上界从 1 放宽到 2。 金的红通道实测 1.059、铯的高光 1.073——超出 sRGB 色域的 反射率是真实测量值,不是错误。渲染时钳制是显示行为;在库里钳制等于丢掉测量。
  2. 佐证条目必须声明自己的 specificity,容差取两者中较钝的一侧。 证据:混凝土 C35/45(4.17%)、E 玻纤(3.2%)、S-2 玻纤(1.6%)此前按 grade 的 1% 被否, 但它们的对照来源是通用参考——拿通用参考去卡牌号精度,否掉的不是错误而是“两个来源能达到的最接近”。 这条同时让 6061/7075 可以被通用铝参考佐证并发布,代价是要如实说明: 通用对照能抓住单位错误和用错材料,抓不住用错牌号;牌号级佐证等 D1。
文件 职责
packages/aira-contracts/src/material-binding.ts Body.extensions['aira.material/0.1'] 的读写、别名解析、外观投影入口
apps/web/src/authoring/exact-body-material-v0.4.ts 构造单条 body.put 补丁;未知 body、未解析材料、无变化三种情况直接拒绝

没有改 AMIR schema,也没有新增执行管线。 Body.extensions 是既有开放字段,body.put 是既有补丁操作, model.proposePatch 是既有 Interface 操作——所以撤销/重做、保存重开、原子提交与守恒不是这批新写的, 而是这条补丁走既有 proposePatch → preview → validate → commit 路径自然继承的。新增的只是 “怎么把材料正确地放进一条 body.put,以及什么情况下拒绝”。

赋material 会触发一次几何重算(文档变了,head 前移,render packet 重新派生)。为省这次重算另建一条 提交路径会违反“不另建执行管线”,因此不做。

验证(scratch 脚本,未入库):14 行全部有密度且有可解析外观类;别名解析覆盖 id、标准号、 中英文别名与大小写空格差异;被扣留的材料不可解析(polymer.pvc.generic 查不到,因此不可能被赋到 body 上); withBodyMaterial 不改动入参、保留其他扩展与 authority、清除时删键而非置 null; JSON 往返后仍可读出;扩展被写坏时读作“无材料”而不是抛错。 tsc(contracts + web)、eslint(--max-warnings 0)、prettier 全部通过。

控制器与 UI 接线没有做。 LiveWorkbenchController.ts、i18n/locales/en.ts、zh-CN.ts 当前正被并发会话修改,在这三个文件上动手会和对方的在途改动纠缠。 这部分本来也更适合放进 P3:材料能设却看不见,不是一个可交付的产品状态。 P3 会同时补上外观投影和选择控件,那时接线是纯 UI 改动。

13. P2 与 P3 执行记录(2026-09-09)

Section titled “13. P2 与 P3 执行记录(2026-09-09)”

expect 增加 massKg(千克)。host 用已有的体积测量乘以材料密度得到质量, 与 volume 共用 quantityRelative 容差。没有新增任何几何测量。

ExactCadPlanStep 增加 set-material:像 replace-program 不指名程序节点一样,它不指名 body, 由 host 解析文档中唯一的 body;材料可写 id、标准号或常用名,解析不到直接拒绝。 该步骤直接复用 P1 的 createExactBodyMaterialPatchV04——P1 的补丁构造器由此拿到了它的调用方。

set-material 可以带 expect,并且是 massKg 第一个能被满足的步骤:赋材料与断言质量是同一步, 不需要先赋材料再补一个借口性的编辑。它以 affects: []、enforce: true 进入守恒检查—— 材料赋值不该改变任何几何,强制这一点正是 host 证明它没改的方式。

在没有材料时声明 massKg,得到的不是“未知”,而是指名缺失那一半的诊断: measured: unknown (the output body carries no material)。

三个刻意的取舍:

  • 单位写进字段名(massKg)。毫米由文档强制,千克与克不是;名字是最便宜的一道防线。
  • preserve 不扩展到质量。材料不变时质量守恒等价于体积守恒,而程序步骤改不了材料。
  • 质量的容差沿用 volume 的 quantityRelative:密度是表中一个确定的数,质量与体积严格成正比。
改动 说明
MaterialSlot.baseColorSrgb → baseColorLinear 改名是纠错:three.js 的 new Color(r,g,b) 按工作色彩空间(线性)解释,这个字段一直存的就是线性值,名字在说谎。上界同时放宽到 2(见 §12.2)
MaterialSlot 增加可选 materialId / metalness / roughness 带 materialId 的槽位是“这个零件是什么做的”,不带的是显示默认值
materialSlotAppearance() class → 槽位,并施加 AS_MACHINED_ROUGHNESS = 0.35
createExactFeatureRenderTransfer(..., materialId?) 由 session 用 nodeOutputMaterialId(document, outputNodeId) 传入
viewer 消费 slot.metalness/slot.roughness;无材料时仍是原来的 0.05/0.72
applyMaterialPalette 不再覆盖带材料的网格——调色板是“问题没被回答”时的外观,不是盖住答案的装饰

两处需要说法的选择:

  1. 没有升到 MeshPhysicalMaterial。 ior 只在透射/清漆下才看得出来,我们两者都不用; 基色、金属度、粗糙度已经是钢和 PC 在屏幕上的全部差别,MeshStandardMaterial 更便宜。 这推翻了 §10.5 里 P3 的原写法,理由如上。
  2. AS_MACHINED_ROUGHNESS = 0.35 是产品选择,不是测量值,并在代码里如此标注。 库里的粗糙度测的是抛光样品,直接用会把每个金属零件画成镜子;这一个数暂代逐零件表面处理, 取值使金属度而不是光泽成为金属与聚合物的视觉分界。

tsc(contracts build + web)、eslint --max-warnings 0、prettier 全过。scratch 脚本(未入库)覆盖:

  • set-material 的语法(id / 标准号 / 中文别名可用;缺 material 拒绝;写 bodyId 拒绝——计划永远不指名 body);
  • massKg 的算术文法(100*80*10*2700/1000000000 可用,科学计数法不在文法内,负值拒绝);
  • 质量换算:80 cm³ 的 6061(2700 kg/m³)= 0.216 kg,与声明一致;
  • 外观投影:14 行全部有槽位,粗糙度都不低于 as-machined 下限,钢 metalness=1、PC metalness=0、 两者基色不同;被扣留的材料投不出外观;返回的颜色是副本,改它不会改到库。

没有做可视验证:那需要起 dev server 并走一次真实模型调用,两者都要显式授权。

人工材料选择控件没有做。 它是一个独立的交互面(view model + shell + i18n + controller), 其中两个文件正被并发会话修改;而且赋材料现在已经有了主路径——AI 计划的 set-material, 所以外观投影不是没有驱动方的死代码。控件是下一步,接线点已经就位。