discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Creating a 3D Screw with linear_extrude

NS
Nathan Sokalski
Wed, Apr 24, 2024 4:50 PM

I am working on learning how to make screw-like structures for things like the threads of screws & lids. I tried using code such as the following:

linear_extrude(height=50,twist=3*360)square([40,5]);

This is fine except for 1 thing: it is not 3D. I'm not sure if this is exactly true, since it does move around the z axis as going upwards, but it has a thickness of 0 (well, almost). How do I create a screw/thread that has thickness? Are there any tutorials or articles about ways to make good screws/threads using linear_extrude (or if there is a better way, whatever that is)? I would prefer not to use any third party libraries, because I like to have full knowledge of what OpenSCAD is using. Any ideas? Thanks!

Nathan Sokalski
njsokalski@hotmail.commailto:njsokalski@hotmail.com

I am working on learning how to make screw-like structures for things like the threads of screws & lids. I tried using code such as the following: linear_extrude(height=50,twist=3*360)square([40,5]); This is fine except for 1 thing: it is not 3D. I'm not sure if this is exactly true, since it does move around the z axis as going upwards, but it has a thickness of 0 (well, almost). How do I create a screw/thread that has thickness? Are there any tutorials or articles about ways to make good screws/threads using linear_extrude (or if there is a better way, whatever that is)? I would prefer not to use any third party libraries, because I like to have full knowledge of what OpenSCAD is using. Any ideas? Thanks! Nathan Sokalski njsokalski@hotmail.com<mailto:njsokalski@hotmail.com>
ST
Shaporev, Timur
Wed, Apr 24, 2024 5:01 PM

https://www.thingiverse.com/thing:2989174 :-)


From: Nathan Sokalski via Discuss discuss@lists.openscad.org
Sent: 24 April 2024 19:50:58
To: discuss@lists.openscad.org
Cc: Nathan Sokalski
Subject: [OpenSCAD] Creating a 3D Screw with linear_extrude

I am working on learning how to make screw-like structures for things like the threads of screws & lids. I tried using code such as the following:

linear_extrude(height=50,twist=3*360)square([40,5]);

This is fine except for 1 thing: it is not 3D. I'm not sure if this is exactly true, since it does move around the z axis as going upwards, but it has a thickness of 0 (well, almost). How do I create a screw/thread that has thickness? Are there any tutorials or articles about ways to make good screws/threads using linear_extrude (or if there is a better way, whatever that is)? I would prefer not to use any third party libraries, because I like to have full knowledge of what OpenSCAD is using. Any ideas? Thanks!

Nathan Sokalski
njsokalski@hotmail.commailto:njsokalski@hotmail.com

https://www.thingiverse.com/thing:2989174 :-) ________________________________ From: Nathan Sokalski via Discuss <discuss@lists.openscad.org> Sent: 24 April 2024 19:50:58 To: discuss@lists.openscad.org Cc: Nathan Sokalski Subject: [OpenSCAD] Creating a 3D Screw with linear_extrude I am working on learning how to make screw-like structures for things like the threads of screws & lids. I tried using code such as the following: linear_extrude(height=50,twist=3*360)square([40,5]); This is fine except for 1 thing: it is not 3D. I'm not sure if this is exactly true, since it does move around the z axis as going upwards, but it has a thickness of 0 (well, almost). How do I create a screw/thread that has thickness? Are there any tutorials or articles about ways to make good screws/threads using linear_extrude (or if there is a better way, whatever that is)? I would prefer not to use any third party libraries, because I like to have full knowledge of what OpenSCAD is using. Any ideas? Thanks! Nathan Sokalski njsokalski@hotmail.com<mailto:njsokalski@hotmail.com>
JB
Jordan Brown
Wed, Apr 24, 2024 6:25 PM

Yep, it always seems like linear_extrude with a twist would do it,
but... it doesn't, at least not straightforwardly.

It is possible.  You have to derive and then extrude a sort of
banana-shaped horizontal cross-section.
https://lists.openscad.org/empathy/thread/DC2WDIIZS57SIDWVAVKDN3NEN4MOZOYM
https://www.thingiverse.com/thing:1098806

There are three ways to design a helical sort of object:

  • horizontal cross section (which is what linear_extrude with a twist
    does)
  • vertical cross section
  • cross section parallel to the helix

I am told that real threads are usually designed with a vertical cross
section.  There are no built-in OpenSCAD mechanisms to generate such a
thing.

