Skip to content

gear -- Generation of gears, racks, etc

This module provide functions to generate racks and gears with many different shapes.

The mainstream gears are involute gears (using involute of circles as contact curves). This is due to the standard shape of racks. And involute gears are the best choice for most designs, which is why the current implementation focusses on them.

However the tools here are modular, which means you can combine them with your own functions to create customized gears.

Examples

As a first use, you may want to generate a fully finished spur gear If you do not specify optional arguments, the function will provide good defaults for it.

    >>> # fully featured gear
    >>> gear(step=3, teeth=12, depth=4, bore_radius=1.5)

You may want to generate a more bizarre gear, with a a different hub for instance. You will then need to assemble a gear from its 3 components: exterior (tooths), structure (between hub and exterior), and hub (what holds the gear on an axis)

    >>> # this assemble a gear specifying each independant sub-parts
    >>> ext_radius = (3 * 12) / (2 * pi) - 3
    >>> int_radius = 4
    >>> geargather(
    ...      gearexterior(repeataround(gearprofile(3, 30), 30), depth=4),
    ...      gearstructure("rounded", ext_radius, int_radius, 2, patterns=6),
    ...      my_hub_mesh,
    ... )

For reuse in your custom functions, the functions used to generate the gears are exposed:

    >>> # this is the raw profile of a tooth
    >>> gearprofile(step=3, teeth=12)

Tooth profiles generation

The following functions are focussing on involute gears. If you want more details on how involutes gears are defined and computed, you can take a look at the algorithm section

rackprofile(step, height=None, offset=0, asymetry=None, pressure_angle=radians(20), resolution=None)

Generate a 1-period tooth profile for a rack

rackprofile

Parameters:

Name Type Description Default
step

period length over the primitive line

required
height

tooth half height

None
offset

rack reference line offset with the primitive line (as a distance) - the primitive line is the adherence line with gears - the reference line is the line half the tooth is above and half below

0
pressure_angle

angle of the tooth sides, a.k.a pressure angle of the contact

radians(20)
Source code in madcad/gear.py
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def rackprofile(step, height=None, offset=0, asymetry=None, pressure_angle=radians(20), resolution=None) -> Wire:
	''' Generate a 1-period tooth profile for a rack

	![rackprofile](../screenshots/rackprofile.png)

	Parameters:
		step:		period length over the primitive line
		height:			tooth half height
		offset:	 	rack reference line offset with the primitive line (as a distance)
					  - the primitive line is the adherence line with gears
					  - the reference line is the line half the tooth is above and half below
		pressure_angle:		angle of the tooth sides, a.k.a  pressure angle of the contact
	'''
	# change name for convenience
	h = height
	a = asymetry
	e = offset
	if h is None:
		h = default_height(step, pressure_angle)
	if a is None:
		a = -0.1*h
	ta = tan(pressure_angle)
	x = 0.5 - 2*e/step*ta  # fraction of the tooth above the primitive circle

	return Wire([
		vec3(step*x/2 - ta * ( h-e-a),   h-e-a,  0),
		vec3(step*x/2 - ta * (-h-e-a),  -h-e-a,  0),
		vec3(step*(2-x)/2 + ta * (-h-e-a),  -h-e-a,  0),
		vec3(step*(2-x)/2 + ta * ( h-e-a),   h-e-a,  0),
		vec3(step*(2+x)/2 - ta * ( h-e-a),   h-e-a,  0),
		], groups=['rack'])

gearprofile(step, teeth, height=None, offset=0, asymetry=None, pressure_angle=radians(20), resolution=None, **kwargs)

Generate a 1-period tooth profile for a straight gear

gearprofile

Parameters:

Name Type Description Default
step

period length over the primitive circle

required
tooth

number of tooth on the gear this profile is meant for

required
height

tooth half height

None
offset

offset distance of the matching rack profile (see above)

0
pressure_angle

pressure angle in the contact

