Skip to content

Instantly share code, notes, and snippets.

@fragmuffin
Last active September 18, 2017 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fragmuffin/266bee4babd9a25aea2d53c739144ee3 to your computer and use it in GitHub Desktop.
Save fragmuffin/266bee4babd9a25aea2d53c739144ee3 to your computer and use it in GitHub Desktop.
CadQuery thread (method not recommended)
import cadquery
from Helpers import show
helical_radius = 6.0
core_radius = 4.0
pitch = 2.0 # length per revolution
length = 12.0
def helical_path(p, l, r):
wire = cadquery.Wire.makeHelix(p, l, r, angle=0)
shape = cadquery.Wire.combine([wire])
path = cadquery.Workplane("XY").newObject([shape])
return path
# Inverted Thread profile
# FIXME: thread model must extend past helical_radius to make a clean cut
points = [
(0.5 * pitch, helical_radius * 1.01),
(0, core_radius),
(-0.5 * pitch, helical_radius * 1.01),
]
# Inverted Thread: a single turn, around world origin
single_turn = helical_path(pitch, pitch, helical_radius).translate((0, 0, -pitch / 2))
inv_thread = cadquery.Workplane("ZX").center(-pitch / 2., 0) \
.moveTo(*points[0]).polyline(points[1:]).close() \
.sweep(single_turn, isFrenet=True)
# cross-section face of thread (at origin)
cross_section = cadquery.Workplane("XY").workplane(offset=-pitch / 2.) \
.circle(helical_radius).extrude(pitch / 2.) \
.cut(inv_thread).faces(">Z")
cross_section_face = cross_section.val() # cadquery.Face
cross_section_wire = cross_section_face.Wires().pop() # cadquery.Wire
cross_section_wire.forConstruction = False
# Thread created from profile sweep
full_helix = helical_path(pitch, length, helical_radius)
my_model = cadquery.Workplane("XY").box(1,1,1)
my_model._addPendingWire(cross_section_wire) # FIXME: using private function
my_model.sweep(full_helix, isFrenet=True)
# Use the following to render your model with grey RGB and no transparency
#show(cross_section)
show(my_model, (204, 204, 204, 0.5))
@fragmuffin
Copy link
Author

Using the guidance of: https://www.freecadweb.org/wiki/Thread_for_Screw_Tutorial and attempting to implement in cadquery.

What's wrong with this implementation?

very slow
takes ~15sec to generate on my laptop
note: this could be drastically improved by

  • creating the thread profile mathematically (it's actually not as hard as it sounds)
  • sweeping a single turn, then duplicating it along the thread's length

Thread Profile imperfect
if profile is <= outer radius, cut operation fails
this is why the thread's outer edge appears as a thicker line, because it's not just an edge, it's comprised of 2 very thin flat helical faces.
see FIXME in the code

Uses backdoors

  • the cadquery.Wire's forConstruction attribute does not exist in a Wire instance unless explicitly set
  • using cadquery.Workplane private function _addPendingWire to use a face in a sweep

@dcowden
Copy link

dcowden commented Sep 18, 2017

@fragmuffin this is awesome!

This helps me understand what the cq direct API needs to look like as it relates to wires.

The cadquery newObject is also a backdoor in the current API, so we need to make it easier to decorate result objects with a selector.

The need to adjust the cut a slight amount to avoid an error is common. I have written many scripted features using Onshape (which is based on parasolid) and even there this is commonly necessary.

It's hard to get around the speed issue. Even with parasolid, it is slow to make real screw threads.

Other ideas for enhancements:

Internal threads
50% and 75% threads based on standards
Choose standard sizes
Taper thread entry and exit
Cut threads on existing cylinder
Trapezoidal thread profile
Multiple starts

@fragmuffin
Copy link
Author

@dcowden: my reply in #195

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment