教程 12:脚本报表导出

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

环礁的渲染视图

本教程介绍了如何将 CGA 报表变量与基于 Python 的导出器结合使用。 您将使用岛屿上未来城市的场景。 在此设置中,您将学习如何报告场景中所分布实例的信息,并使用该信息在简单的文本文件中生成实例地图。 该文本文件包含将分布式建筑物实例直接加载到任意后续应用程序中所需的数据。

对于每个实例,您将写入以下值:

  • 资产标识符
  • 3 个轴中的位置
  • 3 个轴中的旋转
  • 3 个轴中的缩放

应采用以下格式写入值:

nrassetxposxrotxscale

0

scifi_building_9.obj

-529.4803009

0

1.051229466

1

scifi_building_17.obj

236.6141357

0

0.933861537

2

scifi_building_5.obj

499.4240112

0

1.256899709

本教程分为三部分:

  • 在第一部分中,您将扩展一个现有 CGA 文件,该文件使用通用规则分发实例化建筑物,以报告有关分布式建筑物的变量。
  • 接下来,您将创建一个 Python 脚本,以使用基于脚本的导出器将报告的变量写入文本文件。
  • 最后,您将重用在本教程第一部分中创建的规则以报告并导出其他资产的变量。

本教程要求用户具备 CGA 形状语法的基础知识以及编写 Python 脚本的基础知识。 有关详细信息,请参阅基于脚本的导出

实例化建筑物的报表信息

首先,您将准备用于报告的外部 CGA 文件。

创建用于报告的通用规则

要创建用于报告的规则,请执行以下操作:

  1. Navigator 窗口中展开 Tutorial_12_Scripted_Report_Export 教程文件夹。
  2. 双击 scenes 文件夹中的 reportInstances_01.cej 场景以将场景在视窗窗口中打开。
  3. 单击文件 > 新建 > CityEngine > CGA 规则文件以创建一个规则文件。
  4. 将该规则命名为 instanceReporting.cga

报告变换数据

接下来,您将构建报告规则。

  1. 添加 InstanceReport 规则:

    InstanceReport(asset) -->
    	report("asset", asset)

    您需要将资产的路径作为规则参数进行传递,以便能够将其报告为资产的标识符。

  2. 添加比例的报告命令:

    report("xscale", scope.sx/assetInfo(asset, "sx"))
    report("yscale", scope.sy/assetInfo(asset, "sy")) 
    report("zscale", scope.sz/assetInfo(asset, "sz"))

    在大多数情况下,您需要一个与原始资产大小相对应的范围。 您不能仅报告范围大小,必须将其除以资产大小。 您可以使用 assetInfo() 命令查询原始资产大小;例如,assetInfo(asset, "sx") 可查询在 x 轴的大小。

  3. 要以世界坐标报告旋转,您需要在 CityEngine 中使用 convert() 命令转换范围旋转:

    report("xrot", convert(x, scope, world, orient, 0,0,0))
    report("yrot", convert(y, scope, world, orient, 0,0,0))
    report("zrot", convert(z, scope, world, orient, 0,0,0))

  4. 查看资产的枢轴和位置:

    为了能够在您的后续应用程序中正确地实例化您的资产,重要的是要注意所使用资产的枢轴和位置。 在本例中,资产的枢轴位于地平面的中心,并且位于世界原点上:

    以世界坐标系中心为轴

    以世界坐标系中心为轴,正面

    由此可确保所报告的位置与资产的枢轴相对应。

  5. 将位置转换为世界坐标:

    report("xpos", convert(x, scope, world, pos, scope.sx/2,0,scope.sz/2))
    report("ypos", convert(y, scope, world, pos, scope.sx/2,0,scope.sz/2))
    report("zpos", convert(z, scope, world, pos, scope.sx/2,0,scope.sz/2))

    现在,您已经报告了全部的所需值。

  6. 为了确保不会显示不需要的几何,请在报告规则的末尾添加 NIL 命令:

    InstanceReport(asset) -->
    
    	## report instance ID
    	report("asset", asset)	
    	
    	## report scale values relative to asset
    	report("xscale", scope.sx/assetInfo(asset, "sx"))
    	report("yscale", scope.sy/assetInfo(asset, "sy")) 
    	report("zscale", scope.sz/assetInfo(asset, "sz"))
    
    	## report rotation in world coords
    	report("xrot", convert(x, scope, world, orient, 0,0,0))
    	report("yrot", convert(y, scope, world, orient, 0,0,0))
    	report("zrot", convert(z, scope, world, orient, 0,0,0))
    
    	## report position in world coords
    	report("xpos", convert(x, scope, world, pos, scope.sx/2,0,scope.sz/2))
    	report("ypos", convert(y, scope, world, pos, scope.sx/2,0,scope.sz/2))
    	report("zpos", convert(z, scope, world, pos, scope.sx/2,0,scope.sz/2))
    
    	NIL

    打开 instanceReporting_dist.cga 文件以查看最终规则。

