1 #ifndef SPUR_H
2 #define SPUR_H
3 
4 // topology computation
5 #include <vcg/complex/algorithms/update/topology.h>
6 
7 // append
8 #include <vcg/complex/append.h>
9 
10 // clean
11 #include <vcg/complex/algorithms/clean.h>
12 #include <vcg/complex/algorithms/update/position.h>
13 
14 // just for writing log
15 #include <QString>
16 #include <common/interfaces.h>
17 
18 // temporary
19 #include <GL/glew.h>
20 #include <wrap/gl/glu_tessellator_cap.h>
21 
22 using namespace vcg;
23 
24 // class that creates only the gear profile
25 template <typename MeshType> class Spur {
26 
27 private:
28     static const int ppinv = 20;
29     static const int ppc = 10;
30     static const int pph = 60;
31 
32     // involute tooth profile
tooth(MeshType & tth,float r,float m,float rtop,float pangle)33     static void tooth(MeshType &tth, float r, float m, float rtop, float pangle) {
34 
35         float rb = r * cos(pangle*M_PI/180);
36         float angle = (M_PI * m / r)/2;
37         float maxt = math::Sqrt((rtop)*(rtop)/(rb*rb)-1);
38         float maxl = rb*maxt*maxt/2.0;
39         float theta = math::Asin((m/3)/(r-1.25*m+m/3));
40 
41         //ascending involute
42         int i = 0;
43         for (; i <= ppinv; ++i) {
44 
45             float t = sqrt(2*(maxl*i/ppinv)/rb);
46 
47             float x = rb * (cos(t) + t * sin(t));
48             float y = -rb * (sin(t) - t * cos(t));
49 
50             // avoid strange tooth form
51             if (y < tan(-angle/2)*x) {
52                 break;
53             }
54 
55             typename tri::Allocator<MeshType>::VertexIterator vp = tri::Allocator<MeshType>::AddVertices(tth, 1);
56             vp->P().X() = x*cos(angle) - y*sin(angle);
57             vp->P().Y() = x*sin(angle) + y*cos(angle);
58             vp->P().Z() = 0;
59 
60         }
61 
62         // descending involute
63         --i;
64         for (; i >= 0; --i) {
65 
66             float t = sqrt(2*(maxl*i/ppinv)/rb);
67 
68             float x = rb * (cos(t) + t * sin(t));
69             float y = rb * (sin(t) - t * cos(t));
70 
71             typename tri::Allocator<MeshType>::VertexIterator vp = tri::Allocator<MeshType>::AddVertices(tth, 1);
72             vp->P().X() = x;
73             vp->P().Y() = y;
74             vp->P().Z() = 0;
75 
76         }
77 
78         // descending arc circle
79         float cx = (r-1.25*m+m/3) * cos(-theta);
80         float cy = (r-1.25*m+m/3) * sin(-theta);
81         for (float alpha = M_PI/2.0; alpha < M_PI - theta; alpha += (M_PI/2 - theta)/ppc) {
82             float x = m/3 * cos(alpha) + cx;
83             float y = m/3 * sin(alpha) + cy;
84             typename tri::Allocator<MeshType>::VertexIterator vp = tri::Allocator<MeshType>::AddVertices(tth, 1);
85             vp->P().X() = x;
86             vp->P().Y() = y;
87             vp->P().Z() = 0;
88         }
89 
90         // ascending arc circle
91         for (float alpha = M_PI - theta; alpha > M_PI/2.0; alpha -= (M_PI/2 - theta)/ppc) {
92             float x = m/3 * cos(alpha) + cx;
93             float y = - (m/3 * sin(alpha) + cy);
94             typename tri::Allocator<MeshType>::VertexIterator vp = tri::Allocator<MeshType>::AddVertices(tth, 1);
95             vp->P().X() = x*cos(-angle) - y*sin(-angle);
96             vp->P().Y() = x*sin(-angle) + y*cos(-angle);
97             vp->P().Z() = 0;
98         }
99 
100     }
101 
rotateTooth(MeshType & tth,float angle)102     static void rotateTooth(MeshType &tth, float angle) {
103 
104         for (typename MeshType::VertexIterator vi = tth.vert.begin(); vi != tth.vert.end(); ++vi) {
105             float x = vi->P().X();
106             float y = vi->P().Y();
107             vi->P().X() = x * cos(angle) - y * sin(angle);
108             vi->P().Y() = x * sin(angle) + y * cos(angle);
109         }
110 
111     }
112 
113     // create gears, requires previously checked parameters
create(MeshType & g,float r,float m,float rtop,int n,float angle,float h)114     static void create(MeshType &g, float r, float m, float rtop, int n, float angle, float h) {
115 
116         MeshType tth;
117 
118         tooth(tth, r, m, rtop, angle);
119         tri::Append<MeshType, MeshType>::Mesh(g, tth);
120 
121         // add teeth
122         for (int i = 1; i < n; i++) {
123             rotateTooth(tth, -2*M_PI/n);
124             tri::Append<MeshType, MeshType>::Mesh(g, tth);
125         }
126 
127         // add edges
128         for (int i = 0; i < g.vn; ++i) {
129             typename tri::Allocator<MeshType>::EdgeIterator ep = tri::Allocator<MeshType>::AddEdges(g, 1);
130             ep->V(0) = &g.vert[i];
131             ep->V(1) = &g.vert[(i+1)%(g.vn)];
132         }
133 
134         // add hole
135         if (h > 0) {
136             int count = g.vn;
137             for (int i = 0; i < pph; ++i) {
138                 typename tri::Allocator<MeshType>::VertexIterator vp = tri::Allocator<MeshType>::AddVertices(g, 1);
139                 vp->P().X() = h*cos(math::ToRad(i*360.0/pph));
140                 vp->P().Y() = h*sin(math::ToRad(i*360.0/pph));
141                 vp->P().Z() = 0;
142             }
143             for (int i = 0; i < pph; ++i) {
144                 typename tri::Allocator<MeshType>::EdgeIterator ep = tri::Allocator<MeshType>::AddEdges(g, 1);
145                 ep->V(0) = &g.vert[i+count];
146                 ep->V(1) = &g.vert[(i+1)%pph+count];
147             }
148         }
149 
150     }
151 
152 
153 public:
154 
155     // create a couple of spur gears, checking for input parameters
156     static bool createCouple(MeshFilterInterface &fi, QString &err, MeshType &sprocket, MeshType &gear, float interaxis, float transmission, float module, float pangle = 20.0, float hole = 0.0) {
157 
158         if ( (interaxis < 0) || (transmission <= 0) || (module <= 0) || (pangle <= 0) || (pangle >= 90.0) || (hole < 0)) {
159             err = "Bad parameter.";
160             return false;
161         }
162 
163         float rs = interaxis / (transmission+1);
164         int ns = 2 * rs / module;
165 
166         // teeth number
167         if (2.0 * rs / module - ns != 0) {
168             err = "The number of teeth of the sprocket is not an integer. Try adjusting the interaxis, the speed ratio or the module.";
169             return false;
170         }
171 
172         float rg = transmission*interaxis / (transmission+1);
173         int ng = 2 * rg / module;
174 
175         if (2.0 * rg / module - ng != 0) {
176             err = "The number of teeth of the gear is not an integer. Try adjusting the interaxis, the speed ratio or the module.";
177             return false;
178         }
179 
180 
181         // base radius vs. foot radius
182         float rbs = rs * cos(pangle*M_PI/180);
183         if (rbs < rs - 1.25*module + module/3) {
184             err = "Root radius bigger than base radius in sprocket. Try increasing the module or decreasing the pressure angle.";
185             return false;
186         }
187 
188         float rbg = rg * cos(pangle*M_PI/180);
189         if (rbg < rg - 1.25*module + module/3) {
190             err = "Root radius bigger than base radius in gear. Try increasing the module or decreasing the pressure angle.";
191             return false;
192         }
193 
194         // holes
195         if (hole >= rs - 1.25*module) {
196             err = "Hole radius bigger than root radius of sprocket.";
197             return false;
198         }
199         if (hole >= rg - 1.25*module) {
200             err = "Hole radius bigger than root radius of gear.";
201             return false;
202         }
203 
204         //interference
205         float rtops = rs + module;
206         float rmaxs = math::Sqrt(rbs*rbs + math::Sqr(interaxis*sin(pangle*M_PI/180)));
207         if (rmaxs < rtops) {
208             fi.Log("Sprocket interference, adopting corrections.\n");
209             rtops = rmaxs;
210         }
211 
212         float rtopg = rg + module;
213         float rmaxg = math::Sqrt(rbg*rbg + math::Sqr(interaxis*sin(pangle*M_PI/180)));
214         if (rmaxg < rtopg) {
215             fi.Log("Gear interference, adopting corrections.\n");
216             rtopg = rmaxg;
217         }
218 
219         // contact ratio
220         float deg = math::Sqrt(sqr(rtops) - sqr(rs - 1.25*module + module/3));
221         deg += math::Sqrt(sqr(rtopg) - sqr(rg - 1.25*module + module/3));
222         deg -= interaxis * sin(pangle*M_PI/180);
223         deg /= M_PI * module;
224         if (deg < 1)
225             fi.Log("Contact ratio is less than 1.\n");
226 
227         // strange teeth form
228         float maxt = math::Sqrt(sqr(rs+module)/(rbs*rbs)-1);
229         float x = rbs * (cos(maxt) + maxt * sin(maxt));
230         float y = -rbs * (sin(maxt) - maxt * cos(maxt));
231         float angle = (M_PI * module / rs)/4;
232         if (y < tan(-angle)*x) {
233             fi.Log("Waring: top of the teeth of the sprocket must be cut, to avoid this try decreasing the pressure angle.\n");
234         }
235 
236         maxt = math::Sqrt(sqr(rg+module)/(rbg*rbg)-1);
237         x = rbg * (cos(maxt) + maxt * sin(maxt));
238         y = -rbg * (sin(maxt) - maxt * cos(maxt));
239         angle = (M_PI * module / rg)/4;
240         if (y < tan(-angle)*x) {
241             fi.Log("Waring: top of the teeth of the gear must be cut, to avoid this try decreasing the pressure angle.\n");
242         }
243 
244 
245         // finally create gears
246         create(sprocket, rs, module, rtops, ns, pangle, hole);
247 
248         create(gear, rg, module, rtopg, ng, pangle, hole);
249 
250         return true;
251 
252     }
253 
254     // create a single spur gear, checking for input parameters
255     static bool createSingle(MeshFilterInterface &fi, QString &err, MeshType &gear, float radius, float module, float pangle = 20.0, float hole = 0.0) {
256 
257         if ( (radius <= 0) || (module <= 0) || (pangle <= 0) || (pangle >= 90.0) || (hole < 0)) {
258             err = "Bad parameter.";
259             return false;
260         }
261 
262         // teeth number
263         int n = 2 * radius / module;
264         if (2.0 * radius / module - n != 0) {
265             err = "The number of teeth is not an integer. Make sure the module divides the diameter.";
266             return false;
267         }
268 
269         // base radius vs. foot radius
270         float rb = radius * cos(pangle*M_PI/180);
271         if (rb < radius - 1.25*module + module/3) {
272             err = "Root radius bigger than base radius. Try increasing the module or decreasing the pressure angle.";
273             return false;
274         }
275 
276         // hole
277         if (hole >= radius - 1.25*module) {
278             err = "Hole radius bigger than root radius.";
279             return false;
280         }
281 
282         // strange teeth form
283         float maxt = math::Sqrt(sqr(radius+module)/(rb*rb)-1);
284         float x = rb * (cos(maxt) + maxt * sin(maxt));
285         float y = -rb * (sin(maxt) - maxt * cos(maxt));
286         float angle = (M_PI * module / radius)/4;
287         if (y < tan(-angle)*x) {
288             fi.Log("Waring: top of the teeth must be cut, to avoid this try decreasing the pressure angle.\n");
289         }
290 
291         create(gear, radius, module, radius+module, n, pangle, hole);
292 
293         return true;
294 
295     }
296 
297 };
298 
299 
300 #endif // SPUR_H
301