

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 sweepwitheasing 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 <scadutils/transformations.scad>
use <scadutils/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), 1818*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


Jon,
let me remark some things before giving you advice.
1. your code produces selfintersection. 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 nonplanarity
leads to CGALerrors. https://github.com/openscad/openscad/issues/22463. 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:900137w = 40;
// sweep(trajectory(10), showslices = true); // view polygons as slices
// w = $t*9010; animated();
module animated()
{
difference()
{
sweep(trajectory(10));
sweep(trajectory(9, 14));
}
}
function trajectory(r0 = 10, r1=15, N = 20) = [for(i=[0:N1])
let(angle = 90/N*i)
let(r = max(r0, bulb(r1, 1.9, wangle)))
Ry_(angle, Tx_(100, vec3D(circle(r))))];
function circle(r, N=20) = [for(i=[0:N1]) r*[sin(360/N*i), cos(360/N*i)]];
function bulb(r, scale=1, x) = abs(x)<r?scale*sqrt(r*rx*x):0;

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


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.
path = [ for (i=[0:steps]) [18*sin(i), 1818*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) = 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[l1]) : 0 , rt = [ for (i = [0:l1]) construct_rt(rotations[i], path[i]) * rotation( [0, 0, twist*i/(l1)] ) ] ) [for (i = [0:l1]) rt[i]*shape_transf[i] ]; [ [l/2,l/2], [l/2,l/2], [l/2,l/2], [l/2,l/2] ]; [for(i=[0:$fn1]) [cos(360*i/$fn),sin(360*i/$fn)] ];
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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 selfintersection. 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 nonplanarity
> leads to CGALerrors. 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*9010; animated();
>
> module animated()
> {
> difference()
> {
> sweep(trajectory(10));
> sweep(trajectory(9, 14));
> }
> }
>
> function trajectory(r0 = 10, r1=15, N = 20) = [for(i=[0:N1])
> let(angle = 90/N*i)
> let(r = max(r0, bulb(r1, 1.9, wangle)))
> Ry_(angle, Tx_(100, vec3D(circle(r))))];
>
> function circle(r, N=20) = [for(i=[0:N1]) r*[sin(360/N*i), cos(360/N*i)]];
> function bulb(r, scale=1, x) = abs(x)<r?scale*sqrt(r*rx*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


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.
path = [ for (i=[0:steps]) [18*sin(i),
1818*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) =
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[l1]) : 0 ,
rt = [ for (i = [0:l1])
construct_rt(rotations[i], path[i]) * rotation( [0, 0,
twist*i/(l1)] ) ] )
[for (i = [0:l1])
rt[i]*shape_transf[i] ];
[ [l/2,l/2], [l/2,l/2], [l/2,l/2],
[l/2,l/2] ];
[for(i=[0:$fn1])
[cos(360*i/$fn),sin(360*i/$fn)] ];
_______________________________________________
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


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


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=[]) =
_accum_sum(l, offs+l[len(res)], concat(res, [ offs+l[len(res)] ] ));
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 ] ];
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


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), 1818*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); 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), transform(path_transforms[0], shape3d) : transform(path_transforms[pathlen1], shape3d) ; function annular_polyhedron(ring1, ring2,inv) = len(ring1)!=len(ring2) ? undef : let( verts = concat( ring1, ring2 ), facet = [for(i=[0:n1], j=[0,1]) [(i+j)%n,(i+1)%n+j*n,i+n] : [(i+1)%n+j*n,(i+j)%n,i+n] ] ) module buildPolyhedron(polys, convexity = 10) { function _accum_sum(l, offs=0, res=[]) = _accum_sum(l, offs+l[len(res)], concat(res, [ offs+l[len(res)] ] )); 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 ] ];
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