使用报表规则

接下来,您将打开规则文件并使用准备好的报告规则。

  1. 双击 rules 文件夹中的 instance_city_01.cga 文件,在 CGA 编辑器窗口中打开规则。
  2. 在文件 instance_city_01.cga 的开头添加以下行,以导入准备好的 ID 为 instanceReporting 的报表规则文件:

    import instanceReporting:"instanceReporting.cga"

  3. InstanceReport 规则添加到 Building 规则的末尾。

    Building(asset) --> 
    	s('1,0,'1) 
    	i(asset) Asset.
    	instanceReporting.InstanceReport(asset)

    插入命令后的 Asset. 叶规则可确保生产资产。

  4. 生成建筑物,并查看检查器窗口的报告部分,其外观应类似于以下示例:
    检查器窗口中显示的报告变量

创建脚本以导出报告

现在,您将使用 Python 基于脚本的导出器来处理准备好的报告数据。 为此,您需要创建 Python 脚本。 有关详细信息,请参阅基于脚本的导出

根据导出报告模板创建模块

接下来,您将创建 Python 模块。

  1. 单击文件 > 新建 > Python > Python模块
  2. 对于源文件夹,单击浏览以选择 scripts 文件夹:

    Python 模块向导

    将该脚本命名为 exportInstances

  3. 单击完成以打开模板对话框。
  4. 依次单击 Module Export(Reporting)确定

    Python 模板对话框

    exportInstances 模块随即在 Python 编辑器中打开。

    该模板包含 4 个函数,但本教程中仅需要 finishModel()finishExport() 函数,因此可以删除其他函数。

访问 finishModel() 中的报表数据

接下来,您将访问报告变量。

  1. finishModel() 函数的底部添加以下行:

    model.getReports()['asset']

    可以访问当前已处理形状的报告变量数组,其中 asset 为报表变量的名称。

  2. 修改该行以检查报告数据是否存在:

    if(model.getReports().has_key('asset')):

    由于并非所有生成的形状上都具有实例(例如空的地面形状或街道形状),因此需要使用其中一个报告变量(本例中为 'asset')来检查报告数据是否存在。

  3. 添加以下行以对报告的数据集进行循环:

    l = len(model.getReports()['asset'])
    for i in range(0,l): 
    	print model.getReports()

    如果仔细查看所生成建筑物的 CGA 规则,您将会注意到某些形状包含多个实例。 通过首先获取 'asset' 数组的长度,可以按形状对已报告的数据集进行循环。

    作为第一个测试,您需要将报告数据数组打印到 Python 控制台。

通过打印到控制台来测试脚本

