
12

I know that we can sweep a polygon around a circle like this, making a 3D object. :
rotate_extrude($fn=100) polygon(points = MyPts);
Recently, however, I wanted to construct a cover for a lathe that had curved sides, but when viewed faceon had an irregular shape. It's shaped like a triangle with curved corners. It would have been very nice to create a polygon for the side contour and then been able to sweep it around my custom shape.
Can OpenSCAD do this? If not, would it be a complex feature to add?
Thanks in advance, Kevin T
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Administrator

kdtop wrote
> ...
> Recently, however, I wanted to construct a cover for a lathe that had
> curved sides, but when viewed faceon had an irregular shape. It's shaped
> like a triangle with curved corners. It would have been very nice to
> create a polygon for the side contour and then been able to sweep it
> around
> my custom shape.
>
> Can OpenSCAD do this? If not, would it be a complex feature to add?
>
> Thanks in advance,
> Kevin T
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@.openscad
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.orgI'm not visualising it well, a picture is worth a thousand lines of code...
I suspect sweep() would be suited, *can someone point to the latest sweep()*
I'm out of date on the topic.

Admin  email* me if you need anything, or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me.
Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.
The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out!

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Admin  email* me if you need anything, or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me.
Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.
The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out!


Thanks for the replies.
Here is a picture that shows the shape with the side pieces spaced out.
To make my 3D shape, I simply put many many more of these side pieces together so that there were no gaps. The problem is that each side piece is a 3D object with a flat back and a given width. So the side walls ended up with jags. And it is ultimately an inefficient way of doing this. (a CGAL render takes 12 HOURS!) The sides really should be a 2D object that is then swept around a path defining the outer curves.
I don't think minkowski() would have any application in this situation. And a hull() would make a solid object, not concave like I want.
It appears that the sweep() is part of a library rather than an intrinsic function of OpenSCAD. Is this correct ? If so, then which is the best or recommended library to use?
I found these links. Questions: 1) In this ( https://github.com/openscad/listcomprehensiondemos/blob/master/sweeptest.scad) code example, I see the following at the top: use <sweep.scad> use <scadutils/transformations.scad> use <scadutils/shapes.scad> Is the \scadutils\ folder a standard thing with anOpenSCAD install? I.e. can I use this directly? I.e. is there a way in OpenSCAD to set up a search path for library folders? So far I have been putting a copy of any library used into the folder containing my current project. Thus I have many copies scattered across my various projects. I am on mac OSX. I went to the application folder, rightclicked on OpenSCAD, chose "show package content" and from there found a folder .\Content\Resources\libraries\MCAD. This contains many files that would seem to be helpful libraries. How is one supposed to use these? Copy them to a working folder? Figure out the long complex path and link to that directly?
2) I have been using this ( http://www.openscad.org/documentation.html) link as my source of documentation to learn OpenSCAD. If some of these other features, such as sweep() are official, should they be included there? If not official, should they be made official? And even is sweep() is not included with the distribution, is there documentation of the libraries that ARE included with the application?
Thanks in advance,
Kevin
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Kevin,
Sweep is not a builtin OpenScad operator neither it is included as a standard library. AFIK, there is two main sweep libraries around there: one was written by Oskar Linde and is part of the list comprehension demos you have found, the other was created by Parkinbot. Linde's sweep is a module that receives a planar 2D section and a sequence of affine transformations. The transformations are applied to each section to position them in the 3D space and the set of such sections is wraped in a OpenScad polyhedron. No boolean operation is used so the process is relatively fast. An utility function  paths_transforms  can be used to compute the sequence (list, array) of transformations from a sweep path. The affine transforms generated by that function are restricted to rigid body transforms. To help several tasks, Linde has written a bunch of general use libraries under the name scadutils that can be found at:
A copy of that set of libraries should be in an appropriate location in order to be found by <use> or <include>.
Parkinbot's sweep on the other hand expects as input a sequence of 3D planar polygons already positioned in the space and, as Linde's sweep does, wrap it in a polyhedron. No utility function is included in Parkinbot's sweep library to generate the 3D planar polygon. However, Parkinbot's approach is more general than Linde's one as it allows that each 3D planar polygon has it own shape provided that all polygons have the same number of vertices.
The contribution you have found in my Github repository is deeply based on Linde's approach and restricted to: commenting the code, cleaning some functions and adopting a different way to compute the path transforms that avoids some wild twist the original strategy may produce. That new computation is based on a Linde's proposal published in this forum that have never been included in the list comprehension demo repository. My codes also requires functions of scadutils.
None of those sweeps can be used blindly. The OpenScad render geometric engine  CGAL  will complaint if the resulting polyhedron has selfintersections. It is the user responsibility to avoid them.
Ronaldo Persiano Em sáb, 1 de dez de 2018 às 14:34, Kevin Toppenberg < [hidden email]> escreveu: Thanks for the replies.
Here is a picture that shows the shape with the side pieces spaced out.
To make my 3D shape, I simply put many many more of these side pieces together so that there were no gaps. The problem is that each side piece is a 3D object with a flat back and a given width. So the side walls ended up with jags. And it is ultimately an inefficient way of doing this. (a CGAL render takes 12 HOURS!) The sides really should be a 2D object that is then swept around a path defining the outer curves.
I don't think minkowski() would have any application in this situation. And a hull() would make a solid object, not concave like I want.
It appears that the sweep() is part of a library rather than an intrinsic function of OpenSCAD. Is this correct ? If so, then which is the best or recommended library to use?
I found these links. Questions: 1) In this ( https://github.com/openscad/listcomprehensiondemos/blob/master/sweeptest.scad) code example, I see the following at the top: use <sweep.scad> use <scadutils/transformations.scad> use <scadutils/shapes.scad> Is the \scadutils\ folder a standard thing with anOpenSCAD install? I.e. can I use this directly? I.e. is there a way in OpenSCAD to set up a search path for library folders? So far I have been putting a copy of any library used into the folder containing my current project. Thus I have many copies scattered across my various projects. I am on mac OSX. I went to the application folder, rightclicked on OpenSCAD, chose "show package content" and from there found a folder .\Content\Resources\libraries\MCAD. This contains many files that would seem to be helpful libraries. How is one supposed to use these? Copy them to a working folder? Figure out the long complex path and link to that directly?
2) I have been using this ( http://www.openscad.org/documentation.html) link as my source of documentation to learn OpenSCAD. If some of these other features, such as sweep() are official, should they be included there? If not official, should they be made official? And even is sweep() is not included with the distribution, is there documentation of the libraries that ARE included with the application?
Thanks in advance,
Kevin
_______________________________________________
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


this is not the fastest code, but it does what you se3m want
difference()
{
triag(10, 9);
triag(9, 10);
}
module triag(r = 10, h)
hull()
{
forN(50, 3) sphere(r);
forN(50, 3) cylinder(r=r, h=h);
}
module forN(r, n)
for(i=[0:n1]) rotate([0,0,360/n*i]) translate([r, 0, 0]) children();

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


Ronaldo,
Thank you for this helpful information. I will work on this and see if I can get it going.
Thanks again Kevin On Sat, Dec 1, 2018 at 12:21 PM Ronaldo Persiano < [hidden email]> wrote: Kevin,
Sweep is not a builtin OpenScad operator neither it is included as a standard library. AFIK, there is two main sweep libraries around there: one was written by Oskar Linde and is part of the list comprehension demos you have found, the other was created by Parkinbot. Linde's sweep is a module that receives a planar 2D section and a sequence of affine transformations. The transformations are applied to each section to position them in the 3D space and the set of such sections is wraped in a OpenScad polyhedron. No boolean operation is used so the process is relatively fast. An utility function  paths_transforms  can be used to compute the sequence (list, array) of transformations from a sweep path. The affine transforms generated by that function are restricted to rigid body transforms. To help several tasks, Linde has written a bunch of general use libraries under the name scadutils that can be found at:
A copy of that set of libraries should be in an appropriate location in order to be found by <use> or <include>.
Parkinbot's sweep on the other hand expects as input a sequence of 3D planar polygons already positioned in the space and, as Linde's sweep does, wrap it in a polyhedron. No utility function is included in Parkinbot's sweep library to generate the 3D planar polygon. However, Parkinbot's approach is more general than Linde's one as it allows that each 3D planar polygon has it own shape provided that all polygons have the same number of vertices.
The contribution you have found in my Github repository is deeply based on Linde's approach and restricted to: commenting the code, cleaning some functions and adopting a different way to compute the path transforms that avoids some wild twist the original strategy may produce. That new computation is based on a Linde's proposal published in this forum that have never been included in the list comprehension demo repository. My codes also requires functions of scadutils.
None of those sweeps can be used blindly. The OpenScad render geometric engine  CGAL  will complaint if the resulting polyhedron has selfintersections. It is the user responsibility to avoid them.
Ronaldo Persiano
Em sáb, 1 de dez de 2018 às 14:34, Kevin Toppenberg < [hidden email]> escreveu: Thanks for the replies.
Here is a picture that shows the shape with the side pieces spaced out.
To make my 3D shape, I simply put many many more of these side pieces together so that there were no gaps. The problem is that each side piece is a 3D object with a flat back and a given width. So the side walls ended up with jags. And it is ultimately an inefficient way of doing this. (a CGAL render takes 12 HOURS!) The sides really should be a 2D object that is then swept around a path defining the outer curves.
I don't think minkowski() would have any application in this situation. And a hull() would make a solid object, not concave like I want.
It appears that the sweep() is part of a library rather than an intrinsic function of OpenSCAD. Is this correct ? If so, then which is the best or recommended library to use?
I found these links. Questions: 1) In this ( https://github.com/openscad/listcomprehensiondemos/blob/master/sweeptest.scad) code example, I see the following at the top: use <sweep.scad> use <scadutils/transformations.scad> use <scadutils/shapes.scad> Is the \scadutils\ folder a standard thing with anOpenSCAD install? I.e. can I use this directly? I.e. is there a way in OpenSCAD to set up a search path for library folders? So far I have been putting a copy of any library used into the folder containing my current project. Thus I have many copies scattered across my various projects. I am on mac OSX. I went to the application folder, rightclicked on OpenSCAD, chose "show package content" and from there found a folder .\Content\Resources\libraries\MCAD. This contains many files that would seem to be helpful libraries. How is one supposed to use these? Copy them to a working folder? Figure out the long complex path and link to that directly?
2) I have been using this ( http://www.openscad.org/documentation.html) link as my source of documentation to learn OpenSCAD. If some of these other features, such as sweep() are official, should they be included there? If not official, should they be made official? And even is sweep() is not included with the distribution, is there documentation of the libraries that ARE included with the application?
Thanks in advance,
Kevin
_______________________________________________
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


And if want different radii, you can use minkowski over a hull of cylinders
or alternatively hull over three tori for the lower part.
< http://forum.openscad.org/file/t887/pool.png>
$fn = 50;
difference()
{
triag(r=30, rm=10, R=50, h=19);
triag(r=29, rm=8, R=50, h=30);
}
module triag(r = 10, R = 50, rm = 3, h)
{
hull()
{
minkowski()
{
hull()
forN(R, 3) cylinder(r=r, 1);
sphere(rm);
}
forN(50, 3) cylinder(r=r+rm, h=h);
}
}
module forN(r, n)
for(i=[0:n1]) rotate([0,0,360/n*i]) translate([r, 0, 0]) children();

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


Parkinbot,
You solved my problem without the need for sweep(). I hadn't thought about subtracting 2 hull()'s. While I still want to learn how to use the sweep library (for other situations), I like your solution. I had in my mind that hull() was a computationally expensive function. But your code finished a CGAL (F6) render in about 10 seconds. So clearly it is better than my prior method.
In my model, one of the sides bulged out, but I could solve that by putting some more posts in there before calling the hull().
Thanks again,
Kevin And if want different radii, you can use minkowski over a hull of cylinders
or alternatively hull over three tori for the lower part.
<http://forum.openscad.org/file/t887/pool.png>
$fn = 50;
difference()
{
triag(r=30, rm=10, R=50, h=19);
triag(r=29, rm=8, R=50, h=30);
}
module triag(r = 10, R = 50, rm = 3, h)
{
hull()
{
minkowski()
{
hull()
forN(R, 3) cylinder(r=r, 1);
sphere(rm);
}
forN(50, 3) cylinder(r=r+rm, h=h);
}
}
module forN(r, n)
for(i=[0:n1]) rotate([0,0,360/n*i]) translate([r, 0, 0]) children();

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


Your problem appears to be solved, but for what it's worth, I wrote a 'loft'
function a while ago that sweeps the interpolation between two
twodimensional profiles along a threedimensional path. It is very similar
to the other 'sweep' libraries mentioned (except mine is poorly documented
and the code probably unreadable, sorry ;)). The transformations along the
path are computed using quaternions and the usual restrictions apply
(profiles have to be singlyconnected and have the same number of points in
them, no selfintersections).
Maybe it is useful to somebody...
Marko
function flatten(vec) = [for (v=vec) for(e=v) e];
function Q_im(q) = [q[1], q[2], q[3]];
function Q_conj(q) = [q[0], q[1], q[2], q[3]];
function Q_mult(q,p) =
[(q[0]*p[0]q[1]*p[1]q[2]*p[2]q[3]*p[3]),(q[1]*p[0]+q[0]*p[1]+q[2]*p[3]q[3]*p[2]),(q[2]*p[0]+q[0]*p[2]q[1]*p[3]+q[3]*p[1]),(q[3]*p[0]+q[0]*p[3]+q[1]*p[2]q[2]*p[1])];
function rotQ(q, a, n) = Q_mult(flatten([cos(a/2),n*sin(a/2)]),q);
function poly_rotQ(list, q) = [for (v=list)
Q_im(Q_mult(q,Q_mult([0,v.x,v.y,v.z],Q_conj(q))))];
function poly_rot2d(list, a) = [for (x=list) [cos(a)*x[0]+sin(a)*x[1],
sin(a)*x[0]+cos(a)*x[1]]];
function poly_translate(list, d) = [for (v=list) v+d];
function interp_lists(l1, w1, l2, w2) = [for (i=[0:len(l1)1])
w1*l1[i]+w2*l2[i]];
function poly_loft_faces (N_z, N_x, closed=false) = flatten([
(closed ? ([for (i=[0:N_x1]) [(N_z1)*N_x+i, (N_z1)*N_x+(i+1)%N_x,
i],
for (i=[0:N_x1]) [(i+1)%N_x, i, (N_z1)*N_x+(i+1)%N_x]])
: concat([[for (i=[0:N_x1]) N_x1i]], [[for (i=[0:N_x1])
(N_z1)*N_x+i]])), // caps
for (i=[0:N_z2],j=[0:N_x1]) [[(i+1)*N_x+j, i*N_x+j,
i*N_x+((j+1)%N_x)],[i*N_x+((j+1)%N_x), (i+1)*N_x+((j+1)%N_x),
(i+1)*N_x+j]]]);
// extrude a cross section linearly interpolated between cross sections cr1
and cr2 along path 'path',
// with optional tangential twist linearly increasing along path
module loft (path, cr1, cr2, twist=0) {
p = flatten([path, [2*path[len(path)1]path[len(path)2]]]);
pts = flatten([
for (i=1, d=p[1]p[0], u=cross([0,0,1], d), un=norm(u), dn=norm(d),
a=asin(un/dn),
q=un>0?rotQ([1,0,0,0],a,u/un) : [1,0,0,0], n=d/dn, cr=cr1;
i<len(p);
d=p[i]path[i1], u=cross(n, d), un=norm(u), dn=norm(d),
a=asin(un/dn),
n=d/dn,q=un>0?rotQ(q,a,u/un):q,
cr=interp_lists(cr1,1(i1)/(len(p)1),cr2,(i1)/(len(p)1)), i=i+1)
poly_translate(poly_rotQ(twist!=0?[for(v=poly_rot2d([for (v=cr)
[v.x,v.y,0]],i*twist/(len(p)1))) [v.x,v.y,0]]:[for (v=cr) [v.x,v.y,0]], q),
p[i1])
]);
fcs = poly_loft_faces(len(path), len(cr1));
polyhedron(pts, fcs, convexity=8);
}
pH = [[1, 1], [0.8,1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1, 1],
[1, 1], [0.8, 1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1, 1]];
pH2 = [for (v=pH) 2*v];
phelix = [for (i=[0:6:3*360]) 5*[cos(i), sin(i), i/360]];
loft(phelix, pH, pH2, 170);

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


