81 Commits
0.3 ... py2

Author SHA1 Message Date
lorenz
9bf77e9347 add support 2019-09-28 13:23:44 +02:00
lorenz
7e958ee02b Update README.md 2019-09-16 16:11:50 +02:00
luz.paz
0a95618e05 Typo fix and hyperlink 2019-09-16 16:11:50 +02:00
luz.paz
6a0776c764 README: add Addon Manager install method + clarifications 2019-09-16 16:11:50 +02:00
looooo
fe88e0aba3 Revert "Add helical angle to distance calculator"
This reverts commit e4d6955b0b.
2019-09-07 21:20:46 +02:00
lorenz
77a61f7abf roll-diameter -> pitch diameter 2019-09-07 20:45:44 +02:00
looooo
97f1bf5ece add computed properties 2019-09-07 20:22:04 +02:00
lorenz
e4d6955b0b Add helical angle to distance calculator 2019-09-05 08:06:10 +02:00
luz.paz
3923eb0d24 Fix typos 2019-08-13 07:45:07 +02:00
luz.paz
0e72001cf2 Added license detail: GPL 2.0 2019-08-11 08:50:10 +02:00
luz.paz
bd99f95ef3 Add license and added more elaborations 2019-08-11 08:50:10 +02:00
luz.paz
b5970131c4 README: Tweaks 2019-08-11 08:50:10 +02:00
looooo
eade914494 Merge branch 'master' of https://github.com/looooo/freecad.gears 2019-03-07 10:59:49 +01:00
looooo
2127e03a8d update bevel-gear-example 2019-03-07 10:59:24 +01:00
lorenz
102df7bce1 Update README.md 2019-03-05 12:23:13 +01:00
looooo
49c8de36a2 add commands to console 2019-03-05 12:14:34 +01:00
lorenz
10160e8d52 add necesarry line to make namespace-package work 2018-12-17 23:38:24 +01:00
lorenz
925a1e7db2 Update setup.py 2018-11-08 20:44:28 +01:00
lorenz
0414269517 Update README.md 2018-07-06 18:23:44 +02:00
lo
7d08263965 some unnecessary landscape stuff 2018-07-05 16:41:51 +02:00
looooo
5976130c15 readme 2018-07-03 11:15:37 +02:00
looooo
913f3cd954 change install instruction 2018-07-03 10:50:04 +02:00
looooo
fc39fba219 change crown-gear default parameter height 2018-04-12 19:18:57 +02:00
looooo
95fda0e272 add gif 2018-03-27 10:06:09 +02:00
looooo
ae5c393b6f gif 2018-03-27 10:05:20 +02:00
lo
2d803e15e5 simplify the simplified 2018-03-23 13:38:58 +01:00
lo
a2c6f96686 move bevel-gear
- by default to z=0 plane
- set "reset_origin" to false to get old behaviour
2018-03-20 20:26:54 +01:00
lo
45a44e42e4 readme 2018-03-16 23:57:14 +01:00
lo
c7bcbf3349 some examples 2018-03-16 23:54:10 +01:00
lo
02816ddb44 image again 2018-03-16 11:48:14 +01:00
lo
dec4e7736c image 2018-03-16 11:47:29 +01:00
lo
739da7b534 spiral-gear 2018-03-16 11:45:16 +01:00
lo
19a0393385 make new-style-module 2018-03-14 19:04:02 +01:00
looooo
f316faa37f 1 != 2 2017-09-18 14:16:27 +02:00
looooo
534c3aaad8 added function to compute ax distance of shifted gears 2017-09-18 13:08:59 +02:00
looooo
255c77c1b2 crown gear, spiral gear 2017-09-06 11:09:19 +02:00
looooo
6096e15894 crown-gear + crown-gear docs 2017-09-02 15:34:20 +02:00
looooo
7530372a35 add icon for crown gear 2017-08-29 11:38:05 +02:00
looooo
795c166e69 add crown-gear (not yet working) 2017-08-28 20:13:24 +02:00
looooo
962c0e4ffe involute-rack: add head parameter 2017-06-29 10:23:30 +02:00
lorenz
e419f55709 Merge pull request #16 from looooo/develop
fix mirror problem
2017-06-28 11:16:22 +02:00
looooo
c70726a293 fix mirror problem 2017-06-28 11:14:10 +02:00
looooo
61b0d56ae4 use alternative approach to fuse the two solids of a double-helical-gear 2017-06-27 17:14:53 +02:00
looooo
4448f1f7e1 double helix rack 2017-06-27 11:44:05 +02:00
looooo
4b34073f28 add helical extrusion to cycloid gear 2017-06-27 09:09:48 +02:00
kcleung
38b03df09b cleanup 2017-06-27 09:02:13 +02:00
kcleung
42ebf8b59b fixed accidental translation of double helix, and height and position is always same as single helix now 2017-06-27 09:02:13 +02:00
kcleung
3aca091811 fixed height bug where single helix accidentally have height halved 2017-06-27 09:02:13 +02:00
looooo
941f480b0a use compound for double helix 2017-06-26 06:59:41 +02:00
kcleung
1b3044f00c fixed double height bug 2017-06-26 06:43:08 +02:00
kcleung
279da3e304 initial implementation of double helix for involute gear, though mirroring is hard coded to XY plane at Z=0, regardless of actual position and orientation of the gear. This issue is to be fixed in subsequent commits 2017-06-26 06:42:59 +02:00
looooo
c078b8f9f0 add reconstruction example 2017-05-29 07:57:54 +02:00
looooo
b604fe8ec8 simplify helical extrusion 2017-05-14 13:59:52 +02:00
looooo
37ebd2d59e py3: map 2017-02-13 21:54:55 +01:00
lorenz
8d10fa7ff8 Update README.md 2017-02-13 21:54:55 +01:00
looooo
d739065008 added some possibilities to influence the involute-gear profile 2017-02-03 13:58:57 +01:00
looooo
db2c46f331 bevel fix 2016-09-08 17:16:08 +02:00
looooo
8464f37a73 occt7 updates 2016-09-08 16:54:43 +02:00
lorenz_l
9c6920af84 Merge branch 'master' of https://github.com/looooo/FCGear 2016-04-14 10:16:46 +02:00
lorenz_l
0610b41339 py3: returning objects where generators are involved give fatal untrackable errors 2016-04-14 10:15:32 +02:00
lorenz
66b5ca42bf Merge pull request #3 from BPLRFE/master
Update Readme.md
2016-04-09 22:52:02 +02:00
BPLRFE
c34b104a52 Update Readme.md
Added installation instructions for Linux/Windows
2016-04-04 18:27:59 +02:00
looooo
e54cc4d8cf fix <16 error 2016-02-08 20:13:44 +01:00
looooo
75f2189852 proper case naming
proposal from http://forum.freecadweb.org/viewtopic.php?f=3&t=12878&start=30#p112465
2016-01-31 11:46:41 +01:00
looooo
d4104c30de update to make it possible to use this workbench with older versions of freecad 2016-01-31 11:25:53 +01:00
looooo
b0a813c849 update bevel_gear symbol 2016-01-31 09:05:28 +01:00
looooo
fa16fce5e9 Update Readme and add new Icon from Jill Kitten
http://forum.freecadweb.org/viewtopic.php?f=3&t=12878&start=30#p112376
2016-01-30 19:24:56 +01:00
looooo
fbf1dda6b5 python3 updates 2016-01-27 17:09:02 +01:00
looooo
6660e24676 Gui.Workbench accesable 2016-01-04 20:36:15 +01:00
looooo
9e10aa2f74 fix the problem with negative values for beta:
http://forum.freecadweb.org/viewtopic.php?f=13&t=12819
2015-12-07 23:36:53 +01:00
looooo
e371d021a2 added symbol 2015-11-23 18:12:09 +01:00
looooo
57c69f91cf update readme 2015-10-28 14:15:13 +01:00
looooo
ecbdfb9d14 changed directory structure 2015-10-28 14:13:22 +01:00
looooo
5f661cdce8 added bevel gear example 2015-10-25 13:35:45 +01:00
looooo
c6c8a23c9e better naming 2015-10-24 19:09:11 +02:00
looooo
b6499ebd40 works now 2015-10-24 18:41:38 +02:00
looooo
894a283afc scaled clearence 2015-10-24 18:38:36 +02:00
looooo
578855d6b2 alpha bug 2015-10-24 18:31:15 +02:00
looooo
cb17e3ca49 delete debug prints 2015-10-22 23:14:46 +02:00
looooo
a77861fd8f update gear_wb: bevel_gear clearence 2015-10-22 23:11:45 +02:00
looooo
1972520677 update bevel 2015-10-22 23:01:31 +02:00
38 changed files with 2336 additions and 14141 deletions

1
MANIFEST.in Normal file
View File

@@ -0,0 +1 @@
recursive-include freecad/gears/icons *

View File