要将报告数据数组打印到 Python 控制台,请执行以下操作:

  1. 选择一个小型的建筑物或地块形状集。
  2. 单击文件 > 导出模型以打开模型导出对话框。
  3. 单击基于脚本的导出器 (Python),然后单击下一步
  4. 浏览至 scripts 文件夹中的 exportInstances.py 导出脚本:

    “基于脚本的导出”对话框包含已设置的导出脚本

  5. 单击完成以运行导出器。
  6. 单击窗口 > 控制台以打开 Python 控制台。

    Python 控制台的输出应类似于以下内容:

    {'zpos': [-362.6108093261719], 'yrot': [-69.42008209228516], 'asset': ...
    {'zpos': [-362.6108093261719], 'yrot': [-69.42008209228516], 'asset': ...
    {'zpos': [-412.1033630371094], 'yrot': [165.30718994140625], 'asset': ...
    ...

    可以使用控制台工具栏上的显示所选控制台下拉菜单来选择输出控制台。

添加全局变量

现在,您需要添加一个新 processInstance() 函数,用于处理和采集报告值。 您还需要添加两个全局变量(finishModel 函数上方),用于采集数据和追踪实例计数:

# Globals
gInstanceData = "" # global string that collects all data to be written
gInstanceCount = 0 # global count to enumerate all instances

finishModel() 函数

finishModel() 函数更新为以下代码片段:

# Called for each initial shape after generation.
def finishModel(exportContextOID, initialShapeOID, modelOID):
	global gInstanceData, gInstanceCount
	model = Model(modelOID)
	if(model.getReports().has_key('asset')): # only write t3d entry if report data available
		# there might be more than one asset per model, therefore loop
		l = len(model.getReports()['asset'])
		for i in range(0,l):
			instanceData = processInstance(model.getReports(),gInstanceCount, i-1)
			gInstanceData = gInstanceData+instanceData
			gInstanceCount = gInstanceCount+1

processInstance() 函数

添加 processInstance() 函数,该函数将以制表符分隔的字符串形式返回所有报告变量:

# Collect the instance information in a tab-separated string 
def processInstance(reports, count, index):

	## remove path from asset string
	asset = reports['asset'][index]
	asset = asset.rpartition("/")[2]

	## prepare the string for the instance map
	text  = "%d\t" % count;
	text += "%s\t" % asset;
	text += "%.3f\t%.3f\t%.3f\t" % (reports['xpos'][index],reports['ypos'][index], reports['zpos'][index])
	text += "%.3f\t%.3f\t%.3f\t" % (reports['xrot'][index],reports['yrot'][index], reports['zrot'][index])
	text += "%.3f\t%.3f\t%.3f\n" % (reports['xscale'][index], reports['yscale'][index], reports['zscale'][index])
	return text

finishExport() 函数

添加 finishExport() 函数。 所有形状的生成均完成后,系统将调用此函数。 您将定义包含实例地图的文本文件的文件名,然后调用 writeFile() 函数:

# Called after all initial shapes are generated.
def finishExport(exportContextOID):
	global gInstanceData, gInstanceCount

	## path of the output file
	file = ce.toFSPath("models")+"/instanceMap.txt"

	## write collected data to file
	writeFile(file, gInstanceData)
	print str(gInstanceCount)+"instances written to "+file +"\n"

writeFile() 函数

在底部添加 writeFile() 函数,此函数可添加标题信息并将所采集的报告字符串写入磁盘:

# combining data (header and content) and writing file
def writeFile(file, content):

	## prepare the head string
	head = "nr\tasset\txpos\typos\tzpos\txrot\tyrot\tzrot\txscale\tyscale\tzscale\n"

	## combine header and content
	content = head + content

	## write data to the file
	report = open(file, "w")
	report.write(content)
	report.close()

保存 exportInstances.py 脚本。

运行最终脚本

现在,您将运行最终脚本并创建导出文件。

  1. 选择一个建筑物或地块形状集。
  2. 单击文件 > 导出模型
  3. 单击基于脚本的导出器 (Python),然后单击下一步
  4. 单击浏览以选择 exportInstances.py 导出脚本。
  5. 单击完成以运行导出器。

    生成的 instanceMap.txt 文件保存在 models 文件夹中。

  6. 双击 instanceMap.txt 文件将其打开:

    instanceMap.txt 文件

    注:

    除了编写制表符分隔的文本文件外,您还可以使用其他一些方法来处理报告的数据,例如,为 Maya 编写创建实例的 Mel 脚本、将位置信息写入数据库或编写基于 ASCII 的自定义格式。

    打开 scripts 文件夹中的 exportInstances_dist.py 文件以查看最终脚本。

报告并导出附加资产的信息

借助报告规则,您现在可以轻松地使用附加实例元素来扩展 CGA 规则集,以便用于报告和导出。

  1. 打开 reportInstances_02.cej 场景和 instance_city_02.cga 规则。
  2. 缩放至街道级别,注意观察弧形的未来桥梁:

    桥梁资产

    沿街道分布的桥梁资产

  3. instance_city_02.cga 规则中,通过在 Bridge 规则底部添加 InstanceReport 规则,将桥梁实例导出至 instanceMap.txt 文件:

    Bridge --> 
    	s(1,8,scope.sz+3.2) center(xz) 
    	i(bridge_asset) 
    	s(calcHeight2(scope.sx),calcHeight2(scope.sy),'1)
    	Bridge.
    	instanceReporting.InstanceReport(bridge_asset)

  4. 保存规则。
  5. 进行新的选择,其中包括场景中的一些街道。
  6. 再次运行脚本导出器。
  7. 再次打开 instanceMap.txt 文件:

    InstanceMap.txt 文件

    之前的 instanceMap.txt 文件被覆盖,新文件还会列出桥梁资产的实例。

    打开 reportInstances_03.cej 场景和 instance_city_03.cga 规则以查看分配了最终规则的形状。

在本教程中,您学习了如何执行以下操作:

  • 实例化资产的报告信息。
  • 创建脚本以将报告导出至文本文件。
  • 通过基于脚本的导出器运行导出脚本。

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