You would have to to it by generating a polyhedron, which is tedious but
once you get the hang of it not all that hard.  Mostly you need to
figure out the pattern that you want and the math to generate it.

But this is really something that's best done with a library that
somebody else has written.  Study the library if you want to know what's
going on.  DIY is hard and it will take a lot of work to replicate stuff
that other people have already done, e.g. duplicating standard threads.

Yep, it always seems like linear_extrude with a twist would do it, but... it doesn't, at least not straightforwardly. It *is* possible.  You have to derive and then extrude a sort of banana-shaped horizontal cross-section. https://lists.openscad.org/empathy/thread/DC2WDIIZS57SIDWVAVKDN3NEN4MOZOYM https://www.thingiverse.com/thing:1098806 There are three ways to design a helical sort of object: * horizontal cross section (which is what linear_extrude with a twist does) * vertical cross section * cross section parallel to the helix I am told that real threads are usually designed with a vertical cross section.  There are no built-in OpenSCAD mechanisms to generate such a thing. You would have to to it by generating a polyhedron, which is tedious but once you get the hang of it not all that hard.  Mostly you need to figure out the pattern that you want and the math to generate it. But this is really something that's best done with a library that somebody else has written.  Study the library if you want to know what's going on.  DIY is hard and it will take a lot of work to replicate stuff that other people have already done, e.g. duplicating standard threads.
JB
Jordan Brown
Thu, Apr 25, 2024 2:49 AM

On 4/24/2024 11:25 AM, Jordan Brown via Discuss wrote:

You would have to to it by generating a polyhedron, which is tedious
but once you get the hang of it not all that hard.  Mostly you need to
figure out the pattern that you want and the math to generate it.

I am deranged and think that generating polyhedra is kind of fun, so
here's a simple standalone thread generator.

This is basically a helical rotate_extrude.  The principles here apply
to most polyhedron construction:  calculate all the points, then connect
them up into faces.  Note that faces must wind clockwise.  I don't
bother obsessing over which way that is; I preview with View / Thrown
Together and reverse anything that ends up purple.  (Note that reversing
a triangle is just swapping any two coordinates.)

A similar strategy can be used to generate the female side of the
thread.  In fact, you could probably use this same module, with the
right profile and radius.

Filling the center core is left as an exercise for the reader.  Hint: 
make it a little bigger than the thread radius, so that the two overlap
everywhere.

Note that real threads are cleverer than this; they taper the top
thread, and so on.


// Given a point in XY space, pivot it to be in XZ space and rotate it around Z by the specified angle.
function rotz23(p, a) = [ p.x * cos(a), p.x * sin(a), p.y ];

// Generate a thread using a caller-supplied profile.
// profile - profile of thread, as a clockwise list of points in XY space, based at X=0
// r - inside radius of the thread
// h - total height
// pitch - pitch, in Z units per rotation
//
// Caution:  bad stuff will happen if the Z size of the profile is >= the pitch.
//
module thread(profile, r, h, pitch) {
// Use the standard $fn/$fs/$fa calculation to pick the number of steps per
// rotation, based on the inside radius.
fn = $fn > 0
? ($fn>=3?$fn:3)
:ceil(max(min(360/$fa,r2PI/$fs),5));

// Number of times the thread twists around the core.
// NB probably not an integer.
twists = h / pitch;
// Total number of steps in the entire helix. (Plus a starting step.)
nSteps = ceil(twists * fn);
// Angle for each step.
aStep = 360 * twists / nSteps;
// Z increment for each step.
zStep = h / nSteps;
// Number of sides in the profile.
nSides = len(profile);

// Calculate all of the points for the entire helix.
// For each step, for each point in the profile:
// * offset the point out by the radius
// * rotate it the right amount for this step
// * offset it up the right amount for this step
points = [
    for (i = [0:nSteps])
        for (p = profile)
            rotz23(p + [r,0], i * aStep) + [ 0, 0, i * zStep  ]
];

// Connect the points into faces.
faces = [
    // The starting polygon.
    [ for (i = [0:nSides-1]) i ],
    // The ending polygon.
    [ for (i = [nSides-1:-1:0]) len(points) - nSides + i ],
    // Now the body.  Each quad is split into two triangles;
    // generate the two in two separate loops.
    // (I'm not sure whether the quads are planar; if they are
    // then each one could be a face.  But triangularizing is the
    // general answer for most things, so just do it.)
    // First, generate triangles with their base at step i,
    // and their point at step i-1.
    for (i = [1:nSteps])
        for (j = [0:nSides-1]) [
            i * nSides + j,
            i * nSides + (j+1)%nSides,
            (i-1) * nSides + j
        ],
    // Then generate triangles with their point at step i,
    // and their base at step i-1.
    for (i = [1:nSteps])
        for (j = [0:nSides-1]) [
            (i-1) * nSides + (j+1)%nSides,
            (i-1) * nSides + j,
            i * nSides + (j+1)%nSides
        ],
];
// And generate the helix.
polyhedron(points, faces);

}

