# Gear Drawing with Bézier Curves

## Introduction

Spur gear tooth profiles are shaped as circle involute curves. The involute is generated from its base circle as if a taut line were unwound from the circumference, the end of that line would describe a circle involute. The involute is a transcendental function usually drawn by calculating coordinates of many points along the curve and plotting straight line segments between them.

In an effort to simplify the drafting of circular involute functions, Fumitaka Higuchi et al [1] developed a method of approximating the involute using Bézier curves. The result is a smooth, quite accurate approximation, suitable for CAD. The Bézier curve is defined by just a few control points and maintains it shape under 3D transformation. This greatly reduces the computational load required for drafting.

Set out here is a brief description of the Higuchi method, along with a JavaScript implementation. The accuracy of the approximation is calculated and examples of drawing gears with the Bézier curves are shown.

### Circle involute parametric equations

Fig 1 shows a graphical representation of how the involute profile for a gear tooth is generated. Click on the red dot and drag the 'taut' line as it unwraps from the blue base circle. The dot traces out a circle involute.

The Cartesian coordinates of a point on the involute may be expressed in parametric form using the generating angle \( \theta \) as a parameter. Click here to show the construction lines of the derivation (click again to hide them).

From the diagram, point \( x',y' \) is at radius \( R_b \) and angle \( \theta \), therefore:

$$\begin{aligned} x' &= R_b\, \cos(\theta)\\ y' &= R_b\, \sin(\theta) \end{aligned}$$The line c, as it unwinds from the circle, is always tangential to the circumference and the radius \( R_b \) is always perpendicular to c. Therefore:

$$\begin{aligned} x &= x' + c\, \sin(\theta)\\ y &= y' - c\, \cos(\theta) \end{aligned}$$The involute is the locus of the end of a string being 'unwound' from the base circle. This implies:

$$ c' = c = R_b \theta $$Therefore, the parametric equations for the involute, to be approximated with Bézier curves, are:

### Involute gear tooth profile dimensions

The geometry of a gear is set by the following basic factors:

Module value, \( m \),

Number of gear teeth \( Z \),

Pressure angle \( \phi \).

The pitch circle diameter \( D \), involute base circle radius \( R_b \) and addendum circle radius \( R_a \) are related by the formulae:

$$\begin{aligned} D &= m*Z\\ R_b &= D/2 \, \cos(\phi)\\ R_a &= D/2 + m \end{aligned}$$The involute gear profile starts at the base circle and ends where the involute meets the tip circle, also known as the addendum circle. The value of the involute generating parameter \( \theta \) starts at \( 0 \) on the base circle and ends at value, \( \theta_a \), which may be calculated the schematic diagram shown in Fig. 2 as follows:

The Cartesian coordinates of a point on the involute are given at eqn 1. Substituting the polar coordinates of the point, \( (R, \psi) \), results in the expression:

$$\begin{aligned} R \cos(\psi) &= R_b \cos(\theta) + R_b \theta \sin(\theta)\\ R \sin(\psi) &= R_b \sin(\theta) - R_b \theta \cos(\theta) \end{aligned}$$Squaring both sides and adding:

$$\begin{aligned} R^2 &= R_b^2 (1 + \theta^2)\\ \theta &= \frac{\sqrt{R^2 - R_b^2}}{R_b} \end{aligned}$$Hence the value of \( \theta \) at the addendum, the outer radius of the gear teeth, is given by

$$\theta_a = \frac{\sqrt{R_a^2 - R_b^2}}{R_b}$$Also useful in Higuchi's approximation method, is an expression for the distance along the involute, \( s \), as a function of \( \theta \).

$$s(\theta) = \frac{R_b\theta^2}{2} $$## Higuchi *et al* involute approximation method

The first step in the Higuchi method [1] is to approximate the circle involute curve using the Chebyshev approximation formula which expresses the curve as a truncated series of polynomials. This requires mapping θ onto the -1..+1 range expected by the Chebyshev formula. The terms of the series are then recombined to represent the Bernstein polynomial form (the basis of Bézier curves). A further parameter mapping of the Chebyshev parameter onto the 0..1 range for the Bézier parameter is required.

The radius of curvature of the involute varies along its length, starting from zero at its on the base circle. This singularity generates a corresponding singularity in the Bézier approximation, resulting in a double control point at the base circle. Higuchi suggests avoiding this wasted node by beginning the approximation a short distance from the base circle, say 1% of the total length.

Higuchi applies this method to a typical gear, having module, 3mm, 17 teeth and pressure angle 25°. Approximation errors are reported for Bézier approximations of order 4, 6 and 8. These errors are typically a few parts in 10^{6}, 10^{9} and 10^{12} respectively when normalised by the diametral pitch.

### JavaScript implementation

