diff --git a/threading.scad b/threading.scad
index 9ae5431..bd77ad9 100644
--- a/threading.scad
+++ b/threading.scad
@@ -151,15 +151,10 @@ module trapezoidal_threaded_rod(
     higbee=0, higbee1, higbee2,
     center, anchor, spin, orient
 ) {
-    function _thread_pt(thread, threads, start, starts, astep, asteps, part, parts) =
-        astep + asteps * (thread + threads * (part + parts * start));
-
     _r1 = get_radius(d1=d1, d=d, dflt=10);
     _r2 = get_radius(d1=d2, d=d, dflt=10);
-    sides = segs(max(_r1,_r2));
+    sides = quantup(segs(max(_r1,_r2)), starts);
     rsc = internal? (1/cos(180/sides) + $slop*3) : 1;
-    astep = 360 / quantup(sides, starts);
-    asteps = ceil(360/astep);
     threads = ceil(l/pitch/starts)+(starts<4?4-starts:1);
     depth = min((thread_depth==undef? pitch/2 : thread_depth), pitch/2/tan(thread_angle));
     pa_delta = min(pitch/4-0.01,depth*tan(thread_angle)/2)/pitch;
@@ -175,12 +170,12 @@ module trapezoidal_threaded_rod(
     assert(higang2 < twist/2);
 
     higbee_table = [
-        [-twist, 0],
-        [-twist/2-0.001, 0],
+        [-twist,           0.01],
+        [-twist/2,         0.01],
         [-twist/2+higang1, 1],
         [ twist/2-higang2, 1],
-        [ twist/2+0.001, 0],
-        [ twist, 0]
+        [ twist/2,         0.01],
+        [ twist,           0.01]
     ];
 
     r1 = -depth/pitch;
@@ -192,132 +187,59 @@ module trapezoidal_threaded_rod(
         [ z1,  0],
         [ z2, r1],
     ];
-    parts = len(profile);
-    poly_points = concat(
-        [
-            for (
-                start  = [0:1:starts-1],
-                part   = [0:1:parts-1],
-                thread = [0:1:threads-1],
-                astep  = [0:1:asteps-1]
-            ) let (
-                a = astep / asteps,
-                z = (thread + a - threads/2) * starts * pitch,
-                u = z / l,
-                higsc = higbee1==0 && higbee2==0? 1 :
-                    let ( tot_ang = (thread+a-threads/2) * 360 )
-                    lookup(tot_ang, higbee_table),
-                ppt = profile[part] * pitch,
-                dz = ppt.x,
-                r = lerp(_r1, _r2, u) - depth + higsc*(ppt.y+depth),
-                c = cos(360 * (a * dir + start/starts)),
-                s = sin(360 * (a * dir + start/starts))
-            ) [r*c, r*s, z+dz]
-        ],
-        [[0, 0, -threads*pitch*starts/2-pitch/4], [0, 0, threads*pitch*starts/2+pitch/4]]
-    );
-    point_count = len(poly_points);
-    poly_faces = concat(
-        // Thread surfaces
-        [
-            for (
-                start  = [0:1:starts-1],
-                part   = [0:1:parts-2],
-                thread = [0:1:threads-1],
-                astep  = [0:1:asteps-1],
-                trinum = [0, 1]
-            ) let (
-                p0 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
-                p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
-                p2 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part, parts),
-                p3 = _thread_pt(thread, threads, start, starts, astep+1, asteps, part+1, parts),
-                tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
-                otri = left_handed? [tri[0], tri[2], tri[1]] : tri
-            )
-            if (!(thread == threads-1 && astep == asteps-1)) otri
-        ],
-        // Thread trough bottom
-        [
-            for (
-                start  = [0:1:starts-1],
-                thread = [0:1:threads-1],
-                astep  = [0:1:asteps-1],
-                trinum = [0, 1]
-            ) let (
-                p0 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
-                p1 = _thread_pt(thread, threads, (start+(left_handed?1:starts-1))%starts, starts, astep+asteps/starts, asteps, 0, parts),
-                p2 = p0 + 1,
-                p3 = p1 + 1,
-                tri = trinum==0? [p0, p1, p3] : [p0, p3, p2],
-                otri = left_handed? [tri[0], tri[2], tri[1]] : tri
-            )
-            if (
-                !(thread >= threads-1 && astep > asteps-asteps/starts-2) &&
-                !(thread >= threads-2 && starts == 1 && astep >= asteps-1)
-            ) otri
-        ],
-        // top and bottom thread endcap
-        [
-            for (
-                start  = [0:1:starts-1],
-                part   = [1:1:parts-2],
-                is_top = [0, 1]
-            ) let (
-                astep = is_top? asteps-1 : 0,
-                thread = is_top? threads-1 : 0,
-                p0 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
-                p1 = _thread_pt(thread, threads, start, starts, astep, asteps, part, parts),
-                p2 = _thread_pt(thread, threads, start, starts, astep, asteps, part+1, parts),
-                tri = is_top? [p0, p1, p2] : [p0, p2, p1],
-                otri = left_handed? [tri[0], tri[2], tri[1]] : tri
-            ) otri
-        ],
-        // body side triangles
-        [
-            for (
-                start  = [0:1:starts-1],
-                is_top = [false, true],
-                trinum = [0, 1]
-            ) let (
-                astep = is_top? asteps-1 : 0,
-                thread = is_top? threads-1 : 0,
-                ostart = (is_top != left_handed? (start+1) : (start+starts-1))%starts,
-                ostep = is_top? astep-asteps/starts : astep+asteps/starts,
-                oparts = is_top? parts-1 : 0,
-                p0 = is_top? point_count-1 : point_count-2,
-                p1 = _thread_pt(thread, threads, start, starts, astep, asteps, 0, parts),
-                p2 = _thread_pt(thread, threads, start, starts, astep, asteps, parts-1, parts),
-                p3 = _thread_pt(thread, threads, ostart, starts, ostep, asteps, oparts, parts),
-                tri = trinum==0?
-                    (is_top? [p0, p1, p2] : [p0, p2, p1]) :
-                    (is_top? [p0, p3, p1] : [p0, p3, p2]),
-                otri = left_handed? [tri[0], tri[2], tri[1]] : tri
-            ) otri
-        ],
-        // Caps
-        [
-            for (
-                start  = [0:1:starts-1],
-                astep  = [0:1:asteps/starts-1],
-                is_top = [0, 1]
-            ) let (
-                thread = is_top? threads-1 : 0,
-                part = is_top? parts-1 : 0,
-                ostep = is_top? asteps-astep-2 : astep,
-                p0 = is_top? point_count-1 : point_count-2,
-                p1 = _thread_pt(thread, threads, start, starts, ostep, asteps, part, parts),
-                p2 = _thread_pt(thread, threads, start, starts, ostep+1, asteps, part, parts),
-                tri = is_top? [p0, p2, p1] : [p0, p1, p2],
-                otri = left_handed? [tri[0], tri[2], tri[1]] : tri
-            ) otri
-        ]
-    );
+    pdepth = -min(subindex(profile,1));
+    eprofile = [
+        [-0.5, 0],
+        each move([0,pdepth], p=profile),
+        [ 0.5, 0],
+    ] * pitch;
+    angstep = 360 / sides;
+    angsteps = ceil(twist / (360 / sides)) + sides;
+    zang = atan2(_r2-_r1,l);
+    thread_verts = [
+        [for (x = eprofile) [0,0,-l/2]],
+        for (a = [0:1:angsteps]) let (
+            u = (a-angsteps/2) / (angsteps-sides),
+            ang = u * twist,
+            r = lerp(_r1, _r2, u) * rsc,
+            hsc = higbee1==0 && higbee2==0? 1 : lookup(ang, higbee_table),
+            mat = affine3d_zrot(ang*dir) *
+                affine3d_translate([r-pdepth*pitch, 0, l*u-0*pitch]) *
+                affine3d_xrot(90) *
+                affine3d_skew_xz(xa=zang) * 
+                affine3d_mirror([-1,1]) *
+                affine3d_scale([1,hsc,1]),
+            pts = apply(mat, path3d(eprofile))
+        ) pts,
+        [for (x = eprofile) [0,0, l/2]],
+    ];
+    thread_vnf = vnf_vertex_array(thread_verts, reverse=left_handed);
+    eplen = len(eprofile);
+    vlen = len(thread_vnf[0]);
+    thread_vnf2 = [
+        concat(thread_vnf[0], [[0,0,-l/2], [0,0,l/2]]),
+        concat(thread_vnf[1], [
+            for (i = [0:1:sides/starts]) each
+            left_handed? [
+                [eplen*(i+1), eplen*i, vlen],
+                [vlen-eplen*(i+1)-1, vlen-eplen*i-1, vlen+1]
+            ] : [
+                [eplen*i,        eplen*(i+1),      vlen],
+                [vlen-eplen*i-1, vlen-eplen*(i+1)-1, vlen+1]
+            ]
+        ])
+    ];
+    thread_vnfs = vnf_merge([
+        for (start = [0:1:starts-1]) zrot(start*360/starts, p=thread_vnf2)
+    ]);
     anchor = get_anchor(anchor, center, BOT, CENTER);
     attachable(anchor,spin,orient, r1=_r1, r2=_r2, l=l) {
         difference() {
-            polyhedron(points=poly_points, faces=poly_faces, convexity=threads*starts*2);
-            zcopies(l+4*pitch*starts) cylinder(h=4*pitch*starts, r=2*max(_r1,_r2)+1, center=true);
-            if (bevel) cylinder_mask(r1=_r1, r2=_r2, l=l+0.01, chamfer=depth);
+            vnf_polyhedron(thread_vnfs, convexity=10);
+            zcopies(l+4*pitch*starts)
+                cylinder(h=4*pitch*starts, r=2*max(_r1,_r2)+1, center=true);
+            if (bevel)
+                cylinder_mask(r1=_r1, r2=_r2, l=l+0.01, chamfer=depth);
         }
         children();
     }
diff --git a/version.scad b/version.scad
index 93a7a48..429cd19 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,554];
+BOSL_VERSION = [2,0,555];
 
 
 // Section: BOSL Library Version Functions