class CrystalScad::PrintedThreads::PrintedThread

Ported from dkprojects.net/openscad-threads/threads.scad

original Author Dan Kirshner - dan_kirshner@yahoo.com

Public Class Methods

new(args={}) click to toggle source

internal - true = clearances for internal thread (e.g., a nut).

false = clearances for external thread (e.g., a bolt).
(Internal threads should be "cut out" from a solid using
difference()).

number_of_starts - Number of thread starts (e.g., DNA, a “double helix,” has

n_starts=2).  See wikipedia Screw_thread.
# File lib/crystalscad/PrintedThreads.rb, line 16
def initialize(args={})
        @args = args
        @args[:diameter] ||= 8
        @args[:pitch] ||= 1.25
        @args[:length] ||=10
        @args[:internal] ||= false
        @args[:number_of_starts] ||= 1
end

Public Instance Methods

metric_thread_turn(diameter, pitch, internal, number_of_starts) click to toggle source
# File lib/crystalscad/PrintedThreads.rb, line 56
def metric_thread_turn(diameter, pitch, internal, number_of_starts)
        number_of_segments = segments(diameter)
fraction_circle = 1.0/number_of_segments
        res = nil

        (0..number_of_segments-1).each do |i|
                res += thread_polyhedron(diameter/2.0, pitch, internal, number_of_starts).translate(z:i*number_of_starts*pitch*fraction_circle).rotate(z:i*360*fraction_circle)
        end
        res

end
output() click to toggle source
# File lib/crystalscad/PrintedThreads.rb, line 29
def output
        number_of_turns = (@args[:length].to_f/@args[:pitch].to_f).floor
        number_of_segments = segments(@args[:diameter])
        h = @args[:pitch] * Math::cos(radians(30)) 
                
        res  = nil
        ((-1*@args[:number_of_starts])..(number_of_turns+1)).each do |i|
                res += metric_thread_turn(@args[:diameter], @args[:pitch], @args[:internal], @args[:number_of_starts]).translate(z:i*@args[:pitch])
        end
        # cut to length
        res *= cube(x:@args[:diameter]*1.1, y:@args[:diameter]*1.1, z:@args[:length]).center.translate(z:@args[:length]/2.0)
        
        if @args[:internal]
                # Solid center, including Dmin truncation.
                res += cylinder(r:@args[:diameter]/2.0 - h*5.0/8.0, h:@args[:length], segments:number_of_segments)
        else
                # External thread includes additional relief.
                res += cylinder(r:@args[:diameter]/2.0 - h*5.3/8.0, h:@args[:length], segments:number_of_segments)                  
        end                  
        
        res                  
end
segments(diameter) click to toggle source
# File lib/crystalscad/PrintedThreads.rb, line 52
def segments(diameter)
        [50, (diameter*6).ceil].min
end
show() click to toggle source
# File lib/crystalscad/PrintedThreads.rb, line 25
def show
        output
end
thread_polyhedron(radius, pitch, internal, n_starts) click to toggle source
       (angles x0 and x3 inner are actually 60 deg)

                             /\  (x2_inner, z2_inner) [2]
                            /  \
(x3_inner, z3_inner) /    \
                     [3]   \     \
                           |\     \ (x2_outer, z2_outer) [6]
                           | \    /
                           |  \  /|
                z          |   \/ / (x1_outer, z1_outer) [5]
                |          |   | /
                |   x      |   |/
                |  /       |   / (x0_outer, z0_outer) [4]
                | /        |  /     (behind: (x1_inner, z1_inner) [1]
                |/         | /
       y________|          |/
(r)                  / (x0_inner, z0_inner) [0]

end

# File lib/crystalscad/PrintedThreads.rb, line 94
def thread_polyhedron(radius, pitch, internal, n_starts)
  n_segments = segments(radius*2)
      fraction_circle = 1.0/n_segments

        h = pitch * Math::cos(radians(30))
        outer_r = radius + (internal ? h/20 : 0) # Adds internal relief.
         
        inner_r = radius - 0.875*h #  Does NOT do Dmin_truncation - do later with cylinder.

        # Make these just slightly bigger (keep in proportion) so polyhedra will overlap.
        x_incr_outer = outer_r * fraction_circle * 2 * Math::PI * 1.005
        x_incr_inner = inner_r * fraction_circle * 2 * Math::PI * 1.005
        z_incr = n_starts * pitch * fraction_circle * 1.005
        
        x1_outer = outer_r * fraction_circle * 2 * Math::PI

        z0_outer = z_fct(outer_r, radius, pitch);
        z1_outer = z0_outer + z_incr;
# Rule for triangle ordering: look at polyhedron from outside: points must
# be in clockwise order.
        
                points = [
                                      [-x_incr_inner/2, -inner_r, 0],                                    # [0]
                                      [x_incr_inner/2, -inner_r, z_incr],                    # [1]
                                      [x_incr_inner/2, -inner_r, pitch + z_incr],            # [2]
                                      [-x_incr_inner/2, -inner_r, pitch],                                # [3]

                                      [-x_incr_outer/2, -outer_r, z0_outer],                             # [4]
                                      [x_incr_outer/2, -outer_r, z0_outer + z_incr],         # [5]
                                      [x_incr_outer/2, -outer_r, pitch - z0_outer + z_incr], # [6]
                                      [-x_incr_outer/2, -outer_r, pitch - z0_outer]                      # [7]
                                     ]

                triangles = [
                                      [0, 3, 4],  # This-side trapezoid, bottom
                                      [3, 7, 4],  # This-side trapezoid, top

                                      [1, 5, 2],  # Back-side trapezoid, bottom
                                      [2, 5, 6],  # Back-side trapezoid, top

                                      [0, 1, 2],  # Inner rectangle, bottom
                                      [0, 2, 3],  # Inner rectangle, top

                                      [4, 6, 5],  # Outer rectangle, bottom
                                      [4, 7, 6],  # Outer rectangle, top

                                      [7, 2, 6],  # Upper rectangle, bottom
                                      [7, 3, 2],  # Upper rectangle, top

                                      [0, 5, 1],  # Lower rectangle, bottom
                                      [0, 4, 5]   # Lower rectangle, top
                                     ]

        return polyhedron(points:points, triangles:triangles)
end
z_fct(current_radius, radius, pitch) click to toggle source

z (see diagram) as function of current radius. (Only good for first half-pitch.)

# File lib/crystalscad/PrintedThreads.rb, line 70
def z_fct(current_radius, radius, pitch)
        0.5*(current_radius - (radius - 0.875*pitch*Math::cos(radians(30))))/Math::cos(radians(30))                  
end