radians(20)
Source code in madcad/gear.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def gearprofile(step, teeth, height=None, offset=0, asymetry=None, pressure_angle=radians(20), resolution=None, **kwargs) -> Wire:
	''' Generate a 1-period tooth profile for a straight gear

	![gearprofile](../screenshots/gearprofile.png)

	Parameters:
		step:		period length over the primitive circle
		tooth:			number of tooth on the gear this profile is meant for
		height:			tooth half height
		offset:		offset distance of the matching rack profile (see above)
		pressure_angle:		pressure angle in the contact
	'''
	# change name for convenience
	z = teeth
	h = height
	a = asymetry
	if h is None:
		h = default_height(step, pressure_angle)
	if a is None:
		a = -0.1*h
	p = step*z / (2*pi)	# primitive circle
	c = p * cos(pressure_angle)	# tangent circle to gliding axis

	e = offset  # change name for convenience
	#e = offset + 0.05*h  # the real offset is 5% (the 1*m, 1.25*m) when the standard says it is 0
	x = 0.5 + 2*e/step*tan(pressure_angle)  # fraction of the tooth above the primitive circle
	n = 2 + settings.curve_resolution(h, step/p, resolution)	# number of points to place

	o0 = angle(involute(c, 0, tan(pressure_angle)))	# offset of contact curve
	oi = atan((h-e-a)/p * tan(pressure_angle))		# offset of interference curve

	l0 = involuteat(c, p+h+e+a)	# interval size of contact curve

	# if the tooth height is unreachable, find the intersection between the two contact curves
	t0 = -step/(2*p)*x - o0
	t = t0+l0
	if involute(c, t0, t)[1] > 0:
		# Newton solver method
		for i in range(2*n+5):
			f = sin(t) + cos(t)*(t0-t)
			J = - sin(t)*(t0-t)
			t -= f/J
		l0 = t-t0

	# if there is an interference curve
	interference = c > p-h+e+a
	if interference:
		# Newton solver method
		# to compute the parameters (t1, t2) of the intersection between contact line and interference line
		t0, ti = o0, oi
		# initial state
		t1 = t0 - tan(pressure_angle)	# put contact line on primitive
		t2 = ti + sqrt(c**2 - (p-h+e+a)**2) /p	# put interference point on base circle
		for i in range(2*n+5):
			ct1, ct2 = cos(t1), cos(t2)
			st1, st2 = sin(t1), sin(t2)
			# function value
			f = (	c*vec2(ct1,st1) + c*(t0-t1)*vec2(-st1,ct1)
				+	(h-e-a-p)*vec2(ct2,st2) -p*(ti-t2)*vec2(-st2,ct2)
				)
			# jacobian matrix (f partial derivatives)
			J = mat2(
				-c*(t0-t1)*vec2(ct1,st1),
				p*(ti-t2)*vec2(ct2,st2) + (h-e)*vec2(-st2,ct2),
				)
			# iteration
			t1, t2 = vec2(t1,t2) - inverse(J)*f
			# prevent divergence out of the interesting range
			t1 = min(0, t1)
			t2 = max(0, t2)
		li = t2 - ti	# interval size of interference curve
		s0 = t0 - t1	# generation start of contact curve
	else:
		s0 = involuteat(c, p-h+e+a)

	points = []
	tracks = []

	# parameters for first side
	place = step/(2*p)*-x
	t0 = place - o0
	ti = place - oi
	# interference line
	if interference:
		for i in range(n):
			t = interpol1(ti, ti-li, i/n)
			v = involuteof(p, ti, -h+e+a, t)
			points.append(vec3(v,0))
			tracks.append(0)
		tracks[-1] = 1
	# contact line
	for i in range(n+1):
		t = interpol1(t0+s0, t0+l0, i/n)
		v = involute(c, t0, t)
		points.append(vec3(v,0))
		tracks.append(1)
	tracks[-1] = 2

	# parameter for second side
	place = step/(2*p)*x	# place of intersection with the primitive circle
	t0 = place + o0	# start of contact curve
	ti = place + oi	# start of interference curve
	# contact line
	for i in range(n+1):
		t = interpol1(t0-l0, t0-s0, i/n)
		v = involute(c, t0, t)
		points.append(vec3(v,0))
		tracks.append(3)
	tracks[-1] = 4
	# interference line
	if interference:
		for i in range(1, n+1):
			t = interpol1(ti+li, ti, i/n)
			v = involuteof(p, ti, -h+e+a, t)
			points.append(vec3(v,0))
			tracks.append(4)
		tracks[-1] = 5

	points.append(angleAxis(step/p, vec3(0,0,1)) * points[0])
	tracks.append(5)

	return Wire(points, tracks=tracks, groups=['interference', 'contact', 'top', 'contact', 'interference', 'bottom'])

spherical_rackprofile(teeth, pressure_angle=pi / 9, ka=1, kd=1.25, resolution=None)

Return a Wire which is a tooth of the rack.

spherical_rackprofile

Parameters:

Name Type Description Default
teeth float

number of tooth of the rack equal to z_pinion / sin(pitch_cone_angle) or z_wheel / sin(shaft_angle - pitch_cone_angle)

required
pressure_angle float

the pressure angle of the gear

pi / 9
ka float

the addendum coefficient

1
kd float

the dedendum coefficient

1.25
Source code in madcad/gear.py
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
def spherical_rackprofile(teeth:float, pressure_angle:float=pi / 9, ka:float=1, kd:float=1.25, resolution=None):
	"""
	Return a `Wire` which is a tooth of the rack.

	![spherical_rackprofile](../screenshots/spherical_rackprofile.png)

	Parameters:
		teeth (float):
			number of tooth of the rack equal to `z_pinion / sin(pitch_cone_angle)`
			or `z_wheel / sin(shaft_angle - pitch_cone_angle)`
		pressure_angle (float): 	the pressure angle of the gear
		ka (float): 				the addendum coefficient
		kd (float): 				the dedendum coefficient
	"""
	div = settings.curve_resolution(1, pi/teeth, resolution)
	t_min, t_max, phase1, phase2, involute = spherical_rack_tools(teeth, pressure_angle, ka, kd)

	side1 = [involute(t, 0)		 for t in linrange(t_min, t_max, div=div)]
	side2 = [involute(-t, phase1)   for t in linrange(t_min, t_max, div=div)]
	segment = Segment(involute(t_min, -phase2), side1[0]).mesh()
	segment2 = Segment(side1[-1], side2[-1]).mesh()
	wire = segment + Wire(side1) + segment2 + Wire(side2).flip()
	return wire

spherical_gearprofile(teeth, pitch_cone_angle, pressure_angle=pi / 9, ka=1, kd=1.25, resolution=None)

Generate and return a Wire of a 1-period tooth spherical profile for a filet gear

spherical_gearprofile

Parameters:

Name Type Description Default
teeth int

number of tooth on the gear this profile is meant for

required
pitch_cone_angle float

the pitch cone angle

required
pressure_angle float

pressure angle of the tooth

pi / 9
ka float

addendum coefficient

1
kd float

dedendum coefficient

