more sweep() issues

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

more sweep() issues

jon_bondy

I want to make horns similar to those shown in the first screen capture, below.

I started out with sweep() but could not see how to incorporate scaling into that approach.  I hacked the sweep.scad module so that the global shape() function was called inside sweep() (rather than passing the output of shape() into sweep() as a parameter), so that I could return shapes which scaled during the sweep.

That approach (although ugly/hacky) worked to some extent.  But since what I really wanted was a hollow horn, things fell apart when I tried to create two horns with different scales, so that I could subtract the inner from the outer.  With only one global shape() function available, the only way I could see to make this work was to duplicate the sweep() code so that I could use two global shape() functions.  I felt as if I was heading towards hacking hell.  Simple use of scale() failed because I need the path to remain unscaled while the object that is being swept is scaled.

I tried to use Ronaldo's sweep-with-easing approach (although I never understood what "easing" was).  The result is unacceptable because the shapes used are always horizontal: they do not rotate to stay orthogonal to the path.  Perhaps this is due to errors in my approach (code is below).

In addition, I was unable to get the horn shapes to have caps on the ends.

I gave up on hollow horns, and made them solid, figuring that I would be able to hollow them out with MeshMixer (annoying, but acceptable).  But the STLs created were so damaged that neither MeshMixer nor NetFabb were able to repair them.

I feel as if I am flailing about randomly.  Perhaps one of you can point me in a more productive direction.

Thanks!

Jon


use <sweep.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

sweep(circle_points, my_path);

my_path = [ for (i=[0:steps])
    translation([18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)]) *
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) *
    rotation([0,0, steps]) ];




-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

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

Re: more sweep() issues

Parkinbot
Jon,

let me remark some things before giving you advice.
1. your code produces self-intersection. Check this with F12. It will never
pass CGAL
<http://forum.openscad.org/file/t887/jon1.png>
2. I have noticed that current dev snapshots have a bug concerning the use
of rotated polygons as start/end shapes of sweeps. Unavoidable non-planarity
leads to CGAL-errors. https://github.com/openscad/openscad/issues/2246
3. some years ago I have played with the version of sweep you are currently
using, but felt finally that its implicit restriction to using a certain
basic shape is too restrictive for my purposes. Therefore I developed my own
version, which you should know. It expects a vector of polygons placed in 3D
and skins it, just like skin().
4. here a simple animation showing a bulb walking through a pipe.
Uncommenting the first call showes, how the polygons are constructed and
placed in 3D space. Uncommenting the second call and enabling animation
(e.g. 10/100) shows the animation of a bubble wandering through a pipe.

use <Naca_sweep.scad> // https://www.thingiverse.com/thing:900137
w = 40;

// sweep(trajectory(10), showslices = true); // view polygons as slices
// w = $t*90-10; animated();

module animated()
{
  difference()
  {
    sweep(trajectory(10));
    sweep(trajectory(9, 14));
  }
}

function trajectory(r0 = 10, r1=15, N = 20) =  [for(i=[0:N-1])
   let(angle = 90/N*i)
   let(r = max(r0, bulb(r1, 1.9, w-angle)))
   Ry_(angle, Tx_(100, vec3D(circle(r))))];

function circle(r, N=20) = [for(i=[0:N-1]) r*[sin(360/N*i), cos(360/N*i)]];
function bulb(r, scale=1, x) =  abs(x)<r?scale*sqrt(r*r-x*x):0;




--
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: more sweep() issues

Ronaldo
In reply to this post by jon_bondy
If understood correctly your code, your variable my_path is a prebuilt transform path for sweep that does not include the necessary rotations of the sections to make them orthogonal to the path. That is why the sections are all parallel to plane xy after sweep.

In the following code, I separate the path from the shape transform sequence you want to apply at each path point. And I define a function path_shape_transforms(), based on construct_transform_path(), that takes in account a shape transform sequence besides the path itself. 

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

path = [ for (i=[0:steps]) [18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)] ];
  
shtransf = [ for (i=[0:steps])  
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) * 
    rotation([0,0, steps]) ];

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