@@ -1,14 +1,82 @@
a gearmodule for freecad # A Gear module for FreeCAD
[![Liberapay](http://img.shields.io/liberapay/patrons/looooo.svg?logo=liberapay)](https://liberapay.com/looooo/donate)
## Requirements
FreeCAD > v0.16
# Screenshots
![gear](examples/spiral.png)
![gear1](examples/animated_spiral.gif)
## Supported gear-types
### Cylindric Involute
#### Shifting
#### Helical
#### Double Helical
#### Undercut
### Involute Rack
### Cylindric Cycloid
#### Helical
#### Double Helical
### Spherical Involute Bevel-Gear
#### Spiral
### Crown-Gear
--------------------------- ---------------------------
* install: ## Installation
* git clone https://github.com/looooo/FCGear.git
* link or copy the FCgear/gear into /freecad/Mod (sudo ln -s (path_to_FCGear)/gear (path_to_freecad)/Mod
### Addon Manger
Starting from v0.17 it's possible to use the built-in FreeCAD [Addon Manager](https://github.com/FreeCAD/FreeCAD-addons#1-builtin-addon-manager)
located in the `Tools` > `Addon Manager` dropdown menu.
* create a gear: ### pip
* open freecad
* go to the gear workbench `pip install https://github.com/looooo/FCGear/archive/master.tar.gz`
* create new document
* create a gear (click on gear symbol) **Important note:** Most systems have multiple versions of python installed. Make sure the `pip` you're using is used by FreeCAD as well.
* change parameters
## Usage
### Create a gear manually
* Open freecad
* Switch to the gear workbench
* Create new document
* Create a gear (click on a gear symbol in the toolbar)
* Change the gear parameters
## Scripted gears
Use the power of python to automate your gear modeling:
```python
import FreeCAD as App
import freecad.gears.commands
gear = freecad.gears.commands.CreateInvoluteGear.create()
gear.teeth = 20
gear.beta = 20
gear.height = 10
gear.double_helix = True
App.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")
```
## References
* Elements of Metric Gear Technology ([PDF](http://qtcgears.com/tools/catalogs/PDF_Q420/Tech.pdf))
### FreeCAD Forum threads
These are forum threads where FreeCAD Gears has been discussed. If you want to give Feedback
or report a bug please use the below threads. Please make sure that the report hasn't been reported already
by browsing this repositories [issue queue](https://github.com/looooo/freecad.gears/issues).
* "CONTINUED: involute gear generator preview !" ([thread](https://forum.freecadweb.org/viewtopic.php?f=10&t=4829))
* "Bevel gear - module/script/tutorial" ([thread](https://forum.freecadweb.org/viewtopic.php?f=3&t=12878))
* "Gears in FreeCAD: FC Gear" ([thread](https://forum.freecadweb.org/viewtopic.php?f=24&t=27381))
* "FC Gears: Feedback thread" ([thread](https://forum.freecadweb.org/viewtopic.php?f=8&t=27626))
# License
GNU General Public License v2.0

BIN
docs/crown_gear.pdf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

32
examples/animation.py Normal file
View File

@@ -0,0 +1,32 @@
# script for bevel-gear animation
from PySide import QtGui, QtCore
import FreeCADGui as Gui
import numpy as np
import imageio
doc = App.ActiveDocument
g2 = doc.Common
g1 = doc.Common001
timer = QtCore.QTimer()
def make_pics():
n = 30
for i in range(n):
phi = np.pi * 2 / 30 / n
g1.Placement.Rotation.Angle += phi * 2
g2.Placement.Rotation.Angle -= phi
Gui.activeDocument().activeView().saveImage('/home/lo/Schreibtisch/animated_gear/gear_{}.png'.format(i) ,300,300,'Current')
def make_animated_gif():
def update(*args):
print("time")
delta_phi = 0.005
g1.Placement.Rotation.Angle += delta_phi * 2
g2.Placement.Rotation.Angle -= delta_phi
timer.timeout.connect(update)
timer.start()

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
examples/spiral.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

1
freecad/__init__.py Normal file
View File

@@ -0,0 +1 @@
__path__ = __import__('pkgutil').extend_path(__path__, __name__)

View File

@@ -0,0 +1,2 @@
import pygears
__version__ = pygears.__version__

94
freecad/gears/commands.py Normal file
View File

@@ -0,0 +1,94 @@
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 os
import FreeCAD
import FreeCADGui as Gui
from .features import ViewProviderGear, involute_gear, involute_gear_rack
from .features import cycloide_gear, bevel_gear, crown_gear
class BaseCommand(object):
NAME = ""
GEAR_FUNCTION = None
ICONDIR = os.path.join(os.path.dirname(__file__), "icons")
def __init__(self):
pass
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
def Activated(self):
Gui.doCommandGui("import freecad.gears.commands")
Gui.doCommandGui("freecad.gears.commands.{}.create()".format(self.__class__.__name__))
FreeCAD.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")
@classmethod
def create(cls):
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", cls.NAME)
cls.GEAR_FUNCTION(obj)
ViewProviderGear(obj.ViewObject)
return obj
def GetResources(self):
return {'Pixmap': self.Pixmap,
'MenuText': self.MenuText,
'ToolTip': self.ToolTip}
class CreateInvoluteGear(BaseCommand):
NAME = "InvoluteGear"
GEAR_FUNCTION = involute_gear
Pixmap = os.path.join(BaseCommand.ICONDIR, 'involutegear.svg')
MenuText = 'involute gear'
ToolTip = 'involute gear'
class CreateInvoluteRack(BaseCommand):
NAME = "InvoluteRack"
GEAR_FUNCTION = involute_gear_rack
Pixmap = os.path.join(BaseCommand.ICONDIR, 'involuterack.svg')
MenuText = 'involute rack'
ToolTip = 'involute rack'
class CreateCrownGear(BaseCommand):
NAME = "CrownGear"
GEAR_FUNCTION = crown_gear
Pixmap = os.path.join(BaseCommand.ICONDIR, 'crowngear.svg')
MenuText = 'crown gear'
ToolTip = 'crown gear'
class CreateCycloideGear(BaseCommand):
NAME = "CycloidGear"
GEAR_FUNCTION = cycloide_gear
Pixmap = os.path.join(BaseCommand.ICONDIR, 'cycloidegear.svg')
MenuText = 'cycloide gear'
ToolTip = 'cycloide gear'
class CreateBevelGear(BaseCommand):
NAME = "BevelGear"
GEAR_FUNCTION = bevel_gear
Pixmap = os.path.join(BaseCommand.ICONDIR, 'bevelgear.svg')
MenuText = 'bevel gear'
ToolTip = 'bevel gear'

611
freecad/gears/features.py Normal file
View File

@@ -0,0 +1,611 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 *
#* *
#***************************************************************************
from __future__ import division
import os
import numpy as np
from pygears.involute_tooth import involute_tooth, involute_rack
from pygears.cycloide_tooth import cycloide_tooth
from pygears.bevel_tooth import bevel_tooth
from pygears._functions import rotation3D, rotation
import FreeCAD as App
import Part
from Part import BSplineCurve, Shape, Wire, Face, makePolygon, \
BRepOffsetAPI, Shell, makeLoft, Solid, Line, BSplineSurface, makeCompound,\
show, makePolygon, makeHelix, makeShell, makeSolid
__all__=["involute_gear",
"cycloide_gear",
"bevel_gear",
"involute_gear_rack",
"ViewProviderGear"]
def fcvec(x):
if len(x) == 2:
return(App.Vector(x[0], x[1], 0))
else:
return(App.Vector(x[0], x[1], x[2]))
class ViewProviderGear(object):
def __init__(self, obj):
''' Set this object to the proxy object of the actual view provider '''
obj.Proxy = self
def attach(self, vobj):
self.vobj = vobj
def getIcon(self):
__dirname__ = os.path.dirname(__file__)
return(os.path.join(__dirname__, "icons", "involutegear.svg"))
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class involute_gear(object):
"""FreeCAD gear"""
def __init__(self, obj):
self.involute_tooth = involute_tooth()
obj.addProperty(
"App::PropertyBool", "simple", "gear_parameter", "simple")
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyBool", "undercut", "gear_parameter", "undercut")
obj.addProperty(
"App::PropertyFloat", "shift", "gear_parameter", "shift")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyAngle", "pressure_angle", "involute_parameter", "pressure angle")
obj.addProperty(
"App::PropertyFloat", "clearance", "gear_parameter", "clearance")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty(
"App::PropertyAngle", "beta", "gear_parameter", "beta ")
obj.addProperty(
"App::PropertyBool", "double_helix", "gear_parameter", "double helix")
obj.addProperty(
"App::PropertyLength", "backlash", "tolerance", "backlash")
obj.addProperty(
"App::PropertyBool", "reversed_backlash", "tolerance", "backlash direction")
obj.addProperty(
"App::PropertyFloat", "head", "gear_parameter", "head_value * modul_value = additional length of head")
obj.addProperty("App::PropertyPythonObject", "gear", "gear_parameter", "test")
obj.addProperty("App::PropertyFloat", "dw", "computed", "pitch diameter", 1)
obj.gear = self.involute_tooth
obj.simple = False
obj.undercut = False
obj.teeth = 15
obj.module = '1. mm'
obj.shift = 0.
obj.pressure_angle = '20. deg'
obj.beta = '0. deg'
obj.height = '5. mm'
obj.clearance = 0.25
obj.head = 0.
obj.numpoints = 6
obj.double_helix = False
obj.backlash = '0.00 mm'
obj.reversed_backlash = False
self.obj = obj
obj.Proxy = self
def execute(self, fp):
fp.gear.double_helix = fp.double_helix
fp.gear.m_n = fp.module.Value
fp.gear.z = fp.teeth
fp.gear.undercut = fp.undercut
fp.gear.shift = fp.shift
fp.gear.pressure_angle = fp.pressure_angle.Value * np.pi / 180.
fp.gear.beta = fp.beta.Value * np.pi / 180
fp.gear.clearance = fp.clearance
fp.gear.backlash = fp.backlash.Value * (-fp.reversed_backlash + 0.5) * 2.
fp.gear.head = fp.head
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
rotated_pts = pts
rot = rotation(-fp.gear.phipart)
for i in range(fp.gear.z - 1):
rotated_pts = list(map(rot, rotated_pts))
pts.append(np.array([pts[-1][-1], rotated_pts[0][0]]))
pts += rotated_pts
pts.append(np.array([pts[-1][-1], pts[0][0]]))
if not fp.simple:
wi = []
for i in pts:
out = BSplineCurve()
out.interpolate(list(map(fcvec, i)))
wi.append(out.toShape())
wi = Wire(wi)
if fp.beta.Value == 0:
sh = Face(wi)
fp.Shape = sh.extrude(App.Vector(0, 0, fp.height.Value))
else:
fp.Shape = helicalextrusion(
wi, fp.height.Value, fp.height.Value * np.tan(fp.gear.beta) * 2 / fp.gear.d, fp.double_helix)
else:
rw = fp.gear.dw / 2
fp.Shape=Part.makeCylinder(rw,fp.height.Value)
fp.dw = fp.gear.dw
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class involute_gear_rack(object):
"""FreeCAD gear rack"""
def __init__(self, obj):
self.involute_rack = involute_rack()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyLength", "thickness", "gear_parameter", "thickness")
obj.addProperty(
"App::PropertyAngle", "beta", "gear_parameter", "beta ")
obj.addProperty(
"App::PropertyAngle", "pressure_angle", "involute_parameter", "pressure angle")
obj.addProperty(
"App::PropertyBool", "double_helix", "gear_parameter", "double helix")
obj.addProperty(
"App::PropertyFloat", "head", "gear_parameter", "head_value * modul_value = additional length of head")
obj.addProperty("App::PropertyPythonObject", "rack", "test", "test")
obj.rack = self.involute_rack
obj.teeth = 15
obj.module = '1. mm'
obj.pressure_angle = '20. deg'
obj.height = '5. mm'
obj.thickness = '5 mm'
obj.beta = '0. deg'
self.obj = obj
obj.Proxy = self
def execute(self, fp):
fp.rack.m = fp.module.Value
fp.rack.z = fp.teeth
fp.rack.pressure_angle = fp.pressure_angle.Value * np.pi / 180.
fp.rack.thickness = fp.thickness.Value
fp.rack.beta = fp.beta.Value * np.pi / 180.
fp.rack.head = fp.head
fp.rack._update()
pts = fp.rack.points()
pol = Wire(makePolygon(list(map(fcvec, pts))))
if fp.beta.Value == 0:
face = Face(Wire(pol))
fp.Shape = face.extrude(fcvec([0., 0., fp.height.Value]))
elif fp.double_helix:
beta = fp.beta.Value * np.pi / 180.
pol2 = Part.Wire(pol)
pol2.translate(fcvec([0., np.tan(beta) * fp.height.Value / 2, fp.height.Value / 2]))
pol3 = Part.Wire(pol)
pol3.translate(fcvec([0., 0., fp.height.Value]))
fp.Shape = makeLoft([pol, pol2, pol3], True, True)
else:
beta = fp.beta.Value * np.pi / 180.
pol2 = Part.Wire(pol)
pol2.translate(fcvec([0., np.tan(beta) * fp.height.Value, fp.height.Value]))
fp.Shape = makeLoft([pol, pol2], True)
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class crown_gear(object):
def __init__(self, obj):
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty("App::PropertyInteger",
"other_teeth", "gear_parameter", "number of teeth of other gear")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyLength", "thickness", "gear_parameter", "thickness")
obj.addProperty(
"App::PropertyAngle", "pressure_angle", "involute_parameter", "pressure angle")
obj.addProperty("App::PropertyInteger",
"num_profiles", "accuracy", "number of profiles used for loft")
obj.addProperty("App::PropertyBool",
"construct", "accuracy", "number of profiles used for loft")
obj.teeth = 15
obj.other_teeth = 15
obj.module = '1. mm'
obj.pressure_angle = '20. deg'
obj.height = '2. mm'
obj.thickness = '5 mm'
obj.num_profiles = 4
obj.construct = True
self.obj = obj
obj.Proxy = self
def profile(self, m, r, r0, t_c, t_i, alpha_w, y0, y1, y2):
r_ew = m * t_i / 2
# 1: modifizierter Waelzkreisdurchmesser:
r_e = r / r0 * r_ew
# 2: modifizierter Schraegungswinkel:
alpha = np.arccos(r0 / r * np.cos(alpha_w))
# 3: winkel phi bei senkrechter stellung eines zahns:
phi = np.pi / t_i / 2 + (alpha - alpha_w) + (np.tan(alpha_w) - np.tan(alpha))
# 4: Position des Eingriffspunktes:
x_c = r_e * np.sin(phi)
dy = -r_e * np.cos(phi) + r_ew
# 5: oberer Punkt:
b = y1 - dy
a = np.tan(alpha) * b
x1 = a + x_c
# 6: unterer Punkt
d = y2 + dy
c = np.tan(alpha) * d
x2 = x_c - c
r *= np.cos(phi)
pts = [
[-x1, r, y0],
[-x2, r, y0 - y1 - y2],
[x2, r, y0 - y1 - y2],
[x1, r, y0]
]
pts.append(pts[0])
return pts
def execute(self, fp):
inner_diameter = fp.module.Value * fp.teeth
outer_diameter = inner_diameter + fp.height.Value * 2
inner_circle = Part.Wire(Part.makeCircle(inner_diameter / 2.))
outer_circle = Part.Wire(Part.makeCircle(outer_diameter / 2.))
inner_circle.reverse()
face = Part.Face([outer_circle, inner_circle])
solid = face.extrude(App.Vector([0., 0., -fp.thickness.Value]))
### cutting obj
alpha_w = np.deg2rad(fp.pressure_angle.Value)
m = fp.module.Value
t = fp.teeth
t_c = t
t_i = fp.other_teeth
rm = inner_diameter / 2
y0 = m * 0.5
y1 = m + y0
y2 = m
r0 = inner_diameter / 2 - fp.height.Value * 0.1
r1 = outer_diameter / 2 + fp.height.Value * 0.3
polies = []
for r_i in np.linspace(r0, r1, fp.num_profiles):
pts = self.profile(m, r_i, rm, t_c, t_i, alpha_w, y0, y1, y2)
poly = Wire(makePolygon(list(map(fcvec, pts))))
polies.append(poly)
loft = makeLoft(polies, True)
rot = App.Matrix()
rot.rotateZ(2 * np.pi / t)
if fp.construct:
cut_shapes = [solid]
for _ in range(t):
loft = loft.transformGeometry(rot)
cut_shapes.append(loft)
fp.Shape = Part.Compound(cut_shapes)
else:
for i in range(t):
loft = loft.transformGeometry(rot)
solid = solid.cut(loft)
fp.Shape = solid
def __getstate__(self):
pass
def __setstate__(self, state):
pass
class cycloide_gear(object):
"""FreeCAD gear"""
def __init__(self, obj):
self.cycloide_tooth = cycloide_tooth()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyLength", "inner_diameter", "cycloid_parameter", "inner_diameter")
obj.addProperty(
"App::PropertyLength", "outer_diameter", "cycloid_parameter", "outer_diameter")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyBool", "double_helix", "gear_parameter", "double helix")
obj.addProperty(
"App::PropertyFloat", "clearance", "gear_parameter", "clearance")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty("App::PropertyAngle", "beta", "gear_parameter", "beta")
obj.addProperty(
"App::PropertyLength", "backlash", "gear_parameter", "backlash in mm")
obj.addProperty("App::PropertyPythonObject", "gear", "gear_parameter", "the python object")
obj.gear = self.cycloide_tooth
obj.teeth = 15
obj.module = '1. mm'
obj.inner_diameter = '5 mm'
obj.outer_diameter = '5 mm'
obj.beta = '0. deg'
obj.height = '5. mm'
obj.clearance = 0.25
obj.numpoints = 15
obj.backlash = '0.00 mm'
obj.double_helix = False
obj.Proxy = self
def execute(self, fp):
fp.gear.m = fp.module.Value
fp.gear.z = fp.teeth
fp.gear.z1 = fp.inner_diameter.Value
fp.gear.z2 = fp.outer_diameter.Value
fp.gear.clearance = fp.clearance
fp.gear.backlash = fp.backlash.Value
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
rotated_pts = pts
rot = rotation(-fp.gear.phipart)
for i in range(fp.gear.z - 1):
rotated_pts = list(map(rot, rotated_pts))
pts.append(np.array([pts[-1][-1], rotated_pts[0][0]]))
pts += rotated_pts
pts.append(np.array([pts[-1][-1], pts[0][0]]))
wi = []
for i in pts:
out = BSplineCurve()
out.interpolate(list(map(fcvec, i)))
wi.append(out.toShape())
wi = Wire(wi)
if fp.beta.Value == 0:
sh = Face(wi)
fp.Shape = sh.extrude(App.Vector(0, 0, fp.height.Value))
else:
fp.Shape = helicalextrusion(
wi, fp.height.Value, fp.height.Value * np.tan(fp.beta.Value * np.pi / 180) * 2 / fp.gear.d, fp.double_helix)
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class bevel_gear(object):
"""parameters:
pressure_angle: pressureangle, 10-30°
pitch_angle: cone angle, 0 < pitch_angle < pi/4
"""
def __init__(self, obj):
self.bevel_tooth = bevel_tooth()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyAngle", "pitch_angle", "involute_parameter", "pitch_angle")
obj.addProperty(
"App::PropertyAngle", "pressure_angle", "involute_parameter", "pressure_angle")
obj.addProperty("App::PropertyLength", "m", "gear_parameter", "m")
obj.addProperty(
"App::PropertyFloat", "clearance", "gear_parameter", "clearance")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty("App::PropertyBool", "reset_origin", "gear_parameter",
"if value is true the gears outer face will match the z=0 plane")
obj.addProperty(
"App::PropertyLength", "backlash", "gear_parameter", "backlash in mm")
obj.addProperty("App::PropertyPythonObject", "gear", "gear_paramenter", "test")
obj.addProperty("App::PropertyAngle", "beta", "gear_paramenter", "test")
obj.gear = self.bevel_tooth
obj.m = '1. mm'
obj.teeth = 15
obj.pressure_angle = '20. deg'
obj.pitch_angle = '45. deg'
obj.height = '5. mm'
obj.numpoints = 6
obj.backlash = '0.00 mm'
obj.clearance = 0.1
obj.beta = '0 deg'
obj.reset_origin = True
self.obj = obj
obj.Proxy = self
def execute(self, fp):
fp.gear.z = fp.teeth
fp.gear.module = fp.m.Value
fp.gear.pressure_angle = (90 - fp.pressure_angle.Value) * np.pi / 180.
fp.gear.pitch_angle = fp.pitch_angle.Value * np.pi / 180
fp.gear.backlash = fp.backlash.Value
scale = fp.m.Value * fp.gear.z / 2 / np.tan(fp.pitch_angle.Value * np.pi / 180)
fp.gear.clearance = fp.clearance / scale
fp.gear._update()
pts = list(fp.gear.points(num=fp.numpoints))
rot = rotation3D(2 * np.pi / fp.teeth)
# if fp.beta.Value != 0:
# pts = [np.array([self.spherical_rot(j, fp.beta.Value * np.pi / 180.) for j in i]) for i in pts]
rotated_pts = pts
for i in range(fp.gear.z - 1):
rotated_pts = list(map(rot, rotated_pts))
pts.append(np.array([pts[-1][-1], rotated_pts[0][0]]))
pts += rotated_pts
pts.append(np.array([pts[-1][-1], pts[0][0]]))
wires = []
scale_0 = scale - fp.height.Value / 2
scale_1 = scale + fp.height.Value / 2
if fp.beta.Value == 0:
wires.append(makeBSplineWire([scale_0 * p for p in pts]))
wires.append(makeBSplineWire([scale_1 * p for p in pts]))
else:
for scale_i in np.linspace(scale_0, scale_1, 20):
# beta_i = (scale_i - scale_0) * fp.beta.Value * np.pi / 180
# rot = rotation3D(beta_i)
# points = [rot(pt) * scale_i for pt in pts]
angle = fp.beta.Value * np.pi / 180. * np.sin(np.pi / 4) / np.sin(fp.pitch_angle.Value * np.pi / 180.)
points = [np.array([self.spherical_rot(p, angle) for p in scale_i * pt]) for pt in pts]
wires.append(makeBSplineWire(points))
shape = makeLoft(wires, True)
if fp.reset_origin:
mat = App.Matrix()
mat.A33 = -1
mat.move(fcvec([0, 0, scale_1]))
shape = shape.transformGeometry(mat)
fp.Shape = shape
# fp.Shape = self.create_teeth(pts, pos1, fp.teeth)
def create_tooth(self):
w = []
scal1 = self.obj.m.Value * self.obj.gear.z / 2 / np.tan(
self.obj.pitch_angle.Value * np.pi / 180) - self.obj.height.Value / 2
scal2 = self.obj.m.Value * self.obj.gear.z / 2 / np.tan(
self.obj.pitch_angle.Value * np.pi / 180) + self.obj.height.Value / 2
s = [scal1, scal2]
pts = self.obj.gear.points(num=self.obj.numpoints)
for j, pos in enumerate(s):
w1 = []
scale = lambda x: fcvec(x * pos)
for i in pts:
i_scale = list(map(scale, i))
w1.append(i_scale)
w.append(w1)
surfs = []
w_t = zip(*w)
for i in w_t:
b = BSplineSurface()
b.interpolate(i)
surfs.append(b)
return Shape(surfs)
def spherical_rot(self, point, phi):
new_phi = np.sqrt(np.linalg.norm(point)) * phi
return rotation3D(new_phi)(point)
def create_teeth(self, pts, pos, teeth):
w1 = []
pts = [pt * pos for pt in pts]
rotated_pts = scaled_points
rot = rotation3D(- 2 * i * np.pi / teeth)
for i in range(teeth - 1):
rotated_pts = map(rot, rotated_pts)
pts.append(np.array([pts[-1][-1], rotated_pts[0][0]]))
pts += rotated_pts
s = Wire(Shape(w1).Edges)
wi = []
for i in range(teeth):
rot = App.Matrix()
rot.rotateZ(2 * i * np.pi / teeth)
tooth_rot = s.transformGeometry(rot)
if i != 0:
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = tooth_rot.Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi.append(tooth_rot)
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = wi[0].Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
return(Wire(wi))
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def helicalextrusion(wire, height, angle, double_helix = False):
direction = bool(angle < 0)
if double_helix:
first_spine = makeHelix(height * 2. * np.pi / abs(angle), 0.5 * height, 10., 0, direction)
first_solid = first_spine.makePipeShell([wire], True, True)
second_solid = first_solid.mirror(fcvec([0.,0.,0.]), fcvec([0,0,1]))
faces = first_solid.Faces + second_solid.Faces
faces = [f for f in faces if not on_mirror_plane(f, 0., fcvec([0., 0., 1.]))]
solid = makeSolid(makeShell(faces))
mat = App.Matrix()
mat.move(fcvec([0, 0, 0.5 * height]))
return solid.transformGeometry(mat)
else:
first_spine = makeHelix(height * 2 * np.pi / abs(angle), height, 10., 0, direction)
first_solid = first_spine.makePipeShell([wire], True, True)
return first_solid
def make_face(edge1, edge2):
v1, v2 = edge1.Vertexes
v3, v4 = edge2.Vertexes
e1 = Wire(edge1)
e2 = Line(v1.Point, v3.Point).toShape().Edges[0]
e3 = edge2
e4 = Line(v4.Point, v2.Point).toShape().Edges[0]
w = Wire([e3, e4, e1, e2])
return(Face(w))
def makeBSplineWire(pts):
wi = []
for i in pts:
out = BSplineCurve()
out.interpolate(list(map(fcvec, i)))
wi.append(out.toShape())
return Wire(wi)
def on_mirror_plane(face, z, direction, small_size=0.000001):
# the tolerance is very high. Maybe there is a bug in Part.makeHelix.
return (face.normalAt(0, 0).cross(direction).Length < small_size and
abs(face.CenterOfMass.z - z) < small_size)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -18,31 +18,43 @@
#* * #* *
#*************************************************************************** #***************************************************************************
import os
import FreeCADGui as Gui import FreeCADGui as Gui
import FreeCAD import FreeCAD as App
import gear_rc __dirname__ = os.path.dirname(__file__)
try:
from FreeCADGui import Workbench
except ImportError as e:
App.Console.PrintWarning("you are using the GearWorkbench with an old version of FreeCAD (<0.16)")
App.Console.PrintWarning("the class Workbench is loaded, although not imported: magic")
class gearWorkbench(Workbench): class gearWorkbench(Workbench):
"""glider workbench""" """glider workbench"""
MenuText = "gear" MenuText = "Gear"
ToolTip = "gear workbench" ToolTip = "Gear Workbench"
Icon = "gearworkbench.svg" Icon = os.path.join(__dirname__, 'icons', 'gearworkbench.svg')
commands = [
"CreateInvoluteGear",
"CreateInvoluteRack",
"CreateCycloideGear",
"CreateBevelGear",
"CreateCrownGear"]
def GetClassName(self): def GetClassName(self):
return "Gui::PythonWorkbench" return "Gui::PythonWorkbench"
def Initialize(self): def Initialize(self):
from .commands import CreateCycloideGear, CreateInvoluteGear
from gearfunc import CreateCycloideGear, CreateInvoluteGear, CreateBevelGear, CreateInvoluteRack from .commands import CreateBevelGear, CreateInvoluteRack, CreateCrownGear
self.appendToolbar("Gear", self.commands)
self.appendToolbar("Gear", ["CreateInvoluteGear", "CreateInvoluteRack", "CreateCycloideGear", "CreateBevelGear"]) self.appendMenu("Gear", self.commands)
self.appendMenu("Gear", ["CreateInvoluteGear", "CreateInvoluteRack", "CreateCycloideGear","CreateBevelGear"]) Gui.addIconPath(App.getHomePath()+"Mod/gear/icons/")
Gui.addIconPath(FreeCAD.getHomePath()+"Mod/gear/icons/")
Gui.addCommand('CreateInvoluteGear', CreateInvoluteGear()) Gui.addCommand('CreateInvoluteGear', CreateInvoluteGear())
Gui.addCommand('CreateCycloideGear', CreateCycloideGear()) Gui.addCommand('CreateCycloideGear', CreateCycloideGear())
Gui.addCommand('CreateBevelGear', CreateBevelGear()) Gui.addCommand('CreateBevelGear', CreateBevelGear())
Gui.addCommand('CreateInvoluteRack', CreateInvoluteRack()) Gui.addCommand('CreateInvoluteRack', CreateInvoluteRack())
Gui.addCommand('CreateCrownGear', CreateCrownGear())
def Activated(self): def Activated(self):
pass pass

View File

@@ -1,9 +0,0 @@
<RCC>
<qresource>
<file>icons/gearworkbench.svg</file>
<file>icons/involutegear.svg</file>
<file>icons/cycloidegear.svg</file>
<file>icons/involuterack.svg</file>
<file>icons/bevelgear.svg</file>
</qresource>
</RCC>

View File

@@ -1,7 +0,0 @@
<RCC>
<qresource>
<file>icons/gearworkbench.svg</file>
<file>icons/involutegear.svg</file>
<file>icons/cycloidegear.svg</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,20 +0,0 @@
#!/usr/lib/python
from gearfunc._involute_tooth import involute_rack, involute_tooth
from gearfunc._cycloide_tooth import cycloide_tooth
from gearfunc._bevel_tooth import bevel_tooth
from gearfunc import CreateInvoluteRack, CreateCycloideGear, CreateInvoluteGear, CreateBevelGear
from tests import bspline_surf
__All__ = [
"CreateInvoluteRack",
"CreateCycloideGear",
"CreateInvoluteGear",
"CreateBevelGear",
"involute_rack",
"involute_tooth",
"bevel_tooth"
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,445 +0,0 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 *
#* *
#***************************************************************************
from __future__ import division
import FreeCAD as App
from _involute_tooth import involute_tooth, involute_rack
from _cycloide_tooth import cycloide_tooth
from _bevel_tooth import bevel_tooth
from Part import BSplineCurve, Shape, Wire, Face, makePolygon, \
BRepOffsetAPI, Shell, makeLoft, Solid, Line, BSplineSurface, Compound,\
show, makePolygon, makeLoft, makeHelix
import Part
from _functions import rotation3D
from numpy import pi, cos, sin, tan
import numpy
def fcvec(x):
if len(x) == 2:
return(App.Vector(x[0], x[1], 0))
else:
return(App.Vector(x[0], x[1], x[2]))
class involute_gear():
"""FreeCAD gear"""
def __init__(self, obj):
self.involute_tooth = involute_tooth()
obj.addProperty(
"App::PropertyBool", "simple", "gear_parameter", "simple")
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyBool", "undercut", "gear_parameter", "undercut")
obj.addProperty(
"App::PropertyFloat", "shift", "gear_parameter", "shift")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyAngle", "alpha", "involute_parameter", "alpha")
obj.addProperty(
"App::PropertyFloat", "clearence", "gear_parameter", "clearence")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty(
"App::PropertyAngle", "beta", "gear_parameter", "beta ")
obj.addProperty(
"App::PropertyLength", "backlash", "gear_parameter", "backlash in mm")
obj.addProperty("App::PropertyPythonObject", "gear", "test", "test")
obj.gear = self.involute_tooth
obj.simple = False
obj.undercut = False
obj.teeth = 15
obj.module = '1. mm'
obj.shift = 0.
obj.alpha = '20. deg'
obj.beta = '0. deg'
obj.height = '5. mm'
obj.clearence = 0.25
obj.numpoints = 6
obj.backlash = '0.00 mm'
self.obj = obj
obj.Proxy = self
def execute(self, fp):
fp.gear.m_n = fp.module.Value
fp.gear.z = fp.teeth
fp.gear.undercut = fp.undercut
fp.gear.shift = fp.shift
fp.gear.alpha = fp.alpha.Value * pi / 180.
fp.gear.beta = fp.beta.Value * pi / 180
fp.gear.clearence = fp.clearence
fp.gear.backlash = fp.backlash.Value
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
if not fp.simple:
wi = []
for i in pts:
out = BSplineCurve()
out.interpolate(map(fcvec, i))
wi.append(out)
s = Wire(Shape(wi).Edges)
wi = []
for i in range(fp.gear.z):
rot = App.Matrix()
rot.rotateZ(-i * fp.gear.phipart)
tooth_rot = s.transformGeometry(rot)
if i != 0:
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = tooth_rot.Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi.append(tooth_rot)
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = wi[0].Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi = Wire(wi)
fp.Shape = wi
if fp.beta.Value == 0:
sh = Face(wi)
fp.Shape = sh.extrude(App.Vector(0, 0, fp.height.Value))
else:
fp.Shape = helicalextrusion(
wi, fp.height.Value, fp.height.Value * tan(fp.gear.beta) * 2 / fp.gear.d)
else:
rw = fp.gear.dw / 2
circle = Part.Circle(App.Vector(0, 0, 0), App.Vector(0, 0, 1), rw)
wire = Part.Wire(circle.toShape())
face = Part.Face(wire)
fp.Shape = face.extrude(App.Vector(0, 0, fp.height.Value))
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class involute_gear_rack():
"""FreeCAD gear rack"""
def __init__(self, obj):
self.involute_rack = involute_rack()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyLength", "thickness", "gear_parameter", "thickness")
obj.addProperty(
"App::PropertyAngle", "alpha", "involute_parameter", "alpha")
obj.addProperty("App::PropertyPythonObject", "rack", "test", "test")
obj.rack = self.involute_rack
obj.teeth = 15
obj.module = '1. mm'
obj.alpha = '20. deg'
obj.height = '5. mm'
obj.thickness = '5 mm'
self.obj = obj
obj.Proxy = self
def execute(self, fp):
fp.rack.m = fp.module.Value
fp.rack.z = fp.teeth
fp.rack.alpha = fp.alpha.Value * pi / 180.
fp.rack.thickness = fp.thickness.Value
fp.rack._update()
pts = fp.rack.points()
pol = Wire(makePolygon(map(fcvec, pts)))
fp.Shape = Face(Wire(pol)).extrude(fcvec([0., 0., fp.height]))
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class cycloide_gear():
"""FreeCAD gear"""
def __init__(self, obj):
self.cycloide_tooth = cycloide_tooth()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "module", "gear_parameter", "module")
obj.addProperty(
"App::PropertyLength", "inner_diameter", "cycloid_parameter", "inner_diameter")
obj.addProperty(
"App::PropertyLength", "outer_diameter", "cycloid_parameter", "outer_diameter")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyFloat", "clearence", "gear_parameter", "clearence")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty("App::PropertyAngle", "beta", "gear_parameter", "beta")
obj.addProperty(
"App::PropertyLength", "backlash", "gear_parameter", "backlash in mm")
obj.addProperty("App::PropertyPythonObject", "gear", "test", "test")
obj.gear = self.cycloide_tooth
obj.teeth = 15
obj.module = '1. mm'
obj.inner_diameter = '5 mm'
obj.outer_diameter = '5 mm'
obj.beta = '0. deg'
obj.height = '5. mm'
obj.clearence = 0.25
obj.numpoints = 15
obj.backlash = '0.00 mm'
obj.Proxy = self
def execute(self, fp):
pass
fp.gear.m = fp.module.Value
fp.gear.z = fp.teeth
fp.gear.z1 = fp.inner_diameter.Value
fp.gear.z2 = fp.outer_diameter.Value
fp.gear.clearence = fp.clearence
fp.gear.backlash = fp.backlash.Value
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
wi = []
for i in pts:
out = BSplineCurve()
out.interpolate(map(fcvec, i))
wi.append(out)
s = Wire(Shape(wi).Edges)
wi = []
for i in range(fp.gear.z):
rot = App.Matrix()
rot.rotateZ(-i * fp.gear.phipart)
tooth_rot = s.transformGeometry(rot)
if i != 0:
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = tooth_rot.Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi.append(tooth_rot)
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = wi[0].Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi = Wire(wi)
if fp.beta.Value == 0:
sh = Face(wi)
fp.Shape = sh.extrude(App.Vector(0, 0, fp.height.Value))
else:
pass
fp.Shape = helicalextrusion(
wi, fp.height.Value, fp.height.Value * tan(fp.beta.Value * pi / 180) * 2 / fp.gear.d)
def __getstate__(self):
return None
def __setstate__(self, state):
return None
class bevel_gear():
"""parameters:
alpha: pressureangle, 10-30°
gamma: cone angle, 0 < gamma < pi/4
"""
def __init__(self, obj):
self.bevel_tooth = bevel_tooth()
obj.addProperty("App::PropertyInteger",
"teeth", "gear_parameter", "number of teeth")
obj.addProperty(
"App::PropertyLength", "height", "gear_parameter", "height")
obj.addProperty(
"App::PropertyAngle", "gamma", "involute_parameter", "gamma")
obj.addProperty(
"App::PropertyAngle", "alpha", "involute_parameter", "alpha")
obj.addProperty("App::PropertyLength", "m", "gear_parameter", "m")
obj.addProperty(
"App::PropertyFloat", "clearence", "gear_parameter", "clearence")
obj.addProperty("App::PropertyInteger", "numpoints",
"gear_parameter", "number of points for spline")
obj.addProperty(
"App::PropertyLength", "backlash", "gear_parameter", "backlash in mm")
obj.addProperty("App::PropertyPythonObject", "gear", "test", "test")
obj.gear = self.bevel_tooth
obj.m = '1. mm'
obj.teeth = 15
obj.alpha = '70. deg'
obj.gamma = '45. deg'
obj.height = '5. mm'
obj.numpoints = 6
obj.backlash = '0.00 mm'
obj.clearence = 0.1
self.obj = obj
obj.Proxy = self
def execute1(self, fp):
fp.gear.z = fp.teeth
fp.gear.alpha = fp.alpha.Value * pi / 180.
fp.gear.gamma = fp.gamma.Value * pi / 180
fp.gear.backlash = fp.backlash
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
tooth = self.create_tooth()
teeth = [tooth]
rot = App.Matrix()
rot.rotateZ(2 * pi / fp.teeth)
top_cap = [i.Edges[0] for i in tooth.Faces]
bottom_cap = [i.Edges[3] for i in tooth.Faces]
for i in range(fp.teeth - 1):
new_tooth = teeth[-1].transformGeometry(rot)
edge1 = new_tooth.Faces[0].Edges[2]
edge2 = teeth[-1].Faces[-1].Edges[1]
face1 = make_face(edge1, edge2)
teeth.append(face1)
teeth.append(new_tooth)
top_cap.append(face1.Edges[3])
bottom_cap.append(face1.Edges[1])
top_cap += [i.Edges[0] for i in new_tooth.Faces]
bottom_cap += [i.Edges[3] for i in new_tooth.Faces]
edge1 = teeth[0].Faces[0].Edges[2]
edge2 = teeth[-1].Faces[-1].Edges[1]
face1 = make_face(edge1, edge2)
teeth.append(face1)
top_cap.append(face1.Edges[3])
bottom_cap.append(face1.Edges[1])
top_cap = Face(Wire(top_cap))
bottom_cap = Face(Wire(bottom_cap))
fcs = Compound(teeth).Faces
top_cap.reverse()
fp.Shape = Solid(Shell(fcs + [top_cap, bottom_cap]))
def execute(self, fp):
fp.gear.z = fp.teeth
fp.gear.module = fp.m.Value
fp.gear.alpha = fp.alpha.Value * pi / 180.
fp.gear.gamma = fp.gamma.Value * pi / 180
fp.gear.backlash = fp.backlash.Value
fp.gear.clearence = fp.clearence
fp.gear._update()
pts = fp.gear.points(num=fp.numpoints)
scal1 = fp.m.Value * fp.gear.z / 2 / tan(
fp.gamma.Value * pi / 180) - fp.height.Value / 2
scal2 = fp.m.Value * fp.gear.z / 2 / tan(
fp.gamma.Value * pi / 180) + fp.height.Value / 2
fp.Shape = makeLoft([self.createteeths(pts, scal1, fp.teeth), self.createteeths(pts, scal2, fp.teeth)], True)
# fp.Shape = self.createteeths(pts, pos1, fp.teeth)
def create_tooth(self):
w = []
scal1 = self.obj.m.Value * self.obj.gear.z / 2 / tan(
self.obj.gamma.Value * pi / 180) - self.obj.height.Value / 2
scal2 = self.obj.m.Value * self.obj.gear.z / 2 / tan(
self.obj.gamma.Value * pi / 180) + self.obj.height.Value / 2
s = [scal1, scal2]
pts = self.obj.gear.points(num=self.obj.numpoints)
for j, pos in enumerate(s):
w1 = []
scale = lambda x: fcvec(x * pos)
for i in pts:
i_scale = map(scale, i)
w1.append(i_scale)
w.append(w1)
surfs = []
w_t = zip(*w)
for i in w_t:
b = BSplineSurface()
b.interpolate(i)
surfs.append(b)
return Shape(surfs)
def createteeths(self, pts, pos, teeth):
w1 = []
for i in pts:
scale = lambda x: x * pos
i_scale = map(scale, i)
out = BSplineCurve()
out.interpolate(map(fcvec, i_scale))
w1.append(out)
s = Wire(Shape(w1).Edges)
wi = []
for i in range(teeth):
rot = App.Matrix()
rot.rotateZ(2 * i * pi / teeth)
tooth_rot = s.transformGeometry(rot)
if i != 0:
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = tooth_rot.Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
wi.append(tooth_rot)
pt_0 = wi[-1].Edges[-1].Vertexes[0].Point
pt_1 = wi[0].Edges[0].Vertexes[-1].Point
wi.append(Wire([Line(pt_0, pt_1).toShape()]))
return(Wire(wi))
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def helicalextrusion(wire, height, angle):
face_a = Face(wire)
face_b = face_a.copy()
face_transform = App.Matrix()
face_transform.rotateZ(angle)
face_transform.move(App.Vector(0, 0, height))
face_b . transformShape(face_transform)
spine = Wire(Line(fcvec([0., 0, 0]), fcvec([0, 0, height])).toShape())
auxspine = makeHelix(height * 2 * pi / angle, height, 1.)
faces = [face_a, face_b]
pipeshell = BRepOffsetAPI.MakePipeShell(spine)
pipeshell.setSpineSupport(spine)
pipeshell.add(wire)
pipeshell.setAuxiliarySpine(auxspine, True, False)
assert(pipeshell.isReady())
pipeshell.build()
faces.extend(pipeshell.shape().Faces)
fullshell = Shell(faces)
solid = Solid(fullshell)
if solid.Volume < 0:
solid.reverse()
assert(solid.Volume >= 0)
return(solid)
def make_face(edge1, edge2):
v1, v2 = edge1.Vertexes
v3, v4 = edge2.Vertexes
e1 = Wire(edge1)
e2 = Line(v1.Point, v3.Point).toShape().Edges[0]
e3 = edge2
e4 = Line(v4.Point, v2.Point).toShape().Edges[0]
w = Wire([e3, e4, e1, e2])
return(Face(w))

View File

@@ -1,108 +0,0 @@
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 FreeCAD
import FreeCADGui as Gui
from _Classes import involute_gear, cycloide_gear, bevel_gear, involute_gear_rack
class CreateInvoluteGear():
"""create an involute gear"""
def __init__(self):
pass
def GetResources(self):
return {'Pixmap': 'involutegear.svg', 'MenuText': 'involute gear', 'ToolTip': 'involute gear'}
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
def Activated(self):
a = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "involute_gear")
involute_gear(a)
a.ViewObject.Proxy = 0.
FreeCAD.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")
class CreateInvoluteRack():
def __init__(self):
pass
def GetResources(self):
return {'Pixmap': 'involuterack.svg', 'MenuText': 'involute rack', 'ToolTip': 'involute rack'}
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
def Activated(self):
a = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "involute_rack")
involute_gear_rack(a)
a.ViewObject.Proxy = 0.
FreeCAD.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")
class CreateCycloideGear():
def __init__(self):
pass
def GetResources(self):
return {'Pixmap': 'cycloidegear.svg', 'MenuText': 'cycloide gear', 'ToolTip': 'cycloide gear'}
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
def Activated(self):
a = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "cycloide_gear")
cycloide_gear(a)
a.ViewObject.Proxy = 0.
FreeCAD.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")
class CreateBevelGear():
def __init__(self):
pass
def GetResources(self):
return {'Pixmap': 'bevelgear.svg', 'MenuText': 'bevel gear', 'ToolTip': 'bevel gear'}
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
def Activated(self):
a = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "bevel_gear")
bevel_gear(a)
a.ViewObject.Proxy = 0.
FreeCAD.ActiveDocument.recompute()
Gui.SendMsgToActiveView("ViewFit")

View File

@@ -1,168 +0,0 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 *
#* *
#***************************************************************************
from __future__ import division
from __future__ import division
from numpy import cos, sin, tan, arccos, arctan, pi, array, linspace, transpose, vstack, sqrt
from _functions import rotation3D, reflection3D
class bevel_tooth(object):
def __init__(self, alpha=70 * pi / 180, gamma=pi / 4, clearence=0.1,
z=21, backlash=0.00, module=0.25):
self.alpha = alpha
self.gamma = gamma
self.z = z
self.clearence = clearence
self.backlash = backlash
self.module = module
self.involute_end = arccos(
1 / sqrt(2) * sqrt((42. + 16.*cos(2.*self.alpha) +
6.*cos(4.*self.alpha) + cos(4.*self.alpha - 4.*self.gamma) - 8.*cos(2.*self.alpha - 2.*self.gamma) -
4.*cos(4.*self.alpha - 2.*self.gamma) + 24.*cos(2.*self.gamma) - 2.*cos(4.*self.gamma) -
8.*cos(2.*(self.alpha + self.gamma)) + cos(4.*(self.alpha + self.gamma)) -
4.*cos(4.*self.alpha + 2.*self.gamma) + 24.*cos((4.*sin(self.gamma))/self.z) +
4.*cos(2.*self.alpha - (4.*sin(self.gamma))/self.z) + 4.*cos(2.*self.alpha -
4.*self.gamma - (4.*sin(self.gamma))/self.z) - 8.*cos(2.*self.alpha - 2.*self.gamma -
(4.*sin(self.gamma))/self.z) + 24.*cos(4.*(self.gamma + sin(self.gamma)/self.z)) -
8.*cos(2.*(self.alpha + self.gamma + (2.*sin(self.gamma))/self.z)) + 4.*cos(2.*self.alpha +
(4.*sin(self.gamma))/self.z) + 16.*cos(2.*self.gamma + (4.*sin(self.gamma))/self.z) +
4.*cos(2.*self.alpha + 4.*self.gamma + (4.*sin(self.gamma))/self.z) + 32.*abs(cos(self.gamma +
(2.*sin(self.gamma))/self.z))*cos(self.alpha)*sqrt(4.*cos(2.*self.alpha) -
2.*(-2. + cos(2.*self.alpha - 2.*self.gamma) - 2.*cos(2.*self.gamma) + cos(2.*(self.alpha + self.gamma)) +
4.*cos(2.*self.gamma + (4.*sin(self.gamma))/self.z)))*sin(2.*self.gamma))/(-6. - 2.*cos(2.*self.alpha) +
cos(2.*self.alpha - 2.*self.gamma) - 2.*cos(2.*self.gamma) + cos(2.*(self.alpha + self.gamma)))**2))
self.involute_start = -pi/2. + \
arctan(1/tan(self.gamma)*1/cos(self.alpha))
self.involute_start_radius = self.getradius(self.involute_start)
self.r_f = sin(self.gamma - sin(gamma) * 2 / self.z) - self.clearence * sin(self.gamma)
self.z_f = cos(self.gamma - sin(gamma) * 2 / self.z)
self.add_foot = True
if self.involute_start_radius < self.r_f:
self.add_foot = False
self.involute_start = -arccos(
sqrt((42 + 16*cos(2*self.alpha) + 6*cos(4*self.alpha) -
4*cos(4*self.alpha - 2*self.gamma) - 8*cos(2*(self.alpha - self.gamma)) +
cos(4*(self.alpha - self.gamma)) + 24*cos(2*self.gamma) - 2*cos(4*self.gamma) -
8*cos(2*(self.alpha + self.gamma)) + cos(4*(self.alpha + self.gamma)) -
4*cos(2*(2*self.alpha + self.gamma)) + 24*cos((4*sin(self.gamma))/self.z) +
4*cos(2*self.alpha - (4*sin(self.gamma))/self.z) + 16*cos(2*self.gamma -
(4*sin(self.gamma))/self.z) + 24*cos(4*self.gamma - (4*sin(self.gamma))/self.z) +
4*cos(2*self.alpha + 4*self.gamma - (4*sin(self.gamma))/self.z) -
8*cos(2*(self.alpha + self.gamma - (2*sin(self.gamma))/self.z)) +
4*cos(2*self.alpha + (4*sin(self.gamma))/self.z) + 4*cos(2*self.alpha -
4*self.gamma + (4*sin(self.gamma))/self.z) - 8*cos(2*self.alpha - 2*self.gamma +
(4*sin(self.gamma))/self.z) + 32*sqrt(2)*sqrt(-(cos(self.alpha)**2*
(-2 - 2*cos(2*self.alpha) + cos(2*(self.alpha - self.gamma)) -
2*cos(2*self.gamma) + cos(2*(self.alpha + self.gamma)) +
4*cos(2*self.gamma - (4*sin(self.gamma))/self.z))*cos(self.gamma - (2*sin(self.gamma))/self.z)**2*
sin(2*self.gamma)**2)))/(-6 - 2*cos(2*self.alpha) + cos(2*(self.alpha - self.gamma)) -
2*cos(2*self.gamma) + cos(2*(self.alpha + self.gamma)))**2)/sqrt(2))
def involute_function_x(self):
def func(s):
return((
-(cos(s*1/sin(self.alpha)*1/sin(self.gamma))*sin(self.alpha)*sin(s)) +
(cos(s)*sin(self.gamma) + cos(self.alpha)*cos(self.gamma)*sin(s))*
sin(s*1/sin(self.alpha)*1/sin(self.gamma))))
return(func)
def involute_function_y(self):
def func(s):
return((
cos(s*1/sin(self.alpha)*1/sin(self.gamma))*(cos(s)*sin(self.gamma) +
cos(self.alpha)*cos(self.gamma)*sin(s)) + sin(self.alpha)*sin(s)*
sin(s*1/sin(self.alpha)*1/sin(self.gamma))))
return(func)
def involute_function_z(self):
def func(s):
return((
cos(self.gamma)*cos(s) - cos(self.alpha)*sin(self.gamma)*sin(s)))
return(func)
def getradius(self, s):
x = self.involute_function_x()
y = self.involute_function_y()
rx = x(s)
ry = y(s)
return(sqrt(rx**2 + ry**2))
def involute_points(self, num=10):
pts = linspace(self.involute_start, self.involute_end, num=num)
fx = self.involute_function_x()
x = array(map(fx, pts))
fy = self.involute_function_y()
y = array(map(fy, pts))
fz = self.involute_function_z()
z = array(map(fz, pts))
xyz = transpose(array([x, y,z]))
if self.add_foot:
p = xyz[0]
p1 =map(lambda x: x * (self.r_f / sqrt(p[0]**2 + p[1]**2)), p)
p1[2] = self.z_f
xyz=vstack([[p1], xyz])
xy = [[i[0]/i[2],i[1]/i[2],1.] for i in xyz]
backlash_rot = rotation3D(self.backlash / 4)
xy = backlash_rot(xy)
return(xy)
def points(self, num=10):
pts = self.involute_points(num = num)
rot = rotation3D(-pi/self.z/2)
pts = rot(pts)
ref = reflection3D(pi/2)
pts1 = ref(pts)[::-1]
rot = rotation3D(2*pi/self.z)
pt3 = rot(pts[0])
if self.add_foot:
return(array([
[pts[0],pts[1]],
pts[1:],
[pts[-1], pts1[0]],
pts1[:-1],
[pts1[-2], pts1[-1]]
]))
return(array([pts,[pts[-1],pts1[0]], pts1]))
else:
return(array([pts,[pts[-1],pts1[0]], pts1]))
def _update(self):
self.__init__(z = self.z, clearence = self.clearence,
alpha = self.alpha, gamma = self.gamma, backlash = self.backlash, module = self.module)
if __name__ == "__main__":
from matplotlib import pyplot
gear = bevel_tooth()
x = []
y = []
for i in gear.points(30):
for j in i:
x.append(j[0])
y.append(j[1])
pyplot.plot(x,y)
pyplot.show()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

1
pygears/__init__.py Normal file
View File

@@ -0,0 +1 @@
__version__ = "0.01"

View File

@@ -22,28 +22,30 @@
from __future__ import division from __future__ import division
from numpy import sin, cos, dot, array, ndarray, vstack, transpose, sqrt from numpy import sin, cos, dot, array, ndarray, vstack, transpose, sqrt
from numpy.linalg import solve from numpy.linalg import solve
import numpy as np
def reflection(alpha): def reflection(pressure_angle):
mat = array( mat = array(
[[cos(2 * alpha), -sin(2 * alpha)], [-sin(2 * alpha), -cos(2 * alpha)]]) [[cos(2 * pressure_angle), -sin(2 * pressure_angle)], [-sin(2 * pressure_angle), -cos(2 * pressure_angle)]])
def func(x): def func(x):
return(dot(x, mat)) return(dot(x, mat))
return(func) return(func)
def reflection3D(alpha): def reflection3D(pressure_angle):
mat = array([[cos(2 * alpha), -sin(2 * alpha), 0.], mat = array([[cos(2 * pressure_angle), -sin(2 * pressure_angle), 0.],
[-sin(2 * alpha), -cos(2 * alpha), 0.], [0., 0., 1.]]) [-sin(2 * pressure_angle), -cos(2 * pressure_angle), 0.], [0., 0., 1.]])
def func(x): def func(x):
return(dot(x, mat)) return(dot(x, mat))
return(func) return(func)
def rotation(alpha, midpoint=[0, 0]): def rotation(pressure_angle, midpoint=None):
mat = array([[cos(alpha), -sin(alpha)], [sin(alpha), cos(alpha)]]) midpoint = midpoint or [0., 0.]
mat = array([[cos(pressure_angle), -sin(pressure_angle)], [sin(pressure_angle), cos(pressure_angle)]])
midpoint = array(midpoint) midpoint = array(midpoint)
vec = midpoint - dot(midpoint, mat) vec = midpoint - dot(midpoint, mat)
trans = translation(vec) trans = translation(vec)
@@ -53,11 +55,11 @@ def rotation(alpha, midpoint=[0, 0]):
return(func) return(func)
def rotation3D(alpha): def rotation3D(pressure_angle):
mat = array( mat = array(
[ [
[cos(alpha), -sin(alpha), 0.], [cos(pressure_angle), -sin(pressure_angle), 0.],
[sin(alpha), cos(alpha), 0.], [sin(pressure_angle), cos(pressure_angle), 0.],
[0., 0., 1.]]) [0., 0., 1.]])
def func(xx): def func(xx):
@@ -70,7 +72,7 @@ def translation(vec):
return([x[0] + vec[0], x[1] + vec[1]]) return([x[0] + vec[0], x[1] + vec[1]])
def func(x): def func(x):
return(array(map(trans, x))) return(array(list(map(trans, x))))
return(func) return(func)
@@ -98,8 +100,8 @@ def trim(p1, p2, p3, p4):
return(p2) return(p2)
try: try:
g, h = solve(transpose([-a2 + a1, a4 - a3]), a1 - a3) g, h = solve(transpose([-a2 + a1, a4 - a3]), a1 - a3)
except: except Exception as e:
print(Exception) print(e)
return(False) return(False)
else: else:
if 0. < g < 1. and 0. < h < 1.: if 0. < g < 1. and 0. < h < 1.:
@@ -136,10 +138,7 @@ def trimfunc(l1, l2):
def norm(vec1, vec2): def norm(vec1, vec2):
vec = array(vec2) - array(vec1) vec = array(vec2) - array(vec1)
out = 0 return np.linalg.norm(vec)
for i in vec:
out += i ** 2
return(sqrt(out))
def nearestpts(evolv, underc): def nearestpts(evolv, underc):
@@ -160,3 +159,15 @@ def nearestpts(evolv, underc):
jk += 1 jk += 1
ik += 1 ik += 1
return([vstack([underc[:jout], evolv[iout]]), evolv[iout:]]) return([vstack([underc[:jout], evolv[iout]]), evolv[iout:]])
def intersection_line_circle(p1, p2, r):
"""return the intersection point of a line from p1 to p2 and a sphere of radius 1 and
midpoint 0,0,0"""
d = p2 - p1
d /= np.linalg.norm(d)
p_half = d.dot(p1)
q = p1.dot(p1) - r ** 2
t = -p_half + sqrt(p_half ** 2 - q)
return p1 + d * t

169
pygears/bevel_tooth.py Normal file
View File

@@ -0,0 +1,169 @@
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library 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 *
#* *
#***************************************************************************
from __future__ import division
from __future__ import division
from numpy import cos, sin, tan, arccos, arctan, pi, array, linspace, transpose, vstack, sqrt
import numpy as np
from ._functions import rotation3D, reflection3D, intersection_line_circle
class bevel_tooth(object):
def __init__(self, pressure_angle=70 * pi / 180, pitch_angle=pi / 4, clearance=0.1,
z=21, backlash=0.00, module=0.25):
self.pressure_angle = pressure_angle
self.pitch_angle = pitch_angle
self.z = z
self.clearance = clearance
self.backlash = backlash
self.module = module
self.involute_end = arccos(
1 / sqrt(2) * sqrt((42. + 16.*cos(2.*self.pressure_angle) +
6.*cos(4.*self.pressure_angle) + cos(4.*self.pressure_angle - 4.*self.pitch_angle) - 8.*cos(2.*self.pressure_angle - 2.*self.pitch_angle) -
4.*cos(4.*self.pressure_angle - 2.*self.pitch_angle) + 24.*cos(2.*self.pitch_angle) - 2.*cos(4.*self.pitch_angle) -
8.*cos(2.*(self.pressure_angle + self.pitch_angle)) + cos(4.*(self.pressure_angle + self.pitch_angle)) -
4.*cos(4.*self.pressure_angle + 2.*self.pitch_angle) + 24.*cos((4.*sin(self.pitch_angle))/self.z) +
4.*cos(2.*self.pressure_angle - (4.*sin(self.pitch_angle))/self.z) + 4.*cos(2.*self.pressure_angle -
4.*self.pitch_angle - (4.*sin(self.pitch_angle))/self.z) - 8.*cos(2.*self.pressure_angle - 2.*self.pitch_angle -
(4.*sin(self.pitch_angle))/self.z) + 24.*cos(4.*(self.pitch_angle + sin(self.pitch_angle)/self.z)) -
8.*cos(2.*(self.pressure_angle + self.pitch_angle + (2.*sin(self.pitch_angle))/self.z)) + 4.*cos(2.*self.pressure_angle +
(4.*sin(self.pitch_angle))/self.z) + 16.*cos(2.*self.pitch_angle + (4.*sin(self.pitch_angle))/self.z) +
4.*cos(2.*self.pressure_angle + 4.*self.pitch_angle + (4.*sin(self.pitch_angle))/self.z) + 32.*abs(cos(self.pitch_angle +
(2.*sin(self.pitch_angle))/self.z))*cos(self.pressure_angle)*sqrt(4.*cos(2.*self.pressure_angle) -
2.*(-2. + cos(2.*self.pressure_angle - 2.*self.pitch_angle) - 2.*cos(2.*self.pitch_angle) + cos(2.*(self.pressure_angle + self.pitch_angle)) +
4.*cos(2.*self.pitch_angle + (4.*sin(self.pitch_angle))/self.z)))*sin(2.*self.pitch_angle))/(-6. - 2.*cos(2.*self.pressure_angle) +
cos(2.*self.pressure_angle - 2.*self.pitch_angle) - 2.*cos(2.*self.pitch_angle) + cos(2.*(self.pressure_angle + self.pitch_angle)))**2))
self.involute_start = -pi/2. + arctan(1/tan(self.pitch_angle)*1/cos(self.pressure_angle))
self.involute_start_radius = self.get_radius(self.involute_start)
self.r_f = sin(self.pitch_angle - sin(pitch_angle) * 2 / self.z) - self.clearance * sin(self.pitch_angle)
self.z_f = cos(self.pitch_angle - sin(pitch_angle) * 2 / self.z)
self.add_foot = True
# if self.involute_start_radius < self.r_f:
# self.add_foot = False
# self.involute_start = -arccos(
# sqrt((42 + 16*cos(2*self.pressure_angle) + 6*cos(4*self.pressure_angle) -
# 4*cos(4*self.pressure_angle - 2*self.pitch_angle) - 8*cos(2*(self.pressure_angle - self.pitch_angle)) +
# cos(4*(self.pressure_angle - self.pitch_angle)) + 24*cos(2*self.pitch_angle) - 2*cos(4*self.pitch_angle) -
# 8*cos(2*(self.pressure_angle + self.pitch_angle)) + cos(4*(self.pressure_angle + self.pitch_angle)) -
# 4*cos(2*(2*self.pressure_angle + self.pitch_angle)) + 24*cos((4*sin(self.pitch_angle))/self.z) +
# 4*cos(2*self.pressure_angle - (4*sin(self.pitch_angle))/self.z) + 16*cos(2*self.pitch_angle -
# (4*sin(self.pitch_angle))/self.z) + 24*cos(4*self.pitch_angle - (4*sin(self.pitch_angle))/self.z) +
# 4*cos(2*self.pressure_angle + 4*self.pitch_angle - (4*sin(self.pitch_angle))/self.z) -
# 8*cos(2*(self.pressure_angle + self.pitch_angle - (2*sin(self.pitch_angle))/self.z)) +
# 4*cos(2*self.pressure_angle + (4*sin(self.pitch_angle))/self.z) + 4*cos(2*self.pressure_angle -
# 4*self.pitch_angle + (4*sin(self.pitch_angle))/self.z) - 8*cos(2*self.pressure_angle - 2*self.pitch_angle +
# (4*sin(self.pitch_angle))/self.z) + 32*sqrt(2)*sqrt(-(cos(self.pressure_angle)**2*
# (-2 - 2*cos(2*self.pressure_angle) + cos(2*(self.pressure_angle - self.pitch_angle)) -
# 2*cos(2*self.pitch_angle) + cos(2*(self.pressure_angle + self.pitch_angle)) +
# 4*cos(2*self.pitch_angle - (4*sin(self.pitch_angle))/self.z))*cos(self.pitch_angle - (2*sin(self.pitch_angle))/self.z)**2*
# sin(2*self.pitch_angle)**2)))/(-6 - 2*cos(2*self.pressure_angle) + cos(2*(self.pressure_angle - self.pitch_angle)) -
# 2*cos(2*self.pitch_angle) + cos(2*(self.pressure_angle + self.pitch_angle)))**2)/sqrt(2))
def involute_function_x(self):
def func(s):
return((
-(cos(s*1/sin(self.pressure_angle)*1/sin(self.pitch_angle))*sin(self.pressure_angle)*sin(s)) +
(cos(s)*sin(self.pitch_angle) + cos(self.pressure_angle)*cos(self.pitch_angle)*sin(s))*
sin(s*1/sin(self.pressure_angle)*1/sin(self.pitch_angle))))
return(func)
def involute_function_y(self):
def func(s):
return((
cos(s*1/sin(self.pressure_angle)*1/sin(self.pitch_angle))*(cos(s)*sin(self.pitch_angle) +
cos(self.pressure_angle)*cos(self.pitch_angle)*sin(s)) + sin(self.pressure_angle)*sin(s)*
sin(s*1/sin(self.pressure_angle)*1/sin(self.pitch_angle))))
return(func)
def involute_function_z(self):
def func(s):
return((
cos(self.pitch_angle)*cos(s) - cos(self.pressure_angle)*sin(self.pitch_angle)*sin(s)))
return(func)
def get_radius(self, s):
x = self.involute_function_x()
y = self.involute_function_y()
rx = x(s)
ry = y(s)
return(sqrt(rx**2 + ry**2))
def involute_points(self, num=10):
pts = linspace(self.involute_start, self.involute_end, num=num)
fx = self.involute_function_x()
x = array(list(map(fx, pts)))
fy = self.involute_function_y()
y = array(list(map(fy, pts)))
fz = self.involute_function_z()
z = array(list(map(fz, pts)))
xyz = transpose(array([x, y, z]))
# conical projection to z=1
xy = [[i[0] / i[2], i[1] / i[2]] for i in xyz]
xy = array([[0, 0]] + xy)
r_cut = self.r_f / self.z_f
for i, point in enumerate(xy[1:]):
if point.dot(point) >= r_cut ** 2:
break
if i > 0:
self.add_foot = False
intersection_point = intersection_line_circle(xy[i], point, r_cut)
xy = array([intersection_point] + list(xy[i+1:]))
xyz = [[p[0], p[1], 1] for p in xy]
backlash_rot = rotation3D(self.backlash / 4)
xyz = backlash_rot(xyz)
return(xyz)
def points(self, num=10):
pts = self.involute_points(num=num)
rot = rotation3D(-pi/self.z/2)
pts = rot(pts)
ref = reflection3D(pi/2)
pts1 = ref(pts)[::-1]
rot = rotation3D(2*pi/self.z)
if self.add_foot:
return(array([
array([pts[0], pts[1]]),
pts[1:],
array([pts[-1], pts1[0]]),
pts1[:-1],
array([pts1[-2], pts1[-1]])
]))
else:
return(array([pts, array([pts[-1], pts1[0]]), pts1]))
def _update(self):
self.__init__(z=self.z, clearance=self.clearance,
pressure_angle=self.pressure_angle,
pitch_angle=self.pitch_angle,
backlash=self.backlash, module=self.module)
if __name__ == "__main__":
from matplotlib import pyplot
gear = bevel_tooth(z=60, clearance=0.0, pitch_angle=np.deg2rad(45))
x, y, z = gear.involute_points().T
pyplot.plot(x, y)
pyplot.show()

23
pygears/computation.py Normal file
View File

@@ -0,0 +1,23 @@
import numpy as np
from scipy import optimize as opt
def computeShiftedGears(m, alpha, t1, t2, x1, x2):
"""Summary
Args:
m (float): common module of both gears [length]
alpha (float): pressure-angle [rad]
t1 (int): number of teeth of gear1
t2 (int): number of teeth of gear2
x1 (float): relative profile-shift of gear1
x2 (float): relative profile-shift of gear2
Returns:
(float, float): distance between gears [length], pressure angle of the assembly [rad]
"""
inv = lambda x: np.tan(x) - x
inv_alpha_w = inv(alpha) + 2 * np.tan(alpha) * (x1 + x2) / (t1 + t2)
root_inv = lambda x: inv(x) - inv_alpha_w
alpha_w = opt.fsolve(root_inv, 0.)
dist = m * (t1+ t2) / 2 * np.cos(alpha) / np.cos(alpha_w)
return dist, alpha_w

View File

@@ -19,28 +19,27 @@
#* * #* *
#*************************************************************************** #***************************************************************************
from __future__ import division
from __future__ import division from __future__ import division
from numpy import cos, sin, arccos, pi, array, linspace, transpose, vstack from numpy import cos, sin, arccos, pi, array, linspace, transpose, vstack
from _functions import rotation, reflection from ._functions import rotation, reflection
class cycloide_tooth(): class cycloide_tooth():
def __init__(self, z1 = 5, z2 = 5, z = 14, m = 5, clearence = 0.12, backlash = 0.00): def __init__(self, z1 = 5, z2 = 5, z = 14, m = 5, clearance = 0.12, backlash = 0.00):
self.m = m self.m = m
self.z = z self.z = z
self.clearence = clearence self.clearance = clearance
self.backlash = backlash self.backlash = backlash
self.z1 = z1 self.z1 = z1
self.z2 = z2 self.z2 = z2
self._calc_gear_factors() self._calc_gear_factors()
def _calc_gear_factors(self): def _calc_gear_factors(self):
self.d1 = self.z1 * self.m self.d1 = self.z1 * self.m
self.d2 = self.z2 * self.m self.d2 = self.z2 * self.m
self.phi = self.m * pi self.phi = self.m * pi
self.d = self.z * self.m self.d = self.z * self.m
self.da = self.d + 2*self.m self.da = self.d + 2*self.m
self.di = self.d - 2*self.m - self.clearence * self.m self.di = self.d - 2*self.m - self.clearance * self.m
self.phipart = 2 * pi / self.z self.phipart = 2 * pi / self.z
def epicycloide_x(self): def epicycloide_x(self):
@@ -87,10 +86,10 @@ class cycloide_tooth():
t_outer_end = self.outer_end() t_outer_end = self.outer_end()
t_vals_outer = linspace(0, t_outer_end, num) t_vals_outer = linspace(0, t_outer_end, num)
t_vals_inner = linspace(t_inner_end,0,num) t_vals_inner = linspace(t_inner_end,0,num)
pts_outer_x = map(outer_x, t_vals_outer) pts_outer_x = list(map(outer_x, t_vals_outer))
pts_outer_y = map(outer_y, t_vals_outer) pts_outer_y = list(map(outer_y, t_vals_outer))
pts_inner_x = map(inner_x, t_vals_inner) pts_inner_x = list(map(inner_x, t_vals_inner))
pts_inner_y = map(inner_y, t_vals_inner) pts_inner_y = list(map(inner_y, t_vals_inner))
pts_outer = transpose([pts_outer_x, pts_outer_y]) pts_outer = transpose([pts_outer_x, pts_outer_y])
pts_inner = transpose([pts_inner_x, pts_inner_y]) pts_inner = transpose([pts_inner_x, pts_inner_y])
pts1 = vstack([pts_inner[:-2],pts_outer]) pts1 = vstack([pts_inner[:-2],pts_outer])
@@ -103,7 +102,7 @@ class cycloide_tooth():
def _update(self): def _update(self):
self.__init__(m = self.m, z = self.z, z1 = self.z1, z2 = self.z2, self.__init__(m = self.m, z = self.z, z1 = self.z1, z2 = self.z2,
clearence = self.clearence, backlash = self.backlash) clearance = self.clearance, backlash = self.backlash)
if __name__ == "__main__": if __name__ == "__main__":
from matplotlib import pyplot from matplotlib import pyplot

View File

@@ -21,44 +21,46 @@
from __future__ import division from __future__ import division
from numpy import tan, cos, sin, sqrt, arctan, pi, array, linspace, transpose, vstack, ndarray from numpy import tan, cos, sin, sqrt, arctan, pi, array, linspace, transpose, vstack, ndarray
from _functions import nearestpts, rotation, reflection, trimfunc, norm, translation from ._functions import nearestpts, rotation, reflection, trimfunc, norm, translation
import numpy as np import numpy as np
class involute_tooth(): class involute_tooth():
def __init__(self, m=5, z=15, alpha=20 * pi / 180., clearence=0.12, shift=0.5, beta=0., undercut=False, backlash=0.00): def __init__(self, m=5, z=15, pressure_angle=20 * pi / 180., clearance=0.12, shift=0.5, beta=0.,
self.alpha = alpha undercut=False, backlash=0.00, head=0.00):
self.pressure_angle = pressure_angle
self.beta = beta self.beta = beta
self.m_n = m self.m_n = m
self.z = z self.z = z
self.undercut = undercut self.undercut = undercut
self.shift = shift self.shift = shift
self.clearence = clearence self.clearance = clearance
self.backlash = backlash self.backlash = backlash
self.head = head # factor, rename!!!
self._calc_gear_factors() self._calc_gear_factors()
def _calc_gear_factors(self): def _calc_gear_factors(self):
self.alpha_t = arctan(tan(self.alpha) / cos(self.beta)) self.pressure_angle_t = arctan(tan(self.pressure_angle) / cos(self.beta))
self.m = self.m_n / cos(self.beta) self.m = self.m_n / cos(self.beta)
self.c = self.clearence * self.m_n self.c = self.clearance * self.m_n
self.midpoint = [0., 0.] self.midpoint = [0., 0.]
self.d = self.z * self.m self.d = self.z * self.m
self.dw = self.m * self.z self.dw = self.m * self.z
self.da = self.dw + 2. * self.m_n + 2. * self.shift * self.m_n self.da = self.dw + 2. * self.m_n + 2. * (self.shift + self.head) * self.m_n
self.df = self.dw - 2. * self.m_n - \ self.df = self.dw - 2. * self.m_n - \
2 * self.c + 2. * self.shift * self.m_n 2 * self.c + 2. * self.shift * self.m_n
self.dg = self.d * cos(self.alpha_t) self.dg = self.d * cos(self.pressure_angle_t)
self.phipart = 2 * pi / self.z self.phipart = 2 * pi / self.z
self.undercut_end = sqrt(-self.df ** 2 + self.da ** 2) / self.da self.undercut_end = sqrt(-self.df ** 2 + self.da ** 2) / self.da
self.undercut_rot = (-self.df / self.dw * tan(arctan((2 * ((self.m * pi) / 4. - self.undercut_rot = (-self.df / self.dw * tan(arctan((2 * ((self.m * pi) / 4. -
(self.c + self.m_n) * tan(self.alpha_t))) / self.df))) (self.c + self.m_n) * tan(self.pressure_angle_t))) / self.df)))
self.involute_end = sqrt(self.da ** 2 - self.dg ** 2) / self.dg self.involute_end = sqrt(self.da ** 2 - self.dg ** 2) / self.dg
self.involute_rot1 = sqrt(-self.dg ** 2 + (self.dw) ** 2) / self.dg - arctan( self.involute_rot1 = sqrt(-self.dg ** 2 + (self.dw) ** 2) / self.dg - arctan(
sqrt(-self.dg ** 2 + (self.dw) ** 2) / self.dg) sqrt(-self.dg ** 2 + (self.dw) ** 2) / self.dg)
self.involute_rot2 = self.m / \ self.involute_rot2 = self.m / \
(self.d) * (pi / 2 + 2 * self.shift * tan(self.alpha_t)) (self.d) * (pi / 2 + 2 * self.shift * tan(self.pressure_angle_t))
self.involute_rot2 = 1 / self.z * (pi / 2 + 2 * self.shift * tan(self.alpha_t)) self.involute_rot2 = 1 / self.z * (pi / 2 + 2 * self.shift * tan(self.pressure_angle_t))
self.involute_rot = self.involute_rot1 + self.involute_rot2 self.involute_rot = self.involute_rot1 + self.involute_rot2
self.involute_start = 0. self.involute_start = 0.
if self.dg <= self.df: if self.dg <= self.df:
@@ -68,9 +70,9 @@ class involute_tooth():
def undercut_points(self, num=10): def undercut_points(self, num=10):
pts = linspace(0, self.undercut_end, num=num) pts = linspace(0, self.undercut_end, num=num)
fx = self.undercut_function_x() fx = self.undercut_function_x()
x = array(map(fx, pts)) x = array(list(map(fx, pts)))
fy = self.undercut_function_y() fy = self.undercut_function_y()
y = array(map(fy, pts)) y = array(list(map(fy, pts)))
xy = transpose([x, y]) xy = transpose([x, y])
rotate = rotation( rotate = rotation(
self.undercut_rot + self.phipart / 2 - self.backlash / 4) self.undercut_rot + self.phipart / 2 - self.backlash / 4)
@@ -80,9 +82,9 @@ class involute_tooth():
def involute_points(self, num=10): def involute_points(self, num=10):
pts = linspace(self.involute_start, self.involute_end, num=num) pts = linspace(self.involute_start, self.involute_end, num=num)
fx = self.involute_function_x() fx = self.involute_function_x()
x = array(map(fx, pts)) x = array(list(map(fx, pts)))
fy = self.involute_function_y() fy = self.involute_function_y()
y = array(map(fy, pts)) y = array(list(map(fy, pts)))
rot = rotation(self.involute_rot - self.backlash / 4) rot = rotation(self.involute_rot - self.backlash / 4)
xy = rot(transpose(array([x, y]))) xy = rot(transpose(array([x, y])))
return(xy) return(xy)
@@ -145,38 +147,44 @@ class involute_tooth():
def _update(self): def _update(self):
self.__init__(m = self.m_n, z = self.z, self.__init__(m = self.m_n, z = self.z,
alpha = self.alpha, clearence = self.clearence, shift = self.shift, pressure_angle = self.pressure_angle, clearance = self.clearance, shift = self.shift,
beta = self.beta, undercut = self.undercut, backlash = self.backlash) beta = self.beta, undercut = self.undercut, backlash = self.backlash, head = self.head)
class involute_rack(object): class involute_rack(object):
def __init__(self, m=5, z=15, alpha=20 * pi / 180., thickness=5): def __init__(self, m=5, z=15, pressure_angle=20 * pi / 180., thickness=5, beta=0, head=0):
self.alpha = alpha self.pressure_angle = pressure_angle
self.thickness = thickness self.thickness = thickness
self.m = m self.m = m
self.z = z self.z = z
self.beta = beta
self.head = head
def _update(self): def _update(self):
self.__init__(m = self.m, z = self.z, alpha = self.alpha, thickness = self.thickness) self.__init__(m = self.m, z = self.z, pressure_angle = self.pressure_angle,
thickness=self.thickness, beta=self.beta, head=self.head)
def points(self, num=10): def points(self, num=10):
a = 2 * self.m * tan(self.alpha) pressure_angle_t = arctan(tan(self.pressure_angle) / cos(self.beta))
b = ((self.m * pi) / 2 - a) / 2 m = self.m / cos(self.beta)
a = (2 + self.head) * m * tan(pressure_angle_t)
b = (m * pi) / 4 - (1 + self.head) * m * tan(pressure_angle_t)
tooth= [ tooth= [
[self.m, -a - b], [-self.m, -a - b],
[-self.m, -b], [self.m * (1 + self.head), -b],
[-self.m, b], [self.m * (1 + self.head), b],
[self.m, a + b] [-self.m, a + b]
] ]
teeth = [tooth] teeth = [tooth]
trans = translation([0., self.m * pi, 0.]) trans = translation([0., m * pi, 0.])
for i in range(self.z): for i in range(self.z - 1):
teeth.append(trans(teeth[-1])) teeth.append(trans(teeth[-1]))
teeth = list(np.vstack(teeth)) teeth = list(np.vstack(teeth))
teeth.append(list(teeth[-1])) teeth.append(list(teeth[-1]))
teeth[-1][0] += self.thickness teeth[-1][0] -= self.thickness
teeth.append(list(teeth[0])) teeth.append(list(teeth[0]))
teeth[-1][0] += self.thickness teeth[-1][0] -= self.thickness
teeth.append(teeth[0]) teeth.append(teeth[0])
return(teeth) return(teeth)

14
setup.py Normal file
View File

@@ -0,0 +1,14 @@
from setuptools import setup
from pygears import __version__
setup(name='freecad.gears',
version=str(__version__),
packages=['freecad',
'freecad.gears',
'pygears'],
maintainer="looooo",
maintainer_email="sppedflyer@gmail.com",
url="https://github.com/looooo/FCGear",
description="gears for FreeCAD",
install_requires=['numpy'],
include_package_data=True)