MadMax50 Posted June 27, 2019 Share Posted June 27, 2019 Hello, I am trying to understand the foreach loop in vex. I want to loop over my boxes and assign a random color to it. So if the structure of the foreach loop is like this: foreach( element; array) { // do things to element } So if I were to apply this to my example of randomizing color on boxes: the "array" should be the class attribute stored in a custom array... and the "element" should be the iteration of each class right ? I'm stuck on storing the class attribute into an array. I know how to make a custom array like this: float myclass[]={1,2,22,3,45}; but how would I store an attribute into an array? If anyone can give me a simple example of how this works. It would be much appreciated. Thank you. Quote Link to comment Share on other sites More sharing options...
flcc Posted June 27, 2019 Share Posted June 27, 2019 (edited) Attribute Array declaration is slightly different than standard array. f[]@myclass = {1,2,22,3,45}; float val = f[]@myclass[3]; Apparently this syntax disturbs more than one (me the first). I Already respond to this question three days ago . It must be said that this particular sintax is not really easy to find in the doc. It's in the array section of the Using VEX expressions chapter, but not in the declare attibutes section and not in the array chapter ! Check the Mestela Wiki for more infos http://www.tokeru.com/cgwiki/?title=HoudiniVex#Arrays Edited June 27, 2019 by flcc Quote Link to comment Share on other sites More sharing options...
MadMax50 Posted June 28, 2019 Author Share Posted June 28, 2019 @flccThank you for the response. I understand how to create array attributes manually. My issue is that I don't no how to get an existing attribute like @class created by the connectivity sop and store those values in an array. All the documentation I read up on does not explain this even on Mestelas Wiki or Joy of VEX. Perhaps I am thinking about arrays differently than they are supposed to be used? Would love to get any insight. Thanks again. Quote Link to comment Share on other sites More sharing options...
ikoon Posted June 28, 2019 Share Posted June 28, 2019 Hi @MadMax50, maybe this thread might help you too? We had similar talk: https://forums.odforce.net/topic/41982-vex-foreach-i-dont-get-it/ Towards the end, there are commented examples. Quote Link to comment Share on other sites More sharing options...
Lucy Coleclough Posted June 28, 2019 Share Posted June 28, 2019 To accumulate an array of all your class attributes it is my understanding that you would have to loop over every prim, check to see if that prim's class is already in your array and if it isn't then append it. Then if you wanted to loop over each object like you said you could use for (int i:array) which is something vex picked up from c++ then you would have to loop over each prim again to see if it has a matching class attrib and only then could you assign a random value instead you could loop over each primitive in a detail and assign it a random colour based on the class attribute. for (int primitive=0;prim<nprimitives(0);prim++) { vector randCd=rand(prim(0,"class",primitive)); setprimattrib(0,"Cd",primitive,randCd,"set"); } Quote Link to comment Share on other sites More sharing options...
pabcou Posted June 28, 2019 Share Posted June 28, 2019 15 hours ago, MadMax50 said: how to get an existing attribute like @class created by the connectivity sop and store those values in an array This, in a detail wrangle, will do it; although as you'll see it's quite a roundabout way to work: // Construct `class` array from the prim attribute. int class[], primclass; for(int primnum = 0; primnum < nprimitives(0); primnum++) { primclass = prim(0, 'class', primnum); push(class, primclass); } // Construct `class_uniques` array from `class` without duplicates. int class_uniques[], count = 0; if (len(class)) { // Proceed only if the array is non-empty. class = sort(class); // Add the first element, so we have something to compare against below. push(class_uniques, class[0]); count++; foreach(int elem; class[1:]) { // For each, leaving the first element out. // If the current element is different from the preceding one, add it. if (elem != class_uniques[count-1]) { push(class_uniques, elem); count++; } } } i[]@class_uniques = class_uniques; Instead of doing this, I would suggest using a For-Each SOP block. It's much simpler, and I assume also more efficient. If you want to have a look, the attached file shows both approaches for setting color by connectivity class. class_to_array__forum.hiplc Quote Link to comment Share on other sites More sharing options...
MadMax50 Posted June 28, 2019 Author Share Posted June 28, 2019 @flcc @pabcou @ColecloughGeorge @ikoon Thank you everyone for the help. I will definitely be reading through those links you sent me. @ColecloughGeorgeThank you for the file. I didn't realize that doing something so simple would be that complicated with a foreach in vex. My follow up question with your code would have to be this: 1. What is the difference between a "for" and a "foreach". Aren't both doing pretty much the same thing ? Quote Link to comment Share on other sites More sharing options...
mestela Posted June 29, 2019 Share Posted June 29, 2019 A for loop requires you to control the variable you're iterating, do your own comparison, and extract the element of an array yourself. A foreach does all that for you. These are functionally equivalent: int myarray[] = {2345,3456,234,34,6,8,567,34,5,346,45}; for (int i = 0; i < len(myarray); i++) { @P.x += myarray[i]; } // vs... foreach(int element; myarray) { @P.x += element; } 1 Quote Link to comment Share on other sites More sharing options...
Lucy Coleclough Posted June 29, 2019 Share Posted June 29, 2019 You supply for loops with a variable to iterate over, a condition that if not true will stop the loop and something that happens to the variable each loop. For example you could have: for (int i=5; i>1; i/2) You can also have for loops that iterate over array members such as for (int i:array) foreach (int i;array) Functionally these both do the same thing to my knowledge. Also I believe the above answer is wrong as those two for loops will have different results. E.g. int array[]={5,9,2,8}; foreach(int i; array) printf i; //This would return 5,9,2,8 for (int i=0; i<len(array); i++) printf i; //This would return 0,1,2,3 There is a great website for some nice syntax hints http://www.cplusplus.com/doc/tutorial/control/ Quote Link to comment Share on other sites More sharing options...
mestela Posted June 29, 2019 Share Posted June 29, 2019 The above answer is wrong? My one? Look closer; the first example uses the iterator 'i' to get a value from the array, the other one accesses the array value directly. Quote Link to comment Share on other sites More sharing options...
anim Posted June 29, 2019 Share Posted June 29, 2019 16 hours ago, pabcou said: Instead of doing this, I would suggest using a For-Each SOP block you can easily remove your For Each Loop, Prim Wrangle with @Cd = rand(i@class); is enough to randomize color per class Quote Link to comment Share on other sites More sharing options...
MadMax50 Posted June 29, 2019 Author Share Posted June 29, 2019 @mestela Thank you for the reply. That makes sense to me now. I guess the reason for my original question of this thread was to get as many examples as I can to understand for loops in vex. I went through the examples on Joy of Vex talking about loops in relation to the nearpoints function but I think I need to see even more examples of how they work. That is why I thought my randomize color based of @class idea was going to be a fairly basic example but apparently not haha. I already started a master file for all the for loop examples I came across so far. Thank you . Quote Link to comment Share on other sites More sharing options...
Lucy Coleclough Posted June 30, 2019 Share Posted June 30, 2019 On 29/06/2019 at 10:27 AM, mestela said: The above answer is wrong? My one? Look closer; the first example uses the iterator 'i' to get a value from the array, the other one accesses the array value directly. Apologies Quote Link to comment Share on other sites More sharing options...
pabcou Posted June 30, 2019 Share Posted June 30, 2019 On 6/29/2019 at 12:09 PM, anim said: you can easily remove your For Each Loop Thank you for pointing this out, Tomas. On 6/28/2019 at 8:33 PM, MadMax50 said: I didn't realize that doing something so simple would be that complicated with a foreach in vex. It turns out it can be simplified. I've just learned about the `uniquevals` function, which, per the docs, "returns the set of unique values across all values for an int or string attribute." So it seems like a direct answer to your original question. Using it, you can get rid of all the code in my previous post, and instead put this in a Detail Wrangle: int class[] = uniquevals(0, 'prim', 'class'); foreach(int elem; class) { vector Cd = rand(elem); int prims[] = findattribval(0, 'prim', 'class', elem); foreach(int prim; prims) { setprimattrib(0, 'Cd', prim, Cd); } } 1 1 Quote Link to comment Share on other sites More sharing options...
MadMax50 Posted July 1, 2019 Author Share Posted July 1, 2019 @pabcouWow thank you. This is definitely much easier to understand. Thanks! Quote Link to comment Share on other sites More sharing options...
kris Posted July 25, 2019 Share Posted July 25, 2019 (edited) we are testing out how to find min max of a attribute in a point geo. (1 million points) attrib promoting to detail as min and max using two nodes took 196.23 ms and float test[]; for (int point=0;point<npoints(0);point++) { float getval = point(0,'test',point); push(test,getval); } @min_val = min(test); @max_val = max(test); above wrangle code took 355.94 ms setdetailattrib(0, 'attrib_set_min', @test, "min"); setdetailattrib(0, 'attrib_set_max', @test, "max"); this one took 176.36 ms Edited July 25, 2019 by kris 2 Quote Link to comment Share on other sites More sharing options...
ikoon Posted July 25, 2019 Share Posted July 25, 2019 Hi kris, nice test. You might also test to resize() the array before the loop. Then, instead of push(), use the index test[point]. It is faster (but not as fast as the Promote SOP or the setdetailattrib()) float test[]; int npoints = npoints(0); resize(test, npoints); for (int point=0; point<npoints; point++) { float getval = point(0,'test',point); test[point] = getval; } @min_val = min(test); @max_val = max(test); 1 Quote Link to comment Share on other sites More sharing options...
swarmagent Posted February 4, 2022 Share Posted February 4, 2022 On 6/30/2019 at 1:14 PM, pabcou said: Thank you for pointing this out, Tomas. It turns out it can be simplified. I've just learned about the `uniquevals` function, which, per the docs, "returns the set of unique values across all values for an int or string attribute." So it seems like a direct answer to your original question. Using it, you can get rid of all the code in my previous post, and instead put this in a Detail Wrangle: int class[] = uniquevals(0, 'prim', 'class'); foreach(int elem; class) { vector Cd = rand(elem); int prims[] = findattribval(0, 'prim', 'class', elem); foreach(int prim; prims) { setprimattrib(0, 'Cd', prim, Cd); } } Hi fellas! I'm still new to Houdini and love this thread. It's helped me understand a lot. Using from what I learned from all of you, I would like set color or remove a group of primitives that are intersecting another geometry. I was able to get rid of the affected primitives but not the whole set. In the image, anything that has a color or mask value > 0.001 should be deleted. Ultimately I'd be left with the one strip below the collider. Any help is very much appreciated. Thank you. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.