ptrans = path_shape_transforms(path, shtransf);

sweep(circle_points, ptrans);

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( l = len(path),
        tangents = tangts==undef ? tangent_path(path, closed) : tangts,
        local_rotations = minimizing_rotations(concat([[0,0,1]], tangents)),
        rotations = accumulate_rotations(local_rotations),
        twist = closed ? calculate_twist(rotations[0], rotations[l-1]) : 0 ,
        rt = [ for (i = [0:l-1]) construct_rt(rotations[i], path[i]) * rotation( [0, 0, twist*i/(l-1)] ) ] )
    [for (i = [0:l-1]) rt[i]*shape_transf[i] ];

function square(l) =
  [ [-l/2,-l/2], [-l/2,l/2], [l/2,l/2], [l/2,-l/2] ];

function circle(r) =
  [for(i=[0:$fn-1]) [cos(360*i/$fn),sin(360*i/$fn)] ];




2018-01-05 15:21 GMT-02:00 jon <[hidden email]>:

I want to make horns similar to those shown in the first screen capture, below.

I started out with sweep() but could not see how to incorporate scaling into that approach.  I hacked the sweep.scad module so that the global shape() function was called inside sweep() (rather than passing the output of shape() into sweep() as a parameter), so that I could return shapes which scaled during the sweep.

That approach (although ugly/hacky) worked to some extent.  But since what I really wanted was a hollow horn, things fell apart when I tried to create two horns with different scales, so that I could subtract the inner from the outer.  With only one global shape() function available, the only way I could see to make this work was to duplicate the sweep() code so that I could use two global shape() functions.  I felt as if I was heading towards hacking hell.  Simple use of scale() failed because I need the path to remain unscaled while the object that is being swept is scaled.

I tried to use Ronaldo's sweep-with-easing approach (although I never understood what "easing" was).  The result is unacceptable because the shapes used are always horizontal: they do not rotate to stay orthogonal to the path.  Perhaps this is due to errors in my approach (code is below).

In addition, I was unable to get the horn shapes to have caps on the ends.

I gave up on hollow horns, and made them solid, figuring that I would be able to hollow them out with MeshMixer (annoying, but acceptable).  But the STLs created were so damaged that neither MeshMixer nor NetFabb were able to repair them.

I feel as if I am flailing about randomly.  Perhaps one of you can point me in a more productive direction.

Thanks!

Jon


use <sweep.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

sweep(circle_points, my_path);

my_path = [ for (i=[0:steps])
    translation([18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)]) *
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) *
    rotation([0,0, steps]) ];




-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

_______________________________________________
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: more sweep() issues

jon_bondy
In reply to this post by Parkinbot
Parkinbot:

Thanks so much for your time!  I was able to get a solid object out of
this, but when I changed the path to be the one that I am working on,
the top flattened again.  I imagine that I need to rotate the slices
better.  Your example had a fairly simple rotation, one that was easy to
specify.  I guess I need to write code to take two points along the path
and compute the rotations necessary to get the disks oriented properly.

Jon



On 1/5/2018 2:08 PM, Parkinbot wrote:

