Attachment 'ss5.c'
Download 1 // ss5.c
2 // gcc -o ss5 ss5.c -lm -lgd
3 //
4 // The perspective sucks
5 // The light pressure of tilted thrusters is treated here as constant.
6 // The actual light pressure is proportional to cos^2( sun angle )
7 // This assumes a 4:3 ratio, with gauges down the right side
8
9 #define GIFOUT "ss5.gif"
10 #define FNT "DejaVuMonoSans"
11 #define SCALE 0.09 // size of serversat
12
13 #define FSZ 20 // this scales the font and the whole drawing
14
15 #define Z0 25.0 // depth scaling for cheesy perspective
16 #define ACC 8 // acceleration in degrees/minute^2
17 #define TSTART 0
18 #define TIME1 150 // acceleration time in seconds
19 #define TEND 300
20 #define TDELTA 15 // display timestep
21 #define ASTEP0 400 // starting and ending hold times
22 #define ASTEP1 80 // image rate (1.25 images/second )
23 #define NSTARS 500 // background stars (this shows transparency)
24 #define MOVE 0.3 // how much the background stars move
25
26 #define LINETHICK 1
27 #define XSIZE 40*FSZ
28 #define YSIZE 30*FSZ
29 #define MINUTE 60
30 #define HOUR 3600
31
32 #include "gd.h"
33 #include <math.h>
34 #include <string.h>
35 #include <stdlib.h>
36
37 #define PI 3.14159265359
38 #define DEG2RAD(x) ((x)*PI/180.)
39
40 // #define WIRING 1 // show solar cell wires
41
42 gdImagePtr im0, im1, im;
43 int black, white, gray, dgray, trans ;
44 int xgauge = ( XSIZE + YSIZE ) / 2 ; // down the right edge
45 double scale = SCALE * YSIZE ; // scale serversat in pixels
46
47 // starting values
48 double anglerad = 0.0 ;
49 double time = 0.0 ;
50 double angle_vel = 0.0 ;
51 double angle_acc = 0.0 ;
52 double angle = 0.0 ;
53
54 double min_vel = 0.0 ;
55 double max_vel = ACC * TIME1 / MINUTE ;
56 double angle_min = 0.0 ;
57 double angle_max = ACC * TIME1 * TIME1 / ( MINUTE * MINUTE ) ;
58 double min_acc = -ACC ;
59 double max_acc = ACC ;
60
61 //--------------------------------------------------------------------
62 // fixed rectangle subroutines, swap order if needed
63 // gdImageRectangle silently fails unless it gets left, bottom, right, top
64
65 void RectE( gdImagePtr imm,
66 double rx1, double ry1, double rx2, double ry2, int rcolor ) {
67 if( rx1 < rx2 ) {
68 if( ry1 < ry2 ) {
69 gdImageRectangle( imm, rx1, ry1, rx2, ry2, rcolor );
70 } else {
71 gdImageRectangle( imm, rx1, ry2, rx2, ry1, rcolor );
72 }
73 } else {
74 if( ry1 < ry2 ) {
75 gdImageRectangle( imm, rx2, ry1, rx1, ry2, rcolor );
76 } else {
77 gdImageRectangle( imm, rx2, ry2, rx1, ry1, rcolor );
78 }
79 }
80 }
81
82
83 void RectF( gdImagePtr imm,
84 double rx1, double ry1, double rx2, double ry2, int rcolor ) {
85 if( rx1 < rx2 ) {
86 if( ry1 < ry2 ) {
87 gdImageFilledRectangle( imm, rx1, ry1, rx2, ry2, rcolor );
88 } else {
89 gdImageFilledRectangle( imm, rx1, ry2, rx2, ry1, rcolor );
90 }
91 } else {
92 if( ry1 < ry2 ) {
93 gdImageFilledRectangle( imm, rx2, ry1, rx1, ry2, rcolor );
94 } else {
95 gdImageFilledRectangle( imm, rx2, ry2, rx1, ry1, rcolor );
96 }
97 }
98 }
99
100
101 //--------------------------------------------------------------------
102 // rotation, transformation, scaling --------
103 //
104 // This is very weak. I would love to be able to make multiple
105 // rotations of a serversat along multiple axes.
106
107 gdPoint sr( double inx, double iny, double inz ) {
108 gdPoint retvar ;
109
110 // rotate, IN ONE PLANE ONLY
111 // z is into the plane, away from observer
112 double rx = inx ;
113 double ry = iny * cos( anglerad ) - inz * sin( anglerad ) ;
114 double rz = iny * sin( anglerad ) + inz * cos( anglerad ) ;
115
116 // depth transform - THIS IS PROBABLY INCORRECT
117 double trx = rx*(1.0+rz/Z0) ;
118 double try = ry*(1.0+rz/Z0) ;
119
120 retvar.x = (int) ( 0.5*YSIZE + scale * trx ) ;
121 retvar.y = (int) ( 0.5*YSIZE - scale * try ) ;
122
123 return retvar;
124 }
125
126 // draw random star field and move it with time ----------------------------
127 // uses all globals
128
129 // star array, overlaps right edge, unscaled
130 double starx[NSTARS], stary[NSTARS];
131
132 void
133 makestars() {
134 int nstar ;
135 for( nstar = 0 ; nstar < NSTARS ; nstar++ ) {
136 starx[nstar] = drand48() * ( XSIZE + MOVE*TEND ) ;
137 stary[nstar] = drand48() * YSIZE ;
138 }
139 }
140
141
142 void
143 drawstars() {
144 int nstar, xs, ys ;
145 for( nstar = 0 ; nstar < NSTARS ; nstar++ ) {
146 xs = (int) ( starx[nstar] - MOVE*time ) ;
147 ys = (int) stary[nstar] ;
148 if ( xs < YSIZE ) {
149 gdImageSetPixel( im, xs, ys, white);
150 }
151 }
152 }
153
154 // draw gauges ---------------------------------
155 // uses globals
156
157 #define YCLOCK (4*FSZ)
158 #define YACC (10*FSZ)
159 #define YVEL (16*FSZ)
160 #define YANG (22*FSZ)
161 #define F2 (4*FSZ/5)
162 #define F4 (FSZ/4)
163
164 #define RCLOCK (3*FSZ+8)
165 #define SECHAND (3*FSZ)
166 #define MINHAND1 (2*FSZ)
167 #define MINHAND2 (2*FSZ+5)
168 #define MINWID 40
169
170 int gleft = YSIZE + 2*FSZ ;
171 int gright = XSIZE - 2*FSZ ;
172
173
174 int gscale( double gvar, double gmin, double gmax ) {
175 return ( (int) ( gleft + (gvar-gmin)
176 * ( (double)(gright-gleft))/(gmax-gmin) ) ) ;
177 }
178
179 void drawgauges() {
180
181 double wangle ; // working angle
182 int cx1, cy1, cx2, cy2 ;
183 char s[80];
184 int ic ;
185
186 // clock at xgauge, 100 -----------------------------
187
188 gdImageArc( im, xgauge, YCLOCK, 2*RCLOCK, 2*RCLOCK, 0, 360, white );
189
190 // clock / 60
191 for( ic = 0; ic < 60 ; ic += 1 ) {
192 wangle = PI * ic / 30 ;
193 if ( ic%15 == 0 ) {
194 cx1 = xgauge + (int)(0.5 + (RCLOCK-6)*sin(wangle)) ;
195 cy1 = YCLOCK - (int)(0.5 + (RCLOCK-6)*cos(wangle)) ;
196 }
197 else if( ic%5 == 0 ) {
198 cx1 = xgauge + (int)(0.5 + (RCLOCK-4)*sin(wangle)) ;
199 cy1 = YCLOCK - (int)(0.5 + (RCLOCK-4)*cos(wangle)) ;
200 }
201 else {
202 cx1 = xgauge + (int)(0.5 + (RCLOCK-2)*sin(wangle)) ;
203 cy1 = YCLOCK - (int)(0.5 + (RCLOCK-2)*cos(wangle)) ;
204 }
205 cx2 = xgauge + (int)(0.5 + RCLOCK *sin(wangle) ) ;
206 cy2 = YCLOCK - (int)(0.5 + RCLOCK *cos(wangle) ) ;
207 gdImageLine( im, cx1, cy1, cx2, cy2, white ) ;
208 }
209
210 // second hand
211 wangle = 2.0 * PI * time / MINUTE ;
212 cx1 = xgauge+(int)(0.5 + SECHAND*sin(wangle) ) ;
213 cy1 = YCLOCK-(int)(0.5 + SECHAND*cos(wangle) ) ;
214 gdImageLine( im, xgauge, YCLOCK, cx1, cy1, white ) ;
215
216
217 // minute hand (two strokes )
218 wangle = 2.0 * PI * (time + MINWID) / HOUR ;
219 cx1 = xgauge+(int)(0.5 + MINHAND1*sin(wangle) ) ;
220 cy1 = YCLOCK-(int)(0.5 + MINHAND1*cos(wangle) ) ;
221
222 wangle = 2.0 * PI * (time ) / HOUR ;
223 cx2 = xgauge+(int)(0.5 + MINHAND2*sin(wangle) ) ;
224 cy2 = YCLOCK-(int)(0.5 + MINHAND2*cos(wangle) ) ;
225 gdImageLine( im, xgauge, YCLOCK, cx1, cy1, white ) ;
226 gdImageLine( im, cx2, cy2, cx1, cy1, white );
227
228 wangle = 2.0 * PI * (time - MINWID) / HOUR ;
229 cx1 = xgauge+(int)(0.5 + MINHAND1*sin(wangle) ) ;
230 cy1 = YCLOCK-(int)(0.5 + MINHAND1*cos(wangle) ) ;
231 gdImageLine( im, cx2, cy2, cx1, cy1, white );
232 gdImageLine( im, xgauge, YCLOCK, cx1, cy1, white ) ;
233
234 // text clock
235
236 sprintf( s, "%3.0f secs", time );
237 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, xgauge-2*FSZ, 9*FSZ, s );
238
239 // angular acceleration gauge ----------------
240
241 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0,
242 YSIZE, YACC+2*FSZ-F4, "acceleration" );
243 gdImageStringFT( im, NULL, white, FNT, F2, 0.0,
244 YSIZE, YACC+5*FSZ, "degrees/min^2" );
245
246
247 sprintf( s, "%2.0f", min_acc );
248 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, YSIZE, YACC+4*FSZ, s );
249
250 sprintf( s, "%2.0f", max_acc );
251 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, gright+F4, YACC+4*FSZ, s );
252
253 cx1 = gscale( angle_acc, min_acc, max_acc ) ;
254 cx2 = gscale( 0, min_acc, max_acc ) ;
255 RectE( im, gleft, YACC+2*FSZ, gright, YACC+4*FSZ, white );
256 RectF( im, cx1, YACC+2*FSZ, cx2, YACC+4*FSZ, white );
257
258 // angular velocity gauge ---------------------
259
260 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0,
261 YSIZE, YVEL+2*FSZ-F4, "velocity" );
262 gdImageStringFT( im, NULL, white, FNT, F2, 0.0,
263 YSIZE, YVEL+5*FSZ, "degrees/min" );
264
265 sprintf( s, "%2.0f", min_vel );
266 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, YSIZE, YVEL+4*FSZ, s );
267
268 sprintf( s, "%2.0f", max_vel );
269 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, gright+F4, YVEL+4*FSZ, s );
270
271 cx1 = gscale( angle_vel, min_vel, max_vel ) ;
272 cx2 = gscale( 0, min_vel, max_vel ) ;
273 RectE( im, gleft, YVEL+2*FSZ, gright, YVEL+4*FSZ, white );
274 RectF( im, cx1, YVEL+2*FSZ, cx2, YVEL+4*FSZ, white );
275
276 // angle gauge -------------------------------
277
278 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0,
279 YSIZE, YANG+2*FSZ-F4, "angle" );
280 gdImageStringFT( im, NULL, white, FNT, F2, 0.0,
281 YSIZE, YANG+5*FSZ, "degrees" );
282
283 sprintf( s, "%2.0f", angle_min );
284 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, YSIZE, YANG+4*FSZ, s );
285
286 sprintf( s, "%2.0f", angle_max );
287 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0, gright+F4, YANG+4*FSZ, s );
288
289 cx1 = gscale( angle, angle_min, angle_max ) ;
290 cx2 = gscale( 0, angle_min, angle_max ) ;
291 RectE( im, gleft, YANG+2*FSZ, gright, YANG+4*FSZ, white );
292 RectF( im, cx1, YANG+2*FSZ, cx2, YANG+4*FSZ, white );
293 }
294
295
296 // draw circle ---------------------------------
297 // uses some globals
298 // fill inner circle with area factor "fill"
299 // draw outer circle with full radius
300 // used for main solar cell, and thrusters
301
302 #define NPTS 100
303 gdPoint pointsf[NPTS]; // filled circle points
304 gdPoint pointse[NPTS]; // edge circle points
305
306 void drawcircle( int color, double fill,
307 double centerx, double centery, double radius ) {
308
309 int cntr ;
310 double dangle = (2.0 * PI)/( NPTS-1 );
311 double sradius = radius*sqrt(fill) ;
312 double c, s;
313
314 for( cntr=0 ; cntr < NPTS ; cntr++ ) {
315 c = cos( dangle * cntr ) ;
316 s = sin( dangle * cntr ) ;
317
318 pointsf[cntr] = sr( centerx + sradius*c , centery + sradius*s, 0.0 ) ;
319 pointse[cntr] = sr( centerx + radius*c , centery + radius*s, 0.0 ) ;
320 }
321
322 gdImageFilledPolygon( im, pointsf, NPTS, color );
323 gdImagePolygon( im, pointse, NPTS, color );
324 }
325
326 // ----------------------------------------------------------------------------
327 // perpendicular arrow
328 void arrow( int acolor, double acenterx, double acentery, double alength ) {
329 gdPoint pointsa[8];
330 double xwid = 0.05*alength ;
331 double xhead = 0.15*alength ;
332 double zhead = 0.3*alength ;
333
334 pointsa[0] = sr( acenterx, acentery, alength );
335 pointsa[1] = sr( acenterx+xhead, acentery, alength-zhead );
336 pointsa[2] = sr( acenterx+xwid, acentery, alength-zhead );
337 pointsa[3] = sr( acenterx+xwid, acentery, 0.0 );
338 pointsa[4] = sr( acenterx-xwid, acentery, 0.0 );
339 pointsa[5] = sr( acenterx-xwid, acentery, alength-zhead );
340 pointsa[6] = sr( acenterx-xhead, acentery, alength-zhead );
341 pointsa[7] = sr( acenterx, acentery, alength );
342 gdImageFilledPolygon( im, pointsa, 8, acolor );
343 }
344
345 // ----------------------------------------------------------------------------
346 // cell wiring stuff
347
348 // draw scalable rectangle
349 void RectS( double scolor, double sx1, double sy1, double sx2, double sy2) {
350 gdPoint pointss[5];
351
352 pointss[0] = sr( sx1, sy1, 0.0 );
353 pointss[1] = sr( sx2, sy1, 0.0 );
354 pointss[2] = sr( sx2, sy2, 0.0 );
355 pointss[3] = sr( sx1, sy2, 0.0 );
356 pointss[4] = sr( sx1, sy1, 0.0 );
357 gdImageFilledPolygon( im, pointss, 5, scolor );
358 }
359
360 // draw cell wiring ---------------------------------
361 // This draws a cheesy wiring grid on the front of the cell
362
363 void drawcellwire( int wcolor, double widthspace,
364 double centerx, double centery, double wsize ) {
365
366 int icnt ;
367 int nlines = (int) ( 0.6666666*wsize/widthspace-1.0 ) ;
368 double vsize = widthspace*( 1.5*nlines );
369
370 // center bar
371 RectS( wcolor, centerx-widthspace, centery-vsize,
372 centerx+widthspace, centery+vsize );
373
374 // horizontal lines
375 for( icnt=0 ; icnt<=nlines ; icnt++ ) {
376 RectS( wcolor, -wsize+centerx, (3.0*icnt )*widthspace+centery-vsize,
377 wsize+centerx, (3.0*icnt+1.0)*widthspace+centery-vsize );
378 }
379 }
380
381 //=====================================================================
382
383 int main () {
384 FILE *gifout;
385 char comment[80];
386 double timem ; // time in minutes
387 double t1, t2, t3 ; // thrust value for each cell
388 int astep ; // time step in hundredths of seconds
389
390 im1 = gdImageCreate (XSIZE, YSIZE);
391 white = gdImageColorAllocate (im1, 255, 255, 255);
392 black = gdImageColorAllocate (im1, 0, 0, 0);
393 gray = gdImageColorAllocate (im1, 127, 127, 127);
394 dgray = gdImageColorAllocate (im1, 64, 64, 64);
395 trans = gdImageColorAllocate (im1, 1, 1, 1);
396
397 makestars();
398
399 gifout = fopen ( GIFOUT , "wb");
400 // gdImageGifAnimBegin( im1, gifout, 1, -1 ) ; // no repeat
401 // gdImageGifAnimBegin( im1, gifout, 1, 4 ) ; // repeat 4 times
402 gdImageGifAnimBegin( im1, gifout, 1, 0 ) ; // continuous repeat
403
404 for( time = TSTART ; time <= TEND+0.1 ; time += TDELTA ) {
405
406 // start out stopped, display for a while
407 if( time <= 0.0 ) {
408 angle_acc = 0.0 ;
409 angle_vel = 0.0 ;
410 angle = 0.0 ;
411 t1 = 0.5 ;
412 t2 = 0.5 ;
413 t3 = 0.5 ;
414 astep = ASTEP0 ;
415 strcpy( comment, "stopped" );
416 }
417 // accelerate between 0 seconds and TIME1 seconds
418 else if( time < 1.0*TIME1 ) {
419 timem = time/ MINUTE ;
420 angle_acc = ACC ;
421 angle_vel = ACC * timem ;
422 angle = ACC * 0.5 * timem * timem ;
423 t1 = 0.0 ;
424 t2 = 0.0 ;
425 t3 = 1.0 ;
426 astep = ASTEP1 ;
427 strcpy( comment, "accelerating" );
428 }
429 // decelerate between TIME1 seconds and 2*TIME1 seconds
430 else if( time < 2.0*TIME1 ) {
431 timem = (2.0*TIME1-time)/ MINUTE ;
432 angle_acc = -ACC ;
433 angle_vel = ACC * timem ;
434 angle = angle_max - ( 0.5 * ACC * timem * timem );
435 t1 = 1.0 ;
436 t2 = 1.0 ;
437 t3 = 0.0 ;
438 astep = ASTEP1 ;
439 strcpy( comment, "decelerating" );
440 }
441 // end up stopped, display for a while
442 else {
443 angle_acc = 0.0 ;
444 angle_vel = 0.0 ;
445 angle = angle_max;
446 t1 = 0.5 ;
447 t2 = 0.5 ;
448 t3 = 0.5 ;
449 astep = ASTEP0 ;
450 strcpy( comment, "stopped" );
451 }
452
453 anglerad = DEG2RAD( angle );
454
455 im = gdImageCreate( XSIZE, YSIZE ) ;
456 gdImagePaletteCopy ( im, im1 ) ;
457
458 drawstars(); // draw stars
459 drawgauges(); // draw gauges
460
461 // draw serversat -----------------------------------------------
462
463 gdImageSetThickness( im, LINETHICK );
464
465 drawcircle( gray, 1.0, 0.0000, 0.0000, 3.0000 );
466 drawcircle( white, t1, -3.4641, 2.0000, 1.0000 );
467 drawcircle( white, t2, 3.4641, 2.0000, 1.0000 );
468 drawcircle( white, t3, 0.0000, -4.0000, 1.0000 );
469
470 #ifdef WIRING
471 drawcellwire( gray, 0.10, 0.0000, 0.0000, 2.0000 );
472 #endif // WIRING
473
474 // arrow and status text
475
476 RectS( white, -4.5000, -0.0001, 4.5000, 0.0001 ) ;
477 arrow( white, -4.0000, 0.0000, 2.0000 ) ;
478 arrow( white, 4.0000, 0.0000, 2.0000 ) ;
479
480 gdImageStringFT( im, NULL, white, FNT, 2*FSZ, 0.0, FSZ, 4*FSZ, comment );
481
482 // add frame to animation -------------------------------------
483
484 gdImageGifAnimAdd ( im, gifout, 0, 0, 2, astep,
485 gdDisposalRestoreBackground, im1 );
486
487 im0 = im1 ;
488 im1 = im ;
489 gdImageDestroy (im0);
490 }
491
492 gdImageGifAnimEnd(gifout);
493 fclose (gifout);
494 gdImageDestroy (im1);
495 return 0;
496 }
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.