Curve U Map - Runs over several primitives

Creates two point attributes. One 0 - 1 and one 0 - 1 - 0 along each curve, based on point number / vertex order for each primitive.

Run in a Wrangle SOP (Run over - Primitives)

int prim_points[];
float umap, umap_half;

addattrib(geoself(), "point", "umap", 0.0);
addattrib(geoself(), "point", "umap_half", 0.0);

prim_points = primpoints(geoself(), @primnum);

for ( int i = 0; i < len(prim_points); i++ ){
    
    umap = float(i) / (len(prim_points) - 1);
    umap_half = clamp(umap, 0, 0.5) * clamp(umap * -1 + 1, 0, 0.5) * 4;
    
    setattrib(geoself(), "point", "umap", prim_points[i], 0, umap, "set");
    setattrib(geoself(), "point", "umap_half", prim_points[i], 0, umap_half, "set");
}

Curve Normals - Runs over a single primitive

Creates a normal along a single curve, two point based, unnormalized

Run in a Wrangle SOP (Run over - Points)

vector pos, nor_a, nor_b;

if ( @ptnum == 0) {
    getattribute(@OpInput1, pos, "point", "P", @ptnum + 1, 0);
    @N = @P - pos;
} else if ( @ptnum == (npoints(@OpInput1) - 1) ) {
    getattribute(@OpInput1, pos, "point", "P", @ptnum - 1, 0);
    @N = pos - @P;
} else {
    getattribute(@OpInput1, pos, "point", "P", @ptnum - 1, 0);
    nor_a = pos - @P;
    getattribute(@OpInput1, pos, "point", "P", @ptnum + 1, 0);
    nor_b = @P - pos;
    @N = (nor_a + nor_b) / 2;
}

Curve Normals - Runs over several primitives

Creates a normal along a curve for each primitive, single point based, normalized

Run in a Wrangle SOP (Run over - Primitives)

int prim_points[];
vector pos_A, pos_B, dir;

addattrib(geoself(), "point", "N", {0, 0, 0});

prim_points = primpoints(geoself(), @primnum);

for ( int i = 0; i < len(prim_points); i++ ){

    getattribute(@OpInput1, pos_A, "point", "P", prim_points[i], 0);
    
    if ( i == 0) {
        getattribute(@OpInput1, pos_B, "point", "P", prim_points[1], 0);
        dir = normalize(pos_B - pos_A);
    }
    else {
        getattribute(@OpInput1, pos_B, "point", "P", prim_points[i - 1], 0);
        dir = normalize(pos_A - pos_B);
    }
    setattrib(geoself(), "point", "N", prim_points[i], 0, dir, "set");
}

Curve length

Creates two attributes, one primitive attribute for the total length of each curve and one point attribute for the partial length of the curve up to that point

Run in a Wrangle SOP (Run over - Primitives)

int     prim_points[];
float   length;
vector  pos_A, pos_B;

addattrib(geoself(), "point", "length_partial", 0.0);

prim_points = primpoints(geoself(), @primnum);

length = 0;

for (int i = 1; i < len(prim_points); i++){
    getattribute(@OpInput1, pos_A, "point", "P", prim_points[i - 1], 0);
    getattribute(@OpInput1, pos_B, "point", "P", prim_points[i], 0);

    length += distance(pos_A, pos_B);

    setattrib(geoself(), "point", "length_partial", prim_points[i], 0, length, "set");
}

f@length = length;

Curve Orient - Runs over several primitives

Creates a orient attribute along each curve. A point normal vector attribute pointing along the curve is needed. 
Uncomment line 21 if you have a unique up vector point attribute for each curve that you want to use.

Run in a Wrangle SOP (Run over - Primitives)

addattrib(geoself(), "point", "up", {0, 0, 0});
addattrib(geoself(), "point", "side", {0, 0, 0});
addattrib(geoself(), "point", "orient", {0, 0, 0, 0});

int curve_pts[];

matrix3 matx;
vector  v_align_to, v_align_from, v_up, v_side;
vector4 quat;

vector  v_ref = {1, 0, 0};