A JavaScript implementation of the Higuchi method was written and the source code is available in the file gearUtils-05.js. This implementation handles any order Bézier curve from 3 upward, with arbitrary start and end points along the involute.

The JavaScript utility provides the function:

involuteBezCoeffs(module, numTeeth, pressureAngle, order, fstart, fstop)

The required parameters are **module**, the metric gear size, and **numTeeth**, the number of teeth. The optional parameters are: **pressureAngle** (defaults to 20°), **order**, the order of the Bézier approximation (defaults to 3), **fstart**, the start offset as a proportion of the involute profile length from start to addendum (defaults to 0.01) and **fstop**, the stop offset as a fraction of the distance to addendum (defaults to 1). The function returns an array of JavaScript objects of the form {x:, y:} representing a x,y coordinates of the Bézier curve nodes. For an order N approximation, there will be N+1 nodes in the array; the start point, N-1 control points and the end point.

### Cubic Bézier approximation

The Higuchi technique would be of great benefit in web based gear modelling if it produced accurate approximations using cubic (order 3) Bézier curves, as the HTML5 canvas element has native support only for quadratic and cubic Bézier curves.

To test the method's performance, a cubic Bézier curve fit was made to a typical gear profile. The specifications of the gear used in the example are the same as used in Higuchi's paper, (module=3, teeth=17, pressureAngle=25). Fig. 3 shows a plot of the cubic Bézier curve approximation to the involute (green line). A piece-wise plot of the true involute, is shown for comparison (magenta line). The Bézier curve control points are shown as crosses.

### Cubic Bézier errors

Table 1 shows the approximation errors for the cubic Bézier approximation to the involute shown in Fig. 3. The errors are calculated at intervals along the involute. Column 1 shows the distance along the profile as a fraction of total length. Column 2 shows the errors as the absolute value of the distance of the point on the approximation to the closest point on the true involute, measured in millimetres. Column 3 shows these error values normalised to the pitch diameter.

Distance along involute |
Error (mm) |
Error/Diametral Pitch |
---|---|---|

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

Using a cubic Bézier curve to approximate the full profile length results in normalised errors of a few parts in 10^{4}. The worst errors occur at the extremities, not accurate enough for gear design work.

## Two cubic Bézier approximation

The solution to reducing the approximation error is to split the involute into two sections fitting a cubic Bézier curve to each. This reduces the errors by an order of magnitude, to just of a few parts in 10^{5}.

The junction point of the two Bézier curves is set 25% along the involute, this helps apportion the curvature to be modelled between the two curves. The first cubic Bézier starts 1% of the way along the involute to avoid the duplicated node at the involute singularity. The start point of the second Bézier coincides with the end point of the first Bézier, so one of these nodes may be discarded. The resulting Bézier approximation has 7 nodes, start, mid and end points and 4 control points.

Here is an example using the 'involuteBezCoeffs' function to generate the two cubic Bézier curves representing a gear profile. The gear parameters are the same as the example in the Higuchi paper.

var module = 3; var teeth = 17; var pressureAngle = 25; var Rpitch = module*teeth/2; var Rb = Rpitch * Math.cos(pressureAngle*Math.PI/180); // base circle radius

// generate Higuchi involute approximation var fs = 0.01; // start 1% off the base circle var fm = 0.25; // break 25% along involute var fe = 1; // end at 100% var dedBz = involuteBezCoeffs(module, teeth, pressureAngle, 3, fs, fm); var addBz = involuteBezCoeffs(module, teeth, pressureAngle, 3, fm, fe); ... // draw the approximation data = ["M", dedBez[0].x, dedBez[0].y, "C", dedBez[1].x, dedBez[1].y, dedBez[2].x, dedBez[2].y, dedBez[3].x, dedBez[3].y, "C", addBez[1].x, addBez[1].y, addBez[2].x, addBez[2].y, addBez[3].x, addBez[3].y]; // draw the involute using Cango library g.drawPath(data, {x:-Rpitch, y:0, strokeColor:'blue'});

Fig. 4 shows a plot of the two cubic Bézier approximation to a circular involute (blue line) calculated by dividing the involute into two sections and fitting a cubic Bézier to each section using the Higuchi-Chebyshev approximation method. For comparison the magenta line is the true involute.

## Two cubic Bézier errors

Table 2 shows the approximation errors at various points along the involute. Column 1 shows the distance along the involute expressed as a fraction of the total length. Column 2 shows the approximation error, the absolute value of distance of a point from a Bézier curve measured in millimetres. Column 3 shows these values normalised to the gear's pitch circle diameter.

Distance along involute |
Error (mm) |
Error/Diametral Pitch |
---|---|---|

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

xx | yy | zz |

**Table 2.** Approximation errors for a two cubic Bézier curve approximation. Each error is the distance to the closest point on the true involute.

The two cubic Bézier approximation provides a quick, accurate method of drawing involute gear teeth suitable for 3D manipulation.

