About CityEngine Blog


CityEngine is a great tool that is able to create large scale models, mainly of cityscapes, quickly, and with the ability to make adjustments based on a rule file in a procedural manner.

I hope to show you some of the work I have done with CityEngine creating a variety of models across a range of projects. I have mainly used the software for planning applications but have learnt a great deal of the potential for other applications.

I want to concentrate on the writing of rule files which is the core use of CityEngine. Without rule files no 3D content can be generated and this is very important to understand. I will also strive to bring news and updates regarding CityEngine as well.

I hope you find what I share useful and please feel free to share and contribute your thoughts and experience.


Wednesday, 4 September 2013

CityEngine Starter Project 3 - Basic CGA operations, simple calculations and elementary looping


Basic CGA operations

Now I wanted to separate the shapes by ZONETYPE. This would allow me to work on the different zone types individually. First I carried out a case (conditional) statement. To do this I needed to close the Lot rule and pass the transformed shape onto a single successor (Lot1). The successor could then be used to carry out the conditional rule:

## Rules

@startRule

Lot -->
     alignScopeToGeometry(yUp, auto)
     set(ParcelArea, geometry.area)
     report("A Parcel Area (m2)", ParcelArea)
     Lot1
    
Lot1 -->
     case ZONETYPE == "Residential" : ResidentialLot
     else : CommercialLot

Note that a case statement must include an else, and that there are a number of special characters that must be used. Now I had a successor that contained the residential shapes (ResidentialLot) and another that contained the commercial shapes (CommercialLot)

Now concentrating on the residential buildings, I wanted to apply a yard rule by adding a setback operation using the streetside selector. A new attribute called YARD was added under the Attributes heading and a default value of 2.5 was chosen. I also included a range that allows values from 0m to 5m. Note that this is not a text based attribute so the " " characters are not needed.

@Range(0,5)
attr YARD = 2.5

Using the ResidentialLot successor I applied the code below - the setback operation. Note that the operation has certain information that it requires - the setback distance, setback selector operator and the remainder operator.

ResidentialLot -->
      setback(YARD) {street.front : NIL  | remainder : ResidentialLot2}

After updating the models you can now see that the residential shapes now have the yard area removed. The slider YARD slider can be played with to increase/decrease the setback distance.


In this example, I knew that all of the parcel shapes were regular in their geometry (all nice rectangles) and so only a few simple operations needed to be applied to achieve my simple goals. By removing the yard area it guarantees that the residential buildings would not be built within the yard. This is a pretty basic planning rule that is often applied to all types of zoning. Now I could concentrate on the building shape before making the building the coverage I wanted.

On the ResidentialLot2 successor I carried out an innerRect function (to give a completely regular rectangle) and then an shapeL function that will give the building a more of a house feel. This is a very basic residential structure and could be made far more complex by adding further operations. Instead of just one operation before a successor is generated, you can see that here I have stacked the innerRect and ShapeL operations together before having to create a successor.

ResidentialLot2 -->
     innerRect
     shapeL(scope.sz*0.75,scope.sx*0.75) {shape : ResidentialLot3 | remainder : NIL}


Simple calculations and elementary looping

I now had a simple house style shape. The next type of planning rule that I wished to apply was a building coverage. I created an attribute and slider called COVERAGE (under the Attributes heading) that had a default value of 30 (%) and a range of 25 to 100 (%). This is the coverage as a percentage of the original parcel area (ParcelArea).

@Range(25,100)
attr COVERAGE = 30

On the next successor (ResidentialLot3) I added a Set and Report operation that calculate the size of the geometry area that we need to meet the to reach the coverage required (FootprintNeeded). This requires setting a value that takes the ParcelArea and calculates the FootprintNeeded as a percentage. In order for the FootprintNeeded value to be set I also needed to create a Hidden Attribute (just like for ParcelArea) 

ResidentialLot3 -->
     set(FootprintNeeded, (ParcelArea/100)*COVERAGE)
     report("B Footprint Needed (m2)", FootprintNeeded)  
     ResidentialLot4

A simple loop was created where the successor is continually passed back to the parent, gradually decreasing the shape size until the area is the same or less than the value for FootprintNeeded. A size operation within a case statement asks if the geometry.area is more than the FootprintNeeded, if so the shape is reduced in size, and is centred. It is then passed back up to the parent successor where the same case statement works again until the area is as required and past to a new successor.

ResidentialLot4 -->
     case geometry.area > FootprintNeeded : s('0.99,0,'0.99) center(xz) ResidentialLot4
     else : ResidentialLot5

Note the characters used in the size function. The apostrophe evokes the relative use of the operator, essentially in this case I reduced the size of the shape to 99% of its original size each time it passes through the loop. The models now looked like the image below, reflecting the coverage that is required.


The 2D element to the residential buildings were now pretty much complete. I could of course play with the sliders to dynamically change either or both the Yard and Coverage values but the image above shows all shapes with the default.

In the next post I'll run through how to create some simple code that deals with a very gentle terrain and also some basic model detail to take our 2D shapes and create 3D models.











No comments:

Post a Comment