2176f3ba7881fea3c9e56b7de591a8a8bf1bcf86
1 #define INKSCAPE_LPE_DOEFFECT_STACK_CPP
3 /*
4 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
5 *
6 * Released under GNU GPL, read the file 'COPYING' for more information
7 */
9 #include "live_effects/lpe-gears.h"
11 #include <vector>
12 #include <2geom/d2.h>
13 #include <2geom/sbasis.h>
14 #include <2geom/bezier-to-sbasis.h>
15 #include <2geom/path.h>
17 using std::vector;
18 using namespace Geom;
20 class Gear {
21 public:
22 // pitch circles touch on two properly meshed gears
23 // all measurements are taken from the pitch circle
24 double pitch_diameter() {return (_number_of_teeth * _module) / M_PI;}
25 double pitch_radius() {return pitch_diameter() / 2.0;}
26 void pitch_radius(double R) {_module = (2 * M_PI * R) / _number_of_teeth;}
28 // base circle serves as the basis for the involute toothe profile
29 double base_diameter() {return pitch_diameter() * cos(_pressure_angle);}
30 double base_radius() {return base_diameter() / 2.0;}
32 // diametrical pitch
33 double diametrical_pitch() {return _number_of_teeth / pitch_diameter();}
35 // height of the tooth above the pitch circle
36 double addendum() {return 1.0 / diametrical_pitch();}
37 // depth of the tooth below the pitch circle
38 double dedendum() {return addendum() + _clearance;}
40 // root circle specifies the bottom of the fillet between teeth
41 double root_radius() {return pitch_radius() - dedendum();}
42 double root_diameter() {return root_radius() * 2.0;}
44 // outer circle is the outside diameter of the gear
45 double outer_radius() {return pitch_radius() + addendum();}
46 double outer_diameter() {return outer_radius() * 2.0;}
48 // angle covered by the tooth on the pitch circle
49 double tooth_thickness_angle() {return M_PI / _number_of_teeth;}
51 Geom::Point centre() {return _centre;}
52 void centre(Geom::Point c) {_centre = c;}
54 double angle() {return _angle;}
55 void angle(double a) {_angle = a;}
57 int number_of_teeth() {return _number_of_teeth;}
59 Geom::Path path();
60 Gear spawn(Geom::Point p);
62 Gear(int n, double m, double phi) {
63 _number_of_teeth = n;
64 _module = m;
65 _pressure_angle = phi;
66 _clearance = 0.0;
67 _angle = 0.0;
68 _centre = Geom::Point(0.0,0.0);
69 }
70 private:
71 int _number_of_teeth;
72 double _pressure_angle;
73 double _module;
74 double _clearance;
75 double _angle;
76 Geom::Point _centre;
77 D2<SBasis> _involute(double start, double stop) {
78 D2<SBasis> B;
79 D2<SBasis> I;
80 Linear bo = Linear(start,stop);
82 B[0] = cos(bo,2);
83 B[1] = sin(bo,2);
85 I = B - Linear(0,1) * derivative(B);
86 I = I*base_radius() + _centre;
87 return I;
88 }
89 D2<SBasis> _arc(double start, double stop, double R) {
90 D2<SBasis> B;
91 Linear bo = Linear(start,stop);
93 B[0] = cos(bo,2);
94 B[1] = sin(bo,2);
96 B = B*R + _centre;
97 return B;
98 }
99 // angle of the base circle used to create the involute to a certain radius
100 double involute_swath_angle(double R) {
101 if (R <= base_radius()) return 0.0;
102 return sqrt(R*R - base_radius()*base_radius())/base_radius();
103 }
105 // angle of the base circle between the origin of the involute and the intersection on another radius
106 double involute_intersect_angle(double R) {
107 if (R <= base_radius()) return 0.0;
108 return (sqrt(R*R - base_radius()*base_radius())/base_radius()) - acos(base_radius()/R);
109 }
110 };
112 void makeContinuous(D2<SBasis> &a, Point const b) {
113 for(unsigned d=0;d<2;d++)
114 a[d][0][0] = b[d];
115 }
117 Geom::Path Gear::path() {
118 Geom::Path pb;
120 // angle covered by a full tooth and fillet
121 double tooth_rotation = 2.0 * tooth_thickness_angle();
122 // angle covered by an involute
123 double involute_advance = involute_intersect_angle(outer_radius()) - involute_intersect_angle(root_radius());
124 // angle covered by the tooth tip
125 double tip_advance = tooth_thickness_angle() - (2 * (involute_intersect_angle(outer_radius()) - involute_intersect_angle(pitch_radius())));
126 // angle covered by the toothe root
127 double root_advance = (tooth_rotation - tip_advance) - (2.0 * involute_advance);
128 // begin drawing the involute at t if the root circle is larger than the base circle
129 double involute_t = involute_swath_angle(root_radius())/involute_swath_angle(outer_radius());
131 //rewind angle to start drawing from the leading edge of the tooth
132 double first_tooth_angle = _angle - ((0.5 * tip_advance) + involute_advance);
134 Geom::Point prev;
135 for (int i=0; i < _number_of_teeth; i++)
136 {
137 double cursor = first_tooth_angle + (i * tooth_rotation);
139 D2<SBasis> leading_I = compose(_involute(cursor, cursor + involute_swath_angle(outer_radius())), Linear(involute_t,1));
140 if(i != 0) makeContinuous(leading_I, prev);
141 pb.append(SBasisCurve(leading_I));
142 cursor += involute_advance;
143 prev = leading_I.at1();
145 D2<SBasis> tip = _arc(cursor, cursor+tip_advance, outer_radius());
146 makeContinuous(tip, prev);
147 pb.append(SBasisCurve(tip));
148 cursor += tip_advance;
149 prev = tip.at1();
151 cursor += involute_advance;
152 D2<SBasis> trailing_I = compose(_involute(cursor, cursor - involute_swath_angle(outer_radius())), Linear(1,involute_t));
153 makeContinuous(trailing_I, prev);
154 pb.append(SBasisCurve(trailing_I));
155 prev = trailing_I.at1();
157 if (base_radius() > root_radius()) {
158 Geom::Point leading_start = trailing_I.at1();
159 Geom::Point leading_end = (root_radius() * unit_vector(leading_start - _centre)) + _centre;
160 prev = leading_end;
161 pb.appendNew<LineSegment>(leading_end);
162 }
164 D2<SBasis> root = _arc(cursor, cursor+root_advance, root_radius());
165 makeContinuous(root, prev);
166 pb.append(SBasisCurve(root));
167 cursor += root_advance;
168 prev = root.at1();
170 if (base_radius() > root_radius()) {
171 Geom::Point trailing_start = root.at1();
172 Geom::Point trailing_end = (base_radius() * unit_vector(trailing_start - _centre)) + _centre;
173 pb.appendNew<LineSegment>(trailing_end);
174 prev = trailing_end;
175 }
176 }
178 return pb;
179 }
181 Gear Gear::spawn(Geom::Point p) {
182 double radius = Geom::distance(this->centre(), p) - this->pitch_radius();
183 int N = (int) floor( (radius / this->pitch_radius()) * this->number_of_teeth() );
185 Gear gear(N, _module, _pressure_angle);
186 gear.centre(p);
188 double a = atan2(p - this->centre());
189 double new_angle = 0.0;
190 if (gear.number_of_teeth() % 2 == 0)
191 new_angle -= gear.tooth_thickness_angle();
192 new_angle -= (_angle) * (pitch_radius() / gear.pitch_radius());
193 new_angle += (a) * (pitch_radius() / gear.pitch_radius());
194 gear.angle(new_angle + a);
195 return gear;
196 }
200 // #################################################################
204 namespace Inkscape {
205 namespace LivePathEffect {
208 LPEGears::LPEGears(LivePathEffectObject *lpeobject) :
209 Effect(lpeobject),
210 teeth(_("Teeth"), _("The number of teeth"), "teeth", &wr, this, 10),
211 phi(_("Phi"), _("???"), "phi", &wr, this, 5)
212 {
213 registerParameter( dynamic_cast<Parameter *>(&teeth) );
214 registerParameter( dynamic_cast<Parameter *>(&phi) );
215 }
217 LPEGears::~LPEGears()
218 {
220 }
222 std::vector<Geom::Path>
223 LPEGears::doEffect (std::vector<Geom::Path> & path_in)
224 {
225 std::vector<Geom::Path> path_out;
226 Geom::Path gearpath = path_in[0];
228 Geom::Path::iterator it(gearpath.begin());
229 if ( it == gearpath.end() ) return path_out;
231 Gear * gear = new Gear(teeth, 200.0, phi * M_PI / 180);
232 Geom::Point gear_centre = (*it).finalPoint();
233 gear->centre(gear_centre);
234 gear->angle(atan2((*it).initialPoint() - gear_centre));
236 it++; if ( it == gearpath.end() ) return path_out;
237 gear->pitch_radius(Geom::distance(gear_centre, (*it).finalPoint()));
239 path_out.push_back( gear->path());
241 for (it++ ; it != gearpath.end() ; it++) {
242 // iterate through Geom::Curve in path_in
243 Gear* gearnew = new Gear(gear->spawn( (*it).finalPoint() ));
244 path_out.push_back( gearnew->path() );
245 delete gear;
246 gear = gearnew;
247 }
248 delete gear;
250 return path_out;
251 }
254 } // namespace LivePathEffect
255 } /* namespace Inkscape */
257 /*
258 Local Variables:
259 mode:c++
260 c-file-style:"stroustrup"
261 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
262 indent-tabs-mode:nil
263 fill-column:99
264 End:
265 */
266 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :