/** * File: International City.cga * Created: 6 Nov 2013 * Updated: 11 April 2014 * Author: Esri R&D Center Zurich */ version "2014.0" # # City Wizard Example Rule # # Notes: # - since city wizard examples have to run on arbitrary lot sizes, lots might be subdivided further in the grammar # - the different building types are depending on the distance to origin (usually this is controlled via landuse maps etc) # import Street_Modern_Standard: "/ESRI.lib/rules/Streets/Street_Modern_Standard.cga" @Hidden import Facade_Textures : "/ESRI.lib/rules/Facades/Facade_Textures.cga" () # completely controlled in rules below @Hidden import Roof_Textures : "/ESRI.lib/rules/Roofs/Roof_Textures.cga" () # completely controlled in rules below @Hidden import Plant_Loader : "/ESRI.lib/rules/Plants/Plant_Loader.cga" () # completely controlled in rules below ###################################################### # control attributes (set by user or mapped) # @Group("Building",1) @Order(1) @Range("Highrise Building","Office Building","Apartment Building","Residential","Open Space") @Order(1) attr Type = getType @Order(2) @Range(0.5,2) attr HeightFactor = 1 @Group("Trees",3) @Order(1) @Range("None","Fan","Model","Analytical") @Description("Do not generate Models for whole city i.e. take care with polygon counts!") attr ShowTrees = "Fan" @Order(2) @Range("Random Forest","Tropical","Zone 6 Trees") attr Mix = "Zone 6 Trees" # Mapped Attributes for Streets (comming from graph) @Hidden @Order(1) @Range(0,30) attr streetWidth = geometry.dv(0,unitSpace) # REALWORLD-distance in V-direction corresponds to width of street (in case the geometry does not contain rounded entry geometry) @Hidden @Order(2) @Range(1,6) attr laneWidth = streetWidth/geometry.dv(0,uvSpace) # note that TEXTURE-distance in V-direction corresponds to number of lanes (as generated by CityEngine) @Hidden @Order(3) attr connectionEnd = "STREET" # built in value attributes, needs to be sourced as Object (parent) @Hidden @Order(4) attr connectionStart = "STREET" # built in value attributes, needs to be sourced as Object (parent) @Hidden @Order(5) attr valency = 0 # Constants const getType = case distanceToCenter < radiusHighriseArea : 80%: "Highrise Building" 15%: "Office Building" 2%: "Apartment Building" else: "Open Space" # mainly highrises and commercial case distanceToCenter < radiusCommercialArea : 29%: "Highrise Building" 60%: "Office Building" 10%: "Apartment Building" else: "Open Space" # mainly offices case distanceToCenter < radiusApartmentArea : 20%: "Office Building" 76%: "Apartment Building" 3%: "Residential" else: "Open Space" # mainly apartments case distanceToCenter < radiusResidentialArea: 5%: "Office Building" 40%: "Apartment Building" 53%: "Residential" else: "Open Space" # mainly residential and apartments else : 1%: "Office Building" 4%: "Apartment Building" 90%: "Residential" else: "Open Space" # more or less only residential const radiusHighriseArea = 500 const radiusCommercialArea = 900 const radiusApartmentArea = 1300 const radiusResidentialArea = 1600 const distanceToCenter = sqrt(initialShape.origin.px*initialShape.origin.px +initialShape.origin.pz*initialShape.origin.pz) ################################################### ################################################### ## ## RULES ## ## @StartRule Lot --> translate(rel,world,0,Street_Modern_Standard.SidewalkHeight,0) LotAligned LotInner --> translate(rel,world,0,Street_Modern_Standard.SidewalkHeight,0) LotInnerAligned LotCorner --> Street_Modern_Standard.Pavement ###################################################3 # Type Distribution # LotAligned --> case Type == "Open Space" : GreenGround Trees case Type == "Residential" : ResidentialBlock case Type == "Apartment Building" : ApartmentBlock case Type == "Office Building" : CommercialBlock else : HighriseBlock LotInnerAligned --> case Type == "Open Space" : GreenGround Trees case Type == "Residential" : 5%: ResidentialBlock else: GreenGround Trees case Type == "Apartment Building" : 5%: ApartmentBlock 10%: ParkingGround else: GreenGround Trees case Type == "Office Building" : 10%: CommercialBlock 20%: ParkingGround else: GreenGround Trees else : 30%: HighriseBlock 20%: ParkingGround else: GreenGround Trees ###################################################3 # Residential # @Hidden attr buildingHeight = 0 @Hidden attr groundFloorHeight = 0 @Hidden attr roofAngle = rand(15,25) @Hidden attr roofOverhang = 10%: 0 else: rand(0.2,0.6) extensionRoofType = 70%: "gable" else: "hip" garageRoofType = 20%: "gable" else: "flat" getUpperfloorHeight = case buildingHeight-groundFloorHeight > 2: buildingHeight-groundFloorHeight else: 2.5 # Block Parceling (in case needed) ######## ResidentialBlock --> # here we subdivide the initial shape further in case it is too big (to get kind of row housing...) case scope.sx > 20 : setback(rand(20,35)){ front: ResidentialBlockStripe | remainder: ResidentialBlockBack } else : ResidentialBlockBack ResidentialBlockBack --> case scope.sz > 20 : setback(rand(20,35)){ left: ResidentialBlockStripe | remainder: ResidentialBlockRight } else : ResidentialBlockStripe ResidentialBlockRight --> case scope.sz > 20 : setback(rand(20,35)){ right: ResidentialBlockStripe | remainder: GreenGround Trees Trees } else : ResidentialBlockStripe ResidentialBlockStripe --> alignScopeToGeometry(yUp, 0, longest) ResidentialBlockStripeSubdivide ResidentialBlockStripeSubdivide --> case scope.sx > 30: split(x){ ~rand(16,30): ResidentialBlockStripeSubdivide }* case geometry.isConcave && scope.sx > 25: # concaves are subdivided further (trying to get rid of the concavity) split(x){ ~rand(14,23): ResidentialBlockStripeSubdivide }* case p(0.3) && geometry.isConcave && scope.sz > 25: split(z){ ~rand(14,23): ResidentialBlockStripeSubdivide }* case p(0.3) && geometry.isRectangular(25) && scope.sz > scope.sx*3: split(z){ ~1: alignScopeToGeometry(yUp,2) ResidentialLot | ~1: ResidentialLot } else: ResidentialLot # Lot Preperation ######## ResidentialLot --> GreenGround ResidentialLotAlign ResidentialLotAlign --> case geometry.nVertices < 4: Trees case !geometry.isRectangular(10): innerRect split(x){ 1 : NIL | 'rand(.85,.9): split(z){ ~rand(1,3): Trees | (rand(15,20)): ResidentialBuildingArea | ~1: Trees } | 1 : NIL } else: split(x){ 1 : NIL | 'rand(.85,.9): split(z){ ~rand(1,3): Trees | (rand(15,20)): ResidentialBuildingArea | ~1: Trees } | 1 : NIL } ResidentialBuildingArea --> case scope.sx < 10 || scope.sz < 10: # too small to build a house NIL else: alignScopeToAxes(y) s('1,0,'1) # there are different possibilites to handle non-horizontal lots... scaling it to zero in the y-direction like here is the simplest way to handle it ResidentialBuilding # Building Generation ######## ResidentialBuilding --> # building settings set(buildingHeight, 20%: rand(3,3.5) else: rand(5,6.5)) set(groundFloorHeight, rand(2.9,3.4)) set(roofAngle, rand(15,25)) set(roofOverhang, 20%: 0 else: rand(0.2,0.6)) # facade settings set(Facade_Textures.Usage, "Residential") set(Facade_Textures.BuildingHeight, buildingHeight*HeightFactor) set(Facade_Textures.UpperfloorsTexture, Facade_Textures.getUpperfloorsTexture) set(Facade_Textures.GroundfloorTexture, Facade_Textures.getGroundfloorTexture) set(Facade_Textures.UpperfloorHeight, getUpperfloorHeight) set(Facade_Textures.GroundfloorHeight, groundFloorHeight) set(Facade_Textures.TileWidth, rand(2.6,3)) # roof settings set(Roof_Textures.FlatRoofTexture, Roof_Textures.getFlatRoofTexture) set(Roof_Textures.SlopedRoofTexture, Roof_Textures.getSlopedRoofTexture) # invoke geometry creation ResidentialShape set(Facade_Textures.GroundfloorHeight, 0) ResidentialExtension ResidentialGarage # Stochastic Mass Model Composition ######## ResidentialShape --> s('rand(0.6,0.8),0,'rand(0.45,0.6)) center(xz) ResidentialShape(buildingHeight) ResidentialShape(h) --> 15% : Mass(h,"gable") 5% : Mass(h,"hip") 17% : [ s('1.0,0,'0.8) Mass(h,"gable") ] split(x){ 'rand(0.35,0.6): t(0,0,'0.4) s('1,0,'rand(0.45,0.65)) Mass(h,"gable2") } # L-shape left for gable roofs 17% : [ s('1.0,0,'0.8) Mass(h,"hip") ] split(x){ 'rand(0.35,0.6): t(0,0,'0.1) s('1,0,'rand(0.8,0.95)) Mass(h,"hip") } # L-shape left for hip roofs 17% : [ s('1.0,0,'0.8) Mass(h,"gable") ] split(x){ ~1: NIL | 'rand(0.35,0.6): t(0,0,'0.4) s('1,0,'rand(0.45,0.65)) Mass(h,"gable2") } # L-shape right for gable roofs 17% : [ s('1.0,0,'0.8) Mass(h,"hip") ] split(x){ ~1: NIL | 'rand(0.35,0.6): t(0,0,'0.1) s('1,0,'rand(0.8,0.95)) Mass(h,"hip") } # L-shape right for hip roofs 5% : [ s('1.0,0,'0.8) Mass(h,"gable") ] split(x){ ~1: NIL | 'rand(0.35,0.6): t(0,0,'0.4) s('1,0,'rand(0.55,0.65)) Mass(h,"gable2") | ~1: NIL } # T-shape for gable roofs 5% : [ s('1.0,0,'0.8) Mass(h,"hip") ] split(x){ ~1: NIL | 'rand(0.35,0.6): t(0,0,'0.1) s('1,0,'rand(0.8,0.95)) Mass(h,"hip") | ~1: NIL } # T-shape for hip roofs 1% : [ s('1.0,0,'0.8) Mass(h,"gable") ] t(0,0,'0.4) s('1,0,'rand(0.55,0.65)) split(x){ 'rand(0.3,0.4): Mass(h,"gable2") | ~1: NIL | 'rand(0.3,0.4): Mass(h,"gable2") } # U-shape for gable roofs else: [ s('1.0,0,'0.8) Mass(h,"hip") ] t(0,0,'0.1) s('1,0,'rand(0.8,0.95)) split(x){ 'rand(0.3,0.4): Mass(h,"hip") | ~1: NIL | 'rand(0.3,0.4): Mass(h,"hip") } # U-shape for hip roofs ResidentialExtension --> 7% : split(z){ (rand(1,3)): NIL | ~1: Mass(rand(3,4),extensionRoofType) | (rand(1,3)): NIL } 18% : split(z){ '(rand(.4,.7)): split(x){ '(rand(.3,.7)): Mass(rand(3,4.5),extensionRoofType) } } 18% : split(z){ '(rand(.2)): NIL | '(rand(.2,.5)): split(x){ '(rand(.3,.7)): Mass(rand(3,4.5),extensionRoofType) } } 18% : split(z){ '(rand(.4,.7)): split(x){ ~1: NIL | '(rand(.3,.7)): Mass(rand(3,4.5),extensionRoofType) } } 18% : split(z){ '(rand(.2)): NIL | '(rand(.2,.5)): split(x){ ~1: NIL | '(rand(.3,.7)): Mass(rand(3,4.5),extensionRoofType) } } else: NIL ResidentialGarage --> 46% : split(z){ ~1: NIL | '(rand(.3,.6)): split(x){ (rand(5,8)): Mass(groundFloorHeight,garageRoofType) } | '(rand(.05,.25)): NIL } 46% : split(z){ ~1: NIL | '(rand(.3,.6)): split(x){ ~1: NIL | (rand(5,8)): Mass(groundFloorHeight,garageRoofType) } | '(rand(.05,.25)): NIL } else: NIL # Mass Model ######## Mass(h,rooftype) --> extrude(h*HeightFactor) Stories comp(f){top: Roof(rooftype) } Stories --> comp(f){ side: Facade } Facade --> Facade_Textures.Generate ###################################################3 # Appartments # ApartmentBlock --> case scope.sx > 60: split(x){ (rand(35,50)): ApartmentLot | ~1: ApartmentBlock } else: ApartmentLot ApartmentLot --> GreenGround ApartmentLotAlign ApartmentLotAlign --> cleanupGeometry(all, 1) offset(-rand(2,4), inside) split(z){ ~rand(1,3): Trees | (rand(20,30)): ApartmentBuildingArea | ~1: FewTrees } ApartmentBuildingArea --> case scope.sx < 20: # too small to build a house NIL else: alignScopeToAxes(y) s('1,0,'1) # there are different possibilites to handle non-horizontal lots... scaling it to zero in the y-direction like here is the simplest way to handle it ApartmentBuilding ApartmentBuilding --> # building settings set(buildingHeight, rand(8,14)) set(groundFloorHeight, rand(3.1,4)) set(roofAngle, rand(15,25)) set(roofOverhang, 10%: 0 else: rand(0.5,1)) # facade settings set(Facade_Textures.Usage, "") set(Facade_Textures.BuildingHeight, buildingHeight*HeightFactor) set(Facade_Textures.UpperfloorsTexture, Facade_Textures.getUpperfloorsTexture) set(Facade_Textures.GroundfloorTexture, Facade_Textures.getGroundfloorTexture) set(Facade_Textures.UpperfloorHeight, rand(2.7,3.2)) set(Facade_Textures.GroundfloorHeight, groundFloorHeight) set(Facade_Textures.TileWidth, rand(2.7,3.5)) # roof settings set(Roof_Textures.FlatRoofTexture, Roof_Textures.getFlatRoofTexture) set(Roof_Textures.SlopedRoofTexture, Roof_Textures.getSlopedRoofTexture) # invoke geometry creation ApartmentShape(buildingHeight) ApartmentShape(h) --> 25% : shapeL(scope.sz*rand(0.4,0.8),scope.sx*rand(0.3,0.4)){ shape: ApartmentMass(h) } 25% : shapeU(scope.sz*rand(0.4,0.8),scope.sx*rand(0.3,0.4),0){ shape: ApartmentMass(h) } 25% : shapeU(scope.sz*rand(0.4,0.7),scope.sx*rand(0.2,0.4),scope.sx*rand(0.2,0.4)){ shape: ApartmentMass(h) } else: shapeO(0,scope.sx*rand(0.2,0.4),scope.sz*rand(0.4,0.7),scope.sx*rand(0.2,0.4)){ shape: ApartmentMass(h) } ApartmentMass(h) --> 30% : Mass(h,"gable") 25% : Mass(h,"hip") else: Mass(h,"flat") ###################################################3 # Office Buildings # commercialBuildingWidth = 70%: rand(15,25) else: rand(25,80) CommercialBlock --> case scope.sz > 40: setback(rand(40,80)){ front: CommercialRow | remainder: rotateScope(0,180,0) CommercialRow } else: CommercialRow CommercialRow --> case scope.sx > 30: split(x){ commercialBuildingWidth: CommercialLot | ~1: CommercialRow } else: CommercialLot CommercialLot --> 40% : split(z){ '(rand(0.2,0.4)): ParkingGround | ~1: ParkingGround CommercialBuildingArea(1) | (rand(4)): GreenGround } # 20% with a setback 30% : GreenGround split(z){ '(rand(0.2,0.4)): FewTrees | ~1: CommercialBuildingArea(1) } else: GreenGround split(z){ '(rand(0.2,0.4)): Trees | ~1: CommercialBuildingArea(1) } CommercialBuildingArea(count) --> case scope.sx < 10 || scope.sz < 10: # too small to build a house NIL else: alignScopeToAxes(y) s('1,0,'1) # there are different possibilites to handle non-horizontal lots... scaling it to zero in the y-direction like here is the simplest way to handle it CommercialBuilding(count) CommercialBuilding(count) --> cleanupGeometry(all, 1) # building settings set(buildingHeight, case scope.sx>40: rand(16,30) else: rand(10,20)) set(groundFloorHeight, rand(4,5.5)) set(roofAngle, rand(20,30)) set(roofOverhang, 0) # facade settings set(Facade_Textures.Usage, "") set(Facade_Textures.BuildingHeight, buildingHeight*HeightFactor) set(Facade_Textures.UpperfloorsTexture, Facade_Textures.getUpperfloorsTexture) set(Facade_Textures.GroundfloorTexture, Facade_Textures.getGroundfloorTexture) set(Facade_Textures.UpperfloorHeight, rand(2.8,3.3)) set(Facade_Textures.GroundfloorHeight, groundFloorHeight) set(Facade_Textures.TileWidth, rand(2.2,3.7)) # roof settings set(Roof_Textures.FlatRoofTexture, Roof_Textures.getFlatRoofTexture) set(Roof_Textures.SlopedRoofTexture, Roof_Textures.getSlopedRoofTexture) # invoke geometry creation offset(case scope.sx>30 && p(0.6): -rand(2,6) else: 0,inside) CommercialShape(buildingHeight) CommercialShape(h) --> 35% : shapeL(scope.sz*rand(0.7,0.95),scope.sx*rand(0.2,0.8)){ shape: CommercialMass(h) } 35% : shapeU(scope.sz*rand(0.7,0.95),scope.sx*rand(0.2,0.8),0){ shape: CommercialMass(h) } else: shapeU(scope.sz*rand(0.8,0.95),scope.sx*rand(0.2,0.45),scope.sx*rand(0.2,0.45)){ shape: CommercialMass(h) } CommercialMass(h) --> 99% : Mass(h,"rooffloor") else: Mass(h,"flat") ###################################################3 # Highrise # # function: distance to center controls the building height highriseBuildingHeight = case distanceToCenter < radiusHighriseArea/4 && geometry.area > 2000 : rand(200,350) //rand(100,250) case distanceToCenter < radiusHighriseArea/4 && geometry.area > 600 : rand(120,250) //rand(100,250) case distanceToCenter < radiusHighriseArea/2 && geometry.area > 300 : rand(80,200) //rand(80,150) case distanceToCenter < radiusHighriseArea && geometry.area > 150 : rand(20,100) //rand(40,80) case distanceToCenter < (radiusHighriseArea+radiusCommercialArea)/2 : rand(30,60) else : rand(20,50) HighriseBlock --> HighriseBlock(0) HighriseBlock(index) --> case index >= geometry.nEdges || geometry.nVertices == 3: CommercialLot case scope.sz > 50: split(z){ ~1: alignScopeToGeometry(yUp,index+1) HighriseBlock(index+1) | (rand(40,80)): HighriseRow } else: alignScopeToGeometry(yUp,index+1) HighriseRow HighriseRow --> case scope.sx > 60: split(x){ (rand(40,80)): HighriseLot | ~1: HighriseRow } else: HighriseLot HighriseLot --> case scope.sx < 30 || scope.sz < 30: # too small to build a house CommercialLot else: ParkingGround alignScopeToAxes(y) s('1,0,'1) # there are different possibilites to handle non-horizontal lots... scaling it to zero in the y-direction like here is the simplest way to handle it HighriseBuilding(rand(7,12)) HighriseBuilding(lowerH) --> cleanupGeometry(all, 1) # building settings set(buildingHeight, highriseBuildingHeight) set(groundFloorHeight, rand(4.5,6)) set(roofAngle, rand(20,30)) set(roofOverhang, 0) # facade settings set(Facade_Textures.Usage, "") set(Facade_Textures.BuildingHeight, buildingHeight*HeightFactor) set(Facade_Textures.UpperfloorsTexture, Facade_Textures.getUpperfloorsTexture) set(Facade_Textures.GroundfloorTexture, Facade_Textures.getGroundfloorTexture) set(Facade_Textures.UpperfloorHeight, rand(2.9,3.4)) set(Facade_Textures.GroundfloorHeight, groundFloorHeight) set(Facade_Textures.TileWidth, rand(2.2,3.9)) # roof settings set(Roof_Textures.FlatRoofTexture, Roof_Textures.getFlatRoofTexture) set(Roof_Textures.SlopedRoofTexture, Roof_Textures.getSlopedRoofTexture) # invoke geometry creation offset(30%: -sqrt(geometry.area)*rand(0.05,0.1) else: 0, inside) Mass(lowerH/HeightFactor,"flat") t(0,lowerH,0) offset(50%: -sqrt(geometry.area)*rand(0.05,0.1) else: 0, inside) HighriseUpper # Highrise Type Decision ##### HighriseUpper --> case distanceToCenter < radiusHighriseArea/2 : 45%: InternationalTower 45%: SetbackTower 5%: HighriseShape else: LShape(highriseBuildingHeight*0.5) case distanceToCenter < radiusHighriseArea/2 : 40%: InternationalTower 30%: SetbackTower 25%: HighriseShape else: LShape(highriseBuildingHeight*0.5) case distanceToCenter < radiusHighriseArea : 45%: InternationalTower 5%: SetbackTower 40%: HighriseShape else: LShape(highriseBuildingHeight*0.5) else : 40%: InternationalTower 1%: SetbackTower 55%: HighriseShape else: LShape(highriseBuildingHeight*0.5) # Highrise L/U-Shape ##### HighriseShape --> case scope.sz > 40 && p(0.5): split(z){ 'rand(.1,.3): NIL | ~1: HighriseShape } else: 70% : LShape(highriseBuildingHeight) 20% : UShape(highriseBuildingHeight) else: split(z){ ~1: NIL | 'rand(.4,.6): HighriseMass } LShape(h) --> split(z){ ~1: LShapeWing(h) | 'rand(.4,.6): HighriseMass(h) } LShapeWing(h) --> 50% : split(x){ ~1 : NIL | 'rand(0.4,0.6) : Wing(h) } // right side else: split(x){ 'rand(0.4,0.6) : Wing(h) } // left side UShape(h) --> case scope.sx > scope.sz: split(z){ ~1: UShapeWings(h) | 'rand(0.4,0.7): HighriseMass(h) } else: split(z){ 'rand(.3,.4): HighriseMass(h) | ~1: CHWing(h) | 'rand(.3,.4): HighriseMass(h) } UShapeWings(h) --> split(x){ 'rand(0.3,0.4): Wing(h) | ~1: NIL | 'rand(0.3,0.4): Wing(h) } Wing(h) --> 30% : HighriseMass(h) // same height 30% : HighriseMass(h*rand(0.5,0.9)) // lower height 1 else: HighriseMass(highriseBuildingHeight*rand(0.5,0.7)) // lower height 2 CHWing(h) --> 40% : split(x){ ~1: NIL | 'rand(0.5,0.7): HighriseMass(h) | ~1: NIL } 30% : split(x){ 'rand(0.5,0.7): HighriseMass(h) } else: split(x){ ~1: NIL | 'rand(0.5,0.7): HighriseMass(h) } HighriseMass --> Mass(buildingHeight,"rooffloor") HighriseMass(h) --> Mass(h,"rooffloor") # Setback Tower ##### lowHeight = 50% : 0.3 else: 0.7 // switching between these two values creates visually appealing setbacks const offset = rand(0.05,0.1) SetbackTower --> case scope.sx < 20 || scope.sz < 20: LShape(highriseBuildingHeight*0.3) case scope.sx < 30: shapeO(scope.sz*0.1,0,scope.sz*0.1,0){ remainder: extrude(buildingHeight*HeightFactor*rand(0.9,1)) RecursiveSetbacks } shapeO(0,scope.sx*0.21,0,scope.sx*0.21){ remainder: extrude(buildingHeight*HeightFactor) RecursiveSetbacks } case p(0.5): shapeO(scope.sz*0.15,0,scope.sz*0.15,0){ remainder: extrude(buildingHeight*HeightFactor*rand(0.9,1)) RecursiveSetbacks } shapeO(0,scope.sx*0.21,0,scope.sx*0.21){ remainder: extrude(buildingHeight*HeightFactor) RecursiveSetbacks } else: shapeO(scope.sz*0.21,0,scope.sz*0.21,0){ remainder: extrude(buildingHeight*HeightFactor) RecursiveSetbacks } shapeO(0,scope.sx*0.1,0,scope.sx*0.1){ remainder: extrude(buildingHeight*HeightFactor*rand(0.9,1)) RecursiveSetbacks } RecursiveSetbacks --> case scope.sy > 10 && scope.sx > 10 && scope.sz > 10: split(y){ 'lowHeight : Stories comp(f){top: Roof("flat") } | ~1: RecursiveSetbacksCall(scope.sy) } else: s('1,5,'1) Stories comp(f){top: Roof("rooffloor") } RecursiveSetbacksCall(h) --> t(0,-h,0) comp(f){top: alignScopeToAxes(y) shapeO(scope.sz*offset,scope.sx*offset,scope.sz*offset,scope.sx*offset) { remainder: extrude(h) RecursiveSetbacks } } # International Style ##### InternationalTower --> case sqrt(geometry.area) < 35: split(z){ (sqrt(geometry.area)): HighriseMass(buildingHeight*0.7) } case p(0.7): split(z){ (sqrt(geometry.area)*0.4): HighriseMass | ~1: [ extrude(0.2) GreenGround ] t(0,0.2,0) Trees } case p(0.1): split(z){ (sqrt(geometry.area)*0.4): HighriseMass } else: LShape(highriseBuildingHeight*0.7) ###################################################3 # Roof Generation # Roof(rooftype) --> case rooftype == "rooffloor": RoofPlane alignScopeToGeometry(yUp,auto) RoofFloor case rooftype == "gable1": roofGable(roofAngle,roofOverhang,roofOverhang,false,1) comp(f){ bottom: NIL | vertical: Facade | all: RoofPlane } case rooftype == "gable2": roofGable(roofAngle,0,roofOverhang,false,0) comp(f){ bottom: NIL | vertical: Facade | all: RoofPlane } case rooftype == "gable": roofGable(roofAngle,roofOverhang) comp(f){ bottom: NIL | vertical: Facade | all: RoofPlane } case rooftype == "hip": roofHip(roofAngle,roofOverhang) comp(f){ bottom: NIL | all: RoofPlane } else: RoofPlane RoofFloor --> 21% : offset(-scope.sz*rand(0.0,0.35),inside) shapeL(scope.sz*rand(0.2,0.7),scope.sx*rand(0.2,0.8)){ shape: rotateScope(0,90,0) Mass(rand(1,3)/HeightFactor,"flat") } 21% : offset(-scope.sz*rand(0.0,0.35),inside) shapeL(scope.sz*rand(0.2,0.7),scope.sx*rand(0.2,0.8)){ shape: rotateScope(0,90,0) Mass(rand(1,3)/HeightFactor,"flat") } 26% : innerRect [ s('(rand(0.6,0.9)),'(rand(0.6,0.9)),'1) center(xy) RoofFloorShape(rand(3,4)/HeightFactor) ] 21% : innerRect [ s('(rand(0.6,0.9)),'(rand(0.6,0.9)),'1) center(xy) RoofFloorShape(rand(1,2)/HeightFactor) ] 10% : set(Roof_Textures.SlopedRoofTexture, Roof_Textures.getFlatRoofTexture) innerRect [ s('(rand(0.2,0.4)),'1,'(rand(0.2,0.4))) center(xz) t('rand(-0.5,0.5),0,'rand(-0.5,0.5)) ResidentialShape(rand(2,3)/HeightFactor) ] [ s('(rand(0.6,0.9)),'1,'1) center(xz) RoofFloorShape(rand(1,2)/HeightFactor) ] else: NIL RoofFloorShape(h) --> split(z){ ~1: RoofFloorBack(h) | 'rand(0.5,0.7): Mass(h,"flat") } RoofFloorBack(h) --> 20% : split(x){ 'rand(0.2,0.8): Mass(h,"flat") } # L-shape left 20% : split(x){ ~1: NIL | 'rand(0.2,0.8): Mass(h,"flat") } # L-shape right 40% : split(x){ ~(rand): NIL | (rand(0.8,1.5)*scope.sz): Mass(h,"flat") | ~(rand): NIL } # T-shape 10% : split(x){ 'rand(0.2,0.45): Mass(h,"flat") | ~1: NIL | 'rand(0.2,0.45): Mass(h,"flat") } # U-shape else: NIL RoofPlane --> Roof_Textures.Generate ###################################################3 # Ground Cover # const getDirtmapTexture = fileRandom("/ESRI.lib/assets/General/Dirtmap/dirtmap*.jpg") const getParkingTexture = fileRandom("/ESRI.lib/assets/Groundcover/Parking/parking*.jpg") getGreenSpaceTexture = imageBestRatio("/ESRI.lib/assets/Groundcover/Green/green*.jpg","yx") ParkingGround --> alignScopeToGeometry(zUp,0,longest) setupProjection(0,scope.yx,20,35) projectUV(0) texture(getParkingTexture) setupProjection(2,scope.yx,'1,'1) projectUV(2) set(material.dirtmap,getDirtmapTexture) GreenGround --> alignScopeToGeometry(zUp,0,longest) setupProjection(0,scope.yx,'1,'1) projectUV(0) texture(getGreenSpaceTexture) setupProjection(2,scope.yx,'1,'1) projectUV(2) set(material.dirtmap,getDirtmapTexture) ###################################################3 # Trees # getTreeTropical = listRandom("Coconut Palm;Date Palm;Palm Lily;Mexican Palmetto;California Palm;Ruffle Palm;Banana Tree;Bamboo;Cabbage Palm Fern;") getTreeRandomForest = listRandom("American Chestnut;Red Hickory;Southern Magnolia;Sugar Maple;Northern Red Oak;White Oak;Scots Pine;Douglas Fir;Lodgepole Pine;California Redwood;Giant Sequoia;American Sycamore;Sassafras;California Walnut;") getTreeZone06Tree = listRandom("Sugar Maple;California Incense Cedar;Red Hickory;American Chestnut;Western Juniper;American Sycamore;Northern Red Oak;Basswood;Field Elm;Lawson Cypress;Honey Locust;Yellow Poplar;Black Tupelo;") getTree = case Mix == "Tropical" : getTreeTropical case Mix == "Random Forest" : getTreeRandomForest case Mix == "Zone 6 Trees" : getTreeZone06Tree else : "" FewTrees --> case ShowTrees != "None": set(Plant_Loader.Representation,ShowTrees) scatter(surface, floor(geometry.area/250), uniform){ Plant_Loader.Generate(getTree) } NIL else: NIL Trees --> case ShowTrees != "None": set(Plant_Loader.Representation,ShowTrees) scatter(surface, floor(geometry.area/300), uniform){ Plant_Loader.Generate(getTree) } scatter(surface, floor(geometry.area/200), uniform){ Plant_Loader.Generate(getTree) } scatter(surface, floor(geometry.area/400), uniform){ Plant_Loader.Generate(getTree) } NIL else: NIL ###################################################3 # Street # Street --> Street_Modern_Standard.Street Joint --> Street_Modern_Standard.Joint Crossing --> Street_Modern_Standard.Crossing Junction --> Street_Modern_Standard.Junction Freeway --> Street_Modern_Standard.Freeway FreewayEntry --> Street_Modern_Standard.FreewayEntry Roundabout --> Street_Modern_Standard.Roundabout RoundaboutIsland --> Street_Modern_Standard.RoundaboutIsland Sidewalk --> Street_Modern_Standard.Sidewalk /* */