[OpenSCAD] more sweep() issues

Ronaldo Persiano rcmpersiano at gmail.com
Fri Jan 5 16:47:50 EST 2018


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 <rcmpersiano at gmail.com>:

> 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 <rcmpersiano at gmail.com>:
>
>> 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 <jon at jonbondy.com>:
>>
>>> 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
>>> Discuss at lists.openscad.org
>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20180105/7792ef14/attachment-0002.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: horn.PNG
Type: image/png
Size: 32738 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20180105/7792ef14/attachment.PNG>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cajeplmoagikdifl.png
Type: image/png
Size: 56639 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20180105/7792ef14/attachment.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: jeiboandnhdkpfdo.png
Type: image/png
Size: 44943 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20180105/7792ef14/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: hollowed_horn.PNG
Type: image/png
Size: 54089 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20180105/7792ef14/attachment-0001.PNG>


More information about the Discuss mailing list