Needs a lot of cleanup. Data has been de-duplicated, and where identical copies existed, one of them has been replaced with a symlink. Some files have been excluded, such as binaries, installers and debug dumps. Some of that may still be present.
666 lines
26 KiB
Text
666 lines
26 KiB
Text
/**
|
|
* 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
|
|
|
|
|
|
/*
|
|
*/
|
|
|