CityEngine CGA 官方操作函数实现文档

createurban.com (gromgull/cgajs) 引擎扩展 — 基于 Three.js 的 CGA Shape Grammar 运行时

47
新增函数
7
功能大类
62
总支持函数
15+6
原有+新增Body操作

📋 实现概述

本次扩展在 src/cgaprocessor.js 中通过 register_func() 机制注册了 47 个 CityEngine 官方操作函数。所有函数均遵循现有引擎架构:

同时修复了 src/cgaparser.js 中的模块路径问题(require("cga")require("./cga")),使 Node.js 直接运行测试成为可能。

🧊 几何创建函数 4

primitiveQuad(w, h)

Geometry

创建四边形平面,默认适配当前 scope 的 x/z 尺寸。

参数: w 宽度, h 高度
实现: THREE.PlaneGeometry → 绕 X 轴旋转 -90° → 平移到 boundingBox 中心。
// 创建一个 2x3 的平面
Lot --> primitiveQuad(2, 3) color("red")

primitiveDisk(r, seg)

Geometry

创建圆盘(圆形平面),默认适配 scope 的 x/z 最大值的一半作为半径。

参数: r 半径, seg 分段数(默认 32)
实现: THREE.CircleGeometry → 绕 X 轴旋转 -90° → 平移到中心。
// 创建半径为 1.5 的圆盘
Lot --> primitiveDisk(1.5, 32)

primitiveCone(r, h, seg)

Geometry

创建圆锥体,默认适配当前 scope。

参数: r 底面半径, h 高度, seg 分段数(默认 16)
实现: THREE.ConeGeometry → 平移使底面位于 y=0。
// 创建圆锥
Lot --> primitiveCone(1, 2, 16) color("blue")

primitivePyramid(w, d, h)

Geometry

创建四棱锥(金字塔),手动构建 5 个顶点(底面 4 点 + 顶点)和 6 个面。

参数: w 底面宽, d 底面深, h 高度
实现: 手动构建 THREE.Geometry 顶点与面索引 → mergeVertices()
// 创建金字塔
Lot --> primitivePyramid(2, 2, 1.5)

🏠 屋顶操作 5

roofHip(height)

Roof

四坡屋顶。提取 footprint 边界,生成向内收缩的顶部平顶 + 斜面。

参数: height 屋顶高度
实现: 边界顶点向内插值 30% 作为顶部轮廓 → 连接边界与顶部生成斜面。
// 四坡屋顶
Lot --> extrude(2) roofHip(1)

roofGable(height)

Roof

人字屋顶(三角顶)。沿 footprint 的 X 轴方向创建脊线。

参数: height 屋顶高度
实现: 计算 footprint 的 minX/maxX → 在中心高度创建脊线两端点 → 边界顶点根据 z 坐标连接到对应脊线端点。
// 人字屋顶
Lot --> primitiveCube(3, 2, 3) roofGable(1.2)

roofPyramid(height)

Roof

金字塔屋顶。所有边界顶点连接到 footprint 中心上方的顶点。

参数: height 屋顶高度
实现: footprint 中心点 + height 作为顶点 → 扇形三角面连接边界各边。
// 金字塔屋顶(适合方形 base)
Lot --> primitiveCube(2, 2, 2) roofPyramid(1.5)

roofRidge(height, angle)

Roof

脊线屋顶。在 footprint 中心上方创建一条脊线,两侧坡度对称。

参数: height 高度, angle 坡度角(可选,保留参数)
实现: 类似 gable,但脊线长度为 footprint 宽度的 60%。
// 脊线屋顶
Lot --> primitiveCube(4, 2, 3) roofRidge(1)

roofShed(height, angle)

Roof

单坡屋顶。中心一点高,所有边界连接到中心顶点形成单一坡度。

参数: height 高度, angle 坡度角(可选)
实现: footprint 中心上方一点作为顶点 → 扇形三角面。
// 单坡屋顶
Lot --> primitiveCube(2, 2, 2) roofShed(1)

🔧 几何修改操作 17

offset(distance)

Modify

将所有面沿法线方向平移指定距离,生成"外壳"几何体。

实现: 遍历每个面,顶点沿 face.normal 偏移 distance → 重建面索引。

envelope(angle)

Modify

锥化/包络操作。根据角度参数将上部顶点向中心收缩。

实现: 复制所有面 → 按 Y 轴高度比例缩放 X/Z 坐标(scale = 1 - t * (1 - factor))。

cleanupGeometry()

Modify

清理几何体,合并重合顶点。

实现: 调用 geometry.mergeVertices()

convexify()

Modify

凸化几何体。用当前 bounding box 替代原几何体。

实现: 计算 boundingBox → 创建 BoxGeometry 替换原几何体。