curve_pts = primpoints(geoself(), @primnum);

for (int i = 0; i < len(curve_pts); i++)
{
        if ( i == 0 )
        {
                // For the first point
                getattribute(@OpInput1, v_align_to, "point", "N", curve_pts[0], 0);
                //getattribute(@OpInput1, v_ref, "point", "up", curve_pts[0], 0);

                v_up    = cross(normalize(v_align_to), normalize(v_ref));
                v_side  = cross(normalize(v_align_to), normalize(v_up));

                setattrib(geoself(), "point", "up",     curve_pts[0], 0, v_up,     "set");
                setattrib(geoself(), "point", "side",   curve_pts[0], 0, v_side,   "set");

                matx = lookat({ 0, 0, 0 }, v_align_to, v_up);
                quat = quaternion(matx);

                setattrib(geoself(), "point", "orient", curve_pts[0], 0, quat, "set");  
        } 
        
        // Get the current points normal
        getattribute(@OpInput1, v_align_from, "point", "N", curve_pts[i], 0);
        
        matx = dihedral(v_align_to, v_align_from);

        v_align_to  = normalize(v_align_from);
        v_up        = normalize(v_up * matx);
        v_side      = normalize(v_side * matx);

        setattrib(geoself(), "point", "up",     curve_pts[i], 0, v_up,     "set");
        setattrib(geoself(), "point", "side",   curve_pts[i], 0, v_side,   "set");

        matx = lookat({ 0, 0, 0 }, v_align_to, v_up);
        quat = quaternion(matx);

        setattrib(geoself(), "point", "orient", curve_pts[i], 0, quat, "set");
}

Curve Multi Carve

Let's you carve several curves at one based on a unique primitive carve attribute for each curve. Based on point number and depends on a point U Map attribute between 0-1 on each curve.

Run in a Wrangle SOP (Run over - Primitives)

int prim_points[], carve_point_start, carve_point_end;
float carve_start, carve_end, umap;
vector pos_u;

prim_points = primpoints(geoself(), @primnum);

//carve_start = f@carve_start;
//carve_end = f@carve_start;

carve_start = ch("carve_start");
carve_end = ch("carve_end");

if ( carve_start >= carve_end )
    removeprim(geoself(), @primnum, 1);
else {
    carve_point_start = -1;
    carve_point_end = -1;
    
    // Carve Start
    for ( int i = len(prim_points)-1; i >= 0; i-- ){
        
        getattribute(@OpInput1, umap, "point", "umap", prim_points[i], 0);
        
        if ( umap < carve_start ){
             
            carve_point_start = i;
            
            if ( i != len(prim_points) + 1 ){
                
                for ( int j = i - 1; j >= 0; j-- ){
                    removepoint(geoself(), prim_points[j]);
                }
                break;
            }
        }
    }
    
    // Carve End
    for ( int i = 0; i < len(prim_points); i++ ){
        
        getattribute(@OpInput1, umap, "point", "umap", prim_points[i], 0);
            
        if ( umap > carve_end ){
                                
            carve_point_end = i;
            
            if ( i != len(prim_points) + 1 ){
                
                for ( int j = i + 1; j < len(prim_points); j++ ){
                    removepoint(geoself(), prim_points[j]);
                }
                break;
            }
        }
    }
    
    if ( carve_point_start >= 0 ){
        pos_u = primuv(@OpInput1, "P", @primnum, set(carve_start, 0, 0));
        setattrib(geoself(), "point", "P", prim_points[carve_point_start], 0, pos_u, "set");
    }
    
    if ( carve_point_end >= 0 ){
        pos_u = primuv(@OpInput1, "P", @primnum, set(carve_end, 0, 0));
        setattrib(geoself(), "point", "P", prim_points[carve_point_end], 0, pos_u, "set");
    }
}

Multi Skin

A prim_id primitive attribute is needed to separate each group of primitives

Run in a Wrangle SOP (Run over - Primitives)

int prim_A_points[], prim_B_points[], newPrim_points[], prim, num_prim, prim_id[];

