上篇文章介绍了CityEngine + Python自动化建模的原理,本篇文章给出自动化建模的实际代码(代码已经过实际验证,可放心使用),将对应内容修改为自己项目中的实际内容即可。
如果你喜欢本文,欢迎收藏、分享和转载,转载请注明出处:https://blog.csdn.net/shaxiaozilove/article/details/116903530
如果你有任何问题,欢迎与我联系和沟通,谢谢。
下面是自动化建模全面和详细的代码,欢迎参考:
'''
Created on 2020-10-27
@author: QinC
'''
from scripting import *
import os
import math
# get a CityEngine instance
ce = CE()
def isFileExist(f_path):
return os.path.exists(f_path)
# create a new scene and set it's spatial reference system
def createScene(scene_name, wkid):
if not scene_name.endswith('.cej'):
scene_name = scene_name + '.cej'
ce.newFile('scenes/' + scene_name)
ce.setSceneCoordSystem(wkid)
print 'create secne and set srs successfully'
# import spefify layer from gdb
def importShapeFromGDB(gdb_path, dataset):
absolute_path = ce.toFSPath(gdb_path)
if not isFileExist(absolute_path):
print 'path of gdb not exist: %s' % absolute_path
return
if not isinstance(dataset, list):
print 'parameter type of dataset should be list: %s' % str(dataset)
return
if not len(dataset):
print 'at least one feature class should be imported: %s' % str(dataset)
return
gdbSettings = FGDBImportSettings()
gdbSettings.setDatasetFilter(dataset)
ce.importFile(ce.toFSPath(gdb_path), gdbSettings, False)
ce.setSelection(None)
print 'import shape successfully'
'''
first, set cga rule file and start rule for scene whole shapes
next, set cag's parameter Floor from Object(connect Floor to layer's attribute Floor)
then, set new name for object if specify a valid field_name
cga_path: relative path of cga
start_rule: start rule, string type
'''
def setRule(cga_path, start_rule):
# judge if the cga_path exist by absolute path
if not isFileExist(ce.toFSPath(cga_path)):
print 'the specified cga file not exist: %s' % cga_path
return
shapes = ce.getObjectsFrom(ce.scene, ce.isShape)
ce.setRuleFile(shapes, cga_path, True)
ce.setStartRule(shapes, start_rule)
print 'set rule file and start rule successfully'
'''
if attr in cga file has the same name with one of layer's attribute table fields,
then it's attr source is Object default and value is same
so, if you want to get value from layer attribute table, it is import to set attr name in cga
the next line is not necessary
'''
ce.setAttributeSource(shapes, '/ce/rule/Floor', 'Object')
print 'set Floor attr source successfully'
ce.saveFile()
'''
set shape name use layer's field value
shapes: shaped to set new name
field_name: the field to set shape's name
'''
def setObjectName(shapes, field_name):
for shape in shapes:
ce.setName(shape, ce.getAttribute(shape, field_name))
'''
export models
format: format to export, eg. gdb, gltf, glb ...
path: where the model to export, use relative path
base_name: base name of the exported file
field_name: source layer's field name, used to reset object name
admin_codes: admin codes of a city, generate model of this area each time, default value is empty list,
if not assigned or pass empty list, generate and export a certain number of model each time
certain_number: the number of models generate and export each time
'''
def exportModels(format, path, base_name, field_name = None, admin_codes = [], certain_number = 10000):
shapes = ce.getObjectsFrom(ce.scene, ce.isShape)
if field_name and len(admin_codes) > 0:
# set a new name for object(here is shapes)
setObjectName(shapes, field_name)
print 'set object name with category code successfully'
# generate and export model by category code
for code in admin_codes:
# filter scene shapes with name
classified_shapes = ce.getObjectsFrom(ce.scene, ce.isShape, ce.withName('"' + code + '"'))
doGenerateAndExport(classified_shapes, format, path, base_name, code)
print 'generate and export models successfully with field name [%s], codes %s.' % (field_name, str(admin_codes))
else:
# export certain number model each time
length = len(shapes)
count = int(math.floor(length / certain_number))
for i in range(count):
certain_shapes = shapes[i * certain_number: (i + 1) * certain_number]
doGenerateAndExport(certain_shapes, format, path, base_name, i + 1)
# left models to process(number should be int, not floor)
left_shapes = shapes[count * certain_number: length]
doGenerateAndExport(left_shapes, format, path, base_name, count + 1)
print 'generate and export models with certain number each time successfully, and total %d parts.' % (count + 1)
ce.saveFile()
'''
genarate and export model, you can specify format, path and base name
shapes: objects to generate model
format: format to export, eg. gdb, gltf, glb ...
path: where the model to export, use relative path
base_name: base name of the exported file
suffix: used as suffix of base name to distingush different part, default value is 1
'''
def doGenerateAndExport(shapes, format, path, base_name, suffix = 1):
models = ce.generateModels(shapes, True, False)
if len(models):
exportSetting = getExportSetting(format, path, base_name, suffix)
ce.export(models, exportSetting, False)
print 'models of part %d has generate and export successfully' % suffix
else:
print 'models of part %d has no model to generate and export' % suffix
# get export setting info
def getExportSetting(format, path, f_name, suffix):
if not f_name.endswith('.' + format):
f_name = f_name + '_' + str(suffix) + '.' + format
else:
f_name = os.path.splitext(f_name)[0] + '_' + str(suffix) + '.' + format
exportSettings = FGDBExportModelSettings()
if format == 'gdb':
exportSettings.setOutputPath(ce.toFSPath(path) + '/')
exportSettings.setGeodatabaseName(f_name)
elif format == 'gltf' or format == 'glb':
exportSettings = GLTFExportModelSettings()
exportSettings.setOutputPath(ce.toFSPath(path))
exportSettings.setBaseName(f_name)
return exportSettings
if __name__ == '__main__':
scene_name = 'wuhan_auto_cga.cej'
# coordinate system code, eg 3857 4547
wkid = 'EPSG:4547'
gdb_path = 'data/building.gdb'
dataset = ['/wuhan_for_local_test']
cga_path = 'rules/wuhan_blank.cga'
start_rule = 'Lot'
field_name = 'Adcode'
# admin code of wuhan
adcodes = ['420102', '420103', '420104', '420105', '420106', '420107', '420111', '420112', '420113', '420114', '420115', '420116', '420117']
certain_number = 10000
export_path = 'models'
base_name = 'wuhan'
createScene(scene_name, wkid)
importShapeFromGDB(gdb_path, dataset)
setRule(cga_path, start_rule)
exportModels('gdb', export_path, base_name, certain_number = 5000)
ce.refreshWorkspace()