Skip to content

Commit 92a8dac

Browse files
Merge pull request #10 from Jojain/master
adding gear example
2 parents 1460cb2 + f34480d commit 92a8dac

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

examples/cylindrical_gear.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import cadquery as cq
2+
from math import *
3+
4+
class HollowCylinderSelector(cq.Selector):
5+
"""
6+
Selects any shape present in the infinite hollow cylinder.
7+
"""
8+
#It works for the use I have in this code, it's not tested for any other configuration hence it might not be super robust
9+
def __init__(self, inner_radius, outer_radius, along_axis = "Z"):
10+
self.r1 = inner_radius
11+
self.r2 = outer_radius
12+
if along_axis == "X":
13+
self.axis = 0
14+
elif along_axis == "Y":
15+
self.axis = 1
16+
elif along_axis == "Z":
17+
self.axis = 2
18+
19+
def filter(self, objectList):
20+
result =[]
21+
for o in objectList:
22+
p = o.Center()
23+
p_coords = [p.x, p.y, p.z]
24+
del p_coords[self.axis]
25+
p_radius = sqrt(p_coords[0]**2 + p_coords[1]**2)
26+
27+
if p_radius> self.r1 and p_radius < self.r2 :
28+
result.append(o)
29+
30+
return result
31+
32+
def involute(r):
33+
#callback for paramCurve() function
34+
def curve(t):
35+
"""
36+
The involute curve is the curve that describe the flank of a tooth of a gear
37+
"""
38+
x = r*(cos(t) + t*sin(t))
39+
y = r*(sin(t) - t*cos(t))
40+
return x,y
41+
return curve
42+
43+
def cylindrical_gear(m, z, alpha, b, helix_angle = None):
44+
"""
45+
Create a cylindrical gear (either straight or helix)
46+
Note that the helix one is pretty slow to be generated and the filling of the root edge of the gear don't work for helix_angle > 3°
47+
48+
params :
49+
m : module of the gear (gear meshes only if they have the same module)
50+
z : number of teeths
51+
b : thickness of the gear
52+
"""
53+
r_p = m*z/2 #primitif radius (radius at which contact with other gear is made)
54+
r_a = r_p + m #radius of the top of the tooth
55+
r_f = r_p - 1.25*m #radius of the root of the tooth
56+
r_b = r_p*cos(radians(alpha)) #radius of the base circle from where the involute curve starts
57+
58+
def create_tooth_profile(m, z, alpha):
59+
#Callback for eachpoint() function
60+
def tooth_profile(loc):
61+
62+
63+
STOP = sqrt((r_a/r_b)**2 - 1) # the STOP value is calculated by solving the following equation for t : ||involute(t)|| = r_a , ||involute(t)|| being the norm of the vector
64+
#below I start my 2D shape by sketching the 2 flanks of the tooth define by the 2 involutes
65+
right = cq.Workplane("XY").parametricCurve(involute(r_b), stop = STOP, makeWire=False)
66+
wire = cq.Workplane("XY").tag("base").transformed(rotate=(0,0,180/z)).parametricCurve(involute(r_b), stop = -STOP, makeWire=False)
67+
68+
end_point_a = wire.val().endPoint().toTuple() #storing the global coord of the point for later use
69+
if r_b < r_f:
70+
raise ValueError("r_b is smaller than r_f, your gear is undercut, try changing yours input parameter (use smaller alpah angle")
71+
# A gear could work even if it's undercut, I was just lazy to take care of it
72+
73+
else:
74+
wire = (wire.vertices("<X").workplane(centerOption="CenterOfMass").hLine(r_f-r_b)) # drawsing the rest of the profile starting from the bottom of the left involute
75+
start_arc_root_pt = wire.val().endPoint().toTuple() #storing coord of the point again
76+
#below building the final closed wire of the 2D tooth shape
77+
wire = (wire.workplaneFromTagged("base")
78+
.moveTo(start_arc_root_pt[0], start_arc_root_pt[1] )
79+
.radiusArc((r_f,0),r_f)
80+
.hLine(r_b-r_f)
81+
.parametricCurve(involute(r_b), stop = STOP, makeWire=False)
82+
.radiusArc(end_point_a,r_a)
83+
.combine()
84+
.wire().clean()
85+
)
86+
return wire.val().moved(loc) #took the trick from slot2D function, eachpoint feeds via the previously created polararray
87+
# the Location objects of the points, so this return create a 2D tooth profile and then rotate it to the right coord
88+
return tooth_profile
89+
90+
#creating all the 2D profiles of the gear
91+
teeths = (cq.Workplane("XY")
92+
.polarArray(0, 0, 360, z) #since my involute curve starts at the origin, I just need rotate workplane, which actually works when specifing 0 radius to polararray
93+
.eachpoint(create_tooth_profile(m,z,alpha), useLocalCoordinates=True)
94+
)
95+
96+
#extruding the 2D teeths in 3D
97+
if helix_angle is None:
98+
teeths = teeths.extrude(b)
99+
else:
100+
teeths = teeths.twistExtrude(b, helix_angle)
101+
102+
# creating the final gear by extruding the middle portion and unioning it with alls the teeths previously created
103+
gear = (cq.Workplane("XY").circle(r_f).extrude(b).union(teeths)
104+
.edges( #Selecting only the edges parallel to Z axis at the root of the teeths
105+
HollowCylinderSelector(0, 1.01*r_f) -
106+
cq.DirectionMinMaxSelector(cq.Vector(0,0,1)) -
107+
cq.DirectionMinMaxSelector(cq.Vector(0,0,1),directionMax=False)
108+
)
109+
.fillet(0.4*m)
110+
.faces(">Z")
111+
.circle(0.5*r_f)
112+
.cutThruAll()
113+
)
114+
return gear
115+
116+
############################################################
117+
############################################################
118+
############################################################
119+
120+
#Creation of 2 gears that meshes
121+
122+
alpha = 20
123+
m = 1
124+
z1 = 20
125+
z2 = 12
126+
b = m*5
127+
128+
129+
gear = cylindrical_gear(m,z1,alpha,b)
130+
gear2 = cylindrical_gear(m,z2,alpha,b).val().move(cq.Location(cq.Vector(m*z1/2+m*z2/2,0,0)))
131+
show_object(gear)
132+
show_object(gear2)

examples/gear_cadquery.PNG

79.5 KB
Loading

0 commit comments

Comments
 (0)