num_prim = nprimitives(@OpInput1);

removeprim(geoself(), @primnum, 0);

if ( @primnum < num_prim - 1 ){
    
    getattribute(@OpInput1, prim_id[0], "primitive", "prim_id", @primnum, 0);
    getattribute(@OpInput1, prim_id[1], "primitive", "prim_id", @primnum + 1, 0);
    
    if ( prim_id[0] == prim_id[1] ){
        prim_A_points = primpoints(geoself(), @primnum);
        prim_B_points = primpoints(geoself(), @primnum + 1);
            
        for ( int i = 0; i < len(prim_A_points); i++ ){
            
            prim = addprim(geoself(), "poly");
            
            if ( i == len(prim_A_points) - 1 ){
                addvertex(geoself(), prim, prim_B_points[i]);
                addvertex(geoself(), prim, prim_B_points[0]);
                addvertex(geoself(), prim, prim_A_points[0]);
                addvertex(geoself(), prim, prim_A_points[i]);
            }
            else {
                addvertex(geoself(), prim, prim_B_points[i]);
                addvertex(geoself(), prim, prim_B_points[i + 1]);
                addvertex(geoself(), prim, prim_A_points[i + 1]);
                addvertex(geoself(), prim, prim_A_points[i]);
            }
        }
    }
}

Curve Sections

Creates a unique primitive for each section of a curve

Run in in a Wrangle SOP (Run Over - Primitive)

int prim_points[], prim, point_A, point_B;
vector pos_A, pos_B;
prim_points = primpoints(geoself(), @primnum);

for ( int i = 1; i < len(prim_points); i++ )
{
    prim = addprim(geoself(), "polyline");
    
    pos_A = attrib( 0, "point", "P", prim_points[i - 1] );
    pos_B = attrib( 0, "point", "P", prim_points[i] );
    
    point_A = addpoint( geoself(), pos_A );
    point_B = addpoint( geoself(), pos_B );
        
    addvertex(geoself(), prim, point_A );
    addvertex(geoself(), prim, point_B );
}
removeprim(geoself(), @primnum, 1);

Add a point at the center of each primitive

Adds a point at the center of each primitive and removes the primitive, useful for a bunch of stuff.

Run in a Wrangle SOP (Run over - Primitives)

int prim_points[];
vector accum_pos, pos;
accum_pos = {0, 0, 0};

for (int i = 0; i < primvertexcount(geoself(), @primnum); i++)
{
    int vtx_index = vertexindex(geoself(), @primnum, i);
    int vtx_point = vertexpoint(geoself(), vtx_index); 
    prim_points[i] = vtx_point;
    getattribute(@OpInput1, pos, "point", "P", vtx_point, 0);
    accum_pos += pos;
}

addpoint(geoself(), accum_pos / len(prim_points));
removeprim(geoself(), @primnum, 1);

Create a poly line between adjacent points

Good for creating constraints. Similar to Connect Adjacent Pieces SOP. Beware though it creates overlapping primitives, i.e. twice as many lines as you probably want. See the next VEX snippet for a solution that removes overlapping primitives.

Run in a Wrangle SOP (Run over - Points)

float   radius_max = chf("radius");
int     points_max = chi("connections");

int     points[] = nearpoints( 0, @P, radius_max, points_max );

int     prim;
string  name;

for ( int i = 0; i < len(points); i++ )
{
    if ( points[i] <= @ptnum )
        continue;         
        
    name = attrib( 0, "point", "name", points[i] );
    
    if ( name == s@name )
        continue;         
    
    prim = addprim( geoself(), "polyline" );            
    
    addvertex( geoself(), prim, @ptnum );
    addvertex( geoself(), prim, points[i] );
    
    @Cd = {1, 0, 0};
}

Remove overlapping primitives

Mainly a complement to the previous VEX snippet.

Run in a Wrangle SOP (Run over - Primitives)

int prim_points[] = primpoints( geoself(), @primnum );
vector pos_accum = 0;

for ( int i = 0; i < len(prim_points); i++ )
{
    pos_accum += attrib( 0, "point", "P", prim_points[i] );
}

