conditional rule and addressing functions

3455
7
11-01-2013 02:56 AM
VencislavValchev
New Contributor
Hello guys,

I have been reading your forum for a couple of weeks now. In my opinion City Engine is a great peace of software, although CGA  gives me hard time.
I watched/red most of the tutorials and I read the help all the time but It seems my way of thinking is a bit different.

My first question is about conditional rule. How do I nest conditions properly?

nRange = 4 
attr temp = 0

Lot --> Loop(nRange)

Loop(nRange) -->
 case nRange >= temp: print("nRange = " + nRange) Loop(nRange - 1) 
  case nRange == 3: print("INNER CASE")
 else: print("END OF LOOP")


What I want to achieve is to print:

nRange = 4
nRange = 3
INNERCASE
nRange = 2
nRange = 1
nRange = 0
END OF LOOP

But it seems the cycle never gets within the second case, so instead I get:

nRange = 4
nRange = 3
nRange = 2
nRange = 1
nRange = 0
END OF LOOP

Second question is about how to properly address a function?
What I want to achieve is the following:

const listOfBuildings =  //what is the purpose of constant in CGA?
 "building_01.obj;building_02.obj;building_03.obj;building_04.obj;" 
nRange = (listSize(listOfBuildings) - 1) 
buildingList = ""/empty string to fill with chosen buildings
const temp = 0

#FUNCTION
testFunction(nRange) = //not sure about the attribute here
 listAdd(buildingList, listItem(listOfBuildings, nRange))
#RULE
Loop(nRange) -->
 case nRange >= temp: Loop(nRange - 1)
  case geometry.isRectangular(5)  
  && ((scope.sx > assetInfo(listItem(listOfBuildings, nRange), sx) 
  && scope.sz > assetInfo(listItem(listOfBuildings, nRange), sz))) 
  || ((scope.sx > assetInfo(listItem(listOfBuildings, nRange), sz) 
  && scope.sz > assetInfo(listItem(listOfBuildings, nRange), sx))):
  testFunctionn(nRange)                  //this gives me error? what should I put here ???
 else: print("END OF LOOP")          //not sure about this


Basically I want to test every building in listOfBuildings if it fits within xz scope of the current Lot. If it fits I want to put it in buildingList so I can randomly choose between several buildings whitch fit the current lot.  

Well this is for now.

Best,
pledgeshield
0 Kudos
7 Replies
MatthiasBuehler1
Frequent Contributor
Hi !

EVERY new case block must be ended with an else.

case:
else :


or

case :
    case:
    else:
else:


or

probability = 0.5

case p(probability):
else:


or

50%:
else:


or

attr doIt = true # or false

case doIt:
else:


or

function = case 5>3

case !function:
else:


or

case (scope.sx > scope.sz) && (geometry.area() < 2):
else:



sorry, don't have time currently for more text here ..

work with this for now, ok ?


m.
0 Kudos
VencislavValchev
New Contributor
Thanks for responding to me matthias!

Nice examples, they should be put into the next help file! I dug into the forums and I found an old thread which gave me some hints about the case problem. Here it is: Click

Well here is what I came up with... not very pretty but works 🙂

nRange = 4
temp = 0

Lot --> Loop(nRange)

Loop(nRange) -->
 case nRange >= temp: innerLoop(nRange) print("nRange: " + nRange) Loop(nRange - 1) 
 else: print("END OF LOOP")
 
innerLoop(test) -->
 case test == 3: print("INNER LOOP")
 else: NIL


And the result is:

nRange: 4
nRange: 3
INNER LOOP
nRange: 2
nRange: 1
nRange: 0
END OF LOOP

It would be nice if I can replace innerLoop rule with function.

Best,
pledgeshield
0 Kudos
MatthiasBuehler1
Frequent Contributor
You need something like this ..

attr valueA = 10
attr valueB = 5

Start -->
    RecursionA(valueA)

RecursionA(a) -->
    case a == 0:
        RecursionB(valueB ) # done, continue with B.
    else:
        RecursionA(a-1)