1.25
Source code in madcad/gear.py
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
def spherical_gearprofile(
		teeth:int, 
		pitch_cone_angle:float, 
		pressure_angle:float=pi / 9, 
		ka:float=1, 
		kd:float=1.25, 
		resolution = None,
		) -> Wire:
	"""
	Generate and return a `Wire` of a 1-period tooth spherical profile for a filet gear

	![spherical_gearprofile](../screenshots/spherical_gearprofile.png)

	Parameters:
		teeth (int):						number of tooth on the gear this profile is meant for
		pitch_cone_angle (float): 		the pitch cone angle
		pressure_angle (float):			pressure angle of the tooth
		ka (float):						addendum coefficient
		kd (float): 					dedendum coefficient
	"""
	# Initialization of parameters
	gamma_p = pitch_cone_angle # for convenience
	gamma_b = asin(cos(pressure_angle) * sin(gamma_p))
	cos_b, sin_b = cos(gamma_b), sin(gamma_b)
	tooth_size = pi / teeth
	involute = lambda t, t0 : spherical_involute(gamma_b, t0, t)
	epsilon_p = acos(cos(gamma_p) / cos_b) / sin_b
	theta_p = anglebt(involute(0, 0) * vec3(1, 1, 0), involute(epsilon_p, 0) * vec3(1, 1, 0))
	phase_diff = tooth_size + 2 * theta_p
	phase_empty = phase_interference = 2 * pi / teeth - phase_diff
	# The following number `k` is useful to simplify some calculations
	# It's broadly speaking `1/z_rack` and `z_rack` is not an integer !
	k = sin(gamma_p) / teeth

	# Spherical involute part
	gamma_f = gamma_p + 2 * ka * k # addendum cone angle
	gamma_r = gamma_p - 2 * kd * k # dedendum cone angle
	t_min = 0
	t_max = acos(cos(gamma_f) / cos_b) / sin_b
	if gamma_r > gamma_b:
		v = vec3(1, 1, 0)
		t_min = acos(cos(gamma_r) / cos_b) / sin_b
		phase_empty = 2 * pi / teeth - anglebt(
			involute(t_min, 0) * v, involute(-t_min, phase_diff) * v
		)

	# Calculation of offsets due to geometry of spherical rack
	_, t_rack_max, phase1, _, rinvolute = spherical_rack_tools(1 / k, pressure_angle, ka, kd)
	interference = lambda t, t0 : spherical_involuteof(gamma_p, t0, pressure_angle, t)
	pressure_angle = 2 * ka * k
	n1, n2 = rinvolute(t_rack_max, 0) * vec3(1, 1, 0), rinvolute(-t_rack_max, phase1) * vec3(1, 1, 0)
	beta = 0.5 * anglebt(n1, n2) * length(n1) / sin_b

	# Newton method to calculate the intersection between
	# the spherical involute and the spherical interference.
	# Objective function
	involuteat = lambda t2, t0 : spherical_involuteof(gamma_p, t0, pressure_angle, t2)
	f = lambda t1, t2: involute(t1, 0) - involuteat(t2, -0.5 * phase_interference + beta)
	# Jacobian matrix
	J = jacobian_spherical_involute(gamma_b, gamma_p, 0, -0.5 * phase_interference + beta, pressure_angle)

	# Compute the intersection values
	t1, t2, t3 = 0.5 * t_max, -0.5 * t_max, 0
	for i in range(8):
		t1, t2, t3 = vec3(t1, t2, t3) - inverse(J(t1, t2)) * f(t1, t2)

	# Build sides of a tooth
	div = settings.curve_resolution(1, 2*pi/teeth, resolution)
	interference1 = [interference(t, -0.5 * phase_interference + beta) for t in linrange(0, t2, div=div)]
	interference2 = [interference(-t, phase_diff + 0.5 * phase_interference - beta) for t in linrange(0, t2, div=div)]
	side1 = Wire(interference1[:-1]) + Wire([involute(t, 0) for t in linrange(t1, t_max, div=div)])
	side2 = Wire(interference2[:-1]) + Wire([involute(-t, phase_diff) for t in linrange(t1, t_max, div=div)])
	side2.groups = side1.groups = ['interference', 'contact']

	# Extreme points of sides to compute angle between them
	a = interference(0, -0.5 * phase_interference + beta)
	b = interference(0, phase_diff + 0.5 * phase_interference - beta)
	final_phase_empty = 2 * pi / teeth - anglebt(a * vec3(1, 1, 0), b * vec3(1, 1, 0))
	top = Segment(involute(t_max, 0), involute(-t_max, phase_diff)).mesh()
	bottom = Segment(angleAxis(-final_phase_empty, vec3(0, 0, 1)) * a, a).mesh()
	top.groups = ['top']
	bottom.groups = ['bottom']

	return bottom + side1 + top + side2.flip()

Gear generation

gear(step, teeth, depth, bore_radius=0, int_height=0, pattern='full', **kwargs)

Generate a pinion.

gear

Any extra argument will go to functions gearprofile, gearstructure, or gearhub

Parameters:

Name Type Description Default
step float

tooth step over the primitive curve, same as the matching rack step the primitive perimeter is step * teeth and radius is step * teeth / 2*pi

required
teeth int

number of teeth

required
depth float

extrusion eight - width of the gear along its axis

required
bore_radius float

radius of the main bore

0
int_height float

if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height

0
pattern

determine the structure between exterior (tooth) and hub This argument specifies the use a a function named 'pattern_'+pattern in this module.

'full'
  • Extra parameters for gearprofile

    offset (float):         offset of tooth (as a distance)
    pressure_angle (float):                 pressure angle in radian
    
  • Extra parameters for gearexterior

    helix_angle (float):    helix angle to get a helical pinion in radian
    chamfer (bool | float | (float, float)):
    
            set the parameter of chamfer `(angle, ratio)` such as `angle` is the chamfer angle,
            `ratio` is where the chamfer is applied (`rmin + ratio * (rmax - rmin)`)
    
  • Extra parameters for gearstructure

    ratio (float):  influence the proportion of dimensions of the structure
    

Note: int_height impacts the thickness of the structure unless specified

  • Extra parameters for gearhub
    hub_height (float):             height of the hub shoulder
    

Note:

    - `int_height` impacts the height of the hub unless specified.
    - if `hub_height` is null, there will be no hub.