deleteHoles()

Modify

删除内部孔洞面。识别共享边数 > 2 的内部面并移除。

实现: 统计每条边的共享次数 → 保留仅出现 1~2 次的边界/表面面。

reverseNormals()

Modify

反转所有面的法线方向。

实现: 遍历所有 Face3,交换 ab 顶点索引。

setNormals()

Modify

重新计算面法线和顶点法线。

实现: computeFaceNormals() + computeVertexNormals()

softenNormals()

Modify

软化法线,使光照过渡平滑。

实现: 调用 computeVertexNormals()(共享顶点法线取平均)。

rectify()

Modify

矫正几何体为轴对齐包围盒。

实现: 计算 boundingBox → 用 BoxGeometry 替换。

reduceGeometry(percentage)

Modify

简化几何体,按百分比减少面数。

实现: 计算目标面数 → 循环 faces.pop() 直到达标。

resetGeometry()

Modify

重置几何体为当前 scope 的轴对齐包围盒。

实现: 同 rectify,用 boundingBox 尺寸创建立方体。

trim()

Modify

删除面积过小的退化面。

实现: 计算每个三角面面积 → 过滤掉面积 < 1e-6 的面。

tag(tagName)

Modify

为当前几何体添加标签。

实现:geometry.attrs.tags 数组中追加标签名。

deleteTags()

Modify

删除当前几何体的所有标签。

实现: 清空 geometry.attrs.tags 数组。

mirror(axis)

Modify

沿指定轴镜像几何体。

实现: 对指定轴调用 geometry.scale(-1, 1, 1) 等。

footprint()

Modify

提取当前几何体在 XZ 平面的投影(bounding box 底面)。

实现: 取 boundingBox 的 min.y 平面 → 创建 4 顶点矩形面。

📐 Scope / 变换操作 7

alignScopeToAxes(axis)

Scope

将 scope 的旋转重置为与世界坐标轴对齐。

实现: pivotRotate = new Quaternion()(单位四元数)→ 更新变换矩阵。

alignScopeToGeometry()

Scope

将 scope 对齐到第一个面的法线方向。

实现: 取第一个面的 normal → 计算与 Z 轴对齐的四元数 → 赋值给 pivotRotate

alignScopeToGeometryBBox()

Scope

将 scope 的 pivot 设为几何体 bounding box 中心,旋转重置。

实现: pivot = boundingBox.getCenter() + pivotRotate = 单位四元数

rotateScope(x, y, z)

Scope

绕各轴旋转 scope(角度制)。

实现: Quaternion.setFromEulerpremultiply 到现有 pivotRotate

setPivot(x, y, z)

Scope

设置 pivot 点到指定世界坐标。

实现: 直接设置 pivot = new Vector3(x, y, z) → 更新变换矩阵。

mirrorScope(axis)

Scope

沿指定轴镜像 scope 变换矩阵。

实现:pivotTransform 调用 scale(-1, 1, 1) 等 → 重算逆矩阵。

NIL

Scope

空操作,不产生任何几何输出。

实现: stack.pop(); stack.push(null)。在 applyRule 中 null 被识别为 NIL 规则。

🎨 材质 / UV 操作 7

texture(name)

Material

设置纹理名称。

实现: set(material.texture, name) → 存入 attrs.material.texture

setupProjection(mode, axes)

Material

设置纹理投影模式和轴向。

实现: 存入 attrs.material.projectionModeprojectionAxes

translateUV(x, y)

UV

平移 UV 坐标。

实现: 累加到 attrs.uv.x / .y

scaleUV(x, y)

UV

缩放 UV 坐标。

实现: 累乘到 attrs.uv.sx / .sy

rotateUV(angle)

UV

旋转 UV 坐标。

实现: 累加到 attrs.uv.rot

normalizeUV()

UV

重置 UV 到标准状态(无平移、无缩放、无旋转)。

实现: attrs.uv = {x:0, y:0, sx:1, sy:1, rot:0}

tileUV(x, y)

UV

UV 平铺(同 scaleUV 的语义包装)。

实现: 累乘到 attrs.uv.sx / .sy

🔗 插入 / 规则调用 2

i(shapeName)

Insert

插入(调用)指定名称的规则。同 CityEngine 的 i() 操作。

实现: 查找 processor.rules[shapeName] → 调用 applyRule()

insert(shapeName)

Insert

i() 的完整名称别名。

实现:i() 共用 func_insert 实现。

📦 带 Body 的操作 6

setback(distance) { ... }

Body

将 footprint 向内收缩指定距离后执行 body。

实现: boundingBox 各边内缩 distance → 创建矩形 footprint → push/pop 栈执行 body。
Lot --> setback(0.5) { color("red") }

