Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
539 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
================================================ | ||
FCGear: an Involute Gear Generator for FreeCAD | ||
================================================ | ||
|
||
This is a simple gear generation tool usable in FreeCAD. The tooth | ||
profiles are approximations of the ideal involutes by Bezier curves, | ||
according the paper: | ||
|
||
Approximation of Involute Curves for CAD-System Processing | ||
Higuchi et al. approximation to an involute. | ||
ref: YNU Digital Eng Lab Memorandum 05-1 | ||
http://maekawalab-ynu.com/papers.html | ||
|
||
This code is based on the JavaScript implementation of the published | ||
method provided by A.R. Collins in his gearUtils.js tool: | ||
|
||
Based on gearUtils-03.js by Dr A.R.Collins | ||
Latest version: <www.arc.id.au/gearDrawing.html> | ||
|
||
Also took inspirations from the Inkscape extension provided by Matthew | ||
Dockrey on | ||
|
||
https://github.com/attoparsec/inkscape-extensions.git | ||
|
||
The simplest way to use it is to copy the example macro file | ||
gear.FCMacro to ~/.FreeCAD/ (make sure the fcgear directory is in the | ||
FreeCAD's Python path). | ||
|
||
Copyright 2014 David Douard <david.douard@gmail.com>. | ||
Distributed under the LGPL licence. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# (c) 2014 David Douard <david.douard@gmail.com> | ||
# | ||
# 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. | ||
# | ||
# FCGear 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 FCGear; if not, write to the Free Software | ||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
|
||
from math import cos, sin, pi, acos, asin, atan, sqrt | ||
|
||
import FreeCAD, FreeCADGui, Part | ||
from FreeCAD import Base, Console | ||
import involute | ||
reload(involute) | ||
rotate = involute.rotate | ||
|
||
|
||
def makeGear(m, Z, angle, split=True): | ||
if FreeCAD.ActiveDocument is None: | ||
FreeCAD.newDocument("Gear") | ||
doc = FreeCAD.ActiveDocument | ||
w = FCWireBuilder() | ||
involute.CreateExternalGear(w, m, Z, angle, split) | ||
gearw = Part.Wire([o.toShape() for o in w.wire]) | ||
gear = doc.addObject("Part::Feature", "Gear") | ||
gear.Shape = gearw | ||
return gear | ||
|
||
|
||
class FCWireBuilder(object): | ||
"""A helper class to prepare a Part.Wire object""" | ||
def __init__(self): | ||
self.pos = None | ||
self.theta = 0.0 | ||
self.wire = [] | ||
|
||
def move(self, p): | ||
"""set current position""" | ||
self.pos = Base.Vector(*p) | ||
|
||
def line(self, p): | ||
"""Add a segment between self.pos and p""" | ||
p = rotate(p, self.theta) | ||
end = Base.Vector(*p) | ||
self.wire.append(Part.Line(self.pos, end)) | ||
self.pos = end | ||
|
||
def arc(self, p, r, sweep): | ||
""""Add an arc from self.pos to p which radius is r | ||
sweep (0 or 1) determine the orientation of the arc | ||
""" | ||
p = rotate(p, self.theta) | ||
end = Base.Vector(*p) | ||
mid = Base.Vector(*(midpoints(p, self.pos, r)[sweep])) | ||
self.wire.append(Part.Arc(self.pos, mid, end)) | ||
self.pos = end | ||
|
||
def curve(self, *points): | ||
"""Add a Bezier curve from self.pos to points[-1] | ||
every other points are the control points of the Bezier curve (which | ||
will thus be of degree len(points) ) | ||
""" | ||
points = [Base.Vector(*rotate(p, self.theta)) for p in points] | ||
bz = Part.BezierCurve() | ||
bz.setPoles([self.pos] + points) | ||
self.wire.append(bz) | ||
self.pos = points[-1] | ||
|
||
def close(self): | ||
pass | ||
|
||
def midpoints(p1, p2, r): | ||
"""A very ugly function that returns the midpoint of a p1 and p2 | ||
on the circle which radius is r and which pass throught p1 and | ||
p2 | ||
Return the 2 possible solutions | ||
""" | ||
vx, vy = p2[0]-p1[0], p2[1]-p1[1] | ||
b = (vx**2 + vy**2)**.5 | ||
v = (vx/b, vy/b) | ||
cosA = b**2 / (2*b*r) | ||
A = acos(cosA) | ||
|
||
vx, vy = rotate(v, A) | ||
c1 = (p1[0]+r*vx, p1[1]+r*vy) | ||
m1x, m1y = ((p1[0]+p2[0])/2 - c1[0], (p1[1]+p2[1])/2 - c1[1]) | ||
dm1 = (m1x**2+m1y**2)**.5 | ||
m1x, m1y = (c1[0] + r*m1x/dm1, c1[1] + r*m1y/dm1) | ||
m1 = (m1x, m1y) | ||
|
||
vx, vy = rotate(v, -A) | ||
c2 = (p1[0]+r*vx, p1[1]+r*vy) | ||
m2x, m2y = ((p1[0]+p2[0])/2 - c2[0], (p1[1]+p2[1])/2 - c2[1]) | ||
dm2 = (m2x**2+m2y**2)**.5 | ||
m2x, m2y = (c2[0] + r*m2x/dm2, c2[1] + r*m2y/dm2) | ||
m2 = (m2x, m2y) | ||
|
||
return m1, m2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# (c) 2014 David Douard <david.douard@gmail.com> | ||
# | ||
# 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. | ||
# | ||
# FCGear 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 FCGear; if not, write to the Free Software | ||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
|
||
from PyQt4 import QtGui as qt | ||
import fcgear | ||
import FreeCAD, FreeCADGui | ||
|
||
class GearCreationFrame(qt.QFrame): | ||
def __init__(self, parent=None): | ||
super(GearCreationFrame, self).__init__(parent) | ||
self.Z = qt.QSpinBox(value=26) | ||
self.m = qt.QDoubleSpinBox(value=2.5) | ||
self.angle = qt.QDoubleSpinBox(value=20) | ||
self.split = qt.QComboBox() | ||
self.split.addItems(['2x3', '1x4']) | ||
l = qt.QFormLayout(self) | ||
l.setFieldGrowthPolicy(l.ExpandingFieldsGrow) | ||
l.addRow('Number of teeth:', self.Z) | ||
l.addRow('Modules (mm):', self.m) | ||
l.addRow('Pressure angle:', self.angle) | ||
l.addRow('Number of curves:', self.split) | ||
|
||
class GearDialog(qt.QDialog): | ||
def __init__(self, parent=None): | ||
super(GearDialog, self).__init__(parent) | ||
self.gc = GearCreationFrame() | ||
|
||
btns = qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel | ||
buttonBox = qt.QDialogButtonBox(btns, | ||
accepted=self.accept, | ||
rejected=self.reject) | ||
l = qt.QVBoxLayout(self) | ||
l.addWidget(self.gc) | ||
l.addWidget(buttonBox) | ||
self.setWindowTitle('Gear cration dialog') | ||
|
||
def accept(self): | ||
if FreeCAD.ActiveDocument is None: | ||
FreeCAD.newDocument("Gear") | ||
|
||
gear = fcgear.makeGear(self.gc.m.value(), | ||
self.gc.Z.value(), | ||
self.gc.angle.value(), | ||
not self.gc.split.currentIndex()) | ||
FreeCADGui.SendMsgToActiveView("ViewFit") | ||
return super(GearDialog, self).accept() | ||
|
||
|
||
if __name__ == '__main__': | ||
a = qt.QApplication([]) | ||
w = GearDialog() | ||
w.show() | ||
a.exec_() |
Oops, something went wrong.