Source code in madcad/gear.py
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
@cachefunc
def gear(
	step,
	teeth: int,
	depth,
	bore_radius = 0,
	int_height = 0,
	pattern = 'full',
	**kwargs,
) -> Mesh:
	"""
	Generate a pinion.

	![gear](../screenshots/gear-minimal.png)

	Any extra argument will go to functions `gearprofile`, `gearstructure`, or `gearhub`

	Parameters:
		step (float):
			tooth step over the primitive curve, same as the matching rack step
			the primitive perimeter is `step * teeth` and radius is `step * teeth / 2*pi`
		teeth (int):				number of teeth
		depth (float):			extrusion eight - width of the gear along its axis
		bore_radius (float):	radius of the main bore
		int_height (float):		if you want a pinion with a structure thinner than the value of `depth`,
								the total height will be `total_height = depth - 2 * int_height`
		pattern:
			determine the structure between exterior (tooth) and hub
			This argument specifies the use a a function named `'pattern_'+pattern` in this module.

	* Extra parameters for `gearprofile`

		offset (float):		offset of tooth (as a distance)
		pressure_angle (float): 		pressure angle in radian

	* Extra parameters for `gearexterior`

		helix_angle (float):	helix angle to get a helical pinion in radian
		chamfer (bool | float | (float, float)):

			set the parameter of chamfer `(angle, ratio)` such as `angle` is the chamfer angle,
			`ratio` is where the chamfer is applied (`rmin + ratio * (rmax - rmin)`)

	* Extra parameters for `gearstructure`

		ratio (float):	influence the proportion of dimensions of the structure

	Note: `int_height` impacts the thickness of the structure unless specified

	* Extra parameters for `gearhub`

		hub_height (float):		height of the hub shoulder

	Note:

		- `int_height` impacts the height of the hub unless specified.
		- if `hub_height` is null, there will be no hub.
	"""
	# profile = repeataround(gearprofile(step, teeth, **kwargs), teeth)
	profile = gearprofile(step, teeth, **kwargs)

	# Parts
	exterior = gearexterior(profile, teeth, depth, step, **kwargs)
	ext_int = minmax_radius(exterior.points)[0]
	hub = gearhub(bore_radius, depth, int_height, hub_radius=min(2 * bore_radius, 0.9 * ext_int), **kwargs)
	hub_ext = minmax_radius(hub.points)[1]
	structure = gearstructure(
					pattern,
					0.95 * ext_int,
					max(hub_ext, 0.2 * ext_int),
					depth,
					int_height,
					**kwargs)
	return geargather(exterior, structure, hub)

geargather(exterior, structure, hub)

Gather all parts: exterior, structure, and hub

You can obtain them via the provided functions, or generate them yourself.

Source code in madcad/gear.py
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
def geargather(exterior, structure, hub) -> Mesh:
	"""
	Gather all parts: exterior, structure, and hub

	You can obtain them via the provided functions, or generate them yourself.
	"""
	exterior.mergeclose()
	structure.mergeclose()
	hub.mergeclose()

	# Parameters
	int_e_radius = minmax_radius(exterior.points)[0]

	box = structure.box()
	height_top = box.max.z
	height_bot = box.min.z
	int_radius, ext_radius = minmax_radius(structure.points)

	box = hub.box()
	height_h_top = box.max.z
	height_h_bot = box.min.z
	ext_h_radius = minmax_radius(hub.points)[1]

	assert ext_h_radius * COMPREC <= int_radius
	assert ext_radius * COMPREC <= int_e_radius

	# borderline overlapping check
	prec2 = (4*NUMPREC*ext_radius)**2
	def radius_height(circle):
		p = circle.points[circle.edges[0][0]]
		return vec2(length(p - circle.barycenter()), p.z)
	def samecircle(c1, c2):
		return distance2(radius_height(c1), radius_height(c2)) < prec2

	# select and join all borderlines
	# j1 is the junction between `exterior` and `structure`
	# j2 is the junction between `structure` and `hub`
	top = j1_top = j2_top = bottom = j1_bot = j2_bot = Mesh()

	circle_int_e_top = select(exterior, vec3(0, 0, height_top))
	circle_ext_h_top = select(hub, vec3(ext_h_radius, 0, height_h_top))
	if not samecircle(circle_int_e_top, circle_ext_h_top):
		circle_ext_s_top = select(structure, vec3(ext_radius, 0, height_top))
		circle_int_s_top = select(structure, vec3(int_radius, 0, height_top))

		if not samecircle(circle_ext_s_top, circle_int_e_top):
			j1_top = junction(circle_ext_s_top, circle_int_e_top, tangents="straight", resolution=('div',0))
		if not samecircle(circle_ext_h_top, circle_int_s_top):
			j2_top = junction(circle_ext_h_top, circle_int_s_top, tangents="straight", resolution=('div',0))

		top = j1_top + j2_top

	circle_int_e_bot = select(exterior, vec3(0, 0, height_bot))
	circle_ext_h_bot = select(hub, vec3(ext_h_radius, 0, height_h_bot))
	if not samecircle(circle_int_e_bot, circle_ext_h_bot):
		circle_ext_s_bot = select(structure, vec3(ext_radius, 0, height_bot))
		circle_int_s_bot = select(structure, vec3(int_radius, 0, height_bot))

		if not samecircle(circle_ext_s_bot, circle_int_e_bot):
			j1_bot = junction(circle_ext_s_bot, circle_int_e_bot, tangents="straight", resolution=('div',0))
		if not samecircle(circle_ext_h_bot, circle_int_s_bot):
			j2_bot = junction(circle_ext_h_bot, circle_int_s_bot, tangents="straight", resolution=('div',0))

		bottom = j1_bot + j2_bot

	if isinstance(structure, Web):
		mesh = exterior + top + bottom + hub
	else:
		mesh = exterior + top + structure + bottom + hub
	return mesh.finish() .option(color=settings.colors['gear'])

gearexterior(profile, teeth, depth, step=None, helix_angle=0, chamfer=0, resolution=None, **kwargs)

Generate the external part of the pinion

gearexterior

Parameters:

Name Type Description Default
profile Web

profile of the pinion generated by gearprofile

required
depth float

extrusion eight - width of the gear along its axis

required
step float

step of chordal pitch, must be specified for non-null helix_angle, unused otherwise

None
helix_angle float

helix angle for helical gears - only without filet; filet = False - it must be a radian angle

0
chamfer bool | float | (float, float)

set the parameter of chamfer (angle, ratio) such as angle is the chamfer angle, ratio is where the chamfer is applied (rmin + ratio * (rmax - rmin))

