problem reusing (global) variables in different parts of CGA code

1431
3
02-16-2017 08:08 AM
MarekDekys
New Contributor III

Hello, I am having a problem while setting a variable in one part of code and then reusing it in another part of code:

let's say I have a simple square footprint shape and I use following rule on it:

attr counter = 0
Lot -->
set(counter,counter+1)
set(counter,counter+1)

print (counter)

and it works pefectly fine and print returns:

2

when I try to use it from two different parts of code e.g. Lot and Cube

attr counter = 0


Lot -->
set(counter,counter+1)
print("output from Lot: "+counter)
extrude(3) Cube(counter)

Cube(cnt) -->
set(counter,cnt+1)
print("output from Cube: "+counter)

it also works fine (because I passed the variable from one rule to another in as an argument )  and the otuput is:

output from Lot: 1
output from Cube: 2

but when I extend the previous rule so that:

attr counter = 0


Lot -->
set(counter,counter+1)
print("output from Lot: "+counter)
extrude(3) Cube(counter)

Cube(cnt) -->
set(counter,cnt+1)
print("output from Cube: "+counter)

comp(f){side:Sides(counter)}

Sides(cnt) -->
set(counter,cnt+1)
print("output from Sides: "+counter)

I get the output:

output from Lot: 1
output from Cube: 2
output from Sides: 3
output from Sides: 3
output from Sides: 3
output from Sides: 3

and I'm expecting output:

output from Lot: 1
output from Cube: 2
output from Sides: 3
output from Sides: 4
output from Sides: 5
output from Sides: 6

because I expect that Sides(cnt) part of a code runs 4 times (for each face of the box) thus each iteration will increment counter by 1

another weird thing is that the mentioned attribude value doesn't change in Inspector:

any ideas?

thanks,

Marek

0 Kudos
3 Replies
CherylLau
Esri Regular Contributor

The comp split takes each side face and calls the rule Sides(counter) where counter=2, so for each side face the value of counter starts at 2, and the rule is applied independently to each side face, so counter will be increased to 3 for each side face.

In the Model Hierarchy (Window -> Show Model Hierarchy -> select object in Viewport), you can see the shape tree.  Before the comp, there is one shape.  At this point in the shape tree, the code sets counter=2.  Then, the comp split creates four side faces represented by the nodes called Sides.  These side faces are independent of each other.  Each of the side faces gets the value counter=2 and increases it to 3.

-> Attributes in CityEngine do not act like global static variables.  They can be set anywhere in the shape tree, and calling set in one rule only affects the value of that attribute in the shape generated by that rule and it's children.

-> Sibling shapes are independent of each other.  This means, a shape will not know what its sibling shape has for the value of counter.

The inspector shows the rule default as set by the rule or what the user sets the attribute to.  (Or, it shows the value it was set to through other links like layer or object attributes.)  Calling set in the rules only changes the attribute value for that particular shape in the shape tree and its descendants, and these values are not shown in the Inspector because different shapes in the shape tree can have different values for the same attribute.

Perhaps comp.index and/or comp.total would help you count the sides.

comp Shape Attribute 

There is also a similar way to count components from a split using split.index and split.total.

split Shape Attribute 

0 Kudos
JonMullen1
New Contributor

I am having a similar problem when attempting to customize the front facade of my buildings.  I need 2 global static variables to serve as flags to customize my front facade.  

I used the comp(f) functionality to split my single-family home into front, sides, back and roof.  Being that I am working with single-family homes, they are often irregular shaped and thus many parts of the house are part of the "front facade."  I checked the scope.sx of each comp.index of the front facade and decided, based on that size, which tile element I should place on that comp.index piece of the front.  I managed to do this in 3-4 different ways, but the problem with such a simple check is that I often end up with multiple front doors or multiple garage doors on one house, when I only want 1 door and 1 garage door.  I initially assumed I'd be able to toggle two bool attributes from false to true when  a comp.index side was assigned a door or garage tile (so then, no more comp.index sides would be assigned door or garage tiles).  

Despite my best efforts, I am unable to find a way to save the "true" flag value to my "doorused" and "garageused" attributes in a global static state, to be used continually as I go from one comp.index side to the next.  The CityEngine documentation says that Attributes are a set of static global variables, but this does not seem to be the case, as changes to an attribute made within a case do not hold when the next iteration of the comp.index side is checked.

I feel like a check of this nature should be easy to code with the cga rules, as it would be exceptionally useful for designing more detailed and varied buildings.  Am I missing something here?  Is there a way to do what I am trying to do?

I'll also note that I attempted to use a = instead of : for the front facade comp(f) declaration to make it one continuous shape, but that doesn't work for such irregular shaped buildings.  I don't want doors or windows wrapped around corners.

0 Kudos
CherylLau
Esri Regular Contributor

Unfortunately, I don't think this is currently possible because each of the elements of the comp are sibling shapes that don't know about each other.

Sorry, maybe I was too hasty in my previous post to say that the attributes are not like global static variables when the help doc says they are.  However, the help doc is not entirely correct about the static part.  (Thanks for pointing it out and helping us find that.)

The doc means to say that, at a first glance, attributes are similar to static variables because an attribute is set to an initial value, and this attribute persists throughout the lifetime of the program.  Memory for this attribute is allocated at the beginning of execution, the attribute's value is set, and this value is accessible throughout the rest of the code.

Attributes are not like static variables because of how the set() function works.  A traditional use case for static variables is to use them as counters where each time a function is called, the variable is incremented.  Attributes cannot be used like these static variable counters where sibling shapes try to increment the counter variable.  When cga code is executed, shape trees are created.  When the set() function is called in a rule, the attribute is set to the desired value in the shape corresponding to that rule.  The attributes value is then set for that shape and the shape's children in the shape tree.  A sibling shape is not affected by the set() performed in it's sibling.  This is how attributes are NOT like static variables.

0 Kudos