// Demonstration...

// A simple trapezoidal profile.
// NB must wind clockwise, lest the
// helix be inside-out.
profile = [
[0,0],
[0,3],
[2,2],
[2,1],
];

// Uncomment if you want to see the profile "raw".
// !polygon(profile);

// Generate the thread.
thread(profile=profile, r=5, h=21, pitch=4);

On 4/24/2024 11:25 AM, Jordan Brown via Discuss wrote: > You would have to to it by generating a polyhedron, which is tedious > but once you get the hang of it not all that hard.  Mostly you need to > figure out the pattern that you want and the math to generate it. I am deranged and think that generating polyhedra is kind of fun, so here's a simple standalone thread generator. This is basically a helical rotate_extrude.  The principles here apply to most polyhedron construction:  calculate all the points, then connect them up into faces.  Note that faces must wind clockwise.  I don't bother obsessing over which way that is; I preview with View / Thrown Together and reverse anything that ends up purple.  (Note that reversing a triangle is just swapping any two coordinates.) A similar strategy can be used to generate the female side of the thread.  In fact, you could probably use this same module, with the right profile and radius. Filling the center core is left as an exercise for the reader.  Hint:  make it a little bigger than the thread radius, so that the two overlap everywhere. Note that real threads are cleverer than this; they taper the top thread, and so on. --- // Given a point in XY space, pivot it to be in XZ space and rotate it around Z by the specified angle. function rotz23(p, a) = [ p.x * cos(a), p.x * sin(a), p.y ]; // Generate a thread using a caller-supplied profile. // profile - profile of thread, as a clockwise list of points in XY space, based at X=0 // r - inside radius of the thread // h - total height // pitch - pitch, in Z units per rotation // // Caution: bad stuff will happen if the Z size of the profile is >= the pitch. // module thread(profile, r, h, pitch) { // Use the standard $fn/$fs/$fa calculation to pick the number of steps per // rotation, based on the inside radius. fn = $fn > 0 ? ($fn>=3?$fn:3) :ceil(max(min(360/$fa,r*2*PI/$fs),5)); // Number of times the thread twists around the core. // NB probably not an integer. twists = h / pitch; // Total number of steps in the entire helix. (Plus a starting step.) nSteps = ceil(twists * fn); // Angle for each step. aStep = 360 * twists / nSteps; // Z increment for each step. zStep = h / nSteps; // Number of sides in the profile. nSides = len(profile); // Calculate all of the points for the entire helix. // For each step, for each point in the profile: // * offset the point out by the radius // * rotate it the right amount for this step // * offset it up the right amount for this step points = [ for (i = [0:nSteps]) for (p = profile) rotz23(p + [r,0], i * aStep) + [ 0, 0, i * zStep ] ]; // Connect the points into faces. faces = [ // The starting polygon. [ for (i = [0:nSides-1]) i ], // The ending polygon. [ for (i = [nSides-1:-1:0]) len(points) - nSides + i ], // Now the body. Each quad is split into two triangles; // generate the two in two separate loops. // (I'm not sure whether the quads are planar; if they are // then each one could be a face. But triangularizing is the // general answer for most things, so just do it.) // First, generate triangles with their base at step i, // and their point at step i-1. for (i = [1:nSteps]) for (j = [0:nSides-1]) [ i * nSides + j, i * nSides + (j+1)%nSides, (i-1) * nSides + j ], // Then generate triangles with their point at step i, // and their base at step i-1. for (i = [1:nSteps]) for (j = [0:nSides-1]) [ (i-1) * nSides + (j+1)%nSides, (i-1) * nSides + j, i * nSides + (j+1)%nSides ], ]; // And generate the helix. polyhedron(points, faces); } // Demonstration... // A simple trapezoidal profile. // NB must wind clockwise, lest the // helix be inside-out. profile = [ [0,0], [0,3], [2,2], [2,1], ]; // Uncomment if you want to see the profile "raw". // !polygon(profile); // Generate the thread. thread(profile=profile, r=5, h=21, pitch=4);