> Jon,
>
> let me remark some things before giving you advice.
> 1. your code produces self-intersection. Check this with F12. It will never
> pass CGAL
> <http://forum.openscad.org/file/t887/jon1.png>
> 2. I have noticed that current dev snapshots have a bug concerning the use
> of rotated polygons as start/end shapes of sweeps. Unavoidable non-planarity
> leads to CGAL-errors. https://github.com/openscad/openscad/issues/2246
> 3. some years ago I have played with the version of sweep you are currently
> using, but felt finally that its implicit restriction to using a certain
> basic shape is too restrictive for my purposes. Therefore I developed my own
> version, which you should know. It expects a vector of polygons placed in 3D
> and skins it, just like skin().
> 4. here a simple animation showing a bulb walking through a pipe.
> Uncommenting the first call showes, how the polygons are constructed and
> placed in 3D space. Uncommenting the second call and enabling animation
> (e.g. 10/100) shows the animation of a bubble wandering through a pipe.
>
> use <Naca_sweep.scad> // https://www.thingiverse.com/thing:900137
> w = 40;
>
> // sweep(trajectory(10), showslices = true); // view polygons as slices
> // w = $t*90-10; animated();
>
> module animated()
> {
>    difference()
>    {
>      sweep(trajectory(10));
>      sweep(trajectory(9, 14));
>    }
> }
>
> function trajectory(r0 = 10, r1=15, N = 20) =  [for(i=[0:N-1])
>     let(angle = 90/N*i)
>     let(r = max(r0, bulb(r1, 1.9, w-angle)))
>     Ry_(angle, Tx_(100, vec3D(circle(r))))];
>
> function circle(r, N=20) = [for(i=[0:N-1]) r*[sin(360/N*i), cos(360/N*i)]];
> function bulb(r, scale=1, x) =  abs(x)<r?scale*sqrt(r*r-x*x):0;
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
>

--
Sent from my desktop computer.
I do not receive emails while away from my desk,
nor do I receive texts on my main phone number
(which is a land line).
If you know that I am on the road, please text me.
If you know that I am home, please email me.


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

Re: more sweep() issues

jon_bondy
In reply to this post by Ronaldo

Ronaldo:

Thank you for your time!  I was able to get "my" shape fairly easily with your approach, and I could even create two objects (one inside the other) to make progress toward a hollow shape (that is not just a single surface).  Unfortunately, I do not see how to get the ends to close up.  I'm not sure that this is necessary if I plunge the two ends into a solid (like a cube).  However, when I just union() the horn surface (not solid object but surface) with a sphere, the resulting horn is problematic and cannot be repaired.

Very interesting to see the different ways that each of you think about these problems.

Jon


On 1/5/2018 2:22 PM, Ronaldo Persiano wrote:
If understood correctly your code, your variable my_path is a prebuilt transform path for sweep that does not include the necessary rotations of the sections to make them orthogonal to the path. That is why the sections are all parallel to plane xy after sweep.

In the following code, I separate the path from the shape transform sequence you want to apply at each path point. And I define a function path_shape_transforms(), based on construct_transform_path(), that takes in account a shape transform sequence besides the path itself. 

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

path = [ for (i=[0:steps]) [18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)] ];
  
shtransf = [ for (i=[0:steps])  
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) * 
    rotation([0,0, steps]) ];

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

ptrans = path_shape_transforms(path, shtransf);

sweep(circle_points, ptrans);

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( l = len(path),
        tangents = tangts==undef ? tangent_path(path, closed) : tangts,
        local_rotations = minimizing_rotations(concat([[0,0,1]], tangents)),
        rotations = accumulate_rotations(local_rotations),
        twist = closed ? calculate_twist(rotations[0], rotations[l-1]) : 0 ,
        rt = [ for (i = [0:l-1]) construct_rt(rotations[i], path[i]) * rotation( [0, 0, twist*i/(l-1)] ) ] )
    [for (i = [0:l-1]) rt[i]*shape_transf[i] ];

function square(l) =
  [ [-l/2,-l/2], [-l/2,l/2], [l/2,l/2], [l/2,-l/2] ];

function circle(r) =
  [for(i=[0:$fn-1]) [cos(360*i/$fn),sin(360*i/$fn)] ];




2018-01-05 15:21 GMT-02:00 jon <[hidden email]>:

I want to make horns similar to those shown in the first screen capture, below.

I started out with sweep() but could not see how to incorporate scaling into that approach.  I hacked the sweep.scad module so that the global shape() function was called inside sweep() (rather than passing the output of shape() into sweep() as a parameter), so that I could return shapes which scaled during the sweep.

That approach (although ugly/hacky) worked to some extent.  But since what I really wanted was a hollow horn, things fell apart when I tried to create two horns with different scales, so that I could subtract the inner from the outer.  With only one global shape() function available, the only way I could see to make this work was to duplicate the sweep() code so that I could use two global shape() functions.  I felt as if I was heading towards hacking hell.  Simple use of scale() failed because I need the path to remain unscaled while the object that is being swept is scaled.