## Drawing an spur gear tooth with Cango

Having established the profile of the tooth face, the full tooth shape may be generated by the addition of an arc across the tip of the tooth, the mirror image of the tooth profile and then root fillets and the arc across the root circle to the next tooth.

The angular spacing between teeth, pitch angle, for a gear with Z teeth is:

pitch angle = \( 2\pi/Z \)

Drawing involute profiles is simplified by using the polar coordinate form of the involute equation. This expression is readily determined from Fig. 2:

Using the cosine rule of the triangle in Fig. 2:

$$\begin{aligned} R_b^2 + R^2 - 2R_b\, R\, \cos(\theta - \psi) &= c^2\\ &= R^2 - R_b^2\\ \cos(\theta - \psi) &= \frac{R_b}{R} \end{aligned}$$Since \(c = R_b \theta\)

$$ \psi(R) = \frac{\sqrt{R^2 - R_b^2}}{R_b} - \cos^{-1}(\frac{R_b}{R}) $$Shown below is the JavaScript source code to create a set of drawing commands for a single gear tooth outline. The output of this function is an array of drawing commands in SVG format that can be used to create a Cango Path object representing the outline of a single gear tooth. This Cango object can be duplicated and rotated and appended to create all the teeth on a gear. This code is included in the 'gearUtils' file.