RecursionB(b) -->
    case b == 0:
        Done.
    else:
        RecursionB(b-1)


So the structure you need/mention MUST be done via rules, that means also the whole geometry is copied 'from rule to rule'.


Note that 'functions' and 'rule bodys' are have a different semantic meaning than in other programming languages.

functions:


f = 5
blah(n) = 7 * u


rule body:

A -->
    B.

..


OK ?
😮
0 Kudos
VencislavValchev
New Contributor
Well I stumbled over new issues. As I said in my first post I am trying to create the following:

(this is just a bunch of pseudocode mixed with CGA, I am sorry but I am not a programmer)

attr string1 = "building1;building2;building3;building4"
attr string2 = "" //used as buffer
attr var1 = listSize(string1) 

while(var1 >= 0)
{
   if(geometry.isRectangular(5))
     {
       listAdd(string2, listItem(string1, var3)) //adds the buildings which passed the test to string2
     }
   else: break;
   var1 = var1 - 1
}

Building --> rand(string2) // get a random building from string2 and place it at the current lot


1. Why I cant use functions such as listAdd on their own:
Lot --> Building(listAdd(some code))// works
Lot --> listAdd(some code)// does not work ?

2. How do I write a while loop without modifying the model hierarchy? I really don't like the sight of 15 while(s) in model hierarchy window!
3.How do I add stuff from one list to another? Here is some code:
attr string1 = "models/box1.obj;models/box2.obj;models/box3.obj;"
attr string2 = ""
attr var1 = listSize(string1)   

Lot --> While(var1 - 1)
While(var2) -->
 case var2 >= 0:
   If(var2)
   While(var2 - 1)
 else: NIL

If(var3) -->
 case geometry.isRectangular(5):
  Test(listAdd(string2, listItem(string1, var3)))
 else: NIL

Test(str) -->
 print(str)


The result I want to get is:
models/box1.obj;models/box2.obj;models/box3.obj;
models/box1.obj;models/box2.obj;
models/box1.obj;

Instead of:
models/box3.obj;
models/box2.obj;
models/box1.obj;

:confused:
0 Kudos
MatthiasBuehler1
Frequent Contributor
Hi,

1]
that's the way the system is designed. rules are rules and functions are functions.

that's how it is.


2]
currently not possible.

maybe one day in the future, more advanced things are added to CGA, but that's how it works in the current state.

3]

I recommend working with 'Generic Attributes'.

That means instead of passing on values as 'rule parameters, such as

Start -->
    A(5)

A(n) -->
    ..


I'd say code like this:

attr myStringList1 = "a;b;c;d"
attr myStringList2 = "u;v;w;x;y;z"

Lot -->
    set(myStringList1, ..)
    set(myStringList2, ..)
    Continue.



Question:

What's the overall problem you try to solve that way ? I've never seen the need for this code structure before. What type of city are you trying to create ?

Matt
0 Kudos
VencislavValchev
New Contributor
Hi Matt,

Lets say that I have an infrastructure of a city(streets and empty lots) and I have a library of premade 3D buildings which I want to place on lots and to create urban environment. What I want to do is to insert buildings into corresponding lots without modifying building's dimensions. I know how to test a building if it fits into a lot (or at least I think so). The problem is that it always fits the smallest building and this brakes the overall variety.

I have tried functions such as assetBestSize but they don't work as I expected. These functions modify the dimensions of the buildings.

So basically this is the problem which I try to solve.

best,
pledge
0 Kudos
MatthiasBuehler1
Frequent Contributor
Hi,

the best approach is inded using the assetBestSize / assetBestRatio / operations.


note that
s(0,0,0)
before the i() operation insert with the original asset size. this is used to not scale the asset at all.


maybe also check out the Example 'Instanced City', this uses those operations, but scales the buildings.

otherwise, what you can do is use assetInfo() and create a series of splits that check the dimensions of the empty lots and insert the buildings by using splits.

hope this gives some inputs ..

m.
0 Kudos