Ole Posted September 2, 2014 Share Posted September 2, 2014 Hi there. I need some help with Vex. I've set up a Python Sop with the code below but this is very slow. So my next challenge is to re-create it in vex (or fix the Python code if it can run much faster). Vex is unknown territory, and my vex code fail already with the attempt to create an array with unique cluster values ('clusters' in the Python code). When I foreach() on the array to look up the existing values within the while loop, VEX execution seems to go into an infinite loop if I have a printf() statement anywhere in the code. I've put the vex code in a Attribute Wrangle Sop with Run Over set to Detail (to be able to count over points). My working Python code: node = hou.pwd() geo = node.geometry() # Add code to modify contents of geo. # Use drop down menu to select examples. geo.addAttrib(hou.attribType.Point, "activate_by_cluster", 0) #geo.addAttrib(hou.attribType.Point, "Cd", (0.0, 0.0, 0.0)) # Set threshold for number of points in a cluster before becoming active min_points = 40 clusters = [] for p in geo.iterPoints(): cluster = p.attribValue("cluster"); if cluster not in clusters: clusters.append(cluster) for cl in clusters: active_cluster = False threshold = 0 for p in geo.iterPoints(): if p.attribValue("cluster") == cl and p.attribValue("activate_box") == 1: threshold += 1 if threshold >= min_points: active_cluster = True break if active_cluster == True: for p in geo.iterPoints(): if p.attribValue("cluster") == cl: p.setAttribValue("activate_by_cluster", 1) This is the vex code I got so far: //Global settings int min_points = 400; //Global variables int clusters[] = {0}; //Get the existing clusters from the points int pt_num = 0; while(pt_num < @numpt){ int _cluster = point(geoself(), "cluster", pt_num); foreach(int i; clusters){ if(_cluster != i){ push(clusters, _cluster); } } pt_num++; } //printf("%d", clusters); foreach(int i; clusters){ int active_cluster = 0; int threshold = 0; while(threshold < @numpt){ int _cluster = point(geoself(), "cluster", pt_num); int _activate_box = point(geoself(), "activate_box", pt_num); if(_cluster == i){ if(_activate_box == 1){ threshold++; } } } if(threshold >= min_points){ active_cluster = 1; break; } if (active_cluster == 1){ pt_num = 0; while(pt_num < @numpt){ int _cluster = point(geoself(), "cluster", pt_num); if(_cluster == i){ //setpointattrib(geoself(),"activate_by_chunk", pt_num, 1, "set"); } } } } I've just tried to do the same in vex as I did in Python. Needless to say, it does not work as it is although I get no error messages. In case the intention is unclear: I am looping over the current points looking for the cluster attribute (coming from Cluster Points sop). I then go through the points in each cluster looking for the "activate_box" attribute. If this is 1 and a minimum of points with these conditions is found, set all points in the cluster to have the "activate_by_chunk" attribute to 1. This is used downstream. Please let me know if you have any ideas! Ole Quote Link to comment Share on other sites More sharing options...
graham Posted September 2, 2014 Share Posted September 2, 2014 I can't really help much with trying this in VEX, but there are definitely some things in your Python code that aren't going to help with performance: Using hou.Geometry.iterPoints() is highly efficient for random access into the point list, however is generally slightly slower than just points() when you are straight up iterating over all the points in the range. This will only be exasperated since you are doing loops within loops. You are accessing and setting attribute values by name instead of using a reference to a hou.Attrib object. Every time you set by name Houdini as to look up the attribute to get the reference internally. This can cause a bunch of slowdown the more entities you have. All the constant iteration over large geometry sets will definitely cause a lot of slowdown. Here is something I think should probably be faster. It tries to avoid actually dealing with Houdini points and tries to just perform operations on lists of attribute values which can be accessed, manipulated and set back more efficiently. Here's some test code that should probably be faster but is untested. min_points = 40 attr = geo.addAttrib(hou.attribType.Point, "activate_by_cluster", 0) # Get all the point cluster and activation values. clusters = geo.pointIntAttribValues("cluster") abb = geo.pointIntAttribValues("activate_by_box") # A list of cluster value counts. This assumes your clusters are indexed 0-N and have continuous value ranges. active = [0] * len(set(clusters)) # Build a simple list of the matching counts. for cluster, val in zip(clusters, abb): if val: active[cluster] += 1 # Determine which clusters actually need to be activated. mask = [int(val > min_points) for val in active] # Build a list of the activate_by_cluster values. to_set = [] for cluster in clusters: to_set.append(mask[cluster]) # Set the values to the points. geo.setPointIntAttribValues("activate_by_cluster", to_set) 1 Quote Link to comment Share on other sites More sharing options...
petz Posted September 3, 2014 Share Posted September 3, 2014 (edited) untested vex version... putting this into an attribWrangle set to DETAIL should work. it´s most probably not much faster (if it is at all) than grahams python code since it doesn´t use multithreading. int num_cluster, num_points, num, i, p, min_points, count; min_points = 40; num_cluster = nuniqueval(@OpInput1, "point", "cluster"); for(i = 0; i < num_cluster; i++) { num_points = findattribvalcount(@OpInput1, "point", "cluster", i); count = 0; p = 0; while(p < num_points && count < min_points + 1) { num = findattribval(@OpInput1, "point", "cluster", i, p++); if(point(@OpInput1, "activate_box", num) == 1) count += 1; } if(count > min_points) { p = 0; while(p < num_points) { num = findattribval(@OpInput1, "point", "cluster", i, p++); setpointattrib(geoself(), "activate_by_cluster", num, 1, "set"); } } } edit: "activate_by_cluster" must be an existing attribute. Edited September 3, 2014 by petz 1 Quote Link to comment Share on other sites More sharing options...
Ole Posted September 8, 2014 Author Share Posted September 8, 2014 Thank you for the code Graham and petz! Quote Link to comment Share on other sites More sharing options...
fathom Posted September 8, 2014 Share Posted September 8, 2014 (edited) two point wrangles: wrangle 1: v@clusterP = 0; v@clusterP.x = i@cluster; v@clusterP.y = i@activate_box; wrangle 2: int activate; int handle = pcopen("op:`opinputpath('.',0)", "clusterP", v@clusterP, 0.001, 10000000); if (pcnumfound(handle)>40) activate = 1; addattribute("activate_by_cluster",activate); the first wrangle sets up a point cloud search proxy using the "cluster" and "activate_box" int attributes. the second uses that proxy to search for like points (ie, same cluster value and same activate_box value). (this was dry coded, so there may be a syntax error or two) Edited September 8, 2014 by fathom Quote Link to comment Share on other sites More sharing options...
Ole Posted September 11, 2014 Author Share Posted September 11, 2014 two point wrangles: wrangle 1: v@clusterP = 0; v@clusterP.x = i@cluster; v@clusterP.y = i@activate_box; wrangle 2: int activate; int handle = pcopen("op:`opinputpath('.',0)", "clusterP", v@clusterP, 0.001, 10000000); if (pcnumfound(handle)>40) activate = 1; addattribute("activate_by_cluster",activate); the first wrangle sets up a point cloud search proxy using the "cluster" and "activate_box" int attributes. the second uses that proxy to search for like points (ie, same cluster value and same activate_box value). (this was dry coded, so there may be a syntax error or two) Thank you for the example, Miles! 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.