Marko,
A few years ago I was studying up on 3D engines and learned about quats, but haven't thought about them since. I seem to recall they are a method of achieving a transformation and avoids gimblelock that can occur with standard XYZ transformation matrices. Is there built in functionality for quats or did you write a library for yourself?
Thanks for the code. I will keep this as a reference.
Kevin
Your problem appears to be solved, but for what it's worth, I wrote a 'loft'
function a while ago that sweeps the interpolation between two
twodimensional profiles along a threedimensional path. It is very similar
to the other 'sweep' libraries mentioned (except mine is poorly documented
and the code probably unreadable, sorry ;)). The transformations along the
path are computed using quaternions and the usual restrictions apply
(profiles have to be singlyconnected and have the same number of points in
them, no selfintersections).
Maybe it is useful to somebody...
Marko
function flatten(vec) = [for (v=vec) for(e=v) e];
function Q_im(q) = [q[1], q[2], q[3]];
function Q_conj(q) = [q[0], q[1], q[2], q[3]];
function Q_mult(q,p) =
[(q[0]*p[0]q[1]*p[1]q[2]*p[2]q[3]*p[3]),(q[1]*p[0]+q[0]*p[1]+q[2]*p[3]q[3]*p[2]),(q[2]*p[0]+q[0]*p[2]q[1]*p[3]+q[3]*p[1]),(q[3]*p[0]+q[0]*p[3]+q[1]*p[2]q[2]*p[1])];
function rotQ(q, a, n) = Q_mult(flatten([cos(a/2),n*sin(a/2)]),q);
function poly_rotQ(list, q) = [for (v=list)
Q_im(Q_mult(q,Q_mult([0,v.x,v.y,v.z],Q_conj(q))))];
function poly_rot2d(list, a) = [for (x=list) [cos(a)*x[0]+sin(a)*x[1],
sin(a)*x[0]+cos(a)*x[1]]];
function poly_translate(list, d) = [for (v=list) v+d];
function interp_lists(l1, w1, l2, w2) = [for (i=[0:len(l1)1])
w1*l1[i]+w2*l2[i]];
function poly_loft_faces (N_z, N_x, closed=false) = flatten([
(closed ? ([for (i=[0:N_x1]) [(N_z1)*N_x+i, (N_z1)*N_x+(i+1)%N_x,
i],
for (i=[0:N_x1]) [(i+1)%N_x, i, (N_z1)*N_x+(i+1)%N_x]])
: concat([[for (i=[0:N_x1]) N_x1i]], [[for (i=[0:N_x1])
(N_z1)*N_x+i]])), // caps
for (i=[0:N_z2],j=[0:N_x1]) [[(i+1)*N_x+j, i*N_x+j,
i*N_x+((j+1)%N_x)],[i*N_x+((j+1)%N_x), (i+1)*N_x+((j+1)%N_x),
(i+1)*N_x+j]]]);
// extrude a cross section linearly interpolated between cross sections cr1
and cr2 along path 'path',
// with optional tangential twist linearly increasing along path
module loft (path, cr1, cr2, twist=0) {
p = flatten([path, [2*path[len(path)1]path[len(path)2]]]);
pts = flatten([
for (i=1, d=p[1]p[0], u=cross([0,0,1], d), un=norm(u), dn=norm(d),
a=asin(un/dn),
q=un>0?rotQ([1,0,0,0],a,u/un) : [1,0,0,0], n=d/dn, cr=cr1;
i<len(p);
d=p[i]path[i1], u=cross(n, d), un=norm(u), dn=norm(d),
a=asin(un/dn),
n=d/dn,q=un>0?rotQ(q,a,u/un):q,
cr=interp_lists(cr1,1(i1)/(len(p)1),cr2,(i1)/(len(p)1)), i=i+1)
poly_translate(poly_rotQ(twist!=0?[for(v=poly_rot2d([for (v=cr)
[v.x,v.y,0]],i*twist/(len(p)1))) [v.x,v.y,0]]:[for (v=cr) [v.x,v.y,0]], q),
p[i1])
]);
fcs = poly_loft_faces(len(path), len(cr1));
polyhedron(pts, fcs, convexity=8);
}
pH = [[1, 1], [0.8,1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1, 1],
[1, 1], [0.8, 1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1, 1]];
pH2 = [for (v=pH) 2*v];
phelix = [for (i=[0:6:3*360]) 5*[cos(i), sin(i), i/360]];
loft(phelix, pH, pH2, 170);

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


Marko,
So I understand how one can translate the vertices of a polygon in 3D space. But I am confused about how to make it into a 3D object. Take for example a square that is going to be swept through space to make a square tube. How does one figure out how to arrange the points in the resulting faces?
In the example, as the square is swept from P_init to P_final, there should a face using points 1, 1b, 3, 3b. And another using 1b, 1c, 3b, 3c. That should be OK to figure out. But doesn't the ordering of the vertices have to be in a counterclockwise rotation so that the normal faces outward, and thus has the proper orientation? Using all those points to build a polygon seem daunting.
Kevin T
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Kevin,
To answer your second question first: you are correct, the ordering of the
polygon points has to conform to the OpenSCAD convention. I should have
mentioned that my function assumes that the points describing the cross
sections (second and third argument to the 'loft()' call) have to be
correctly ordered for the resulting autogenerated triangles to be oriented
correctly. This is less tricky than it sounds, though  if the order is
wrong (can be seen by rendering in 'Thrown together' mode, for example) the
order simply has to be reversed. This is a manual step, the loft function
will gladly produce an invalid polyhedron.
Also, figuring out the triangulation of the swept walls is actually fairly
straightforward (assuming adjacent polygons are pretty similar), pretty much
exactly what you described in your illustration.
As for your first question: the routine first adds a zcoordinate of 0 to
each 2D polygon point (essentially turning it into a flat polygon in the
xyplane);
it then figures out the appropriate rotation of this 3D polygon to orient
its normal axis along a tangent to the path (well, really the direction
between two adjacent, discrete path points) and applies it (step wise along
the path, so that the twist along the path does not develop discontinuities)
 that's the part that uses quaternions, but could equally well be done with
