基于规则的建模

要访问 ArcGIS CityEngine 中的教程工程,请打开 CityEngine,然后在主菜单中单击帮助 > 下载教程和示例。 在选择教程或示例后,系统会自动下载工程并将其添加到 CityEngine 工作空间。

本教程与 Houseal Lavigne Associates 的 Devin Lavigne 合作创建。

CGA 建模

CityEngine 是一款程序建模应用程序,这意味着 2D 形状将经过一系列用于生成 3D 模型的程序(CGA 规则文件)。 CityEngine 的优势在于 CGA(计算机生成架构)。 CGA 是 CityEngine 的形状语法,是一种独特的编程语言,可以指定它来生成建筑 3D 内容。 实际上,将 CGA 规则分配给或应用于形状时,将创建 3D 模型。 3D 模型的复杂程序取决于 CGA 规则和其中的说明。 简单 CGA 文件可能会采用建筑物覆盖区并将其拉伸以使其具有 3D 形式或质量。 而更复杂的 CGA 规则可能会将纹理应用到质量的外立面,或将其拆分为其他部分,生成丰富、详细的 3D 模型。

编写 CGA 的关键之一是逐步编写规则并在执行过程中构建功能。 虽然为期望结果制定计划非常重要,但不能编写 500 行代码然后再开始。 相反,您需要开始逐步构建规则,并在进行时测试结果。

本教程将指导您如何创建规则,从一个简单的轮廓线创建一系列 3D 建筑物。

打开场景

首先,打开工程 \scenes\ 文件夹中的 BasicsOfRules.cej 场景:

场景中的基本形状

Hello, World!

在编码中有一种名为“Hello, World!”的内容。 – 一种编写简单代码的方法,输出一条简单的消息,这样您就可以查看基本语法并确认您的代码正在运行。 在 CityEngine 中“Hello World!”的简单版本是对形状应用颜色的随机高度的简单拉伸。

因此,要创建第一个规则,请右键单击 \rules\ 文件夹,转到 新建 > CGA 规则文件,然后将规则命名为 DetailedBuilding.cga

首先,在说明您正在使用的 CityEngine 版本(例如版本 2022.1)的代码行下方添加以下行,然后保存您的规则。

@StartRule
Footprint -->
	extrude(rand(10,100))  
	color(1,1,0)

通过进行 @StartRule 注记,可以使 Footprint 规则在选取器中可用。 下一行将形状拉伸为 10 到 100 米之间的随机高度。 最后,最后一行将形状着色为 RGB 中的黄色。

分配规则

保存规则后,选择形状并为其分配规则(见下图)。 如果在分配新规则后未发生任何变化,请单击生成模型工具生成 (Ctrl+G) 或单击主菜单中的 形状 > 生成模型

添加属性

现在您的规则正在运行,添加高度作为属性,以为规则提供一些其他功能。 请记住,关键是增量变化,您不是从头开始,而是要修改已经开始使用的规则:

@Group("Building Shell")
@Range(min=0, max=100, stepsize=1)
attr building_height = rint(rand(10,100))

@StartRule
Footprint -->
	extrude(building_height)  
	color(1,1,0)

这些更改可以将随机的建筑物高度移动到名为 building_height 的属性中。 这仍然会为每个形状生成,但会将其移动到您可以在检查器窗口中控制的属性。 您还添加了一个名为 rint 的新内置函数,它将随机数四舍五入为最接近的整数。

@Group 注记有助于组织属性在检查器窗口中的显示位置。 @Range 注记用于控制滑块功能。 通过将建筑物高度设置为属性,您现在有一个用于控制各个形状高度的滑块。

使用 @Range 滑块控制高度

现在,如果单击建筑物,则可以调整高度并覆盖随机数。 此外,滑块现在仅介于范围的最小值和最大值之间,即 0 和 100 之间。

通过滑块调整高度

添加控点

控点扩展了属性的功能,并可以实现非常直观和交互的场景控制方式。

将添加 @Handle 注记和 Mass 规则以包含控制模型中建筑物高度的控点:

@Group("Building Shell")
@Handle(shape=Mass, axis=y)
@Range(min=0, max=100, stepsize=1)
attr building_height = rint(rand(0,100))

@StartRule
Footprint -->
	extrude(building_height)  
	color(1,1,0)
	Mass

