Split a block in different separate shapes

758
3
Jump to solution
10-22-2017 07:04 PM
AbeleGiandoso
Occasional Contributor

Hi

I am trying to precisely control the subdivision of the inside area of a block generated with "offset subdivision" ,the one that responds to the InnerLot start rule. 

Specifically I want to create big areas for parks and squares (around 5%) and for the rest instead have very small lots for tiny houses. The base parameters in the "offset subdivision"  don't give me the control I need as they tend to even out everything so I thought about using a recursive splitArea operation to split the inner portion myself with greater control.

5% of the lots will stop subdividing when they reach a "ParkMinArea" and the rest will continue to split until they reach a "HouseMinArea". It works but there is a major problem I ca not resolve:

All the Lots I create are still connected to the original main shape and that means that attributes and constants are giving the same results for all the buildings created on the inside area from that same original inner space instade of variate per building as I hoped they would have. That causes all of them to have the same aspect instead of being able to have each one his own "personality". 

I tried to set the seedian to a random number 

RSeed = rint (rand(1,10000))

set (seedian, RSeed)

for each of the final base shapes but it does not work.

Isn't this what setting the seedian is supposed to do?

If someone does know what I am doing wrong or can give me a hand I'll be very grateful

Many Thanks

PS: My alternative plan is to assign a "Park" label to a random final small shape (one every 100) and use a mindistance contextquary inter operation to NIL all the faces in a certain radius from the labeled shape to generate the empty space I need. But it is a heavy calculation so I would prefer avoiding it if possible.

0 Kudos
1 Solution

Accepted Solutions
CherylLau
Esri Regular Contributor

No, setting the seedian in this case wouldn't help because the attribute height is initially set to a random number before the rules are executed, and this value for height does not change as you execute the rules unless you use set() to change it.

However, you can change height by making it a function rather than an attribute.  This way, a different random number is retrieved every time the function is called.  Then, you don't have to set the attribute value.  You just have to remove the "attr" keyword in front of height, but in this example, I also renamed it to getHeight to make it clear (as an example) that it is going to be executed every time the function is called on line 7 (for each lot).

getHeight = rand(1,10)

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     extrude(getHeight)

You could extend this to work for materials as well.

getHeight = rand(1,10)
getMaterial =
     30%: "wood"
     30%: "brick"
     else: "concrete"

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     extrude(getHeight)
     Building(getMaterial)
     
Building(material) -->
     case material=="wood":
          color(1,0,0)
     case material=="brick":
          color(0,1,0)
     else:
          color(0,0,1)

Either by setting attributes or creating functions, you can achieve what you're looking for.  There are probably other ways too.

I don't think you need to set the seedian.  For the initial block shape, one cga rule is executed, and every rand() call within that rule file will return a random number.  Imagine that you have 5 blocks that are initial shapes onto which you apply the rule file.  If the seedian of these 5 blocks were the same, then you would get the same result for each block because each block has the same seedian.  In this case, it makes sense to set the seedian of the initial shapes to something different so that all 5 blocks have different seedian values.  Then, the 5 blocks will have different results.  This case where initial shapes start with the same seedian is not a common case.  As a side note, this rare case can arise when you create static models/initial shapes out of shapes that are stacked vertically (with the same xz values but different y values).

View solution in original post

3 Replies
CherylLau
Esri Regular Contributor

When you put a rule on the block shape, this start shape will have all the attributes of the rule, and they will initially all be set to the same value.  This block shape will also have one seedian for the whole block.  You can see this in the Inspector in the Information section.  When the block is divided into lots in the rule, then these lots all share the attributes and the seedian.

You can, however, set the value of these attributes to be different for each lot.  This can be done in the cga code using the set() function.

set Operation 

When you set the value of an attribute in the cga code, you will not see this value in the Inspector.  The Inspector will show the initial value set on the block shape, not the values set on each lot.  This is because the value set on each lot is set on a shape in the shape tree and applies to that shape and it's children.  In the Model Hierarchy (Window -> Show Model Hierarchy -> Inspect Model -> select object), you can see the shape tree.  The root would be the block shape, if the block were divided into 10 lots, there would be 10 child shapes, one for each lot.  Each of these lot shapes can be assigned a different value for the attribute.  By using the set() function, you set the attribute on the shape in the shape tree where the set() function is called.

For example, this sets the attribute height to a random value in [1,10] for each lot, but the value for height is 0 for the block, which is what is shown in the Inspector.

attr height = 0

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     set(height, rand(1,10))
     extrude(height)
‍‍‍‍‍‍‍‍
AbeleGiandoso
Occasional Contributor

Thanks Cheryl, I'll try this tonight!

As a curiosity, wouldn't set the seedian to a random value like this

attr height = rand (1,10)

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     set(seedian, rint(rand(1,100000)))
     extrude(height)

 produce the same effect, and allow the whole shape tree to be different from the neighbour one even if they are grown the same block?

Otherwise I have no idea of what setting the seedian to a value could be useful for. 

Also let say I want each of the houses have a different texture, like one is bricks the other concrete, the other is wood. If I use the technique above mentioned to texture the faces of a building would't each single face get a random texture without consistency (like front facade wood, back concrete, sides bricks for instance) and so on for each buidling? 

What I am trying to obtain is each building from the same base block having its own material

0 Kudos
CherylLau
Esri Regular Contributor

No, setting the seedian in this case wouldn't help because the attribute height is initially set to a random number before the rules are executed, and this value for height does not change as you execute the rules unless you use set() to change it.

However, you can change height by making it a function rather than an attribute.  This way, a different random number is retrieved every time the function is called.  Then, you don't have to set the attribute value.  You just have to remove the "attr" keyword in front of height, but in this example, I also renamed it to getHeight to make it clear (as an example) that it is going to be executed every time the function is called on line 7 (for each lot).

getHeight = rand(1,10)

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     extrude(getHeight)

You could extend this to work for materials as well.

getHeight = rand(1,10)
getMaterial =
     30%: "wood"
     30%: "brick"
     else: "concrete"

Block -->
     split(x) { ~1: Lot }*
     
Lot -->
     extrude(getHeight)
     Building(getMaterial)
     
Building(material) -->
     case material=="wood":
          color(1,0,0)
     case material=="brick":
          color(0,1,0)
     else:
          color(0,0,1)

Either by setting attributes or creating functions, you can achieve what you're looking for.  There are probably other ways too.

I don't think you need to set the seedian.  For the initial block shape, one cga rule is executed, and every rand() call within that rule file will return a random number.  Imagine that you have 5 blocks that are initial shapes onto which you apply the rule file.  If the seedian of these 5 blocks were the same, then you would get the same result for each block because each block has the same seedian.  In this case, it makes sense to set the seedian of the initial shapes to something different so that all 5 blocks have different seedian values.  Then, the 5 blocks will have different results.  This case where initial shapes start with the same seedian is not a common case.  As a side note, this rare case can arise when you create static models/initial shapes out of shapes that are stacked vertically (with the same xz values but different y values).