createGearTooth = function(module, teeth, pressureAngle) { function genInvolutePolar(Rb, R) // Rb = base circle radius { // returns the involute angle as function of radius R. return (Math.sqrt(R*R - Rb*Rb)/Rb) - Math.acos(Rb/R); } function rotate(pt, rads) // rotate pt by rads radians about origin { var sinA = Math.sin(rads); var cosA = Math.cos(rads); return {x: pt.x*cosA - pt.y*sinA, y: pt.x*sinA + pt.y*cosA}; } function toCartesian(radius, angle) // convert polar coords to cartesian { return {x: radius*Math.cos(angle), y: radius*Math.sin(angle)}; } // ****** external gear specifications var m = module, // Module = mm of pitch diameter per tooth Z = teeth, // Number of teeth phi = pressureAngle || 20, // pressure angle (degrees) addendum = m, // pitch circle to tip circle distance dedendum = 1.25*m, // pitch circle to root, sets clearance clearance = dedendum - addendum, // Calculate radii Rpitch = Z*m/2, // pitch circle radius Rb = Rpitch*Math.cos(phi*Math.PI/180), // base circle radius Ra = Rpitch + addendum, // tip (addendum) circle radius Rroot = Rpitch - dedendum, // root circle radius fRad = 1.5*clearance, // fillet radius, max 1.5*clearance Rf, // radius at top of fillet // ****** calculate angles (all in radians) pitchAngle = 2*Math.PI/Z, // angle subtended by whole tooth (rads) baseToPitchAngle = genInvolutePolar(Rb, Rpitch), pitchToFilletAngle = baseToPitchAngle, // profile starts at base circle filletAngle = Math.atan(fRad/(fRad+Rroot)), // radians fe, fs, fm, dedBz, addBz, inv, invR, fillet, filletR, filletNext, rootR, rootNext, pt, i, data; Rf = Math.sqrt((Rroot+fRad)*(Rroot+fRad)-(fRad*fRad)); // radius at top of fillet if (Rb < Rf) { Rf = Rroot+clearance; } if (Rf > Rb) // start profile at top of fillet (if its greater) { pitchToFilletAngle -= genInvolutePolar(Rb, Rf); } // ****** generate Higuchi involute approximation fe = 1; // fraction of profile length at end of approx fs = 0.01; // fraction of length offset from base to avoid singularity if (Rf > Rb) { fs = (Rf*Rf-Rb*Rb)/(Ra*Ra-Rb*Rb); // offset start to top of fillet } // approximate in 2 sections, split 25% along the involute fm = fs+(fe-fs)/4; // fraction of length at junction (25% along profile) dedBz = involuteBezCoeffs(m, Z, phi, 3, fs, fm); addBz = involuteBezCoeffs(m, Z, phi, 3, fm, fe); // join the 2 sets of coeffs (skip duplicate mid point) inv = dedBz.concat(addBz.slice(1)); //create the back profile of tooth (mirror image) invR = []; // involute profile along back of tooth for (i=0; i<inv.length; i++) { // rotate all points to put pitch point at y = 0 pt = rotate(inv[i], -baseToPitchAngle-pitchAngle/4); inv[i] = pt; // generate the back of tooth profile nodes, mirror coords in X axis invR[i] = {x:pt.x, y:-pt.y}; } // ****** calculate section junction points R=back of tooth, Next=front of next tooth) fillet = toCartesian(Rf, -pitchAngle/4-pitchToFilletAngle); // top of fillet filletR = {x:fillet.x, y:-fillet.y}; // flip to make same point on back of tooth rootR = toCartesian(Rroot, pitchAngle/4+pitchToFilletAngle+filletAngle); rootNext = toCartesian(Rroot, 3*pitchAngle/4-pitchToFilletAngle-filletAngle); filletNext = rotate(fillet, pitchAngle); // top of fillet, front of next tooth // ****** create the drawing command data array for the tooth data = []; data.push("M", fillet.x, fillet.y); // start at top of fillet if (Rf < Rb) { data.push("L", inv[0].x, inv[0].y); // line from fillet up to base circle } data.push("C", inv[1].x, inv[1].y, inv[2].x, inv[2].y, inv[3].x, inv[3].y, inv[4].x, inv[4].y, inv[5].x, inv[5].y, inv[6].x, inv[6].y); data.push("A", Ra, Ra, 0, 0, 0, invR[6].x, invR[6].y); // arc across addendum circle data.push("C", invR[5].x, invR[5].y, invR[4].x, invR[4].y, invR[3].x, invR[3].y, invR[2].x, invR[2].y, invR[1].x, invR[1].y, invR[0].x, invR[0].y); if (Rf < Rb) { data.push("L", filletR.x, filletR.y); // line down to top of fillet } if (rootNext.y > rootR.y) // is there a section of root circle between fillets? { data.push("A", fRad, fRad, 0, 0, 1, rootR.x, rootR.y);// back fillet data.push("A", Rroot, Rroot, 0, 0, 0, rootNext.x, rootNext.y); // root circle arc } data.push("A", fRad, fRad, 0, 0, 1, filletNext.x, filletNext.y); return data; // return an array of Cango (SVG) format draw commands };

## Drawing gears with Cango

To create the outline of a full gear from the profile of the tooth, the Cango Path object representing one tooth is created, this is then duplicated, rotated by the pitch angle and appended to the gear object to make each of the gear's teeth. This gear outline then has a circular axle shaft hole appended, its then ready to be rendered to the screen and animated. The code snippet to create a gear using Cango is shown below:

var m = module, // Module = mm of pitch diameter per tooth Zg = gearTeeth, phi = pressureAngle || 20, Rg = Zg*m/2; // gear Pitch radius // generate gear data = createGearTooth(m, Zg, phi); gearTooth = new Shape(data, { fillColor:"#ddd0dd", border: true, strokeColor: "#606060" }); gear = gearTooth.dup(); for (i=1; i<Zg; i++) { newTooth = gearTooth.dup(); newTooth.rotate(360*i/Zg); gear.appendPath(newTooth, true); // trim move command = true } gear.rotate(180/Zg); // rotate gear 1/2 tooth to mesh // add axle hole Dsg = 0.6*Rg; // diameter of gear shaft shaft = new Path(shapeDefs.circle(Dsg)); shaft.revWinding(); gear.appendPath(shaft); // retain the 'moveTo' command for shaft sub path

### Adding backlash when drawing meshed gears

In practical gearing there is always a gap between the non-drive face of the pinion tooth and the adjacent wheel tooth to prevent gears from jamming. This gap is termed backlash. If the direction of rotation is reversed, there is a period during which the pinion moves independently until the backlash gap is taken up and gear tooth contact re-established.

Backlash may be created by cutting the gear spaces a little deeper, so the gaps are wider than the teeth, this method is preferred for stock gears. Alternatively, backlash may be introduced by increasing the center distance between the gears. This separation does not affect the speed ratio between the gears or require any alteration to the gear tooth profile.

Recommended backlash is:

backlash = 0.04*ModuleTo create this backlash the center distance is increased by ΔC where:

ΔC = backlash/2 * tan(phi);

Fig. 5 shows a pair of gears with module value of 5 mm. The pinion has 24 teeth and the gear 52, the pressure angle is 20°. The involute profiles were calculated using the 2 cubic Bézier approximation. Backlash of 0.2 mm was added by increasing the center distance by 0.275 mm.

## Internal gear drawing example

Internal gears, or ring gears, may be drawn with similar efficiency. Fig. 6 shows an internal gear and pinion with module value of 5 mm. The pinion has 22 teeth and the ring gear 42, the pressure angle is 20°. The involute profiles were calculated using the 2 cubic Bézier approximation. Backlash of 0.2 mm was added by increasing the center distance.

The Higuchi method has proven to be applicable to gear drawing on the HTML5 canvas element despite the limitation to order 3 Bézier approximation that the canvas imposes. All the source code used on this page is released free for non-commercial use.

**References:**

1. F.Higuchi, S. Gofuku, T. Maekawa, H. Mukundan, N.M. Patrikalakis, "Approximation of Involute Curves for CAD-System
Processing"
*YNU Digital Eng Lab Memorandum 05-1* 2006.

2. G.M.Maitra, Handbook of Gear Design, 1994