I tried to use Ronaldo's sweep-with-easing approach (although I never understood what "easing" was).  The result is unacceptable because the shapes used are always horizontal: they do not rotate to stay orthogonal to the path.  Perhaps this is due to errors in my approach (code is below).

In addition, I was unable to get the horn shapes to have caps on the ends.

I gave up on hollow horns, and made them solid, figuring that I would be able to hollow them out with MeshMixer (annoying, but acceptable).  But the STLs created were so damaged that neither MeshMixer nor NetFabb were able to repair them.

I feel as if I am flailing about randomly.  Perhaps one of you can point me in a more productive direction.

Thanks!

Jon


use <sweep.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

sweep(circle_points, my_path);

my_path = [ for (i=[0:steps])
    translation([18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)]) *
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) *
    rotation([0,0, steps]) ];




-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

_______________________________________________
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

-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

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

Re: more sweep() issues

Parkinbot
In reply to this post by jon_bondy
Jon,
of course you have adopt the example to your needs. To get more rotations
you can use

R_(anglex, anglez, anglez, Tx_(100, vec3D(circle(r))))];

or use single rotations in a specific order while R_() has a fixed order
like rotation().

Ry_(angley, Rz_(anglez, Rx_(anglex, Tx_(100, vec3D(circle(r))))))];

Obviously you can specify anglex, anglez, anglez as functions of the
iteration variable to make them do what you want. Following this pattern you
can stack any affine operations (rotations, translations and scales) the way
you want to model your extrusion path. The innermost operation is executed
first then the next one, and so on.  



--
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: more sweep() issues

Ronaldo
In reply to this post by Ronaldo
First of all, the path_shape_transforms() I defined before may be simpler defined by:

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( rt = construct_transform_path(path, closed=false, tangts) )
    [for (i = [0:len(rt)-1]) rt[i]*shape_transf[i] ];

Now I want to discuss your question on how to deal with a hollow sweep. My approach to that is the following:
a) build a skin for the outer surface without cap in a suitable form;
b) build a skin for the inner surface without cap in the same form;
c) build a skin (a polygon) connecting one end of the first skin with one end of the other skin;
d) do the same with the other end;
e) aggregate those four skins in one polyhedron call.

The suitable form I use for all skins is a polyhedron data format: a pair of a point list and a facet list. The first two skins are built by sweep_polyhedron() (a function you find in my fork code) without caps. The last two skins may also be built by sweep_polyhedron() applying a round if necessary but it may be just a annular surface connecting two sections.The last process, I called the aggregate, is a very general module that receives a list of polyhedron data, process them and make a call to the polyhedron primitive.

module buildPolyhedron(polys, convexity = 10) {
    function _accum_sum(l, offs=0, res=[]) =
        len(res) == len(l) ?
            res :
            _accum_sum(l, offs+l[len(res)], concat(res, [ offs+l[len(res)] ] ));

    function acc_len( f ) = 
        concat([0], _accum_sum([ for(fi=f) len(fi) ]));

    vertlist = [for(p=polys, pt=p[0]) pt]; // collect all verts from polyhedra
    vertlen  = [for(p=polys) p[0] ];
    acclen   = acc_len(vertlen);
    facets   = [ for(i=[0:len(polys)-1], f=polys[i][1] ) [ for(v=f) acclen[i]+v ] ];
echo(acclen);
    polyhedron(
        points = vertlist,
        faces  = facets,
        convexity = convexity
    );
}




2018-01-05 17:22 GMT-02:00 Ronaldo Persiano <[hidden email]>:
If understood correctly your code, your variable my_path is a prebuilt transform path for sweep that does not include the necessary rotations of the sections to make them orthogonal to the path. That is why the sections are all parallel to plane xy after sweep.

In the following code, I separate the path from the shape transform sequence you want to apply at each path point. And I define a function path_shape_transforms(), based on construct_transform_path(), that takes in account a shape transform sequence besides the path itself. 

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

