Download src/Mod/PartDesign/Scripts/Gear.py from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/Scripts/Gear.py
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/PartDesign/Scripts/Gear.py
-
curl -L -o Gear.py https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/PartDesign/Scripts/Gear.py
10.8 kB
| # Involute Gears Generation Script | |
| # by Marcin Wanczyk (dj_who) | |
| # (c) 2011 LGPL | |
| import FreeCAD | |
| import FreeCADGui | |
| import Part | |
| import Draft | |
| import MeshPart | |
| import Mesh | |
| import math | |
| from PySide import QtGui, QtCore | |
| App = FreeCAD | |
| Gui = FreeCADGui | |
| def proceed(): | |
| try: | |
| compute() | |
| except Exception: | |
| hide() | |
| QtGui.QApplication.restoreOverrideCursor() | |
| def compute(): | |
| QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) | |
| if FreeCAD.ActiveDocument is None: | |
| FreeCAD.newDocument("Gear") | |
| oldDocumentObjects = App.ActiveDocument.Objects | |
| try: | |
| N = int(l1.text()) | |
| p = float(l2.text()) | |
| alfa = int(l3.text()) | |
| y = float(l4.text()) # standard value y<1 for gear drives y>1 for Gear pumps | |
| m = ( | |
| p / math.pi | |
| ) # standard value 0.06, 0.12, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 60 (polish norm) | |
| c = float(l5.text()) * m # standard value 0,1*m - 0,3*m | |
| j = float(l6.text()) * m # standard value 0,015 - 0,04*m | |
| width = float(l7.text()) # gear width | |
| except ValueError: | |
| FreeCAD.Console.PrintError("Wrong input! Only numbers allowed.\n") | |
| # tooth height | |
| h = 2 * y * m + c | |
| # pitch diameter | |
| d = N * m | |
| # root diameter | |
| df = d - 2 * y * m - 2 * c # df=d-2hf where and hf=y*m+c | |
| # addendum diameter | |
| da = d + 2 * y * m # da=d+2ha where ha=y*m | |
| # base diameter for involute | |
| db = d * math.cos(math.radians(alfa)) | |
| # Base circle | |
| baseCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BaseCircle") | |
| Draft._Circle(baseCircle) | |
| Draft._ViewProviderDraft(baseCircle.ViewObject) | |
| baseCircle.Radius = db / 2 | |
| baseCircle.FirstAngle = 0.0 | |
| baseCircle.LastAngle = 0.0 | |
| # Root circle | |
| rootCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "RootCircle") | |
| Draft._Circle(rootCircle) | |
| Draft._ViewProviderDraft(rootCircle.ViewObject) | |
| rootCircle.Radius = df / 2 | |
| rootCircle.FirstAngle = 0.0 | |
| rootCircle.LastAngle = 0.0 | |
| # Addendum circle | |
| addendumCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "AddendumCircle") | |
| Draft._Circle(addendumCircle) | |
| Draft._ViewProviderDraft(addendumCircle.ViewObject) | |
| addendumCircle.Radius = da / 2 | |
| addendumCircle.FirstAngle = 0.0 | |
| addendumCircle.LastAngle = 0.0 | |
| # Pitch circle | |
| pitchCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "PitchCircle") | |
| Draft._Circle(pitchCircle) | |
| Draft._ViewProviderDraft(pitchCircle.ViewObject) | |
| pitchCircle.Radius = d / 2 | |
| pitchCircle.FirstAngle = 0.0 | |
| pitchCircle.LastAngle = 0.0 | |
| # ************ Calculating right sides of teeth | |
| # Involute of base circle | |
| involute = [] | |
| involutee = [] | |
| involutesav = [] | |
| for t in range(0, 60, 1): | |
| x = db / 2 * (math.cos(math.radians(t)) + math.radians(t) * math.sin(math.radians(t))) | |
| y = db / 2 * (math.sin(math.radians(t)) - math.radians(t) * math.cos(math.radians(t))) | |
| involute.append(Part.Vertex(x, y, 0).Point) | |
| # ************ Drawing right sides of teeth | |
| involutesav.extend(involute) | |
| involutee.extend(involute) | |
| for angle in range(1, N + 1, 1): | |
| involuteobj = FreeCAD.ActiveDocument.addObject("Part::Feature", "InvoluteL" + str(angle)) | |
| involutee.insert(0, (0, 0, 0)) | |
| involuteshape = Part.makePolygon(involutee) | |
| involuteobj.Shape = involuteshape | |
| involutee = [] | |
| for num in range(0, 60, 1): | |
| point = involute.pop() | |
| pointt = Part.Vertex( | |
| point.x * math.cos(math.radians(angle * 360 / N)) | |
| - point.y * math.sin(math.radians(angle * 360 / N)), | |
| point.x * math.sin(math.radians(angle * 360 / N)) | |
| + point.y * math.cos(math.radians(angle * 360 / N)), | |
| 0, | |
| ).Point | |
| involutee.insert(0, pointt) | |
| involute.extend(involutesav) | |
| involutee = [] | |
| # ************ Calculating difference between tooth spacing on BaseCircle and PitchCircle | |
| pc = App.ActiveDocument.getObject("PitchCircle") | |
| inv = App.ActiveDocument.getObject("InvoluteL1") | |
| cut = inv.Shape.cut(pc.Shape) | |
| # FreeCAD.ActiveDocument.addObject("Part::Feature","CutInv").Shape=cut | |
| invPoint = cut.Vertexes[0].Point | |
| diff = invPoint.y * 2 # instead of making axial symmetry and calculating point distance. | |
| anglediff = 2 * math.asin(diff / d) | |
| # ************ Calculating left sides of teeth | |
| # ************ Inversing Involute | |
| for num in range(0, 60, 1): | |
| point = involute.pop() | |
| pointt = Part.Vertex(point.x, point.y * -1, 0).Point | |
| involutee.insert(0, pointt) | |
| involute.extend(involutee) | |
| involutee = [] | |
| # Normal tooth size calculated as: 0,5* p - j j = m * 0,1 below are calculations | |
| # 0,5* p - m * 0,1 | |
| # 0,5* p - p /pi * 0,1 | |
| # 0,5*360/N - ((360/N)/pi)* 0,1 | |
| # 0,5*360/N - (360/N)*((1/pi)*0,1) j = (p/pi)*0,1 | |
| # 0,5*360/N - (360/N)*((p/pi)*0,1)/p | |
| # 0,5*360/N - (360/N)*( j )/p | |
| for num in range(0, 60, 1): | |
| point = involute.pop() | |
| pointt = Part.Vertex( | |
| point.x * math.cos(math.radians(180 / N - (360 / N) * (j / p)) + anglediff) | |
| - point.y * math.sin(math.radians(180 / N - (360 / N) * (j / p)) + anglediff), | |
| point.x * math.sin(math.radians(180 / N - (360 / N) * (j / p)) + anglediff) | |
| + point.y * math.cos(math.radians(180 / N - (360 / N) * (j / p)) + anglediff), | |
| 0, | |
| ).Point | |
| involutee.insert(0, pointt) | |
| involute.extend(involutee) | |
| involutesav = [] | |
| involutesav.extend(involute) | |
| # ************ Drawing left sides of teeth | |
| for angle in range(1, N + 1, 1): | |
| involuteobj = FreeCAD.ActiveDocument.addObject("Part::Feature", "InvoluteR" + str(angle)) | |
| involutee.insert(0, (0, 0, 0)) | |
| involuteshape = Part.makePolygon(involutee) | |
| involuteobj.Shape = involuteshape | |
| involutee = [] | |
| for num in range(0, 60, 1): | |
| point = involute.pop() | |
| pointt = Part.Vertex( | |
| point.x * math.cos(math.radians(angle * 360 / N)) | |
| - point.y * math.sin(math.radians(angle * 360 / N)), | |
| point.x * math.sin(math.radians(angle * 360 / N)) | |
| + point.y * math.cos(math.radians(angle * 360 / N)), | |
| 0, | |
| ).Point | |
| involutee.insert(0, pointt) | |
| involute.extend(involutesav) | |
| Gui.SendMsgToActiveView("ViewFit") | |
| # ************ Forming teeth | |
| cutCircle = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "CutCircle") | |
| Draft._Circle(cutCircle) | |
| Draft._ViewProviderDraft(cutCircle.ViewObject) | |
| cutCircle.Radius = da # da because must be bigger than addendumCircle and bigger than whole construction da is right for this but it not has to be. | |
| cutCircle.FirstAngle = 0.0 | |
| cutCircle.LastAngle = 0.0 | |
| cutTool = cutCircle.Shape.cut(addendumCircle.Shape) | |
| # cutshape = Part.show(cutTool) | |
| gearShape = rootCircle.Shape | |
| for invNum in range(1, N + 1, 1): | |
| invL = App.ActiveDocument.getObject("InvoluteL" + str(invNum)) | |
| invR = App.ActiveDocument.getObject("InvoluteR" + str(invNum)) | |
| cutL = invL.Shape.cut(cutTool) | |
| cutR = invR.Shape.cut(cutTool) | |
| pointL = cutL.Vertexes.pop().Point | |
| pointR = cutR.Vertexes.pop().Point | |
| faceEdge = Part.makeLine(pointL, pointR) | |
| toothWhole = cutL.fuse(cutR) | |
| toothWhole = toothWhole.fuse(faceEdge) | |
| toothWire = Part.Wire(toothWhole.Edges) | |
| toothShape = Part.Face(toothWire) | |
| # tooth = App.ActiveDocument.addObject("Part::Feature", "Tooth" +str(invNum)) | |
| # tooth.Shape=toothShape | |
| gearShape = gearShape.fuse(toothShape) | |
| for o in App.ActiveDocument.Objects: | |
| if oldDocumentObjects.count(o) == 0: | |
| App.ActiveDocument.removeObject(o.Name) | |
| gearFlat = App.ActiveDocument.addObject("Part::Feature", "GearFlat") | |
| gearFlat.Shape = gearShape | |
| Gui.ActiveDocument.getObject(gearFlat.Name).Visibility = False | |
| gear = App.ActiveDocument.addObject("Part::Extrusion", "Gear3D") | |
| gear.Base = gearFlat | |
| gear.Dir = (0, 0, width) | |
| App.ActiveDocument.recompute() | |
| if c1.isChecked(): | |
| gearMesh = App.ActiveDocument.addObject("Mesh::Feature", "Gear3D-mesh") | |
| faces = [] | |
| triangles = gear.Shape.tessellate( | |
| 1 | |
| ) # the number represents the precision of the tessellation) | |
| for tri in triangles[1]: | |
| face = [] | |
| for i in range(3): | |
| vindex = tri[i] | |
| face.append(triangles[0][vindex]) | |
| faces.append(face) | |
| mesh = Mesh.Mesh(faces) | |
| gearMesh.Mesh = mesh | |
| App.ActiveDocument.removeObject(gear.Name) | |
| App.ActiveDocument.removeObject(gearFlat.Name) | |
| App.ActiveDocument.recompute() | |
| Gui.SendMsgToActiveView("ViewFit") | |
| QtGui.QApplication.restoreOverrideCursor() | |
| hide() | |
| def hide(): | |
| dialog.hide() | |
| dialog = QtGui.QDialog() | |
| dialog.resize(200, 450) | |
| dialog.setWindowTitle("Gear") | |
| la = QtGui.QVBoxLayout(dialog) | |
| t1 = QtGui.QLabel("Number of teeth (N)") | |
| la.addWidget(t1) | |
| l1 = QtGui.QLineEdit() | |
| l1.setText("16") | |
| la.addWidget(l1) | |
| t2 = QtGui.QLabel("Circular pitch (p)") | |
| la.addWidget(t2) | |
| l2 = QtGui.QLineEdit() | |
| l2.setText("1.65") | |
| la.addWidget(l2) | |
| t3 = QtGui.QLabel("Pressure angle (alfa)") | |
| la.addWidget(t3) | |
| l3 = QtGui.QLineEdit() | |
| l3.setText("20") | |
| la.addWidget(l3) | |
| t4 = QtGui.QLabel("Tooth height factor (y)") | |
| la.addWidget(t4) | |
| l4 = QtGui.QLineEdit() | |
| l4.setText("1.0") | |
| la.addWidget(l4) | |
| t5 = QtGui.QLabel("Tooth clearance (c)") | |
| la.addWidget(t5) | |
| l5 = QtGui.QLineEdit() | |
| l5.setText("0.1") | |
| la.addWidget(l5) | |
| t6 = QtGui.QLabel("Tooth lateral clearance (j)") | |
| la.addWidget(t6) | |
| l6 = QtGui.QLineEdit() | |
| l6.setText("0.04") | |
| la.addWidget(l6) | |
| t7 = QtGui.QLabel("Gear width") | |
| la.addWidget(t7) | |
| l7 = QtGui.QLineEdit() | |
| l7.setText("6.0") | |
| la.addWidget(l7) | |
| c1 = QtGui.QCheckBox("Create as a Mesh") | |
| la.addWidget(c1) | |
| e1 = QtGui.QLabel("(for faster rendering)") | |
| commentFont = QtGui.QFont("Times", 8, True) | |
| e1.setFont(commentFont) | |
| la.addWidget(e1) | |
| okbox = QtGui.QDialogButtonBox(dialog) | |
| okbox.setOrientation(QtCore.Qt.Horizontal) | |
| okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) | |
| la.addWidget(okbox) | |
| QtCore.QObject.connect(okbox, QtCore.SIGNAL("accepted()"), proceed) | |
| QtCore.QObject.connect(okbox, QtCore.SIGNAL("rejected()"), hide) | |
| QtCore.QMetaObject.connectSlotsByName(dialog) | |
| dialog.show() | |