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.


Tuesday, 17 September 2013

CityEngine Starter Project 7 - Lessons learnt and the full rule file


Lessons learnt

As a result of this project I had learnt a number of things regarding rule file creation:

  • How to structure the rule file
  • How to create attributes and give them additional information such as a range
  • How to create functions and loops within the rule file
  • How to create a conditional (case) statement

Within the rule file I also was able to understand and use a number of CityEngine operations including:

  • Split
  • Extrude
  • Comp
  • Align
  • Set
  • Report
  • Setback
  • Roof operations
  • Translate
Looking back at what I intended to achieve a result of the project, I think I covered everything pretty well. I created a basic street and parcel network, however, I think that maybe some of the parcels are either to big and / or I could have added more streets. I created a rule file that included some very basic planning rules, I will of course include more rules in future but this will also require me to understand what the planning rules are, what they intend to allow or not allow to happen on a zone and how this can be translated into a rule file. I also created an output visualisation, this step was by far the easiest and using the Web Scene technology is something that I very much look forward to utilising again in future. 

The full rule file

Below is the full rule file created for this project:


/**

 * File:    StarterProject.cga
 * Created: 01 Jan 2013 01:02:07 GMT
 * Author:  ellawayc
 */

version "2012.1"

## Hidden Attributes ##
@Hidden
attr ParcelArea = 0
@Hidden
attr FootprintNeeded = 0
@Hidden
attr Length = 0
@Hidden
attr Width = 0

## Attributes ##

@Range("Residential","Commercial")
attr ZONETYPE = "Residential"
@Range(0,5)
attr YARD = 2.5
@Range(25,100)
attr COVERAGE = 30

## Functions ##

getHeight =
      25% : 8.5
      50% : 12.5
      else : 16.5

## Constants ##

## Assets ##

## Rules

@startRule

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

##### Residential Zone ##### 
ResidentialLot -->
      setback(YARD) {street.front : NIL  | remainder : ResidentialLot2}      
     
ResidentialLot2 -->
      innerRect
      shapeL(scope.sz*0.75,scope.sx*0.75) {shape : ResidentialLot3 | remainder : NIL}

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

ResidentialLot4 -->
      case geometry.area > FootprintNeeded : s('0.99,0,'0.99) center(xz) ResidentialLot4
      else : ResidentialLot5
     
ResidentialLot5 -->    
      extrude(world.y, 5)
      split(y){~0.25 : ResidentialLot6 BaseKeeper | 5 : NIL}     
     
ResidentialLot6 -->
      comp(f){top : alignScopeToGeometry(yUp, auto) ResidentialLot7}   

ResidentialLot7 -->    
      extrude(5.5)     
      comp(f){top : Roof | all : ResidentialLot8}    
     
Roof -->
      roofHip(18.5, 0.4)     
     
##### Commercial Zone #####  
CommercialLot -->
      innerRect  
      alignScopeToGeometry(yUp, 0, longest)    
      set(Length, scope.sx)
      set(Width, scope.sz)
      report("B Length (m)", Length)
      report("C Width (m)", Width)
      CommercialLot1
     
CommercialLot1 -->
      20% : CommercialLot3
            else :
                  case ParcelArea < 500 : CommercialLot3
                  case Width < 15 :
                        50% : setback(4){street.left : NIL | remainder : CommercialLot2}
                        else :      setback(4){street.right : NIL | remainder : CommercialLot2}
                  else :
                        50% : setback(scope.sz*0.2){street.left : NIL | remainder : CommercialLot2}
                        else :      setback(scope.sz*0.2){street.right : NIL | remainder : CommercialLot2}
                 
CommercialLot2 -->
      20% : CommercialLot3
            else :
                  case Length > 30 : setback(scope.sx*0.3){street.back : NIL | remainder : CommercialLot3}
                  else :
                        50% : setback(4){street.back : NIL | remainder : CommercialLot3}             
                        else : CommercialLot3
                 
CommercialLot3 -->
      extrude(world.y, 5)
      split(y){~0.25 : CommercialLot4 BaseKeeper | 5 : NIL}                        
                 
CommercialLot4 -->
      comp(f){top : alignScopeToGeometry(yUp, auto) CommercialLot5}                
     
CommercialLot5 -->
      extrude(getHeight)                 
      split(y){4.5 : GroundFloor | {~4 : UpperFloor(split.index, split.total)}*}         
                 
GroundFloor -->
      comp(f){side: GroundFloor1}              
                 
GroundFloor1 -->
      split(x){0.5 : Wall | ~5 : LargeWindow | 3 : Entrance | {~5 : LargeWindow}* | 0.5 : Wall}
                 
UpperFloor(idx,n) -->              
      case idx == n-1 : TopFloor UpperFloor1
      else : UpperFloor1           

UpperFloor1 -->
      comp(f){side: UpperFloor2}
     
UpperFloor2 -->
      split(x){0.5 : Wall | {~2.5 : Window}* | 0.5 : Wall}                   
     
LargeWindow -->
      split(x){0.25 : SolidWall | ~5 : split(y){0.50 : SolidWall | ~1 : LargeWindow1 | 0.25 : SolidWall} | 0.25 : SolidWall}                 
                 
LargeWindow1 -->
      t(0,0,-0.4)
           
Window -->
      split(x){0.2 : SolidWall | ~2.5 : split(y){0.2 : SolidWall | ~1 : Window1 | 0.2 : SolidWall} | 0.2 : SolidWall}            

Window1 -->
      t(0,0,-0.2)

Entrance -->
      split(x){0.2 : SolidWall | ~2.5 : split(y){~1 : Entrance1 | 0.35 : SolidWall} | 0.2 : SolidWall}
     
Entrance1 -->
      t(0,0,-0.4)
           
SolidWall -->
      extrude(0.4)
      t(0,-0.4,0)            
     
TopFloor -->
      comp(f){top : CommercialRoof}
     
CommercialRoof -->
      extrude(0.15)    
      comp(f){top : CommercialRoof1 RoofKeeper | all : RoofKeeper }    

CommercialRoof1 -->
      setback(0.4){all : CommercialRoof2}
     
CommercialRoof2 -->
      extrude(0.4)        

No comments:

Post a Comment