2 This page is in the table of contents.
3 The gear script can generate a spur gear couple, a bevel gear couple, a ring gear couple and a rack & pinion couple.
5 A helix pattern can be added to each gear type. All the gear types have a clearance and all the teeth can be beveled. A keyway, shaft and lightening holes can be added to all the round gears, and rack holes can be added to the rack. The script can output solid gears or only the gear profiles. Both gears of the couple can be generated or just one.
7 The couple has a pinion gear and a complement.
10 The link text includes the distinguishing parameters. Each svg page was generated from an xml page of the same root name using carve. For example, gear.svg was generated by clicking 'Carve' on the carve tool panel and choosing gear.xml in the file chooser.
12 Each generated svg file has the xml fabmetheus element without comments towards the end of the file. To see it, open the svg file in a text editor and search for 'fabmetheus' If you copy that into a new text document, add the line '<?xml version='1.0' ?>' at the beginning and then give it a file name with the extension '.xml', you could then generate another svg file using carve.
17 <a href='../models/xml_models/creation/gear/bevel.svg'>gear operatingAngle=90</a>
20 Spur gear couple and each gear has a collar.
22 <a href='../models/xml_models/creation/gear/collar.svg'>gear complementCollarLengthOverFaceWidth='1' pinionCollarLengthOverFaceWidth='1' shaftRadius='5'</a>
25 Default spur gear with no parameters.
27 <a href='../models/xml_models/creation/gear/gear.svg'>gear</a>
30 Spur gear couple and each gear has a collar and defined keyway.
32 <a href='../models/xml_models/creation/gear/keyway.svg'>gear complementCollarLengthOverFaceWidth='1' keywayRadius='2' pinionCollarLengthOverFaceWidth='1' shaftRadius='5'</a>
35 Rack and pinion couple.
37 <a href='../models/xml_models/creation/gear/rack.svg'>gear teethComplement='0'</a>
40 Rack and pinion couple, with holes in the rack.
42 <a href='../models/xml_models/creation/gear/rack_hole.svg'>gear rackHoleRadiusOverWidth='0.2' rackWidthOverFaceWidth='2' teethComplement='0'</a>
47 <a href='../models/xml_models/creation/gear/ring.svg'>gear teethComplement='-23'</a>
50 Spur gear couple and each gear has a square shaft hole.
52 <a href='../models/xml_models/creation/gear/shaft.svg'>gear shaftRadius='5'</a>
55 Spur gear couple and each gear has a round shaft hole, truncated on top.
57 <a href='../models/xml_models/creation/gear/shaft_top.svg'>gear shaftRadius='5' shaftSides='13' shaftDepthTop='2'</a>
60 Spur gear couple with the gear teeth following a helix path.
62 <a href='../models/xml_models/creation/gear/spur_helix.svg'>gear helixAngle='45'</a>
64 ===Spur Herringbone===
65 Spur gear couple with the gear teeth following a herringbone path.
67 <a href='../models/xml_models/creation/gear/spur_herringbone.svg'>gear helixAngle='45' helixType='herringbone'</a>
70 Spur gear couple with the gear teeth following a parabolic path.
72 <a href='../models/xml_models/creation/gear/spur_parabolic.svg'>gear helixAngle='45' helixType='parabolic'</a>
75 Spur gear couple profile. Since this is just a horizontal path, it can not be sliced, so the path is then extruded to create a solid which can be sliced and viewed.
77 <a href='../models/xml_models/creation/gear/spur_profile.svg'>gear id='spurProfile' faceWidth='0' | extrude target='=document.getElementByID(spurProfile)</a>
81 Default is such that the pitch radius works out to twenty.
83 Defines the distance between the gear centers.
85 ===Clearance Couplet===
86 ====Clearance Over Wavelength====
89 Defines the ratio of the clearance over the wavelength of the gear profile. The wavelength is the arc distance between the gear teeth.
92 Default is the 'Clearance Over Wavelength' times the wavelength.
94 Defines the clearance between the gear tooth and the other gear of the couple. If the clearance is zero, the outside of the gear tooth will touch the other gear. If the clearance is too high, the gear teeth will be long and weak.
96 ===Collar Addendum Couplet===
97 ====Collar Addendum Over Radius====
100 Defines the ratio of the collar addendum over the shaft radius.
102 ====Collar Addendum====
103 Default is the 'Collar Addendum Over Radius' times the shaft radius.
105 Defines the collar addendum.
107 ===Complement Collar Length Couplet===
108 ====Complement Collar Length Over Face Width====
111 Defines the ratio of the complement collar length over the face width.
113 ====Complement Collar Length====
114 Default is the 'Complement Collar Length Over Face Width' times the face width.
116 Defines the complement collar length. If the complement collar length is zero, there will not be a collar on the complement gear.
122 When selected, the pinion and complement will be generated.
125 When selected, only the complement gear or rack will be generated.
128 When selected, only the pinion will be generated.
133 Defines the face width.
135 ===Gear Hole Paths===
138 Defines the centers of the gear holes. If the gear hole paths parameter is the default empty, then the centers of the gear holes will be generated from other parameters.
146 Defines the helix path of the gear teeth. If the helix path is the default empty, then the helix will be generated from the helix angle and helix type.
152 When selected, the helix will be basic.
155 When selected, the helix will have a herringbone pattern.
158 When selected, the helix will have a parabolic pattern.
160 ===Keyway Radius Couplet===
161 ====Keyway Radius Over Radius====
164 Defines the ratio of the keyway radius over the shaft radius.
166 ====Keyway Radius====
167 Default is the 'Keyway Radius Over Radius' times the shaft radius.
169 Defines the keyway radius. If the keyway radius is zero, there will not be a keyway on the collar.
171 ===Lightening Hole Margin Couplet===
172 ====Lightening Hole Margin Over Rim Dedendum====
175 Defines the ratio of the lightening hole margin over the rim dedendum.
177 ====Lightening Hole Margin====
178 Default is the 'Lightening Hole Margin Over Rim Dedendum' times the rim dedendum.
180 Defines the minimum margin between lightening holes.
182 ===Lightening Hole Minimum Radius===
185 Defines the minimum radius of the lightening holes.
188 Default is 'separate'.
191 When selected, the gears will be not be moved and will therefore overlap. Afterwards the write plugin could be used to write each gear to a different file, so they can be fabricated in separate operations.
194 When selected, the gears will be separated horizontally so that they just mesh. This is useful to test if the gears mesh properly.
197 When selected, the gears will be separated horizontally with a gap between them.
200 When selected, the gears will be separated vertically.
202 ===Operating Angle===
203 Default is 180 degrees.
205 Defines the operating angle between the gear axes. If the operating angle is not 180 degrees, a bevel gear couple will be generated.
207 ===Pinion Collar Length Couplet===
208 ====Pinion Collar Length Over Face Width====
211 Defines the ratio of the pinion collar length over the face width.
213 ====Pinion Collar Length====
214 Default is the 'Pinion Collar Length Over Face Width' times the face width.
216 Defines the pinion collar length. If the pinion collar length is zero, there will not be a collar on the pinion gear.
219 Default is twenty if the pitch radius has not been set. If the center distance is set, the default pitch radius is the center distance times the number of pinion teeth divided by the total number of gear teeth.
221 Defines the pinion pitch radius.
223 ===Plate Clearance Couplet===
224 ====Plate Clearance Over Length====
227 Defines the ratio of the plate clearance over the plate length.
229 ====Plate Clearance====
230 Default is the 'Plate Clearance Over Length' times the plate length.
232 Defines the clearance between the pinion and the plate of the ring gear. If the clearance is zero, they will touch.
234 ===Plate Length Couplet===
235 ====Plate Length Over Face Width====
238 Defines the ratio of the plate length over the face width.
241 Default is the 'Plate Length Over Face Width' times the face width.
243 Defines the length of the plate of the ring gear.
246 Default is twenty degrees.
248 Defines the pressure angle of the gear couple.
250 ===Profile Surfaces===
253 Defines the number of profile surfaces.
255 ===Rack Hole Below Over Width Couplet===
256 ====Rack Hole Below Over Width====
259 Defines the ratio of the distance below the pitch of the rack holes over the rack width.
261 ====Rack Hole Below====
262 Default is the 'Rack Hole Below Over Width' times the rack width.
264 Defines the the distance below the pitch of the rack holes.
266 ===Rack Hole Radius Couplet===
267 ====Rack Hole Radius Over Width====
270 Defines the ratio of the rack hole radius over the rack width.
272 ====Rack Hole Radius====
273 Default is the 'Rack Hole Radius Over Width' times the rack width.
275 Defines the radius of the rack holes. If the rack hole radius is zero, there won't be any rack holes.
277 ===Rack Hole Step Over Width Couplet===
278 ====Rack Hole Step Over Width====
281 Defines the ratio of the rack hole step over the rack width.
283 ====Rack Hole Step====
284 Default is the 'Rack Hole Step Over Width' times the rack width.
286 Defines the horizontal step distance between the rack holes.
288 ===Rack Length Over Radius Couplet===
289 ====Rack Length Over Radius====
290 Default is two times pi.
292 Defines the ratio of the rack length over the pitch radius.
295 Default is the 'Rack Length Over Radius' times the pitch radius.
297 Defines the rack length.
299 ===Rack Width Couplet===
300 ====Rack Width Over Face Width====
303 Defines the ratio of the rack width over the face width.
306 Default is the 'Rack Width Over Face Width' times the face width.
308 Defines the rack width.
310 ===Rim Dedendum Couplet===
311 ====Rim Dedendum Over Radius====
314 Defines the ratio of the rim dedendum over the pitch radius.
317 Default is the 'Rim Dedendum Over Radius' times the pitch radius.
319 Defines the rim dedendum of the gear.
321 ===Root Bevel Couplet===
322 ====Root Bevel Over Clearance====
325 Defines the ratio of the root bevel over the clearance.
328 Default is the 'Root Bevel Over Clearance' times the clearance.
330 Defines the bevel at the root of the gear tooth.
332 ===Shaft Depth Bottom Couplet===
333 ====Shaft Depth Bottom Over Radius====
336 Defines the ratio of the bottom shaft depth over the shaft radius.
338 ====Shaft Depth Bottom====
339 Default is the 'Shaft Depth Bottom Over Radius' times the shaft radius.
341 Defines the bottom shaft depth.
343 ===Shaft Depth Top Couplet===
344 ====Shaft Depth Top Over Radius====
347 Defines the ratio of the top shaft depth over the shaft radius.
349 ====Shaft Depth Top====
350 Default is the 'Shaft Depth Top Over Radius' times the shaft radius.
352 Defines the top shaft depth.
357 Defines the path of the shaft hole. If the shaft path is the default empty, then the shaft path will be generated from the shaft depth bottom, shaft depth top, shaft radius and shaft sides.
359 ===Shaft Radius Couplet===
360 ====Shaft Radius Over Pitch Radius====
363 Defines the ratio of the shaft radius over the pitch radius.
366 Default is the 'Shaft Radius Over Pitch Radius' times the pitch radius.
368 Defines the shaft radius. If the shaft radius is zero there will not be a shaft hole.
373 Defines the number of shaft sides.
378 Defines the number of teeth in the pinion.
380 ===Teeth Complement===
381 Default is seventeen.
383 Defines the number of teeth in the complement of the gear couple. If the number of teeth is positive, the gear couple will be a spur or bevel type. If the number of teeth is zero, the gear couple will be a rack and pinion. If the number of teeth is negative, the gear couple will be a spur and ring.
385 ===Tip Bevel Couplet===
386 ====Tip Bevel Over Clearance====
389 Defines the ratio of the tip bevel over the clearance.
392 Default is the 'Tip Bevel Over Clearance' times the clearance.
394 Defines the bevel at the tip of the gear tooth.
396 ===Tooth Thickness Multiplier===
399 Defines the amount the thickness of the tooth will multiplied. If when the gears are produced, they mesh too tightly, you can reduce the tooth thickness multiplier so that they mesh with reasonable tightness.
403 from __future__ import absolute_import
405 from fabmetheus_utilities.geometry.creation import extrude
406 from fabmetheus_utilities.geometry.creation import lineation
407 from fabmetheus_utilities.geometry.creation import shaft
408 from fabmetheus_utilities.geometry.creation import solid
409 from fabmetheus_utilities.geometry.creation import teardrop
410 from fabmetheus_utilities.geometry.geometry_tools import path
411 from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
412 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
413 from fabmetheus_utilities.geometry.geometry_utilities import matrix
414 from fabmetheus_utilities.geometry.solids import triangle_mesh
415 from fabmetheus_utilities.vector3 import Vector3
416 from fabmetheus_utilities.vector3index import Vector3Index
417 from fabmetheus_utilities import euclidean
421 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
422 __credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
423 __date__ = '$Date: 2008/02/05 $'
424 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
427 def addBevelGear(derivation, extrudeDerivation, pitchRadius, positives, teeth, vector3GearProfile):
428 "Get extrude output for a cylinder gear."
429 totalPitchRadius = derivation.pitchRadiusComplement + derivation.pitchRadius
430 totalTeeth = derivation.teethPinion + derivation.teethComplement
431 portionDirections = extrude.getSpacedPortionDirections(extrudeDerivation.interpolationDictionary)
432 loopLists = extrude.getLoopListsByPath(extrudeDerivation, None, vector3GearProfile[0], portionDirections)
433 firstLoopList = loopLists[0]
434 gearOverPinion = float(totalTeeth - teeth) / float(teeth)
435 thirdLayerHeight = 0.33333333333 * setting.getLayerHeight(derivation.elementNode)
436 pitchRadian = math.atan(math.sin(derivation.operatingRadian) / (gearOverPinion + math.cos(derivation.operatingRadian)))
437 coneDistance = pitchRadius / math.sin(pitchRadian)
438 apex = Vector3(0.0, 0.0, math.sqrt(coneDistance * coneDistance - pitchRadius * pitchRadius))
439 cosPitch = apex.z / coneDistance
440 sinPitch = math.sin(pitchRadian)
441 for loop in firstLoopList:
443 alongWay = point.z / coneDistance
444 oneMinusAlongWay = 1.0 - alongWay
445 pointComplex = point.dropAxis()
446 pointComplexLength = abs(pointComplex)
447 deltaRadius = pointComplexLength - pitchRadius
448 cosDeltaRadius = cosPitch * deltaRadius
449 sinDeltaRadius = sinPitch * deltaRadius
450 pointComplex *= (cosDeltaRadius + pitchRadius) / pointComplexLength
451 point.x = pointComplex.real
452 point.y = pointComplex.imag
453 point.z += sinDeltaRadius
454 point.x *= oneMinusAlongWay
455 point.y *= oneMinusAlongWay
456 addBottomLoop(-thirdLayerHeight, firstLoopList)
457 topLoop = firstLoopList[-1]
459 topZ = euclidean.getTopPath(topLoop) + thirdLayerHeight
460 oldIndex = topLoop[-1].index
461 for point in topLoop:
463 topAddition.append(Vector3Index(oldIndex, 0.8 * point.x, 0.8 * point.y, topZ))
464 firstLoopList.append(topAddition)
465 translation = Vector3(0.0, 0.0, -euclidean.getBottomByPaths(firstLoopList))
466 euclidean.translateVector3Paths(firstLoopList, translation)
467 geometryOutput = triangle_mesh.getPillarsOutput(loopLists)
468 positives.append(geometryOutput)
470 def addBottomLoop(deltaZ, loops):
471 "Add bottom loop to loops."
472 bottomLoop = loops[0]
474 bottomZ = euclidean.getBottomByPath(bottomLoop) + deltaZ
475 for point in bottomLoop:
476 bottomAddition.append(Vector3Index(len(bottomAddition), point.x, point.y, bottomZ))
477 loops.insert(0, bottomAddition)
481 point.index = numberOfVertexes
482 numberOfVertexes += 1
484 def addCollarShaft(collarLength, derivation, elementNode, negatives, positives):
486 if collarLength <= 0.0:
487 addShaft(derivation, negatives, positives)
489 connectionEnd = Vector3(0.0, 0.0, derivation.faceWidth + collarLength)
490 copyShallow = derivation.elementNode.getCopyShallow()
491 copyShallow.attributes['path'] = [Vector3(0.0, 0.0, derivation.faceWidth), connectionEnd]
492 collarDerivation = extrude.ExtrudeDerivation(copyShallow)
493 addCollarShaftSetDerivation(collarDerivation, collarLength, derivation, elementNode, negatives, positives)
495 def addCollarShaftSetDerivation(collarDerivation, collarLength, derivation, elementNode, negatives, positives):
496 'Add collar and shaft.'
497 collarSides = evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, derivation.shaftRimRadius)
498 collarProfile = euclidean.getComplexPolygon(complex(), derivation.shaftRimRadius, collarSides)
499 vector3CollarProfile = euclidean.getVector3Path(collarProfile)
500 extrude.addPositives(collarDerivation, [vector3CollarProfile], positives)
501 addShaft(derivation, negatives, positives)
502 drillZ = derivation.faceWidth + 0.5 * collarLength
503 drillEnd = Vector3(0.0, derivation.shaftRimRadius, drillZ)
504 drillStart = Vector3(0.0, 0.0, drillZ)
505 teardrop.addNegativesByRadius(elementNode, drillEnd, negatives, derivation.keywayRadius, drillStart)
507 def addLighteningHoles(derivation, gearHolePaths, negatives, pitchRadius, positives):
508 "Add lightening holes."
509 positiveVertexes = matrix.getVertexes(positives)
510 bottomPath = euclidean.getTopPath(positiveVertexes)
511 topPath = euclidean.getBottomByPath(positiveVertexes)
512 copyShallow = derivation.elementNode.getCopyShallow()
513 copyShallow.attributes['path'] = [Vector3(0.0, 0.0, bottomPath), Vector3(0.0, 0.0, topPath)]
514 extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
515 vector3LighteningHoles = getLighteningHoles(derivation, gearHolePaths, pitchRadius)
516 extrude.addNegativesPositives(extrudeDerivation, negatives, vector3LighteningHoles, positives)
518 def addRackHole(derivation, elementNode, vector3RackProfiles, x):
519 "Add rack hole to vector3RackProfiles."
520 rackHole = euclidean.getComplexPolygon(complex(x, -derivation.rackHoleBelow), derivation.rackHoleRadius, -13)
521 vector3RackProfiles.append(euclidean.getVector3Path(rackHole))
523 def addRackHoles(derivation, elementNode, vector3RackProfiles):
524 "Add rack holes to vector3RackProfiles."
525 if len(derivation.gearHolePaths) > 0:
526 vector3RackProfiles += derivation.gearHolePaths
528 if derivation.rackHoleRadius <= 0.0:
530 addRackHole(derivation, elementNode, vector3RackProfiles, 0.0)
531 rackHoleMargin = derivation.rackHoleRadius + derivation.rackHoleRadius
532 rackHoleSteps = int(math.ceil((derivation.rackDemilength - rackHoleMargin) / derivation.rackHoleStep))
533 for rackHoleIndex in xrange(1, rackHoleSteps):
534 x = float(rackHoleIndex) * derivation.rackHoleStep
535 addRackHole(derivation, elementNode, vector3RackProfiles, -x)
536 addRackHole(derivation, elementNode, vector3RackProfiles, x)
538 def addShaft(derivation, negatives, positives):
540 if len(derivation.shaftPath) < 3:
542 positiveVertexes = matrix.getVertexes(positives)
543 bottomPath = euclidean.getTopPath(positiveVertexes)
544 topPath = euclidean.getBottomByPath(positiveVertexes)
545 copyShallow = derivation.elementNode.getCopyShallow()
546 copyShallow.attributes['path'] = [Vector3(0.0, 0.0, bottomPath), Vector3(0.0, 0.0, topPath)]
547 extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
548 extrude.addNegativesPositives(extrudeDerivation, negatives, [derivation.shaftPath], positives)
550 def getAxialMargin(circleRadius, numberOfSides, polygonRadius):
552 return polygonRadius * math.sin(math.pi / float(numberOfSides)) - circleRadius
554 def getBevelPath(begin, bevel, center, end):
556 centerMinusBegin = center - begin
557 centerMinusBeginLength = abs(centerMinusBegin)
558 endMinusCenter = end - center
559 endMinusCenterLength = abs(endMinusCenter)
560 endMinusCenter /= endMinusCenterLength
561 maximumExtensionLength = 0.333333333 * endMinusCenterLength
562 if centerMinusBeginLength <= bevel * 1.5:
563 extensionLength = min(maximumExtensionLength, centerMinusBeginLength)
564 return [complex(center.real, center.imag) + extensionLength * endMinusCenter]
565 centerMinusBegin *= (centerMinusBeginLength - bevel) / centerMinusBeginLength
566 extensionLength = min(maximumExtensionLength, bevel)
567 bevelPath = [complex(center.real, center.imag) + extensionLength * endMinusCenter]
568 bevelPath.append(begin + centerMinusBegin)
571 def getGearPaths(derivation, pitchRadius, teeth, toothProfile):
574 return getGearProfileAnnulus(derivation, pitchRadius, teeth, toothProfile)
576 return [getGearProfileRack(derivation, toothProfile)]
577 return [getGearProfileCylinder(teeth, toothProfile)]
579 def getGearProfileAnnulus(derivation, pitchRadius, teeth, toothProfile):
580 'Get gear profile for an annulus gear.'
581 gearProfileCylinder = getGearProfileCylinder(teeth, toothProfile)
582 annulusRadius = derivation.dedendum + derivation.rimDedendum - pitchRadius
583 return [euclidean.getComplexPolygon(complex(), annulusRadius, -teeth, 0.5 * math.pi), gearProfileCylinder]
585 def getGearProfileCylinder(teeth, toothProfile):
586 'Get gear profile for a cylinder gear.'
588 toothAngleRadian = 2.0 * math.pi / float(teeth)
589 totalToothAngle = 0.0
590 for toothIndex in xrange(abs(teeth)):
591 for toothPoint in toothProfile:
592 gearProfile.append(toothPoint * euclidean.getWiddershinsUnitPolar(totalToothAngle))
593 totalToothAngle += toothAngleRadian
596 def getGearProfileRack(derivation, toothProfile):
597 'Get gear profile for rack.'
598 derivation.extraRackDemilength = 0.0
599 for complexPoint in derivation.helixPath:
600 derivation.extraRackDemilength = max(abs(derivation.helixHeight * complexPoint.imag), derivation.extraRackDemilength)
601 rackDemilengthPlus = derivation.rackDemilength
602 if derivation.faceWidth > 0.0:
603 derivation.extraRackDemilength *= 1.1
604 rackDemilengthPlus += derivation.extraRackDemilength
605 teethRack = int(math.ceil(rackDemilengthPlus / derivation.wavelength))
607 for toothIndex in xrange(-teethRack, teethRack + 1):
608 translateComplex = complex(-toothIndex * derivation.wavelength, 0.0)
609 translatedPath = euclidean.getTranslatedComplexPath(toothProfile, translateComplex)
610 gearProfile += translatedPath
611 gearProfile = euclidean.getHorizontallyBoundedPath(rackDemilengthPlus, -rackDemilengthPlus, gearProfile)
612 firstPoint = gearProfile[0]
613 lastPoint = gearProfile[-1]
614 rackWidth = derivation.rackWidth
615 minimumRackWidth = 1.1 * derivation.dedendum
616 if rackWidth < minimumRackWidth:
617 rackWidth = minimumRackWidth
618 print('Warning, rackWidth is too small in getGearProfileRack in gear.')
619 print('RackWidth will be set to a bit more than the dedendum.')
620 gearProfile += [complex(lastPoint.real, -rackWidth),complex(firstPoint.real, -rackWidth)]
623 def getGeometryOutput(derivation, elementNode):
624 "Get vector3 vertexes from attribute dictionary."
625 if derivation == None:
626 derivation = GearDerivation(elementNode)
627 creationFirst = derivation.creationType.lower()[: 1]
628 toothProfileComplement = getToothProfile(derivation, derivation.pitchRadiusComplement, derivation.teethComplement)
629 pinionProfile = getGearProfileCylinder(derivation.teethPinion, derivation.pinionToothProfile)
630 complementPaths = getGearPaths(
631 derivation, derivation.pitchRadiusComplement, derivation.teethComplement, toothProfileComplement)
632 vector3PinionProfile = euclidean.getVector3Path(pinionProfile)
633 vector3ComplementPaths = euclidean.getVector3Paths(complementPaths)
634 translation = Vector3()
635 moveFirst = derivation.moveType.lower()[: 1]
637 distance = derivation.pitchRadius
639 distance += derivation.pitchRadiusComplement
641 distance += abs(derivation.pitchRadiusComplement)
642 decimalPlaces = 1 - int(math.floor(math.log10(distance)))
643 distance += derivation.halfWavelength + derivation.halfWavelength
644 distance = round(1.15 * distance, decimalPlaces)
645 translation = Vector3(0.0, -distance)
646 if derivation.faceWidth <=0.0:
647 return getPathOutput(
648 creationFirst, derivation, elementNode, translation, vector3ComplementPaths, vector3PinionProfile)
649 pitchRadius = derivation.pitchRadius
650 teeth = derivation.teethPinion
651 twist = derivation.helixHeight / derivation.pitchRadius
652 extrudeOutputPinion = getOutputCylinder(
653 derivation.pinionCollarLength, derivation, elementNode, None, pitchRadius, teeth, twist, [vector3PinionProfile])
654 if creationFirst == 'p':
655 return extrudeOutputPinion
656 teeth = derivation.teethComplement
657 extrudeOutputSecond = None
659 extrudeOutputSecond = getOutputRack(derivation, elementNode, vector3ComplementPaths[0])
661 twist = -derivation.helixHeight / derivation.pitchRadiusComplement
662 extrudeOutputSecond = getOutputCylinder(
663 derivation.complementCollarLength,
666 derivation.gearHolePaths,
667 derivation.pitchRadiusComplement,
670 vector3ComplementPaths)
671 if creationFirst == 'c':
672 return extrudeOutputSecond
673 gearVertexes = matrix.getVertexes(extrudeOutputSecond)
675 translation = Vector3(0.0, 0.0, euclidean.getTopPath(gearVertexes))
676 euclidean.translateVector3Path(matrix.getVertexes(extrudeOutputPinion), translation)
678 euclidean.translateVector3Path(gearVertexes, translation)
679 return {'group' : {'shapes' : [extrudeOutputPinion, extrudeOutputSecond]}}
681 def getGeometryOutputByArguments(arguments, elementNode):
682 "Get vector3 vertexes from attribute dictionary by arguments."
683 return getGeometryOutput(None, elementNode)
685 def getHalfwave(pitchRadius, teeth):
686 'Get tooth halfwave.'
687 return pitchRadius * math.pi / float(teeth)
689 def getHelixComplexPath(derivation, elementNode):
690 'Set gear helix path.'
691 helixTypeFirstCharacter = derivation.helixType.lower()[: 1]
692 if helixTypeFirstCharacter == 'b':
693 return [complex(), complex(1.0, 1.0)]
694 if helixTypeFirstCharacter == 'h':
695 return [complex(), complex(0.5, 0.5), complex(1.0, 0.0)]
696 if helixTypeFirstCharacter == 'p':
697 helixComplexPath = []
699 xStep = setting.getLayerHeight(elementNode) / derivation.faceWidth
700 justBelowOne = 1.0 - 0.5 * xStep
701 while x < justBelowOne:
702 distanceFromCenter = 0.5 - x
703 parabolicTwist = 0.25 - distanceFromCenter * distanceFromCenter
704 helixComplexPath.append(complex(x, parabolicTwist))
706 helixComplexPath.append(complex(1.0, 0.0))
707 return helixComplexPath
708 print('Warning, the helix type was not one of (basic, herringbone or parabolic) in getHelixComplexPath in gear for:')
709 print(derivation.helixType)
710 print(derivation.elementNode)
712 def getLiftedOutput(derivation, geometryOutput):
713 "Get extrude output for a rack."
714 if derivation.moveType.lower()[: 1] == 'm':
715 return geometryOutput
716 geometryOutputVertexes = matrix.getVertexes(geometryOutput)
717 translation = Vector3(0.0, 0.0, -euclidean.getBottomByPath(geometryOutputVertexes))
718 euclidean.translateVector3Path(geometryOutputVertexes, translation)
719 return geometryOutput
721 def getLighteningHoles(derivation, gearHolePaths, pitchRadius):
722 'Get cutout circles.'
723 if gearHolePaths != None:
724 if len(gearHolePaths) > 0:
726 innerRadius = abs(pitchRadius) - derivation.dedendum
727 lighteningHoleOuterRadius = innerRadius - derivation.rimDedendum
728 shaftRimRadius = max(derivation.shaftRimRadius, (lighteningHoleOuterRadius) * (0.5 - math.sqrt(0.1875)))
729 lighteningHoleRadius = 0.5 * (lighteningHoleOuterRadius - derivation.shaftRimRadius)
730 if lighteningHoleRadius < derivation.lighteningHoleMinimumRadius:
733 numberOfLighteningHoles = 3
734 polygonRadius = lighteningHoleOuterRadius - lighteningHoleRadius
735 rimDemiwidth = 0.5 * derivation.lighteningHoleMargin
736 axialMargin = getAxialMargin(lighteningHoleRadius, numberOfLighteningHoles, polygonRadius)
737 if axialMargin < rimDemiwidth:
738 while axialMargin < rimDemiwidth:
739 lighteningHoleRadius *= 0.999
740 if lighteningHoleRadius < derivation.lighteningHoleMinimumRadius:
742 axialMargin = getAxialMargin(lighteningHoleRadius, numberOfLighteningHoles, polygonRadius)
744 newNumberOfLighteningHoles = numberOfLighteningHoles
745 while axialMargin > rimDemiwidth:
746 numberOfLighteningHoles = newNumberOfLighteningHoles
747 newNumberOfLighteningHoles += 2
748 axialMargin = getAxialMargin(lighteningHoleRadius, newNumberOfLighteningHoles, polygonRadius)
749 sideAngle = 2.0 * math.pi / float(numberOfLighteningHoles)
751 for lighteningHoleIndex in xrange(numberOfLighteningHoles):
752 unitPolar = euclidean.getWiddershinsUnitPolar(startAngle)
753 lighteningHole = euclidean.getComplexPolygon(unitPolar * polygonRadius, lighteningHoleRadius, -13)
754 lighteningHoles.append(lighteningHole)
755 startAngle += sideAngle
756 return euclidean.getVector3Paths(lighteningHoles)
758 def getNewDerivation(elementNode):
759 'Get new derivation.'
760 return GearDerivation(elementNode)
762 def getOutputCylinder(
763 collarLength, derivation, elementNode, gearHolePaths, pitchRadius, teeth, twist, vector3GearProfile):
764 "Get extrude output for a cylinder gear."
765 copyShallow = derivation.elementNode.getCopyShallow()
766 copyShallow.attributes['path'] = [Vector3(), Vector3(0.0, 0.0, derivation.faceWidth)]
767 extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
771 twistDegrees = math.degrees(twist)
772 extrudeDerivation.twistPathDefault = []
773 for complexPoint in derivation.helixPath:
774 extrudeDerivation.twistPathDefault.append(Vector3(complexPoint.real, twistDegrees * complexPoint.imag))
775 extrude.insertTwistPortions(extrudeDerivation, elementNode)
776 if derivation.operatingAngle != 180.0:
777 addBevelGear(derivation, extrudeDerivation, pitchRadius, positives, teeth, vector3GearProfile)
778 addCollarShaft(collarLength, derivation, elementNode, negatives, positives)
779 return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
781 extrude.addNegativesPositives(extrudeDerivation, negatives, vector3GearProfile, positives)
782 addLighteningHoles(derivation, gearHolePaths, negatives, pitchRadius, positives)
783 addCollarShaft(collarLength, derivation, elementNode, negatives, positives)
784 return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
785 if derivation.plateLength <= 0.0:
786 extrude.addNegativesPositives(extrudeDerivation, negatives, vector3GearProfile, positives)
787 return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
788 portionDirections = extrude.getSpacedPortionDirections(extrudeDerivation.interpolationDictionary)
789 outerGearProfile = vector3GearProfile[0]
790 outerLoopLists = extrude.getLoopListsByPath(extrudeDerivation, None, outerGearProfile, portionDirections)
791 addBottomLoop(-derivation.plateClearance, outerLoopLists[0])
792 geometryOutput = triangle_mesh.getPillarsOutput(outerLoopLists)
793 positives.append(geometryOutput)
794 innerLoopLists = extrude.getLoopListsByPath(extrudeDerivation, None, vector3GearProfile[1], portionDirections)
795 addBottomLoop(-derivation.plateClearance, innerLoopLists[0])
796 geometryOutput = triangle_mesh.getPillarsOutput(innerLoopLists)
797 negatives.append(geometryOutput)
798 connectionStart = Vector3(0.0, 0.0, -derivation.plateLength)
799 copyShallow = derivation.elementNode.getCopyShallow()
800 copyShallow.attributes['path'] = [connectionStart, Vector3(0.0, 0.0, -derivation.plateClearance)]
801 plateDerivation = extrude.ExtrudeDerivation(copyShallow)
802 extrude.addNegativesPositives(plateDerivation, negatives, [outerGearProfile], positives)
803 vector3LighteningHoles = getLighteningHoles(derivation, gearHolePaths, pitchRadius)
804 extrude.addNegativesPositives(plateDerivation, negatives, vector3LighteningHoles, positives)
805 addShaft(derivation, negatives, positives)
806 positiveOutput = triangle_mesh.getUnifiedOutput(positives)
807 annulusPlateOutput = {'difference' : {'shapes' : [positiveOutput] + negatives}}
808 if collarLength <= 0.0:
809 outputCylinder = solid.getGeometryOutputByManipulation(elementNode, annulusPlateOutput)
810 return getLiftedOutput(derivation, outputCylinder)
813 connectionEnd = Vector3(0.0, 0.0, derivation.faceWidth + collarLength)
814 copyShallow = derivation.elementNode.getCopyShallow()
815 copyShallow.attributes['path'] = [Vector3(0.0, 0.0, -derivation.plateClearance), connectionEnd]
816 collarDerivation = extrude.ExtrudeDerivation(copyShallow)
817 addCollarShaftSetDerivation(collarDerivation, collarLength, derivation, elementNode, negatives, positives)
818 collarOutput = {'difference' : {'shapes' : positives + negatives}}
819 cylinderOutput = {'union' : {'shapes' : [annulusPlateOutput, collarOutput]}}
820 outputCylinder = solid.getGeometryOutputByManipulation(elementNode, cylinderOutput)
821 return getLiftedOutput(derivation, outputCylinder)
823 def getOutputRack(derivation, elementNode, vector3GearProfile):
824 "Get extrude output for a rack."
826 for complexPoint in derivation.helixPath:
827 point = Vector3(derivation.helixHeight * complexPoint.imag, 0.0, derivation.faceWidth * complexPoint.real)
829 copyShallow = derivation.elementNode.getCopyShallow()
830 copyShallow.attributes['path'] = path
831 extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
834 vector3RackProfiles = [vector3GearProfile]
835 if derivation.extraRackDemilength > 0.0:
836 yMaximum = -912345678.0
837 yMinimum = 912345678.0
838 for point in vector3GearProfile:
839 yMaximum = max(point.y, yMaximum)
840 yMinimum = min(point.y, yMinimum)
841 muchLessThanWidth = 0.01 * derivation.rackWidth
842 yMaximum += muchLessThanWidth
843 yMinimum -= muchLessThanWidth
844 extraRackLength = derivation.extraRackDemilength + derivation.extraRackDemilength
845 rackDemilengthPlus = derivation.rackDemilength + extraRackLength
847 Vector3(-derivation.rackDemilength, yMaximum),
848 Vector3(-derivation.rackDemilength, yMinimum),
849 Vector3(-rackDemilengthPlus, yMinimum),
850 Vector3(-rackDemilengthPlus, yMaximum)]
851 vector3RackProfiles.append(leftNegative)
853 Vector3(rackDemilengthPlus, yMaximum),
854 Vector3(rackDemilengthPlus, yMinimum),
855 Vector3(derivation.rackDemilength, yMinimum),
856 Vector3(derivation.rackDemilength, yMaximum)]
857 vector3RackProfiles.append(rightNegative)
858 addRackHoles(derivation, elementNode, vector3RackProfiles)
859 extrude.addNegativesPositives(extrudeDerivation, negatives, vector3RackProfiles, positives)
860 return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
862 def getPathOutput(creationFirst, derivation, elementNode, translation, vector3ComplementPaths, vector3PinionProfile):
863 "Get gear path output."
864 vector3PinionProfile = lineation.getPackedGeometryOutputByLoop(elementNode, lineation.SideLoop(vector3PinionProfile))
865 if creationFirst == 'p':
866 return vector3PinionProfile
867 packedGearGeometry = []
868 for vector3ComplementPath in vector3ComplementPaths:
869 sideLoop = lineation.SideLoop(vector3ComplementPath)
870 packedGearGeometry += lineation.getPackedGeometryOutputByLoop(elementNode, sideLoop)
871 if creationFirst == 'c':
872 return packedGearGeometry
873 euclidean.translateVector3Paths(packedGearGeometry, translation)
874 return vector3PinionProfile + packedGearGeometry
876 def getThicknessMultipliedPath(path, thicknessMultiplier):
877 "Get thickness multiplied path."
878 for pointIndex, point in enumerate(path):
879 path[pointIndex] = complex(point.real * thicknessMultiplier, point.imag)
882 def getToothProfile(derivation, pitchRadius, teeth):
883 'Get profile for one tooth.'
885 return getToothProfileAnnulus(derivation, pitchRadius, teeth)
887 return getToothProfileRack(derivation)
888 return getToothProfileCylinder(derivation, pitchRadius, teeth)
890 def getToothProfileAnnulus(derivation, pitchRadius, teeth):
891 'Get profile for one tooth of an annulus.'
892 toothProfileHalf = []
893 toothProfileHalfCylinder = getToothProfileHalfCylinder(derivation, pitchRadius)
894 pitchRadius = -pitchRadius
895 innerRadius = pitchRadius - derivation.addendum
896 # tooth is multiplied by 1.02 because at around 1.01 for a 7/-23/20.0 test case, there is intersection since the paths are bending together
897 for point in getThicknessMultipliedPath(toothProfileHalfCylinder, 1.02 / derivation.toothThicknessMultiplier):
898 if abs(point) >= innerRadius:
899 toothProfileHalf.append(point)
900 profileFirst = toothProfileHalf[0]
901 profileSecond = toothProfileHalf[1]
902 firstMinusSecond = profileFirst - profileSecond
903 remainingAddendum = abs(profileFirst) - innerRadius
904 firstMinusSecond *= remainingAddendum / abs(firstMinusSecond)
905 extensionPoint = profileFirst + firstMinusSecond
906 if derivation.tipBevel > 0.0:
907 unitPolar = euclidean.getWiddershinsUnitPolar(2.0 / float(teeth) * math.pi)
908 mirrorPoint = complex(-extensionPoint.real, extensionPoint.imag) * unitPolar
909 bevelPath = getBevelPath(profileFirst, derivation.tipBevel, extensionPoint, mirrorPoint)
910 toothProfileHalf = bevelPath + toothProfileHalf
912 toothProfileHalf.insert(0, extensionPoint)
913 profileLast = toothProfileHalf[-1]
914 profilePenultimate = toothProfileHalf[-2]
915 lastMinusPenultimate = profileLast - profilePenultimate
916 remainingDedendum = pitchRadius - abs(profileLast) + derivation.dedendum
917 lastMinusPenultimate *= remainingDedendum / abs(lastMinusPenultimate)
918 extensionPoint = profileLast + lastMinusPenultimate
919 if derivation.rootBevel > 0.0:
920 mirrorPoint = complex(-extensionPoint.real, extensionPoint.imag)
921 bevelPath = getBevelPath(profileLast, derivation.rootBevel, extensionPoint, mirrorPoint)
923 toothProfileHalf += bevelPath
925 toothProfileHalf.append(extensionPoint)
926 toothProfileAnnulus = euclidean.getMirrorPath(toothProfileHalf)
927 toothProfileAnnulus.reverse()
928 return toothProfileAnnulus
930 def getToothProfileCylinder(derivation, pitchRadius, teeth):
931 'Get profile for one tooth of a cylindrical gear.'
932 toothProfileHalfCylinder = getToothProfileHalfCylinder(derivation, pitchRadius)
933 toothProfileHalfCylinder = getThicknessMultipliedPath(toothProfileHalfCylinder, derivation.toothThicknessMultiplier)
934 toothProfileHalf = []
935 innerRadius = pitchRadius - derivation.dedendum
936 for point in toothProfileHalfCylinder:
937 if abs(point) >= innerRadius:
938 toothProfileHalf.append(point)
939 return getToothProfileCylinderByProfile(derivation, pitchRadius, teeth, toothProfileHalf)
941 def getToothProfileCylinderByProfile(derivation, pitchRadius, teeth, toothProfileHalf):
942 'Get profile for one tooth of a cylindrical gear.'
943 profileFirst = toothProfileHalf[0]
944 profileSecond = toothProfileHalf[1]
945 firstMinusSecond = profileFirst - profileSecond
946 remainingDedendum = abs(profileFirst) - pitchRadius + derivation.dedendum
947 firstMinusSecond *= remainingDedendum / abs(firstMinusSecond)
948 extensionPoint = profileFirst + firstMinusSecond
949 if derivation.rootBevel > 0.0:
950 unitPolar = euclidean.getWiddershinsUnitPolar(-2.0 / float(teeth) * math.pi)
951 mirrorPoint = complex(-extensionPoint.real, extensionPoint.imag) * unitPolar
952 bevelPath = getBevelPath(profileFirst, derivation.rootBevel, extensionPoint, mirrorPoint)
953 toothProfileHalf = bevelPath + toothProfileHalf
955 toothProfileHalf.insert(0, extensionPoint)
956 if derivation.tipBevel > 0.0:
957 profileLast = toothProfileHalf[-1]
958 profilePenultimate = toothProfileHalf[-2]
959 mirrorPoint = complex(-profileLast.real, profileLast.imag)
960 bevelPath = getBevelPath(profilePenultimate, derivation.tipBevel, profileLast, mirrorPoint)
962 toothProfileHalf = toothProfileHalf[: -1] + bevelPath
963 return euclidean.getMirrorPath(toothProfileHalf)
965 def getToothProfileHalfCylinder(derivation, pitchRadius):
966 'Get profile for half of a one tooth of a cylindrical gear.'
968 # x = -y * tan(p) + 1
969 # x*x + y*y = (2-cos(p))^2
970 # y*y*t*t-2yt+1+y*y=4-4c-c*c
971 # y*y*(t*t+1)-2yt=3-4c-c*c
972 # y*y*(t*t+1)-2yt-3+4c-c*c=0
976 a = derivation.tanPressure * derivation.tanPressure + 1.0
977 b = -derivation.tanPressure - derivation.tanPressure
978 cEnd = derivation.cosPressure * (4.0 - derivation.cosPressure) - 3.0
979 yEnd = (-b - math.sqrt(b*b - 4 * a * cEnd)) * 0.5 / a
980 yEnd *= derivation.pitchRadius / abs(pitchRadius)
981 yEnd -= derivation.clearance / abs(pitchRadius)
982 # to prevent intersections, yBegin is moved towards the base circle, giving a thinner tooth
984 if pitchRadius > 0.0:
985 yBegin = 0.5 * derivation.sinPressure + 0.5 * yBegin
986 beginComplex = complex(1.0 - yBegin * derivation.tanPressure, yBegin)
987 endComplex = complex(1.0 - yEnd * derivation.tanPressure, yEnd)
988 endMinusBeginComplex = endComplex - beginComplex
989 wholeAngle = -abs(endMinusBeginComplex) / derivation.cosPressure
990 wholeAngleIncrement = wholeAngle / float(derivation.profileSurfaces)
991 stringStartAngle = abs(beginComplex - complex(1.0, 0.0)) / derivation.cosPressure
992 wholeDepthIncrementComplex = endMinusBeginComplex / float(derivation.profileSurfaces)
993 for profileIndex in xrange(derivation.profileSurfaces + 1):
994 contactPoint = beginComplex + wholeDepthIncrementComplex * float(profileIndex)
995 stringAngle = stringStartAngle + wholeAngleIncrement * float(profileIndex)
996 angle = math.atan2(contactPoint.imag, contactPoint.real) - stringAngle
997 angle += 0.5 * math.pi - derivation.quarterWavelength / abs(pitchRadius)
998 toothPoint = abs(contactPoint) * euclidean.getWiddershinsUnitPolar(angle) * abs(pitchRadius)
999 toothProfile.append(toothPoint)
1002 def getToothProfileRack(derivation):
1003 'Get profile for one rack tooth.'
1004 addendumSide = derivation.quarterWavelength - derivation.addendum * derivation.tanPressure
1005 addendumComplex = complex(addendumSide, derivation.addendum)
1006 dedendumSide = derivation.quarterWavelength + derivation.dedendum * derivation.tanPressure
1007 dedendumComplex = complex(dedendumSide, -derivation.dedendum)
1008 toothProfile = [dedendumComplex]
1009 if derivation.rootBevel > 0.0:
1010 mirrorPoint = complex(derivation.wavelength - dedendumSide, -derivation.dedendum)
1011 toothProfile = getBevelPath(addendumComplex, derivation.rootBevel, dedendumComplex, mirrorPoint)
1012 if derivation.tipBevel > 0.0:
1013 mirrorPoint = complex(-addendumComplex.real, addendumComplex.imag)
1014 bevelPath = getBevelPath(dedendumComplex, derivation.tipBevel, addendumComplex, mirrorPoint)
1016 toothProfile += bevelPath
1018 toothProfile.append(addendumComplex)
1019 return euclidean.getMirrorPath(getThicknessMultipliedPath(toothProfile, derivation.toothThicknessMultiplier))
1021 def processElementNode(elementNode):
1022 "Process the xml element."
1023 geometryOutput = getGeometryOutput(None, elementNode)
1024 if geometryOutput.__class__ == list:
1025 path.convertElementNode(elementNode, geometryOutput)
1027 solid.processElementNodeByGeometry(elementNode, geometryOutput)
1030 class GearDerivation(object):
1031 "Class to hold gear variables."
1032 def __init__(self, elementNode):
1034 self.clearanceOverWavelength = evaluate.getEvaluatedFloat(0.1, elementNode, 'clearanceOverWavelength')
1035 self.collarAddendumOverRadius = evaluate.getEvaluatedFloat(1.0, elementNode, 'collarAddendumOverRadius')
1036 self.complementCollarLengthOverFaceWidth = evaluate.getEvaluatedFloat(
1037 0.0, elementNode, 'complementCollarLengthOverFaceWidth')
1038 self.copyShallow = elementNode.getCopyShallow()
1039 self.creationType = evaluate.getEvaluatedString('both', elementNode, 'creationType')
1040 self.creationTypeMenuRadioStrings = 'both complement pinion'.split()
1041 self.elementNode = elementNode
1042 self.faceWidth = evaluate.getEvaluatedFloat(10.0, elementNode, 'faceWidth')
1043 self.helixAngle = evaluate.getEvaluatedFloat(0.0, elementNode, 'helixAngle')
1044 self.helixType = evaluate.getEvaluatedString('basic', elementNode, 'helixType')
1045 self.helixTypeMenuRadioStrings = 'basic herringbone parabolic'.split()
1046 self.keywayRadiusOverRadius = evaluate.getEvaluatedFloat(0.5, elementNode, 'keywayRadiusOverRadius')
1047 self.lighteningHoleMarginOverRimDedendum = evaluate.getEvaluatedFloat(
1048 1.0, elementNode, 'lighteningHoleMarginOverRimDedendum')
1049 self.lighteningHoleMinimumRadius = evaluate.getEvaluatedFloat(
1050 1.0, elementNode, 'lighteningHoleMinimumRadius')
1051 self.moveType = evaluate.getEvaluatedString('separate', elementNode, 'moveType')
1052 self.moveTypeMenuRadioStrings = 'mesh none separate vertical'.split()
1053 self.operatingAngle = evaluate.getEvaluatedFloat(180.0, elementNode, 'operatingAngle')
1054 self.pinionCollarLengthOverFaceWidth = evaluate.getEvaluatedFloat(
1055 0.0, elementNode, 'pinionCollarLengthOverFaceWidth')
1056 self.plateClearanceOverLength = evaluate.getEvaluatedFloat(0.2, elementNode, 'plateClearanceOverLength')
1057 self.plateLengthOverFaceWidth = evaluate.getEvaluatedFloat(0.5, elementNode, 'plateLengthOverFaceWidth')
1058 self.pressureAngle = evaluate.getEvaluatedFloat(20.0, elementNode, 'pressureAngle')
1059 self.profileSurfaces = evaluate.getEvaluatedInt(11, elementNode, 'profileSurfaces')
1060 self.rackHoleBelowOverWidth = evaluate.getEvaluatedFloat(0.6, elementNode, 'rackHoleBelowOverWidth')
1061 self.rackHoleRadiusOverWidth = evaluate.getEvaluatedFloat(0.0, elementNode, 'rackHoleRadiusOverWidth')
1062 self.rackHoleStepOverWidth = evaluate.getEvaluatedFloat(1.0, elementNode, 'rackHoleStepOverWidth')
1063 self.rackLengthOverRadius = evaluate.getEvaluatedFloat(math.pi + math.pi, elementNode, 'rackLengthOverRadius')
1064 self.rackWidthOverFaceWidth = evaluate.getEvaluatedFloat(1.0, elementNode, 'rackWidthOverFaceWidth')
1065 self.rimDedendumOverRadius = evaluate.getEvaluatedFloat(0.2, elementNode, 'rimDedendumOverRadius')
1066 self.rootBevelOverClearance = evaluate.getEvaluatedFloat(0.5, elementNode, 'rootBevelOverClearance')
1067 self.shaftDepthBottomOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'shaftDepthBottomOverRadius')
1068 self.shaftDepthTopOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'shaftDepthOverRadius')
1069 self.shaftRadiusOverPitchRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'shaftRadiusOverPitchRadius')
1070 self.shaftSides = evaluate.getEvaluatedInt(4, elementNode, 'shaftSides')
1071 self.teethComplement = evaluate.getEvaluatedInt(17, elementNode, 'teethComplement')
1072 self.teethPinion = evaluate.getEvaluatedInt(7, elementNode, 'teeth')
1073 totalTeethOverPinionTeeth = float(self.teethComplement + self.teethPinion) / float(self.teethPinion)
1074 self.centerDistance = evaluate.getEvaluatedFloat(20.0 * totalTeethOverPinionTeeth, elementNode, 'centerDistance')
1075 derivedPitchRadius = self.centerDistance / totalTeethOverPinionTeeth
1076 self.pitchRadius = evaluate.getEvaluatedFloat(derivedPitchRadius, elementNode, 'pitchRadius')
1077 self.tipBevelOverClearance = evaluate.getEvaluatedFloat(0.1, elementNode, 'tipBevelOverClearance')
1078 # tooth multiplied by 0.99999 to avoid an intersection
1079 self.toothThicknessMultiplier = evaluate.getEvaluatedFloat(0.99999, elementNode, 'toothThicknessMultiplier')
1080 # Set derived variables.
1081 self.wavelength = self.pitchRadius * 2.0 * math.pi / float(self.teethPinion)
1082 self.clearance = self.wavelength * self.clearanceOverWavelength
1083 self.clearance = evaluate.getEvaluatedFloat(self.clearance, elementNode, 'clearance')
1084 self.complementCollarLength = self.faceWidth * self.complementCollarLengthOverFaceWidth
1085 self.complementCollarLength = evaluate.getEvaluatedFloat(self.complementCollarLength, elementNode, 'complementCollarLength')
1086 self.gearHolePaths = evaluate.getTransformedPathsByKey([], elementNode, 'gearHolePaths')
1087 self.pinionCollarLength = self.faceWidth * self.pinionCollarLengthOverFaceWidth
1088 self.pinionCollarLength = evaluate.getEvaluatedFloat(self.pinionCollarLength, elementNode, 'pinionCollarLength')
1089 self.plateLength = self.faceWidth * self.plateLengthOverFaceWidth
1090 self.plateLength = evaluate.getEvaluatedFloat(self.plateLength, elementNode, 'plateLength')
1091 self.plateClearance = self.plateLength * self.plateClearanceOverLength
1092 self.plateClearance = evaluate.getEvaluatedFloat(self.plateClearance, elementNode, 'plateClearance')
1093 self.rackLength = self.pitchRadius * self.rackLengthOverRadius
1094 self.rackLength = evaluate.getEvaluatedFloat(self.rackLength, elementNode, 'rackLength')
1095 self.rackDemilength = 0.5 * self.rackLength
1096 self.rackWidth = self.faceWidth * self.rackWidthOverFaceWidth
1097 self.rackWidth = evaluate.getEvaluatedFloat(self.rackWidth, elementNode, 'rackWidth')
1098 self.rimDedendum = self.pitchRadius * self.rimDedendumOverRadius
1099 self.rimDedendum = evaluate.getEvaluatedFloat(self.rimDedendum, elementNode, 'rimDedendum')
1100 self.rootBevel = self.clearance * self.rootBevelOverClearance
1101 self.rootBevel = evaluate.getEvaluatedFloat(self.rootBevel, elementNode, 'rootBevel')
1102 self.shaftRadius = self.pitchRadius * self.shaftRadiusOverPitchRadius
1103 self.shaftRadius = evaluate.getEvaluatedFloat(self.shaftRadius, elementNode, 'shaftRadius')
1104 self.collarAddendum = self.shaftRadius * self.collarAddendumOverRadius
1105 self.collarAddendum = evaluate.getEvaluatedFloat(self.collarAddendum, elementNode, 'collarWidth')
1106 self.keywayRadius = self.shaftRadius * self.keywayRadiusOverRadius
1107 self.keywayRadius = lineation.getFloatByPrefixBeginEnd(elementNode, 'keywayRadius', 'keywayDiameter', self.keywayRadius)
1108 self.lighteningHoleMargin = self.rimDedendum * self.lighteningHoleMarginOverRimDedendum
1109 self.lighteningHoleMargin = evaluate.getEvaluatedFloat(
1110 self.lighteningHoleMargin, elementNode, 'lighteningHoleMargin')
1111 self.rackHoleBelow = self.rackWidth * self.rackHoleBelowOverWidth
1112 self.rackHoleBelow = evaluate.getEvaluatedFloat(self.rackHoleBelow, elementNode, 'rackHoleBelow')
1113 self.rackHoleRadius = self.rackWidth * self.rackHoleRadiusOverWidth
1114 self.rackHoleRadius = lineation.getFloatByPrefixBeginEnd(elementNode, 'rackHoleRadius', 'rackHoleDiameter', self.rackHoleRadius)
1115 self.rackHoleStep = self.rackWidth * self.rackHoleStepOverWidth
1116 self.rackHoleStep = evaluate.getEvaluatedFloat(self.rackHoleStep, elementNode, 'rackHoleStep')
1117 self.shaftDepthBottom = self.shaftRadius * self.shaftDepthBottomOverRadius
1118 self.shaftDepthBottom = evaluate.getEvaluatedFloat(self.shaftDepthBottom, elementNode, 'shaftDepthBottom')
1119 self.shaftDepthTop = self.shaftRadius * self.shaftDepthTopOverRadius
1120 self.shaftDepthTop = evaluate.getEvaluatedFloat(self.shaftDepthTop, elementNode, 'shaftDepthTop')
1121 self.shaftPath = evaluate.getTransformedPathByKey([], elementNode, 'shaftPath')
1122 if len(self.shaftPath) < 3:
1123 self.shaftPath = shaft.getShaftPath(self.shaftDepthBottom, self.shaftDepthTop, self.shaftRadius, -self.shaftSides)
1124 self.tipBevel = self.clearance * self.tipBevelOverClearance
1125 self.tipBevel = evaluate.getEvaluatedFloat(self.tipBevel, elementNode, 'tipBevel')
1126 # Set derived values.
1127 self.helixRadian = math.radians(self.helixAngle)
1128 if self.teethComplement <= 0.0 and self.operatingAngle != 180.0:
1129 print('Warning, an operatingAngle other than 180 degrees can only work with a positive number of gear teeth.')
1130 print('Therefore the operatingAngle will be reset to 180 degrees.')
1131 self.operatingAngle = 180.0
1132 self.tanHelix = math.tan(self.helixRadian)
1133 self.helixHeight = self.tanHelix * self.faceWidth
1134 self.operatingRadian = math.radians(self.operatingAngle)
1135 self.pitchRadiusComplement = self.pitchRadius * float(self.teethComplement) / float(self.teethPinion)
1136 self.pressureRadian = math.radians(self.pressureAngle)
1137 self.cosPressure = math.cos(self.pressureRadian)
1138 self.sinPressure = math.sin(self.pressureRadian)
1139 self.tanPressure = math.tan(self.pressureRadian)
1140 self.halfWavelength = 0.5 * self.wavelength
1141 self.helixPath = euclidean.getComplexPath(evaluate.getTransformedPathByKey([], elementNode, 'helixPath'))
1142 if len(self.helixPath) < 1:
1143 self.helixPath = getHelixComplexPath(self, elementNode)
1144 self.quarterWavelength = 0.25 * self.wavelength
1145 self.shaftRimRadius = self.shaftRadius + self.collarAddendum
1146 self.toothProfileHalf = getToothProfileHalfCylinder(self, self.pitchRadius)
1147 self.toothProfileHalf = getThicknessMultipliedPath(self.toothProfileHalf, self.toothThicknessMultiplier)
1148 self.addendum = self.toothProfileHalf[-1].imag - self.pitchRadius
1149 self.dedendum = abs(self.toothProfileHalf[-1]) - self.pitchRadius + self.clearance
1150 self.pinionToothProfile = getToothProfileCylinderByProfile(self, self.pitchRadius, self.teethPinion, self.toothProfileHalf)