R3 rotation matrices;
finally, each rotated polygon is translated to its appropriate position
along the path.
The rest then is really the answer to your first question, i.e. figuring out
a triangulation for the resulting point cloud.
Hope this helps,
Marko

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


It does help. Thanks Marko
Kevin Kevin,
To answer your second question first: you are correct, the ordering of the
polygon points has to conform to the OpenSCAD convention. I should have
mentioned that my function assumes that the points describing the cross
sections (second and third argument to the 'loft()' call) have to be
correctly ordered for the resulting autogenerated triangles to be oriented
correctly. This is less tricky than it sounds, though  if the order is
wrong (can be seen by rendering in 'Thrown together' mode, for example) the
order simply has to be reversed. This is a manual step, the loft function
will gladly produce an invalid polyhedron.
Also, figuring out the triangulation of the swept walls is actually fairly
straightforward (assuming adjacent polygons are pretty similar), pretty much
exactly what you described in your illustration.
As for your first question: the routine first adds a zcoordinate of 0 to
each 2D polygon point (essentially turning it into a flat polygon in the
xyplane);
it then figures out the appropriate rotation of this 3D polygon to orient
its normal axis along a tangent to the path (well, really the direction
between two adjacent, discrete path points) and applies it (step wise along
the path, so that the twist along the path does not develop discontinuities)
 that's the part that uses quaternions, but could equally well be done with