pos_accum /= len(prim_points);

int xyz_prim;
vector xyz_uv;

float xyz_dist = xyzdist( 0, pos_accum, xyz_prim, xyz_uv);

if ( xyz_prim > @primnum && xyz_dist < 0.001 )
    removeprim(geoself(), @primnum, 1);
else if ( xyz_prim < @primnum && xyz_dist < 0.001 )
    removeprim(geoself(), xyz_prim, 1);

Random text as a point string attribute

string alphabet[] = string[](array
    ("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
    );

s@text = alphabet[int(fit01(rand(@ptnum), 0, len(alphabet) - 1))];

Random Groups

int my_rand = int(rand(@ptnum) * 10);

setpointgroup(geoself(), sprintf("points_%g", (@ptnum + my_rand) % ch("num_groups") ), @ptnum, 1, "set");

Simple smooth operation that supports point groups

Put it in a For Each SOP and disable Merge Results and set it to For - Each Number, to get iterations

Run in in a Wrangle SOP (Run Over - Detail)

for ( int j = 0; j < npoints(@OpInput1); j++ ){

    if ( inpointgroup(@OpInput1, "holes", j )){
    
        int pt_neighbours[];
        vector neighbour_pos, neighbour_pos_accum, pos;
        
        pt_neighbours = neighbours(@OpInput1, j);
        
        neighbour_pos_accum = 0;
        
        for ( int k = 0; k < len(pt_neighbours); k++ ){
            
            getattribute(@OpInput1, neighbour_pos, "point", "P", pt_neighbours[k], 0);
            
            neighbour_pos_accum += neighbour_pos;
        
        }
        
        neighbour_pos_accum = neighbour_pos_accum / len(pt_neighbours);
        
        getattribute(@OpInput1, pos, "point", "P", j, 0);
            
        pos = lerp(pos, neighbour_pos_accum, 0.5);
        
        setattrib(geoself(), "point", "P", j, 0, pos, "set");
        
    }
}

Point Cloud - Base

Base code for point cloud opertations

int pc_ptnum, pc_points;
float pc_attr, accum;
vector pc_pos;

pc_points = 40;
pc_attr = 0;
accum = 0;

int handle = pcopen(@OpInput1, "P", @P, 1000, pc_points);

while(pciterate(handle)) {

    pcimport(handle, "point.number", pc_ptnum);

    if (pc_ptnum == @ptnum)
        continue; 
    
    pcimport(handle, "Alpha", pc_attr);

    accum += pc_attr;
}
pcclose(handle);
f@Alpha = accum / pc_points;

Find opposite point on a quadrilateral (4 points) primitive

I had to squash a primitive together, from on point towards the opposite of the point (the one point that wasn't connected to the "main" point). For this I needed the direction and distance to move the point.

Run in in a Wrangle SOP (Run Over - Primitive)

int prim_points[], point_A, point_B, connected, pt_neighbours[];
vector pos_A, pos_B, dir_opposite;

prim_points = primpoints(geoself(), @primnum);

for ( int i = 0; i < len(prim_points); i++ ){

    if ( inpointgroup(@OpInput1, "main", prim_points[i] )){
        point_A = prim_points[i];
        break;
    }

}

for ( int i = 0; i < len(prim_points); i++ ){

    if ( prim_points[i] == point_A )
        continue;

    connected = 0;

    pt_neighbours = neighbours(@OpInput1, prim_points[i]);

    for ( int j = 0; j < len(pt_neighbours); j++ ){

        if ( pt_neighbours[j] == point_A )
            connected = 1;

    }

    if ( connected == 0 ){

        point_B = prim_points[i];
        //printf("Main point %g opposite point is %g \n", point_A, point_B);
        break;

    }
}

getattribute(@OpInput1, pos_A, "point", "P", point_A, 0);
getattribute(@OpInput1, pos_B, "point", "P", point_B, 0);

dir_opposite = pos_B - pos_A;

addattrib(geoself(), "point", "dir_opposite", {0, 0, 0});
setattrib(geoself(), "point", "dir_opposite", point_A, 0, dir_opposite, "set");

Velocity vector

Calculate a velocity vector, same result as if you would take a Trail SOP and set it to Compute Velocity.

Run in a Wrangle SOP (Run over - Points)

@v = (new_pos - @P) * (1 / @Timeinc);

Read velocity as units / second or meter / second

Run in a Wrangle SOP (Run over - Points)

f@speed = length(@v) * @Timeinc;

Camera Orient

Object Merge the cameras camOrigin into SOP's with two extra point added on the add node in the camera

Point 0: 0, 0, 0
Point  1: 0,  1, 0
Point 2: 0, 0, -1 

Run in a Wrangle SOP (Run over - Points)

if ( @ptnum == 0 ){
    vector front, up, pos_front, pos_up;
    matrix3     matx;
    vector4     orient;
    
    getattribute(@OpInput1, pos_up,     "point", "P", 1, 0);
    getattribute(@OpInput1, pos_front,  "point", "P", 2, 0);
    
    up = normalize(pos_up - @P);
    front = normalize(pos_front - @P);
    
    matx = lookat({ 0, 0, 0 }, front, up);
    
    orient = quaternion(matx);

    p@orient = orient;
    
} else {
    removepoint(geoself(), @ptnum);
}

Reset orient

If you use orient to align objects before a Bullet simulation, you need to multiply the orient attribute you get from bullet with your initial orient attribute. To get a orient attribute that works correctly with transform pieces SOP or copy to point SOP. 

Run in a Wrangle SOP (Run over - Points)

p@orient = qmultiply( p@orient, p@orient_init);

Point unique id

In DOP's when creating new points with a Wrangle node in a SOP Solver, it's tricky to assign unique id attribute when several points are created on the same time step. 
Assign -1 as the id on all the points that is created and run them trough a second Wrangle node.
You need a detail attribute named id_max with the largest current id value

Run in a Wrangle SOP (Run over - Detail)

int num_new_children, new_child, new_child_id, id_max;

id_max = detail( @OpInput1, "id_max", 0);

num_new_children = findattribvalcount( @OpInput1, "point", "id", -1);

for ( int i = 0; i < num_new_children; i++ ){

    new_child = findattribval( @OpInput1, "point", "id", -1, i);
    
    new_child_id = id_max + i + 1;
    
    setattrib(geoself(), "point", "id", new_child, 0, new_child_id, "set");
    
}

Cavity map

Calculates how much a deformed geometry is squashed and skewed. For each point it takes the angle between perpendicular N and each point neighbor and compares the value between rest and deformed geometry.

Run in a Wrangle SOP (Run over - Points). Plug in the rest geometry into the first input and the deformed geometry into the other. Point order has to match.

int points[];

points = neighbours( 0, @ptnum );

float   angle_A_accum, angle_B_accum;
vector  pos, nrm, dir;

angle_A_accum = 0;

for( int i = 0; i < len(points); i++ )
{
    pos = attrib( 0, "point", "P", points[i] );    
    nrm = @N;
    
    dir = pos - @P;
    
    nrm = normalize(nrm);
    dir = normalize(dir);
    
    angle_A_accum += dot(nrm, dir);
}

points = neighbours( 1, @ptnum );

angle_B_accum = 0;

for( int i = 0; i < len(points); i++ )
{
    pos = attrib( 1, "point", "P", points[i] );    
    nrm = attrib( 1, "point", "N", @ptnum );
    
    dir = pos - attrib( 1, "point", "P", @ptnum );
    
    nrm = normalize(nrm);
    dir = normalize(dir);
    
    angle_B_accum += dot(nrm, dir);
}

angle_A_accum = abs( angle_A_accum );
angle_B_accum = abs( angle_B_accum );

f@angle_A_accum = angle_A_accum;
f@angle_B_accum = angle_B_accum;

float angle;

angle = abs( angle_A_accum - angle_B_accum );

angle = fit( angle, 0, 1, 0, 1);

f@angle = angle * -1 + 1;

@Cd = chramp("color", angle );