0
Source code in madcad/gear.py
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
def gearexterior(
	profile: Wire,
	teeth,
	depth,
	step=None,
	helix_angle=0,
	chamfer=0,
	resolution=None,
	**kwargs,
) -> Mesh:
	"""
	Generate the external part of the pinion

	![gearexterior](../screenshots/gearexterior.png)

	Parameters:
		profile (Web):			profile of the pinion generated by `gearprofile`
		depth (float):			extrusion eight - width of the gear along its axis
		step (float):			step of chordal pitch, must be specified for non-null helix_angle, unused otherwise
		helix_angle (float):	helix angle for helical gears - only without filet; `filet` = False - it must be a radian angle
		chamfer (bool | float | (float, float)):
			set the parameter of chamfer `(angle, ratio)` such as `angle` is the chamfer angle,
			`ratio` is where the chamfer is applied (`rmin + ratio * (rmax - rmin)`)
	"""

	# Parameters
	rmin, rmax = minmax_radius(profile.points)
	margin = 0.1*(rmax - rmin)
	radial = normalize(profile[0])

	if chamfer:
		if isinstance(chamfer, (tuple, list)):
			chamfer_angle, ratio = chamfer
		elif isinstance(chamfer, float):
			chamfer_angle, ratio = chamfer, 0.5
		elif isinstance(chamfer, bool):
			chamfer_angle, ratio = pi / 8, 0.5
		else:
			raise TypeError('chamfer value must be a tuple, float or bool, not {}'.format(type(chamfer)))
		if chamfer_angle < 0:
			raise ValueError("chamfer angle must be positive.")

		top = wire([
			radial * (rmin - margin),
			radial * mix(rmin, rmax, ratio),
			radial * (rmax + margin) - Z * tan(chamfer_angle) * (ratio*(rmax-rmin) + margin)
			]).segmented()
	else:
		top = wire([
			radial * (rmin - margin),
			radial * (rmax + margin),
			]).segmented()

	top = revolution(top, angle=2*pi/teeth)
	bottom = top.transform(scaledir(Z, -1)) .flip()

	if abs(helix_angle) > pi/2:
		raise ValueError("helix angle absolute value must be below pi/2")
	if helix_angle:  # helical tooth case
		# Step to generate a helical transformation
		angle = depth/rmax * tan(helix_angle)
		step = settings.curve_resolution(
			depth / cos(helix_angle), 
			abs(angle), 
			resolution)
		# Generation of helical gear surface
		transform = lambda x: translate(x*depth*Z) * rotate(x*angle, Z)
		tooth = extrans(profile, map(transform, linrange(0-NUMPREC, 1+NUMPREC, div=step)))
		top = top.transform(transform(1))
	else:  
		# straight tooth case
		transform = depth*Z
		tooth = extrusion(profile, transform)
		top = top.transform(transform)

	# Boolean operation
	flanges = top + bottom
	result = intersection(flanges, tooth).transform(-0.5*depth*Z)
	# Repetition for a complete exterior surface
	return repeataround(result, teeth).finish()

gearstructure(pattern, ext_radius, int_radius, depth, int_height=0, ratio=1, **kwargs)

Generate the internal part of the pinion

gearstructure

Parameters:

Name Type Description Default
ext_radius float

given by the attribut _radius of the result of repeataround - to avoid interference, it must be smaller than _radius (for instance 0.95 * _radius))

required
int_radius float

it is the same radius of the largest radius of the hub part

required
depth float

face width

required
pattern

any of 'full', 'circle', 'rect', 'rounded'

required
int_height float

if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height

0
Source code in madcad/gear.py
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
def gearstructure(
	pattern,
	ext_radius,
	int_radius,
	depth,
	int_height = 0,
	ratio = 1,
	**kwargs,
) -> Mesh:
	"""
	Generate the internal part of the pinion

	![gearstructure](../screenshots/gearstructure.png)

	Parameters:
		ext_radius (float):
			given by the attribut `_radius` of the result of `repeataround` -
			to avoid interference, it must be smaller than `_radius` (for instance 0.95 * `_radius`))
		int_radius (float):	it is the same radius of the largest radius of the hub part
		depth (float):		face width
		pattern:			any of 'full', 'circle', 'rect', 'rounded'
		int_height (float):
			if you want a pinion with a structure thinner than the value of `depth`,
			the total height will be `total_height = depth - 2 * int_height`
	"""
	# int_radius must not be 0
	int_radius = int_radius or 0.1 * ext_radius
	pattern = "full" if ext_radius == int_radius else pattern
	pattern_function = globals()['pattern_' + pattern]
	return pattern_function(ext_radius, int_radius, depth, int_height, ratio=ratio, **kwargs)

gearhub(bore_radius, depth, int_height=0, hub_height=None, hub_radius=None, resolution=None, **kwargs)

Generate a hub for a pinion part

Parameters:

Name Type Description Default
bore_radius float

radius of the central bore

required
depth float

face width; same parameter for gearexterior and gearstructure

required
int_height float

only useful for no hub case, checkout the function gearstructure for more information

0
hub_height float

height of the hub

None
hub_radius float

external radius of the hub

None
Note
  • if bore_radius is null, the function will return a top circle and a bottom circle used for geargather function
  • if hub_height is null, the function will return a structure with a bore and without a hub