R3 rotation matrices;
finally, each rotated polygon is translated to its appropriate position
along the path.
The rest then is really the answer to your first question, i.e. figuring out
a triangulation for the resulting point cloud.
Hope this helps,
Marko

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


wow Marko, this is one of the coolest code I saw in a while !! Thx for
sharing.
btw the name "loft" seems a bit misleading. To my knowledge, "loft" means
(1)sweeping + (2)change of shape (like from square to circle): See :
https://www.cati.com/blog/2012/11/tipsandtricksforusingthesolidworksloftfeature/berkenb wrote
> Your problem appears to be solved, but for what it's worth, I wrote a
> 'loft'
> function a while ago that sweeps the interpolation between two
> twodimensional profiles along a threedimensional path. It is very
> similar
> to the other 'sweep' libraries mentioned (except mine is poorly documented
> and the code probably unreadable, sorry ;)). The transformations along
> the
> path are computed using quaternions and the usual restrictions apply
> (profiles have to be singlyconnected and have the same number of points
> in
> them, no selfintersections).
> Maybe it is useful to somebody...
> Marko
>
> function flatten(vec) = [for (v=vec) for(e=v) e];
> function Q_im(q) = [q[1], q[2], q[3]];
> function Q_conj(q) = [q[0], q[1], q[2], q[3]];
> function Q_mult(q,p) =
> [(q[0]*p[0]q[1]*p[1]q[2]*p[2]q[3]*p[3]),(q[1]*p[0]+q[0]*p[1]+q[2]*p[3]q[3]*p[2]),(q[2]*p[0]+q[0]*p[2]q[1]*p[3]+q[3]*p[1]),(q[3]*p[0]+q[0]*p[3]+q[1]*p[2]q[2]*p[1])];
> function rotQ(q, a, n) = Q_mult(flatten([cos(a/2),n*sin(a/2)]),q);
> function poly_rotQ(list, q) = [for (v=list)
> Q_im(Q_mult(q,Q_mult([0,v.x,v.y,v.z],Q_conj(q))))];
> function poly_rot2d(list, a) = [for (x=list) [cos(a)*x[0]+sin(a)*x[1],
> sin(a)*x[0]+cos(a)*x[1]]];
> function poly_translate(list, d) = [for (v=list) v+d];
> function interp_lists(l1, w1, l2, w2) = [for (i=[0:len(l1)1])
> w1*l1[i]+w2*l2[i]];
>
>
> function poly_loft_faces (N_z, N_x, closed=false) = flatten([
> (closed ? ([for (i=[0:N_x1]) [(N_z1)*N_x+i, (N_z1)*N_x+(i+1)%N_x,
> i],
> for (i=[0:N_x1]) [(i+1)%N_x, i, (N_z1)*N_x+(i+1)%N_x]])
> : concat([[for (i=[0:N_x1]) N_x1i]], [[for (i=[0:N_x1])
> (N_z1)*N_x+i]])), // caps
> for (i=[0:N_z2],j=[0:N_x1]) [[(i+1)*N_x+j, i*N_x+j,
> i*N_x+((j+1)%N_x)],[i*N_x+((j+1)%N_x), (i+1)*N_x+((j+1)%N_x),
> (i+1)*N_x+j]]]);
>
>
> // extrude a cross section linearly interpolated between cross sections
> cr1
> and cr2 along path 'path',
> // with optional tangential twist linearly increasing along path
> module loft (path, cr1, cr2, twist=0) {
> p = flatten([path, [2*path[len(path)1]path[len(path)2]]]);
> pts = flatten([
> for (i=1, d=p[1]p[0], u=cross([0,0,1], d), un=norm(u), dn=norm(d),
> a=asin(un/dn),
> q=un>0?rotQ([1,0,0,0],a,u/un) : [1,0,0,0], n=d/dn, cr=cr1;
> i<len(p);
> d=p[i]path[i1], u=cross(n, d), un=norm(u), dn=norm(d),
> a=asin(un/dn),
> n=d/dn,q=un>0?rotQ(q,a,u/un):q,
> cr=interp_lists(cr1,1(i1)/(len(p)1),cr2,(i1)/(len(p)1)), i=i+1)
> poly_translate(poly_rotQ(twist!=0?[for(v=poly_rot2d([for (v=cr)
> [v.x,v.y,0]],i*twist/(len(p)1))) [v.x,v.y,0]]:[for (v=cr) [v.x,v.y,0]],
> q),
> p[i1])
> ]);
> fcs = poly_loft_faces(len(path), len(cr1));
> polyhedron(pts, fcs, convexity=8);
> }
>
> pH = [[1, 1], [0.8,1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1, 1],
> [1, 1], [0.8, 1], [0.8, 0.1], [0.8, 0.1], [0.8, 1], [1,
> 1]];
> pH2 = [for (v=pH) 2*v];
> phelix = [for (i=[0:6:3*360]) 5*[cos(i), sin(i), i/360]];
>
> loft(phelix, pH, pH2, 170);
>
>
>
> 
> Sent from: http://forum.openscad.org/>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@.openscad
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
$ Runsun Pan, PhD $ libs: scadx , doctest , faces ( git ), offline doc ( git ), runscad.py ( 2 , git ), editor of choice: CudaText ( OpenSCAD lexer ); $ Tips ; $ Snippets

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


