class SolidRuby::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/solidruby/printed_thread.rb, line 29
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/solidruby/printed_thread.rb, line 69
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/solidruby/printed_thread.rb, line 42
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/solidruby/printed_thread.rb, line 65
def segments(diameter)
  [50, (diameter * 6).ceil].min
end
show() click to toggle source
# File lib/solidruby/printed_thread.rb, line 38
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________|          |/

® / (x0_inner, z0_inner) [0]

# File lib/solidruby/printed_thread.rb, line 106
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

  #TODO: test code to see if x1_outer and/or z1_outer are needed
  #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
  ]

   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/solidruby/printed_thread.rb, line 82
def z_fct(current_radius, radius, pitch)
  0.5 * (current_radius - (radius - 0.875 * pitch * Math.cos(radians(30)))) / Math.cos(radians(30))
end