1
2/*
3 * GearTrain Simulator * Version:  1.00
4 *
5 * Copyright (C) 1999  Shobhan Kumar Dutta  All Rights Reserved.
6 * <skdutta@del3.vsnl.net.in>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * SHOBHAN KUMAR DUTTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
23 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27
28#include <assert.h>
29#include <math.h>
30#include <stdlib.h>
31#include "glut_wrap.h"
32#include <string.h>
33#include <stdio.h>
34
35#ifndef min
36#define min(x, y) ( x < y ? x : y )
37#endif
38
39#ifndef M_PI
40#define M_PI 3.14159265
41#endif	/*  */
42typedef GLfloat TDA[4];
43
44TDA background;
45
46
47struct AXLE
48  {
49    char name[20];
50      GLint id;
51      GLfloat radius;
52      GLint axis;
53      TDA color;
54      TDA position;
55      GLfloat length;
56      GLint motored;
57      GLfloat angular_velocity;
58      GLint direction;
59  };
60
61
62struct GEAR
63  {
64    char name[20];
65    char type[7];
66      GLint face;
67      GLint id;
68      GLfloat radius;
69      GLfloat width;
70      GLint teeth;
71      GLfloat tooth_depth;
72      GLfloat angle;
73      GLfloat angular_velocity;
74      TDA color;
75      GLint relative_position;
76      TDA position;
77    char axle_name[20];
78      GLint axis;
79      GLint direction;
80      GLint motored;
81  };
82
83
84struct BELT
85  {
86    char name[20];
87      GLint id;
88    char gear1_name[20];
89    char gear2_name[20];
90  };
91
92
93FILE * mainfile;
94struct GEAR g[10];
95struct AXLE a[10];
96struct BELT b[10];
97int number_of_gears;
98int number_of_axles;
99int number_of_belts;
100
101
102char Buf1[256], Buf2[256], Buf3[256], Buf4[256], Buf5[256];
103
104static GLint T0 = 0;
105static GLint Frames = 0;
106
107
108static void
109Clear_Buffers (void)
110{
111    memset (Buf1, '\0', 256);
112    memset (Buf2, '\0', 256);
113    memset (Buf3, '\0', 256);
114    memset (Buf4, '\0', 256);
115    memset (Buf5, '\0', 256);
116}
117
118
119static void
120LoadTriplet (TDA A)
121{
122    int result;
123    Clear_Buffers ();
124    result = fscanf (mainfile, "%s %s %s %s", Buf1, Buf2, Buf3, Buf4);
125    assert(result != EOF);
126    A[0] = atof (Buf2);
127    A[1] = atof (Buf3);
128    A[2] = atof (Buf4);
129}
130
131
132static void
133LoadReal (float *a)
134{
135    int result;
136    Clear_Buffers ();
137    result = fscanf (mainfile, "%s %s", Buf1, Buf2);
138    assert(result != EOF);
139    *a = atof (Buf2);
140}
141
142
143static void
144LoadInteger (int *a)
145{
146    int result;
147    Clear_Buffers ();
148    result = fscanf (mainfile, "%s %s", Buf1, Buf2);
149    assert(result != EOF);
150    *a = atoi (Buf2);
151}
152
153
154static void
155LoadText (char *a)
156{
157    int result;
158    Clear_Buffers ();
159    result = fscanf (mainfile, "%s %s", Buf1, Buf2);
160    assert(result != EOF);
161    strcpy (a, Buf2);
162}
163
164
165static void
166getdata (char filename[])
167{
168    int gear_count = 0, axle_count = 0, belt_count = 0, i;
169
170    mainfile = fopen (filename, "r");
171    if (!mainfile) {
172       printf("Error: couldn't open %s\n", filename);
173       exit(-1);
174    }
175
176    do
177    {
178	int result;
179	Clear_Buffers ();
180	result = fscanf (mainfile, "%s", Buf1);
181	(void) result;
182	if (ferror (mainfile))
183	{
184	    printf ("\nError opening file !\n");
185	    exit (1);
186	}
187
188	if (!(strcmp (Buf1, "BACKGROUND")))
189	  LoadTriplet (background);
190
191	if (!(strcmp (Buf1, "ANAME")))
192	{
193	    LoadText (a[axle_count].name);
194	    axle_count++;
195	}
196
197	if (!(strcmp (Buf1, "ARADIUS")))
198	  LoadReal (&a[axle_count - 1].radius);
199
200	if (!(strcmp (Buf1, "AAXIS")))
201	  LoadInteger (&a[axle_count - 1].axis);
202
203	if (!(strcmp (Buf1, "ACOLOR")))
204	  LoadTriplet (a[axle_count - 1].color);
205
206	if (!(strcmp (Buf1, "APOSITION")))
207	  LoadTriplet (a[axle_count - 1].position);
208
209	if (!(strcmp (Buf1, "ALENGTH")))
210	  LoadReal (&a[axle_count - 1].length);
211
212	if (!(strcmp (Buf1, "AMOTORED")))
213	  LoadInteger (&a[axle_count - 1].motored);
214
215	if (!(strcmp (Buf1, "AANGULARVELOCITY")))
216	  LoadReal (&a[axle_count - 1].angular_velocity);
217
218	if (!(strcmp (Buf1, "ADIRECTION")))
219	  LoadInteger (&a[axle_count - 1].direction);
220
221	if (!(strcmp (Buf1, "GNAME")))
222	{
223	    LoadText (g[gear_count].name);
224	    gear_count++;
225	}
226
227	if (!(strcmp (Buf1, "GTYPE")))
228	  LoadText (g[gear_count - 1].type);
229
230	if (!(strcmp (Buf1, "GFACE")))
231	  LoadInteger (&g[gear_count - 1].face);
232
233	if (!(strcmp (Buf1, "GRADIUS")))
234	  LoadReal (&g[gear_count - 1].radius);
235
236	if (!(strcmp (Buf1, "GWIDTH")))
237	  LoadReal (&g[gear_count - 1].width);
238
239	if (!(strcmp (Buf1, "GTEETH")))
240	  LoadInteger (&g[gear_count - 1].teeth);
241
242	if (!(strcmp (Buf1, "GTOOTHDEPTH")))
243	  LoadReal (&g[gear_count - 1].tooth_depth);
244
245	if (!(strcmp (Buf1, "GCOLOR")))
246	  LoadTriplet (g[gear_count - 1].color);
247
248	if (!(strcmp (Buf1, "GAXLE")))
249	  LoadText (g[gear_count - 1].axle_name);
250
251	if (!(strcmp (Buf1, "GPOSITION")))
252	  LoadInteger (&g[gear_count - 1].relative_position);
253
254	if (!(strcmp (Buf1, "BELTNAME")))
255	{
256	    LoadText (b[belt_count].name);
257	    belt_count++;
258	}
259
260	if (!(strcmp (Buf1, "GEAR1NAME")))
261	  LoadText (b[belt_count - 1].gear1_name);
262
263	if (!(strcmp (Buf1, "GEAR2NAME")))
264	  LoadText (b[belt_count - 1].gear2_name);
265    }
266    while (Buf1[0] != 0);
267
268    number_of_gears = gear_count;
269    number_of_axles = axle_count;
270    number_of_belts = belt_count;
271
272    for (i = 0; i < number_of_gears; i++)
273    {
274	g[i].axis = -1;
275	g[i].direction = 0;
276	g[i].angular_velocity = 0.0;
277    }
278
279    fclose (mainfile);
280}
281
282
283static void
284axle (GLint j, GLfloat radius, GLfloat length)
285{
286    GLfloat angle, rad, incr = 10.0 * M_PI / 180.0;
287
288    /* draw main cylinder */
289    glBegin (GL_QUADS);
290    for (angle = 0.0; angle < 360.0; angle += 5.0)
291    {
292	rad = angle * M_PI / 180.0;
293	glNormal3f (cos (rad), sin (rad), 0.0);
294	glVertex3f (radius * cos (rad), radius * sin (rad), length / 2);
295	glVertex3f (radius * cos (rad), radius * sin (rad), -length / 2);
296	glVertex3f (radius * cos (rad + incr), radius * sin (rad + incr), -length / 2);
297	glVertex3f (radius * cos (rad + incr), radius * sin (rad + incr), length / 2);
298    }
299    glEnd ();
300
301    /* draw front face */
302    glNormal3f (0.0, 0.0, 1.0);
303    glBegin (GL_TRIANGLES);
304    for (angle = 0.0; angle < 360.0; angle += 5.0)
305    {
306	rad = angle * M_PI / 180.0;
307	glVertex3f (0.0, 0.0, length / 2);
308      	glVertex3f (radius * cos (rad), radius * sin (rad), length / 2);
309	glVertex3f (radius * cos (rad + incr), radius * sin (rad + incr), length / 2);
310	glVertex3f (0.0, 0.0, length / 2);
311    }
312    glEnd ();
313
314    /* draw back face */
315    glNormal3f (0.0, 0.0, -1.0);
316    glBegin (GL_TRIANGLES);
317    for (angle = 0.0; angle <= 360.0; angle += 5.0)
318    {
319	rad = angle * M_PI / 180.0;
320	glVertex3f (0.0, 0.0, -length / 2);
321	glVertex3f (radius * cos (rad), radius * sin (rad), -length / 2);
322	glVertex3f (radius * cos (rad + incr), radius * sin (rad + incr), -length / 2);
323	glVertex3f (0.0, 0.0, -length / 2);
324    }
325    glEnd ();
326}
327
328
329
330static void
331gear (GLint j, char type[], GLfloat radius, GLfloat width,
332      GLint teeth, GLfloat tooth_depth)
333{
334    GLint i;
335    GLfloat r1, r2_front, r2_back;
336    GLfloat angle, da;
337    GLfloat u, v, len, fraction = 0.5;
338    GLfloat n = 1.0;
339
340    r1 = radius - tooth_depth;
341    r2_front = r2_back = radius;
342
343    fraction = 0.5;
344    n = 1.0;
345
346    da = 2.0 * M_PI / teeth / 4.0;
347    if (!(strcmp (type, "BEVEL")))
348    {
349        if (g[j].face)
350            r2_front = radius - width;
351        else
352            r2_back = radius - width;
353    }
354
355    /* draw front face */
356	glNormal3f (0.0, 0.0, 1.0 * n);
357	glBegin (GL_QUAD_STRIP);
358	for (i = 0; i <= teeth; i++)
359	{
360	    angle = i * 2.0 * M_PI / teeth;
361	    glVertex3f (0.0, 0.0, width * fraction);
362	    glVertex3f (r1 * cos (angle), r1 * sin (angle), width * fraction);
363	    glVertex3f (0.0, 0.0, width * fraction);
364	    glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), width * fraction);
365	}
366	glEnd ();
367
368    /* draw front sides of teeth */
369	glNormal3f (0.0, 0.0, 1.0 * n);
370	glBegin (GL_QUADS);
371	da = 2.0 * M_PI / teeth / 4.0;
372	for (i = 0; i < teeth; i++)
373	{
374	    angle = i * 2.0 * M_PI / teeth;
375	    glVertex3f (r1 * cos (angle), r1 * sin (angle), width * fraction);
376	    glVertex3f (r2_front * cos (angle + da), r2_front * sin (angle + da), width * fraction);
377	    glVertex3f (r2_front * cos (angle + 2 * da), r2_front * sin (angle + 2 * da), width * fraction);
378	    glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), width * fraction);
379	}
380	glEnd ();
381
382    /* draw back face */
383    glNormal3f (0.0, 0.0, -1.0 * n);
384    glBegin (GL_QUAD_STRIP);
385    for (i = 0; i <= teeth; i++)
386    {
387	angle = i * 2.0 * M_PI / teeth;
388	glVertex3f (r1 * cos (angle), r1 * sin (angle), -width * fraction);
389	glVertex3f (0.0, 0.0, -width * fraction);
390	glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), -width * fraction);
391	glVertex3f (0.0, 0.0, -width * fraction);
392    }
393    glEnd ();
394
395    /* draw back sides of teeth */
396    glNormal3f (0.0, 0.0, -1.0 * n);
397    glBegin (GL_QUADS);
398    da = 2.0 * M_PI / teeth / 4.0;
399    for (i = 0; i < teeth; i++)
400    {
401	angle = i * 2.0 * M_PI / teeth;
402	glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), -width * fraction);
403	glVertex3f (r2_back * cos (angle + 2 * da), r2_back * sin (angle + 2 * da), -width * fraction);
404	glVertex3f (r2_back * cos (angle + da), r2_back * sin (angle + da), -width * fraction);
405	glVertex3f (r1 * cos (angle), r1 * sin (angle), -width * fraction);
406    }
407    glEnd ();
408
409
410    /* draw outward faces of teeth. The visible faces are the backfaces, for testing purposes */
411	glBegin (GL_QUAD_STRIP);
412	for (i = 0; i < teeth; i++)
413	{
414	    angle = i * 2.0 * M_PI / teeth;
415
416	    glNormal3f (-cos (angle - 0.5*da), -sin (angle - 0.5*da), 0.0);
417	    glVertex3f (r1 * cos (angle), r1 * sin (angle), -width * fraction);
418	    glVertex3f (r1 * cos (angle), r1 * sin (angle), width * fraction);
419	    u = (r2_front+r2_back)/2.0 * cos (angle + da) - r1 * cos (angle);
420	    v = (r2_front+r2_back)/2.0 * sin (angle + da) - r1 * sin (angle);
421	    len = sqrt (u * u + v * v);
422	    u /= len;
423	    v /= len;
424	    glNormal3f (-v, u, 0.0);
425	    glVertex3f (r2_back * cos (angle + da), r2_back * sin (angle + da), -width * fraction);
426	    glVertex3f (r2_front * cos (angle + da), r2_front * sin (angle + da), width * fraction);
427	    glNormal3f (-cos (angle + 1.5*da), -sin (angle + 1.5*da), 0.0);
428	    glVertex3f (r2_back * cos (angle + 2 * da), r2_back * sin (angle + 2 * da), -width * fraction);
429	    glVertex3f (r2_front * cos (angle + 2 * da), r2_front * sin (angle + 2 * da), width * fraction);
430	    u = r1 * cos (angle + 3 * da) - (r2_front+r2_back)/2.0 * cos (angle + 2 * da);
431	    v = r1 * sin (angle + 3 * da) - (r2_front+r2_back)/2.0 * sin (angle + 2 * da);
432	    len = sqrt (u * u + v * v);
433	    u /= len;
434	    v /= len;
435	    glNormal3f (-v, u, 0.0);
436	    glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), -width * fraction);
437	    glVertex3f (r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da), width * fraction);
438	    glNormal3f (-cos (angle + 3.5*da), -sin (angle + 3.5*da), 0.0);
439	}
440
441    glNormal3f (-cos (-0.5*da), -sin (-0.5*da), 0.0);
442    glVertex3f (r1 * cos (0), r1 * sin (0), -width * fraction);
443    glVertex3f (r1 * cos (0), r1 * sin (0), width * fraction);
444    glEnd ();
445}
446
447
448static void
449belt (struct GEAR g1, struct GEAR g2)
450{
451    GLfloat D, alpha, phi, angle, incr, width;
452    GLint indexes[3] =
453    {
454       0, 0, 0
455    };
456
457    GLfloat col[3] =
458    {
459       0.0, 0.0, 0.0
460    };
461
462    width = min (g1.width, g2.width);
463    D = sqrt (pow (g1.position[0] - g2.position[0], 2) + pow (g1.position[1] - g2.position[1], 2) + pow (g1.position[2] - g2.position[2], 2));
464    alpha = acos ((g2.position[0] - g1.position[0]) / D);
465    phi = acos ((g1.radius - g2.radius) / D);
466    glBegin (GL_QUADS);
467    glColor3fv (col);
468    glMaterialiv (GL_FRONT, GL_COLOR_INDEXES, indexes);
469    incr = 1.2 * 360.0 / g1.teeth * M_PI / 180.00;
470    for (angle = alpha + phi; angle <= 2 * M_PI - phi + alpha; angle += 360.0 / g1.teeth * M_PI / 180.00)
471    {
472	glNormal3f (cos (angle), sin (angle), 0.0);
473	glVertex3f (g1.radius * cos (angle), g1.radius * sin (angle), width * 0.5);
474	glVertex3f (g1.radius * cos (angle), g1.radius * sin (angle), -width * 0.5);
475	glVertex3f (g1.radius * cos (angle + incr), g1.radius * sin (angle + incr), -width * 0.5);
476	glVertex3f (g1.radius * cos (angle + incr), g1.radius * sin (angle + incr), width * 0.5);
477    }
478    glEnd ();
479    glBegin (GL_QUADS);
480    glColor3fv (col);
481    glMaterialiv (GL_FRONT, GL_COLOR_INDEXES, indexes);
482    incr = 1.2 * 360.0 / g2.teeth * M_PI / 180.00;
483    for (angle = -phi + alpha; angle <= phi + alpha; angle += 360.0 / g1.teeth * M_PI / 180.0)
484    {
485	glNormal3f (cos (angle), sin (angle), 0.0);
486	glVertex3f (g2.radius * cos (angle) + g2.position[0] - g1.position[0], g2.radius * sin (angle) + g2.position[1] - g1.position[1], width * 0.5);
487	glVertex3f (g2.radius * cos (angle) + g2.position[0] - g1.position[0], g2.radius * sin (angle) + g2.position[1] - g1.position[1], width * -0.5);
488	glVertex3f (g2.radius * cos (angle + incr) + g2.position[0] - g1.position[0], g2.radius * sin (angle + incr) + g2.position[1] - g1.position[1], width * -0.5);
489	glVertex3f (g2.radius * cos (angle + incr) + g2.position[0] - g1.position[0], g2.radius * sin (angle + incr) + g2.position[1] - g1.position[1], width * 0.5);
490    }
491    glEnd ();
492
493    glBegin (GL_QUADS);
494    glColor3fv (col);
495    glMaterialiv (GL_FRONT, GL_COLOR_INDEXES, indexes);
496    glVertex3f (g1.radius * cos (alpha + phi), g1.radius * sin (alpha + phi), width * 0.5);
497    glVertex3f (g1.radius * cos (alpha + phi), g1.radius * sin (alpha + phi), width * -0.5);
498    glVertex3f (g2.radius * cos (alpha + phi) + g2.position[0] - g1.position[0], g2.radius * sin (alpha + phi) + g2.position[1] - g1.position[1], width * -0.5);
499    glVertex3f (g2.radius * cos (alpha + phi) + g2.position[0] - g1.position[0], g2.radius * sin (alpha + phi) + g2.position[1] - g1.position[1], width * 0.5);
500    glVertex3f (g1.radius * cos (alpha - phi), g1.radius * sin (alpha - phi), width * 0.5);
501    glVertex3f (g1.radius * cos (alpha - phi), g1.radius * sin (alpha - phi), width * -0.5);
502    glVertex3f (g2.radius * cos (alpha - phi) + g2.position[0] - g1.position[0], g2.radius * sin (alpha - phi) + g2.position[1] - g1.position[1], width * -0.5);
503    glVertex3f (g2.radius * cos (alpha - phi) + g2.position[0] - g1.position[0], g2.radius * sin (alpha - phi) + g2.position[1] - g1.position[1], width * 0.5);
504    glEnd ();
505}
506
507
508static int
509axle_find (char axle_name[])
510{
511    int i;
512
513    for (i = 0; i < number_of_axles; i++)
514    {
515	if (!(strcmp (axle_name, a[i].name)))
516           break;
517    }
518    return i;
519}
520
521
522static int
523gear_find (char gear_name[])
524{
525    int i;
526
527    for (i = 0; i < number_of_gears; i++)
528    {
529	if (!(strcmp (gear_name, g[i].name)))
530           break;
531    }
532    return i;
533}
534
535
536static void
537process (void)
538{
539    GLfloat x, y, z, D, dist;
540    GLint axle_index, i, j, g1, g2, k;
541
542    for (i = 0; i < number_of_gears; i++)
543    {
544	x = 0.0;
545	y = 0.0;
546	z = 0.0;
547	axle_index = axle_find (g[i].axle_name);
548	g[i].axis = a[axle_index].axis;
549	g[i].motored = a[axle_index].motored;
550	if (a[axle_index].motored)
551	{
552	    g[i].direction = a[axle_index].direction;
553	    g[i].angular_velocity = a[axle_index].angular_velocity;
554	}
555	if (g[i].axis == 0)
556           x = 1.0;
557        else if (g[i].axis == 1)
558           y = 1.0;
559        else
560           z = 1.0;
561
562	g[i].position[0] = a[axle_index].position[0] + x * g[i].relative_position;
563	g[i].position[1] = a[axle_index].position[1] + y * g[i].relative_position;
564	g[i].position[2] = a[axle_index].position[2] + z * g[i].relative_position;
565    }
566
567    for (k = 0; k < number_of_axles; k++)
568    {
569	for (i = 0; i < number_of_gears - 1; i++)
570	{
571	    for (j = 0; j < number_of_gears; j++)
572	    {
573		if (!(strcmp (g[i].type, g[j].type)) && (!(strcmp (g[i].type, "NORMAL"))) && ((strcmp (g[i].axle_name, g[j].axle_name) != 0)) && (g[i].axis == g[j].axis))
574		{
575		    D = sqrt (pow (g[i].position[0] - g[j].position[0], 2) + pow (g[i].position[1] - g[j].position[1], 2) + pow (g[i].position[2] - g[j].position[2], 2));
576		    if (D < 1.1 * (g[i].radius - g[i].tooth_depth + g[j].radius - g[j].tooth_depth))
577		    {
578			printf ("Gear %s and %s are too close to each other.", g[i].name, g[j].name);
579			exit (1);
580		    }
581
582		    if (g[i].axis == 0)
583		    {
584			dist = g[i].position[0] - g[j].position[0];
585		    }
586		    else if (g[i].axis == 1)
587		    {
588			dist = g[i].position[1] - g[j].position[1];
589		    }
590		    else
591                       dist = g[i].position[2] - g[j].position[2];
592
593		    dist = fabs (dist);
594
595		    if (dist < (g[i].width / 2 + g[j].width / 2))
596		    {
597			if ((g[i].motored) && (!(g[j].motored)) && (D < 0.95 * (g[i].radius + g[j].radius)))
598			{
599			    axle_index = axle_find (g[j].axle_name);
600			    if ((a[axle_index].direction != 0) && (g[j].angular_velocity != g[i].angular_velocity * g[i].teeth / g[j].teeth * g[i].radius / g[j].radius))
601			    {
602				printf ("Error in tooth linkage of gears %s and %s.", g[i].name, g[j].name);
603				exit (1);
604			    }
605
606			    g[j].motored = (a[axle_index].motored = 1);
607			    g[j].direction = (a[axle_index].direction = -g[i].direction);
608			    a[axle_index].angular_velocity = g[i].angular_velocity * g[i].teeth / g[j].teeth;
609			    g[j].angular_velocity = (a[axle_index].angular_velocity *= g[i].radius / g[j].radius);
610			}
611
612			if ((!(g[i].motored)) && (g[j].motored) && (D < 0.95 * (g[i].radius + g[j].radius)))
613			{
614			    axle_index = axle_find (g[i].axle_name);
615			    if ((a[axle_index].direction != 0) && (g[i].angular_velocity != g[j].angular_velocity * g[j].teeth / g[i].teeth * g[j].radius / g[i].radius))
616			    {
617				printf ("Error in tooth linkage of gears %s and %s.", g[i].name, g[j].name);
618				exit (1);
619			    }
620
621			    g[i].motored = (a[axle_index].motored = 1);
622			    g[i].direction = (a[axle_index].direction = -g[j].direction);
623			    a[axle_index].angular_velocity = g[j].angular_velocity * g[j].teeth / g[i].teeth;
624			    g[i].angular_velocity = (a[axle_index].angular_velocity *= g[j].radius / g[i].radius);
625
626			}
627		    }
628		}
629
630		if (!(strcmp (g[i].type, g[j].type)) && (!(strcmp (g[i].type, "BEVEL"))) && ((strcmp (g[i].axle_name, g[j].axle_name) != 0)) && (g[i].axis != g[j].axis))
631		{
632		    D = sqrt (pow (g[i].position[0] - g[j].position[0], 2) + pow (g[i].position[1] - g[j].position[1], 2) + pow (g[i].position[2] - g[j].position[2], 2));
633		    if ((g[i].motored) && (!(g[j].motored)) && (D < 0.95 * sqrt (g[i].radius * g[i].radius + g[j].radius * g[j].radius)))
634		    {
635			axle_index = axle_find (g[j].axle_name);
636			if ((a[axle_index].direction != 0) && (g[j].angular_velocity != g[i].angular_velocity * g[i].teeth / g[j].teeth * g[i].radius / g[j].radius))
637			{
638			    printf ("Error in tooth linkage of gears %s and %s.", g[i].name, g[j].name);
639			    exit (1);
640			}
641			g[j].motored = (a[axle_index].motored = 1);
642			g[j].direction = (a[axle_index].direction = -g[i].direction);
643			a[axle_index].angular_velocity = g[i].angular_velocity * g[i].teeth / g[j].teeth;
644			g[j].angular_velocity = (a[axle_index].angular_velocity *= g[i].radius / g[j].radius);
645		    }
646
647
648		    if ((!(g[i].motored)) && (g[j].motored) && (D < 0.95 * sqrt (g[i].radius * g[i].radius + g[j].radius * g[j].radius)))
649		    {
650			axle_index = axle_find (g[i].axle_name);
651			if ((a[axle_index].direction != 0) && (g[i].angular_velocity != g[j].angular_velocity * g[j].teeth / g[i].teeth * g[j].radius / g[i].radius))
652			{
653			    printf ("Error in tooth linkage of gears %s and %s.", g[i].name, g[j].name);
654			    exit (1);
655			}
656			g[i].motored = (a[axle_index].motored = 1);
657			g[i].direction = (a[axle_index].direction = -g[j].direction);
658			a[axle_index].angular_velocity = g[j].angular_velocity * g[j].teeth / g[i].teeth;
659			g[i].angular_velocity = (a[axle_index].angular_velocity *= g[j].radius / g[i].radius);
660		    }
661		}
662	    }
663	}
664
665	for (i = 0; i < number_of_gears; i++)
666	{
667	    axle_index = axle_find (g[i].axle_name);
668	    g[i].motored = a[axle_index].motored;
669	    if (a[axle_index].motored)
670	    {
671		g[i].direction = a[axle_index].direction;
672		g[i].angular_velocity = a[axle_index].angular_velocity;
673	    }
674	}
675
676	for (i = 0; i < number_of_belts; i++)
677	{
678	    g1 = gear_find (b[i].gear1_name);
679	    g2 = gear_find (b[i].gear2_name);
680	    D = sqrt (pow (g[g1].position[0] - g[g2].position[0], 2) + pow (g[g1].position[1] - g[g2].position[1], 2) + pow (g[g1].position[2] - g[g2].position[2], 2));
681	    if (!((g[g1].axis == g[g2].axis) && (!strcmp (g[g1].type, g[g2].type)) && (!strcmp (g[g1].type, "NORMAL"))))
682	    {
683		printf ("Belt %s invalid.", b[i].name);
684		exit (1);
685	    }
686
687	    if ((g[g1].axis == g[g2].axis) && (!strcmp (g[g1].type, g[g2].type)) && (!strcmp (g[g1].type, "NORMAL")))
688	    {
689	      /*
690	         if((g[g1].motored)&&(g[g2].motored))
691	         if(g[g2].angular_velocity!=(g[g1].angular_velocity*g[g1].radius/g[g2].radius))
692	         {
693	         printf("Error in belt linkage of gears %s and %s".,g[g1].name,g[g2].name);
694	         exit(1);
695	         }
696              */
697               if (g[g1].axis == 0)
698                  {
699		    dist = g[g1].position[0] - g[g2].position[0];
700		}
701		else if (g[i].axis == 1)
702		{
703		    dist = g[g1].position[1] - g[g2].position[1];
704		}
705		else
706                   dist = g[g1].position[2] - g[g2].position[2];
707
708		dist = fabs (dist);
709
710		if (dist > (g[g1].width / 2 + g[g2].width / 2))
711		{
712		    printf ("Belt %s invalid.", b[i].name);
713		    exit (1);
714		}
715
716		if (dist < (g[g1].width / 2 + g[g2].width / 2))
717		{
718		    if (D < g[g1].radius + g[g2].radius)
719		    {
720			printf ("Gears %s and %s too close to be linked with belts", g[g1].name, g[g2].name);
721			exit (1);
722		    }
723
724		    if ((g[g1].motored) && (!(g[g2].motored)))
725		    {
726			axle_index = axle_find (g[g2].axle_name);
727			g[g2].motored = (a[axle_index].motored = 1);
728			g[g2].direction = (a[axle_index].direction = g[g1].direction);
729			g[g2].angular_velocity = (a[axle_index].angular_velocity = g[g1].angular_velocity * g[g1].radius / g[g2].radius);
730		    }
731
732		    if ((!(g[g1].motored)) && (g[g2].motored))
733		    {
734			axle_index = axle_find (g[g1].axle_name);
735			g[g1].motored = (a[axle_index].motored = 1);
736			g[g1].direction = (a[axle_index].direction = g[g2].direction);
737			g[g1].angular_velocity = (a[axle_index].angular_velocity = g[g2].angular_velocity * g[g2].radius / g[g1].radius);
738		    }
739		}
740	    }
741	}
742
743	for (i = 0; i < number_of_gears; i++)
744	{
745	    axle_index = axle_find (g[i].axle_name);
746	    g[i].motored = a[axle_index].motored;
747	    if (a[axle_index].motored)
748	    {
749		g[i].direction = a[axle_index].direction;
750		g[i].angular_velocity = a[axle_index].angular_velocity;
751	    }
752	}
753    }
754}
755
756
757
758GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 10.0;
759
760
761static void
762draw (void)
763{
764    int i;
765    GLfloat x, y, z;
766    int index;
767
768    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
769
770    glPushMatrix ();
771    glRotatef (view_rotx, 1.0, 0.0, 0.0);
772    glRotatef (view_roty, 0.0, 1.0, 0.0);
773    glRotatef (view_rotz, 0.0, 0.0, 1.0);
774
775    for (i = 0; i < number_of_gears; i++)
776    {
777	x = 0.0;
778	y = 0.0;
779	z = 0.0;
780	glPushMatrix ();
781/*glTranslatef( -3.0, -2.0, 0.0 );*/
782	glTranslatef (g[i].position[0], g[i].position[1], g[i].position[2]);
783	if (g[i].axis == 0)
784           y = 1.0;
785        else if (g[i].axis == 1)
786           x = 1.0;
787        else
788           z = 1.0;
789
790	if (z != 1.0)
791           glRotatef (90.0, x, y, z);
792
793	glRotatef (g[i].direction * g[i].angle, 0.0, 0.0, 1.0);
794	glCallList (g[i].id);
795	glPopMatrix ();
796    }
797
798    for (i = 0; i < number_of_axles; i++)
799    {
800	x = 0.0;
801	y = 0.0;
802	z = 0.0;
803	glPushMatrix ();
804	glTranslatef (a[i].position[0], a[i].position[1], a[i].position[2]);
805	if (a[i].axis == 0)
806           y = 1.0;
807        else if (a[i].axis == 1)
808           x = 1.0;
809        else
810           z = 1.0;
811
812	if (z != 1.0)
813           glRotatef (90.0, x, y, z);
814
815	glCallList (a[i].id);
816	glPopMatrix ();
817    }
818
819    for (i = 0; i < number_of_belts; i++)
820    {
821	x = 0.0;
822	y = 0.0;
823	z = 0.0;
824	glPushMatrix ();
825	index = gear_find (b[i].gear1_name);
826	glTranslatef (g[index].position[0], g[index].position[1], g[index].position[2]);
827	if (g[index].axis == 0)
828           y = 1.0;
829        else if (g[index].axis == 1)
830           x = 1.0;
831        else
832           z = 1.0;
833
834	if (z != 1.0)
835           glRotatef (90.0, x, y, z);
836
837	glCallList (b[i].id);
838	glPopMatrix ();
839    }
840
841    glPopMatrix ();
842    glutSwapBuffers ();
843
844    {
845	GLint t = glutGet(GLUT_ELAPSED_TIME);
846	Frames++;
847	if (t - T0 >= 5000) {
848	    GLfloat seconds = (t - T0) / 1000.0;
849	    GLfloat fps = Frames / seconds;
850	    printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
851            fflush(stdout);
852	    T0 = t;
853	    Frames = 0;
854	}
855    }
856}
857
858
859static void
860idle (void)
861{
862    int i;
863    static double t0 = -1.;
864    double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
865    if (t0 < 0.0)
866       t0 = t;
867    dt = t - t0;
868    t0 = t;
869    for (i = 0; i < number_of_gears; i++)
870      g[i].angle += g[i].angular_velocity * dt;
871    glutPostRedisplay();
872}
873
874
875
876
877/* change view angle, exit upon ESC */
878static void
879key (unsigned char k, int x, int y)
880{
881    switch (k)
882    {
883    case 'x':
884	view_rotx += 5.0;
885        break;
886    case 'X':
887	view_rotx -= 5.0;
888        break;
889    case 'y':
890	view_roty += 5.0;
891        break;
892    case 'Y':
893	view_roty -= 5.0;
894        break;
895    case 'z':
896	view_rotz += 5.0;
897        break;
898    case 'Z':
899	view_rotz -= 5.0;
900        break;
901    case 0x1B:
902	exit(0);
903    }
904}
905
906
907
908
909/* new window size or exposure */
910static void
911reshape (int width, int height)
912{
913    glViewport (0, 0, (GLint) width, (GLint) height);
914    glMatrixMode (GL_PROJECTION);
915    glLoadIdentity ();
916    if (width > height)
917    {
918	GLfloat w = (GLfloat) width / (GLfloat) height;
919	glFrustum (-w, w, -1.0, 1.0, 5.0, 60.0);
920    }
921    else
922    {
923	GLfloat h = (GLfloat) height / (GLfloat) width;
924	glFrustum (-1.0, 1.0, -h, h, 5.0, 60.0);
925    }
926
927    glMatrixMode (GL_MODELVIEW);
928    glLoadIdentity ();
929    glTranslatef (0.0, 0.0, -40.0);
930    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
931}
932
933
934
935static void
936init (void)
937{
938    GLfloat matShine = 20.00F;
939    const GLfloat light0Pos[4] =
940    {
941       0.70F, 0.70F, 1.25F, 0.50F
942    };
943    int i;
944
945    glShadeModel(GL_FLAT);
946    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
947
948    glClearColor (background[0], background[1], background[2], 1.0F);
949    glClearIndex ((GLfloat) 0.0);
950
951    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, matShine);
952    glLightfv (GL_LIGHT0, GL_POSITION, light0Pos);
953    glEnable (GL_LIGHT0);
954
955    glEnable (GL_LIGHTING);
956    glEnable (GL_DEPTH_TEST);
957    for (i = 0; i < number_of_gears; i++)
958      g[i].angle = 0.0;
959
960    for (i = 0; i < number_of_gears; i++)
961    {
962	g[i].id = glGenLists (1);
963	glNewList (g[i].id, GL_COMPILE);
964	glColor3fv (g[i].color);
965	glMaterialfv (GL_FRONT, GL_SPECULAR, g[i].color);
966	gear (i, g[i].type, g[i].radius, g[i].width, g[i].teeth, g[i].tooth_depth);
967	glEndList ();
968    }
969
970    for (i = 0; i < number_of_axles; i++)
971    {
972	a[i].id = glGenLists (1);
973	glNewList (a[i].id, GL_COMPILE);
974	glColor3fv (a[i].color);
975	glMaterialfv (GL_FRONT, GL_SPECULAR, a[i].color);
976	axle (i, a[i].radius, a[i].length);
977	glEndList ();
978    }
979
980    for (i = 0; i < number_of_belts; i++)
981    {
982	b[i].id = glGenLists (1);
983	glNewList (b[i].id, GL_COMPILE);
984	belt (g[gear_find (b[i].gear1_name)], g[gear_find (b[i].gear2_name)]);
985	glEndList ();
986    }
987
988    glEnable (GL_COLOR_MATERIAL);
989}
990
991
992
993int
994main (int argc, char *argv[])
995{
996    char *file;
997
998    glutInitWindowSize(640,480);
999    glutInit(&argc, argv);
1000    glutInitDisplayMode (GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
1001
1002    if (glutCreateWindow ("Gear Train Simulation") == GL_FALSE)
1003      exit (1);
1004
1005    if (argc < 2)
1006       file = DEMOS_DATA_DIR "geartrain.dat";
1007    else
1008       file = argv[1];
1009
1010    getdata (file);
1011    process ();
1012    init ();
1013
1014    glutDisplayFunc (draw);
1015    glutReshapeFunc (reshape);
1016    glutKeyboardFunc (key);
1017    glutIdleFunc (idle);
1018    glutMainLoop ();
1019    return 0;
1020}
1021