请记住,需要重新生成模型 (CTRL+G),这样控点将出现在建筑物上,以允许调整高度属性。

已添加高度控点

添加楼层分割

继续对规则进行增量修改,现在您将添加一些代码来将建筑物垂直(沿 y 轴)分割各个楼层。

使用由新的 floor_height 属性控制的拆分割操作创建 Mass 规则。 请注意,默认单位是米,因此下面的代码表示 3.048 米,而使用 # 标记的注释表示其为 10 英尺。

@Group("Building Shell")
@Handle(shape=Mass, axis=y)
@Range(min=0, max=100, stepsize=1)
attr building_height = rint(rand(10,100))

@Range(min=1, max=25, stepsize=1)
attr floor_height = 3.048	# 10 feet


@StartRule
Footprint -->
	extrude(building_height)  
	color(1,1,0)
	Mass

Mass -->
	split(y) { floor_height : Floor }*

楼层分割

您可能会注意到建筑物的顶层具有不同的楼层高度。 这是因为拆分从底部开始向上拆分,而顶层高度是执行完所有拆分后剩下的高度。

解决此问题的一种方法是在楼层高度前添加一个波浪号 (~)。 这将指示 CityEngine 使用浮动大小,从而允许软件自动调整分割。 每层楼不会确切为 3.048 米,但它们都是相等的,且不会有剩余部分。

Mass -->
	split(y) { ~floor_height : Floor }*

楼层平均分割前后

构建按用途着色的函数

首先,您应该注释掉在 @StartRule 中为覆盖区分配颜色的行。 虽然在规则之间处理形状时您可以多次更改颜色,但最佳做法是仅设置一次颜色。

添加 #color(1,1,0) 评论:

@StartRule
Footprint -->
	extrude(building_height)  
	#color(1,1,0)
	Mass

函数是例程或代码块,您可以使用和重用它们来执行返回值的过程。 要根据土地利用为楼层着色,可以构建一个简单的函数,并通过调用该函数来使用适当的颜色。 为此,您还需要创建属性以允许您按楼层位置选择不同的土地用途。

@Group("Building Shell")
@Handle(shape=Mass, axis=y)
@Range(min=0, max=100, stepsize=1)
attr building_height = rint(rand(10,100))
@Range(min=1, max=25, stepsize=1)
attr floor_height = 3.048	# 10 feet

@Group("Land Use")
@Enum("Retail","Office","Multi-Family")
attr use_ground = "Retail"

@Enum("Retail","Office","Multi-Family")
attr use_upper = "Multi-Family"

接下来,在您的属性和 @StartRule 之间,创建一个新函数。 以下函数采用 use 参数,并对其进行评估以返回正确的外观颜色。 如果 use 参数不匹配,则将传递颜色 #FFFFFF 或白色。

getColor(use) = 		case use == "Retail" : "#FF6633"
				case use == "Office" : "#6699FF"
				case use == "Multi-Family" : "#A97C50" 
				else: "#FFFFFF"

最后,通过找到底层和上层,然后调用函数为楼层着色,将楼层放在一处。 为了将顶层与所有上层分割区分开来,您可以使用在调用分割时创建的 split.indexsplit.total。 为此,您将扩展代码以添加 Floor 规则。 Floor 规则将首先执行条件规则 case。 如果 split.index 为 0,则为底层,其他为上层。 确定楼层后,即可调用该函数并设置楼层颜色。

Floor -->
	case split.index == 0: 
		color(getColor(use_ground))
	else:
		color(getColor(use_upper))

使用高度和土地利用属性,您现在可以实现更多样化的拓扑:

土地利用属性已调整

创建常量

创建常量允许您创建一个静态数字来执行计算。 这有助于实现多个目的,包括本教程下一部分中介绍的报告。 下面的代码行可帮助您从平方米计算平方英尺,以及建筑物中的居住单元数量。 但是,需要了解常量可用于所有内容,并且可以放置在代码中的任何位置。 也就是说,将常量放在页面顶部附近是一个很好的做法。 请注意,这些常量可将 CityEngine 默认公制值(米)转换为美制英制值(英尺)。

const unitScale = 0.3048			# convert meters to feet
const areaScale = 10.7639			# convert square meters to square feet
const acres = 43560 			# there are 43,560 square feet in an acre

添加报告

