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