I'm trying to draw this (hollow) 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? :
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);
}
}
first the result:
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