🧪 Omega Test 文档

v3.1 最后更新:2026-06-03 | 前往 Omega 工具 →
核心目标:通过 CityEngine 导出的 OBJ 生成黄金标准 JSON,精确对比 CGA.js 引擎与 CityEngine 的函数解析精度。本文档是 Omega 测试体系的唯一权威来源,配置维度调整将在此同步更新。

1. 概述

Omega Test 是 CGA.js 引擎的黄金标准对比测试框架。它的工作原理是:

  1. 在 CityEngine 中应用一个 CGA 规则(如 extrude(10))到标准 footprint
  2. 导出最终 3D 模型为 Wavefront OBJ 格式
  3. 通过 Omega 工具上传 OBJ,填写完整的元数据
  4. 自动生成包含几何数据、Scope、对比策略的黄金标准 JSON
  5. 将 JSON 放入测试套件,对比 CGA.js 引擎的输出

1.1 测试基础设施

📐 几何对比器
顶点数、面数、包围盒(BBox)、Scope 矩阵、NaN/Inf 检查、退化面检测、法线一致性验证。支持分层对比策略。
🏭 Shape 工厂
6 种标准 footprint 预设(正方形/长方形/L形/U形/极小/极大),自动生成 vertices + faces + scope + pivot。
🏃 测试运行器
Golden Runner(黄金标准对比)、Boundary Runner(边界条件测试)、Regression Guard(回归防护)。
🔧 后端转换
FastAPI /api/v1/omega/convert 接收 OBJ + 元数据,调用 obj_to_json.py 解析并组装完整 JSON。

1.2 架构级修补(8 项核心基础设施)

模块 说明 状态
unit_system单位配置(米/英尺/厘米),GlobalUnits 单例✅ 已创建,待接入几何函数
crs坐标系管理,CRSConfig✅ 已创建
randomPark-Miller LCG 确定性随机,GlobalRNG✅ 已创建
scope_matrix正交归一化验证与修复✅ 已创建
attribute_system属性注入与继承,GlobalAttributes✅ 已创建
comp_labels组件面标签系统(top/bottom/left/right/front/back)✅ 已创建
error_handler诊断日志与错误分级✅ 已创建
uv_systemUV 投影系统,GlobalUVProjections✅ 已创建

2. 黄金标准 JSON 结构

Omega 工具生成的 JSON 包含 5 个顶级字段:

{
  "_meta":       { ... },   // 测试元数据(函数、参数、版本、运行环境、对比策略)
  "cga":        "Lot --> extrude(10)",  // CGA 规则源码
  "input":      { ... },   // 初始 Shape(vertices + faces + scope + pivot)
  "expected":   { ... },   // CityEngine 输出的几何数据
  "notes":      { ... }    // 关键检查项、CE 行为说明、边界标签
}

2.1 _meta — 测试元数据

字段 类型 说明
functionstring 必填被测函数名,如 extrude, roofHip, setback
paramsarray函数参数 JSON 数组,如 [10][30, "shape=L"]
input_shapestring 必填输入形状类型:square / rectangle / L_shape / U_shape / concave / with_hole
descriptionstring测试用例目的描述
sourcestringCityEngine 版本:CityEngine_2021.1 ~ 2025.1
exported_bystring转换工具标识,固定为 omega-converter
versionnumberJSON 格式版本,当前为 1
runtimeobject运行环境配置,见 §3.3
comparisonobject对比策略配置,见 §3.4

2.2 input — 初始 Shape

"input": {
  "vertices": [
    {"x": 0, "y": 0, "z": 0},
    {"x": 10, "y": 0, "z": 0},
    {"x": 10, "y": 0, "z": 10},
    {"x": 0, "y": 0, "z": 10}
  ],
  "faces": [
    {"indices": [0,1,2,3], "normal": {"x":0,"y":1,"z":0}}
  ],
  "scope": {"sx":10, "sy":0, "sz":10,
            "tx":0, "ty":0, "tz":0,
            "rx":0, "ry":0, "rz":0},
  "pivot": {"x":0, "y":0, "z":0}
}

2.3 expected — CityEngine 输出

"expected": {
  "vertex_count": 24,
  "face_count": 10,
  "vertices": [[0,0,0], [10,0,0,] ...],
  "faces": [[0,1,2], [0,2,3], ...],
  "bbox": {
    "min": {"x": 0, "y": 0, "z": 0},
    "max": {"x": 10, "y": 10, "z": 10}
  },
  "scope": {"sx":10, "sy":10, "sz":10}
}

2.4 notes — 测试备注