Source code in madcad/gear.py
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
def gearhub(
	bore_radius,
	depth,
	int_height = 0,
	hub_height = None,
	hub_radius = None,
	resolution = None,
	**kwargs,
) -> Web:
	"""
	Generate a hub for a pinion part

	Parameters:
		bore_radius (float):	radius of the central bore
		depth (float):			face width; same parameter for `gearexterior` and `gearstructure`
		int_height (float):		only useful for no hub case, checkout the function `gearstructure` for more information
		hub_height (float):		height of the hub
		hub_radius (float):		external radius of the hub

	Note:
		- if `bore_radius` is null, the function will return a top circle and a bottom circle used for `geargather` function
		- if `hub_height` is null, the function will return a structure with a bore and without a hub
	"""
	if not (bore_radius):  # No hub case
		half_depth = depth / 2
		circle_ref = web(Circle((O,Z), depth * 0.1, resolution=resolution))
		circle_ref = triangulation(circle_ref)
		top_surface = circle_ref.transform(vec3(0, 0, half_depth - int_height))
		bottom_surface = circle_ref.transform(vec3(0, 0, -half_depth + int_height)).flip()
		return top_surface + bottom_surface

	if hub_height is None:
		hub_height = bore_radius
	if not (hub_radius):
		hub_radius = 2 * bore_radius
	height = hub_height + depth / 2 if hub_height else depth / 2 - int_height
	axis = (vec3(0, 0, height), vec3(0, 0, 1))
	bore_circle = Circle(axis, bore_radius, resolution=resolution)
	hub_circle = Circle(axis, hub_radius, resolution=resolution)

	# Top part
	top_surface = triangulation(web(bore_circle).flip() + web(hub_circle))

	# Lateral surfaces
	lateral_surfaces = extrusion(web(bore_circle), vec3(0, 0, -hub_height - depth))

	# Bottom part
	axis = (vec3(0, 0, -depth / 2), vec3(0, 0, 1))
	bottom_bore_circle = Circle(axis, bore_radius, resolution=resolution)
	bottom_hub_circle = Circle(axis, hub_radius, resolution=resolution)
	bottom_web = web(bottom_bore_circle) + web(bottom_hub_circle).flip()
	bottom_surface = triangulation(bottom_web)

	return top_surface + bottom_surface + lateral_surfaces

Bevel gear generation

bevelgear(step, teeth, pitch_cone_angle, pressure_angle=pi / 9, ka=1, kd=1.25, helix_angle=None, bore_radius=None, bore_height=None, resolution=None)

Generate a filet gear.

bevelgear

Parameters:

Name Type Description Default
step float

tooth step over the primitive curve, same as the matching rack step the primitive perimeter is step * teeth and radius is step * teeth / (2 * pi)

required
teeth int

number of teeth

required
pitch_cone_angle float

pitch cone angle

required
pressure_angle float

the pressure angle of the tooth

pi / 9
ka (float)

addendum coefficient

required
kd (float)

dedendum coefficient

required
helix_angle float

helix angle of the tooth

None
bore_radius float

radius of the main bore

None
bore_height float

height of the main bore

None
Source code in madcad/gear.py
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
def bevelgear(
	step:float,
	teeth:int,
	pitch_cone_angle:float,
	pressure_angle:float=pi/9,
	ka:float=1,
	kd:float=1.25,
	helix_angle:float=None,
	bore_radius:float=None,
	bore_height:float=None,
	resolution = None,
):
	"""
	Generate a filet gear.

	![bevelgear](../screenshots/bevelgear.png)

	Parameters:
		step (float):
			tooth step over the primitive curve, same as the matching rack step
			the primitive perimeter is `step * teeth` and radius is `step * teeth / (2 * pi)`
		teeth (int):		 			number of teeth
		pitch_cone_angle (float):	pitch cone angle
		pressure_angle (float):		the pressure angle of the tooth
		ka (float) :				addendum coefficient
		kd (float) :				dedendum coefficient
		helix_angle (float):		helix angle of the tooth
		bore_radius (float):   		radius of the main bore
		bore_height (float):   		height of the main bore
	"""
	if helix_angle:
		return helical_bevel_gear(step, teeth, pitch_cone_angle, pressure_angle, ka, kd, helix_angle, 
						bore_radius, bore_height, resolution)
	else:
		return straight_bevel_gear(step, teeth, pitch_cone_angle, pressure_angle, ka, kd, 
						bore_radius, bore_height, resolution)

Helper tools

gearcircles(step, teeth, height=None, offset=0, pressure_angle=radians(20))

return the convenient circles radius for a gear with the given parameters return is (primitive, base, bottom, top)

Source code in madcad/gear.py
217
218
219
220
221
222
223
224
225
226
def gearcircles(step, teeth, height=None, offset=0, pressure_angle=radians(20)):
	''' return the convenient circles radius for a gear with the given parameters
	return is `(primitive, base, bottom, top)`
	'''
	if height is None:
		height = default_height(step, pressure_angle)
	offset = height*offset
	p = step*teeth / (2*pi)	# primitive circle
	c = p * cos(pressure_angle)	# tangent circle to gliding axis
	return p, c, p-height-offset, p+height-offset

involute(c, t0, t)

give a point of parameter t on involute from circle or radius c, starting from t0 on the circle

t and t0 are angular positions

Source code in madcad/gear.py
231
232
233
234
235
236
237
238
def involute(c, t0, t):
	''' give a point of parameter `t` on involute from circle or radius `c`, starting from `t0` on the circle

		`t` and `t0` are angular positions
	'''
	x = vec2(cos(t), sin(t))
	y = vec2(-x[1], x[0])
	return c*(x + y*(t0-t))

involuteat(c, r)

give the parameter for the involute of circle radius c to reach radius r

Source code in madcad/gear.py
240
241
242
def involuteat(c, r):
	''' give the parameter for the involute of circle radius `c` to reach radius `r` '''
	return sqrt((r/c)**2 - 1)

involuteof(c, t0, d, t)

give a point of parameter t on involute with offset, from circle or radius c, starting from t0 on the circle

t and t0 are angular positions

Source code in madcad/gear.py
244
245
246
247
248
249
250
251
def involuteof(c, t0, d, t):
	''' give a point of parameter `t` on involute with offset, from circle or radius `c`, starting from `t0` on the circle

		`t` and `t0` are angular positions
	'''
	x = vec2(cos(t), sin(t))
	y = vec2(-x[1], x[0])
	return (c+d)*x + c*y*(t0-t)

spherical_involute(cone_angle, t0, t)

Return spherical involute function

Parameters:

Name Type Description Default
t float

the angular position

required
t0 float

the difference phase

required
cone_angle float

the cone angle

required
Return

a normalized vec3

Source code in madcad/gear.py
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
def spherical_involute(cone_angle:float, t0:float, t:float) -> vec3:
	"""
	Return spherical involute function

	Parameters:
		t (float): 				the angular position
		t0 (float): 			the difference phase
		cone_angle (float): 	the cone angle

	Return:
		a normalized `vec3`
	"""
	cos_g, sin_g = cos(cone_angle), sin(cone_angle)
	return vec3(
		sin_g * cos(t * sin_g) * cos(t + t0) + sin(t * sin_g) * sin(t + t0),
		sin_g * cos(t * sin_g) * sin(t + t0) - sin(t * sin_g) * cos(t + t0),
		cos_g * cos(t * sin_g),
	)