Hi runsun,
Thanks. The code posted does actually linearly interpolate between two
shapes as it sweeps along the path; the 'loft' call requires a path and two
cross sections. My example is a little weak, as it uses the first profile
scaled by a factor of 2 as the second profile, i.e. the effect isn't
terribly obvious...
Try this example (with the same loft function):
pts = 24;
l = 2;
psquare = [for (i=[0:pts/41]) [l/2, l/2i/pts*4*l],
for (i=[pts/4:pts/21]) [l/2+(ipts/4)/pts*4*l, l/2],
for (i=[pts/2:3*pts/41]) [l/2, l/2+(ipts/2)/pts*4*l],
for (i=[3*pts/4:pts1]) [l/2(i3*pts/4)/pts*4*l, l/2]
];
pcircle = [for (i=[0:pts1]) [sin(i*360/pts), cos(i*360/pts)]];
phelix = [for (i=[0:6:3*360]) 5*[cos(i), sin(i), i/360]];
loft(phelix, pcircle, psquare);
There are probably still a few bugs in the implementation, I haven't used it
too much yet.
Marko

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


Marko,
I am getting a syntax error on OpenSCAD version 2015.032
I can't figure out what the problem is. I tried reformatting the code so I could understand it better. But even before reformatting, it still has the same error.
Any suggestions? Thanks Kevin
Hi runsun,
Thanks. The code posted does actually linearly interpolate between two
shapes as it sweeps along the path; the 'loft' call requires a path and two
cross sections. My example is a little weak, as it uses the first profile
scaled by a factor of 2 as the second profile, i.e. the effect isn't
terribly obvious...
Try this example (with the same loft function):
pts = 24;
l = 2;
psquare = [for (i=[0:pts/41]) [l/2, l/2i/pts*4*l],
for (i=[pts/4:pts/21]) [l/2+(ipts/4)/pts*4*l, l/2],
for (i=[pts/2:3*pts/41]) [l/2, l/2+(ipts/2)/pts*4*l],
for (i=[3*pts/4:pts1]) [l/2(i3*pts/4)/pts*4*l, l/2]
];
pcircle = [for (i=[0:pts1]) [sin(i*360/pts), cos(i*360/pts)]];
phelix = [for (i=[0:6:3*360]) 5*[cos(i), sin(i), i/360]];
loft(phelix, pcircle, psquare);
There are probably still a few bugs in the implementation, I haven't used it
too much yet.
Marko

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

12