"notes": {
  "critical_checks": [
    "顶点数应为8(4底+4顶)",
    "面数应为6(4侧+顶+底)",
    "顶面法向必须向上(0,1,0)"
  ],
  "obj_precision_warning": "顶点坐标精度受限于OBJ格式(6位小数),对比时使用 epsilon=1e-4",
  "cityengine_behavior": {
    "overhang": 0.5,
    "miter_limit": 0.3,
    "known_cityengine_behavior": "CityEngine在L形凹角处会生成内部脊线",
    "cgajs_approximation": "当前为简化实现,未处理凹角缝合",
    "boundary_tags": ["extreme_ratio"]
  }
}

3. 配置维度总览

Omega 工具从几何、运行环境、对比策略、CityEngine 特殊行为四个维度采集 20+ 个配置项。精确填写这些字段是测试可信度的关键。

3.1 基础元数据

字段 Omega 表单位置 用途与填写建议
function 函数名 * 被测函数名。必须使用引擎内部注册的函数名(如 roofHip 而非 roof_hip)。
params 参数 (JSON 数组) 函数参数。屋顶函数的 overhang 参数需单独在 overhang 字段中记录。
input_shape 输入形状 从下拉菜单选择。如果使用自定义 footprint(非 6 种预设),选择最接近的类型并在描述中说明。
ce_version CityEngine 版本 精确到 minor 版本(如 2023.1)。不同版本的三角化策略可能存在差异。
cga CGA 规则 完整的 CGA 规则源码。用于复现和文档记录。
description 描述 一句话说明此测试用例的目的。例如:"验证 extrude 在 10m 高度下的顶点分布"。
critical_checks 关键检查项 每行一个检查点。这是测试失败时最重要的诊断线索。

3.2 初始 Scope 配置(⚙️ 高级)

为什么重要? 很多引擎实现只测试了轴对齐、无旋转、原点的 trivial 情况。实际 CityEngine 中 footprint 可能是旋转过的,如果引擎内部错误地使用了世界坐标而非局部 Scope 坐标,结果会完全不同。
字段 默认值 测试意义
scope.rx / ry / rz Scope 旋转角度。roofGable 的脊线方向、split(x) 的轴向判断、comp(f) 的面法向分类对此敏感。
scope.tx / ty / tz 0 世界坐标平移。验证函数在非原点输入下是否行为一致。
scope.sx / sy / sz 1.0 非均匀缩放。extrudescale(2,1,1)split 是否按新尺寸切分。
推荐 Scope 测试矩阵
测试场景rxryrztxtytzsxsysz
基准(默认)000000111
Y轴旋转45°0045000111
非均匀缩放00000020.51
远离原点00010050-30111
组合变换1503010051.512

3.3 运行环境(🔧 高级)

字段 默认值 用途
seedian 12345 随机种子,控制 p() / rand() 的确定性序列。同一个 CGA 规则用不同种子应产生不同但各自确定的结果。
max_recursion_depth 300 复杂嵌套规则(如 A --> B --> A --> B...)的终止条件。CityEngine 默认值约为 300。
attributes {} 外部注入 attr 值(如 attr height = 20 从 GIS/Shapefile 读取)。JSON 对象格式。
unit meter 当前固定为 meter。单位系统已创建但未接入几何函数(默认米制无影响)。

3.4 对比策略(📏 高级)

这是避免"假阳性"失败的关键。 如果强制所有函数都用 vertex_exact + epsilon=1e-4,roof 系列几乎不可能通过(CityEngine 的三角化策略和我们不同)。分层对比策略是"精准测试"的核心。
字段 选项 说明
epsilon 1e-4 / 1e-3 / 0.01 顶点坐标容差(米)。简单几何用 1e-4;roof 系列用 1e-3(OBJ 导出已有精度损失)。
mode vertex_exact / bbox / topology / bbox+vertex vertex_exact:顶点坐标逐点对比(最严格)
bbox:只比包围盒(最宽松,用于近似验证)
topology:只比面数/顶点数/拓扑连通性
bbox+vertex:先比 BBox 再比顶点(推荐平衡策略)
ignore 数组 可选项:normals / uvs / colors / scope_rotation。CityEngine 和我们的法线计算策略可能不同。

3.5 CityEngine 特殊行为(🏗️ 高级)

字段 类型 说明
overhang number 屋顶悬挑距离(roofHip(30, 1.0) 中的 1.0)。影响 roof 系列的顶面尺寸。
miter_limit number offset / setback 的斜接限制,影响凹角处的面生成策略。
known_cityengine_behavior string CityEngine 的特殊行为描述。例如:"CityEngine 在 L 形凹角处会生成内部脊线"。
cgajs_approximation string 我们当前实现的已知近似/简化。例如:"当前为简化实现,未处理凹角缝合"。