spherical_involuteof(pitch_cone_angle, t0, pressure_angle, t)

Return the spherical interference function

Parameters:

Name Type Description Default
t float

the angular position

required
t0 float

the difference phase

required
pitch_cone_angle float

the pitch cone angle

required
pressure_angle float

the height angle offset of the rack

required
Return

a normalized vec3

Source code in madcad/gear.py
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
def spherical_involuteof(pitch_cone_angle:float, t0:float, pressure_angle:float, t:float) -> vec3:
	"""
	Return the spherical interference function

	Parameters:
		t (float): 					the angular position
		t0 (float): 				the difference phase
		pitch_cone_angle (float):	the pitch cone angle
		pressure_angle(float): 				the height angle offset of the rack

	Return:
		a normalized `vec3`
	"""
	cos_p, sin_p = cos(pitch_cone_angle), sin(pitch_cone_angle)
	return (
		+ cos(pressure_angle) * spherical_involute(pitch_cone_angle, t0, t) 
		+ sin(pressure_angle) * vec3(-cos_p * cos(t+t0), -cos_p * sin(t+t0), sin_p)
		)

Structure patterns

Those are the functions generating usual structures ready to used in geargather.

pattern_circle(ext_radius, int_radius, depth, int_height=0, ratio=1, patterns=5, circles_radius=None, circles_place=None, **kwargs)

Generate two parts of the structure (the top and the bottom) with patterns distributed on the whole structure.

Return a tuple (Web, Web, Mesh) where the first Web is the top of the structure, the second Web is the bottom of the structure and the last element Mesh is all side surfaces.

Parameters:

Name Type Description Default
ext_radius float

radius of the external border of the structure

required
int_radius float

radius of the internal border of the structure

required
depth float

face width

required
int_height float

if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height

0
ratio float

number that allows to change proportionally the radius of circles

1
patterns int

number of circles of the structure

5
circles_radius float

radius of circles

None
circles_place float

radius where the origins of circles are placed

None
Note
  • For instance, with a ratio of 1.5, the radius of circles circles_radius will be divided by 1.5
  • If circles_radius is chosen, ratio won't impact the radius of circles circles_radius
Source code in madcad/gear.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
def pattern_circle(
	ext_radius,
	int_radius,
	depth,
	int_height = 0,
	ratio = 1,
	patterns: int = 5,
	circles_radius = None,
	circles_place = None,
	**kwargs,
) -> Mesh:
	"""
	Generate two parts of the structure (the top and the bottom) with `patterns` distributed on the whole structure.

	Return a tuple (Web, Web, Mesh) where the first `Web` is the top of the structure,
	the second `Web` is the bottom of the structure and the last element `Mesh` is all side surfaces.

	Parameters:
		ext_radius (float): radius of the external border of the structure
		int_radius (float): radius of the internal border of the structure
		depth (float): face width
		int_height (float): if you want a pinion with a structure thinner than the value of `depth`,
							the total height will be `total_height = depth - 2 * int_height`
		ratio (float): number that allows to change proportionally the radius of circles
		patterns (int): number of circles of the structure
		circles_radius (float): radius of circles
		circles_place (float): radius where the origins of circles are placed

	Note:
		- For instance, with a ratio of 1.5, the radius of circles `circles_radius` will be divided by 1.5
		- If `circles_radius` is chosen, `ratio` won't impact the radius of circles `circles_radius`
	"""
	# Parameters
	half_depth = depth / 2
	if not (circles_radius) and not (circles_place):
		assert 0.5 < ratio, "`ratio` must be in the interval ]0.5; +inf["
	if not circles_place:
		circles_place = (ext_radius + int_radius) / 2
	if not circles_radius:
		circles_radius = (ext_radius - int_radius) / (4 * ratio)

	assert circles_radius / circles_place < sin(pi / patterns), "too many circles for the specified size. Change either 'ratio', 'circle_radius' or 'patterns'"

	Z = vec3(0,0,1)
	axis = (vec3(0,0,0), Z)

	# Borders
	ext_circle = web(Circle(axis, ext_radius))
	int_circle = web(Circle(axis, int_radius)).flip()

	# Pattern
	circle_ref = web(Circle((vec3(circles_place, 0, 0), Z), circles_radius))
	angle = 2 * pi / patterns
	pattern_profile = repeat(circle_ref.flip(), patterns, rotatearound(angle, axis))

	# Profiles and surfaces
	webs_ref = (pattern_profile, ext_circle, int_circle)
	top_webs = [wire.transform(vec3(0, 0, half_depth - int_height)) for wire in webs_ref]
	bottom_webs = [wire.transform(vec3(0, 0, -half_depth + int_height)).flip() for wire in webs_ref]

	top_profile = reduce(add, top_webs)
	bottom_profile = reduce(add, bottom_webs)
	surfaces = extrusion(bottom_webs[0].flip(), vec3(0, 0, depth - 2 * int_height))

	mesh = triangulation(top_profile) + triangulation(bottom_profile) + surfaces
	mesh.mergeclose()
	return mesh

pattern_full(ext_radius, int_radius, depth, int_height=0, **kwargs)

Generate two full parts of the structure (the top and the bottom).

Return a tuple (Web, Web, None) where the first Web is the top of the structure and the second Web is the bottom of the structure.

Parameters:

Name Type Description Default
ext_radius float

