Search code examples
openscad

Linear & rotational extrude at the same time


I'm trying to draw this (hollow) shape:

funky_shape

The circles are actually different diameters, and I am wanting to neck down the middle of the connecting tube like that (but its not a requirement). I can fake the shape by drawing it segment-by-segment, but I have problems necking it down, and it doesn't feel like how OpenSCAD wants it done (namely the hour-long CSG generation). Any better ways to do this? rendered shape:

for(i = [0:180]) {
    rotate([0,i,0])
    translate([26,0,0])
    difference() {
        cylinder(r=10 + (0.083 * i),h=.1);
        cylinder(r=8 + (0.083 * i),h=.1);
    }
}

Solution

  • first the result:

    difference if 2 polyhedrons

    created by difference of two polyhedrons. The 3d-object is valid, see „simple: yes“ in console

    To get the points needed for polyhedron python3 is used: first an arbitrary number of points on the base circle are constructed( the number of points define the resolution of the 3D-object). The points are rotated and scaled in n steps to 180 degrees and the final scalefactor (n controls the resolution too). Then the points are used, to define the faces of the shape. Finally all is written in openscad-syntax to a file.

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import math
    
    # define parameters
    rr = 26                     # radius of rotation
    r1 = 10                     # outer radius of tube                      
    r2 = 8                      # inner radius of tube
    scale = 2                   # scalefactor over rotation
    segments = 90               # segments of base circle   -> resolution
    rAngle = 180                # angle of rotation
    rSegments = 45              # segments of rotation      -> resolution
    
    def polyhedron(rr,radius,scale, segments, rAngle, rSegments):
        stepAngle = 360/segments
        rotAngle = rAngle/rSegments
        points = '['                # string with the vector of point-vectors
        faces = '['                 # string with the vector of face-vectors
        sprs = (scale-1)/rSegments                  # scale per rSegment
    
        # construct all points
        for j in range(0,rSegments+1):
            angle = j*rotAngle
            for i in range(0,segments):
                xflat = (math.sin(math.radians(i*stepAngle))*radius)            # x on base-circle
                xscaled = xflat*(1 + sprs*j) + rr                       # x scaled (+ rr -> correction of centerpoint
                xrot = math.cos(math.radians(angle))*xscaled                # x rotated
                yflat = (math.cos(math.radians(-i*stepAngle))*radius)           # y on base-circle
                yscaled = yflat*(1 + sprs*j)                        # y scaled
                z = math.sin(math.radians(angle))*xscaled                   # z rotated
                string  = '[{},{},{}],'.format(xrot,yscaled,z)
                points += string
    
        points += ']' 
    
        # construct all faces
        # bottom
        f = '['
        for i in range(segments-1,-1,-1):
            f += '{},'.format(i)
        f += '],'
        faces += f                  # add bottom to faces
    
        # all faces on the side of the tube
        for p in range(0, segments*rSegments):
            p1 = p
            p2 = p + 1 -segments if p%segments == segments-1 else p +1
            p3 = p + segments
            p4 = p3 + 1 -segments if p%segments == segments-1 else p3 +1
            f = '[{},{},{}],'.format(p1,p4,p3)
            faces += f
            f = '[{},{},{}],'.format(p1,p2,p4)
            faces += f
        # top
        f = '['
        for i in range(segments*rSegments,segments*(rSegments+1)):
            f += '{},'.format(i)
        f += ']'
        faces += f                  # add top to faces
        faces += ']'
    
        string = 'polyhedron( points = {}, faces = {});'.format(points,faces)
        return string    
    
    # output in openscad-file
    wobj = open('horn.scad','w')            # open openscad-file for writing
    wobj.write('difference() {\n')
    string = '    '
    string += polyhedron(rr,r1,scale,segments,rAngle,rSegments)
    string += '\n'
    wobj.write(string)
    string = '    '
    string += polyhedron(rr,r2,scale,segments,rAngle,rSegments) 
    string += '\n'
    wobj.write(string)
    wobj.write('}')
    wobj.close()                        # close openscad-file
    # finally open openscad-file in openscad
    

    it renders in 34 seconds