diff --git a/.gitignore b/.gitignore
index b6e4761..89e437d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,5 @@ dmypy.json
# Pyre type checker
.pyre/
+*.ipynb
+plugins/gear_generator/src/gear-generator/
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..2c7c8e4
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "python.pythonPath": "D:\\Programmes\\miniconda\\envs\\test_gear_generator\\python.exe"
+}
\ No newline at end of file
diff --git a/plugins/gear_generator/README.md b/plugins/gear_generator/README.md
new file mode 100644
index 0000000..af6ecbf
--- /dev/null
+++ b/plugins/gear_generator/README.md
@@ -0,0 +1,95 @@
+# Gear generator
+
+This plugin provide additionals methods to create various gears.
+As for now you can create these gears (all the gears are involutes):
+* Spur gear
+
+
+
+* Helical gear
+
+
+
+* Rack gear
+
+
+
+* Helical rack gear
+
+
+
+* Crown (or face) gear
+
+
+
+* Bevel gear (straight) (experimental)
+
+
+
+* Bevel gear system (straight) (very experimental)
+
+
+
+
+## Installation
+
+To install this plugin, the following line should be used.
+
+```
+pip install -e "git+https://github.com/CadQuery/cadquery-plugins.git#egg=gear_generator&subdirectory=plugins/gear_generator"
+```
+
+
+## Dependencies
+
+This plugin has no dependencies other than the cadquery library.
+
+## Usage
+
+To use this plugin after it has been installed, just import it and use the make_... methods to create your gears
+```python
+import cadquery as cq
+import gear_generator # automatically links the plugin functions to the cq.Workplane class
+
+module = 2
+nb_teeth = 12
+width = 8
+gear = cq.Workplane("XY").make_gear(module, nb_teeth, width)
+```
+
+
+Currently in cq-editor the automatical linking doesn't work so you should try to link it manually as below :
+```python
+import cadquery as cq
+import gear_generator
+gear_generator.cutter_objects.register_cutter_objects()
+gear_generator.register()
+```
+
+Below is the list of implemented methods :
+```python
+cq.Workplane().make_gear(params)
+cq.Workplane().make_rack_gear(params)
+cq.Workplane().make_crown_gear(params)
+cq.Workplane().make_bevel_gear(params)
+cq.Workplane().make_bevel_gear_system(params)
+
+#You can get info about the parameters by running
+help(cq.Workplane().make_gear)
+>>> _make_gear(m, z, b, alpha=20, helix_angle=None, raw=False) method of cadquery.cq.Workplane instance
+>>> Creates a spur or helical involute gear
+>>>
+>>> Parameters
+>>> ----------
+>>> m : float
+>>> Spur gear modulus
+>>> z : int
+>>> Number of teeth
+>>> b : float
+>>> Tooth width
+>>> alpha : float
+>>> Pressure angle in degrees, industry standard is 20\ufffd
+>>> helix_angle : float
+>>> Helix angle of the helical gear in degrees
+>>> If None creates a spur gear, if specified create a helical gear
+```
diff --git a/plugins/gear_generator/gear_generator/__init__.py b/plugins/gear_generator/gear_generator/__init__.py
new file mode 100644
index 0000000..adbbe21
--- /dev/null
+++ b/plugins/gear_generator/gear_generator/__init__.py
@@ -0,0 +1,9 @@
+from .main import (
+ _make_gear,
+ _make_bevel_gear,
+ _make_bevel_gear_system,
+ _make_crown_gear,
+ _make_rack_gear,
+ register
+)
+register()
\ No newline at end of file
diff --git a/plugins/gear_generator/gear_generator/cutter_objects.py b/plugins/gear_generator/gear_generator/cutter_objects.py
new file mode 100644
index 0000000..1a8380f
--- /dev/null
+++ b/plugins/gear_generator/gear_generator/cutter_objects.py
@@ -0,0 +1,182 @@
+"""
+This module stores functions that are used by the make_XXX_gear functions but are not intended to be used by the final user
+"""
+
+import cadquery as cq
+from math import *
+from .helpers import involute, test_bevel_parameters, rotate_vector_2D
+
+
+def _make_rack_tooth_gap(self, m, b, alpha = 20, helix_angle = None):
+ """
+ Creates a solid which represents the gap between the teeth of the rack gear
+
+ Parameters
+ ----------
+ m : float
+ Crown gear modulus
+ b : float
+ Tooth width
+ alpha : float
+ Pressure angle in degrees, industry standard is 20°
+ helix_angle : float
+ Helix angle in degrees to create a helical rack gear
+
+ Returns
+ -------
+ cq.Workplane
+ Returns the tooth gap solid in a cq.Workplane using eachpoint method
+ """
+ p = pi*m
+ alpha = radians(alpha)
+
+ A = (-2.25*m*sin(alpha)-(p/2 - 2*m*sin(alpha)),0)
+ B = (-(p/2 - 2*m*sin(alpha)), -2.25*m*cos(alpha))
+ C = (B[0] + (p/2 - 2*m*sin(alpha)), -2.25*m*cos(alpha))
+ D = (C[0] + 2.25*m*sin(alpha), 0)
+ tooth_wire = (cq.Workplane("XY").polyline([A,B,C,D])).close()
+ if helix_angle is None:
+ tooth = tooth_wire.extrude(b)
+ else:
+ helix_angle = radians(helix_angle)
+ tooth = tooth_wire.center(tan(helix_angle)*b, 0).workplane(offset=b).polyline([A,B,C,D]).close().loft()
+ return self.eachpoint(lambda loc: tooth.val().located(loc), True)
+
+def _make_bevel_tooth_gap_wire(self, Z_W, m, phi, r_a, r_f, r_base):
+ """
+ Creates the bevel tooth gap wire that will be lofted to a vertex to make the cutter object
+
+ Parameters
+ ----------
+ Z_W : float
+ Z position of the top of the complementary cone in the coord system which as it's origin at the bevel gear cone top point
+ m : float
+ Bevel gear modulus
+ phi : float
+ Complementary cone angle in radians
+ r_a : float
+ Associated virtual spur gear top radius
+ r_f : float
+ Associated virtual spur gear root radius
+ r_base : float
+ Associated virtual spur gear base radius
+
+ Returns
+ -------
+ cq.Workplane
+ Returns a wire in a cq.Workplane that defines the tooth gap cross section at the bevel outer radius
+ """
+ STOP = 2*sqrt((r_a/r_base)**2 - 1) # 2* To be sure to have extra working room
+ #right side
+ right = (cq.Workplane("XY", origin=(0,0,Z_W)).transformed(rotate=(-pi*m,-90+degrees(phi),0))
+ .tag("baseplane")
+ .parametricCurve(involute(r_base), N=8, stop=STOP, makeWire=False))
+ bot_right = right.moveTo(r_f,0).hLine(r_base-r_f)
+ #left side
+ left = (cq.Workplane("XY", origin=(0,0,Z_W)).transformed(rotate=(pi*m,-90+degrees(phi),0))
+ .moveTo(r_f,0)
+ .hLine(r_base-r_f)
+ .parametricCurve(involute(r_base, sign=-1), N=8, stop=STOP, makeWire=False))
+ bot_left = left.moveTo(r_f,0).hLine(r_base-r_f)
+ #Getting points to close the wire
+ pt_top_right = right.vertices(">X").val()
+ pt_bot_right = bot_right.vertices("X").val()
+ pt_bot_left = bot_left.vertices(" clearance_max:
+ raise ValueError(f"Too much clearance, for this set of parameters clearance must be <= {round(clearance_max,3)}")
+
+def rotate_vector_2D(vector, angle):
+ """
+ Rotates a 2D cq.Vector
+
+ Parameters
+ ----------
+ vector : cq.Vector
+ Vector to be rotated
+ angle : float
+ The angle in degrees
+
+ Returns
+ -------
+ cq.Vector
+ Returns a vector rotated by the specified angle
+ """
+ angle = radians(angle)
+ x = cos(angle)*vector.x - sin(angle)*vector.y
+ y = sin(angle)*vector.x + cos(angle)*vector.y
+ return cq.Vector((x,y))
\ No newline at end of file
diff --git a/plugins/gear_generator/gear_generator/main.py b/plugins/gear_generator/gear_generator/main.py
new file mode 100644
index 0000000..9e39f52
--- /dev/null
+++ b/plugins/gear_generator/gear_generator/main.py
@@ -0,0 +1,306 @@
+import cadquery as cq
+from math import pi, cos, sin, tan, sqrt, degrees, radians, atan2, atan, acos
+from .helpers import involute, test_bevel_parameters, rotate_vector_2D
+from .cutter_objects import _make_bevel_tooth_gap_wire, _make_rack_tooth_gap, _make_crown_gear_tooth_gap, register_cutter_objects
+from OCP.BRepOffsetAPI import BRepOffsetAPI_ThruSections
+
+register_cutter_objects()
+
+def _make_bevel_gear(self, m, z, b, delta, alpha = 20, clearance = None):
+ """
+ Creates a bevel gear
+
+ Parameters
+ ----------
+ m : float
+ Crown gear modulus
+ z : int
+ Number of teeth
+ b : float
+ Tooth width
+ delta : float
+ Cone angle in degrees
+ alpha : float
+ Pressure angle in degrees, industry standard is 20°
+ clearance : float
+ Spacing after teeth root to add some material below the teeth
+ Below a (half) bevel gear sketch to understand what is the clearance
+ ____
+ / / } addendum
+ ____/___/ } dedendum
+ _______/ } clearance (the length of the tilted bar)
+
+ Returns
+ -------
+ cq.Workplane
+ Returns the bevel gear solid in a cq.Workplane using eachpoint method
+ """
+
+ # PARAMETERS
+ delta = radians(delta) # cone angle
+ phi = pi/2 - delta # complementary cone angle
+ r = m*z/2 # pitch radius
+ r_inner = r-b*sin(delta) #pitch radius inner radius
+ r_equiv_outer = r/sin(phi) #pitch radius of the associated virtual spur gear
+ r_base_equiv = r_equiv_outer*cos(radians(alpha)) #base radius of the associated virtual spur gear
+ r_f_equiv = (r - 1.25*m*cos(delta))/sin(phi) #root radius of the associated virtual spur gear
+ r_a_equiv = (r + m*cos(delta))/sin(phi) #top radius of the associated virtual spur gear
+ h_f = 1.25*m # dedendum
+ h_a = m # addendum
+ # Z positions of outer and inner pitch radius and top of complementary cone
+ Z_P = -r/tan(delta)
+ Z_P_inner = - r_inner/tan(delta)
+ Z_W = (Z_P - r/tan(phi))*1.0000001 # This allow for the tooth gap wire to be slightly shifted otherwise leads to failing cut operation
+ if clearance is None:
+ clearance = 0.2*r
+ # Test if input parameters make a valid gear
+
+ test_bevel_parameters(m, z, b, r_inner, delta, alpha, phi, clearance, r_f_equiv, r_base_equiv)
+
+ #Definition of bevel half cross section points
+ A = (r + h_a*cos(delta), 0, Z_P + h_a*sin(delta))
+ B = (r - h_f*cos(delta), 0, Z_P - h_f*sin(delta))
+ C = (r - clearance*cos(delta), 0, Z_P - clearance*sin(delta))
+ D = (0, 0, C[2])
+ H = (r_inner + h_a*cos(delta), 0, Z_P_inner + h_a*sin(delta))
+ G = (r_inner - h_f*cos(delta), 0, Z_P_inner - h_f*sin(delta))
+ F = (r_inner - clearance*cos(delta), 0, Z_P_inner - clearance*sin(delta))
+ E = (0, 0, F[2])
+
+ #Creation of the half cross section
+ edges = []
+ edges.append(cq.Edge.makeLine(cq.Vector(A), cq.Vector (B)))
+ edges.append(cq.Edge.makeLine(cq.Vector(B), cq.Vector (C)))
+ edges.append(cq.Edge.makeLine(cq.Vector(C), cq.Vector (D)))
+ edges.append(cq.Edge.makeLine(cq.Vector(D), cq.Vector (E)))
+ edges.append(cq.Edge.makeLine(cq.Vector(E), cq.Vector (F)))
+ edges.append(cq.Edge.makeLine(cq.Vector(F), cq.Vector (G)))
+ edges.append(cq.Edge.makeLine(cq.Vector(G), cq.Vector (H)))
+ edges.append(cq.Edge.makeLine(cq.Vector(H), cq.Vector (A)))
+ cross_sec = cq.Wire.assembleEdges(edges)
+ #Making base solid
+ base = cq.Solid.revolve(cross_sec,[],360, cq.Vector(0,0,0), cq.Vector(0,0,1))
+
+ tooth_gap = cq.Workplane("XY")._make_bevel_tooth_gap_wire(Z_W, m, phi, r_a_equiv, r_f_equiv, r_base_equiv)
+
+ builder = BRepOffsetAPI_ThruSections(True,False) #Builder to create loft to vertex
+ builder.AddWire(tooth_gap.val().wrapped)
+ builder.AddVertex(cq.Vertex.makeVertex(0,0,0).wrapped)
+ cutter = cq.Workplane(obj=cq.Shape.cast(builder.Shape())) #cutter solid
+ #Make a compound of cutters
+ cutters = []
+ for i in range(z):
+ angle = 360/z*i
+ cutters.append(cutter.rotate((0,0,0),(0,0,1),angle).val())
+ final_cutter = cq.Compound.makeCompound(cutters)
+ gear = base.cut(final_cutter)
+ return self.eachpoint(lambda loc: gear.located(loc), True)
+
+def _make_bevel_gear_system(self, m, z1, z2, b, alpha=20, clearance = None, compound = True):
+ """
+ Creates a bevel gear system made of two bevel gears
+
+ Parameters
+ ----------
+ m : float
+ Bevel gears modulus (to be able to mesh they need the same modulus)
+ z1 : int
+ Number of teeth of the first bevel gear
+ z2 : int
+ Number of teeth of the second bevel gear
+ b : float
+ Tooth width
+ delta : float
+ Cone angle in degrees
+ alpha : float
+ Pressure angle in degrees, industry standard is 20°
+ clearance : float
+ Spacing after teeth root to add some material below the teeth
+ Below a (half) bevel gear sketch to understand what is the clearance
+ ____
+ / / } addendum
+ ____/___/ } dedendum
+ _______/ } clearance (the length of the tilted bar)
+
+ Returns
+ -------
+ cq.Workplane
+ If compound = True, returns a cq.Workplane object with the two gears in a cq.Compound
+ tuple
+ If compound = False, returns a 2-tuple with the two gear solid in a cq.Workplane
+ """
+ delta_1 = degrees(atan2(z2,z1))
+ delta_2 = degrees(atan2(z1,z2))
+ gear1 = cq.Workplane("XY").make_bevel_gear(m, z1, b, delta_1, alpha = alpha, clearance = clearance)
+ gear2 = cq.Workplane("YZ").make_bevel_gear(m, z2, b, delta_2, alpha = alpha, clearance = clearance)
+
+ if compound:
+ compound = cq.Compound.makeCompound([gear1.val(), gear2.val()])
+ return self.eachpoint(lambda loc: compound.located(loc), True)
+ else:
+ return gear1, gear2
+
+def _make_gear(self, m, z, b, alpha=20, helix_angle = None, raw = False):
+ """
+ Creates a spur or helical involute gear
+
+ Parameters
+ ----------
+ m : float
+ Spur gear modulus
+ z : int
+ Number of teeth
+ b : float
+ Tooth width
+ alpha : float
+ Pressure angle in degrees, industry standard is 20�
+ helix_angle : float
+ Helix angle of the helical gear in degrees
+ If None creates a spur gear, if specified create a helical gear
+ raw : bool
+ False : Adds filleting a the root teeth edges
+ True : Leave the gear with no filleting
+
+ Returns
+ -------
+ cq.Workplane
+ Returns the gear solid in a cq.Workplane using eachpoint method
+ """
+
+ alpha = radians(alpha)
+
+ # radii
+ r_p = m*z/2
+ r_a = r_p + m
+ r_base = r_p*cos(alpha)
+ r_f = r_p - 1.25*m
+ p = pi * m
+ inv = lambda a: tan(a) - a
+
+ # angles of interest
+ alpha_inv = inv(alpha)
+ alpha_tip = acos(r_base/r_a)
+ alpha_tip_inv = inv(alpha_tip)
+
+ a = 90/z+degrees(alpha_inv)
+ a2 = 90/z+degrees(alpha_inv)-degrees(alpha_tip_inv)
+ STOP = sqrt((r_a/r_base)**2 - 1)
+ # construct all the profiles
+ left = (
+ cq.Workplane()
+ .transformed(rotate=(0,0,a))
+ .parametricCurve(involute(r_base,-1), start=0, stop = STOP, makeWire=False, N=8)
+ .val()
+ )
+
+ right = (
+ cq.Workplane()
+ .transformed(rotate=(0,0,-a))
+ .parametricCurve(involute(r_base), start=0, stop = STOP, makeWire=False, N=8)
+ .val()
+ )
+
+ top = cq.Edge.makeCircle(r_a,angle1=-a2, angle2=a2)
+
+ p0 = left.startPoint()
+ p1 = right.startPoint()
+ side0 = cq.Workplane(origin=p0.toTuple()).hLine(r_f-r_base).val()
+ side1 = cq.Workplane(origin=p1.toTuple()).hLine(r_f-r_base).val()
+ side2 = side0.rotate(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), -360/z)
+
+ p_bot_left = side1.endPoint()
+ p_bot_right = rotate_vector_2D(side0.endPoint(), -360/z)
+
+ bottom = cq.Workplane().moveTo(p_bot_left.x, p_bot_left.y).radiusArc(p_bot_right,r_f).val()
+
+ # single tooth profile
+ profile = cq.Wire.assembleEdges([left,top,right,side1,bottom, side2])
+ # return profile
+ if not raw:
+ profile = profile.fillet2D(0.25*m, profile.Vertices()[-3:-1])
+ # complete gear
+ gear = (
+ cq.Workplane()
+ .polarArray(0,0,360,z)
+ .each(lambda loc: profile.located(loc))
+ .consolidateWires()
+ )
+ if helix_angle is None:
+ gear = gear.extrude(b)
+ else:
+ gear = gear.twistExtrude(b, helix_angle)
+ return self.eachpoint(lambda loc: gear.val().located(loc), True)
+
+def _make_crown_gear(self, m, z, b, alpha = 20, clearance = None):
+ """
+ Create a crown gear (which is the same as a rack gear made circular, also called face gear)
+
+ Parameters
+ ----------
+ m : float
+ Crown gear modulus
+ z : int
+ Number of teeth
+ b : float
+ Tooth width
+ alpha : float
+ Pressure angle in degrees, industry standard is 20°
+ clearance : float
+ The height of the cylinder under the teeth
+ If None, clearance is equal to 1.7*m
+
+ Returns
+ -------
+ cq.Workplane
+ Returns the crown gear solid in a cq.Workplane using eachpoint method
+ """
+ r = m*z/2
+ if clearance is None:
+ clearance = 1.7*m
+ base = cq.Workplane("XY").tag("base").circle(r).extrude(-2.25*m-clearance)
+
+ teeths = cq.Workplane("XY").polarArray(0,0,360,z)._make_crown_gear_tooth_gap(m, r, alpha)
+ teeths = cq.Compound.makeCompound(teeths.vals())
+ gear = base.cut(teeths)
+ gear = gear.cut(cq.Workplane("XY", origin=(0,0,-2.25*m)).circle(r-b).extrude(2.25*m))
+
+ return self.eachpoint(lambda loc: gear.val().located(loc), True)
+
+def _make_rack_gear(self, m, b, length, clearance, alpha = 20, helix_angle = None):
+ """
+ Creates a rack gear
+
+ Parameters
+ ----------
+ m : float
+ Crown gear modulus
+ b : float
+ Tooth width / rack gear width
+ length : float
+ Length of the rack gear
+ alpha : float
+ Pressure angle in degrees, industry standard is 20°
+ helix_angle : float
+ Helix angle in degrees to create a helical rack gear
+
+ Returns
+ -------
+ cq.Workplane
+ Returns the rack gear solid in a cq.Workplane using eachpoint method
+ """
+ p = pi*m
+ z = int(length // p)+1
+ height = 2.25*m*cos(alpha) + clearance
+ points = [(p*i,0) for i in range(z)] + [(-p*i,0) for i in range(z)]
+ teeths = cq.Workplane("XY").pushPoints(points)._make_rack_tooth_gap(m, b, alpha, helix_angle)
+ base = cq.Workplane("ZY").rect(b, -height, centered=False).extrude(-length)
+ gear = base.cut(teeths)
+ return self.eachpoint(lambda loc: gear.val().located(loc), True)
+
+# Adds the functions to cq.Workplane class, it seems to be needed for cq-editor
+def register():
+ cq.Workplane.make_gear = _make_gear
+ cq.Workplane.make_bevel_gear = _make_bevel_gear
+ cq.Workplane.make_bevel_gear_system = _make_bevel_gear_system
+ cq.Workplane.make_rack_gear = _make_rack_gear
+ cq.Workplane.make_crown_gear = _make_crown_gear
\ No newline at end of file
diff --git a/plugins/gear_generator/images/bevel_gear.PNG b/plugins/gear_generator/images/bevel_gear.PNG
new file mode 100644
index 0000000..a475df0
Binary files /dev/null and b/plugins/gear_generator/images/bevel_gear.PNG differ
diff --git a/plugins/gear_generator/images/bevel_gear_system.PNG b/plugins/gear_generator/images/bevel_gear_system.PNG
new file mode 100644
index 0000000..12343f8
Binary files /dev/null and b/plugins/gear_generator/images/bevel_gear_system.PNG differ
diff --git a/plugins/gear_generator/images/crown_gear.PNG b/plugins/gear_generator/images/crown_gear.PNG
new file mode 100644
index 0000000..ae90119
Binary files /dev/null and b/plugins/gear_generator/images/crown_gear.PNG differ
diff --git a/plugins/gear_generator/images/helical_gear.PNG b/plugins/gear_generator/images/helical_gear.PNG
new file mode 100644
index 0000000..3a0f74b
Binary files /dev/null and b/plugins/gear_generator/images/helical_gear.PNG differ
diff --git a/plugins/gear_generator/images/rack_gear_helix.PNG b/plugins/gear_generator/images/rack_gear_helix.PNG
new file mode 100644
index 0000000..7fee284
Binary files /dev/null and b/plugins/gear_generator/images/rack_gear_helix.PNG differ
diff --git a/plugins/gear_generator/images/rack_gear_straight.PNG b/plugins/gear_generator/images/rack_gear_straight.PNG
new file mode 100644
index 0000000..406dc0f
Binary files /dev/null and b/plugins/gear_generator/images/rack_gear_straight.PNG differ
diff --git a/plugins/gear_generator/images/readme_example.PNG b/plugins/gear_generator/images/readme_example.PNG
new file mode 100644
index 0000000..50ef59b
Binary files /dev/null and b/plugins/gear_generator/images/readme_example.PNG differ
diff --git a/plugins/gear_generator/images/straight_gear.PNG b/plugins/gear_generator/images/straight_gear.PNG
new file mode 100644
index 0000000..1484155
Binary files /dev/null and b/plugins/gear_generator/images/straight_gear.PNG differ
diff --git a/plugins/gear_generator/setup.py b/plugins/gear_generator/setup.py
new file mode 100644
index 0000000..766a2c3
--- /dev/null
+++ b/plugins/gear_generator/setup.py
@@ -0,0 +1,44 @@
+from setuptools import setup, find_packages
+
+version = '1.0.0' # Please update this version number when updating the plugin
+plugin_name = 'gear_generator'
+description = 'Add methods to create all sort of gears'
+long_description = ''
+author = 'Romain FERRU'
+author_email = 'Romain.ferru@gmail.com'
+install_requires = [] # Any dependencies that pip also needs to install to make this plugin work
+
+
+setup(
+ name=plugin_name,
+ version=version,
+ url='https://github.com/CadQuery/cadquery-plugins',
+ license='Apache Public License 2.0',
+ author=author,
+ author_email=author_email,
+ description=description,
+ long_description=long_description,
+ packages=find_packages(where='gear_generator'),
+ install_requires=install_requires,
+ include_package_data=True,
+ zip_safe=False,
+ platforms='any',
+ test_suite='tests',
+
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: End Users/Desktop',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: Science/Research',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: POSIX',
+ 'Operating System :: MacOS',
+ 'Operating System :: Unix',
+ 'Programming Language :: Python',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: Internet',
+ 'Topic :: Scientific/Engineering'
+ ]
+)
diff --git a/tests/test_gear_generator.py b/tests/test_gear_generator.py
new file mode 100644
index 0000000..340cd97
--- /dev/null
+++ b/tests/test_gear_generator.py
@@ -0,0 +1,106 @@
+import cadquery as cq
+import plugins.gear_generator.gear_generator
+from unittest import TestCase
+
+class TestGearGenerator(TestCase):
+ def test_make_bevel_gear(self):
+ """
+ Tests if the bevel gear has been created successfully
+ by checking if it's valid and it's resulting volume
+ Numerical values volumes were obtained with the Volume() functions on a Windows 10 machine with python 3.8.8
+ """
+ m = 1.5
+ z = 16
+ b = 6
+ delta = 40
+ alpha = 20
+ clearance = 6
+ gear = cq.Workplane().make_bevel_gear(m, z, b, delta, alpha = alpha, clearance = clearance)
+ self.assertTrue(gear.val().isValid())
+ self.assertAlmostEqual(gear.val().Volume(),2226.028600964595)
+
+
+ def test_make_bevel_gear_system(self):
+ """
+ Tests if the bevel gear system been created successfully
+ by checking if it's valid and it's resulting volume
+ Numerical values volumes were obtained with the Volume() functions on a Windows 10 machine with python 3.8.8
+ """
+ m = 1
+ z1 = 16
+ z2 = 22
+ b = 2
+ alpha = 20
+ clearance = 3
+
+ frozen_gear_system = cq.Workplane().make_bevel_gear_system(m, z1, z2, b, alpha=alpha, clearance = clearance, compound = True)
+ self.assertTrue(frozen_gear_system.val().isValid())
+ self.assertAlmostEqual(frozen_gear_system.val().Volume(),1024.4382489861382)
+
+ gear1, gear2 = cq.Workplane().make_bevel_gear_system(m, z1, z2, b, alpha=alpha, clearance = clearance, compound = False)
+ self.assertTrue(gear1.val().isValid())
+ self.assertAlmostEqual(gear1.val().Volume(),338.4940609342948)
+
+ self.assertTrue(gear2.val().isValid())
+ self.assertAlmostEqual(gear2.val().Volume(),685.9422647793748)
+
+
+ def test_make_gear(self):
+ """
+ Tests if the gear has been created successfully
+ by checking if it's valid and it's resulting volume
+ Numerical values volumes were obtained with the Volume() functions on a Windows 10 machine with python 3.8.8
+ """
+ m = 1.5
+ z = 16
+ b = 6
+ alpha = 20
+ clearance = 6
+ helix_angle = 40
+
+ gear1 = cq.Workplane().make_gear(m, z, b, alpha=alpha, raw = False)
+ self.assertTrue(gear1.val().isValid())
+ self.assertAlmostEqual(gear1.val().Volume(),2646.766251684174)
+
+ gear2 = cq.Workplane().make_gear(m, z, b, alpha=alpha, helix_angle = helix_angle, raw = False)
+ self.assertTrue(gear2.val().isValid())
+ self.assertAlmostEqual(gear2.val().Volume(),2646.816968237718)
+
+
+ def test_make_crown_gear(self):
+ """
+ Tests if the crown gear has been created successfully
+ by checking if it's valid and it's resulting volume
+ Numerical values volumes were obtained with the Volume() functions on a Windows 10 machine with python 3.8.8
+ """
+ m = 1.5
+ z = 16
+ b = 6
+ alpha = 20
+ clearance = 6
+
+ gear = cq.Workplane().make_crown_gear(m, z, b, alpha = alpha, clearance = clearance)
+ self.assertTrue(gear.val().isValid())
+ self.assertAlmostEqual(gear.val().Volume(),3352.5459114045543)
+
+ def test_make_rack_gear(self):
+ """
+ Tests if the rack gear has been created successfully
+ by checking if it's valid and it's resulting volume
+ Numerical values volumes were obtained with the Volume() functions on a Windows 10 machine with python 3.8.8
+ """
+ m = 1.5
+ z = 16
+ b = 6
+ length = 40
+ alpha = 20
+ clearance = 6
+ helix_angle = 45
+
+ gear1 = cq.Workplane().make_rack_gear(m, b, length, clearance, alpha = alpha)
+ self.assertTrue(gear1.val().isValid())
+ self.assertAlmostEqual(gear1.val().Volume(),1381.355198257374)
+
+ gear2 = cq.Workplane().make_rack_gear(m, b, length, clearance, alpha = alpha, helix_angle = helix_angle)
+ self.assertTrue(gear2.val().isValid())
+ self.assertAlmostEqual(gear2.val().Volume(),1369.2236732856904)