home *** CD-ROM | disk | FTP | other *** search
- #! /usr/bin/env python
- '''
- Copyright (C) 2007 Aaron Spike (aaron @ ekips.org)
- Copyright (C) 2007 Tavmjong Bah (tavmjong @ free.fr)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- '''
-
- import inkex
- import simplestyle, sys
- from math import *
-
- def involute_intersect_angle(Rb, R):
- Rb, R = float(Rb), float(R)
- return (sqrt(R**2 - Rb**2) / (Rb)) - (acos(Rb / R))
-
- def point_on_circle(radius, angle):
- x = radius * cos(angle)
- y = radius * sin(angle)
- return (x, y)
-
- def points_to_svgd(p):
- f = p[0]
- p = p[1:]
- svgd = 'M%.3f,%.3f' % f
- for x in p:
- svgd += 'L%.3f,%.3f' % x
- svgd += 'z'
- return svgd
-
- class Gears(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-t", "--teeth",
- action="store", type="int",
- dest="teeth", default=24,
- help="Number of teeth")
- self.OptionParser.add_option("-p", "--pitch",
- action="store", type="float",
- dest="pitch", default=20.0,
- help="Circular Pitch (length of arc from one tooth to next)")
- self.OptionParser.add_option("-a", "--angle",
- action="store", type="float",
- dest="angle", default=20.0,
- help="Pressure Angle (common values: 14.5, 20, 25 degrees)")
- def effect(self):
-
- teeth = self.options.teeth
- pitch = self.options.pitch
- angle = self.options.angle # Angle of tangent to tooth at circular pitch wrt radial line.
-
- # print >>sys.stderr, "Teeth: %s\n" % teeth
-
- two_pi = 2.0 * pi
-
- # Pitch (circular pitch): Length of the arc from one tooth to the next)
- # Pitch diameter: Diameter of pitch circle.
- pitch_diameter = float( teeth ) * pitch / pi
- pitch_radius = pitch_diameter / 2.0
-
- # Base Circle
- base_diameter = pitch_diameter * cos( radians( angle ) )
- base_radius = base_diameter / 2.0
-
- # Diametrial pitch: Number of teeth per unit length.
- pitch_diametrial = float( teeth )/ pitch_diameter
-
- # Addendum: Radial distance from pitch circle to outside circle.
- addendum = 1.0 / pitch_diametrial
-
- # Outer Circle
- outer_radius = pitch_radius + addendum
- outer_diameter = outer_radius * 2.0
-
- # Tooth thickness: Tooth width along pitch circle.
- tooth = ( pi * pitch_diameter ) / ( 2.0 * float( teeth ) )
-
- # Undercut?
- undercut = (2.0 / ( sin( radians( angle ) ) ** 2))
- needs_undercut = teeth < undercut
-
-
- # Clearance: Radial distance between top of tooth on one gear to bottom of gap on another.
- clearance = 0.0
-
- # Dedendum: Radial distance from pitch circle to root diameter.
- dedendum = addendum + clearance
-
- # Root diameter: Diameter of bottom of tooth spaces.
- root_radius = pitch_radius - dedendum
- root_diameter = root_radius * 2.0
-
- half_thick_angle = two_pi / (4.0 * float( teeth ) )
- pitch_to_base_angle = involute_intersect_angle( base_radius, pitch_radius )
- pitch_to_outer_angle = involute_intersect_angle( base_radius, outer_radius ) - pitch_to_base_angle
-
- centers = [(x * two_pi / float( teeth) ) for x in range( teeth ) ]
-
- points = []
-
- for c in centers:
-
- # Angles
- pitch1 = c - half_thick_angle
- base1 = pitch1 - pitch_to_base_angle
- outer1 = pitch1 + pitch_to_outer_angle
-
- pitch2 = c + half_thick_angle
- base2 = pitch2 + pitch_to_base_angle
- outer2 = pitch2 - pitch_to_outer_angle
-
- # Points
- b1 = point_on_circle( base_radius, base1 )
- p1 = point_on_circle( pitch_radius, pitch1 )
- o1 = point_on_circle( outer_radius, outer1 )
-
- b2 = point_on_circle( base_radius, base2 )
- p2 = point_on_circle( pitch_radius, pitch2 )
- o2 = point_on_circle( outer_radius, outer2 )
-
- if root_radius > base_radius:
- pitch_to_root_angle = pitch_to_base_angle - involute_intersect_angle(base_radius, root_radius )
- root1 = pitch1 - pitch_to_root_angle
- root2 = pitch2 + pitch_to_root_angle
- r1 = point_on_circle(root_radius, root1)
- r2 = point_on_circle(root_radius, root2)
- p_tmp = [r1,p1,o1,o2,p2,r2]
- else:
- r1 = point_on_circle(root_radius, base1)
- r2 = point_on_circle(root_radius, base2)
- p_tmp = [r1,b1,p1,o1,o2,p2,b2,r2]
-
- points.extend( p_tmp )
-
- path = points_to_svgd( points )
-
- # Embed gear in group to make animation easier:
- # Translate group, Rotate path.
- t = 'translate(' + str( self.view_center[0] ) + ',' + str( self.view_center[1] ) + ')'
- g_attribs = {inkex.addNS('label','inkscape'):'Gear' + str( teeth ),
- 'transform':t }
- g = inkex.etree.SubElement(self.current_layer, 'g', g_attribs)
-
- # Create SVG Path for gear
- style = { 'stroke': '#000000', 'fill': 'none' }
- gear_attribs = {'style':simplestyle.formatStyle(style), 'd':path}
- gear = inkex.etree.SubElement(g, inkex.addNS('path','svg'), gear_attribs )
-
- if __name__ == '__main__':
- e = Gears()
- e.affect()
-
-
- # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
-