path = [ for (i=[0:steps]) [18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)] ];
  
shtransf = [ for (i=[0:steps])  
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) * 
    rotation([0,0, steps]) ];

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

ptrans = path_shape_transforms(path, shtransf);

sweep(circle_points, ptrans);

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( l = len(path),
        tangents = tangts==undef ? tangent_path(path, closed) : tangts,
        local_rotations = minimizing_rotations(concat([[0,0,1]], tangents)),
        rotations = accumulate_rotations(local_rotations),
        twist = closed ? calculate_twist(rotations[0], rotations[l-1]) : 0 ,
        rt = [ for (i = [0:l-1]) construct_rt(rotations[i], path[i]) * rotation( [0, 0, twist*i/(l-1)] ) ] )
    [for (i = [0:l-1]) rt[i]*shape_transf[i] ];

function square(l) =
  [ [-l/2,-l/2], [-l/2,l/2], [l/2,l/2], [l/2,-l/2] ];

function circle(r) =
  [for(i=[0:$fn-1]) [cos(360*i/$fn),sin(360*i/$fn)] ];




2018-01-05 15:21 GMT-02:00 jon <[hidden email]>:

I want to make horns similar to those shown in the first screen capture, below.

I started out with sweep() but could not see how to incorporate scaling into that approach.  I hacked the sweep.scad module so that the global shape() function was called inside sweep() (rather than passing the output of shape() into sweep() as a parameter), so that I could return shapes which scaled during the sweep.

That approach (although ugly/hacky) worked to some extent.  But since what I really wanted was a hollow horn, things fell apart when I tried to create two horns with different scales, so that I could subtract the inner from the outer.  With only one global shape() function available, the only way I could see to make this work was to duplicate the sweep() code so that I could use two global shape() functions.  I felt as if I was heading towards hacking hell.  Simple use of scale() failed because I need the path to remain unscaled while the object that is being swept is scaled.

I tried to use Ronaldo's sweep-with-easing approach (although I never understood what "easing" was).  The result is unacceptable because the shapes used are always horizontal: they do not rotate to stay orthogonal to the path.  Perhaps this is due to errors in my approach (code is below).

In addition, I was unable to get the horn shapes to have caps on the ends.

I gave up on hollow horns, and made them solid, figuring that I would be able to hollow them out with MeshMixer (annoying, but acceptable).  But the STLs created were so damaged that neither MeshMixer nor NetFabb were able to repair them.

I feel as if I am flailing about randomly.  Perhaps one of you can point me in a more productive direction.

Thanks!

Jon


use <sweep.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

sweep(circle_points, my_path);

my_path = [ for (i=[0:steps])
    translation([18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)]) *
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) *
    rotation([0,0, steps]) ];




-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

_______________________________________________
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: more sweep() issues

Ronaldo
The code bellow illustrates the approach I described before. I had to write some additional helper functions.
The initial parameters and other functions are as before.

Note that if the inner and outer skins intersect the model will not be acceptable by CGAL. It is the programmer responsability to avoid this.
Depending on how the shape and path are defined, some surfaces may be inside out. To correct that sweep_polyhedron() and
annular_polyhedron() have an extra argument, inv, that should be set true to flip the corresponding surface. A preview with 
thrown together is helpful to choose the setting of those arguments.


path = [ for (i=[0:steps]) [18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)] ];
  
shtransf_out = [ for (i=[0:steps])  
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) * 
    rotation([0,0, steps]) ];
// the inner surface section is just a scaled down of the outer section
shtransf_in  = [ for (i=[0:steps])  scaling([0.85,0.85,1])*shtransf_out[i] ];

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

// the path shape transforms of each surface skin
ptrans_out = path_shape_transforms(path, shtransf_out);
ptrans_in  = path_shape_transforms(path, shtransf_in);

// the open mouth of each skin
inner_mouths = [  sweep_end(circle_points, ptrans_in, begin=true),
                  sweep_end(circle_points, ptrans_in, begin=false) ];
outer_mouths = [  sweep_end(circle_points, ptrans_out, begin=true),
                  sweep_end(circle_points, ptrans_out, begin=false) ];
                  