shapeL(fw, lw) { ... }

Body

将 footprint 分割为 L 形(前条 + 左条)。

实现: 按 frontWidth 和 leftWidth 切割 boundingBox → 为每个 body part 生成对应区域几何体。
Lot --> shapeL(1, 1) { front: color("red") | left: color("blue") }

shapeU(fw, lw, rw) { ... }

Body

将 footprint 分割为 U 形(前条 + 左条 + 右条)。

实现: 类似 shapeL,增加右侧条分割。

shapeO(fw, lw, rw, bw) { ... }

Body

将 footprint 分割为 O 形(四边条状)。

实现: 前/左/右/后四条带状区域,中间镂空。

innerRectangle { ... }

Body

在 footprint 内部生成一个内缩矩形并执行 body。

实现: boundingBox 各边内缩固定值 0.2 → 创建矩形 → push/pop 执行 body。

splitAndSetbackPerimeter(offset) { length : depth : ops | ... } { remainder : ops }

Body

沿多边形周长分割并退缩。根据指定的 lengths 将面的周长分割成多个部分,然后对每个部分进行退缩。

实现: 提取 footprint 顶点 → 计算边长与内法线 → 沿周长定位分割点 → 向内退缩 depth → 生成条带与 remainder。
Lot --> splitAndSetbackPerimeter(6)
  { 40 : 5 : Yellow |
    20 : 10 : Blue }
  { remainder : Grey }

scatter(count) { ... }

Body

在 footprint 范围内随机散布指定数量的小几何体并执行 body。

实现: 循环 count 次 → 随机生成 X/Z 位置 → 创建小三角面 → 执行 body。
Lot --> scatter(10) { primitiveCone(0.1, 0.2) }

📊 完整函数清单

函数名类别参数Body实现文件
primitiveQuad几何创建0~2 (w, h)cgaprocessor.js
primitiveDisk几何创建0~2 (r, seg)cgaprocessor.js
primitiveCone几何创建0~3 (r, h, seg)cgaprocessor.js
primitivePyramid几何创建0~3 (w, d, h)cgaprocessor.js
roofHip屋顶1 (height)cgaprocessor.js
roofGable屋顶1 (height)cgaprocessor.js
roofPyramid屋顶1 (height)cgaprocessor.js
roofRidge屋顶1~2 (height, angle)cgaprocessor.js
roofShed屋顶1~2 (height, angle)cgaprocessor.js
offset几何修改1 (distance)cgaprocessor.js
envelope几何修改0~1 (angle)cgaprocessor.js
cleanupGeometry几何修改0cgaprocessor.js
convexify几何修改0cgaprocessor.js
deleteHoles几何修改0cgaprocessor.js
reverseNormals几何修改0cgaprocessor.js
setNormals几何修改0cgaprocessor.js
softenNormals几何修改0cgaprocessor.js
rectify几何修改0cgaprocessor.js
reduceGeometry几何修改0~1 (percentage)cgaprocessor.js
resetGeometry几何修改0cgaprocessor.js
trim几何修改0cgaprocessor.js
tag几何修改1 (tagName)cgaprocessor.js
deleteTags几何修改0cgaprocessor.js
mirror几何修改1 (axis)cgaprocessor.js
footprint几何修改0cgaprocessor.js
alignScopeToAxesScope0~1 (axis)cgaprocessor.js
alignScopeToGeometryScope0cgaprocessor.js
alignScopeToGeometryBBoxScope0cgaprocessor.js
rotateScopeScope3 (x, y, z)cgaprocessor.js
setPivotScope3 (x, y, z)cgaprocessor.js
mirrorScopeScope1 (axis)cgaprocessor.js
NILScope0cgaprocessor.js
texture材质1 (name)cgaprocessor.js
setupProjection材质1~2 (mode, axes)cgaprocessor.js
translateUVUV1~2 (x, y)cgaprocessor.js
scaleUVUV1~2 (x, y)cgaprocessor.js
rotateUVUV1 (angle)cgaprocessor.js
normalizeUVUV0cgaprocessor.js
tileUVUV1~2 (x, y)cgaprocessor.js
i / insert插入1 (shapeName)cgaprocessor.js
setbackBody1 (distance)cgaprocessor.js
shapeLBody2 (fw, lw)cgaprocessor.js
shapeUBody3 (fw, lw, rw)cgaprocessor.js
shapeOBody4 (fw, lw, rw, bw)cgaprocessor.js
innerRectangleBody0cgaprocessor.js
splitAndSetbackPerimeterBody1~3 (offset, firstEdgeIndex, selectedEdgesMask)cgaprocessor.js
scatterBody1 (count)cgaprocessor.js