spiral_extrude() module

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

spiral_extrude() module

boxcarmib
With chat of libraries and the like, I thought I would provide a module that I wrote that I’ve found very helpful in my own work.
I call it “spiral_extrude” and it’s a linear/rotate extrude hybrid.
It’s particularly useful for bolt threads, or perhaps for anyone who wants to model balusters.
It works kind of like the twist parameter in linear extrude except that each spiral extrusion is stitched to the earlier layer forming a closed watertight polyhedron.
(At least I HOPE it does).
Before I release it into the wild (i.e. thingiverse) I’d appreciate feedback… particularly performance improvements, efficiencies or oversights… and then again,  if someone identifies that some existing OpenSCAD functionality does this already and my module is redundant, that would be good to know too. :)
spiral_extrude() does require a set of profile points, but I hope that’s not too much of a drawback. As far as I could determine, there’s no way accomplish the spiral stitching with OpenSCAD 2d objects.
Here’s a picture of the examples produced by the module followed by the code…

/*
spiral_extrude(height, profilePoints, radius, pitch)
from a set of xy points that define a profile, e.g.
[[0,0], [0,.4],[1,1], [1, 1.4], [0,2]]
produce an spiral extruded polyhedron with the specified pitch and radius and of length height along the z axis.

NOTE:
- profilePoints[0] must be on origin [0,0]
- profilePoints y co-ordinates must be positive and in ascending order

procedure:
- for each point in the profile generate a 3d point by adding a z value equal to the
vertical offset for each segment in the spiral. Number of segments in each rotation
is equal to $fn.
- add a base [0,0,0] and top [0,0,height] origin point for stitching
faces for a bottom and top cap
- sealing the polyhedron requires two operations
1) creating triangular faces from the base and top origin points to all ajacent points
in the bottom and top row respectively
2) creating a vertical 'sealing' face to connect the base and top origin point to
each point in the profile in the first and last segment
*/

kClockwise = 1;
kCounterClockwise = -1;

// extrude in clockwise or counterclockwise manner
$spiralVector = kClockwise;
$fn = 100;

// return the maximum value in nth position of vectors v in matrix m
// recursive function
function m_max_v_nth(m, n, _index = 0, _max = 0) =
_index >= len(m)
? _max
: _index == 0
? m_max_v_nth(m, n, 1, m[0][n])
: m_max_v_nth(m, n, _index + 1, max(_max, m[_index][n]));

// return 3d pt of x rotated by angle a with z of z
// a = angle of rotation
function xza2xyz(x,z,a) = [cos(a) * x, sin(a) * x, z];

function points_in_origin(profilePoints, zIncrement, xOffset) =
let(angle = 360 / $fn * $spiralVector)
[for(segment = [0:$fn - 1])
xza2xyz(profilePoints[0][0] + xOffset, profilePoints[0][1] + (zIncrement * segment), segment * angle) ];

function points_in_rotation(segments, profilePoints, zIncrement, xOffset) =
let(angle = 360 / $fn * $spiralVector)
[for(segment = [0:segments])
for(point = [1:len(profilePoints)-1])
xza2xyz(profilePoints[point][0] + xOffset, profilePoints[point][1] + (zIncrement * segment), segment * angle)];


module spiral_extrude(height, profilePoints, radius, pitch) {
defaultWidth = m_max_v_nth(profilePoints,0);
// calculate any additional x offset to increase the diameter of the extrusion
xOffset =
is_undef(radius)
? 0
: defaultWidth < radius
? radius - defaultWidth
: 0;
// calculate any addtitional y offset to pad the profile to the stated pitch
defaultPitch = m_max_v_nth(profilePoints,1);
pHeight = 
is_undef(pitch)
? defaultPitch
: max(pitch, defaultPitch);
rotations = ceil(height / pHeight) + 2;
zIncrement = pHeight / $fn;
pPointCount = len(profilePoints);
pPointLimit = pPointCount - 1;
pFaceCount = pPointLimit;
pFaceLimit = pFaceCount - 1;
segCount = $fn * rotations;
segLimit = segCount - 1;

pp = points_in_rotation(segCount, profilePoints, zIncrement, xOffset);
bp = points_in_origin(profilePoints, zIncrement, xOffset);
// concat all points adding the top bottom and top origin points
allPoints = concat(pp, bp, [[0,0,0], [0,0,segCount * zIncrement + pHeight]]);

ppIndex = 0;
bpIndex = len(pp);
bottomOriginIndex = bpIndex + len(bp);
topOriginIndex = bottomOriginIndex + 1;
// eoPPindex = bpIndex - 1;

ppCount = len(pp);

lastProfilePointPos = ppCount - 1;
firstTopCapPointPos = lastProfilePointPos - ($fn * pPointLimit);
fnLimit = $fn - 1;

af = 
[
for(segment = [0:segLimit])
for(face = [0:pFaceLimit])
let(faces =
face == 0
?
[
segment < $fn
? ppCount + segment
: (segment - fnLimit) * pFaceCount - 1 
,
segment * pFaceCount + face,
(segment + 1) * pFaceCount + face,
segment < fnLimit
? ppCount + segment + 1
: (segment - fnLimit) * pFaceCount + pFaceLimit
]
: // face != 0
[
segment * pFaceCount + face - 1,
segment * pFaceCount + face,
(segment + 1) * pFaceCount + face,
(segment + 1) * pFaceCount + face - 1
]
)
for(i = [0:1])
i == 0
? [faces[1], faces[2], faces[3]] // 0,1,2 ... 0,2,3
: [faces[3], faces[0], faces[1]]
];
bottomCap =
[for(f = [0:$fn - 1])
[
bottomOriginIndex,
bpIndex + f,
f == $fn - 1
? ppIndex + pPointLimit - 1
: bpIndex + f + 1
]
];
topCap =
[for(f = [firstTopCapPointPos:pPointLimit:lastProfilePointPos - 1])
[
topOriginIndex,
f + pPointLimit,
f
]
];

topSeal =
let(startPos = lastProfilePointPos - pPointCount + 1)
[for(f = [0:pPointLimit - 1])
f == 0
? startPos - $fn * pPointLimit + pPointLimit
: startPos + f
,
startPos + f + 1,
topOriginIndex,
]
];
bottomSeal =
[
for(f = [0:pPointLimit - 1])
[
f,
f == 0
? ppCount
: f - 1,
bottomOriginIndex, 
]
];
allFaces = concat(af, bottomCap, topCap, topSeal, bottomSeal);

