Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8db1141a57 | ||
|
|
b1e1d7467d | ||
|
|
c44738a6f6 | ||
|
|
f3ec22f524 | ||
|
|
1b46e4b39a | ||
|
|
62909966f2 | ||
|
|
ecc42b23ca | ||
|
|
00d814e8bd | ||
|
|
ab50047800 | ||
|
|
23f8dbaf19 | ||
|
|
a511a2835d | ||
|
|
ff1fe8bdb3 | ||
|
|
f68653d442 | ||
|
|
4c7f5410b0 | ||
|
|
6abbeb1fef | ||
|
|
146767418a | ||
|
|
97df5a8077 | ||
|
|
5fc6b813e3 | ||
|
|
25aafca940 |
@@ -1 +1 @@
|
|||||||
recursive-include freecad/gears/icons *
|
recursive-include freecad_gear/freecad/icons *
|
||||||
|
|||||||
88
README.md
@@ -1,82 +1,14 @@
|
|||||||
# A Gear module for FreeCAD
|
a gearmodule for freecad
|
||||||
|
|
||||||
[](https://liberapay.com/looooo/donate)
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
FreeCAD > v0.16
|
|
||||||
|
|
||||||
# Screenshots
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## Supported gear-types
|
|
||||||
|
|
||||||
### Cylindric Involute
|
|
||||||
#### Shifting
|
|
||||||
#### Helical
|
|
||||||
#### Double Helical
|
|
||||||
#### Undercut
|
|
||||||
|
|
||||||
### Involute Rack
|
|
||||||
|
|
||||||
### Cylindric Cycloid
|
|
||||||
#### Helical
|
|
||||||
#### Double Helical
|
|
||||||
|
|
||||||
### Spherical Involute Bevel-Gear
|
|
||||||
#### Spiral
|
|
||||||
|
|
||||||
### Crown-Gear
|
|
||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
## Installation
|
* install:
|
||||||
|
* 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.
|
|
||||||
|
|
||||||
### pip
|
* create a gear:
|
||||||
|
* open freecad
|
||||||
`pip install https://github.com/looooo/FCGear/archive/master.tar.gz`
|
* go to the gear workbench
|
||||||
|
* create new document
|
||||||
**Important note:** Most systems have multiple versions of python installed. Make sure the `pip` you're using is used by FreeCAD as well.
|
* create a gear (click on gear symbol)
|
||||||
|
* 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
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 205 KiB |
@@ -1,32 +0,0 @@
|
|||||||
# 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()
|
|
||||||
|
Before Width: | Height: | Size: 82 KiB |
@@ -1 +0,0 @@
|
|||||||
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
import pygears
|
|
||||||
__version__ = pygears.__version__
|
|
||||||
@@ -1,94 +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 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'
|
|
||||||
@@ -1,611 +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 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)
|
|
||||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,66 +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 os
|
|
||||||
import FreeCADGui as Gui
|
|
||||||
import FreeCAD as App
|
|
||||||
__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):
|
|
||||||
"""glider workbench"""
|
|
||||||
MenuText = "Gear"
|
|
||||||
ToolTip = "Gear Workbench"
|
|
||||||
Icon = os.path.join(__dirname__, 'icons', 'gearworkbench.svg')
|
|
||||||
commands = [
|
|
||||||
"CreateInvoluteGear",
|
|
||||||
"CreateInvoluteRack",
|
|
||||||
"CreateCycloideGear",
|
|
||||||
"CreateBevelGear",
|
|
||||||
"CreateCrownGear"]
|
|
||||||
|
|
||||||
def GetClassName(self):
|
|
||||||
return "Gui::PythonWorkbench"
|
|
||||||
|
|
||||||
def Initialize(self):
|
|
||||||
from .commands import CreateCycloideGear, CreateInvoluteGear
|
|
||||||
from .commands import CreateBevelGear, CreateInvoluteRack, CreateCrownGear
|
|
||||||
self.appendToolbar("Gear", self.commands)
|
|
||||||
self.appendMenu("Gear", self.commands)
|
|
||||||
Gui.addIconPath(App.getHomePath()+"Mod/gear/icons/")
|
|
||||||
Gui.addCommand('CreateInvoluteGear', CreateInvoluteGear())
|
|
||||||
Gui.addCommand('CreateCycloideGear', CreateCycloideGear())
|
|
||||||
Gui.addCommand('CreateBevelGear', CreateBevelGear())
|
|
||||||
Gui.addCommand('CreateInvoluteRack', CreateInvoluteRack())
|
|
||||||
Gui.addCommand('CreateCrownGear', CreateCrownGear())
|
|
||||||
|
|
||||||
def Activated(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def Deactivated(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
Gui.addWorkbench(gearWorkbench())
|
|
||||||
7
freecad_gear/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/lib/python
|
||||||
|
|
||||||
|
from freecad_gear.gearfunc._involute_tooth import involute_rack, involute_tooth
|
||||||
|
from freecad_gear.gearfunc._cycloide_tooth import cycloide_tooth
|
||||||
|
from freecad_gear.gearfunc._bevel_tooth import bevel_tooth
|
||||||
|
|
||||||
|
import freecad_gear.freecad
|
||||||
143
freecad_gear/freecad/__init__.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#***************************************************************************
|
||||||
|
#* *
|
||||||
|
#* 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
|
||||||
|
from PySide import QtGui, QtCore
|
||||||
|
|
||||||
|
freecad_found = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
import FreeCADGui as Gui
|
||||||
|
import Part
|
||||||
|
import FreeCAD as App
|
||||||
|
except ImportError:
|
||||||
|
freecad_found = False
|
||||||
|
|
||||||
|
if freecad_found:
|
||||||
|
|
||||||
|
import freecad_gear as gear
|
||||||
|
from freecad_gear.freecad.commands import (createInvoluteGear,
|
||||||
|
createCycloidGear, createBevelGear, createInvoluteRack)
|
||||||
|
|
||||||
|
|
||||||
|
class gearToolBox(object):
|
||||||
|
def __init__(self):
|
||||||
|
mw = Gui.getMainWindow()
|
||||||
|
[
|
||||||
|
self.involuteGearAction,
|
||||||
|
self.involuteRackAction,
|
||||||
|
self.bevelGearAction,
|
||||||
|
self.cycloidGearAction,
|
||||||
|
self.dropdown_action] = [None, None, None, None, None]
|
||||||
|
self.defaultAction = createInvoluteGear
|
||||||
|
self.add_gear_wb()
|
||||||
|
mw.workbenchActivated.connect(self.add_gear_wb)
|
||||||
|
timer = mw.findChild(QtCore.QTimer, "activityTimer")
|
||||||
|
timer.connect(timer, QtCore.SIGNAL("timeout()"), self.checkDocument)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_gear_wb(self, *args):
|
||||||
|
print("Workbench_changed")
|
||||||
|
try:
|
||||||
|
wb = Gui.activeWorkbench()
|
||||||
|
except Exception as e:
|
||||||
|
return
|
||||||
|
|
||||||
|
if "PartWorkbench" in str(wb):
|
||||||
|
|
||||||
|
mainWindow = Gui.getMainWindow()
|
||||||
|
|
||||||
|
# add the module to Freecad
|
||||||
|
try:
|
||||||
|
if Gui.gear.gear_toolbar:
|
||||||
|
Gui.gear.gear_toolbar.show()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
Gui.gear = gear.__class__("gear")
|
||||||
|
print(type(gear))
|
||||||
|
|
||||||
|
# create toolbar
|
||||||
|
Gui.gear.gear_toolbar = mainWindow.addToolBar("Part: GearToolbar")
|
||||||
|
Gui.gear.gear_toolbar.setObjectName("GearToolbar")
|
||||||
|
|
||||||
|
this_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.dropdown = QtGui.QMenu("gear_menu", Gui.gear.gear_toolbar)
|
||||||
|
|
||||||
|
# create commands
|
||||||
|
icon = QtGui.QIcon(this_path + "/icons/involutegear.svg")
|
||||||
|
self.involuteGearAction = QtGui.QAction(icon, "involute gear", self.dropdown)
|
||||||
|
self.involuteGearAction.setObjectName("GearToolbar")
|
||||||
|
self.involuteGearAction.triggered.connect(
|
||||||
|
self.set_default_action(self.involuteGearAction, createInvoluteGear))
|
||||||
|
|
||||||
|
icon = QtGui.QIcon(this_path + "/icons/involuterack.svg")
|
||||||
|
self.involuteRackAction = QtGui.QAction(icon, "involute rack", self.dropdown)
|
||||||
|
self.involuteRackAction.setObjectName("GearToolbar")
|
||||||
|
self.involuteRackAction.triggered.connect(
|
||||||
|
self.set_default_action(self.involuteRackAction, createInvoluteRack))
|
||||||
|
|
||||||
|
icon = QtGui.QIcon(this_path + "/icons/cycloidegear.svg")
|
||||||
|
self.cycloidGearAction = QtGui.QAction(icon, "cycloid gear", self.dropdown)
|
||||||
|
self.cycloidGearAction.setObjectName("GearToolbar")
|
||||||
|
self.cycloidGearAction.triggered.connect(
|
||||||
|
self.set_default_action(self.cycloidGearAction, createCycloidGear))
|
||||||
|
|
||||||
|
icon = QtGui.QIcon(this_path + "/icons/bevelgear.svg")
|
||||||
|
self.bevelGearAction = QtGui.QAction(icon, "bevel gear", self.dropdown)
|
||||||
|
self.bevelGearAction.setObjectName("GearToolbar")
|
||||||
|
self.bevelGearAction.triggered.connect(
|
||||||
|
self.set_default_action(self.bevelGearAction, createBevelGear))
|
||||||
|
|
||||||
|
|
||||||
|
temp1 = self.dropdown.addAction(self.involuteGearAction)
|
||||||
|
temp2 = self.dropdown.addAction(self.involuteRackAction)
|
||||||
|
temp3 = self.dropdown.addAction(self.cycloidGearAction)
|
||||||
|
temp4 = self.dropdown.addAction(self.bevelGearAction)
|
||||||
|
|
||||||
|
self.dropdown.setIcon(self.involuteGearAction.icon())
|
||||||
|
temp5 = Gui.gear.gear_toolbar.addAction(self.dropdown.menuAction())
|
||||||
|
self.checkDocument()
|
||||||
|
|
||||||
|
self.defaultCommand = createInvoluteGear
|
||||||
|
self.dropdown.menuAction().triggered.connect(self.defaultCommand)
|
||||||
|
|
||||||
|
def set_default_action(self, action, command):
|
||||||
|
def cb(*args):
|
||||||
|
self.dropdown.setIcon(action.icon())
|
||||||
|
self.defaultCommand = command
|
||||||
|
command()
|
||||||
|
return cb
|
||||||
|
|
||||||
|
def checkDocument(self, *args):
|
||||||
|
enable = False
|
||||||
|
if App.ActiveDocument:
|
||||||
|
enable = True
|
||||||
|
for action in [self.involuteGearAction, self.involuteRackAction,
|
||||||
|
self.bevelGearAction, self.cycloidGearAction, self.dropdown.menuAction()]:
|
||||||
|
if action:
|
||||||
|
action.setEnabled(enable)
|
||||||
|
|
||||||
|
if freecad_found:
|
||||||
|
a = gearToolBox()
|
||||||
52
freecad_gear/freecad/commands.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#***************************************************************************
|
||||||
|
#* *
|
||||||
|
#* 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 as App
|
||||||
|
import FreeCADGui as Gui
|
||||||
|
from freecad_gear.gearfunc._Classes import involute_gear, cycloide_gear, bevel_gear, involute_gear_rack
|
||||||
|
|
||||||
|
|
||||||
|
def createInvoluteGear(*args):
|
||||||
|
a = App.ActiveDocument.addObject("Part::FeaturePython", "involute_gear")
|
||||||
|
involute_gear(a)
|
||||||
|
a.ViewObject.Proxy = 0.
|
||||||
|
App.ActiveDocument.recompute()
|
||||||
|
Gui.SendMsgToActiveView("ViewFit")
|
||||||
|
|
||||||
|
def createInvoluteRack(*args):
|
||||||
|
a = App.ActiveDocument.addObject("Part::FeaturePython", "involute_gear")
|
||||||
|
involute_gear_rack(a)
|
||||||
|
a.ViewObject.Proxy = 0.
|
||||||
|
App.ActiveDocument.recompute()
|
||||||
|
Gui.SendMsgToActiveView("ViewFit")
|
||||||
|
|
||||||
|
def createBevelGear(*args):
|
||||||
|
a = App.ActiveDocument.addObject("Part::FeaturePython", "bevel_gear")
|
||||||
|
bevel_gear(a)
|
||||||
|
a.ViewObject.Proxy = 0.
|
||||||
|
App.ActiveDocument.recompute()
|
||||||
|
Gui.SendMsgToActiveView("ViewFit")
|
||||||
|
|
||||||
|
def createCycloidGear(*args):
|
||||||
|
a = App.ActiveDocument.addObject("Part::FeaturePython", "cycloide_gear")
|
||||||
|
cycloide_gear(a)
|
||||||
|
a.ViewObject.Proxy = 0.
|
||||||
|
App.ActiveDocument.recompute()
|
||||||
|
Gui.SendMsgToActiveView("ViewFit")
|
||||||
356
freecad_gear/freecad/icons/bevelgear.svg
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
445
freecad_gear/gearfunc/_Classes.py
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
# -*- 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))
|
||||||
|
|
||||||
0
freecad_gear/gearfunc/__init__.py
Normal file
168
freecad_gear/gearfunc/_bevel_tooth.py
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
# -*- 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()
|
||||||
@@ -19,27 +19,28 @@
|
|||||||
#* *
|
#* *
|
||||||
#***************************************************************************
|
#***************************************************************************
|
||||||
|
|
||||||
|
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, clearance = 0.12, backlash = 0.00):
|
def __init__(self, z1 = 5, z2 = 5, z = 14, m = 5, clearence = 0.12, backlash = 0.00):
|
||||||
self.m = m
|
self.m = m
|
||||||
self.z = z
|
self.z = z
|
||||||
self.clearance = clearance
|
self.clearence = clearence
|
||||||
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.clearance * self.m
|
self.di = self.d - 2*self.m - self.clearence * self.m
|
||||||
self.phipart = 2 * pi / self.z
|
self.phipart = 2 * pi / self.z
|
||||||
|
|
||||||
def epicycloide_x(self):
|
def epicycloide_x(self):
|
||||||
@@ -86,10 +87,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 = list(map(outer_x, t_vals_outer))
|
pts_outer_x = map(outer_x, t_vals_outer)
|
||||||
pts_outer_y = list(map(outer_y, t_vals_outer))
|
pts_outer_y = map(outer_y, t_vals_outer)
|
||||||
pts_inner_x = list(map(inner_x, t_vals_inner))
|
pts_inner_x = map(inner_x, t_vals_inner)
|
||||||
pts_inner_y = list(map(inner_y, t_vals_inner))
|
pts_inner_y = 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])
|
||||||
@@ -102,7 +103,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,
|
||||||
clearance = self.clearance, backlash = self.backlash)
|
clearence = self.clearence, backlash = self.backlash)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from matplotlib import pyplot
|
from matplotlib import pyplot
|
||||||
@@ -22,30 +22,28 @@
|
|||||||
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(pressure_angle):
|
def reflection(alpha):
|
||||||
mat = array(
|
mat = array(
|
||||||
[[cos(2 * pressure_angle), -sin(2 * pressure_angle)], [-sin(2 * pressure_angle), -cos(2 * pressure_angle)]])
|
[[cos(2 * alpha), -sin(2 * alpha)], [-sin(2 * alpha), -cos(2 * alpha)]])
|
||||||
|
|
||||||
def func(x):
|
def func(x):
|
||||||
return(dot(x, mat))
|
return(dot(x, mat))
|
||||||
return(func)
|
return(func)
|
||||||
|
|
||||||
|
|
||||||
def reflection3D(pressure_angle):
|
def reflection3D(alpha):
|
||||||
mat = array([[cos(2 * pressure_angle), -sin(2 * pressure_angle), 0.],
|
mat = array([[cos(2 * alpha), -sin(2 * alpha), 0.],
|
||||||
[-sin(2 * pressure_angle), -cos(2 * pressure_angle), 0.], [0., 0., 1.]])
|
[-sin(2 * alpha), -cos(2 * alpha), 0.], [0., 0., 1.]])
|
||||||
|
|
||||||
def func(x):
|
def func(x):
|
||||||
return(dot(x, mat))
|
return(dot(x, mat))
|
||||||
return(func)
|
return(func)
|
||||||
|
|
||||||
|
|
||||||
def rotation(pressure_angle, midpoint=None):
|
def rotation(alpha, midpoint=[0, 0]):
|
||||||
midpoint = midpoint or [0., 0.]
|
mat = array([[cos(alpha), -sin(alpha)], [sin(alpha), cos(alpha)]])
|
||||||
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)
|
||||||
@@ -55,11 +53,11 @@ def rotation(pressure_angle, midpoint=None):
|
|||||||
return(func)
|
return(func)
|
||||||
|
|
||||||
|
|
||||||
def rotation3D(pressure_angle):
|
def rotation3D(alpha):
|
||||||
mat = array(
|
mat = array(
|
||||||
[
|
[
|
||||||
[cos(pressure_angle), -sin(pressure_angle), 0.],
|
[cos(alpha), -sin(alpha), 0.],
|
||||||
[sin(pressure_angle), cos(pressure_angle), 0.],
|
[sin(alpha), cos(alpha), 0.],
|
||||||
[0., 0., 1.]])
|
[0., 0., 1.]])
|
||||||
|
|
||||||
def func(xx):
|
def func(xx):
|
||||||
@@ -72,7 +70,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(list(map(trans, x))))
|
return(array(map(trans, x)))
|
||||||
return(func)
|
return(func)
|
||||||
|
|
||||||
|
|
||||||
@@ -100,8 +98,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 Exception as e:
|
except:
|
||||||
print(e)
|
print(Exception)
|
||||||
return(False)
|
return(False)
|
||||||
else:
|
else:
|
||||||
if 0. < g < 1. and 0. < h < 1.:
|
if 0. < g < 1. and 0. < h < 1.:
|
||||||
@@ -138,7 +136,10 @@ def trimfunc(l1, l2):
|
|||||||
|
|
||||||
def norm(vec1, vec2):
|
def norm(vec1, vec2):
|
||||||
vec = array(vec2) - array(vec1)
|
vec = array(vec2) - array(vec1)
|
||||||
return np.linalg.norm(vec)
|
out = 0
|
||||||
|
for i in vec:
|
||||||
|
out += i ** 2
|
||||||
|
return(sqrt(out))
|
||||||
|
|
||||||
|
|
||||||
def nearestpts(evolv, underc):
|
def nearestpts(evolv, underc):
|
||||||
@@ -159,15 +160,3 @@ 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
|
|
||||||
@@ -21,46 +21,44 @@
|
|||||||
|
|
||||||
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, pressure_angle=20 * pi / 180., clearance=0.12, shift=0.5, beta=0.,
|
def __init__(self, m=5, z=15, alpha=20 * pi / 180., clearence=0.12, shift=0.5, beta=0., undercut=False, backlash=0.00):
|
||||||
undercut=False, backlash=0.00, head=0.00):
|
self.alpha = alpha
|
||||||
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.clearance = clearance
|
self.clearence = clearence
|
||||||
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.pressure_angle_t = arctan(tan(self.pressure_angle) / cos(self.beta))
|
self.alpha_t = arctan(tan(self.alpha) / cos(self.beta))
|
||||||
self.m = self.m_n / cos(self.beta)
|
self.m = self.m_n / cos(self.beta)
|
||||||
self.c = self.clearance * self.m_n
|
self.c = self.clearence * 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.head) * self.m_n
|
self.da = self.dw + 2. * self.m_n + 2. * self.shift * 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.pressure_angle_t)
|
self.dg = self.d * cos(self.alpha_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.pressure_angle_t))) / self.df)))
|
(self.c + self.m_n) * tan(self.alpha_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.pressure_angle_t))
|
(self.d) * (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_rot2 = 1 / self.z * (pi / 2 + 2 * self.shift * tan(self.alpha_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:
|
||||||
@@ -70,9 +68,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(list(map(fx, pts)))
|
x = array(map(fx, pts))
|
||||||
fy = self.undercut_function_y()
|
fy = self.undercut_function_y()
|
||||||
y = array(list(map(fy, pts)))
|
y = array(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)
|
||||||
@@ -82,9 +80,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(list(map(fx, pts)))
|
x = array(map(fx, pts))
|
||||||
fy = self.involute_function_y()
|
fy = self.involute_function_y()
|
||||||
y = array(list(map(fy, pts)))
|
y = array(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)
|
||||||
@@ -147,44 +145,38 @@ 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,
|
||||||
pressure_angle = self.pressure_angle, clearance = self.clearance, shift = self.shift,
|
alpha = self.alpha, clearence = self.clearence, shift = self.shift,
|
||||||
beta = self.beta, undercut = self.undercut, backlash = self.backlash, head = self.head)
|
beta = self.beta, undercut = self.undercut, backlash = self.backlash)
|
||||||
|
|
||||||
|
|
||||||
class involute_rack(object):
|
class involute_rack(object):
|
||||||
def __init__(self, m=5, z=15, pressure_angle=20 * pi / 180., thickness=5, beta=0, head=0):
|
def __init__(self, m=5, z=15, alpha=20 * pi / 180., thickness=5):
|
||||||
self.pressure_angle = pressure_angle
|
self.alpha = alpha
|
||||||
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, pressure_angle = self.pressure_angle,
|
self.__init__(m = self.m, z = self.z, alpha = self.alpha, thickness = self.thickness)
|
||||||
thickness=self.thickness, beta=self.beta, head=self.head)
|
|
||||||
|
|
||||||
def points(self, num=10):
|
def points(self, num=10):
|
||||||
pressure_angle_t = arctan(tan(self.pressure_angle) / cos(self.beta))
|
a = 2 * self.m * tan(self.alpha)
|
||||||
m = self.m / cos(self.beta)
|
b = ((self.m * pi) / 2 - a) / 2
|
||||||
|
|
||||||
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 * (1 + self.head), -b],
|
[-self.m, -b],
|
||||||
[self.m * (1 + self.head), b],
|
[-self.m, b],
|
||||||
[-self.m, a + b]
|
[self.m, a + b]
|
||||||
]
|
]
|
||||||
teeth = [tooth]
|
teeth = [tooth]
|
||||||
trans = translation([0., m * pi, 0.])
|
trans = translation([0., self.m * pi, 0.])
|
||||||
for i in range(self.z - 1):
|
for i in range(self.z):
|
||||||
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)
|
||||||
|
|
||||||
BIN
pictures/Bildschirmfoto - 2014-06-27 - 09:32:33.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
pictures/Bildschirmfoto - 2014-06-29 - 13:16:21.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
pictures/Bildschirmfoto - 2014-06-29 - 13:36:26.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -1 +0,0 @@
|
|||||||
__version__ = "0.01"
|
|
||||||
@@ -1,169 +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
|
|
||||||
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()
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
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
|
|
||||||
30
setup.py
@@ -1,14 +1,18 @@
|
|||||||
from setuptools import setup
|
import sys
|
||||||
from pygears import __version__
|
import os
|
||||||
|
|
||||||
setup(name='freecad.gears',
|
from setuptools import setup, find_packages
|
||||||
version=str(__version__),
|
|
||||||
packages=['freecad',
|
setup(
|
||||||
'freecad.gears',
|
name = 'freecad_gear',
|
||||||
'pygears'],
|
version = '0.3',
|
||||||
maintainer="looooo",
|
packages = ["freecad_gear", "freecad_gear/freecad/", "freecad_gear/gearfunc/"],
|
||||||
maintainer_email="sppedflyer@gmail.com",
|
include_package_data=True,
|
||||||
url="https://github.com/looooo/FCGear",
|
description = 'Some gears for freecad',
|
||||||
description="gears for FreeCAD",
|
author = 'Lorenz L',
|
||||||
install_requires=['numpy'],
|
author_email = 'sppedflyer@gmail.com',
|
||||||
include_package_data=True)
|
url = 'https://github.com/looooo/FCGear',
|
||||||
|
download_url = 'https://github.com/looooo/FCGear/tarball/0.3',
|
||||||
|
keywords = ['gear', 'freecad'],
|
||||||
|
classifiers = [],
|
||||||
|
)
|
||||||