3.6 边界条件标签

标签 触发条件 CityEngine 预期行为
zero_size 输入尺寸为零(如 extrude(0) 退化为二维面或空几何,不崩溃
degenerate 退化多边形(共线顶点、零面积面) 自动剔除退化面,保留有效部分
extreme_ratio 极端长宽比(>100:1 或 <1:100) 正常生成,数值稳定
negative_param 负参数(如 extrude(-5) 方向反转或报错(视函数而定)
overflow 尺寸溢出浮点精度(>1e6 或 <1e-6) 不生成 NaN/Inf
setback 在退台距离大于 footprint 尺寸时,CityEngine 会退化为一条线而不是崩溃。记录这些边界行为,才能确保我们的引擎也优雅降级而不是抛异常。

4. CityEngine OBJ 导出设置详细指南

OBJ 是 Omega 测试的唯一输入格式。正确的导出设置直接决定黄金标准 JSON 的质量和对比可信度。

核心原则:一个 OBJ = 一个函数 + 一个输入 Shape 的最终结果。不要在一个 OBJ 中包含多个模型或多个生成阶段的几何。

4.1 导出前准备

  1. 在 CityEngine 中写好最小 CGA 规则,确保只调用一个目标函数(如 extrude(10)
  2. 选中场景中的初始 Shape(footprint),应用规则(Generate)
  3. 在 Scene 窗口中,只选中最终生成的 3D 模型(不要选中初始 footprint)
  4. 菜单栏 → FileExport Models...

4.2 基础设置(General)

参数 推荐设置 说明
Format Wavefront OBJ 我们的解析器专为此格式优化。不支持 FBX/DAE/COLLADA。
File {函数}_{参数}_{形状}.obj 命名规范例:extrude_10_square.objroofHip_30_Lshape.obj
Export selected models only 勾选 避免导出场景中其他模型导致几何混杂。
Coordinate system Cartesian(默认) 保持与引擎一致的直角坐标系。
Up axis Y 我们的引擎使用 Y-up。不要选 Z-up,否则屋顶方向会完全相反。

4.3 几何设置(Geometry)

参数 推荐设置 说明
Triangulate geometry ⚠️ 视函数而定 §4.5 三角化策略
Merge geometry 勾选 将同一模型的所有 mesh 合并为一个 object。避免多 object 导致面索引混乱。
Precision 6 或更高 默认 6 位小数足够。roof 系列建议 8(斜面顶点对精度敏感)。
Scale 1.0 不要缩放,保持原始单位(米)。

4.4 法线与 UV(Normals & Texture Coordinates)

参数 推荐设置 说明
Export normals 勾选 生成 vn 数据。我们的解析器支持,且可在对比时选择忽略法线。
Export texture coordinates ✅(如涉及 UV 函数)
❌(纯几何函数)
setupProjection / texture / color 相关测试需要 UV。
Normal type Vertex normals(默认) 每顶点法线,与 Three.js 的 BufferGeometry 一致。

4.5 材质(Materials)

参数 推荐设置 说明
Export materials 不勾选 黄金标准测试只关注几何。材质会增加文件体积且无意义。解析器会跳过 usemtl

4.6 三角化策略(最关键)

这是最容易导致面数不一致的问题。CityEngine 对某些面保持四边形,对其他面自动三角化。我们的解析器支持多边形(face indices > 3),但对比时的 faceCount 必须严格一致

测试函数 Triangulate 原因
extrude 不勾选 生成的侧面和顶/底面通常是规整的四边形。保持四边形,面数 = 4 侧面 + 2 端面 = 6。
split 不勾选 切分后的面保持四边形。三角化会导致面数不可预测地翻倍。
comp(f) 不勾选 组件分离后的面保持原始形状。
setback 不勾选 退台后的面保持多边形。
offset 不勾选 偏移后的面保持多边形。
roofHip 勾选 屋顶函数 CityEngine 内部会三角化。如果不勾选,对比时面数可能不一致。
roofGable 勾选 同上。三角面是 roof 系列的内部表示。
roofPyramid 勾选 金字塔屋顶必然三角化。
roofShed 勾选 单坡屋顶通常三角化。
primitive 系列 勾选 圆柱/球体/圆锥 CityEngine 会参数化三角化。
验证方法:导出后打开 OBJ 文件,检查 f 行。如果每行有 3 个索引(如 f 1 2 3),说明是三角化;如果有 4 个(如 f 1 2 3 4),是四边形。我们的解析器两者都支持

4.7 导出后验证清单

导出完成后,在文本编辑器中打开 OBJ 文件,确认以下结构存在:

# 顶点坐标(至少3列,X Y Z)
v 0.000000 0.000000 0.000000
v 10.000000 0.000000 0.000000
v 10.000000 0.000000 10.000000
v 0.000000 0.000000 10.000000

# 法线(如果勾选了导出法线)
vn 0.000000 1.000000 0.000000

# 面索引(1-based,我们的解析器会自动转为 0-based)
# 四边形格式
f 1 2 3 4
# 或三角化格式
f 1 2 3
f 1 3 4

常见问题排查

现象 原因 解决
OBJ 里只有 v 没有 f 选中了初始 footprint 而非最终模型 重新选中最终生成的 3D 模型再导出
坐标值特别大(如 10000+) 坐标系未投影 / 使用了地理坐标 确保 Shape 是米制直角坐标,或检查 Scene 的 Coordinate System
f 行包含负数索引(如 f -1 -2 -3 CityEngine 某些版本的特殊导出 我们的解析器不支持负数索引,需要手动改为正数
多个 o (object) 块 未勾选 Merge geometry 勾选后重新导出,或手动删除多余的 object 块
面索引包含 v/vt/vn 但我们不需要 vt/vn OBJ 标准格式,不影响 我们的解析器完全支持 v/vt/vnv//vnv/vtv 四种格式

4.8 与 Omega.html 的字段映射

CityEngine 设置 Omega.html 对应字段
是否 Triangulate notes.cityengine_behavior.known_cityengine_behavior
(如"CityEngine 对 roof 面进行了三角化")
Export normals 勾选状态 ignoreTags → 若未导出法线则勾选"忽略法线对比"
坐标异常大 boundary_tags → 勾选"尺寸溢出"
实际单位不是米 runtime.unit → 改为实际单位

5. 函数推荐配置速查表

当您为具体函数创建黄金标准时,可直接套用下表的推荐配置:

函数 compareMode epsilon Triangulate 必须测试的边界条件
extrude vertex_exact 1e-4 零高度、负高度、非均匀 footprint
split vertex_exact 1e-4 尺寸之和>1、尺寸之和<1、浮动~尺寸、零宽度切分
comp(f) topology 1e-4 所有 6 个面方向(top/bottom/left/right/front/back)
comp(e) vertex_exact 1e-4 边界边、共享边、退化边
comp(v) vertex_exact 1e-4 所有顶点位置
roofHip bbox+vertex 1e-3 凹角、带孔洞、极端长宽比、不同 overhang
roofGable bbox+vertex 1e-3 脊线方向、非矩形 footprint
roofPyramid bbox+vertex 1e-3 非正方形底面、极扁/极高
setback vertex_exact 1e-4 退台>尺寸、凹多边形、零退台、极大退台
offset vertex_exact 1e-4 内缩导致退化、斜接限制、负偏移
shapeL / shapeU / shapeO vertex_exact 1e-4 参数边界(如 L 的退台为 0 或等于边长)
primitive 系列 bbox+vertex 1e-3 分段数、半径为 0、高度为 0
color / set topology 1e-4 几何不变,只验证属性传递
texture / setupProjection vertex_exact 1e-4 UV 范围、投影方向、重复模式
rotate / translate / scale vertex_exact 1e-4 组合变换、零缩放、负缩放
nil topology 1e-4 几何为空,验证规则终止

6. 完整测试流程

  1. 编写最小 CGA 规则
    只包含一个目标函数,例如:
    Lot --> extrude(10)Lot --> roofHip(30, 0.5)
  2. 选择或创建标准 footprint
    在 CityEngine 中选中初始 Shape → Generate。
    如果 footprint 不在 6 种预设内,可在 Omega 工具中手动填写 vertices + faces。
  3. 选中最终模型并导出
    Scene 窗口中只选中最终 3D 模型(高亮状态)。
    File → Export Models → Wavefront OBJ,按 §4 设置参数。
  4. 命名文件
    {函数}_{参数}_{形状}.obj,例:roofHip_30_Lshape.obj
  5. 快速验证 OBJ 内容
    文本编辑器打开,确认有 vf 行,且 f 的索引数量符合三角化策略。
  6. 上传 Omega 工具并填写元数据
    访问 /omega.html,拖拽上传 OBJ。
    §3 精确填写所有配置维度。
  7. 生成并下载 JSON
    点击"开始转换",验证 JSON 内容完整后下载。
    文件名自动为:{函数名}_{OBJ文件名}.json
  8. 放入测试套件
    将 JSON 放入 /omega-test/cases/tier_s/ 目录,编写对应的 .test.ts 用例。
  9. 运行对比测试
    cd /omega-test && npm test。观察是否通过,根据 errors/warnings 修复引擎。
  10. 记录已知差异
    如果 CityEngine 行为与引擎输出有预期内的差异(如三角化策略不同),在 notes.cityengine_behavior 中记录,并调整 comparison.ignorecomparison.mode

7. 常见问题

Q1: 为什么 vertex_exact 模式下 roof 系列总是失败?

CityEngine 的 roof 函数内部使用参数化曲面 + 自适应三角化,其顶点分布策略(如脊线细分、边缘插值)与我们的简化实现不同。即使几何形状正确,顶点顺序和细分密度也可能不同。

解决:将 compareMode 改为 bbox+vertexepsilon 放宽到 1e-3,并在 notes 中记录三角化策略差异。

Q2: 面数一致但顶点数不一致,是什么原因?

CityEngine 在导出时可能对共享顶点进行去重复制,导致同样的几何有不同的顶点数。OBJ 格式本身不强制共享顶点。

排查

  • 检查是否勾选了 Merge geometry(未合并可能导致重复顶点)
  • 检查 OBJ 中是否有重复的 v 行(CityEngine 有时会复制顶点以支持硬边法线)
  • 如果顶点数差异在可接受范围(如 ±4 以内),考虑改用 topology 模式
Q3: 同一个 CGA 规则,不同 CityEngine 版本导出的 OBJ 不一样?

是的。CityEngine 在 2022.x → 2023.x 之间对 roof 函数的三角化策略有调整。2024.x 引入了新的曲面细分算法。

建议

  • 固定一个主版本作为黄金标准(推荐 2023.1,稳定性好)
  • _meta.source 中精确记录版本号
  • 如果多版本差异大,可为同一函数生成多个 JSON(如 roofHip_2023.jsonroofHip_2025.json
Q4: 我可以不用 CityEngine,用 Blender / Rhino 生成 OBJ 吗?

不推荐。 Omega 测试的核心是"与 CityEngine 行为一致"。Blender/Rhino 的几何生成逻辑与 CityEngine 完全不同(如 roof 的脊线计算、setback 的倒角策略)。

如果您没有 CityEngine,可以:

  • 联系我们获取已有的黄金标准 JSON
  • 使用预设 footprint + 手动计算 expected 值(仅限简单函数如 extrude)
  • _meta.source 标记为 manual_calculation 并在 notes 中说明
Q5: OBJ 文件太大(>10MB)怎么办?

如果 CityEngine 生成了极高细分的几何(如 primitiveCylinder 的 segments 过多),JSON 会很大。

建议

  • 使用简化的 CGA 规则参数(如减少 cylinder 的 segment 数)
  • 在 Omega 工具中,JSON 生成是服务器端处理,10MB 以内通常无问题
  • 如果超过 20MB,考虑只保留关键几何特征,或分段导出

8. 变更记录

本文档是 Omega 测试体系的唯一权威来源。所有配置维度的调整将在此同步更新。

版本 日期 变更内容
v3.1 2026-06-03 新增:运行环境配置(seedian/maxRecursion/attributes/unit)、对比策略(epsilon/mode/ignore)、CityEngine 特殊行为(overhang/miter_limit/known_behavior/boundary_tags)、初始 Scope 微调(rx/ry/rz/tx/ty/tz/sx/sy/sz)。
新增:6 种标准 footprint 预设(正方形/长方形/L形/U形/极小/极大)。
修复:OBJ 解析器兼容 legacy flat format({vertices:[]})和 undefined geometry。
文档:创建本文档页面 omega-docs.html
v3.0 2026-06-02 新增:Omega Test 基础设施(geometry_comparator, shape_factory, golden/boundary/regression runners)。
新增:8 项架构级核心修补(unit_system, crs, random, scope_matrix, attribute_system, comp_labels, error_handler, uv_system)。
新增:OBJ → JSON 工具链(obj_to_json.py)。
新增:Omega 前端工具(拖拽上传 + 自动转换 + 黄金标准 JSON 生成)。
v2.x 2026-05 IDE 三维解析修复、terser property mangling 移除、初始 Shape 空值崩溃修复、NL2CGA 预留接口。
v1.x 2026-04 引擎基础架构、ANTLR4 CGA 解析器、Three.js 渲染管线、FastAPI 后端、前端 IDE。
如何追踪变更:本文档托管于 /www/wwwroot/www.cgajs.com/omega-docs.html,源码版本与 omega.html.footer 中的版本号保持一致(当前 v3.1)。如有配置维度变更,将在此表格追加记录并提升版本号。