custom threads / nuts
MarcWeber opened this issue · comments
I had a use case pencil like thing with protection cap I wanted to do with screws
This is what I came up with with gumyr's help.
And it works :-)
The question is whether / how to integrate such features into
core library only requiring threads no head no nuts etc.
The idea here is to have the workplane with a location and using that (and it's orientation)
to build the screw with some 'gaps' cutting from original cylinder so that it just works.
The external/internal ThreadCuttings thus build a cylinder to be cutted to then add the
threads. However cutting from an object which has a thread added doesn't work well.
Thus the cylinders to be cutted can be applied first, then all threads get added.
So this example illustrates how to move a thread using
fastener.locate and building the cylinder to be cutted from workplane.
Probably there are better ways but it works.
import cadquery as cq
from copy import copy
from cq_warehouse.fastener import IsoThread, SocketHeadCapScrew
def externalThreadCutting(fastener, clearance = None, workplane=None, simple = False, **kwargs):
"""
cyl = (cq.Workplane("XY").circle(12/2).extrude(20))
thread = IsoThread( major_diameter = 12, pitch = 1, length = 10)
cyl = externalThreadCutting(fastener=thread, clearance = 12)
"""
if workplane == None:
workplane = cq.Workplane("XY")
root_radius = fastener.root_radius
length = fastener.length
if simple:
fastener = (workplane.circle(fastener.apex_radius).circle(root_radius).extrude(length))
else:
fastener = fastener.locate(workplane.plane.location)
if clearance == None:
clearance = 13
# face = thing.faces(faces),
tube = workplane.circle(clearance).circle(root_radius).extrude(length)
# return thing.faces(faces).workplane().cut(tube).add(fastener)
return {"cut": tube, "fastener": fastener}
def internalThreadCutting(fastener, simple = False, workplane = None, **kwargs):
if workplane == None:
workplane = cq.Workplane("XY")
apex_radius = fastener.apex_radius
root_radius = fastener.root_radius
length = fastener.length
if simple:
fastener = (workplane.circle(apex_radius).circle(root_radius).extrude(length))
else:
fastener = fastener.locate(workplane.plane.location)
tube = workplane.circle(apex_radius).extrude(length)
return {"cut": tube, "fastener": fastener}
def _applyFasteners(self, *list):
cut_fasteners = []
for l in list:
x = copy(l)
ff = x.pop("fastenerFunction")
if "workplane" in x:
workplane = x.pop("workplane")
fastener = ff(**x)
l["fastener"] = fastener
cut_fasteners.append(externalThreadCutting(**l) if l["fastener"].external else internalThreadCutting(**l))
thing = self
for x in cut_fasteners:
thing = thing - x["cut"]
for x in cut_fasteners:
thing = thing.add(x["fastener"])
return thing
cq.Workplane.applyFasteners = _applyFasteners
height = 50
D = 12
cap_D = 8
cyl = (cq.Workplane("XY").circle(D/2+10).extrude(height))
thread_fit = 0.1 # eg for resin printers
wp_bottom = cq.Workplane("XY")
wp_top = cq.Workplane("XY", origin = (0,0, height) ).transformed(rotate=cq.Vector(180,0,0))
fasteners = [
{"major_diameter" : D, "pitch" : 1, "external" : True, "length" : 5, "simple" : False, "workplane": wp_bottom, "fastenerFunction": IsoThread},
{"major_diameter" : D, "pitch" : 1, "external" : True, "length" : 5, "simple" : False, "workplane": wp_top, "fastenerFunction": IsoThread},
{"major_diameter" : cap_D + thread_fit, "pitch" : 1, "external" : False, "length" : 5, "simple" : False, "workplane": wp_top, "fastenerFunction": IsoThread}
]
cyl = cyl.applyFasteners(*fasteners)
Here is your objected as I intended cq_warehouse.threads to be used:
import cadquery as cq
from cq_warehouse.fastener import IsoThread
import cq_warehouse.extensions
height, D, cap_D, recess_width = 50, 12, 8, 7
ext = IsoThread(major_diameter=D, pitch=1, length=5)
int = IsoThread(major_diameter=cap_D, pitch=1, length=5, external=False)
outer_radius = ext.min_radius + 10
profile = (
cq.Sketch()
.push([(outer_radius / 2, height / 2)])
.rect(outer_radius, height)
.push(
[
(ext.min_radius + recess_width / 2, ext.length / 2),
(ext.min_radius + recess_width / 2, height - ext.length / 2),
]
)
.rect(recess_width, ext.length, mode="s")
.push([(int.min_radius / 2, height - int.length / 2)])
.rect(int.min_radius, int.length, mode="s")
.clean()
)
cyl = (
cq.Workplane("XZ")
.placeSketch(profile)
.revolve()
.add(
[
ext.cq_object,
ext.cq_object.moved(cq.Location(cq.Vector(0, 0, height - ext.length))),
int.cq_object.moved(cq.Location(cq.Vector(0, 0, height - int.length))),
]
)
)
show_object(cyl, "cyl")
show_object(profile, "profile")
.. shouldn't have used int
as a variable name..