_
Border
Go to New-CVT Go to New-CVT
Go to New-CVT
Go to New-CVT
Home Video FAQ Theory Media Source code Contact
Source code
Here we present the proof for all to see and scrutinise

The history of geared CVTs is one of many failed attempts. Many even patented. Though none going so deep into the fundamentals of involute gearing as we have done. So here we present the proof for all to see. The source code is formatted for use in the free software package called blender, so it is accessible to all. All you need to know is in here. Everybody in the world can test it! We are not afraid, we are sure, we have tested it ourselves.

Instructions for using this source code: Go to www.blender.org and install the latest version of blender (its free). In blender go to the tab 'Scripting', select the tab 'Text' and then click 'New'. Copy and paste the source code below into the empty space. Press the triangle/play icon to run the script (pressing the spacebar with the mouse within the viewing area might be required for starting the animation).

''' INSTRUCTIONS FOR USING THIS SOURCE CODE Go to www.blender.org and install the latest version of blender (its free). In blender go to the tab 'Scripting', select the tab 'Text' and then click 'New' Copy and paste this source code into the empty space. Press the triangle/play icon to run the script (pressing the spacebar with the mouse within the viewing area might be required for starting the animation) You should now see the first demo. You can select other demos by changing the value of Show_Demo. You can change demo 1 by changing the settings below. Please feel free to experiment. Note that blender has the horrible tendency to make changes that are not backwards compatible, even between minor upgrades. So this source code might not work directly in your version of blender. Due to bugs in blender there are parts in the source code that are logically incorrect, but which were necessary to get it working in blender. Once they fix those bugs the source code will probably fail at those points. We try keep our source code up to date with the latest version of blender, so please let us know if our source code does not work and we will fix it. Note to the blender community. Many thanks for creating the software and we hope that you will have a lot of fun with this source code. We used blender because of the high quality animations that it can produce as well as the fact that it is open to everybody as it’s free. It would be nice tough if it could have the option to be more geared to precise engineering (see OpenScad) and with less bugs. ''' Show_Preset_Animation = False Show_Demo = 1 ''' Show_Demo = 1 => Show New-CVT demo Show_Demo = 2 => Show 3D involute shape demo Show_Demo = 3 => Show mulit-ratio gear demo Show_Demo = 4 => Show 3D conical involute gear demo Show_Demo = 5 => Print the demonstration model with 3 gears Show_Demo = 6 => Print the spinner with 3 gears Show_Demo = 7 => Print Lego multi-ratio spur gear plus pinion gear ''' bl_info = { "name": "3D Involute", "author": "New-CVT.com", "version": (1, 1), "blender": (2, 93, 4), "location": "View3D > Add > Mesh > New Object", "description": "Add a 3D Involute", "warning": "", "wiki_url": "", "category": "Add Mesh",} import bpy from bpy.types import Operator from bpy_extras.object_utils import AddObjectHelper, object_data_add from math import pi, sin, cos, tan, sqrt, acos, asin, atan, log from bpy.props import BoolProperty, IntProperty, FloatProperty import bmesh import mathutils import math #Default_Angle_Resolution = 0.001*pi # High resolution / Slow #Default_Angle_Resolution = 0.005*pi # High resolution / Slow #Default_Angle_Resolution = 0.01*pi # Fast / Low resolution #Default_Angle_Resolution = 0.02*pi # Fast / Low resolution Default_Angle_Resolution = 0.05*pi # For debug purposes # All following settings are for the New-CVT demo. Show_Changing_Gear = False Only_Show_Pinion_1 = True # When running the New-CVT demo, setting this to True will only show pinion 1 and the gear # it is intermeshing with. Only_Show_Pinion_1_WIREFRAME = True Default_show_lines = False # When running the New-CVT demo, setting this to True will show the axes. Default_show_pinion_1 = True # When running the New-CVT demo, setting this to True will show pinion 1. Default_show_pinion_2 = True # When running the New-CVT demo, setting this to True will show pinion 2. Default_Pos_Pinion_1 = 0 # When running the New-CVT demo, this number sets the position of pinion 1 on the main gear. # It starts with 0 at the top. Default_Pos_Pinion_2 = 8 # When running the New-CVT demo, this number sets the position of pinion 2 on the main gear. # It starts with 0 at the top. Default_start_with_number_of_teeth = 8 # As low as 6 is possible in this software, but it will require deeper root cuts. # The value must be an even number. Also adjust Tangent_slide_glitch_backlash Default_number_of_gears = 9 # with 8 teeth start => 1:1-1:4 Changing this might require adjustmet of Tangent_slide_glitch_backlash #Default_number_of_gears = 9 # with 8 teeth start => 1:1-1:9 Changing this might require adjustmet of Tangent_slide_glitch_backlash Pinion_Number_Of_Teeth = 12 Pinion_Height = 0.8 # This is the fraction actually used of the height theoretically available (=1) for the height of the pinions Backlash = 0 # A backlash of zero is great for showing how good a theoretical model is, but if you want to print this I suggest using # a bigger value as all real world gearing needs some backlash in order to work. Add_Base_Circle = True #Base_Circle_Width = 0.001 Base_Circle_Width = 0.02 Base_Circle_vertices = 100#0 Base_Circle_Extra_Height = 1 ''' The invention is like a perfect puzzle revealing itself, and seeing it in action you won't notice it, but theoretically there is one slight complication you should be aware of. Namely that the intermeshing line, and the line over which the gears slide over one and other, are not the same. We call it the ‘Tangent slide glitch’. It results in a little backlash in places, and an optimalisation around a standard pressure angle of arctan(1/2). But it does not effect the intermeshing line of contact, so it is not a real problem, just a slight complication in an otherwise beautiful theoretical puzzle. The root cause is that with conical gears, the average operating pressure angle changes as the pinion slides up and down. And this complicates the mathematics considerably as different parts of the involute curve are therefore interacting. So, for example, the 2D formula for calculating the reference circle is slightly off. And as this formula is one of the corner stones of the invention, an optimalisation by hand of the backlash was required. ''' #Tangent_slide_glitch_backlash = -0.0197 # 10 teeth - 6 gears Tangent_slide_glitch_backlash = -0.0186 # 8 teeth - 5 gears #Tangent_slide_glitch_backlash = 0 # 6 teeth - 13 gears Default_Centre_Pressure_Angle = atan(0.5) # = 26.565 degrees – At this value the backlash at the top and bottom gear seems about he same. # Why atan(0.5) seems so perfect I don’t know, I found it trough optimalisation. Pinion_Tip_Cut_At_Number_Of_Extra_Teeth = 0.5 Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth = 0.5 ''' When conical do not slide over one and another, the best angle to cut the tips of the teeth is the same angle as the intermeshing angle at that point of the tooth. However, if the gears do slide over one and another, the story becomes a little more complex as we need to compensate for the involute curve going evermore flat the further away it is from the base circle. So some hand optimalisation might be required. In fact the cut doesn’t even need to be a strait line. ''' Tip_Cut_Angle = atan(1) # This is the angle (going down) at which the tips of the teeth are cut. Arrow_Thickness = 0.5 # If Default_show_lines = True, then this sets the tickness of the lines Arrow_Extra_Length_At_ends = 13 # If Default_show_lines = True, then this sets the exrta length of the lines # - LDU = 0.4 # mm = Lego Draw Unit Lego_Brick_Gap_Horizontal = 0.25 * LDU # = 0.1 mm - Not official, but use it to allow for slight gaps between the bricks Lego_Brick_Width_Depth = 20 * LDU # = 8.0 mm Lego_Brick_Height = 24 * LDU # = 9.6 mm Lego_Brick_Thickness_Walls = 3.75 * LDU # = 1.5 mm Lego_Plate_Height = 8 * LDU # = 3.2 mm Lego_Stud_Diameter = 12 * LDU # = 4.8 mm Lego_Stud_Height = 4 * LDU # = 1.6 mm Lego_Pin_Outer_Diameter = 15.25 * LDU # = 6.1 mm Lego_Pin_Inner_Diameter = 12.25 * LDU # = 4.9 mm Lego_Pin_Length = 40 * LDU # = 16.0 mm Lego_Pin_Outside_Ridge_Width = 2.25 * LDU # = 0.9 mm Lego_Pin_Middle_Ridge_Width = 4.50 * LDU # = 1.8 mm Lego_Pin_Centre_From_Ground = 14 * LDU # = 5.6 mm Lego_Technic_Shaft_Out = 12 * LDU # = 4.8 mm Lego_Technic_Shaft_In = 4.5 * LDU # = 1.8 mm Lego_Technic_Shaft_InRadius = 1 * LDU # = 0.4 mm # 699 POM Plastic ball bearings with Glass balls nylon bearing # https://www.aliexpress.com/item/4000570148861.html?spm=a2g0s.9042311.0.0.368c4c4dzHgQ7N Bearing_9x20x6mm_Outer = 20.08#20.35 # mm Bearing_9x20x6mm_Inner = 9.22#9.23#9.24#9.22#9.25#9.17#9.02#9 # mm Bearing_9x20x6mm_Height = 5.98#6.3 # mm Bearing_9x20x6mm_Ridge = 2.5 # mm # 695 POM Plastic ball bearings with Glass balls nylon bearing # https://www.aliexpress.com/item/4000570148861.html?spm=a2g0s.9042311.0.0.368c4c4dzHgQ7N Bearing_5x13x4mm_Outer = 13.11#13.12#12.97 # mm Bearing_5x13x4mm_Inner = 5.12#5.11#5.10 #5.15 #4.97 # mm Bearing_5x13x4mm_Height = 4.15 #3.95 # mm Bearing_5x13x4mm_Ridge = 1.8 # mm # JMT Carbon Fiber Square Tube Length 500mm for RC DIY Model Aircraft # https://www.aliexpress.com/item/4000598610107.html?spm=a2g0s.9042311.0.0.368c4c4dzHgQ7N Carbon_Fiber_Square_Tube_6x6x5mm_Outer_Witdh = 6 # mm Carbon_Fiber_Square_Tube_6x6x5mm_Inner_Witdh = 5 # mm Carbon_Fiber_Square_Tube_6x6x5mm_Length = 50 # mm # ------------------------------------------------------------------------------------------------------------------- Backlash = Backlash + Tangent_slide_glitch_backlash if (Only_Show_Pinion_1) and (Show_Demo == 1): Pinion_Height = 1 # Here we want the pinion to be of the same height Default_show_pinion_2 = False Show_Preset_Animation = False Only_Show_Pinion_1_WIREFRAME = True Add_Base_Circle = True if Show_Preset_Animation: Show_Changing_Gear = True Only_Show_Pinion_1 = False Default_show_pinion_1 = True Default_show_pinion_2 = True Default_Pos_Pinion_1 = 0 Default_Pos_Pinion_2 = 8 # ------------------------------------------------------------------------------------------------------------------- class InvoluteMenu(bpy.types.Menu): bl_label = "Involute" bl_idname = "OBJECT_MT_my_custom_menu" def draw(self, context): layout = self.layout layout.operator(OBJECT_OT_add_3d_involute_math.bl_idname, text="3D Involute - This shape is the mathematical basis of all involute gears (2D and 3D)", icon='PLUGIN') layout.operator(OBJECT_OT_add_3d_spur_gear.bl_idname, text="Spur_gear (2D & 3D)", icon='PLUGIN') layout.operator(OBJECT_OT_add_3d_cvt.bl_idname, text="New CVT", icon='PLUGIN') layout.operator(OBJECT_OT_add_2_ratio_2d_spur_gear.bl_idname, text="2D spur gear with 2 gear ratio’s", icon='PLUGIN') layout.operator(OBJECT_OT_add_3_gear_demo.bl_idname, text="3_gear_demo", icon='PLUGIN') layout.operator(OBJECT_OT_add_spinner.bl_idname, text="spinner", icon='PLUGIN') layout.operator(OBJECT_OT_add_lego_gears.bl_idname, text="lego_gears", icon='PLUGIN') layout.operator(OBJECT_OT_add_truck_cvt.bl_idname, text="Truck_CVT", icon='PLUGIN') def InvoluteMenuAdd(self, context): self.layout.menu(InvoluteMenu.bl_idname) # ------------------------------------------------------------------------------------------------------------------- # blender functions def applyBoolean(operation, ob, base): # Note: This function in blender is not perfect. Sometimes you need to move # objects a little bit for it to work (if you are lucky). """For operation use either UNION, DIFFERENCE, or INTERSECT""" mod = ob.modifiers.new("", 'BOOLEAN') mod.object = base mod.operation = operation mod.double_threshold = 0.0 bpy.context.view_layer.objects.active = ob bpy.ops.object.modifier_apply(modifier=mod.name) bpy.data.objects.remove(base) def Pos_Pinion(n_id, start_with_number_of_teeth, number_of_gears): # Use this to set the position of the pinion. The top gear has n_id = 0 gear_id = int(n_id / 2) switch = n_id - (2*gear_id) # ? 0 ==> running !? 1 ==> switch gear number_of_teeth = (start_with_number_of_teeth + gear_id*2) + switch height = 2*(number_of_gears - gear_id) - switch - 2 x = reference_circle_radius(number_of_teeth + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash y = height + 1 - 0.5 * (1-Pinion_Height) return gear_id, switch, number_of_teeth, height, x, y # ------------------------------------------------------------------------------------------------------------------- # 3D (and 2D) involute functions #def pressure_angle(number_of_teeth_A, number_of_teeth_B, distance_between_axes_A_B): # return acos( (number_of_teeth_A + number_of_teeth_B) / distance_between_axes_A_B) def reference_circle_radius(number_of_teeth_A, pressure_angle_A): return number_of_teeth_A / cos(pressure_angle_A) def start_angle_calc(pa, n): # Centre_Pressure_Angle, number_of_teeth # perfect intermeshing with different number of teeth as long as the Centre_Pressure_Angle in the same #t = r*sin(pa)/cos(pa) # half of the tangent length of two identical gears when their intermeshing point is on the x-axe (so precisly half way) #b = t / r # The angle reqiured to create the involute curve at the intermeshing point # divide by r => # b = tan(pa) # = sin(pa)/cos(pa) # = sqrt((1 / sqr(cos(pa))) - 1) # j = b - pa # The angle that intermeshing point falls behind the point where the involute curve is at the base circle # note that the distance of half the tangent length is just as far ahead from b as that is behind the involute starting point at the base circle # return (0.5 * pi / n) + j # The 1/4 angle per tooth - the angle that the the intermeshing point is ahead of the start of the involute curve return (0.5 * pi / n) + tan(pa) - pa # The 1/4 angle per tooth - the angle that the intermeshing point is ahead of the start of the involute curve def start_angle_calc_ref_zero(pA0, nA, rA): # Centre_Pressure_Angle when nA = rA, number_of_teeth, radius # perfect intermeshing when pinion nX=nA and paX=pA0 #dA = reference_circle_radius(rA, pA0) # reference circle A with default pressure angle #dB = reference_circle_radius(nA, pA0) # reference circle B with default pressure angle #p1 = pressure_angle(nA, nA, dA+dB) # pressure angle for reference circles A + B #p1 = acos( (2*nA) / ((nA+rA) / cos(pA0))) p1 = acos(cos(pA0)*2*nA/(nA+rA)) #p2 = pressure_angle(nA, nA, 2*dB) # pressure angle for 2 x reference circle B #p2 = acos( (2*nA) / (2*(nA / cos(pA0)))) #p2 = pA0 aB1 = start_angle_calc(p1, nA) # turn angle required to reach radius nA for two identical gears when d = A + B #aB2 = start_angle_calc(p2, nA) # turn angle required to reach radius nA for two identical gears when d = 2 * B aB2 = start_angle_calc(pA0, nA) # turn angle required to reach radius nA for two identical gears when d = 2 * B #f = 2 - (aB2/aB1) return 2*aB1 - aB2 ''' The idea here is create a 3D spur gear with the standard pressure angle at its vertical centre, and with a height equivalent to the reference circle increasing 3 teeth from top to bottom. ''' def start_angle_calc_3D(n): # number_of_teeth return start_angle_calc_ref_zero(Default_Centre_Pressure_Angle, 1.5 + n, n) ''' For a 2D multi-ratio gear this calculates the distance between the axes as well as the pressure angles, from the teeth numbers of both gears. If the pressure angle of one of the gear halves of the multi-ratio gear needs to be the same as that of the pinion gear then this formula can be used. Then if the number of teeth in the gear section of the multi-ratio gear with the least teeth is the same as the number of teeth of the pinion, the pressure angle of the gear section of the multi-ratio gear with the most teeth can be used for the pinion and the start angle of the gear section of the multi-ratio gear with the least teeth can be calculated with: start_angle_calc_ref_zero(pB, number_of_teeth, number_of_teeth + 2). - Imagine a gear gA with base circle bA inside a bigger gear gB with base circle bB, both with the same centre point. And a gear gX with base cricle bX intermeshing with both gear gA and gB. rA = Radius circle bA // use the number of teeth of gA rB = Radius circle bB = rA + some constant // use the number of teeth of gB rX = Radius circle bX // use the number of teeth of gX Centre bA = Centre bB d = Distance between the axes bA (and therefor also bB) and bX tA = The length of the tangent between bA an bX and crossing the horizontal line between the centres x = The length of part the part of tA that starts where tA touches bA, and ends where it cuts trough circle bB y = tA - x = The other part of tA ? Find the d where x/y = rB/rA tA = sqrt(d^2 - (rA + rX)^2) x = sqrt(rB^2-rA^2) x/y = rB/rA <=> sqrt(rB^2-rA^2) / (tA - sqrt(rB^2-rA^2)) = rB/rA <=> sqrt(rB^2-rA^2) / (sqrt(d^2 - (rA + rX)^2) - sqrt(rB^2-rA^2)) = rB/rA <=> rA*sqrt(rB^2-rA^2) = rB*(sqrt(d^2 - (rA + rX)^2) - sqrt(rB^2-rA^2)) <=> rA*sqrt(rB^2-rA^2) = rB*sqrt(d^2 - (rA + rX)^2) - rB*sqrt(rB^2-rA^2) <=> (rA+rB)*sqrt(rB^2-rA^2) = rB*sqrt(d^2 - (rA + rX)^2) <=> (rA+rB)*sqrt(rB^2-rA^2)/rB = sqrt(d^2 - (rA + rX)^2) <=> square both sides => (rA+rB)^2*(rB^2-rA^2)/rB^2 = d^2 - (rA + rX)^2 <=> ((rA+rB)^2*(rB^2-rA^2)/rB^2) + (rA + rX)^2 = d^2 <=> sqrt(((rA+rB)^2*(rB^2-rA^2)/rB^2) + (rA + rX)^2) = d ''' def cvt_calc(rA, rX): rB = rA + 2 dd = ((pow(rA+rB,2)*(pow(rB,2)-pow(rA,2)))/pow(rB,2)) + pow(rA+rX,2) d = sqrt(dd) tA = sqrt(dd - pow(rA + rX, 2)) #tB = sqrt(dd - pow(rB + rX, 2)) pA = acos((rA + rX)/d) # = pressure angle gA with gX pB = acos((rB + rX)/d) # = pressure angle gB with gX x = sqrt(pow(rB, 2) - pow(rA, 2)) return d, pA, pB#, tA, tB, x # Here we set some global variables that we needed these functions for gear_id_A, switch_A, number_of_teeth_A, height_A, x_A, y_A = Pos_Pinion(Default_Pos_Pinion_1, Default_start_with_number_of_teeth, Default_number_of_gears) # ------------------------------------------------------------------------------------------------------------------- # This is the basic mathematical shape underlying all involute gears (2D and 3D) # The basic mathematical shape underlying all involute curves is a triangle with two sides (one horizontal, the other # vertical) of equal lengths at a right angle to each other. This triangle sits against the edge of a cylinder with # its the vertical arm, while its horizontal arm sits against, and crosses perpendicular, the line coming from the # cylinders centre. The cylinder has radius 1 and the height and length of the triangle start at zero, # and then increase equal to the circumference distance that the triangle is moved around the cylinder. def add_3d_involute_math(self, context): clockwise = self.clockwise # If 'True' it turns clockwise, else if 'False' it turns anti-clockwise angle_resolution = self.angle_resolution # This sets the resolution. Lower resolutions are generated faster TriangleCount = int(2*pi/angle_resolution) x_Factor = 1 y_Factor = 1 z_Factor = 1 # Note that the intermeshing angle is 45 degrees. if clockwise: y_Factor = -y_Factor edges = [] verts = [(x_Factor,0,0)] # Add the starting point of the 3D involute for a in range (1, TriangleCount + 1): # The zero point has already been added Angle_and_Unwound_Length_and_Height = 2 * pi * a / TriangleCount # With the radius of the cylinder = 1, # the angle in radians is equal to the circumference distance travelled, as well as the length and # height of the triangle. # The coordinates of the triangle point at the bottom of the cylinder x_Cylinder = x_Factor * cos(Angle_and_Unwound_Length_and_Height) y_Cylinder = y_Factor * sin(Angle_and_Unwound_Length_and_Height) z_Cylinder = 0 vert = (x_Cylinder,y_Cylinder,z_Cylinder) verts.append(vert) # The coordinates of the triangle point at the top of the cylinder x_Top = x_Cylinder y_Top = y_Cylinder z_Top = z_Factor * Angle_and_Unwound_Length_and_Height vert = (x_Top,y_Top,z_Top) verts.append(vert) # The coordinates of the triangle point at the bottom and away from the cylinder l = sqrt(1 + pow(Angle_and_Unwound_Length_and_Height, 2)) h = acos(1/l) x_Involute = x_Factor * l * cos(Angle_and_Unwound_Length_and_Height - h) y_Involute = y_Factor * l * sin(Angle_and_Unwound_Length_and_Height - h) z_Involute = 0 vert = (x_Involute,y_Involute,z_Involute) verts.append(vert) faces = [[0, 2, 3],[0, 1, 2]] # starting faces of 3D involute all_Cylinder = [0] for a in range (0, TriangleCount -1): a_Cylinder = (a * 3) + 1 a_Top = (a * 3) + 2 a_Involute = (a * 3) + 3 b_Cylinder = ((a + 1) * 3) + 1 b_Top = ((a + 1) * 3) + 2 b_Involute = ((a + 1) * 3) + 3 faces.append([a_Cylinder, b_Cylinder, b_Top, a_Top]) faces.append([a_Involute, a_Top, b_Top, b_Involute]) all_Cylinder.append(a_Cylinder) faces.append([b_Cylinder, b_Involute, b_Top]) all_Cylinder.append(b_Cylinder) for a in range (0, TriangleCount): all_Cylinder.append(((TriangleCount - 1 - a) + 1) * 3) faces.append(all_Cylinder) mesh = bpy.data.meshes.new(name="3D Involute Math") mesh.from_pydata(verts, edges, faces) #mesh.validate(verbose=True) # Rem it for final version # useful for development when the mesh may be invalid. object_data_add(context, mesh, operator=self) # The rest is for presentations Involute = bpy.context.object bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0,0,10), rotation=(0,0,pi)) # 4 - 6 bpy.context.object.data.type = 'ORTHO' bpy.context.object.data.ortho_scale = 13 # Rotating bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(12.4, 12.4, 11.2), rotation=(pi/3, 0, -1.25 * pi)) # R10 - R20 Number_Of_Frames = 200 # prepare a scene ctx = bpy.context scn = ctx.scene ops = bpy.ops scn.frame_start = 0 scn.frame_end = Number_Of_Frames - 2 # starts at 0 and the last one needs to be cut as it is the same as the first objectToSelect = Involute objectToSelect.select_set(True) scn.frame_current = 0; Involute.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Involute.rotation_euler = (0, 0, 2*pi) scn.frame_current = Number_Of_Frames - 1; Involute.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) bpy.context.area.type = 'GRAPH_EDITOR' #Change scree n to graph editor to do the next operation bpy.ops.graph.interpolation_type(type='LINEAR') #Set keyframe type to linear to avoid acceleration of the hands animation bpy.context.area.type = 'TEXT_EDITOR' #Change back to text editor # ------------------------------------------------------------------------------------------------------------------- def add_3d_spur_gear(self, context): ''' We scale everything to the unit of length per tooth. We can then scale this unit of length in the vertical so that an increase of 1 tooth, results in an increase of 1 in the gear’s height. So, for example, a 3D involute gear where, from top to bottom, the intermeshing distance goes from n teeth to n + 1 teeth, has a height of 1. All this of course before we scale it up to the dimensions needed for our application. Doing it this way makes it all a lot easier. ''' # [blender] Initialising the variables used in this function. number_of_teeth = self.number_of_teeth # This the number of teeth in this gear. This number must be an integer. number_of_extra_teeth = self.number_of_extra_teeth # If you increased the distance between two perfectly 2D # intermeshing gears, this is the number of extra teeth you would have to add, to this gear, to perfectly intermesh once again. start_at_extra_teeth = self.start_at_extra_teeth # If 0 than the gear starts at the starting angle and the height is # number_of_extra_teeth, else the gear part from the 0 point to the start_at_extra_teeth point is omitted. tip_cut_at_number_of_extra_teeth = self.tip_cut_at_number_of_extra_teeth # Following the same logic as with number_of_extra #_teeth, this is the distance from the base circle at whitch the tips of the teeth are cut in order to prevent # them from cutting into the other gear. angle_start = self.angle_start # the angle travelled, or in this case also the circumference covered. This is the point on the # base circle where the involute curve starts. centre_pressure_angle = self.centre_pressure_angle # Only needed for cutting the tips of the teeth at the right length. angle_resolution = self.angle_resolution # This sets the resolution of the gear as generated in blender. Lower # values result in finer images, but also longer processing times. Note that blender cannot handle very low values very well. extra_root_depth = self.extra_root_depth # With this you can make the roots deeper, this is to prevent de gears from # cutting into each other. half_gear = self.half_gear # Set to 'True' if you only want half a gear. top_of_cvt = self.top_of_cvt # Set to 'True' if it is at the top of the main gear Tip_Cut_Angle = atan(0.75) if self.tip_cut_at_number_of_extra_teeth > 0: tip_cut_at_number_of_extra_teeth = self.tip_cut_at_number_of_extra_teeth Extra_Radius_Root_Circle = 1 # optimise for the prototype elif self.is_pinion: tip_cut_at_number_of_extra_teeth = 1.25 Extra_Radius_Root_Circle = 1.04 elif number_of_teeth ==8: tip_cut_at_number_of_extra_teeth = 1.1 Extra_Radius_Root_Circle = 1.09 elif number_of_teeth ==10: # 1 tip_cut_at_number_of_extra_teeth = 1.14 Extra_Radius_Root_Circle = 1.14 elif number_of_teeth ==12: tip_cut_at_number_of_extra_teeth = 1.03 Extra_Radius_Root_Circle = 1.08 elif number_of_teeth ==14: tip_cut_at_number_of_extra_teeth = 0.97 Extra_Radius_Root_Circle = 1.03 elif number_of_teeth ==16: tip_cut_at_number_of_extra_teeth = 0.92 Extra_Radius_Root_Circle = 1 elif number_of_teeth ==18: tip_cut_at_number_of_extra_teeth = 0.87 Extra_Radius_Root_Circle = 1 elif number_of_teeth ==20: tip_cut_at_number_of_extra_teeth = 0.82 Extra_Radius_Root_Circle = 1 elif number_of_teeth ==22: tip_cut_at_number_of_extra_teeth = 0.81 Extra_Radius_Root_Circle = 1 elif number_of_teeth ==24: tip_cut_at_number_of_extra_teeth = 0.79 Extra_Radius_Root_Circle = 1 ''' if self.extra_radius_root_circle != -1: # Results in a 2D spur gear Extra_Radius_Root_Circle = self.extra_radius_root_circle elif top_of_cvt == True: if number_of_teeth <8: Extra_Radius_Root_Circle = 1.112 elif number_of_teeth ==8: Extra_Radius_Root_Circle = 1.035 elif number_of_teeth ==10: Extra_Radius_Root_Circle = 1.005 else: Extra_Radius_Root_Circle = 1 #print("top_of_cvt == True number_of_teeth", number_of_teeth, "Extra_Radius_Root_Circle", Extra_Radius_Root_Circle) else: if number_of_teeth <10: Extra_Radius_Root_Circle = 1.15 elif number_of_teeth ==10: Extra_Radius_Root_Circle = 1.065 elif number_of_teeth ==12: Extra_Radius_Root_Circle = 1.01 else: Extra_Radius_Root_Circle = 1 #print("top_of_cvt == Fase number_of_teeth", number_of_teeth, "Extra_Radius_Root_Circle", Extra_Radius_Root_Circle) ''' # [blender] Starting this function. Angle_Rotation_Per_Tooth = 2 * pi / number_of_teeth # 360 degrees dived by the number of teeth gives you the number # of degrees per tooth. Half_Angle_Rotation_Per_Tooth = 0.5 * Angle_Rotation_Per_Tooth # Angle_Rotation_Per_Tooth divided by 2 this gives # you the number of degrees per tooth side. Base_Circle_Radious = number_of_teeth Tip_Cut_Radious = (number_of_teeth + tip_cut_at_number_of_extra_teeth) / cos(centre_pressure_angle) # This is the radius # from the centre from which the tips of the teeth are cut, starting from the top of the gear. # Note that we base this on the reference circle via the centre_pressure_angle. if number_of_extra_teeth == 0: # Results in a 2D spur gear height_gear = 1 Horizontal_Distance_Between_Bottom_And_Top = 0 Horizontal_Distance_To_Start = 0 else: # Results in a 3D spur gear height_gear = number_of_extra_teeth Horizontal_Distance_Between_Bottom_And_Top = height_gear / (number_of_teeth * 2) # As seen from above, # the involute curves of the top of the gear starting at the base circle, and the one at the bottom of the gear, only # differ in the point at which they start at the base circle. If the distance travelled from this point is the same for # the top and bottom involute, then the distance between the two resulting points in the horizontal plane is always # the same. This value is the Horizontal_Distance_Between_Bottom_And_Top. Horizontal_Distance_To_Start = start_at_extra_teeth / (number_of_teeth * 2) ''' Note: The root of the gear shown here is just a shape that works, it is NOT integral to the invention. Any hole that prevents intercutting will do. ''' Angle_Root_Circle = Half_Angle_Rotation_Per_Tooth - angle_start # The half holes between, and at the root of, the # teeth, are known as the root circles of the gear. This value is the number of degrees that each root circle # takes from the base circle. Note that their centres are not on the base circle, only their intersecting points are. Distance_To_Root_Centre = Base_Circle_Radious / cos(Angle_Root_Circle) # The half (actually slightly less than a half) # holes between, and at the root of, the teeth, are known as the root circles of the gear. This value is the number # of degrees that each root circle takes from the 360 degrees. At the beginning of the involute curve (at the very # bottom of the tooth), it is pointing directly at the centre of the gear. The root circle connects at this point # and at the same angle (so there are no sharp corners between the two curves). This results in centre of the root # circle being on the line, perpendicular to the line going trough the involute starting point starting from the # centre, as well as going trough the starting point itself. So the centres of the root circle are on the centre # line coming from the centre of the gear, and slightly outside the base circle. x_Centre_Root_Circle = Base_Circle_Radious # The x co-ordinate of the first root circle. y_Centre_Root_Circle = sqrt(pow(Distance_To_Root_Centre, 2) - pow(Base_Circle_Radious, 2)) # The y co-ordinate of the # first root circle. Radius_Root_Circle = Extra_Radius_Root_Circle * y_Centre_Root_Circle # The radius of the first root circle. Bottom_z_Centre_Root_Circle = height_gear - (y_Centre_Root_Circle * 2) # The z co-ordinate of the first root # circle at the bottom of the gear. q0 = height_gear - Bottom_z_Centre_Root_Circle # q0 is used nowhere else q_Radius_Root_Circle = ((q0 - start_at_extra_teeth) / q0) * Radius_Root_Circle Bottom_Radius_Root_Circle = Radius_Root_Circle - (Base_Circle_Radious * Horizontal_Distance_Between_Bottom_And_Top) # In 3D # the root circle becomes a cone that gets thinner as it goes down. This value is the radius at the bottom of the gear. if (Bottom_z_Centre_Root_Circle < 0) or (number_of_extra_teeth == 0) : Root_Cone_Tip_Is_Below_Zero_Ground = True else: Root_Cone_Tip_Is_Below_Zero_Ground = False Start_Angle_Root_Circle = Angle_Root_Circle # The angle at which we start to draw the root circle. End_Angle_Root_Circle = (0.5 * pi - Angle_Root_Circle) + Angle_Root_Circle # The angle at which we stop to draw the root circle. Count_Root_Circle = int(0.25 * (0.5 * pi - Angle_Root_Circle)/angle_resolution) # The number of steps we use to draw the root circle. b = 0 # We use this as a counter Root_Top_Counter = 0 Root_Bottom_Counter = 0 verts = [] # A list with all the x y z co-ordinates of each point in space edges = [] # Not used faces = [] # A list with all the planes in space de fined by the co-ordinates if Root_Cone_Tip_Is_Below_Zero_Ground == False: vert = (x_Centre_Root_Circle, -y_Centre_Root_Circle, Bottom_z_Centre_Root_Circle) verts.append(vert) # The root cone tip has index 0 Root_Top_Counter = Root_Top_Counter + 1 for a in range (0,Count_Root_Circle): # the last point of the root and involute are the same a_Angle_Root_Circle = Start_Angle_Root_Circle + ((0.5*pi - Angle_Root_Circle) * a / Count_Root_Circle) # Current angle we are drawing Top_x_Root_Circle = x_Centre_Root_Circle - pow(32*extra_root_depth, 0.03125) * (q_Radius_Root_Circle * cos(a_Angle_Root_Circle)) Top_y_Root_Circle = -y_Centre_Root_Circle + (q_Radius_Root_Circle * sin(a_Angle_Root_Circle)) Root_Top_Counter = Root_Top_Counter + 1 if number_of_extra_teeth == 0: # Results in a 2D spur gear Bottom_x_Root_Circle = Top_x_Root_Circle Bottom_y_Root_Circle = Top_y_Root_Circle Bottom_z_Root_Circle = 0 vert = (Bottom_x_Root_Circle, Bottom_y_Root_Circle, Bottom_z_Root_Circle) verts.append(vert) # Add x y z co-ordinates of the calculated bottom root circle point to the co-ordinates list Root_Bottom_Counter = Root_Bottom_Counter + 1 elif Root_Cone_Tip_Is_Below_Zero_Ground: # The bottom root circle cone is below the gear, so it is still a circle at the bottom. Bottom_x_Root_Circle = x_Centre_Root_Circle - pow(32*extra_root_depth, 0.03125) * (Bottom_Radius_Root_Circle * cos(a_Angle_Root_Circle)) Bottom_y_Root_Circle = -y_Centre_Root_Circle + (Bottom_Radius_Root_Circle * sin(a_Angle_Root_Circle)) Bottom_z_Root_Circle = 0 vert = (Bottom_x_Root_Circle, Bottom_y_Root_Circle, Bottom_z_Root_Circle) verts.append(vert) # Add x y z co-ordinates of the calculated bottom root circle point to the co-ordinates list Root_Bottom_Counter = Root_Bottom_Counter + 1 vert = (Top_x_Root_Circle, Top_y_Root_Circle, height_gear - start_at_extra_teeth) verts.append(vert) # Add x y z co-ordinates of the calculated top root circle point to the co-ordinates list b = b + 1 ''' Here we start to draw the involute curve. Please check out the function drawing the basic mathematical shape of the 3D involute curve (see the previous function add_3d_involute_math) to better understand this next bit. ''' Involute_Counter = 0 Angle_Reached = 0.0 # We draw the involute curve as a line starting at, and perpendicular to, the base circle. The point # from which we start to draw outwards is defined by the angle to the centre of the gear. The end point is at the distance # equal to the distance travelled over the base circle (see the definition of the involute curve). As we are however interested # in the angle between the resulting end point and the centre, and not the angle we started with to the starting point, we need # to calculate the Angle_Reached so we know when we have reached beyond the end point we need. while (Angle_Reached < angle_start) or ((b - 2 * int(b * 0.5)) == 1) : Angle_and_Unwound_Length_and_Height = ((b - Count_Root_Circle) * angle_resolution) # The coordinates of the triangle point at the bottom and away from the cylinder l_Top = sqrt(1 + pow(Angle_and_Unwound_Length_and_Height + Horizontal_Distance_To_Start, 2)) h_Top = acos(1/l_Top) x_Top_Involute = Base_Circle_Radious * l_Top * cos(Angle_and_Unwound_Length_and_Height - h_Top) y_Top_Involute = Base_Circle_Radious * l_Top * sin(Angle_and_Unwound_Length_and_Height - h_Top) l_Bottom = sqrt(1 + pow(Angle_and_Unwound_Length_and_Height + Horizontal_Distance_Between_Bottom_And_Top, 2)) h_Bottom = acos(1/l_Bottom) x_Bottom_Involute = Base_Circle_Radious * l_Bottom * cos(Angle_and_Unwound_Length_and_Height - h_Bottom) y_Bottom_Involute = Base_Circle_Radious * l_Bottom * sin(Angle_and_Unwound_Length_and_Height - h_Bottom) vert = (x_Bottom_Involute, y_Bottom_Involute, 0) verts.append(vert) # Add x y z co-ordinates of the calculated bottom involute point to the co-ordinates list vert = (x_Top_Involute, y_Top_Involute, height_gear - start_at_extra_teeth) verts.append(vert) # Add x y z co-ordinates of the calculated top involute point to the co-ordinates list # Calculate the angle that has been reached p = sqrt((x_Bottom_Involute * x_Bottom_Involute) + (y_Bottom_Involute * y_Bottom_Involute)) if y_Bottom_Involute >= 0 : Angle_Reached = acos(x_Bottom_Involute / p) - angle_resolution else: Angle_Reached = -acos(x_Bottom_Involute / p) - angle_resolution # Add 1 to the counter b = b + 1 Involute_Counter = Involute_Counter + 1 if Root_Cone_Tip_Is_Below_Zero_Ground: for a in range (0,b-1): faces.append([a*2, (a*2)+1, ((a+1)*2)+1, (a+1)*2]) # add the top and bottom centre points vert = (0,0,0) # Add the bottom centre point of the gear (blender needs this) verts.append(vert) vert = (0,0, height_gear - start_at_extra_teeth) # Add the top centre point of the gear (blender needs this) verts.append(vert) ''' # blender works better with this missing #faces.append([(b-1)*2, ((b-1)*2)+1, (b*2)+1, b*2]) faces.append([b*2, (b*2)+1, ((b-1)*2)+1]) faces.append([b*2, ((b-1)*2)+1, (b-1)*2]) faces.append([b*2, (b*2)+1, 1, 0]) ''' # [blender] Add the bottom face of the shape all_Bottom = [] for a in range (0,b+1): all_Bottom.append(a*2) faces.append(all_Bottom) # [blender] Add the top face of the shape all_Top = [] for a in range (0,b+1): all_Top.append((a*2) + 1) faces.append(all_Top) else: # if Root_Cone_Tip_Is_Below_Zero_Ground: # not used in invention for a in range (0,Root_Top_Counter-2): faces.append([a+1, 0, a+2]) faces.append([Root_Top_Counter-1, Root_Top_Counter+1, 0]) # The last triangle of the root cone. This also the one that # connects to the involute faces.append([ # first involute face Root_Top_Counter, 0, # Root_Cone_Tip Root_Top_Counter + 1, Root_Top_Counter + 3, Root_Top_Counter + 2]) for a in range (1,Involute_Counter-1): faces.append([ Root_Top_Counter+a*2, Root_Top_Counter+(a*2)+1, Root_Top_Counter + ((a+1)*2)+1, Root_Top_Counter + (a+1)*2]) vert = (0,0,0) # = Root_Top_Counter + (Involute_Counter*2) verts.append(vert) # Add the bottom centre point of the gear (blender needs this) vert = (0,0, height_gear - start_at_extra_teeth) # = Root_Top_Counter + (Involute_Counter*2) + 1 verts.append(vert) # Add the top centre point of the gear (blender needs this) faces.append([Root_Top_Counter + (Involute_Counter*2), 0, Root_Top_Counter]) # Root_Top_Counter is the bottom point # of tyhe first involute, this a triangle from the centre over the bottom ''' Might be of use in a new blender version faces.append([ Root_Top_Counter + (Involute_Counter*2), Root_Top_Counter + (Involute_Counter*2) + 1, 1]) # 1 is the top point of tyhe last involute, (it is the other way round to what you migt expect, # Root_Top_Counter - 1 is the top point of the last involute faces.append([ Root_Top_Counter + (Involute_Counter*2), 1, # 1 is the top point of tyhe last involute, (it is the other way round to what you migt expect, # Root_Top_Counter - 1 is the top point of tyhe last involute 0]) ''' faces.append([ Root_Top_Counter + (Involute_Counter*2), Root_Top_Counter + (Involute_Counter*2) + 1, 1, # 1 is the top point of tyhe last involute, (it is the other way round to what you migt expect, # Root_Top_Counter - 1 is the top point of tyhe last involute 0]) faces.append([ Root_Top_Counter + (Involute_Counter*2) + 1, # (0,0,height) Root_Top_Counter + (Involute_Counter*2), # (0,0,0) Root_Top_Counter + ((Involute_Counter-1)*2)+1]) # top last involute faces.append([ Root_Top_Counter + ((Involute_Counter-1)*2)+1, # (0,0,height) Root_Top_Counter + (Involute_Counter*2), # (0,0,0) Root_Top_Counter + ((Involute_Counter-1)*2)]) # Bottom last involute # [blender] Add the bottom of the shape all_Bottom = [Root_Top_Counter + (Involute_Counter*2)] # (0,0,0) for a in range (0, Involute_Counter): all_Bottom.append(Root_Top_Counter + a*2) faces.append(all_Bottom) # [blender] Add the top of the shape all_Top = [Root_Top_Counter + (Involute_Counter*2)+1] # (0,0,height) for a in range (1,Root_Top_Counter): all_Top.append(a) for a in range (0, Involute_Counter): all_Top.append(Root_Top_Counter + a*2 + 1) faces.append(all_Top) #print("verts", verts) #print("faces", faces) # [blender] create the shape so blender can use it mesh = bpy.data.meshes.new(name="3D Involute") mesh.from_pydata(verts, edges, faces) #mesh.validate(verbose=True) # [blender] Rem it for final version # useful for development when the mesh may be invalid. object_data_add(context, mesh, operator=self) me = bpy.context.object.data # [blender] Get the active mesh bm = bmesh.new(use_operators=True) # [blender] create an empty BMesh bm.from_mesh(mesh) # [blender] fill it in from the Mesh # At this point we have a involute curve rising from the x axes, and root circle going down from the x axes. # We now rotate everything downwards so that we have the bottom half of tooth clinging to the x axes. bmesh.ops.rotate( bm, verts=bm.verts, cent=(0,0,0), matrix=mathutils.Matrix.Rotation(-angle_start, 3, 'Z') ) # Now we cut the bottom side of the tooth so the all the teeth we add later do not cut into each other. bmesh.ops.bisect_plane( bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(-0.00000, 0.00000, 0), plane_no=(sin(Half_Angle_Rotation_Per_Tooth+ 0.00000), cos(Half_Angle_Rotation_Per_Tooth+ 0.00000), 0), # the 0.0000001 is for a blender bug clear_inner=True, clear_outer=False, ) # Now we use the x axe as a mirror to create the other (top) half of the tooth. bmesh.ops.symmetrize( bm, input=bm.verts[:]+bm.edges[:]+bm.faces[:], direction='-Y', dist=0.0 ) q = number_of_teeth - 1 w = (2 * pi) - Angle_Rotation_Per_Tooth bmesh.ops.spin( bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], angle=w, steps=q, axis=(0.0, 0.0, 1.0), cent=(0.0, 0.0, 0.0), use_duplicate =True, use_merge =True, ) # Now we cut the tips of the all the teeth (blender doesn’t like it if we do it before). for a in range (0,q+1): rot_Angle = a * Angle_Rotation_Per_Tooth if number_of_extra_teeth == 0: # Results in a 2D spur gear vec = mathutils.Vector((1, 0, 0)) else: # Results in a 3D spur gear vec = mathutils.Vector((cos(Tip_Cut_Angle), 0, sin(Tip_Cut_Angle))) eul = mathutils.Euler((0.0, 0.0, rot_Angle), 'XYZ') vec.rotate(eul) ret = bmesh.ops.bisect_plane( # make the cut bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(Tip_Cut_Radious * cos(rot_Angle), Tip_Cut_Radious * sin(rot_Angle), height_gear), plane_no=vec, clear_inner=False, clear_outer=True ) cut = [e for e in ret["geom_cut"] if isinstance(e, bmesh.types.BMEdge)] bmesh.ops.contextual_create( # fill the hole left by the cut bm, geom=bm.verts[:]+cut+bm.faces[:], ) if half_gear: bmesh.ops.rotate( bm, verts=bm.verts, cent=(0,0,0), matrix=mathutils.Matrix.Rotation(Half_Angle_Rotation_Per_Tooth, 3, 'Z') ) # [blender] Finalising and exiting the function. bm_verts = bm.verts[:] bmesh.ops.remove_doubles(bm, verts=bm_verts, dist=0.01) bm_faces = bm.faces[:] bmesh.ops.recalc_face_normals(bm, faces=bm_faces) bm.to_mesh(me) me.update() bm.free() Gear = bpy.context.object if half_gear: # cut the gear in half CubeSize = 4 * (number_of_teeth + number_of_extra_teeth + tip_cut_at_number_of_extra_teeth) bpy.ops.mesh.primitive_cube_add(location=(0, 0.0001-0.5 * CubeSize, 0.2), size= CubeSize) Cube = bpy.context.object applyBoolean('DIFFERENCE', Gear, Cube) # ------------------------------------------------------------------------------------------------------------------- def add_3d_root_cut(self, context): ''' Note: The root of the gear shown here is just a shape that works, it is NOT integral to the invention. Any hole that prevents intercutting will do. ''' # [blender] Initialising the variables used in this function. number_of_teeth = self.number_of_teeth number_of_extra_teeth = self.number_of_extra_teeth angle_start = self.angle_start angle_resolution = self.angle_resolution extra_root_depth = self.extra_root_depth # optimise for the prototype Tip_Cut_Angle = atan(0.75) Extra_Pow = 2048 if number_of_teeth ==8: Extra_Radius_Root_Circle = 1 elif number_of_teeth ==10: # 1 Extra_Radius_Root_Circle = 0.94 Extra_Pow = 131072 elif number_of_teeth ==12: # 3 Extra_Radius_Root_Circle = 0.96 Extra_Pow = 65536 elif number_of_teeth ==14: # 5 Extra_Radius_Root_Circle = 0.97 Extra_Pow = 32768 elif number_of_teeth ==16: # 7 Extra_Radius_Root_Circle = 0.99 Extra_Pow = 2048 elif number_of_teeth ==18: # 9 Extra_Radius_Root_Circle = 1.03 Extra_Pow = 512 elif number_of_teeth ==20: # 11 Extra_Radius_Root_Circle = 1.08 Extra_Pow = 64 elif number_of_teeth ==22: # 13 Extra_Radius_Root_Circle = 1.16 Extra_Pow = 2 else : # 15 Extra_Radius_Root_Circle = 1.26 Extra_Pow = 0.5 if number_of_extra_teeth == 0: # Results in a 2D spur gear height_gear = 1 else: # Results in a 3D spur gear height_gear = number_of_extra_teeth #print("number_of_teeth", number_of_teeth, "Extra_Radius_Root_Circle", Extra_Radius_Root_Circle) Base_Circle_Radious = number_of_teeth Angle_Rotation_Per_Tooth = 2 * pi / number_of_teeth Half_Angle_Rotation_Per_Tooth = 0.5 * Angle_Rotation_Per_Tooth Angle_Root_Circle = Half_Angle_Rotation_Per_Tooth - angle_start Distance_To_Root_Centre = Base_Circle_Radious / cos(Angle_Root_Circle) x_Centre_Root_Circle = Base_Circle_Radious # The x co-ordinate of the first root circle. y_Centre_Root_Circle = sqrt(pow(Distance_To_Root_Centre, 2) - pow(Base_Circle_Radious, 2)) # The y co-ordinate of the # first root circle. Radius_Root_Circle = Extra_Radius_Root_Circle * y_Centre_Root_Circle # The radius of the first root circle. Triangle_Slope = 2 Bottom_z_Centre_Root_Circle = height_gear - (y_Centre_Root_Circle * 2) if number_of_extra_teeth == 0: # Results in a 2D spur gear Horizontal_Distance_Between_Bottom_And_Top = 0 else: # Results in a 3D spur gear Horizontal_Distance_Between_Bottom_And_Top = height_gear / (Base_Circle_Radious * Triangle_Slope) Bottom_Radius_Root_Circle = Radius_Root_Circle - (Base_Circle_Radious * Horizontal_Distance_Between_Bottom_And_Top) #Start_Angle_Root_Circle = Angle_Root_Circle # The angle at which we start to draw the root circle. Start_Angle_Root_Circle = 0 # The angle at which we start to draw the root circle. End_Angle_Root_Circle = 2 * pi # The angle at which we stop to draw the root circle. #End_Angle_Root_Circle = (0.5 * pi - Angle_Root_Circle) + Angle_Root_Circle # The angle at which we stop to draw the root circle. #Count_Root_Circle = int(0.5 * pi / angle_resolution) # The number of steps we use to draw the root circle. Count_Root_Circle = int(1 * pi / angle_resolution) # The number of steps we use to draw the root circle. b = 0 # We use this as a counter verts = [] # A list with all the x y z co-ordinates of each point in space edges = [] # Not used faces = [] # A list with all the planes in space de fined by the co-ordinates for a in range (0,Count_Root_Circle): # the last point of the root and involute are the same a_Angle_Root_Circle = Start_Angle_Root_Circle + ((2*pi) * a / Count_Root_Circle) # Current angle we are drawing Top_x_Root_Circle = x_Centre_Root_Circle - pow(Extra_Pow*extra_root_depth, 0.03125) * (Radius_Root_Circle * cos(a_Angle_Root_Circle)) Top_y_Root_Circle = -y_Centre_Root_Circle + (Radius_Root_Circle * sin(a_Angle_Root_Circle)) if number_of_extra_teeth == 0: # Results in a 2D spur gear Bottom_x_Root_Circle = Top_x_Root_Circle Bottom_y_Root_Circle = Top_y_Root_Circle Bottom_z_Root_Circle = 0 elif Bottom_z_Centre_Root_Circle < 0: # The bottom root circle cone is below the gear, so it is still a circle at the bottom. Bottom_x_Root_Circle = x_Centre_Root_Circle - (Bottom_Radius_Root_Circle * cos(a_Angle_Root_Circle)) Bottom_y_Root_Circle = -y_Centre_Root_Circle + (Bottom_Radius_Root_Circle * sin(a_Angle_Root_Circle)) Bottom_z_Root_Circle = 0 else: # The root circle cone has ended in a point before it reached the bottom. Bottom_x_Root_Circle = x_Centre_Root_Circle Bottom_y_Root_Circle = -y_Centre_Root_Circle Bottom_z_Root_Circle = Bottom_z_Centre_Root_Circle vert = (Bottom_x_Root_Circle, Bottom_y_Root_Circle, Bottom_z_Root_Circle) verts.append(vert) # Add x y z co-ordinates of the calculated bottom root circle point to the co-ordinates list vert = (Top_x_Root_Circle, Top_y_Root_Circle, height_gear) verts.append(vert) # Add x y z co-ordinates of the calculated top root circle point to the co-ordinates list b = b + 1 #print("verts", verts) for a in range (0,b-1): faces.append([a*2, (a*2)+1, ((a+1)*2)+1, (a+1)*2]) faces.append([((b-1)*2)+1, (b-1)*2, 0, 1]) #print("faces", faces) #print("b", b) # [blender] Add the bottom of the shape all_Bottom = [] for a in range (0,b): all_Bottom.append(a*2) faces.append(all_Bottom) # [blender] Add the top of the shape all_Top = [] for a in range (0,b): all_Top.append((a*2) + 1) faces.append(all_Top) # [blender] create the shape so blender can use it mesh = bpy.data.meshes.new(name="3D Involute") mesh.from_pydata(verts, edges, faces) #mesh.validate(verbose=True) # [blender] Rem it for final version # useful for development when the mesh may be invalid. object_data_add(context, mesh, operator=self) me = bpy.context.object.data # [blender] Get the active mesh bm = bmesh.new(use_operators=True) # [blender] create an empty BMesh bm.from_mesh(mesh) # [blender] fill it in from the Mesh bmesh.ops.rotate( bm, verts=bm.verts, cent=(0,0,0), matrix=mathutils.Matrix.Rotation(-angle_start, 3, 'Z') ) ''' bmesh.ops.spin( bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], angle= pi, steps=1, axis=(0, 0, 1.0), cent=(0.0, 0.0, 0.0), use_duplicate =True, use_merge =True, ) ''' ret = bmesh.ops.duplicate( bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:]) geom_dupe = ret["geom"] verts_dupe = [ele for ele in geom_dupe if isinstance(ele, bmesh.types.BMVert)] del ret # Modify the BMesh, can do anything here... for v in verts_dupe: v.co.x *= -1.0 bmesh.ops.rotate( bm, verts=verts_dupe, cent=(0.0, 0.0, 0.0), matrix=mathutils.Matrix.Rotation(-Angle_Rotation_Per_Tooth, 3, 'Z')) # [blender] Finalising and exiting the function. bm_verts = bm.verts[:] bmesh.ops.remove_doubles(bm, verts=bm_verts, dist=0.01) bm_faces = bm.faces[:] bmesh.ops.recalc_face_normals(bm, faces=bm_faces) bm.to_mesh(me) me.update() bm.free() # ------------------------------------------------------------------------------------------------------------------- def add_3d_cvt_part(self, context): ''' The main gear in the CVT consists of a cascade of separate 3D involute spur gears all stacked on top of each other. Each gear in the cascade having 2 more teeth than the latter. Here we create these separate pieces. Each piece can be seen as a single 3D involute spur gear of height 3, that is to say that the intermeshing distance of the gear at the bottom is as if the gear had 3 more teeth. Each gear piece can be seen to have 3 parts. A top part which is half a gear and split strait trough the middle of a root, a middle part that was not cut, and a bottom part that was cut like the top part and that also has 2 extra cuts to prevent inter-cutting at the switch over point to the next gear in the cascade. At the centre height of each 3D involute gear it has the default pressure angle, this is also true for the pinions. So during normal operation, so when it is not switching gear, the centre heights of the gears will be operating at the default pressure angle. And importantly this means that we can use the 2D involute gear formula to calculate the intermeshing distance between the main gear and its two pinions. Note though that this distance is only valid when not switching between gears. When switching gears the gear part of the main gear will not be at the default pressure angle. ''' new_mat4 = bpy.data.materials.new("Pinion") new_mat4.diffuse_color = (0.5, 1, 0.5, 1) new_mat4.metallic = False new_mat4.roughness = 0.3 # [blender] Initialising the variables used in this function. Gear_Id = self.Gear_Id number_of_teeth = self.number_of_teeth # This the number of teeth in this gear. This number must be an integer. angle_resolution = self.angle_resolution # This sets the resolution of the gear as generated in blender. Lower # values result in finer images, but also longer processing times. Note that blender cannot handle very low values very well. add_top = self.add_top # The top gear does not have a previous part in the cascade, so the top part would lead nowhere # and can therefor be omitted add_middle = self.add_middle add_bottom = self.add_bottom # The bottom gear does not have a next part in the cascade, so the bottom part would lead # nowhere and can therefor be omitted. Half_Angle_Rotation_Per_Tooth = pi / number_of_teeth # 180 degrees dived by the number of teeth angle_start_0 = start_angle_calc_3D(number_of_teeth) angle_start_2 = start_angle_calc_3D(number_of_teeth + 2) # This is for the root cut at the switch point if ((Only_Show_Pinion_1 == True) and (((gear_id_A == Gear_Id - 1) and (switch_A ==1)) or (gear_id_A == Gear_Id))) or (Only_Show_Pinion_1 == False): bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, Half_Angle_Rotation_Per_Tooth), number_of_teeth = number_of_teeth, number_of_extra_teeth = 3, start_at_extra_teeth=0, angle_start = angle_start_0, angle_resolution = angle_resolution, half_gear = False, top_of_cvt = True, ) CVT_Gear_Part = context.object CVT_Gear_Part.name = "CVT part " + str(number_of_teeth) + " teeth" if Add_Base_Circle: ''' bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(0, 0, 1.5), rotation=(0, 0, 0), depth = 3, radius = number_of_teeth, # Base_Circle_Radious ) Base_Circle_Cylinder = context.object applyBoolean('DIFFERENCE', CVT_Gear_Part, Base_Circle_Cylinder) ''' bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(0, 0, -1.5), rotation=(0, 0, 0), depth = 1 + (Base_Circle_Extra_Height/ self.scale_z), radius = 0.5 * Base_Circle_Width + number_of_teeth, # Base_Circle_Radious ) Base_Circle_Cylinder = context.object Base_Circle_Cylinder.name = 'Base_Circle_Cylinder X' bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(0, 0, -1.5), rotation=(0, 0, 0), depth = 1 + (Base_Circle_Extra_Height/ self.scale_z), radius = -0.5 * Base_Circle_Width + number_of_teeth, # Base_Circle_Radious ) Base_Circle_Cylinder_Cut = context.object applyBoolean('DIFFERENCE', Base_Circle_Cylinder, Base_Circle_Cylinder_Cut) #applyBoolean('UNION', CVT_Gear_Part, Base_Circle_Cylinder) Base_Circle_Cylinder.location = self.location Base_Circle_Cylinder.scale = (self.scale_xy, self.scale_xy, self.scale_z) Base_Circle_Cylinder.location.z = self.location.z + 1.5 * self.scale_z bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 CubeSize = 4 * (number_of_teeth + 3 + Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth) # Remove the top half/part of gear - the half is not required for the top 3D involute spur gear of the main CVT gear as it would lead nowhere if add_top and (((Only_Show_Pinion_1== True) and (gear_id_A + switch_A == Gear_Id) and (switch_A ==1)) or (Only_Show_Pinion_1 == False)): bpy.ops.mesh.primitive_cube_add(location=(0, -0.5 * CubeSize, 2.5), size= CubeSize) else: bpy.ops.mesh.primitive_cube_add(location=(0, 0, 2.5), size= CubeSize) Cube = bpy.context.object Cube.scale.z = 0.000000001 + 1 / CubeSize applyBoolean('DIFFERENCE', CVT_Gear_Part, Cube) # Remove the middle part of gear if (not add_middle) or (not ((((Only_Show_Pinion_1 == True) and (gear_id_A == Gear_Id) and (switch_A ==0)) or (Only_Show_Pinion_1 == False)))): bpy.ops.mesh.primitive_cube_add(location=(0, 0, 1.5), size= CubeSize) Cube = bpy.context.object Cube.scale.z = 0.000000001 + 1 / CubeSize applyBoolean('DIFFERENCE', CVT_Gear_Part, Cube) # Remove the bottom half/part of gear - the half is not required for the bottom 3D involute spur gear of the main CVT gear as it would lead nowhere if add_bottom and (((Only_Show_Pinion_1 == True) and (gear_id_A + switch_A == Gear_Id+1) and (switch_A ==1)) or (Only_Show_Pinion_1 == False)): bpy.ops.mesh.primitive_cube_add(location=(0, 0.5 * CubeSize, 0.5), size= CubeSize) else: bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0.5), size= CubeSize) Cube = bpy.context.object Cube.scale.z = 0.000000001 + 1 / CubeSize applyBoolean('DIFFERENCE', CVT_Gear_Part, Cube) ''' bpy.ops.mesh.primitive_cube_add(location=(0, 0, -0.49999), size= CubeSize) Cube = bpy.context.object Cube.scale.z = 0.000000001 + 1 / CubeSize applyBoolean('DIFFERENCE', CVT_Gear_Part, Cube) ''' # We need to make the root cut at the switchover point between two different 3D involute spur gears bigger. Half_Angle_Rotation_Per_Tooth_plus_2 = pi / (number_of_teeth + 2) bpy.ops.mesh.add_3d_root_cut( align='WORLD', location=(0, 0, 0), rotation=(0, 0, Half_Angle_Rotation_Per_Tooth_plus_2), number_of_teeth = number_of_teeth + 2, number_of_extra_teeth = 3, angle_start = angle_start_2, angle_resolution = angle_resolution, ) Root = bpy.context.object Root.location = (0, 0, -2.00) applyBoolean('DIFFERENCE', CVT_Gear_Part, Root) CVT_Gear_Part.location = self.location CVT_Gear_Part.scale = (self.scale_xy, self.scale_xy, self.scale_z) ''' # [blender] Initialising the variables used in this function. Gear_Id = self.Gear_Id number_of_teeth = self.number_of_teeth # This the number of teeth in this gear. This number must be an integer. angle_resolution = self.angle_resolution # This sets the resolution of the gear as generated in blender. Lower # values result in finer images, but also longer processing times. Note that blender cannot handle very low values very well. add_top = self.add_top # The top gear does not have a previous part in the cascade, so the top part would lead nowhere # and can therefor be omitted add_bottom = self.add_bottom # The bottom gear does not have a next part in the cascade, so the bottom part would lead # nowhere and can therefor be omitted. Half_Angle_Rotation_Per_Tooth = pi / number_of_teeth # 180 degrees dived by the number of teeth angle_start_0 = start_angle_calc_3D(number_of_teeth) angle_start_2 = start_angle_calc_3D(number_of_teeth + 2) # This is for the root cut at the switch point # Create the top part of gear - not required for the top 3D involute spur gear of the main CVT gear as it would lead nowhere if add_top and (((Only_Show_Pinion_1== True) and (gear_id_A + switch_A == Gear_Id) and (switch_A ==1)) or (Only_Show_Pinion_1 == False)): bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 2), rotation=(0, 0, pi), number_of_teeth = number_of_teeth, number_of_extra_teeth = 1, start_at_extra_teeth=0, angle_start = angle_start_0, tip_cut_at_number_of_extra_teeth = Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth, angle_resolution = angle_resolution, half_gear = True, top_of_cvt = not add_top, ) Gear_Top = bpy.context.object Gear_Top.name ="CVT " + str(number_of_teeth) + " top" Gear_Top.location.x = self.location.x Gear_Top.location.y = self.location.y Gear_Top.location.z = self.location.z + self.scale_z*2 Gear_Top.scale = (self.scale_xy, self.scale_xy, self.scale_z) # Create the middle part of gear if (((Only_Show_Pinion_1 == True) and (gear_id_A == Gear_Id) and (switch_A ==0)) or (Only_Show_Pinion_1 == False)): bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 1), rotation=(0, 0, Half_Angle_Rotation_Per_Tooth), number_of_teeth = number_of_teeth, number_of_extra_teeth = 2, start_at_extra_teeth = 1, angle_start = angle_start_0, tip_cut_at_number_of_extra_teeth = Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth, angle_resolution = angle_resolution, half_gear = False, top_of_cvt = not add_top, ) Gear_Middle = bpy.context.object Gear_Middle.name ="CVT " + str(number_of_teeth) + " middle" Gear_Middle.location.x = self.location.x Gear_Middle.location.y = self.location.y Gear_Middle.location.z = self.location.z + self.scale_z Gear_Middle.scale = (self.scale_xy, self.scale_xy, self.scale_z) # Create the bottom part of gear - not required for the bottom 3D involute spur gear of the main CVT gear as it would lead nowhere if add_bottom and (((Only_Show_Pinion_1 == True) and (gear_id_A + switch_A == Gear_Id+1) and (switch_A ==1)) or (Only_Show_Pinion_1 == False)): bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth, number_of_extra_teeth = 3, start_at_extra_teeth = 2, angle_start =angle_start_0, tip_cut_at_number_of_extra_teeth = Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth, angle_resolution = angle_resolution, half_gear = True, top_of_cvt = not add_top, ) Gear_Bottom = bpy.context.object # We need to make the root cut at the switchover point between two different 3D involute spur gears bigger. Half_Angle_Rotation_Per_Tooth_plus_2 = pi / (number_of_teeth + 2) bpy.ops.mesh.add_3d_root_cut( align='WORLD', location=(0, 0, 0), rotation=(0, 0, Half_Angle_Rotation_Per_Tooth_plus_2), number_of_teeth = number_of_teeth + 2, number_of_extra_teeth = 3, angle_start = angle_start_2, angle_resolution = angle_resolution, ) Root = bpy.context.object Root.location = (0, 0, 0.001 - 2) applyBoolean('DIFFERENCE', Gear_Bottom, Root) Gear_Bottom.name ="CVT " + str(number_of_teeth) + " bottom" Gear_Bottom.location = self.location Gear_Bottom.scale = (self.scale_xy, self.scale_xy, self.scale_z) bpy.context.object.rotation_euler[2] = pi if Only_Show_Pinion_1 == False: # join the 3 parts into 1, and rename if add_top: objectToSelect = Gear_Top objectToSelect.select_set(True) objectToSelect = Gear_Middle objectToSelect.select_set(True) if add_bottom: objectToSelect = Gear_Bottom objectToSelect.select_set(True) bpy.ops.object.join() CVT_Gear_Part = context.object CVT_Gear_Part.name = "CVT part " + str(number_of_teeth) + " teeth" ''' # ------------------------------------------------------------------------------------------------------------------- def add_3d_cvt(self, context): angle_resolution = self.angle_resolution scale_xy = self.scale_xy scale_z = self.scale_z show_lines = self.show_lines if Only_Show_Pinion_1: show_lines = False show_pinion_1 = self.show_pinion_1 show_pinion_2 = self.show_pinion_2 Pos_Pinion_1 = self.Pos_Pinion_1 Pos_Pinion_2 = self.Pos_Pinion_2 start_with_number_of_teeth = self.start_with_number_of_teeth number_of_gears = self.number_of_gears Do_metallic = 1 new_mat = bpy.data.materials.new("Main gear even") new_mat.diffuse_color = (0.6, 0.8, 1, 1) new_mat.metallic = Do_metallic new_mat.roughness = 0.3 new_mat2 = bpy.data.materials.new("Main gear odd") new_mat2.diffuse_color = (1, 0.8, 0.6, 1) new_mat2.metallic = Do_metallic new_mat2.roughness = 0.3 new_mat3 = bpy.data.materials.new("Pinion") new_mat3.diffuse_color = (1, 0.5, 1, 1) new_mat3.metallic = Do_metallic new_mat3.roughness = 0.3 new_mat4 = bpy.data.materials.new("Pinion") new_mat4.diffuse_color = (0.5, 1, 0.5, 1) new_mat4.metallic = False new_mat4.roughness = 0.3 new_mat5 = bpy.data.materials.new("Shift line") new_mat5.diffuse_color = (0.5, 0.8, 0.5, 1) new_mat5.metallic = Do_metallic new_mat5.roughness = 0.3 Height_Main_Gear = (2*number_of_gears) - 1 for a in range (0, number_of_gears): if a==0: add_top = False else: add_top = True if a==number_of_gears-1: add_bottom = False else: add_bottom = True bpy.ops.mesh.add_3d_cvt_part( align='WORLD', location=(0, 0, scale_z*(number_of_gears*2 - a*2 - 3)), #location=(0, 0, 1.6180339887498948482045868343656 * scale_z*(number_of_gears*2 - a*2 - 3)), rotation=(0, 0, 0), Gear_Id = a, number_of_teeth = start_with_number_of_teeth + a*2, angle_resolution = angle_resolution, scale_xy=scale_xy, scale_z=scale_z, add_top = add_top, add_bottom = add_bottom, ) if (a/2) == round(a/2): if Only_Show_Pinion_1 == False: bpy.ops.object.material_slot_add() context.object.active_material = new_mat else: if Only_Show_Pinion_1 == False: bpy.ops.object.material_slot_add() context.object.active_material = new_mat2 if show_lines: # Line through the centre of the main gear d = (scale_z * Height_Main_Gear) + 2 * Arrow_Extra_Length_At_ends r = Arrow_Thickness else: d = 0 r = 0 if Only_Show_Pinion_1: h = scale_z * y_A else: h = 0.5 * scale_z * Height_Main_Gear bpy.ops.mesh.primitive_cylinder_add( align='WORLD', location=(0, 0, h), rotation=(0, 0, 0), depth = d, radius = r, ) bpy.ops.object.material_slot_add() context.object.active_material = new_mat # Join all the parts into one and give it a name bpy.ops.object.select_all(action='SELECT') if Add_Base_Circle: bpy.data.objects['Base_Circle_Cylinder X'].select_set(False) bpy.data.objects['Base_Circle_Cylinder X'].location.z = 0.5 * self.scale_z bpy.ops.object.join() CVT_Main_Gear = context.object CVT_Main_Gear.name = 'Main gear' if show_lines: # Line over which the pinion 1 moves in order to change gear gear_id_1, switch_1, number_of_teeth_1, height_1, x1, y1 = Pos_Pinion(0, start_with_number_of_teeth, number_of_gears) x1 = x1 * scale_xy y1 = y1 gear_id_2, switch_2, number_of_teeth_2, height_2, x2, y2 = Pos_Pinion((2*Default_number_of_gears)-2, start_with_number_of_teeth, number_of_gears) x2 = x2 * scale_xy y2 = y2 Arrow_Angle = -(x2-x1)/ (scale_z * (y1-y2)) Arrow_Length_Line = (scale_z * Height_Main_Gear / cos(Arrow_Angle)) + 2 * Arrow_Extra_Length_At_ends Arrow_x = reference_circle_radius(start_with_number_of_teeth + number_of_gears - 1 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash # in blender its the centre height of the line you draw that counts if show_pinion_1: bpy.ops.mesh.primitive_cylinder_add( align='WORLD', location=(scale_xy * Arrow_x, 0, scale_z * 0.5 * Height_Main_Gear), rotation=(0, Arrow_Angle, 0), depth = Arrow_Length_Line, radius = Arrow_Thickness, ) Gear_Change_Line_Pinion_1 = context.object Gear_Change_Line_Pinion_1.name = 'Shift line 1' bpy.ops.object.material_slot_add() context.object.active_material = new_mat5 if show_pinion_2: bpy.ops.mesh.primitive_cylinder_add( align='WORLD', location=(scale_xy * -Arrow_x, 0, scale_z * 0.5 * Height_Main_Gear), rotation=(0, -Arrow_Angle, 0), depth = Arrow_Length_Line, radius = Arrow_Thickness, ) Gear_Change_Line_Pinion_2 = context.object Gear_Change_Line_Pinion_2.name = 'Shift line 2' bpy.ops.object.material_slot_add() context.object.active_material = new_mat5 gear_id_1, switch_1, number_of_teeth_1, height_1, Pinion_1_x, Pinion_1_y = Pos_Pinion(Pos_Pinion_1, start_with_number_of_teeth, number_of_gears) if show_pinion_1: # Draw pinion 1 bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(scale_xy * Pinion_1_x, 0, scale_z * Pinion_1_y), rotation=(0, pi, 0), number_of_teeth = Pinion_Number_Of_Teeth, number_of_extra_teeth = (0.5 * Pinion_Height) + 1.5, # = height start_at_extra_teeth = 1.5 - (0.5 * Pinion_Height), angle_start = start_angle_calc_3D(Pinion_Number_Of_Teeth), centre_pressure_angle = Default_Centre_Pressure_Angle, angle_resolution = angle_resolution, half_gear = False, is_pinion = True, ) Pinion_1 = bpy.context.object Pinion_1.name ="Pinion 1" bpy.ops.object.material_slot_add() context.object.active_material = new_mat3 gear_id = int(Pos_Pinion_1 / 2) switch = Pos_Pinion_1 - (2*gear_id) # ? 0 ==> running !? 1 ==> switch gear if Add_Base_Circle: ''' bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(Pinion_1_x, 0, scale_z * Pinion_1_y - 0.5 * Pinion_Height), rotation=(0, 0, 0), depth = Pinion_Height, radius = Pinion_Number_Of_Teeth, # Base_Circle_Radious ) Base_Circle_Cylinder_P1 = context.object applyBoolean('DIFFERENCE', Pinion_1, Base_Circle_Cylinder_P1) ''' bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(scale_xy * Pinion_1_x, 0, 0.5 * scale_z), rotation=(0, 0, 0), depth = Pinion_Height + (Base_Circle_Extra_Height / scale_z), radius = 0.5 *Base_Circle_Width + Pinion_Number_Of_Teeth, # Base_Circle_Radious ) Base_Circle_Cylinder_P1 = context.object Base_Circle_Cylinder_P1.name = 'Base_Circle_Cylinder ' + str(Pinion_Number_Of_Teeth) + " P1" bpy.ops.mesh.primitive_cylinder_add( vertices = Base_Circle_vertices, align='WORLD', location=(scale_xy * Pinion_1_x, 0, 0.5 * scale_z), rotation=(0, 0, 0), depth = Pinion_Height + Base_Circle_Extra_Height, radius = -0.5 *Base_Circle_Width + Pinion_Number_Of_Teeth, # Base_Circle_Radious ) Base_Circle_Cylinder_Cut = context.object applyBoolean('DIFFERENCE', Base_Circle_Cylinder_P1, Base_Circle_Cylinder_Cut) bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 Base_Circle_Cylinder_P1.scale = (scale_xy, scale_xy, scale_z) #applyBoolean('UNION', Pinion_1, Base_Circle_Cylinder_P1) # tangent base if switch == 0: number_of_teeth = (start_with_number_of_teeth + gear_id*2) + switch print("number_of_teeth", number_of_teeth) x_ref = scale_xy * reference_circle_radius(number_of_teeth, Default_Centre_Pressure_Angle) l_ref = 2 * x_ref / sin(Default_Centre_Pressure_Angle) bpy.ops.mesh.primitive_cube_add( location=(x_ref, 0, 0.5 * scale_z), rotation=(0, 0, Default_Centre_Pressure_Angle), size= 1) Cube = bpy.context.object Cube.scale.x = Base_Circle_Width Cube.scale.y = l_ref Cube.scale.z = scale_z + Base_Circle_Extra_Height bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 # tangent base bpy.ops.mesh.primitive_cube_add( location=(x_ref, 0, 0.5 * scale_z), rotation=(0, 0, -Default_Centre_Pressure_Angle), size= 1) Cube2 = bpy.context.object Cube2.scale.x = Base_Circle_Width Cube2.scale.y = l_ref Cube2.scale.z = scale_z + Base_Circle_Extra_Height bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 ''' # left y axes bpy.ops.mesh.primitive_cube_add( location=(0, 0, 0.5*scale_z), size= 1) Cube3 = bpy.context.object Cube3.scale.x = Base_Circle_Width Cube3.scale.y = l_ref * cos(Default_Centre_Pressure_Angle) Cube3.scale.z = scale_z + Base_Circle_Extra_Height bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 # right y axes bpy.ops.mesh.primitive_cube_add( location=(Pinion_1_x, 0, 0.5*scale_z), size= 1) Cube4 = bpy.context.object Cube4.scale.x = Base_Circle_Width Cube4.scale.y = l_ref * cos(Default_Centre_Pressure_Angle) Cube4.scale.z = scale_z + Base_Circle_Extra_Height bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 # hor axes bpy.ops.mesh.primitive_cube_add( location=(0.5 * Pinion_1_x, 0, 0.5*scale_z), size= 1) Cube5 = bpy.context.object Cube5.scale.x = Pinion_1_x Cube5.scale.y = Base_Circle_Width Cube5.scale.z = scale_z + Base_Circle_Extra_Height bpy.ops.object.material_slot_add() context.object.active_material = new_mat4 ''' Pinion_1.scale = (scale_xy, scale_xy, scale_z) if show_lines: # Line to show the rotational axes of pinion 1 Depth_Line_Pinion_1 = Pinion_Height + 2.618 * Arrow_Extra_Length_At_ends bpy.ops.mesh.primitive_cylinder_add( align='WORLD', location=(scale_xy * Pinion_1_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_1_y)), rotation=(0, 0, 0), depth = Depth_Line_Pinion_1, radius = Arrow_Thickness, ) Line_Pinion_1 = bpy.context.object Line_Pinion_1.name ="Line_Pinion_1" bpy.ops.object.material_slot_add() context.object.active_material = new_mat3 ''' # join the 2 parts into 1, and rename objectToSelect = Pinion_1 objectToSelect.select_set(True) objectToSelect = Line_Pinion_1 objectToSelect.select_set(True) bpy.ops.object.join() Pinion_1 = context.object Pinion_1.name = "Pinion 1" ''' gear_id_2, switch_2, number_of_teeth_2, height_2, Pinion_2_x, Pinion_2_y = Pos_Pinion(Pos_Pinion_2, start_with_number_of_teeth, number_of_gears) if show_pinion_2: # Draw pinion 2 Pinion_2_x = -Pinion_2_x bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(scale_xy * Pinion_2_x, 0, scale_z * Pinion_2_y), rotation=(0, pi, 0), number_of_teeth = Pinion_Number_Of_Teeth, number_of_extra_teeth = (0.5 * Pinion_Height) + 1.5, # = height start_at_extra_teeth = 1.5 - (0.5 * Pinion_Height), angle_start = start_angle_calc_3D(Pinion_Number_Of_Teeth), centre_pressure_angle = Default_Centre_Pressure_Angle, angle_resolution = angle_resolution, half_gear = False, is_pinion = True, ) Pinion_2 = bpy.context.object Pinion_2.name ="Pinion 2" Pinion_2.scale = (scale_xy, scale_xy, scale_z) bpy.ops.object.material_slot_add() context.object.active_material = new_mat3 if show_lines: # Line to show the rotational axes of pinion 2 Depth_Line_Pinion_2 = Pinion_Height + 2.618 * Arrow_Extra_Length_At_ends bpy.ops.mesh.primitive_cylinder_add( align='WORLD', location=(scale_xy * Pinion_2_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_2_y)), rotation=(0, 0, 0), depth = Depth_Line_Pinion_2, radius = Arrow_Thickness, ) Line_Pinion_2 = bpy.context.object Line_Pinion_2.name ="Line_Pinion_2" bpy.ops.object.material_slot_add() context.object.active_material = new_mat3 # join the 2 parts into 1, and rename ''' objectToSelect = Pinion_2 objectToSelect.select_set(True) objectToSelect = Line_Pinion_2 objectToSelect.select_set(True) bpy.ops.object.join() Pinion_2 = context.object Pinion_2.name = "Pinion 2" ''' if Only_Show_Pinion_1: CVT_Main_Gear.location=(0, 0, scale_z * Pinion_Height) if show_pinion_1: Pinion_1.location.z = scale_z * Pinion_Height if Only_Show_Pinion_1_WIREFRAME: modifier_Main_Gear = CVT_Main_Gear.modifiers.new(name="WIREFRAME", type='WIREFRAME') modifier_Main_Gear.thickness = 0.06 modifier_Main_Gear.use_even_offset = False modifier_Pinion_1 = Pinion_1.modifiers.new(name="WIREFRAME", type='WIREFRAME') modifier_Pinion_1.thickness = 0.06 modifier_Pinion_1.use_even_offset = False ''' [] Speculair Lighting Film [] transparant Color management - Exposure 2 - Gamma 2 ''' #Number_Of_Frames = 144 if Only_Show_Pinion_1: if switch == 0: Number_Of_Frames = number_of_teeth_A * 144 else: Number_Of_Frames = number_of_teeth_A * 144 else: Number_Of_Frames = 576 #Number_Of_Frames = 1728 #Number_Of_Frames = 3456 # prepare a scene ctx = bpy.context scn = ctx.scene ops = bpy.ops objectToSelect = CVT_Main_Gear objectToSelect.select_set(True) if show_pinion_1: objectToSelect = Pinion_1 objectToSelect.select_set(True) if show_lines: objectToSelect = Line_Pinion_1 objectToSelect.select_set(True) if show_pinion_2: objectToSelect = Pinion_2 objectToSelect.select_set(True) if Show_Preset_Animation: if Show_Changing_Gear: scn.frame_start = Number_Of_Frames scn.frame_end = (4 * Number_Of_Frames) - 2 # starts at 0 and the last one needs to be cut as it is the same as the first else: scn.frame_start = 0 scn.frame_end = Number_Of_Frames - 2 # starts at 0 and the last one needs to be cut as it is the same as the first scn.frame_current = 0; # 0 CVT_Main_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) # 2 == 0 f = 2 print('f', f) Angle_Main_Gear = f*pi Angle_Pinion_1 = -f*pi * number_of_teeth_1 / Pinion_Number_Of_Teeth Angle_Pinion_2 = -f*pi * number_of_teeth_2 / Pinion_Number_Of_Teeth CVT_Main_Gear.rotation_euler = (0, 0, Angle_Main_Gear) Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) Pinion_2.rotation_euler = (0, -pi, Angle_Pinion_2) scn.frame_current = (Number_Of_Frames) - 1; if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) objectToSelect = Pinion_2 objectToSelect.select_set(False) objectToSelect = CVT_Main_Gear objectToSelect.select_set(False) # 2 + 1/(8*2) == 0 f8 = 2 + 1/(number_of_teeth_1*2) f10 = 0 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = (((f-f10) * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # Down 1/2 gear gear_id_1, switch_1, number_of_teeth_1B, height_1, Pinion_1_x, Pinion_1_y = Pos_Pinion(Pos_Pinion_1 + 1, start_with_number_of_teeth, number_of_gears) Pinion_1_x = Pinion_1_x * scale_xy Pinion_1.location=(Pinion_1_x, 0, scale_z * Pinion_1_y) if show_lines: Line_Pinion_1.location=(Pinion_1_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_1_y)) # 3 - 1/(8*2) == 0=>1 f8 = 3 - 1/(number_of_teeth_1*2) f10 = 0 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = (((f-f10) * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # 3 == 1 (8 => 10) f8 = 3 f10 = 0 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; Angle_Pinion_1 = ((f8 * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) # 3 + 1/(10*2) == 1 f8 = 3 f10 = 1/((number_of_teeth_1 + 2)*2) scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = ((f8 * number_of_teeth_1) + ((f - f8) * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # Down 1/2 gear gear_id_1, switch_1, number_of_teeth_1C, height_1, Pinion_1_x, Pinion_1_y = Pos_Pinion(Pos_Pinion_1 + 2, start_with_number_of_teeth, number_of_gears) Pinion_1_x = Pinion_1_x * scale_xy Pinion_1.location=(Pinion_1_x, 0, scale_z * Pinion_1_y) if show_lines: Line_Pinion_1.location=(Pinion_1_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_1_y)) # 4 - 1/(10*2) == 1=>2 f8 = 3 f10 = 1 - 1/((number_of_teeth_1 + 2)*2) scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = ((f8 * number_of_teeth_1) + ((f - f8) * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # 5 + 1/(10*2) == 2 f8 = 3 f10 = 2 + 1/((number_of_teeth_1 + 2)*2) scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = ((f8 * number_of_teeth_1) + ((f - f8) * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # Up 1/2 gear gear_id_1, switch_1, number_of_teeth_1B, height_1, Pinion_1_x, Pinion_1_y = Pos_Pinion(Pos_Pinion_1 + 1, start_with_number_of_teeth, number_of_gears) Pinion_1_x = Pinion_1_x * scale_xy Pinion_1.location=(Pinion_1_x, 0, scale_z * Pinion_1_y) if show_lines: Line_Pinion_1.location=(Pinion_1_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_1_y)) # 6 - 1/(10*2) == 2=>1 f8 = 3 f10 = 3 - 1/((number_of_teeth_1 + 2)*2) scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = ((f8 * number_of_teeth_1) + ((f - f8) * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # 6 == 1 (10 => 8) #f = 6 f8 = 3 f10 = 3 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; Angle_Pinion_1 = ((f8 * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) # 6 + 1/(8*2) f8 = 3 + 1/(number_of_teeth_1*2) f10 = 3 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = (((f - f10) * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # Up 1/2 gear gear_id_1, switch_1, number_of_teeth_1B, height_1, Pinion_1_x, Pinion_1_y = Pos_Pinion(Pos_Pinion_1, start_with_number_of_teeth, number_of_gears) Pinion_1_x = Pinion_1_x * scale_xy Pinion_1.location=(Pinion_1_x, 0, scale_z * Pinion_1_y) if show_lines: Line_Pinion_1.location=(Pinion_1_x, 0, scale_z * ((-0.5*Pinion_Height) + Pinion_1_y)) # 7- 1/(8*2) f8 = 4 - 1/(number_of_teeth_1*2) f10 = 3 scn.frame_current = (Number_Of_Frames * 0.5 * (f8 + f10)) - 1; f = (scn.frame_current + 1) / (Number_Of_Frames * 0.5) # scn.frame_current is an integer so we need to adjust the angle (blender bug) Angle_Pinion_1 = (((f - f10) * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) # 8 Angle_Main_Gear = 8*pi f8 = 5 f10 = 3 Angle_Pinion_1 = ((f8 * number_of_teeth_1) + (f10 * (number_of_teeth_1 + 2))) * -pi / Pinion_Number_Of_Teeth Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) Angle_Pinion_2 = -8*pi * number_of_teeth_2 / Pinion_Number_Of_Teeth CVT_Main_Gear.rotation_euler = (0, 0, Angle_Main_Gear) Pinion_2.rotation_euler = (0, -pi, Angle_Pinion_2) scn.frame_current = (Number_Of_Frames * 4) - 1; objectToSelect = Pinion_2 objectToSelect.select_set(True) objectToSelect = CVT_Main_Gear objectToSelect.select_set(True) CVT_Main_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_1: Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_lines: Line_Pinion_1.keyframe_insert(data_path="location", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) else: scn.frame_start = 0 scn.frame_end = Number_Of_Frames - 2 # starts at 0 and the last one needs to be cut as it is the same as the first scn.frame_current = 0; CVT_Main_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Angle_Main_Gear = pi if switch_1 == 1: Angle_Pinion_1 = -pi * (number_of_teeth_1 - 1) / Pinion_Number_Of_Teeth else: Angle_Pinion_1 = -pi * number_of_teeth_1 / Pinion_Number_Of_Teeth if switch_2 == 1: Angle_Pinion_2 = -pi * (number_of_teeth_2 + 1) / Pinion_Number_Of_Teeth else: Angle_Pinion_2 = -pi * number_of_teeth_2 / Pinion_Number_Of_Teeth CVT_Main_Gear.rotation_euler = (0, 0, Angle_Main_Gear) if show_pinion_1: Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_2: Pinion_2.rotation_euler = (0, -pi, Angle_Pinion_2) scn.frame_current = int((Number_Of_Frames * 0.5) - 1); CVT_Main_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Angle_Main_Gear = 2*pi Angle_Pinion_1 = -2*pi * number_of_teeth_1 / Pinion_Number_Of_Teeth Angle_Pinion_2 = -2*pi * number_of_teeth_2 / Pinion_Number_Of_Teeth CVT_Main_Gear.rotation_euler = (0, 0, Angle_Main_Gear) if show_pinion_1: Pinion_1.rotation_euler = (0, -pi, Angle_Pinion_1) if show_pinion_2: Pinion_2.rotation_euler = (0, -pi, Angle_Pinion_2) scn.frame_current = (Number_Of_Frames) - 1; CVT_Main_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_1: Pinion_1.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) if show_pinion_2: Pinion_2.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) bpy.context.area.type = 'GRAPH_EDITOR' #Change screen to graph editor to do the next operation bpy.ops.graph.interpolation_type(type='LINEAR') #Set keyframe type to linear to avoid acceleration of the hands animation bpy.context.area.type = 'TEXT_EDITOR' #Change back to text editor #bpy.ops.screen.animation_play() rfc = scale_xy * reference_circle_radius(number_of_teeth_A, Default_Centre_Pressure_Angle) #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(rfc, 0, 155), rotation=(0, 0, 0)) # R10 - R20 #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0, 190, 39.2), rotation=(0.5 * pi, 0, pi)) # R10 - R20 #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0, 166, 108), rotation=(1.1635528346628863846041583173124, 0, pi)) #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(12.869, -86.47, 160.8), rotation=(0.25 * pi, 0, 0)) # ortho 75 #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0, -174, 105), rotation=(1.1973, 0, 0)) # ortho 75 if Only_Show_Pinion_1: bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(rfc, 0, 42), rotation=(0, 0, 0)) bpy.context.object.data.type = 'ORTHO' bpy.context.object.data.ortho_scale = 23 #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0, 0, 100 + a * scale_z), rotation=(0, 0,0)) # R10 - R20 #bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(0, -174, 40.46), rotation=(0.5 * pi, 0, 0)) # ortho 75 #bpy.context.object.data.type = 'ORTHO' #bpy.context.object.data.ortho_scale = 22 #bpy.context.object.data.ortho_scale = 121.3 # ------------------------------------------------------------------------------------------------------------------- def add_2_ratio_2d_spur_gear(self, context): ''' This is the 2D part of the invention. It demonstrates how 2D spur gears can be created that continuously switch between two different gear ratios. There is also a formula for calculating the exact pressure angle required, as well as two formulas for calculating the starting point of the involute curve on its base circle. Note these later formulas create slightly smaller roots than standard practice (a 50-50 devide between rootv and tooth), resulting in zero backlash and perfect intermeshing. This part of the source code is bit more messy in order to encourage you to play with it a bit yourself. ''' angle_resolution = self.angle_resolution number_of_teeth = 10 number_of_teeth_X = number_of_teeth # note: (if: number_of_teeth <> number_of_teeth_X) then aA will need optimisation by hand aA_Correction = 0 # note: (if: number_of_teeth = number_of_teeth_X) then this is 0 ''' number_of_teeth_X = 12 # note: (if: number_of_teeth <> number_of_teeth_X) then aA will need optimisation by hand aA_Correction = -0.0016 # note: (if: number_of_teeth = number_of_teeth_X) then this is 0 ''' Number_Of_Frames = 400 Top_Half_Centre_mat = bpy.data.materials.new("Top_Half_Centre") Top_Half_Centre_mat.diffuse_color = (0, 0.39, 0, 1) Top_Half_Centre_mat.metallic = 0 Top_Half_Centre_mat.roughness = 0.3 Top_Half_Out_mat = bpy.data.materials.new("Top_Half_Out") Top_Half_Out_mat.diffuse_color = (0, 1, 0, 1) Top_Half_Out_mat.metallic = 0 Top_Half_Out_mat.roughness = 0.3 Bottom_Half_mat = bpy.data.materials.new("Bottom_Half") Bottom_Half_mat.diffuse_color = (0.15, 0.39, 1, 1) Bottom_Half_mat.metallic = 0 Bottom_Half_mat.roughness = 0.3 Pinion_mat = bpy.data.materials.new("Pinion_mat") Pinion_mat.diffuse_color = (1, 0.1, 0.1, 1) Pinion_mat.metallic = 0 Pinion_mat.roughness = 0.3 Backlash = 0.0#1 # required otherwise it looks unrealisticly tight in blender #Def_Scale = 0.01 Def_Scale = 3 Def_tip_cut = 1.25 Def_extra_root_depth = 48 Extra_Radius_Root_Circle = 1.05 d, pA, pB = cvt_calc(number_of_teeth, number_of_teeth_X) aA1 = start_angle_calc(pB, number_of_teeth) #aA = start_angle_calc(pA, number_of_teeth) // We don’t use this as it would require the pinion to also have pressure angle pA aA = start_angle_calc_ref_zero(pB, number_of_teeth, number_of_teeth + 2) # note there is an error if: number_of_teeth <> number_of_teeth_X. aA = aA + aA_Correction aB = start_angle_calc(pB, number_of_teeth + 2) aX = start_angle_calc(pB, number_of_teeth_X) b = d + Backlash # distance between axes bb = d - reference_circle_radius(number_of_teeth_X, pB) CircLine = number_of_teeth CubeSize = 4 * (number_of_teeth + 6) Cube_Y = 1.35986675 + 0.5 * CubeSize # create top half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth, number_of_extra_teeth = 0, start_at_extra_teeth = 0.0001, angle_start = aA, tip_cut_at_number_of_extra_teeth = 3.26, angle_resolution = angle_resolution, half_gear = True, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Top_Gear = bpy.context.object Top_Gear.scale.z = Def_Scale * 1 bpy.ops.object.material_slot_add() context.object.active_material = Top_Half_Out_mat bpy.ops.mesh.primitive_cube_add(location=(0.0, Cube_Y, 0.1), size= CubeSize) Cube = bpy.context.object applyBoolean('INTERSECT', Top_Gear, Cube) # create bottom half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth+2, number_of_extra_teeth = 0, #angle_start = 0.14, angle_start = aB, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = False, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Bottom_Gear = bpy.context.object Bottom_Gear.scale.z = Def_Scale * 1 bpy.context.object.rotation_euler[2] = pi / (number_of_teeth + 2) bpy.ops.object.material_slot_add() context.object.active_material = Top_Half_Out_mat bpy.ops.mesh.primitive_cube_add(location=(0.0, Cube_Y, 0.1), size= CubeSize) Cube = bpy.context.object applyBoolean('DIFFERENCE', Bottom_Gear, Cube) # join the 2 parts into 1, and rename objectToSelect = Top_Gear objectToSelect.select_set(True) objectToSelect = Bottom_Gear objectToSelect.select_set(True) bpy.ops.object.join() Left_Gear = context.object Left_Gear.name = "2_Ratio" # create default top half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, Def_Scale), rotation=(0, 0, 0), number_of_teeth = number_of_teeth, number_of_extra_teeth = 0, angle_start = aA1, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = True, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Top_Gear_Def = bpy.context.object Top_Gear_Def.name = "Top_Left" Top_Gear_Def.scale.z = Def_Scale bpy.ops.object.material_slot_add() context.object.active_material = Top_Half_Centre_mat # create bottom half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, Def_Scale), rotation=(0, 0, 0), number_of_teeth = number_of_teeth+2, number_of_extra_teeth = 0, #angle_start = 0.14, angle_start = aB, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = False, top_of_cvt = False, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Bottom_Gear = bpy.context.object Bottom_Gear.name = "Bottom_Left" Bottom_Gear.scale.z = Def_Scale bpy.context.object.rotation_euler[2] = pi / (number_of_teeth + 2) bpy.ops.object.material_slot_add() context.object.active_material = Bottom_Half_mat bpy.ops.mesh.primitive_cube_add(location=(0.0, 0.0001+0.5 * CubeSize, 0.1), size= CubeSize) Cube = bpy.context.object applyBoolean('DIFFERENCE', Bottom_Gear, Cube) # create pinion gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(b, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth_X, number_of_extra_teeth = 0, angle_start = aX, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = False, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Pinion = bpy.context.object Pinion.scale.z = Def_Scale bpy.ops.object.material_slot_add() context.object.active_material = Pinion_mat # prepare a scene ctx = bpy.context scn = ctx.scene ops = bpy.ops scn.frame_start = 0 scn.frame_end = Number_Of_Frames - 2 # starts at 0 and the last one needs to be cut as it is the same as the first scn.frame_current = 0; Left_Gear_Angle_Start = pi / (number_of_teeth+2) objectToSelect = Top_Gear_Def objectToSelect.select_set(True) objectToSelect = Bottom_Gear objectToSelect.select_set(True) objectToSelect = Left_Gear objectToSelect.select_set(True) Top_Gear_Def.rotation_euler = (0, 0, 0) Bottom_Gear.rotation_euler = (0, 0, Left_Gear_Angle_Start) Left_Gear.rotation_euler = (0, 0, Left_Gear_Angle_Start) Pinion.rotation_euler = (0, 0, 0) scn.frame_current = 0; Top_Gear_Def.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Bottom_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Left_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Pinion.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Top_Gear_Def.rotation_euler = (0, 0, pi + 0) Bottom_Gear.rotation_euler = (0, 0, pi + Left_Gear_Angle_Start) Left_Gear.rotation_euler = (0, 0, pi + Left_Gear_Angle_Start) Pinion.rotation_euler = (0, 0, -pi * (number_of_teeth+2) / number_of_teeth_X) scn.frame_current = (0.5* Number_Of_Frames) - 1; Top_Gear_Def.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Bottom_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Left_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Pinion.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Top_Gear_Def.rotation_euler = (0, 0, 2*pi + 0) Bottom_Gear.rotation_euler = (0, 0, 2*pi + Left_Gear_Angle_Start) Left_Gear.rotation_euler = (0, 0, 2*pi + Left_Gear_Angle_Start) Pinion.rotation_euler = (0, 0, - pi -pi * (number_of_teeth+2) / number_of_teeth_X) scn.frame_current = (Number_Of_Frames) - 1; Top_Gear_Def.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Bottom_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Left_Gear.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) Pinion.keyframe_insert(data_path="rotation_euler", frame=scn.frame_current) bpy.context.area.type = 'GRAPH_EDITOR' #Change screen to graph editor to do the next operation bpy.ops.graph.interpolation_type(type='LINEAR') #Set keyframe type to linear to avoid acceleration of the hands animation bpy.context.area.type = 'TEXT_EDITOR' #Change back to text editor ''' bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(15, 0, 300), rotation=(0, 0, 0)) # ortho 75 bpy.context.object.data.type = 'ORTHO' bpy.context.object.data.ortho_scale = 74 ''' bpy.ops.object.camera_add(enter_editmode=False, align='VIEW', location=(15, 0, 300), rotation=(0, 0, 0)) # ortho 75 bpy.context.object.data.type = 'ORTHO' bpy.context.object.data.ortho_scale = 72.1 # ------------------------------------------------------------------------------------------------------------------- def add_3_gear_demo(self, context): ''' Note: The bearings used are not all exactly the same shape. So optimize by hand. Print (in any case the gears) at half speed for good quality Theoretically this is calculated with zero backlash, good quality prints might need a little backlash if you are going for absolute perfection, otherwise the design will cope but a small slit might be visible between the base of the pinion and mainframe. These bearings have an upside and down side. Orientate all the bearing with the glass balls visible from the bottom. ''' Pinion_Height = 0.8 angle_resolution = self.angle_resolution #number_of_gears = 3 scale_z = 2 * Lego_Brick_Width_Depth # This needs to be small so it will fit in an envelope (maximum size allowed for an envelope is 20 mm) #scale_z = 12 # This needs to be small so it will fit in an envelope (maximum size allowed for an envelope is 20 mm) start_with_number_of_teeth = 10 # Fewer are possible, but then increase scale_z or the bearing will be too big scale_xy = scale_z/9 Pinion_Number_Of_Teeth = 12 InnerRimBearing = Bearing_9x20x6mm_Ridge # mm InnerRimHeight = 1 # mm Bearing_Outer = Bearing_9x20x6mm_Outer Bearing_Height = Bearing_9x20x6mm_Height Bearing_Inner = Bearing_9x20x6mm_Inner ''' # Printer tests - Use these to get the exact measurements of the bearings right bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, Bearing_Height)) Pin_Main_Frame = bpy.context.object bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(InnerRimBearing + 0.5*Bearing_Outer, InnerRimBearing + 0.5 * Bearing_Outer, Bearing_Height)) OuterFrame = bpy.context.object bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, Bearing_Height)) InPin = bpy.context.object applyBoolean('DIFFERENCE', OuterFrame, InPin) ''' # Main_Gear_Top bpy.ops.mesh.add_3d_cvt_part( align='WORLD', location=(0, 0, 1 * scale_z), rotation=(0, 0, 0), Gear_Id = 0, number_of_teeth = start_with_number_of_teeth, angle_resolution = angle_resolution, scale_xy=scale_xy, scale_z=scale_z, add_top = False, add_middle = True, add_bottom = True, ) Main_Gear_Top = bpy.context.object Main_Gear_Top.name = "Main_Gear_Top" bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, (3 * scale_z) + 0.5 - 0.5 * Bearing_Height), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 1 + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Top, Bearing_Main_Gear) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, (3 * scale_z) - 0.5 * Bearing_Height), scale=(-InnerRimBearing + 0.5*Bearing_Outer, -InnerRimBearing + 0.5 * Bearing_Outer, (2 * InnerRimHeight) + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Top, Bearing_Main_Gear) # Main_Gear_Bottom bpy.ops.mesh.add_3d_cvt_part( align='WORLD', location=(0, 0, -1 * scale_z), rotation=(0, 0, 0), Gear_Id = 0, number_of_teeth = start_with_number_of_teeth + 2, angle_resolution = angle_resolution, scale_xy=scale_xy, scale_z=scale_z, add_top = True, add_middle = True, add_bottom = False, ) Main_Gear_Bottom = bpy.context.object Main_Gear_Bottom.name = "Main_Gear_Bottom" bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, -0.5 + 0.5 * Bearing_Height), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 1 + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Bottom, Bearing_Main_Gear) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(-InnerRimBearing + 0.5*Bearing_Outer, -InnerRimBearing + 0.5*Bearing_Outer, (2 * InnerRimHeight) + Bearing_Height)) Bearing_Main_Gear = bpy.context.object # Main_Gear applyBoolean('DIFFERENCE', Main_Gear_Bottom, Bearing_Main_Gear) objectToSelect = Main_Gear_Top objectToSelect.select_set(True) objectToSelect = Main_Gear_Bottom objectToSelect.select_set(True) bpy.ops.object.join() Main_Gear = bpy.context.object Main_Gear.name = "Main_Gear" # Position pinions x0 = reference_circle_radius(start_with_number_of_teeth + 2 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash z0 = scale_z * 0.5 * (1-Pinion_Height) x1 = reference_circle_radius(start_with_number_of_teeth + 1 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash z1 = -1 * scale_z + scale_z * 0.5 * (1-Pinion_Height) x2 = reference_circle_radius(start_with_number_of_teeth + 0 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash z2 = -2 * scale_z + scale_z * 0.5 * (1-Pinion_Height) # Pinion x = x0 z = z0 bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(scale_xy * x, 0, scale_z - z), rotation=(0, pi, 0), number_of_teeth = Pinion_Number_Of_Teeth, number_of_extra_teeth = (0.5 * Pinion_Height) + 1.5, # = height start_at_extra_teeth = 1.5 - (0.5 * Pinion_Height), angle_start = start_angle_calc_3D(Pinion_Number_Of_Teeth), tip_cut_at_number_of_extra_teeth=Pinion_Tip_Cut_At_Number_Of_Extra_Teeth, centre_pressure_angle = Default_Centre_Pressure_Angle, angle_resolution = angle_resolution, half_gear = False, is_pinion = True, ) Pinion = bpy.context.object Pinion.name ="Pinion" Pinion.scale.z = scale_z Pinion.scale.x = scale_xy Pinion.scale.y = scale_xy bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, -3 + (scale_z * 0.5 ) ), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 6 + Bearing_Height)) Bearing_Pinion = bpy.context.object applyBoolean('DIFFERENCE', Pinion, Bearing_Pinion) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, -3 + (scale_z * 0.5 ) ), scale=(-InnerRimBearing + 0.5*Bearing_Outer,-InnerRimBearing + 0.5 * Bearing_Outer, 6 + (2 * InnerRimHeight) + Bearing_Height)) Bearing_Pinion = bpy.context.object applyBoolean('DIFFERENCE', Pinion, Bearing_Pinion) # Block Height_Top_Bar = 0.5 * scale_z Clearance_Between_Gear_And_Block = 1 #mm Top_Height = Height_Top_Bar + (2 * Clearance_Between_Gear_And_Block) + 3 * scale_z Virtual_Number_Of_Teeth = (Top_Height / scale_z) - 0.5 xBotom = reference_circle_radius(start_with_number_of_teeth + Virtual_Number_Of_Teeth + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) xTop = reference_circle_radius(start_with_number_of_teeth + 0 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) xDelta = (xBotom - xTop) aSlope = Top_Height / (scale_xy * xDelta) Angle = atan(aSlope) xBlock_Top = Bearing_Outer + 2 xBlock_Bottom = (scale_xy * xDelta) + 0.5 * xBlock_Top zBlock_Top = Top_Height - Clearance_Between_Gear_And_Block zBlock_Bottom = - Clearance_Between_Gear_And_Block #yBlock_Inner = scale_xy * 0.5 * reference_circle_radius(start_with_number_of_teeth + 8 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) yBlock_Inner = scale_z * 2 * (15/16) yBlock_Outer = yBlock_Inner + Lego_Brick_Height + Lego_Brick_Width_Depth bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Block = bpy.context.object Block.name = "Main_frame" Block.scale.x = 2 * xBlock_Bottom Block.scale.y = 2 * yBlock_Outer Block.scale.z = Top_Height Block.location.z = (0.5 * Top_Height) - Clearance_Between_Gear_And_Block bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Block_Inner = bpy.context.object Block_Inner.scale.x = 2 * xBlock_Bottom + 10 Block_Inner.scale.y = 2 * yBlock_Inner Block_Inner.scale.z = Top_Height - Height_Top_Bar Block_Inner.location.z = (0.5 * Block_Inner.scale.z) - Clearance_Between_Gear_And_Block applyBoolean('DIFFERENCE', Block, Block_Inner) # Pin Top main gear bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, Top_Height - Height_Top_Bar - Clearance_Between_Gear_And_Block - 0.5 * (Bearing_Height + Clearance_Between_Gear_And_Block)), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, Bearing_Height + Clearance_Between_Gear_And_Block)) Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Block, Pin_Main_Frame) # Ridge Pin Top main gear bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, Top_Height - Height_Top_Bar - Clearance_Between_Gear_And_Block - 0.5 * Clearance_Between_Gear_And_Block), scale=(InnerRimBearing + 0.5*Bearing_Inner, InnerRimBearing + 0.5 * Bearing_Inner, Clearance_Between_Gear_And_Block)) Ridge_Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Block, Ridge_Pin_Main_Frame) # Left and right slope going up for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Anglecut = bpy.context.object Anglecut.scale.x = 300 Anglecut.scale.y = 300 Anglecut.scale.z = 40 Anglecut.location.x = ar * (0.5 * Anglecut.scale.z + 0.5 * xBlock_Top) Anglecut.location.z = Top_Height - Clearance_Between_Gear_And_Block Anglecut.rotation_euler = (0, ar * Angle, 0) applyBoolean('DIFFERENCE', Block, Anglecut) # 4 x Angle cuts for b in range (0, 2): if b == 0: br = 1 else: br =-1 for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Anglecut = bpy.context.object Anglecut.scale.x = 300 Anglecut.scale.y = 300 Anglecut.scale.z = 40 Anglecut.location.x = ar * (0.5 * Anglecut.scale.z + 0.25 * scale_z) Anglecut.location.y = br * (0.5 * Anglecut.scale.y + yBlock_Outer - Lego_Brick_Width_Depth - Lego_Brick_Gap_Horizontal) Anglecut.location.z = Top_Height - Clearance_Between_Gear_And_Block Anglecut.rotation_euler = (0, ar * Angle, 0) applyBoolean('DIFFERENCE', Block, Anglecut) # pin holes for on slopes for b in range (0, 2): if b == 0: br = 1 else: br =-1 for a in range (0, 3): h = (scale_z * 0.5) + (a * scale_z) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), h), scale=(0.5 * Lego_Pin_Inner_Diameter, 0.5 * Lego_Pin_Inner_Diameter, 100)) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Block, Connecting_Pin) xp = 0.5 * xBlock_Top + ((Top_Height - h - 0.5 * Lego_Pin_Inner_Diameter + 0.5 * Clearance_Between_Gear_And_Block) / aSlope) # Center ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), h), scale=(0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, 2*(xp - 0.5 * Lego_Pin_Length + Lego_Pin_Outside_Ridge_Width))) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Block, Connecting_Pin) #other ridges for c in range (0, 2): if c == 0: cr = 1 else: cr =-1 bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(cr * xp, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), (scale_z * 0.5) + (a * scale_z)), scale=(0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, Lego_Pin_Middle_Ridge_Width)) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Block, Connecting_Pin) # Bottom connectors for b in range (0, 2): if b == 0: br = 1 else: br =-1 for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * (1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), (0.5 * Lego_Brick_Width_Depth) - Clearance_Between_Gear_And_Block), scale=( 0.5 * Lego_Pin_Inner_Diameter, 0.5 * Lego_Pin_Inner_Diameter, Lego_Brick_Width_Depth + 1)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Block, Connector_Pin) # Bottom ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * ( 1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), (-0.5 + 0.25 * Lego_Pin_Middle_Ridge_Width) - Clearance_Between_Gear_And_Block), scale=( 0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, 1 + 0.5 * Lego_Pin_Middle_Ridge_Width)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Block, Connector_Pin) # Top ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * ( 1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), (0.5 * Lego_Pin_Length - Lego_Pin_Outside_Ridge_Width + 0.5 * Lego_Pin_Outside_Ridge_Width) - Clearance_Between_Gear_And_Block + 0.5), scale=( 0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, Lego_Pin_Outside_Ridge_Width + 1)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Block, Connector_Pin) # Text 'www.New-CVT.com' bpy.ops.object.text_add( location=(1.75, -(yBlock_Inner + 0.85 * Lego_Brick_Height) - 0.14, Top_Height - Clearance_Between_Gear_And_Block), rotation=(0, 0, 0.5 * pi)) txt = bpy.data.objects['Text'] txt.data.body = 'NEW-CVT.COM' Text_NewCVT = bpy.context.object Text_NewCVT.scale.x = 14.36 Text_NewCVT.scale.y = 20 fnt = bpy.data.fonts.load('C:\Windows\Fonts\Arial.ttf') Text_NewCVT.data.font = fnt Text_NewCVT.data.extrude = 1 bpy.ops.object.convert(target='MESH') Text_NewCVT = bpy.context.object applyBoolean('DIFFERENCE', Block, Text_NewCVT) # Text 'patent pending' bpy.ops.object.text_add( location=(10, -30.5, Top_Height - Clearance_Between_Gear_And_Block), rotation=(0, 0, 0.5 * pi)) txt_pp = bpy.data.objects['Text'] txt_pp.data.body = 'PATENT PENDING' Text_PP = bpy.context.object Text_PP.scale.x = 9.175 Text_PP.scale.y = 11 fnt = bpy.data.fonts.load('C:\Windows\Fonts\Arial.ttf') Text_PP.data.font = fnt Text_PP.data.extrude = 1 bpy.ops.object.convert(target='MESH') Text_PP = bpy.context.object applyBoolean('DIFFERENCE', Block, Text_PP) # Main base plate bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Main_Base_Plate = bpy.context.object Main_Base_Plate.name = "Main_Base_Plate" Main_Base_Plate.scale.x = 2 * yBlock_Inner Main_Base_Plate.scale.y = 2 * yBlock_Outer Main_Base_Plate.scale.z = 0.5 * scale_z Main_Base_Plate.location.z = -(0.5 * Main_Base_Plate.scale.z) - Clearance_Between_Gear_And_Block # Pin Top main gear bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * (Bearing_Height - Clearance_Between_Gear_And_Block)), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, Bearing_Height + Clearance_Between_Gear_And_Block)) Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Main_Base_Plate, Pin_Main_Frame) # Ridge Pin Top main gear bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, - Clearance_Between_Gear_And_Block + 0.5 * Clearance_Between_Gear_And_Block), scale=(InnerRimBearing + 0.5*Bearing_Inner, InnerRimBearing + 0.5 * Bearing_Inner, Clearance_Between_Gear_And_Block)) Ridge_Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Main_Base_Plate, Ridge_Pin_Main_Frame) # Left and right slope going up for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Anglecut = bpy.context.object Anglecut.scale.x = 300 Anglecut.scale.y = 300 Anglecut.scale.z = 40 Anglecut.location.x = ar * (0.5 * Anglecut.scale.z + 0.5 * xBlock_Top) Anglecut.location.z = Top_Height - Clearance_Between_Gear_And_Block Anglecut.rotation_euler = (0, ar * Angle, 0) applyBoolean('DIFFERENCE', Main_Base_Plate, Anglecut) # 4 x Angle cuts for b in range (0, 2): if b == 0: br = 1 else: br =-1 for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Anglecut = bpy.context.object Anglecut.scale.x = 300 Anglecut.scale.y = 300 Anglecut.scale.z = 40 Anglecut.location.x = ar * (0.5 * Anglecut.scale.z + 0.25 * scale_z) Anglecut.location.y = br * (0.5 * Anglecut.scale.y + yBlock_Outer - Lego_Brick_Width_Depth - Lego_Brick_Gap_Horizontal) Anglecut.location.z = Top_Height - Clearance_Between_Gear_And_Block Anglecut.rotation_euler = (0, ar * Angle, 0) applyBoolean('DIFFERENCE', Main_Base_Plate, Anglecut) # bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Side = bpy.context.object Side.scale.x = 2 * yBlock_Inner Side.scale.y = 2 * yBlock_Inner Side.scale.z = 0.5 * scale_z Side.location.z = -(0.5 * Main_Base_Plate.scale.z) - Clearance_Between_Gear_And_Block applyBoolean('UNION', Main_Base_Plate, Side) # Bottom connectors for b in range (0, 2): if b == 0: br = 1 else: br =-1 for a in range (0, 2): if a == 0: ar = 1 else: ar =-1 bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * (1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), -1 * ((0.5 * Lego_Brick_Width_Depth) + Clearance_Between_Gear_And_Block)), scale=( 0.5 * Lego_Pin_Inner_Diameter, 0.5 * Lego_Pin_Inner_Diameter, Lego_Brick_Width_Depth + 1)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Main_Base_Plate, Connector_Pin) # Bottom ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * ( 1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), -1 * ((-0.5 + 0.25 * Lego_Pin_Middle_Ridge_Width) + Clearance_Between_Gear_And_Block)), scale=( 0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, 1 + 0.5 * Lego_Pin_Middle_Ridge_Width)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Main_Base_Plate, Connector_Pin) # Top ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=( br * ( 1 + 0.5 * Lego_Brick_Width_Depth), ar * (yBlock_Outer - 0.5 * Lego_Brick_Height), -1 * ((0.5 * Lego_Pin_Length - Lego_Pin_Outside_Ridge_Width + 0.5 * Lego_Pin_Outside_Ridge_Width) + Clearance_Between_Gear_And_Block + 0.5)), scale=( 0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, Lego_Pin_Outside_Ridge_Width + 1)) Connector_Pin = bpy.context.object applyBoolean('DIFFERENCE', Main_Base_Plate, Connector_Pin) # Pinion base plate z_Pin = Clearance_Between_Gear_And_Block + 0.5 * scale_z + 0.5 * Bearing_Height bpy.ops.mesh.primitive_cube_add(location=(scale_xy * x, 0, 0), size= 1) Pinion_Base_Plate = bpy.context.object Pinion_Base_Plate.name = "Pinion_Base_Plate" Pinion_Base_Plate.scale.x = 1.3333 * yBlock_Inner Pinion_Base_Plate.scale.y = 2 * yBlock_Outer Pinion_Base_Plate.scale.z = 0.5 * scale_z Pinion_Base_Plate.location.z = -(0.5 * Pinion_Base_Plate.scale.z) - Clearance_Between_Gear_And_Block # Pin Top Pinion bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, 0.5 * z_Pin - Clearance_Between_Gear_And_Block), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, z_Pin)) Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Pin_Main_Frame) # Ridge Pin Top Pinion bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, 0.5 * (z_Pin - Bearing_Height) - Clearance_Between_Gear_And_Block), scale=(InnerRimBearing + 0.5*Bearing_Inner, InnerRimBearing + 0.5 * Bearing_Inner, z_Pin - Bearing_Height)) Ridge_Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Ridge_Pin_Main_Frame) # Left and right slope going up bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) aa = bpy.context.object aa.scale.x = 200 aa.scale.y = 200 aa.scale.z = 11 aa.location.x = (0.5 * aa.scale.z + 0.5 * xBlock_Top) aa.location.z = Top_Height - Clearance_Between_Gear_And_Block aa.rotation_euler = (0, Angle, 0) applyBoolean('UNION', Pinion_Base_Plate, aa) # 4 x Angle cuts for b in range (0, 2): if b == 0: br = 1 else: br =-1 ar = 1 bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) aa = bpy.context.object aa.scale.x = 200 aa.scale.y = 200 aa.scale.z = 16 aa.location.x = ar * (0.5 * aa.scale.z + 0.25 * scale_z) aa.location.y = br * (0.5 * aa.scale.y + yBlock_Outer - Lego_Brick_Width_Depth + Lego_Brick_Gap_Horizontal) aa.location.z = Top_Height - Clearance_Between_Gear_And_Block aa.rotation_euler = (0, ar * Angle, 0) applyBoolean('UNION', Pinion_Base_Plate, aa) # bpy.ops.mesh.primitive_cube_add(location=(scale_xy * x, 0, 0), size= 1) pp = bpy.context.object pp.scale.x = 4* yBlock_Inner pp.scale.y = 2 * yBlock_Outer pp.scale.z = 1.5 * scale_z + Clearance_Between_Gear_And_Block pp.location.z = 0.5 * pp.scale.z - 0.5 *scale_z - Clearance_Between_Gear_And_Block applyBoolean('INTERSECT', Pinion_Base_Plate, pp) # bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) aa = bpy.context.object aa.scale.x = 2 * (yBlock_Inner + 8) aa.scale.y = 2 * (yBlock_Inner + 2 * Lego_Brick_Gap_Horizontal) aa.scale.z = 100 aa.location.z = 0 applyBoolean('DIFFERENCE', Pinion_Base_Plate, aa) # pin holes for on slopes for b in range (0, 2): if b == 0: br = 1 else: br =-1 h = (scale_z * 0.5) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), h), scale=(0.5 * Lego_Pin_Inner_Diameter, 0.5 * Lego_Pin_Inner_Diameter, 100)) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Pinion_Base_Plate, Connecting_Pin) xp = 0.5 * xBlock_Top + ((Top_Height - h - 0.5 * Lego_Pin_Inner_Diameter + 0.5 * Clearance_Between_Gear_And_Block) / aSlope) # Center ridge bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), h), scale=(0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, 2 *(scale_xy * x - xp) - Lego_Pin_Length + Lego_Pin_Middle_Ridge_Width)) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Pinion_Base_Plate, Connecting_Pin) #other ridges bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(xp, br * (yBlock_Inner + 0.5 * Lego_Brick_Height), (scale_z * 0.5)), scale=(0.5 * Lego_Pin_Outer_Diameter, 0.5 * Lego_Pin_Outer_Diameter, Lego_Pin_Middle_Ridge_Width)) Connecting_Pin = bpy.context.object Connecting_Pin.rotation_euler = (0, 0.5 * pi, 0) applyBoolean('DIFFERENCE', Pinion_Base_Plate, Connecting_Pin) # ------------------------------------------------------------------------------------------------------------------- def add_spinner(self, context): Pinion_Height = 1 Backlash = 0.32#0.14 # Depends on the quality of your printer. If this is to low the gears won’t spin freely. If so pull up the pinion until they # do. Then measure the height difference in mm, multiply by sin(9.4), and add this to the backlash. Or for the reverse use the multi-ratio gear. angle_resolution = self.angle_resolution scale_z = Lego_Brick_Width_Depth # This needs to be small so it will fit in an envelope (maximum size allowed for an envelope is 20 mm) start_with_number_of_teeth = 10 # Fewer are possible, but then increase scale_z or the bearing will be too big scale_xy = scale_z/9 Pinion_Number_Of_Teeth = 12 InnerRimBearing = Bearing_5x13x4mm_Ridge # mm InnerRimHeight = 0.8 # mm Bearing_Outer = Bearing_5x13x4mm_Outer Bearing_Height = Bearing_5x13x4mm_Height Bearing_Inner = Bearing_5x13x4mm_Inner ''' # Printer tests - Use these to get the exact measurements of the bearings right bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, Bearing_Height)) Pin_Main_Frame = bpy.context.object bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(InnerRimBearing + 0.5*Bearing_Outer, InnerRimBearing + 0.5 * Bearing_Outer, Bearing_Height)) OuterFrame = bpy.context.object bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * Bearing_Height), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, Bearing_Height)) InPin = bpy.context.object applyBoolean('DIFFERENCE', OuterFrame, InPin) ''' # Main_Gear_Top bpy.ops.mesh.add_3d_cvt_part( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), Gear_Id = 0, number_of_teeth = start_with_number_of_teeth, angle_resolution = angle_resolution, scale_xy=scale_xy, scale_z=scale_z, add_top = False, add_middle = False, add_bottom = True, ) Main_Gear_Top = bpy.context.object Main_Gear_Top.name = "Main_Gear_Top" bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, -3 + (scale_z * 0.5 ) ), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 6 + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Top, Bearing_Main_Gear) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, -3 + (scale_z * 0.5 ) ), scale=(-InnerRimBearing + 0.5*Bearing_Outer,-InnerRimBearing + 0.5 * Bearing_Outer, 6 + (2 * InnerRimHeight) + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Top, Bearing_Main_Gear) # Main_Gear_Bottom bpy.ops.mesh.add_3d_cvt_part( align='WORLD', location=(0, 0, -2 * scale_z), rotation=(0, 0, 0), Gear_Id = 0, number_of_teeth = start_with_number_of_teeth + 2, angle_resolution = angle_resolution, scale_xy=scale_xy, scale_z=scale_z, add_top = True, add_middle = False, add_bottom = False, ) Main_Gear_Bottom = bpy.context.object Main_Gear_Bottom.name = "Main_Gear_Bottom" bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, -3 + (scale_z * 0.5 ) ), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 6 + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Bottom, Bearing_Main_Gear) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, -3 + (scale_z * 0.5 ) ), scale=(-InnerRimBearing + 0.5*Bearing_Outer,-InnerRimBearing + 0.5 * Bearing_Outer, 6 + (2 * InnerRimHeight) + Bearing_Height)) Bearing_Main_Gear = bpy.context.object applyBoolean('DIFFERENCE', Main_Gear_Bottom, Bearing_Main_Gear) # Main_Gear objectToSelect = Main_Gear_Top objectToSelect.select_set(True) objectToSelect = Main_Gear_Bottom objectToSelect.select_set(True) bpy.ops.object.join() Main_Gear = bpy.context.object Main_Gear.name = "Main_Gear" # Position pinions x = reference_circle_radius(start_with_number_of_teeth + 1 + Pinion_Number_Of_Teeth, Default_Centre_Pressure_Angle) + Backlash bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(scale_xy * x, 0, scale_z), rotation=(0, pi, 0), number_of_teeth = Pinion_Number_Of_Teeth, number_of_extra_teeth = 2, start_at_extra_teeth = 1, angle_start = start_angle_calc_3D(Pinion_Number_Of_Teeth), tip_cut_at_number_of_extra_teeth=Pinion_Tip_Cut_At_Number_Of_Extra_Teeth, centre_pressure_angle = Default_Centre_Pressure_Angle, angle_resolution = angle_resolution, half_gear = False, is_pinion = True, ) Pinion = bpy.context.object Pinion.name ="Pinion" Pinion.scale.z = scale_z Pinion.scale.x = scale_xy Pinion.scale.y = scale_xy bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, -3 + (scale_z * 0.5 ) ), scale=(0.5*Bearing_Outer, 0.5 * Bearing_Outer, 6 + Bearing_Height)) Bearing_Pinion = bpy.context.object applyBoolean('DIFFERENCE', Pinion, Bearing_Pinion) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, -3 + (scale_z * 0.5 ) ), scale=(-InnerRimBearing + 0.5*Bearing_Outer,-InnerRimBearing + 0.5 * Bearing_Outer, 6 + (2 * InnerRimHeight) + Bearing_Height)) Bearing_Pinion = bpy.context.object applyBoolean('DIFFERENCE', Pinion, Bearing_Pinion) # Block Clearance_Between_Gear_And_Block = 0.5 #mm # Pinion base plate z_Pin = Clearance_Between_Gear_And_Block + 0.5 * scale_z + 0.5 * Bearing_Height bpy.ops.mesh.primitive_cube_add(location=(0.5 * scale_xy * x, 0, 0), size= 1) Pinion_Base_Plate = bpy.context.object Pinion_Base_Plate.name = "Pinion_Base_Plate" Pinion_Base_Plate.scale.x = 8 + 2 * scale_xy * x Pinion_Base_Plate.scale.y = 8 + scale_xy * x Pinion_Base_Plate.scale.z = Lego_Plate_Height Pinion_Base_Plate.location.z = -(0.5 * Pinion_Base_Plate.scale.z) - Clearance_Between_Gear_And_Block # Pin Top Pinion bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, 0.5 * z_Pin - Clearance_Between_Gear_And_Block), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, z_Pin)) Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Pin_Main_Frame) # Ridge Pin Top Pinion bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(scale_xy * x, 0, 0.5 * (z_Pin - Bearing_Height) - Clearance_Between_Gear_And_Block), scale=(InnerRimBearing + 0.5*Bearing_Inner, InnerRimBearing + 0.5 * Bearing_Inner, z_Pin - Bearing_Height)) Ridge_Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Ridge_Pin_Main_Frame) bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * z_Pin - Clearance_Between_Gear_And_Block), scale=(0.5*Bearing_Inner, 0.5 * Bearing_Inner, z_Pin)) Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Pin_Main_Frame) # Ridge Pin Top Pinion bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0.5 * (z_Pin - Bearing_Height) - Clearance_Between_Gear_And_Block), scale=(InnerRimBearing + 0.5*Bearing_Inner, InnerRimBearing + 0.5 * Bearing_Inner, z_Pin - Bearing_Height)) Ridge_Pin_Main_Frame = bpy.context.object applyBoolean('UNION', Pinion_Base_Plate, Ridge_Pin_Main_Frame) # ------------------------------------------------------------------------------------------------------------------- def add_lego_gears(self, context): angle_resolution = self.angle_resolution number_of_teeth = 10 number_of_teeth_X = number_of_teeth # note: (if: number_of_teeth <> number_of_teeth_X) then aA will need optimisation by hand aA_Correction = 0 # note: (if: number_of_teeth = number_of_teeth_X) then this is 0 Backlash = 0.0#1 # required otherwise it looks unrealisticly tight in blender Def_tip_cut = 1.25 Def_extra_root_depth = 48 Extra_Radius_Root_Circle = 1.05 d, pA, pB = cvt_calc(number_of_teeth, number_of_teeth_X) aA1 = start_angle_calc(pB, number_of_teeth) aA = start_angle_calc_ref_zero(pB, number_of_teeth, number_of_teeth + 2) # note there is an error if: number_of_teeth <> number_of_teeth_X. aA = aA + aA_Correction aB = start_angle_calc(pB, number_of_teeth + 2) aX = start_angle_calc(pB, number_of_teeth_X) b = d + Backlash # distance between axes bb = d - reference_circle_radius(number_of_teeth_X, pB) CircLine = number_of_teeth CubeSize = 4 * (number_of_teeth + 6) Cube_Y = 1.35986675 + 0.5 * CubeSize # create top half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth, number_of_extra_teeth = 0, start_at_extra_teeth = 0.0001, angle_start = aA, tip_cut_at_number_of_extra_teeth = 3.26, angle_resolution = angle_resolution, half_gear = True, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Top_Gear = bpy.context.object bpy.ops.mesh.primitive_cube_add(location=(0.0, Cube_Y, 0.1), size= CubeSize) Cube = bpy.context.object applyBoolean('INTERSECT', Top_Gear, Cube) # create bottom half of gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth+2, number_of_extra_teeth = 0, #angle_start = 0.14, angle_start = aB, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = False, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Bottom_Gear = bpy.context.object bpy.context.object.rotation_euler[2] = pi / (number_of_teeth + 2) bpy.ops.mesh.primitive_cube_add(location=(0.0, Cube_Y, 0.1), size= CubeSize) Cube = bpy.context.object applyBoolean('DIFFERENCE', Bottom_Gear, Cube) # join the 2 parts into 1, and rename objectToSelect = Top_Gear objectToSelect.select_set(True) objectToSelect = Bottom_Gear objectToSelect.select_set(True) bpy.ops.object.join() Multi_ratio_Gear = context.object Multi_ratio_Gear.name = "Multi-ratio" # create pinion gear bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(b, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth_X, number_of_extra_teeth = 0, angle_start = aX, tip_cut_at_number_of_extra_teeth = Def_tip_cut, angle_resolution = angle_resolution, half_gear = False, extra_root_depth=Def_extra_root_depth, extra_radius_root_circle = Extra_Radius_Root_Circle, ) Pinion = bpy.context.object Pinion.name = 'Pinion' # So far this was a copy from add_2_ratio_2d_spur_gear Lego_Gear_Height = 14 * LDU # = 5.6 mm Lego_Scale_Factor = (3 * Lego_Brick_Width_Depth - 2 * Lego_Brick_Gap_Horizontal) / b # A zero backlash is not possible in ther real world Multi_ratio_Gear.scale.x = Lego_Scale_Factor Multi_ratio_Gear.scale.y = Lego_Scale_Factor Multi_ratio_Gear.scale.z = Lego_Gear_Height Pinion.scale.x = Lego_Scale_Factor Pinion.scale.y = Lego_Scale_Factor Pinion.scale.z = Lego_Gear_Height Pinion.location.x = 3 * Lego_Brick_Width_Depth # Main gear cross CentreCut_Width = Lego_Brick_Width_Depth - 2 * LDU bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(CentreCut_Width, CentreCut_Width, 30)) CentreCut = bpy.context.object applyBoolean('DIFFERENCE', Multi_ratio_Gear, CentreCut) bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0.5 * Lego_Gear_Height), size= 1) Cross = bpy.context.object Cross.scale.x = (3 * Lego_Technic_Shaft_In) - Lego_Brick_Gap_Horizontal Cross.scale.y = Lego_Technic_Shaft_Out + 2 * Lego_Technic_Shaft_In Cross.scale.z = Lego_Gear_Height bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0.5 * Lego_Gear_Height), size= 1) Cube = bpy.context.object Cube.scale.x = 2 * CentreCut_Width Cube.scale.y = 3 * Lego_Technic_Shaft_In Cube.scale.z = Lego_Gear_Height applyBoolean('UNION', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0.5 * Lego_Gear_Height), size= 1) Cube = bpy.context.object Cube.scale.x = 2 * Lego_Brick_Width_Depth Cube.scale.y = Lego_Technic_Shaft_In - Lego_Brick_Gap_Horizontal Cube.scale.z = 8 applyBoolean('DIFFERENCE', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Cube = bpy.context.object Cube.scale.x = Lego_Technic_Shaft_In Cube.scale.y = Lego_Technic_Shaft_Out Cube.scale.z = 33 applyBoolean('DIFFERENCE', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size= 1) Cube = bpy.context.object Cube.scale.x = (Lego_Technic_Shaft_In + Lego_Technic_Shaft_InRadius) * sqrt(2) Cube.scale.y = Cube.scale.x Cube.scale.z = 33 Cube.rotation_euler = (0, 0, 0.25 * pi) applyBoolean('DIFFERENCE', Cross, Cube) applyBoolean('UNION', Multi_ratio_Gear, Cross) # Pinion gear cross CentreCut_Width = Lego_Brick_Width_Depth - Lego_Technic_Shaft_In bpy.ops.mesh.primitive_cylinder_add( vertices = 5/angle_resolution, radius=1, depth=1, enter_editmode=False, align='WORLD', location=(Pinion.location.x, 0, 0), scale=(CentreCut_Width, CentreCut_Width, 30)) CentreCut = bpy.context.object applyBoolean('DIFFERENCE', Pinion, CentreCut) bpy.ops.mesh.primitive_cube_add(location=(Pinion.location.x, 0, 0.5 * Lego_Gear_Height), size= 1) Cross = bpy.context.object Cross.scale.x = (3 * Lego_Technic_Shaft_In) - Lego_Brick_Gap_Horizontal Cross.scale.y = Lego_Technic_Shaft_Out + 2 * Lego_Technic_Shaft_In Cross.scale.z = Lego_Gear_Height bpy.ops.mesh.primitive_cube_add(location=(Pinion.location.x, 0, 0.5 * Lego_Gear_Height), size= 1) Cube = bpy.context.object Cube.scale.x = 2 * CentreCut_Width Cube.scale.y = 3 * Lego_Technic_Shaft_In Cube.scale.z = Lego_Gear_Height applyBoolean('UNION', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(Pinion.location.x, 0, 0.5 * Lego_Gear_Height), size= 1) Cube = bpy.context.object Cube.scale.x = 2 * Lego_Brick_Width_Depth Cube.scale.y = Lego_Technic_Shaft_In - Lego_Brick_Gap_Horizontal Cube.scale.z = 8 applyBoolean('DIFFERENCE', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(Pinion.location.x, 0, 0), size= 1) Cube = bpy.context.object Cube.scale.x = Lego_Technic_Shaft_In Cube.scale.y = Lego_Technic_Shaft_Out Cube.scale.z = 33 applyBoolean('DIFFERENCE', Cross, Cube) bpy.ops.mesh.primitive_cube_add(location=(Pinion.location.x, 0, 0), size= 1) Cube = bpy.context.object Cube.scale.x = (Lego_Technic_Shaft_In + Lego_Technic_Shaft_InRadius) * sqrt(2) Cube.scale.y = Cube.scale.x Cube.scale.z = 33 Cube.rotation_euler = (0, 0, 0.25 * pi) applyBoolean('DIFFERENCE', Cross, Cube) applyBoolean('UNION', Pinion, Cross) # ------------------------------------------------------------------------------------------------------------------- def add_truck_cvt(self, context): angle_resolution = self.angle_resolution # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_3d_involute_math(Operator, AddObjectHelper): # This shape is the mathematical basis of all involute gears (2D and 3D) """Create a new 3D Involute math""" bl_idname = "mesh.add_3d_involute_math" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} clockwise : BoolProperty( name="clockwise", description="As seen from above turn clockwise", default = False) angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_3d_involute_math(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- # This shape is the mathematical basis of all involute gears (2D and 3D). # Things like 'pressure angle', 'modulus', 'slope', and 'height' are to be achieved via scaling and # stretching of this basic mathematical shape. They are not relevant at this point. # For 2D spur gears set 'number_of_extra'_teeth to zero. class OBJECT_OT_add_3d_spur_gear(Operator, AddObjectHelper): """Create a new 3D spur gear""" bl_idname = "mesh.add_3d_spur_gear" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} number_of_teeth: IntProperty( name = "number_of_teeth", description="The number of teeth in the gear", default = 10, min = 6) number_of_extra_teeth: FloatProperty( # 0 => Spur gear name="number_of_extra_teeth", description="The extra number of teeth", min=0.0, default=3) start_at_extra_teeth: FloatProperty( name="start_at_extra_teeth", description="start_at_extra_teeth", min=0.0, default=0) angle_start: FloatProperty( name="angle_start", description="Angle Start", default=start_angle_calc_3D(10)) tip_cut_at_number_of_extra_teeth: FloatProperty( name="tip_cut_at_number_of_extra_teeth", description="tip_cut_at_number_of_extra_teeth", default=0)#Main_Gear_Tip_Cut_At_Number_Of_Extra_Teeth) centre_pressure_angle: FloatProperty( name="centre_pressure_angle", description="centre_pressure_angle", min=0, default=Default_Centre_Pressure_Angle) angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) extra_root_depth: FloatProperty( # 0 => Spur gear name="extra_root_depth", description="extra_root_depth", min=0.0, default=21024) extra_radius_root_circle: FloatProperty( name="extra_radius_root_circle", description="extra_radius_root_circle", min=-1, default=-1) half_gear : BoolProperty( name="half_gear", description="If True only half a gear is created", default = False) top_of_cvt : BoolProperty( name="top_of_cvt", description="top_of_cvt", default = True) is_pinion : BoolProperty( name="is_pinion", description="is_pinion", default = False) def execute(self, context): add_3d_spur_gear(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_3d_root_cut(Operator, AddObjectHelper): """Create a new 3d_root_cut""" bl_idname = "mesh.add_3d_root_cut" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} number_of_teeth: IntProperty( name = "number_of_teeth", description="The number of teeth in the gear", default = 10, min = 6) number_of_extra_teeth: FloatProperty( # 0 => Spur gear name="number_of_extra_teeth", description="The extra number of teeth", min=0.0, default=3) angle_start: FloatProperty( name="angle_start", description="Angle Start", #min=0.0, max=1.0, default=0.5) #default=0.10211832403786) angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) extra_root_depth: FloatProperty( name="extra_root_depth", description="extra_root_depth", min=0.0, default=1024) def execute(self, context): add_3d_root_cut(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_3d_cvt_part(Operator, AddObjectHelper): """Create a new 3D spur gear""" bl_idname = "mesh.add_3d_cvt_part" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} Gear_Id: IntProperty( name = "Gear_Id", description="Gear_Id", min = 0, default = 0) number_of_teeth: IntProperty( name = "number_of_teeth", description="number_of_teeth", min = 6, default = 10) angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) scale_xy: FloatProperty( name="scale_xy", description="scale_xy", default=1) scale_z: FloatProperty( name="scale_z", description="scale_z", default=1) add_top : BoolProperty( name="add_top", description="add_top", default = True) add_middle : BoolProperty( name="add_middle", description="add_middle", default = True) add_bottom : BoolProperty( name="add_bottom", description="add_bottom", default = True) def execute(self, context): add_3d_cvt_part(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_3d_cvt(Operator, AddObjectHelper): """Create a new 3D spur gear""" bl_idname = "mesh.add_3d_cvt" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} start_with_number_of_teeth : IntProperty( name = "start_with_number_of_teeth", description="start_with_number_of_teeth", min = 6, default = Default_start_with_number_of_teeth) number_of_gears : IntProperty( name = "number_of_gears", description="number_of_gears", min = 2, default = Default_number_of_gears) angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) scale_xy: FloatProperty( name="scale_xy", description="scale_xy", default=1) scale_z: FloatProperty( name="scale_z", description="scale_z", default=1) show_lines : BoolProperty( name="show_lines", description="show_lines", default = Default_show_lines) show_pinion_1 : BoolProperty( name="show_pinion_1", description="show_pinion_1", default = Default_show_pinion_1) show_pinion_2 : BoolProperty( name="show_pinion_2", description="show_pinion_2", default = Default_show_pinion_2) Pos_Pinion_1 : IntProperty( name = "Pos_Pinion_1", description="Pos_Pinion_1", min = 0, default = Default_Pos_Pinion_1) Pos_Pinion_2 : IntProperty( name = "Pos_Pinion_2", description="Pos_Pinion_2", min = 0, default = Default_Pos_Pinion_2) def execute(self, context): add_3d_cvt(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_2_ratio_2d_spur_gear(Operator, AddObjectHelper): """Create a new 3D spur gear""" bl_idname = "mesh.add_2_ratio_2d_spur_gear" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_2_ratio_2d_spur_gear(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_3_gear_demo(Operator, AddObjectHelper): """Create a 3_gear_demo""" bl_idname = "mesh.add_3_gear_demo" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_3_gear_demo(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_spinner(Operator, AddObjectHelper): """Create a spinner""" bl_idname = "mesh.add_spinner" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_spinner(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_lego_gears(Operator, AddObjectHelper): """Create lego gears""" bl_idname = "mesh.add_lego_gears" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_lego_gears(self, context) return {'FINISHED'} # ------------------------------------------------------------------------------------------------------------------- class OBJECT_OT_add_truck_cvt(Operator, AddObjectHelper): """Create a Truck_CVT""" bl_idname = "mesh.add_truck_cvt" bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} angle_resolution: FloatProperty( name="angle_resolution", description="angle_resolution", min=0.0, max=2*pi, default=Default_Angle_Resolution) def execute(self, context): add_truck_cvt(self, context) return {'FINISHED'} # Registration --------------------------------------------------------------------------------------- def register(): bpy.utils.register_class(InvoluteMenu) bpy.types.VIEW3D_MT_mesh_add.append(InvoluteMenuAdd) bpy.utils.register_class(OBJECT_OT_add_3d_involute_math) bpy.utils.register_class(OBJECT_OT_add_3d_spur_gear) bpy.utils.register_class(OBJECT_OT_add_3d_root_cut) bpy.utils.register_class(OBJECT_OT_add_3d_cvt_part) bpy.utils.register_class(OBJECT_OT_add_3d_cvt) bpy.utils.register_class(OBJECT_OT_add_2_ratio_2d_spur_gear) bpy.utils.register_class(OBJECT_OT_add_3_gear_demo) bpy.utils.register_class(OBJECT_OT_add_spinner) bpy.utils.register_class(OBJECT_OT_add_lego_gears) bpy.utils.register_class(OBJECT_OT_add_truck_cvt) def unregister(): bpy.utils.unregister_class(InvoluteMenu) bpy.types.VIEW3D_MT_mesh_add.remove(InvoluteMenuAdd) bpy.utils.unregister_class(OBJECT_OT_add_3d_involute_math) bpy.utils.unregister_class(OBJECT_OT_add_3d_spur_gear) bpy.utils.unregister_class(OBJECT_OT_add_3d_root_cut) bpy.utils.unregister_class(OBJECT_OT_add_3d_cvt_part) bpy.utils.unregister_class(OBJECT_OT_add_3d_cvt) bpy.utils.unregister_class(OBJECT_OT_add_2_ratio_2d_spur_gear) bpy.utils.unregister_class(OBJECT_OT_add_3_gear_demo) bpy.utils.unregister_class(OBJECT_OT_add_spinner) bpy.utils.unregister_class(OBJECT_OT_add_lego_gears) bpy.utils.unregister_class(OBJECT_OT_add_truck_cvt) if __name__ == "__main__": register() # Run --------------------------------------------------------------------------------------- bpy.ops.object.select_all(action="SELECT") bpy.ops.object.delete() for m in bpy.data.materials: bpy.data.materials.remove(m) import os os.system("cls") if Show_Demo == 1: # Show_Demo = 1 => Show New-CVT demo 1:1 <=> 1:4 bpy.ops.mesh.add_3d_cvt( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), scale_xy = sqrt(2), scale_z=9, ) elif Show_Demo == 2: # Show_Demo = 2 => Show 3D involute shape demo bpy.ops.mesh.add_3d_involute_math( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), ) elif Show_Demo == 3: # Show_Demo = 3 => Show 2 ratio gear demo bpy.ops.mesh.add_2_ratio_2d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), ) elif Show_Demo == 4: # Show_Demo = 4 => Show 3D involute spur gear demo number_of_teeth = 8 #3Tip_Cut_Angle = atan(0.69) #Tip_Cut_Angle = atan(0.72) angle_start_0 = start_angle_calc(Default_Centre_Pressure_Angle, number_of_teeth) bpy.ops.mesh.add_3d_spur_gear( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), number_of_teeth = number_of_teeth, number_of_extra_teeth = 3, start_at_extra_teeth=0, angle_start = angle_start_0, #tip_cut_at_number_of_extra_teeth = 0, #angle_resolution = 0.03*pi, top_of_cvt = True, ) Gear = bpy.context.object Gear.scale.z = 9 elif Show_Demo == 5: # bpy.ops.mesh.add_3_gear_demo( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), ) elif Show_Demo == 6: # bpy.ops.mesh.add_spinner( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), ) elif Show_Demo == 7: # bpy.ops.mesh.add_lego_gears( align='WORLD', location=(0, 0, 0), rotation=(0, 0, 0), )



_