Code Analysis: International City, Part 5

A Residential area. Sign me up.

What's Covered:
  • geometry.isRectangular( )
  • geometry.nVertices
  • innerRect/innerRectangle
  • setupProjection
  • texture( )
  • set( )

We have been focusing on how Lots assigned to the “Residential” use type are processed. All of the rules that have sliced and diced our land parcels in Part 4 have finally led us to one rule, ResidentialLot.

This rule simply points us sequentially through two other rules:  the GreenGround rule, which is found way down around Line 606, and ResidentialLot Align which is around Line 152, immediately after where we left off in the previous installment.

To understand what happens when two rules are declared immediately together, I did an experiment.

0 getGreenSpaceTexture = 
   imageBestRatio("/ESRI.lib/assets/Groundcover/Green/green*.jpg","yx")

1 GreenGround -->
2    alignScopeToGeometry(zUp,0,longest)
3    setupProjection(0,scope.yx,'1,'1) projectUV(0)
4    texture(getGreenSpaceTexture)
5    setupProjection(2,scope.yx,'1,'1) projectUV(2)
6    set(material.dirtmap,getDirtmapTexture)

So... we first go through the GreenGround rule.  On Line 2 is an alignScopeToGeometry shape operation, which ESRI documentation says “lets you choose an edge of a face in the geometry. The new x-axis of the scope will be parallel to this edge, and the up-axis will be the face's normal.”  I won’t get into this right now.

The next four lines are familiar: we ran through projecting textures onto surfaces in CGA Code Lesson #4.

  • First, we are setting up a projection on the first of six available texture layers, 0 thru 5. Layer 0 is dedicated to colormaps.
  • We will be projecting onto Layer 0 of the yx side of the cube.
  • The width and the height of the texture is set to ‘1, which means it will be projected once relative to the size of the surface. (Setting it to 0.5 would repeat it twice.)
  • On line 4, the texture operation names the image file that will be used. In this case, the regular file path has been replaced by a variable name, getGreenSpaceTexture, defined on Line 0. When we look at the variable, we see it is a product of a function called imageBestRatio. The function searches through ESRI library assets to a folder /Green and then looks for all .jpg files that start with the characters “ green* ”. Note the * wild card on the end. Finally, “yx” is selected as the axis reference, the same one named in setupProjection.
  • On Line 5, we are setting up another projection, this time on layer 2 which is dedicated to dirt maps. Again, we are projecting it on scope.yx to a proportion of 1:1 relative to the surface area.
  • On Line 6, the set() operation sets the material.dirtmap attribute, assigning the file named in the constant getDirtmapTexture. The constant is the product of the fileRandom function, which will return a random file from the named folder in the ESRI assets library – another way to add randomness in our models.

A lot with three vertices, listed under the Vertices tab in the Shape Inspector.

1 ResidentialLotAlign --> 
2   case geometry.nVertices < 4:  
3      Trees 
4   case !geometry.isRectangular(10): 
5      innerRect
6      split(x){ 1 : NIL
7               | 'rand(.85,.9): split(z){ ~rand(1,3): Trees 
8                   | (rand(15,20)): ResidentialBuildingArea 
9                   | ~1: Trees }
10              | 1 : NIL } 
11   else: split(x){ 1 : NIL
12                | 'rand(.85,.9): split(z){ ~rand(1,3): Trees 
13                      | (rand(15,20)): ResidentialBuildingArea 
14                      | ~1: Trees } 
15                | 1 : NIL }

Now we are pointed to the ResidentialLotAlign rule, where we are presented with some conditional logic and some geometry functions.

  • If the lot has less than four vertices – e.g. is triangular – apply the Trees rule. Vertices are the points where lines in a polygon meet. To find out how many vertices a lot has, click on the lot and look under the Vertices tab on the Shape Inspector. In the illustration below we see the triangle, which has less than four vertices – three are listed in the inspector -- has been assigned a green grass texture.
  • If the lot’s geometry is NOT rectangular to within a tolerance of 10 degrees, apply the innerRectangle function; innerRect was depricated after this rule package was written. The ! before the function name designates “NOT”.
  • If the statement is true, we split three ways on the x-axis. 1 unit (meter, foot) on either end is assigned the NIL function. ESRI documentation says this function deletes these shapes from the “shape tree”, creates holes where other split operations will not apply and terminates recursive rules.
  • Next, we split three ways on the z-axis using random widths of 1-3 on the ends and assigning the ResidentialBuildingArea rule to a random remaining section. Using the float ~ character on the ends ensures the random middle section will adapt to the random ends.
  • Note that the “else” operation is exactly the same as the previous case statement, only it does not use the innerRectangle function, which finds the the largest rectangle inside each block.
ResidentialBuildingArea --> 
     case scope.sx < 10 || scope.sz < 10:NIL 

else: 
    alignScopeToAxes(y) s('1,0,'1)
    ResidentialBuilding

We are now pointed to the ResidentialBuildingArea rule, where the size of each lot is checked. If the lots sx AND sz scopes are less than 10, the lot is too small for locating a house.  Otherwise (else) those that are suitable for homes have their scopes aligned to the y-axes of the terrain – vertically.

We have thus far assigned land uses to parcels. applied setbacks to those assigned as residential, split them up and decided which are suitable for homes.  Next, we will finally begin to generate buildings.

Leave a Reply

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