/*==========================================================================
Filename: gearUtils-09.js
By: Dr A.R.Collins
JavaScript involute gear drawing utilities.
Requires:
'involuteBezCoeffs' can stand alone,
'createGearTooth' and 'createIntGearTooth' generate SVG path data draw
commands defing the gear tooth profile.
Kindly give credit to Dr A.R.Collins
Report bugs to tony at arc.id.au
Date |Description |By
--------------------------------------------------------------------------
20Feb13 First public release ARC
21Feb13 Clarified variable names of start and end parameters ARC
06Mar13 Fixed Rf and filletAngle calculations ARC
25Jun13 Code tidy for JSLint, use strict ARC
16Mar15 Convert sweep direction of "A" commands for RHC coordinates ARC
05Apr19 Add createGearOutline and createIntGearOutline ARC
06Apr19 Added shaft circle to the outline path data ARC
==========================================================================*/
// exposed globals
var involuteBezCoeffs,
createGearTooth, createIntGearTooth,
createGearOutline, createIntGearOutline;
(function()
{
"use strict";
/* ----------------------------------------------------------
* involuteBezCoeffs
*
* JavaScript calculation of Bezier coefficients for
* Higuchi et al. approximation to an involute.
* ref: YNU Digital Eng Lab Memorandum 05-1
*
* Parameters:
* module - sets the size of teeth (see gear design texts)
* numTeeth - number of teeth on the gear
* pressure angle - angle in degrees, usually 14.5 or 20
* order - the order of the Bezier curve to be fitted [3, 4, 5, ..]
* fstart - fraction of distance along tooth profile to start
* fstop - fraction of distance along profile to stop
*-----------------------------------------------------------*/
involuteBezCoeffs = function(module, numTeeth, pressureAngle, order, fstart, fstop)
{
var PI = Math.PI,
Rpitch = module*numTeeth/2, // pitch circle radius
phi = pressureAngle || 20, // pressure angle
Rb = Rpitch*Math.cos(phi*PI/180), // base circle radius
Ra = Rpitch+module, // addendum radius (outer radius)
p = order || 3, // order of Bezier approximation
ta = Math.sqrt(Ra*Ra-Rb*Rb)/Rb, // involute angle at addendum
stop = fstop || 1,
start = 0.01,
te, ts,
bzCoeffs = [],
i, bcoeff;
function chebyExpnCoeffs(j, func)
{
var N = 50, // a suitably large number N>>p
c = 0,
k;
for (k=1; k<=N; k++)
{
c += func(Math.cos(PI*(k-0.5)/N)) * Math.cos(PI*j*(k-0.5)/N);
}
return 2*c/N;
}
function chebyPolyCoeffs(p, func)
{
var coeffs = [],
fnCoeff = [],
T = [[], []],
i, j, k, pwr;
// populate 1st 2 rows of T
for (i=0; i
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 rootR.y) // is there a section of root circle between fillets?
{
data.push("A", fRad, fRad, 0, 0, 0, rootR); // back fillet, sweep 0 for RHC, 1 for SVG
data.push("A", Rroot, Rroot, 0, 0, 1, rootNext); // root circle arc, sweep 1 for RHC, 0 for SVG
}
data.push("A", fRad, fRad, 0, 0, 0, filletNext); // sweep 0 for RHC, 1 for SVG
return data; // return an array of pseudo SVG path data
}
createGearTooth = function(module, teeth, pressureAngle, rotRads)
{
// ****** external gear specifications
var m = module, // Module = mm of pitch diameter per tooth
Z = teeth, // Number of teeth
phi = pressureAngle || 20, // pressure angle (degrees)
rot = rotRads || 0,
pt,
inData = genGearToothData(m, Z, phi), // generate the tooth profile
outData = [],
i;
// apply arbitrary rotation "rot" to each data point
for (i=0; i Rb)
{
tipToPitchAngle -= genInvolutePolar(Rb, Ra); // start profile from addendum
}
pitchToFilletAngle = genInvolutePolar(Rb, Rf) - baseToPitchAngle;
filletAngle = 1.414*clearance/Rf; // to make fillet tangential to root
// ****** generate Higuchi involute approximation
fe = 1; // fraction of involute length at end of approx (fillet circle)
fs = 0.01; // fraction of length offset from base to avoid singularity
if (Ra > Rb)
{
fs = (Ra*Ra-Rb*Rb)/(Rf*Rf-Rb*Rb); // start profile from addendum (tip circle)
}
// approximate in 2 sections, split 25% along the profile
fm = fs+(fe-fs)/4; //
addBz = involuteBezCoeffs(m, Z, phi, 3, fs, fm);
dedBz = involuteBezCoeffs(m, Z, phi, 3, fm, fe);
// join the 2 sets of coeffs (skip duplicate mid point)
invR = addBz.concat(dedBz.slice(1));
//create the front profile of tooth (mirror image)
inv = []; // back involute profile
for (i=0; i0)
{
r = shaftRadius;
gearData.push("M",-r,0, "a", r,r, 0,1,0, r*2,0, "a", r,r, 0,1,0, -r*2,0, "z");
}
return gearData;
};
createIntGearOutline = function(module, teeth, pressureAngle, rimRadius)
{
var m = module, // Module = mm of pitch diameter per tooth
Z = teeth, // Number of teeth
phi = pressureAngle || 20, // pressure angle (degrees)
toothData = genIntGearToothData(m, Z, phi), // generate the tooth profile
rotToothData,
gearData,
r,
i;
rotToothData = rotateTooth(toothData); // convert the first tooth into SVG dta format
gearData = [].concat(rotToothData); // add the unrotated first tooth (including initial "M",x,y)
for (i=1; i0)
{
r = rimRadius;
gearData.push("M", -r,0, "a", r,r, 0,1,0, r*2,0, "a", r,r, 0,1,0, -r*2,0, "z");
}
return gearData;
};
}());