// the annular cap of each end
beg_cap = annular_polyhedron(inner_mouths[0], outer_mouths[0]);
end_cap = annular_polyhedron(inner_mouths[1], outer_mouths[1],inv=true);

// the two sweep skins
skin_out = sweep_polyhedron(circle_points, ptrans_out, caps=false, inv=true);
skin_in  = sweep_polyhedron(circle_points, ptrans_in , caps=false);

// combining everything together
buildPolyhedron([skin_out, skin_in, beg_cap, end_cap]);

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( rt = construct_transform_path(path, closed=false, tangts) )
    [for (i = [0:len(rt)-1]) rt[i]*shape_transf[i] ];

function sweep_end(shape, path_transforms, begin=true) = 
  let( pathlen  = len(path_transforms),
       shape3d  = to_3d(shape) )
  begin ?
    transform(path_transforms[0], shape3d) :
    transform(path_transforms[pathlen-1], shape3d) ;
            
function annular_polyhedron(ring1, ring2,inv) =
  len(ring1)!=len(ring2) ? undef :
    let( verts = concat( ring1, ring2 ),
         n     = len(ring1),
         facet = [for(i=[0:n-1], j=[0,1]) 
                      inv ? 
                        [(i+j)%n,(i+1)%n+j*n,i+n] :
                        [(i+1)%n+j*n,(i+j)%n,i+n] ] )
    [ verts, facet ];
         
module buildPolyhedron(polys, convexity = 10) {
    function _accum_sum(l, offs=0, res=[]) =
        len(res) == len(l) ?
            res :
            _accum_sum(l, offs+l[len(res)], concat(res, [ offs+l[len(res)] ] ));

    function acc_len( f ) = 
        concat([0], _accum_sum([ for(fi=f) len(fi) ]));

    vertlist = [for(p=polys, pt=p[0]) pt]; // collect all verts from polyhedra
    vertlen  = [for(p=polys) p[0] ];
    acclen   = acc_len(vertlen);
    facets   = [ for(i=[0:len(polys)-1], f=polys[i][1] ) [ for(v=f) acclen[i]+v ] ];
    polyhedron(
        points = vertlist,
        faces  = facets,
        convexity = convexity
    );
}




2018-01-05 18:23 GMT-02:00 Ronaldo Persiano <[hidden email]>:
First of all, the path_shape_transforms() I defined before may be simpler defined by:

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( rt = construct_transform_path(path, closed=false, tangts) )
    [for (i = [0:len(rt)-1]) rt[i]*shape_transf[i] ];

Now I want to discuss your question on how to deal with a hollow sweep. My approach to that is the following:
a) build a skin for the outer surface without cap in a suitable form;
b) build a skin for the inner surface without cap in the same form;
c) build a skin (a polygon) connecting one end of the first skin with one end of the other skin;
d) do the same with the other end;
e) aggregate those four skins in one polyhedron call.

The suitable form I use for all skins is a polyhedron data format: a pair of a point list and a facet list. The first two skins are built by sweep_polyhedron() (a function you find in my fork code) without caps. The last two skins may also be built by sweep_polyhedron() applying a round if necessary but it may be just a annular surface connecting two sections.The last process, I called the aggregate, is a very general module that receives a list of polyhedron data, process them and make a call to the polyhedron primitive.

module buildPolyhedron(polys, convexity = 10) {
    function _accum_sum(l, offs=0, res=[]) =
        len(res) == len(l) ?
            res :
            _accum_sum(l, offs+l[len(res)], concat(res, [ offs+l[len(res)] ] ));

    function acc_len( f ) = 
        concat([0], _accum_sum([ for(fi=f) len(fi) ]));

    vertlist = [for(p=polys, pt=p[0]) pt]; // collect all verts from polyhedra
    vertlen  = [for(p=polys) p[0] ];
    acclen   = acc_len(vertlen);
    facets   = [ for(i=[0:len(polys)-1], f=polys[i][1] ) [ for(v=f) acclen[i]+v ] ];
echo(acclen);
    polyhedron(
        points = vertlist,
        faces  = facets,
        convexity = convexity
    );
}




