Importing Code from Other Scripts Using CGA “Includes”

If you are an experienced programmer who is familiar with the idea of "includes" in code, you may have landed here while searching for how to do them in CGA.  Well, CGA uses the term "import" rather than "include"; look for it under CGA Shape Grammar Reference > Other Keywords in the CityEngine online help files.

Experienced coders know that includes (from now on, I'll call them imports) allow us to create modules of code that can be called from other scripts as they are needed. This is great if there are unchanging snippets of code you use often:

  • Call in whatever cga files you need using the import function.
  • You don't have to rewrite the code again in every script where its used.
  • Changing the code in one place will modify the code everywhere..
  • You don't have to look through one long, scrolling page of code to find errors or make changes.

Before I get into this further, I should mention we are coming at this subject kind of sideways.  Imports are part of a larger CityEngine feature, the ability to use permanent sets of resources contained within LIBRARIES. One example is the trove of texture and tree images in the ESRI.lib folder, as seen in the illustration on the right.  Go through the folders and look at some of the resources. Accessing them in a project is as simple as declaring a file path. Let's look at the library example we cited in our analysis of the International City that is generated using CE's City Wizard - VIEW THE PAGE.

For this exercise, I have created a file called MyRules under ESRI.lib/rules.  Here is where I will place all of the rule files I want to call from any project.

A rule file is called from another by using the import statement followed by a file path.

Now will use code similar to the ColorTheCube exercise in our previous installment Annotations #1.  But rather than having a single CGA file, we will have one master document and call the other two scripts from the Library. Locate the files as follows:

  • rules/ColorTheCubeMaster.cga (in your project folder)
  • /ESRI.lib/rules/MyRules/ColorTheCube_1.cga
  • /ESRI.lib/rules/MyRules/ColorTheCube_2.cga

Note that the two ESRI.lib file locations are both preceded by a slash /  indicating this is an absolute path to the workspace root. If we were to call a script or resource within our project, we would use a relative file path such as rules/rulename.cga with no preceding slash.

Here are the three scripts. Copy them and create rule files in the locations we have noted.

First is the "master" script, to be located in our project folder:

/**
 * File: ColorTheCube_Master.cga
 * Created: 12 Feb 2018 19:07:02 GMT
 * Author: Jeff Herzer | jeffherzer.com
 */

version "2017.1"

import ColorTheCube_1: "/ESRI.lib/rules/MyRules/ColorTheCube_1.cga"
import ColorTheCube_2: "/ESRI.lib/rules/MyRules/ColorTheCube_2.cga"


// Shape Inspector Controls
@Group("Dimensions", 1)
@Range(1,5)
attr dimX = 1
@Range(1,5)
attr dimY = 1
@Range(1,5)
attr dimZ = 1

@StartRule
Start--> 
 primitiveCube(dimX,dimY,dimZ)
 ColorTheCube_1.CubeFaces
 ColorTheCube_2.CubeFaces

We start by importing the two scripts from the library, then we set up controls in the Shape Inspector for x,y,z dimensions using the @Group annotation.

  • The rule Start --> is marked as a start rule with the @StartRule annotation.
  • The Start --> rule creates a primitive cube and sets its x,y,z dimensions. We can adjust these dynamically in the Shape Inspector. Then we call the rule CubeFaces --> from both the library scripts.

Here is the next one:

/**
 * File: ColorTheCube_1.cga
 * Created: 12 Feb 2018 19:07:39 GMT
 * Author: Jeff Herzer | jeffherzer.com
 */

version "2017.1"

@Group("Faces", "Colors", 2)

@Group("Faces", "Colors", Front, 3)
@Color
attr colorFront = "#00ffff"


@Group("Faces", "Colors", Back, 4)
@Color
attr colorBack = "#ff00ff"


CubeFaces -->
 comp(f){
 front: CubeFront |
 back : CubeBack 
 }

CubeFront -->
 color(colorFront)
CubeBack -->
 color(colorBack)

The cube is split into its component faces in the comp(f) operation.  The front and back faces are assigned to rules that color them. On to the third script:

/**
 * File: ColorTheCube_2.cga
 * Created: 12 Feb 2018 19:07:56 GMT
 * Author: Jeff Herzer | jeffherzer.com
 */

version "2017.1"


@Group("Faces", "Colors", 2)

@Group("Faces", "Colors", Left, 3)
@Color
attr colorLeft = "#ffff00"


@Group("Faces", "Colors", Right, 4)
@Color
attr colorRight = "#000000"


CubeFaces -->
 comp(f){
 left : CubeLeft |
 right : CubeRight
 }

CubeLeft -->
 color(colorLeft)
CubeRight -->
 color(colorRight)

This is the same as the second script, except we are selecting the left and right faces and sending them to rules that will apply colors.

Apply the ColorTheCube_Master.cga file to your shape.  In the Shape Inspector, you'll see all three rule files listed next to a drop-down menu for STYLES. We will get to this in our next installment.

*   *   *   *   *

Just for fun let's texture one of the cube faces using a library resource.  I created a folder named MyTextures under ESRI.lib/assets and copied my texture image file (an old TV test pattern) there. In the ColorTheCube_1.cga file, change the CubeFront --> rule as follows:

CubeFront -->
 setupProjection(0, scope.xy, '1, '1)
 projectUV(0)
 texture("/ESRI.lib/assets/MyTextures/theTextureFile.png")

This code was covered in a previous installment on Projecting UV Textures.

Leave a Reply

Your email address will not be published. Required fields are marked *