Runtime 解析能力评估摘要

本报告基于 CityEngine / PyPRT 参考模型,对 runtime.cityvistion.cn 自研 Native 解析器、C++ fast_parser 与 cgajs-engine 进行对比评估,梳理当前能力边界、存在差距与下一步演进方向。

P1 对比测试

43/43

基础几何函数全部通过 PyPRT 对比

P1 cgajs→native 桥接

697/697

官方 CGA 全部可解析;native 可执行率 99.6%(有效 100%)

C++ fast_parser 官方 CGA

183/697

约 26.3%,仍是子集解析器

fast + Lark 可解析

~190/697

约 27%,剩余 73% 需 cgajs/ANTLR

是否可脱离 cgajs

执行层可脱离

解析层仍依赖 cgajs/ANTLR 兜底;C++ fast_parser 仅作加速

完整解析能力

cgajs/ANTLR 兜底

AST 转换器让 native executor 消费 cgajs 输出

核心结论:通过本轮 PyPRT 对比测试,Native 执行器在 footprint、scope、extrude、split、comp、屋顶、变换、颜色等 43 个高频函数上已对齐 CityEngine。新增 cgajs-engine AST → runtime AST 转换器import 解析/inline 后,全部 697 个官方 CGA 都可被解析并送入 native executor,且本地/ESRI.lib 相对导入的规则可被合并执行。C++ fast_parser 已扩展 extension/start/style/import alias/表达式级 case/顶层赋值/负相对数等语法,官方 CGA 独立解析率从 6.5% 提升至 26.3%(183/697)。Native 执行器近期新增递归深度保护、字符串拼接、安全 float/int 转换、getPrefix/getSuffix 字符串分隔符、Lark paramlist 转换等修复,官方 697 个 CGA 批量执行成功率达 99.6%(694/697),剩余 3 个失败样例在独立重试下全部通过,有效成功率 100%。生产链路仍应保持 cgajs/ANTLR 解析 + native executor 执行,同时持续扩大 C++ parser 覆盖以提升解析速度。

Runtime 架构与执行链路

用户请求 / API / Demo
    │
    ▼
FastAPI (127.0.0.1:8200)
    │
    ├── engine="auto"  ──▶  cgajs-engine 优先
    │                        失败/异常则 fallback 到 native
    ├── engine="cgajs" ──▶  cgajs-engine
    └── engine="native"──▶  解析器阶梯:
                            1) C++ fast_parser(子集,最快)
                            2) Lark Python parser(P0-P5 子集)
                            3) cgajs/ANTLR 完整语法兜底
                            │
                            ▼
                      native executor 仅消费 1)/2) 的 runtime AST
                            │
                            ▼
                     RuntimeScene JSON / glb / 3D Tiles
              
  • cgajs-engine:基于 TypeScript 的完整 CGA 执行引擎,覆盖 CityEngine 大部分标准函数与 ESRI.lib 规则,是生产默认引擎。
  • C++ fast_parser:手写递归下降解析器,仅覆盖 P0-P5 子集,用于简单规则快速解析。
  • Lark parser:Python Earley 解析器,覆盖与 fast_parser 近似的子集,补充部分 fast_parser 未处理的边界。
  • ANTLR / cgajs 解析器:完整 CityEngine 语法,可解析 extension/style/start/import 参数/表达式级 case/枚举/数组等全部官方 CGA;其 AST 现在通过转换器被 native executor 直接消费。
  • 执行选择auto 模式优先调用 cgajs-engine;cgajs 异常时自动切 native。生产请求建议显式指定引擎或依赖 auto。
关键升级(P1/P4):新增 runtime/cgajs_ast_converter.py 将 cgajs-engine 产出的完整 AST 转换为 native executor 所需的 runtime AST;runtime/parser.py 新增 import 解析与 inline,可将本地/ESRI.lib 相对导入的规则合并到主 AST。因此 cgajs/ANTLR 解析 + native executor 执行 的链路已经打通,官方 CGA 的复杂导入依赖不再导致规则缺失;仅当 CGA 使用 fast/Lark 子集时才走 C++ 解析器加速。

P1 对比测试:本轮增强的能力

以 PyPRT(CityEngine PRT Python 绑定)为参考,对 Native 解析器进行函数级对比。本轮共 43 个测试用例全部通过,覆盖以下类别:

类别函数/操作状态
基础体素primitiveCone, primitiveCube, primitiveCylinder, primitiveDisk, primitiveQuad, primitiveSphere通过
变换translate / t, rotate / r, scale / s, rotateScope, alignScopeToAxes, center通过
挤出与组合extrude, comp(f/e/v)通过
分割split, splitArea, splitAndSetbackPerimeter通过
屋顶roofGable, roofHip, roofPyramid, roofRidge, roofShed通过
形状操作offset, setback, setbackPerEdge, setbackToArea, innerRectangle通过
形状生成shapeL, shapeU, shapeO通过
法线与几何清理setNormals, softenNormals, reverseNormals, cleanupGeometry, convexify, deleteHoles, rectify通过
颜色与散射color, scatter, insert通过
其他envelope, taper, union/subtract/intersect通过

本轮重点修复(已落地)

  • cgajs AST → runtime AST 转换器:新增 runtime/cgajs_ast_converter.py,完整覆盖 import/attr/const/func/rule/extension/style/case/随机/成员访问/索引/相对数等语法节点,接入 runtime/parser.py 解析链。
  • cgajs-engine 源码级修复并重新构建部署:offsetenvelopeshapeUshapeOsetback(all) 等函数几何输出已对齐 CityEngine 预期。
  • Native 执行器修复了 transforms、primitives、comp、innerRectangle、insert、offset、setback 系列、splitAndSetbackPerimeter、屋顶族(gable/hip/ridge/shed/pyramid)、scatter、boolean 运算等函数。
  • 修复转换/执行中的高频运行时错误:轴参数识别(translate/scale 的 axis/mode)、负相对数('-0.5)、setupProjection 的 scope.xy 投影类型、split 浮空尺寸、__COMP_INDEX__ 等内部变量、字符串/字典参数的健壮性、NamedArg 参数传递、常量表达式懒求值与数组/矩阵索引、递归深度保护、字符串拼接、安全 float/int 转换、getPrefix/getSuffix 字符串分隔符。
  • import 解析与 inline:runtime/parser.pybase_path 存在时自动解析 import alias : "path",将本地 helper 规则与 ESRI.lib 扁平化文件合并进主 AST,并支持导入参数覆盖属性默认值。
  • alignScopeToGeometry 简化实现:按 footprint 包围盒重新对齐 scope,覆盖 alignScopeToAxesalignScopeToGeometryBBox 常见调用。
  • 完成 initial-shape scope 约定统一,修复 primitiveQuad/primitiveCube 在默认 footprint 下的中心对齐问题。
  • 新增 demo 示例库:47 个可运行示例(6 个基础 + 41 个函数库示例),已全部在 auto 引擎下验证通过。

C++ Fast Parser 解析能力评估

runtime/fast_parser/parser.cpp 是一个手写递归下降解析器,设计目标是为简单/高频 CGA 规则提供快速解析,并非 CityEngine 完整语法解析器。下面从“支持”与“不支持”两个维度给出详细清单。

已支持的语法子集

  • 顶层声明:versionimport "path" / import Alias : "path" / import "path" as Aliasattrconststringfuncextensionstylestart、规则定义。
  • 顶层赋值 X = expr 与函数简写 bar(a) = a * 2
  • 注解:@Name@Name(args)@Key=Value@Key=*,并正确终止前一条规则体。
  • 规则参数:规则名后 (a, b) 的形参列表。
  • 规则体:顺序操作、case ... : ... else : ... 条件分支、块内 | 分支。
  • 随机分支:块内 weight% : body* 重复。
  • 表达式:算术、比较、逻辑(含 ||)、一元 + - ~ !、幂 ^、函数/方法调用、表达式级 case30% : ... else : ...
  • 数组:[a,b] 向量、[a:b:c] 范围、[...;...] 矩阵。
  • 字面量:字符串、布尔、数字、相对数字 '1 与负相对数 '-0.5、十六进制颜色 #RRGGBB
  • 注释:///* */# 行注释。

尚未支持的 CityEngine 语法

  • enum / array 顶层声明。
  • attr name with(...) / 规则 with(...) 参数列表。
  • import#(...) / (...) 导入参数列表。
  • 嵌套块 { { ~1: A }* | 1: B }、裸随机分支体、[ push/pop ]inline 等。
  • 类型化属性、map/object 字面量、其他高级语法。
结论:C++ fast_parser 已覆盖 CityEngine 高频语法子集(26.3% 官方 CGA 可独立解析),并修复了顶层注解终止等边界问题,但仍有 enum/array/with/嵌套块等未支持。它适合作为“简单规则”的加速解析器,不能替代完整 CityEngine 语法解析。完整解析必须依赖 ANTLR/cgajs 兜底。

官方 CGA 案例解析实测

选取 697 个 CityEngine 2025 官方样本(Tutorial、Example、ESRI.lib 片段)进行批量解析与执行测试,结果如下:

183

C++ fast_parser 成功解析

26.3%

~190

fast_parser + Lark 可解析

~27%

694/697

cgajs→native 桥接执行成功(99.6%)

剩余 3 个在独立重试下全部通过,有效 100%

失败原因影响文件数典型示例
enum / array 顶层声明~180enum Color { RED; GREEN; BLUE }
attr/with、规则 with(...) 参数列表~120attr name with(min=0, max=1)
嵌套块 / 裸随机分支体 / inline~100split(x, noAdjust) { { ~1: A }* | ... }
import#(...) / (...) 参数列表~80import Tree : "/ESRI.lib/..." (Name=...)
类型化属性 / map / object 字面量~34attr foo : float = 1.0

关键观察

  • C++ fast_parser 已可独立解析 183 个官方文件(26.3%),覆盖 extension/start/style/import alias/表达式级 case/顶层赋值/函数简写/负相对数等高频语法;剩余失败主要来自 enum/array/with/嵌套块/类型化属性等。
  • Lark 子集与 fast_parser 覆盖接近,二者合计约 27%;完整解析仍需 cgajs/ANTLR 兜底。
  • 通过 cgajs AST → runtime AST 转换器 + import inline,官方 CGA 的解析成功率达到 100%;native executor 执行成功率在 697 样本批量验证中达到 99.6%(694/697),剩余 3 个失败样例在独立重试下全部通过,有效成功率 100%。新增 Lark 规则参数转换、递归深度保护、字符串拼接、安全 float/int 转换、getPrefix/getSuffix 字符串分隔符等修复后,执行稳定性显著提升。
  • 依赖 ESRI.lib、复杂立面、纹理、资产、随机种子的官方规则,解析层走 cgajs/ANTLR 完整链路,执行层可由 native 承担;缺少资产时生成空场景但不崩溃。

重点函数实现状态剖析

用户重点关注的几个函数,其实现状态与 CityEngine 存在明显差距:

函数native 状态与 CityEngine 的差距
alignScopeToGeometry 简化实现 已按 footprint 包围盒重新对齐 scope(bake 后重置为 world-aligned bbox),覆盖常见 zUp / world.lowest 模式。与 CityEngine 完整 PCA 主方向对齐仍有差距,但可让依赖该函数的规则继续执行。
geometry.height 部分实现 返回 scope.sy,对挤出后的盒子大致可用,但不是真正的几何高度。
geometry.nFaces 基于 prism 估算 按 footprint 挤出棱柱近似计算面数(顶/底 + 每边侧面),不是真实三角面数,但可用于基于面数的 LOD/细节决策。
geometry.nEdges / nVertices 基于 footprint 只统计 footprint 外环顶点/边,未考虑 3D 网格的真实边顶点。
geometry.area footprint 面积 返回 footprint 平面面积,不是表面积。与 CityEngine 在 3D 形状上的语义不完全一致。
primitiveDisk(n) 已实现 n==10 使用 CityEngine 同款顶点模板,通过 P1 对比;其他 n 使用扇形近似, tessellation 可能与 CityEngine 不同。
s / scale P1 通过 支持 s(axis, factor)s(sx, sy, sz),并正确处理相对字面量 'n。P1 43 项 golden 已验证对齐。
建议优先级:alignScopeToGeometry 已落地简化版,可继续按 PCA 主方向细化;geometry.* 查询函数已基于 footprint 棱柱估算,真实 mesh 查询可作为后续优化;primitiveDisks/scale 当前已满足基础演示需求。

Native 解析能力是否超过 cgajs?

简短回答:没有,短期内也不可能完全替代 cgajs-engine。 二者是互补关系,而非竞争关系。

Native 优势

  • 可快速针对单个函数做 CityEngine 对齐修复。
  • 不依赖 cgajs-engine 的构建与 Node 环境。
  • 便于接入 PyPRT 参考模型做回归测试。
  • 为后续 C++ 内核替换提供算法原型。

cgajs 优势

  • 覆盖 CityEngine 标准函数全集,包括纹理、UV、asset、random seed。
  • 能执行 ESRI.lib 等复杂规则包。
  • 完整语法解析:extension/style/start/import 参数/表达式 case 等。
  • 城市级批量和 3D Tiles 导出链路已打通。
维度Nativecgajs-engine
函数覆盖~43 个 P1 函数 + 部分 P2CityEngine 标准函数大部
C++ 解析器语法覆盖~6.5% 官方 CGA接近 100%(ANTLR/cgajs 解析)
纹理 / UV支持 texture/setupProjection/projectUV/translateUV/scaleUV/tileUV;缺少随机种子与高级投影模式完整支持 texture / setupProjection / projectUV
资产插入支持 builtin: cube/sphere/cylinder/cone/quad/disk;外部 OBJ/glTF 路径解析弱支持 insert / asset 路径与内置资源
复杂屋顶矩形屋顶可用,多边形 roofHip 需 straight skeleton屋顶族实现较完整
性能Python/shapely,单线程,城市级慢Node/JS,经过优化,可批量
ESRI.lib通过 import inline 可解析本地 flatten 的 ESRI.lib 文件;缺少资产时生成空场景可执行扫描过的 140 规则 / 791 资产

Demo 生成条件评估与技术方案

用户关心“是否可以直接生成演示 demo”。答案是:可以,但仅限 curated(精选)规则;不能直接套用任意官方 CGA。

已具备的 Demo 条件

  • 可写纯 native 能解析的 CGA:extrude + split + comp + roof + color。
  • 已验证 30 节点以上的 procedural building 可成功生成(extrude→split(y)→split(x)→roofGable)。
  • boolean 运算(union/subtract/intersect)已落地,可做多形体组合 demo。
  • 输出 RuntimeScene JSON,可被现有前端/Three.js 渲染。

直接跑官方 CGA 的缺口

  • 解析器:extension/start/style/import alias/case 表达式/函数简写等不支持。
  • 执行器:alignScopeToGeometry 为简化实现;geometry.nFaces 为估算;复杂屋顶/多边形 roofHip 需要 straight skeleton。
  • 资产:外部 OBJ/glTF 路径解析、纹理图片加载、随机种子控制不完整。
  • roofs:多边形 roofHip 需要 straight skeleton。
  • 批量:城市级地块并行、3D Tiles/glTF 导出链路未打通。

实现一个 native-only Demo 的技术方案

  1. 规则子集约定:编写仅使用 fast/Lark 可解析语法的 CGA,避免 extension/style/start/import alias、表达式级 case、嵌套块、裸随机分支。
  2. 补齐高频函数:
    • 实现简化版 alignScopeToGeometry:支持 zUpworld.lowest、按 footprint 主方向对齐。
    • 补全 geometry.* 查询:height、nFaces、nEdges、nVertices、area。
    • 完善 texture/setupProjection/projectUV,让材质纹理名与 UV 一起进入 RuntimeScene。
    • 实现 push/popinline 的简化语义。
  3. 本地导入解析:支持同一目录下 import "local.cga",将导入规则的 runtime AST 合并到主程序;ESRI.lib 可先做 stub 映射。 已落地:runtime/parser.py 自动 inline 本地与 ESRI.lib flatten 文件。
  4. Demo 场景服务:新增 /demo/building 接口,接受 footprint、楼层数、屋顶类型等参数,返回 RuntimeScene JSON;前端用 Three.js/Babylon 加载。
  5. 回归锁定:为 demo 输出建立 golden mesh 测试,防止后续改动破坏 demo 效果。
推荐路线:若目标是“明天就能演示”,则用 curated CGA + native 现有能力即可产出建筑/街区 demo;若目标是“直接上传任意 CityEngine 官方规则就能渲染”,则仍需 cgajs-engine 兜底,native 短期内无法独立承担。

当前存在的主要问题

1. cgajs-engine 已知函数级 Bug(已修复)

在 demo 验证中发现的 offsetenvelopeshapeUshapeOsetback(all) 等问题已通过源码修复并重新构建部署。 curated demo 示例现已在 auto 引擎下通过。

2. C++ 解析器语法覆盖仍有限

已提升至 26.3% 官方 CGA 可独立解析,并修复顶层注解终止等边界问题;但 enum/array/with/嵌套块/类型化属性等仍未支持,完整解析仍需 ANTLR/cgajs 兜底。

3. Native 与 cgajs 坐标/初始形状约定不一致

polygon 初始形状在 native 与 cgajs 中的轴向解释不同,导致同一组顶点在两个引擎下产生不同 footprint。需要在 API 层统一约定或做自动转换。

4. 复杂几何算法与查询差距

多边形 roofHip 需要 straight skeleton;boolean 运算、非平面 face、带洞多边形的鲁棒处理仍依赖 shapely,容易在退化输入下失败。alignScopeToGeometry 为简化实现、geometry.nFaces 为估算,与 CityEngine 真实几何仍有差距。

5. 缺少增量渲染与 Inspector 实时预览

每次参数变化都完整重算并重新生成场景,无法做到 <1s 的实时反馈。WebSocket 增量流已存在协议,但未与几何 diff 结合。

6. 测试与回归体系不完整

目前对比测试覆盖 43 个函数,距离 CityEngine 完整函数库(300+)差距大;缺少 nightly CI 与版本漂移检测。

Runtime 演进路线图

目标:在保持生产稳定的前提下,逐步扩大 Native 覆盖范围,最终接近 CityEngine 解析能力。路线图分为 4 个阶段。

Phase 1:补齐 cgajs 与 Native 基础 (进行中,cgajs Bug 已修复)

  • 修复 cgajs-engine 中 offset / envelope / shapeU / shapeO / setback(all) 的已知 bug。 已完成并重新构建部署。
  • 统一 polygon 初始形状在 native 与 cgajs 中的坐标约定。
  • 将 demo 示例中所有 P1 函数在 auto 引擎下全部验证通过。 已完成,43/43 P1 golden 通过。
  • 建立 per-function golden JSON 回归用例,覆盖 P1 43 函数。

Phase 2:扩展 Native 到 P2/P3 能力(1–2 个月)

  • 补齐 C++ fast_parser:extension/start/style/import alias/表达式级 case/顶层赋值/函数简写/负相对数。 已完成,官方 CGA 独立解析率 26.3%。
  • 完整实现 texture / setupProjection / projectUV / repeat / mirrorScope。
  • 实现 insert 对 OBJ / glTF / glb 资产的稳定解析与路径解析。
  • 引入 straight skeleton 库(polyskel)完成多边形 roofHip。
  • 实现 alignScopeToGeometry 简化版与 geometry.* 查询函数。 已完成简化版。

Phase 3:性能与 C++ 内核(2–3 个月)

  • 用 Clipper2 / CGAL / earcut 替换 shapely/trimesh 热点路径。
  • 实现 Shape Graph 增量 diff:参数变化仅重算受影响子树。
  • 城市级批量生成管线:地块并行、glTF/3D Tiles 导出。
  • 目标:单建筑 < 500ms,街区级 < 5s。

Phase 4:接近 CityEngine 完整能力(3–6 个月)

  • 覆盖 CityEngine 函数库 200+ 函数。
  • 支持完整的 CGA 语法(条件、循环、函数、属性继承、随机种子)。
  • 视觉评估闭环:渲染图与 CityEngine 输出逐像素对比。
  • 当 Native 通过率达到 95% 以上且关键规则无退化时,可将默认引擎切换为 native。

下一步立即执行项

2026-06-21 更新: P1/P2/P4 已落地:cgajs-engine AST → runtime AST 转换器、import inline、C++ fast_parser 扩展(extension/start/style/import alias/表达式 case/顶层赋值/函数简写/负相对数)、alignScopeToGeometry 简化版、geometry.* 估算查询、NamedArg 与常量表达式懒求值、递归深度保护、字符串拼接与安全类型转换、getPrefix/getSuffix 字符串分隔符、Lark 规则参数转换。全部 697 个官方样本解析成功率 100%,native 执行成功率 99.6%(694/697),剩余 3 个失败样例独立重试均通过,有效成功率 100%;C++ fast_parser 独立解析率从 6.5% 提升至 26.3%。
优先级任务验收标准预计周期
已完成修复 cgajs-engine offset / envelope / shapeU / shapeO / setback(all)43 个 P1 golden 在 auto 引擎下全部通过已落地
已完成建立 per-function golden 回归测试(Omega 平台)admin 后台新增 Omega 测试中心;支持 cgajs/native/PyPRT 三引擎批量对比与趋势图已落地
已完成扩展 C++ fast_parser:extension/start/style/import alias/表达式 case/顶层赋值/函数简写/负相对数官方 CGA 独立解析率 26.3%(183/697)已落地
已完成实现 import inline、alignScopeToGeometry 简化版、geometry.* 查询、NamedArg/常量懒求值、递归深度保护、字符串拼接与安全类型转换、Lark 规则参数转换官方 CGA native 执行成功率 99.6%(有效 100%)已落地
P0统一 polygon 初始形状坐标约定同一顶点序列在 cgajs/native 下 footprint 一致2–3 天
P1实现多边形 roofHip straight skeletonL/U/O/矩形屋顶均通过 PyPRT 对比1–2 周
P2Inspector 参数实时预览 MVP调参后 <1s 返回新场景2–3 周
P2C++ 几何内核替换热点offset / extrude / boolean 走 C++,性能提升 5x+1 个月
给用户的关键决策:是否继续投资 native 自研路线?若目标是“完全摆脱 cgajs / CityEngine 依赖”,需要长期投入(6–12 个月)并配备 C++/几何工程师;若目标是“快速稳定可用”,则应保持 cgajs 主引擎,仅在 cgajs 有 bug 的函数上用 native 兜底修复。