除了生成 3D 模型外,CityEngine 还可以在规则范围内运行和报告计算,以获得有价值的数据。 这意味着您不仅可以可视化计划或开发,还可以生成数字报告,以使 CityEngine 成为地理设计领域的强大工具。 例如,可以包含数字,例如总建筑面积 (GFA)、单元数或土地利用混合。 此外,当更改计划(包括模型和形状)时,报告会自动更新。

根据规则,您将报告一些数据。 一开始很简单,仅需报告建筑面积。 首先修改 Floor 规则以将其延续到名为 Plate 的规则。 在 Plate 规则中,您将几何分解为组件面 (comp(f)),然后将形状的底部传递给 Reporting 规则以计算几何面积。 请注意,您需要先拆分底部形状,否则计算将包括每个形状的所有表面积。

Floor -->
	case split.index == 0: 
		color(getColor(use_ground))
		Plate
	else:
		color(getColor(use_upper))
		Plate

Plate -->
	comp(f) { side : Wall | bottom : Reporting | top : Top }

Reporting -->
	report("FloorArea", geometry.area)

要查看结果,请保存规则文件 (Ctrl+S),选择所有形状 (Ctrl+A),然后单击生成模型 生成 (Ctrl+G)。

展开检查器窗口中的报告部分:

FloorArea 报告

报告指示共有 117 层,总计 85,704.20 平方米。 要将建筑面积转换为平方英尺,仅需将 geometry.area 乘以 areaScale 常量即可。

Reporting -->
	report("FloorArea", geometry.area * areaScale)

FloorArea 转换为平方英尺

现在,如果您希望按土地利用查找面积,或一些重要且常见的城市规划信息,如密度或容积率,则可以对规则进行一些简单的修改,将土地利用信息作为参数传递。 您可以修改代码以将土地利用(use_grounduse_upper)作为 landUse 参数传递给 Plate 规则,而后又将其传递给 Reporting 规则:

Floor -->
	case split.index == 0: 
		color(getColor(use_ground))
		Plate (use_ground)
	else:
		color(getColor(use_upper))
		Plate (use_upper)

Plate(landUse) -->
	comp(f) { side : Wall | bottom : Reporting(landUse) | top : Top }

Reporting(landUse) -->
	report("FloorArea." + landUse, geometry.area * areaScale)

按土地利用报告 FloorArea

要计算容积率(FAR),您需要报告或计算该地块的土地面积。 要获得此计算,请将 report 操作作为 @StartRule 添加到 Footprint 规则。

@StartRule
Footprint -->
	report("LotArea", geometry.area * areaScale)
	extrude(building_height)  
	#color(1,1,0)
	Mass

使用 LotArea 进行土地利用报告

添加仪表盘

仪表盘是扩展 CityEngine 报告的好方法。 使用仪表盘,可以获取规则报告的所有值,根据需要应用其他计算,并使用条形图和图表显示信息。

首先,单击主菜单中的 窗口 > 仪表盘

主菜单中的仪表盘

默认情况下,这会在检查器窗口中打开仪表盘选项卡。

单击添加图表按钮以打开一个窗口。 选择饼图,将土地利用添加到标题框中,然后在报告下拉菜单中选择 FloorArea.*。 最后,单击添加卡片,在仪表盘窗口中放置画布,以添加卡片:

添加仪表盘卡片

添加其他卡片。 这次选择键编号。 将标题命名为 FAR 并选择 FloorArea.* 作为报告,然后您将除以 LotArea。 单击添加卡片并将其添加到画布:

作为最后一步,您可以为图表添加颜色以匹配屏幕上建筑物的颜色。 为此,您需要在报告规则中添加第二行。 这将调用获取土地利用颜色的函数并将其添加为图表的属性。

Reporting(landUse) -->
	report("FloorArea." + landUse, geometry.area * areaScale)
	report("FloorArea." + landUse + "#color", getColor(landUse))

仪表盘土地利用饼图

要查看使用 CityEngine 作为设计工具时仪表盘的强大功能,请选择一座建筑物并使用控点来更改建筑物的高度。

调整控点前的仪表盘

仪表盘将实时更新,这有助于城市规划师或设计师制定满足当地需求或设计目标的计划。

调整控点后的仪表盘

确保已检出其他基础知识教程:CityEngine 游览使用 GIS 数据

要继续学习 CityEngine,请参阅完整的 CityEngine 教程目录