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