2018-01-05 17:22 GMT-02:00 Ronaldo Persiano <[hidden email]>:
If understood correctly your code, your variable my_path is a prebuilt transform path for sweep that does not include the necessary rotations of the sections to make them orthogonal to the path. That is why the sections are all parallel to plane xy after sweep.

In the following code, I separate the path from the shape transform sequence you want to apply at each path point. And I define a function path_shape_transforms(), based on construct_transform_path(), that takes in account a shape transform sequence besides the path itself. 

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

path = [ for (i=[0:steps]) [18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)] ];
  
shtransf = [ for (i=[0:steps])  
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) * 
    rotation([0,0, steps]) ];

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

ptrans = path_shape_transforms(path, shtransf);

sweep(circle_points, ptrans);

function path_shape_transforms(path, shape_transf, closed=false, tangts) = 
   let( l = len(path),
        tangents = tangts==undef ? tangent_path(path, closed) : tangts,
        local_rotations = minimizing_rotations(concat([[0,0,1]], tangents)),
        rotations = accumulate_rotations(local_rotations),
        twist = closed ? calculate_twist(rotations[0], rotations[l-1]) : 0 ,
        rt = [ for (i = [0:l-1]) construct_rt(rotations[i], path[i]) * rotation( [0, 0, twist*i/(l-1)] ) ] )
    [for (i = [0:l-1]) rt[i]*shape_transf[i] ];

function square(l) =
  [ [-l/2,-l/2], [-l/2,l/2], [l/2,l/2], [l/2,-l/2] ];

function circle(r) =
  [for(i=[0:$fn-1]) [cos(360*i/$fn),sin(360*i/$fn)] ];




2018-01-05 15:21 GMT-02:00 jon <[hidden email]>:

I want to make horns similar to those shown in the first screen capture, below.

I started out with sweep() but could not see how to incorporate scaling into that approach.  I hacked the sweep.scad module so that the global shape() function was called inside sweep() (rather than passing the output of shape() into sweep() as a parameter), so that I could return shapes which scaled during the sweep.

That approach (although ugly/hacky) worked to some extent.  But since what I really wanted was a hollow horn, things fell apart when I tried to create two horns with different scales, so that I could subtract the inner from the outer.  With only one global shape() function available, the only way I could see to make this work was to duplicate the sweep() code so that I could use two global shape() functions.  I felt as if I was heading towards hacking hell.  Simple use of scale() failed because I need the path to remain unscaled while the object that is being swept is scaled.

I tried to use Ronaldo's sweep-with-easing approach (although I never understood what "easing" was).  The result is unacceptable because the shapes used are always horizontal: they do not rotate to stay orthogonal to the path.  Perhaps this is due to errors in my approach (code is below).

In addition, I was unable to get the horn shapes to have caps on the ends.

I gave up on hollow horns, and made them solid, figuring that I would be able to hollow them out with MeshMixer (annoying, but acceptable).  But the STLs created were so damaged that neither MeshMixer nor NetFabb were able to repair them.

I feel as if I am flailing about randomly.  Perhaps one of you can point me in a more productive direction.

Thanks!

Jon


use <sweep.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>

bottom_w = 120;
top_w = 3;
height = 120;
steps = 360;

pathstep = height/steps;
delt = top_w - bottom_w;

square_points = square(1);
circle_points = circle(r=0.5, $fn=60);

sweep(circle_points, my_path);

my_path = [ for (i=[0:steps])
    translation([18*sin(i), 18-18*cos(i*0.7),     36*sin(i/2)]) *
    scaling([11 * (1.2 - i/steps), 11 * (1.2 - i/steps), 1]) *
    rotation([0,0, steps]) ];




-- 
Sent from my desktop computer.  
I do not receive emails while away from my desk, 
nor do I receive texts on my main phone number 
(which is a land line).  
If you know that I am on the road, please text me.  
If you know that I am home, please email me.

_______________________________________________
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