CityEngine rules are written in the Computer Generated Architecture (CGA) programming language. Writing a simple CGA rule can be quick and effortless; however, writing a realistic or flexible rule is an involved process. A library of existing rules is provided, and further rules can be found online. The fastest route to creating a 3D scene from a 2D map is by combining and parameterizing these existing rules, without ever writing CGA code ourselves.
Pre-installed rules can be found in the ESRI.lib project. A further selection of well-written rules for a variety of circumstances can also be found in the tutorials and downloads dialog (Help → Download Tutorials and Examples). Finally, many user-generated rule packages (single .RPK files containing rules and resources) of varying quality can be found online (“ArcGIS content search” with keyword CityEngine; Esri 2019c). Exploring existing rules is a powerful way to understand how models can be generated using the CGA language. As rules can take a lot of time to write, reusing existing rules is advisable wherever possible; libraries should be used before writing CGA code ourselves.
To apply a rule or rule package, we may drag the rule package or file from the navigator onto a shape as shown in Fig. 35.8. By selecting a group of shapes before dragging, we may assign the rule to a number of shapes at once. The Inspector panel allows us to customize rules in a variety of ways. Various options exist for selecting shapes by layer or start rule can be found by right-clicking on a shape. After assigning a rule, there is a short delay while the rule is compiled and evaluated to create a model. If we desire more control, the Inspector contains more detailed options for the shape, including the CGA rule file, Start rule, and the previously mentioned rule attributes.
While the mythos of “coders” and “software engineers” may have elevated programming to the status of a divine art, the reality is much more down to earth. CGA is a simpler language than the likes of Python, relying on a few basic operations which are repeatedly applied to write a rule. We find that undergraduate students are able to create their own rules after a few sessions with CityEngine. Those with experience of complex languages such as C or C++ must learn the CGA way of doing things which is more functional than they are used to. The dialect of CGA used in CityEngine has evolved from the version presented in the initial academic publication (Müller et al. 2006); care must be taken when comparing rules from different versions.
We take the opportunity here to untangle the term “shape” in CityEngine. This has been overused to describe both the input shapes (described in the previous sections) and the shapes which are passed between rules in CGA. CityEngine refers to these intermediate shapes as “CGA shapes”; here, we will use the term geometry. This regrettable confusion is somewhat caused by the academic origin of CityEngine, where our input shapes did not exist.
A CGA rule file is a text document containing a collection of rules. A rule is analogous to a function or method in other programming languages. Each rule is identified by its name and set of parameters: X(1) is a different rule to X(1,2). As the rule is executed, it can call various operations, as well as other rules. Operations are analogous to library functions in other programming languages. As parent rules use operations to create new geometries, they label each with a child rule. If this rule exists, it will then be executed on the child geometry. Unlike the academic description of CGA (Müller et al. 2006), there is no concept of priority; rules are evaluated purely according to their parent rule.
Each rule transforms a piece of geometry into new geometries (or nothing); the result is a 3D mesh model consisting of all the geometry that cannot be further transformed. The initial geometry is the input shape to which the initial rule (sometimes designated with the @Startrule annotation) is applied. The rule also has access to attributes, which allows the rule behavior to be customized by the user or a data source. Attributes and parameters are used in the same way other programming languages use variables to customize behavior. Most of the attributes’ values can be set and read by various operations. Attributes are sometimes taken as additional context for operations to define and refine behavior. For example, predominant orientation and origin information are encoded in the scope and pivot attributes. When the split operation is used in the y-direction, this direction is relative to this orientation given by the scope and pivot locations stored in attributes.
The typical pattern of programming in CGA is to repeatedly expand-then-divide geometry. The rule to create a building model may start with a lot shape, expand with an extrude operation to create prism geometry as high as the building, and then use a comp operation to divide the prism into various faces. The face pointing upward expands to create a roof with a roofGable operation, while side faces are divided using the split operation to become floors and then windows. Another extrude operation finally recesses the windows into the façade. We continue to study such operations in more detail.
Learning to write CGA rules is predominantly the process of learning the various operations and their effects on geometry and attributes. While the complexity of existing rules can be overwhelming to the new user, the compact set of CGA operations presents a shallow learning curve.
CGA is a programming language designed to do one thing—model urban environments—and not much else. For this reason, we would describe it as a domain-specific (programming) language (DSL). For other domains, there are other programming languages: We may use L-Systems (Prusinkiewicz 1986) to generate flora or URDF (2019) to create robots. Because CGA is a DSL, its operations are carefully curated for the urban domain. A lot of theoretical effort was expended in finding a compact yet expressive set of operations. In contrast, general-purpose procedural modeling languages, such as Houdini (2019) and Rhino (2019), are not specialized in a single domain and have many complex operations to learn. Figure 35.9 introduces a handful of key CityEngine operations.
By repeatedly applying these operations, we can create a large variety of urban geometries. For example, the setback, extrude, comp, and roofGable operations can be used to create a house with a recessed top story and a gabled roof, as in the following Fig. 35.10.
An important observation is that CGA does not contain loop or repeat operations. To achieve repeating geometry (such as windows on a building façade or trees along a street), we can use the split operation with the asterisk (*) modifier to split a parent shape into a repeating number of child shapes with the same rules. This is illustrated in Fig. 35.11.
In our final example, we create geometry for streets. To create highway lanes, we wish to split down the long axis of the streets, which may be curved. The UV variant of the split operation achieves this. Finally, we may wish to add texture maps (bitmap images) over our geometry instead of simple colors using the texture operations, as in Fig. 35.12.
Creating larger rule files can be a daunting task for those new to writing code. This is a skill that requires time to practice and learn, but when a little knowledge is gained is often intoxicating:
The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. (Brooks 1995)
This initial excitement often causes problems with inexperienced programmers; overconfidence causes a failure to understand the characteristics of a growing code base. As many small problems in the code (“bugs”) become entrenched, it can become very time-consuming to make even small changes. We can provide some general guidance and tools which can help us build large CGA programs:
Write small pieces of code at a time and test them frequently. This makes it much quicker to track down and isolate issues. If you cannot understand some behavior, it is frequently the case that too much code was written before trying to run it.
Create reusable rules. A small rule that you have created which generates an “Acme brand window” may be reused if kept in separate file. CGA provides the import functionality to facilitate using this window rule in other rule files.
Read the provided CGA documentation (Help menu → CGA reference).
It is easy to get lost in the details of programming and write code that is easy to understand today but difficult to understand in a week’s time when you have forgotten the details. Use code comments (sections of code which the computer does not see) to keep notes for yourself and inform future readers. CityEngine comments can be created in two ways:
Collections of rule files can be large, written by multiple people, have multiple versions, or can even evolve different branches as they are developed. For these reasons, programmers will typically use a version control system (such as the insensitively named git (git 2019)) to manage their code.
Be aware of the keyboard shortcuts and context (right-click) menus available in CityEngine. For example, if you have a shape selected with a rule and are editing the rule in the text editor, Ctrl + S followed by Ctrl + G (on Windows or Linux; use the command key instead of Ctrl on OS X) will save and show the updated 3D shape. In the 3D view, the F key will move the view to show the selected object, or F9–F12 will show and hide various classes of objects.
Beyond general programming etiquette, CityEngine provides several bespoke mechanisms to help writing CGA rules. The Model Hierarchy panel shows a graph of the different rule applications (Window → Show Model Hierarchy, Fig. 35.13). This shows the Inspect Model tool button, which can be used to select a building to analyze (Note that Inspect Model is a different piece of functionality to the Inspector panel.). The resulting graph is shown in the panel, with every rule application illustrated by a gray arrow. Lines connect parent/child rule pairs. By selecting a rule in the graph, the 3D view will highlight the resulting geometry and show the scope, pivot, and trim planes valid for the application of the rule. Right-clicking on a rule node in the graph gives the option to jump to the corresponding portion of CGA. A single CGA rule will typically be applied in different locations and so will appear multiple times in the graph.
Another tool provided by CityEngine is the Façade Wizard (Window → Show Façade Wizard). For a single 2D façade, this aids in generating the split and extrude operations required for a well-parameterized façade.
To deliver a CityEngine rule to an end user in a convenient format, use a rule package. This can be built by selecting the CGA file to export in the navigator, right-clicking, and selecting Share As…. Additional resources and metadata are specified in the dialog box. In this way, the resulting .RPK file may include many individual CGA files and other resources such as data in text files and texture images. Such a package is easily distributed as a single file, and Esri provides a cloud system to distribute rules.
Having built our rules and assigned them to our shapes, we are often interested in further customizing the rule’s expression using attributes.
Attributes are used to refine the evaluation of models within a rule application. They allow a rule to be generalized. For example, consider a number of otherwise identical buildings constructed from different materials; instead of a separate rule for each material, we may use a single rule with an attribute for the building material. Attributes can control any behavior of a rule, but typically, control features such as building height, age, or the number of pedestrians created on the sidewalks. CityEngine shows many of the available attributes for the selected shape and rule in the Inspector panel (Fig. 35.14); some rules have a great many attributes. The default attribute values are set by the rule. However, users can override the source of attributes to allow the rule to respond to different inputs.
The attributes in CityEngine have a multitude of different sources, and the interdependencies between them can be complex. Attribute sources include:
Rule-sourced (Rule default), the default attribute behavior
Shape-sourced (Object attributes)
Image- or shape-driven (Layer attributes).
These can be selected by clicking the down arrow next to an attribute in the Inspector panel and selecting Connect Attribute…. Rule-sourced attribute values are given in the CGA rule file. These attributes can be random; this feature can be used to add variation to a rule applied many times; for example, every building may be generated with the same rule, but given a height that is randomly selected between 10 and 20 m [attr height = rand (10,20)].
To allow users to change an attribute without editing the CGA file, attributes edited in the Inspector become user-sourced attributes. However, we may wish our attributes to come from other sources which may be driven by data. Object attributes are visible in the Inspector (under the Object Attributes heading) when a shape is selected. Object attributes can come from input data sources (e.g., OpenStreetMap data often gives every lot shape a building height attribute) or are created by dynamic shapes (e.g., the connectionStart and End attributes are added automatically to street shapes to specify the adjacent junction types).
Layer attributes sample their values from other shapes or a bitmap, as illustrated in Fig. 35.15. For example, we can drive the height-of-building attribute by using a georeferenced heightmap that has been captured by aerial LiDAR. In this way, we can control a rule using several different data sources. This approach significantly improves the accuracy of resulting geometry over a purely rule-driven procedural pipeline.
Finally, it is useful to know that the attributes for multiple shapes can be edited at once by selecting several shapes. Multiple shapes can be selected by shift-clicking or by dragging a selection box around them. Alternately, by right-clicking on shapes in the 3D view, various automatic selection options allow selection of many shapes within a layer. The Inspector shows the available attributes for the entire selection, and editing an attribute or source applies that attribute change to all the selected shapes.
Exploring Design Space
As a designer using CityEngine, the number of decisions that must be made can be very high. Complex rules present hundreds of attributes, and these must be aligned to user requirements, artistic visions, and practical considerations. Because every additional attribute adds a dimension to the design space, it can take a lot of time to explore large, heavily parameterized rules. Further, we may wish to design multiple scenarios: different rules, attributes, and shapes solving the same problem that we wish to compare side by side. CityEngine provides a Python interface for advanced programmers to control attributes (and many other scene elements) using custom code; typical uses are to create video animations of attributes or run custom design-space search algorithms. Most users, however, will want to avoid such complexities.
CityEngine presents a number of tools to help explore this design space of attributes visually. As we have seen, the simplest of these is the Inspector panel which arranges the attributes in groups specified by the rule file and allows the different attribute sources to be selected in a 2D interface. Given the large number of attributes in a rule such as the Paris example, it is often useful to see a visual representation of those attributes next to the 3D model. Handles present this functionality by showing the attributes (such as height) as controls in the 3D view. The handle system was inspired by the dimension lines of engineering diagrams, as introduced by Kelly et al. (2015). When a model with handle functionality is selected in the 3D view, the handles are shown at the edges of the model depending on the viewpoint. Various handles control different types of values: Boolean toggles, multiple-choice dials, distance-as-value dimension lines, and color selector triangular handles are available. The handle locations, behavior as the viewpoint moves, and appearance are defined by the @Handle annotation in the CGA rule file. They are designed by the rule creator and are only available if the rule author chooses to use them. Often the rule author will choose to expose only the most-used attributes using handles to avoid overcrowding the screen.
Handles change the value of an attribute throughout an entire rule evaluation for a single shape. There are situations where we wish to edit an attribute within a rule evaluation, for example, to make one story of a building taller than the others or to move the location of a single window in a large façade. In this situation, we can use local edits. These allow us to edit attributes with handles. Local edits are created by selecting the Local Edits Tool; depending on how the rule is structured, this tool may allow us to edit all local attributes in a row, column, or more complex patterns at once. Local edits are discussed further by Lipp et al. (2019).
As we modify rule attributes, we may be trying to achieve an objective target such as a target floor area for a building or group of buildings. CityEngine’s reporting mechanism allows rules to collate such information and then prepare a summary report for each model. The report operation accumulates values whenever it is invoked, returning a sum total for the entire model [we may use the operation report (“area”, 200)]. Multiple values (floor area, room volume, etc.) can be accumulated for each rule and displayed in the Inspector as a table. If CityEngine’s dashboard functionality is used, these tables can be presented as a range of graphs which update automatically. They can show results over all models in the scene or only those selected.
By taking the time to add reports to your models and using the dashboard functionality, it becomes possible to explore the design space interactively with a wide range of users. For example, clients may appreciate being able to use the handles to edit building heights and receive instant feedback on the effects of available floor area and construction costs.
Beyond raw reported analytics, we may be interested in the visual consequences of our designs. CityEngine provides a range of tools for measuring distance and area in the 3D scene (Fig. 35.16), but most interestingly provides visibility calculations; this highlights the areas of models which are visible or not from a certain location under a given field of view.
Finally, scenarios allow us to compare different events. Each scenario can contain different layers of content on top of a shared background. For example, three different developments proposed for a city block with different height can be shown, while the surrounding city remains constant. A scenario can be duplicated and edited to explore a new design space.