polyhedron(points = allPoints, faces = allFaces);

}



module spiral_extrude_examples() {
circlePoints = [[0, 0], [6.18034, 0.9789], [11.7557, 3.8197], [16.1803, 8.2443], [19.0211, 13.8197], [20, 20], [19.0211, 26.1803], [16.1803, 31.7557], [11.7557, 36.1803], [6.18034, 39.0211], [0, 40]];
topPoints = [[10,0],[12,1],[11,2],[11,3],[13,4],[10,5]];
threadPoints = [[10.9175, 0], [10.9175, 0.5], [12, 1.125], [12, 1.375], [10.9175, 2]];
// polygon(circlePoints);

translate([-100,0,0])
spiral_extrude(200,circlePoints);
translate([-15,0,0])
spiral_extrude(200,circlePoints, radius = 40);

translate([120,0,0])
spiral_extrude(200,circlePoints, radius = 80);
translate([0,180,0]) {
translate([-100,0,0])
spiral_extrude(200,topPoints);
translate([-25,0,0])
spiral_extrude(200,topPoints, radius = 20, pitch = 10);
translate([80,0,0])
spiral_extrude(200,topPoints, radius = 50, pitch = 20);
}

translate([0,-180,0]) {
translate([-100,0,0])
spiral_extrude(200,threadPoints);
translate([-25,0,0])
spiral_extrude(200,threadPoints, radius = 20);
translate([80,0,0])
spiral_extrude(200,threadPoints, radius = 40);
}

}

spiral_extrude_examples();



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

Parkinbot
Seems to work. The only problem I found in my short testing was a purple part
at the top, in F12 view for

spiral_extrude(200,circlePoints, radius = 40, pitch = 100);

Ok, the interface is a bit funky. Usually one would expect the pitch
parameter to scale the thread form itself not just the space in-between.
Additionally one might want to find a parameter for choosing the number of
threads to be able to also design multi-start threads. I know this is
difficult to implement.

Have a look at my  threading lib <https://www.thingiverse.com/thing:1659079>
. It is a very lazy approach that uses a minimum amount of code as it builds
on a general sweep() and lets union() do the dirty work.





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

boxcarmib
Thanks for your input… I don’t know why I didn’t find your threading lib when I decided to write my module… I could have saved myself some time.
As for my implementation of pitch…here’s what happened. One of the things I use this library for is creating channels to hold LED light strips. So while the profile of the channel doesn’t change, the spacing between channels is usually more dynamic,  but when I use the module for threads, I’m dynamically calculating the tooth profile points for the required pitch and don’t want my module to adjust it.
And yes, I avoided more than one start just because the complexity of multi-threads was more intimidating that I was up for when I originally wrote the module.
Anyway, now that I know that your lib is already out there, my offering doesn’t offer any improvement so rather than posting it to thingiverse and muddying the waters I’ll hold back.
Thanks again for taking a look at it.
FYI… your thingiverse threading lib throws up three warnings with the current OpenSCAD release candidate:
WARNING: variable full not specified as parameter, in file Threading.scad, line 38
WARNING: len() parameter could not be converted, in file Naca_sweep.scad, line 115
WARNING: len() parameter could not be converted, in file Naca_sweep.scad, line 127


On Feb 27, 2019, at 6:32 AM, Parkinbot <[hidden email]> wrote:

Seems to work. The only problem I found in my short testing was a purple part
at the top, in F12 view for

spiral_extrude(200,circlePoints, radius = 40, pitch = 100);