float (radius of the external border of the pattern

required
int_radius float

radius of the internal border of the pattern

required
depth float

face width

required
int_height float

if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height

0
Source code in madcad/gear.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
def pattern_full(ext_radius, int_radius, depth, int_height=0, **kwargs) -> Mesh:
	"""
	Generate two full parts of the structure (the top and the bottom).

	Return a tuple (Web, Web, None) where the first `Web` is the top of the structure and
	the second `Web` is the bottom of the structure.

	Parameters:
		ext_radius (float): float (radius of the external border of the pattern
		int_radius (float): radius of the internal border of the pattern
		depth (float): face width
		int_height (float):
			if you want a pinion with a structure thinner than the value of `depth`,
			the total height will be `total_height = depth - 2 * int_height`
	"""
	half_depth = depth / 2
	assert half_depth > int_height, "`int_height` must be smaller than `depth / 2`"

	axis = (O, Z)
	circles_ref = web(Circle(axis, ext_radius)) + web(Circle(axis, int_radius)).flip()
	top_profile = circles_ref.transform(vec3(0, 0, half_depth - int_height))
	bottom_profile = circles_ref.transform(vec3(0, 0, -half_depth + int_height)).flip()
	if ext_radius == int_radius:
		return top_profile + bottom_profile
	mesh = triangulation(top_profile) + triangulation(bottom_profile)
	mesh.mergeclose()
	return mesh

pattern_rect(ext_radius, int_radius, depth, int_height=0, ratio=1, patterns=5, ext_thickness=None, int_thickness=None, **kwargs)

Generate two parts of the structure (the top and the bottom) with patterns distributed on the whole structure. All corners are straight. Check the function pattern_rounded to get rounded corners.

Return a tuple (Web, Web, Mesh) where the first Web is the top of the structure, the second Web is the bottom of the structure and the last element Mesh is all side surfaces.

Parameters:

Name Type Description Default
ext_radius

float (radius of the external border of the structure)

required
int_radius

float (radius of the internal border of the structure)

required
depth

float (face width)

required
int_height

float (if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height)

0
ratio

float (it is a number which is the proportional factor for an homothety of patterns)

1
patterns

int (number of patterns inside the structure)

5
ext_thickness float

internal radius of the pattern

None
int_thickness float

external radius of the pattern

None
Note
  • For instance, if ratio is 1.5, the area of the pattern will be divided by 1.5.
  • If r_int and r_ext are chosen, ratio won't impact these parameters
Source code in madcad/gear.py
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
def pattern_rect(
	ext_radius,
	int_radius,
	depth,
	int_height = 0,
	ratio = 1,
	patterns = 5,
	ext_thickness = None,
	int_thickness = None,
	**kwargs,
) -> Mesh:
	"""
	Generate two parts of the structure (the top and the bottom) with `patterns` distributed on the whole structure.
	All corners are straight. Check the function `pattern_rounded` to get rounded corners.

	Return a tuple (Web, Web, Mesh) where the first `Web` is the top of the structure,
	the second `Web` is the bottom of the structure and the last element `Mesh` is all side surfaces.

	Parameters:
		ext_radius: float (radius of the external border of the structure)
		int_radius: float (radius of the internal border of the structure)
		depth: float (face width)
		int_height: float (if you want a pinion with a structure thinner than the value of `depth`,
							the total height will be `total_height = depth - 2 * int_height`)
		ratio: float (it is a number which is the proportional factor for an homothety of patterns)
		patterns: int (number of patterns inside the structure)
		ext_thickness (float): internal radius of the pattern
		int_thickness (float): external radius of the pattern

	Note:
		- For instance, if `ratio` is 1.5, the area of the pattern will be divided by 1.5.
		- If `r_int` and `r_ext` are chosen, `ratio` won't impact these parameters
	"""
	return create_pattern_rect(ext_radius, int_radius, depth, int_height, ratio, patterns, ext_thickness, int_thickness, False)

pattern_rounded(ext_radius, int_radius, depth, int_height=0, ratio=1, patterns=5, ext_thickness=None, int_thickness=None, **kwargs)

Generate two parts of the structure (the top and the bottom) with patterns distributed on the whole structure. All corners are rounded. Check the function pattern_rect to get straight corners.

Return a tuple (Web, Web, Mesh) where the first Web is the top of the structure, the second Web is the bottom of the structure and the last element Mesh is all side surfaces.

Parameters:

Name Type Description Default
ext_radius

float (radius of the external border of the structure)

required
int_radius

float (radius of the internal border of the structure)

required
depth

float (face width)

required
int_height

float (if you want a pinion with a structure thinner than the value of depth, the total height will be total_height = depth - 2 * int_height)

0
ratio

float (it is a number which is the proportional factor for an homothety of patterns)

1
patterns int

int (number of patterns inside the structure)

5
ext_thickness float

internal radius of the pattern

None
int_thickness float

external radius of the pattern

None
Note
  • For instance, if ratio is 1.5, the area of the pattern will be divided by 1.5.
  • If r_int and r_ext are chosen, ratio won't impact these parameters
Source code in madcad/gear.py
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
def pattern_rounded(
	ext_radius,
	int_radius,
	depth,
	int_height = 0,
	ratio = 1,
	patterns: int = 5,
	ext_thickness = None,
	int_thickness = None,
	**kwargs,
) -> Mesh:
	"""
	Generate two parts of the structure (the top and the bottom) with `patterns` distributed on the whole structure.
	All corners are rounded. Check the function `pattern_rect` to get straight corners.

	Return a tuple (Web, Web, Mesh) where the first `Web` is the top of the structure,
	the second `Web` is the bottom of the structure and the last element `Mesh` is all side surfaces.

	Parameters:
		ext_radius: float (radius of the external border of the structure)
		int_radius: float (radius of the internal border of the structure)
		depth: float (face width)
		int_height: float (if you want a pinion with a structure thinner than the value of `depth`,
							the total height will be `total_height = depth - 2 * int_height`)
		ratio: float (it is a number which is the proportional factor for an homothety of patterns)
		patterns: int (number of patterns inside the structure)
		ext_thickness (float): internal radius of the pattern
		int_thickness (float): external radius of the pattern

	Note:
		- For instance, if `ratio` is 1.5, the area of the pattern will be divided by 1.5.
		- If `r_int` and `r_ext` are chosen, `ratio` won't impact these parameters
	"""
	return create_pattern_rect(ext_radius, int_radius, depth, int_height, ratio, patterns, ext_thickness, int_thickness, True)