Hello. Also it's possible to get it done using neighbour and xyzdist functions. I appended a hip file so you can follow. Before running any code I had to prepare the scene. I created a sphere, then pointsfromvolume, then I ran POP net with random forces to create random point movement in space, then ran trail to create a point trail, and connected them with Add SOP, then froze at 100th frame with timeshift.
Now that we've got the lines that curve in random directions we can move onto deciding what method to use for calculating thickness so that once we run Sweep, we don't get intersecting geo. I want to address the method you mentioned, neighbour function. For this to work, I must highlight that you have to have only 1 primitive per curve, not split up with something like convertline SOP. Make it one continous curve primitive with polypath SOP. Anyway, this method is possible with a workaround. You should first drop "connect adjacent pieces" SOP with "Adjacent Points" connection type. That's going to create necessary connections between points.
Then you run this code:
/*MUST HAVE 1 PRIMITIVE FOR EACH CURVE (RUN POLYPATH SOP)!!!
OTHERWISE YOU CAN'T FIND "current_trail"*/
int current_prims[] = pointprims(0, @ptnum);
int current_trail = current_prims[0];
int all_neighbours[] = neighbours(0, @ptnum);
float min_external_dist = 10000;
foreach (int nb_pt; all_neighbours) {
int target_prims[] = pointprims(0, nb_pt);
int target_trail = target_prims[0];
if (target_trail == current_trail) continue;
vector nb_pos = point(0, "P", nb_pt);
float d = distance(@P, nb_pos);
if (d < min_external_dist) {
min_external_dist = d;
@min_ext_dist = min_external_dist;
}
}
float max_allowed_radius = chf("max_allowed_radius");
float thickness_bonus = chf("thickness_bonus");
if (min_external_dist == 10000.0) {
f@pscale = max_allowed_radius + thickness_bonus;
} else {
float safe_radius = min_external_dist * 0.5;
f@pscale = min(safe_radius, max_allowed_radius) + thickness_bonus;
}
This code searches for prim ID of the current pt and compares it against all connected neighbours. If a neighbour belongs to the same curve, we will skip following calculation. If a valid connection to external/neighbouring curve is found, it calculates a distance radius so the tubes don't intersect. If the point is isolated and doesn't find external trails within Connect Adjacent Pieces search radius, it defaults to max allowed radius slider parameter. There is a "thickness bonus" control parameter as a global scale modifier.
After this we Attribute Copy f@pscale attrib onto curve geo (the one before connect adjacent pieces SOP).
Sweep will recognize pscale attribute btw.
Unlike neighbour() method, the next one based on xyzdist function is a lot faster (more than 20 times) to compute. I prefer this one as you don't need to fiddle around with connectadjacentpieces SOP nor attribute Copy.
Basically you're just going to drop point wrangle and paste this code
/*MUST HAVE 1 PRIMITIVE FOR EACH CURVE (RUN POLYPATH SOP)!!!
OTHERWISE YOU CAN'T FIND "current_trail"*/
int current_trail_prims[] = pointprims(0, @ptnum);
int current_trail = current_trail_prims[0];
float max_search_radius = 5;
// string mask to tell xyzdist to IGNORE our own trail prim
string ignore_self_mask = "!" + itoa(current_trail);
int closest_prim;
vector closest_uv;
float min_midair_dist = xyzdist(0, ignore_self_mask, @P, closest_prim, closest_uv, max_search_radius);
float max_allowed_pscale = chf("max_pscale_limit");
if (min_midair_dist >= max_search_radius) {
f@pscale = max_allowed_pscale;
} else {
float safe_radius = min_midair_dist * 0.5;
f@pscale = min(safe_radius, max_allowed_pscale);
}
A prerequisite is to have 1 unique prim for each curve. We are looking up the prim ID of the current curve/point trail and we create a mask string (for example !0, !1, etc). We will use that mask in xyzdist function which will ignore pt's own curve when searching for closest position on target geo. This approach uses function's all available arguments.
float xyzdist(<geometry>geometry, string primgroup, vector origin, int &prim, vector &uv, float maxdist)
So now we have closest point on any other curve segment in 3D space. If a neighbouring curve is close we calculate a distance radius so tubes don't intersect once we drop Sweep node. It will default to max pscale slider if it doesn't find anything within max search radius.
I've attached a hip file and I encourage you to take a look. Both these methods yield essentially the same result but xyzdist method is a bit more accurate and computes way faster compared to neighbour one.