Ok, the interface is a bit funky. Usually one would expect the pitch
parameter to scale the thread form itself not just the space in-between.
Additionally one might want to find a parameter for choosing the number of
threads to be able to also design multi-start threads. I know this is
difficult to implement.

Have a look at my  threading lib <https://www.thingiverse.com/thing:1659079>
. It is a very lazy approach that uses a minimum amount of code as it builds
on a general sweep() and lets union() do the dirty work.





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

boxcarmib
I just realized that implementing multi-starts is actually a pretty trivial task… I guess my intimidation by the concept clouded my thinking as all that’s really required is to duplicate my profile points for each start greater than 1 and adding an additional y offset to each point in the copied points. duh.


On Feb 27, 2019, at 10:11 AM, Hugo Jackson <[hidden email]> wrote:

Thanks for your input… I don’t know why I didn’t find your threading lib when I decided to write my module… I could have saved myself some time.
As for my implementation of pitch…here’s what happened. One of the things I use this library for is creating channels to hold LED light strips. So while the profile of the channel doesn’t change, the spacing between channels is usually more dynamic,  but when I use the module for threads, I’m dynamically calculating the tooth profile points for the required pitch and don’t want my module to adjust it.
And yes, I avoided more than one start just because the complexity of multi-threads was more intimidating that I was up for when I originally wrote the module.
Anyway, now that I know that your lib is already out there, my offering doesn’t offer any improvement so rather than posting it to thingiverse and muddying the waters I’ll hold back.
Thanks again for taking a look at it.
FYI… your thingiverse threading lib throws up three warnings with the current OpenSCAD release candidate:
WARNING: variable full not specified as parameter, in file Threading.scad, line 38
WARNING: len() parameter could not be converted, in file Naca_sweep.scad, line 115
WARNING: len() parameter could not be converted, in file Naca_sweep.scad, line 127


On Feb 27, 2019, at 6:32 AM, Parkinbot <[hidden email]> wrote:

Seems to work. The only problem I found in my short testing was a purple part
at the top, in F12 view for

spiral_extrude(200,circlePoints, radius = 40, pitch = 100);

Ok, the interface is a bit funky. Usually one would expect the pitch
parameter to scale the thread form itself not just the space in-between.
Additionally one might want to find a parameter for choosing the number of
threads to be able to also design multi-start threads. I know this is
difficult to implement.

Have a look at my  threading lib <https://www.thingiverse.com/thing:1659079>
. It is a very lazy approach that uses a minimum amount of code as it builds
on a general sweep() and lets union() do the dirty work.





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

Parkinbot
In reply to this post by boxcarmib
thanks, I know about the warnings. I'll revise the code as soon as the
release is out and I find time for it.  



--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

Parkinbot
In reply to this post by boxcarmib
I wouldn't call that what you do "muddying the water". It is a clean bottom
up approach. As far as I remember there are some more threading libs out
there and people will adopt what they like more.  
It is always good to have a choice.




--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

nophead
I wish len() would be reverted to accept scalars and return undef as it is documented to do in the wiki. I.e. scalars are valid input to len(). Not only does it break existing libraries but the solution is not backwards compatible and is longer and slower.

On Wed, 27 Feb 2019 at 19:32, Parkinbot <[hidden email]> wrote:
I wouldn't call that what you do "muddying the water". It is a clean bottom
up approach. As far as I remember there are some more threading libs out
there and people will adopt what they like more. 
It is always good to have a choice.




--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

RevarBat
Yes!  I've had to change to testing v[0]==undef and that doesn't work for empty vectors.

- Revar


On Feb 27, 2019, at 11:38 AM, nop head <[hidden email]> wrote:

I wish len() would be reverted to accept scalars and return undef as it is documented to do in the wiki. I.e. scalars are valid input to len(). Not only does it break existing libraries but the solution is not backwards compatible and is longer and slower.

On Wed, 27 Feb 2019 at 19:32, Parkinbot <[hidden email]> wrote:
I wouldn't call that what you do "muddying the water". It is a clean bottom
up approach. As far as I remember there are some more threading libs out
there and people will adopt what they like more. 
It is always good to have a choice.




--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: spiral_extrude() module

nophead
Yes I have: function Len(x) = is_list(x) ? len(x) : 0;

But why do I need it when it has always been a documented feature of len that it returns undef for scalars? That means len should accept scalar arguments without giving a warning.

On Wed, 27 Feb 2019 at 22:02, Revar Desmera <[hidden email]> wrote:
Yes!  I've had to change to testing v[0]==undef and that doesn't work for empty vectors.

- Revar


On Feb 27, 2019, at 11:38 AM, nop head <[hidden email]> wrote:

I wish len() would be reverted to accept scalars and return undef as it is documented to do in the wiki. I.e. scalars are valid input to len(). Not only does it break existing libraries but the solution is not backwards compatible and is longer and slower.

On Wed, 27 Feb 2019 at 19:32, Parkinbot <[hidden email]> wrote:
I wouldn't call that what you do "muddying the water". It is a clean bottom
up approach. As far as I remember there are some more threading libs out
there and people will adopt what they like more. 
It is always good to have a choice.




--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org