Attachment 'echr11.c'
Download 1 // echr11.c
2 // compile: gcc -o echr11 echr11.c -lgd -lpng -lm
3 #define NAME "echr11"
4
5 // A NiOH2 WO3 electrochrome
6
7 #define RATE 6
8 #define HVEL 12.0 // Ion velocity
9 #define ITILT 0.15
10
11 #define NPICS 100 //
12 #define FNT "DejaVuMonoSans"
13 #define FSZ 25 // this scales the font and the whole drawing
14 #define XSIZE 1024
15 #define YSIZE 768
16 #define WIDE ( 2*FSZ)
17 #define TALL (22*FSZ)
18 #define LTALL (18*FSZ)
19 #define XCENT (20*FSZ)
20 #define YCENT (15*FSZ)
21 #define XCC (XCENT)
22 #define XM4 (XCENT-4*WIDE) // front surface front glass
23 #define XM3 (XCENT-3*WIDE) // front of NIOH
24 #define XM2 (XCENT-2*WIDE) // back of NIOH
25 #define XM1 (XCENT-1*WIDE) // front of WO3
26 #define XP1 (XCENT+1*WIDE) // back surface mirror
27 #define XL1 (XCENT+2*WIDE) // label box left
28 #define XL4 (XSIZE-1*WIDE) // label box right
29 #define XL2 ((XL1+XL4)/2 -9 )//
30 #define XL3 ((XL1+XL4)/2 +9 )//
31 #define YL1 (YCENT- 6*FSZ) // label box 1 top
32 #define YL2 (YCENT- 3*FSZ) // label box 1 bottom
33 #define YL3 (YCENT+ 3*FSZ) // label box 2 top
34 #define YL4 (YCENT+ 6*FSZ) // label box 2 bottom
35 #define XCCH (XCC-HVEL) // stopping zone for ions
36 #define XM3H (XM3+HVEL) // stopping zone for ions
37
38 #define ASIZE 2
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 #define PI 3.14159265359
48 #define DEG2RAD(x) ((x)*PI/180.)
49
50 // ----------------------------------------------------
51 char rmmkdir[200] ;
52 char pngfmt[ 200] ;
53 char png2swf[200] ;
54 int rate = RATE ; // swf frame rate
55 double ffrac ; // frame fraction
56 int sign ; // sign of battery
57 int active ; // changing state
58
59 gdImagePtr im;
60
61 int ytop= YCENT - TALL/2 ;
62 int yltop=YCENT -LTALL/2 ;
63 int ybot= YCENT + TALL/2 ;
64 int ylbot=YCENT +LTALL/2 ;
65 int deltay = (int)( ((double)ITILT)*((double)XCENT) ) ;
66 int brown, dblue, lblue ;
67 int black, white, gray ;
68 int red, lred ;
69 int green, lgreen, sun1 ;
70 int backgr, dgray, trans ;
71 int light[256] ; // Yellow color range
72 int light1 ;
73 double pi2 ; //
74 double nioh[1000][1000] ; // NIOH2 cell state
75 double wo3[1000][1000] ; // WO3 cell state
76 int hyd[1000] ; // hydrogen atom position
77
78 //======================================================================
79
80 //----------------------------------------
81 void atom_init() {
82 int x, y ;
83 for( y=ytop ; y<= ybot ; y += ASIZE ) {
84 for( x = 0 ; x < WIDE ; x += ASIZE ) {
85 nioh[x][y]=drand48() ;
86 wo3[x][y] =drand48() ;
87 }
88 hyd[y] = XCC ;
89 } }
90
91 //----------------------------------------
92 void frame_init() {
93 im = gdImageCreateTrueColor(XSIZE, YSIZE);
94
95 white = gdImageColorAllocate (im, 255, 255, 255);
96 black = gdImageColorAllocate (im, 0, 0, 0);
97 gray = gdImageColorAllocate (im, 127, 127, 127);
98 dgray = gdImageColorAllocate (im, 64, 64, 64);
99 red = gdImageColorAllocate (im, 255, 0, 0);
100 green = gdImageColorAllocate (im, 0, 255, 0);
101 lred = gdImageColorAllocate (im, 255, 224, 224);
102 lgreen = gdImageColorAllocate (im, 224, 255, 224);
103 backgr = gdImageColorAllocate (im, 0, 51, 102);
104 trans = gdImageColorAllocate (im, 1, 1, 1);
105 brown = gdImageColorAllocate (im, 60, 40, 0);
106 dblue = gdImageColorAllocate (im, 0, 0, 100);
107 lblue = gdImageColorAllocate (im, 200, 210, 255);
108 }
109
110 //----------------------------------------
111 void light_init() {
112 int i ;
113 int rx, gx, bx ;
114 double di ;
115
116 for( i=0 ; i < 256 ; i++ ) {
117 di = (double) i ;
118 int rx = (double)( di ) ;
119 int gx = (double)( 51.0 + (204.0/256.0) * di ) ;
120 int bx = (double)( 102.0 - (102.0/256.0) * di ) ;
121
122 // printf( "%3d%4d%4d%4d\n", i, rx, gx, bx );
123
124 light[i] = gdImageColorAllocate( im, rx, gx, bx ) ;
125 }
126 sun1 = light[0] ;
127 light1 = light[255] ;
128 }
129
130 //----------------------------------------
131 void draw_background() {
132 gdImageFilledRectangle( im, 0, 0, XSIZE-1, YSIZE-1, backgr );
133 }
134
135 //----------------------------------------
136 void draw_light() {
137
138 int light01 = light[ 127 ] ;
139
140 // gamma is funny, so this corrects additive light
141 int light02 = light[ ((int)(127.0 * (1.0+0.3*sqrt(ffrac)))) ] ;
142 int light03 = light[ ((int)(127.0 * ffrac )) ] ;
143 int light04 = light[ ((int)(127.0 * (1.0-ffrac))) ] ;
144
145 gdPoint alight[8] ;
146
147 // incoming triangle
148 alight[0].x = 0 ;
149 alight[0].y = yltop - deltay ;
150 alight[1].x = 0 ;
151 alight[1].y = yltop + deltay ;
152 alight[2].x = XCENT ;
153 alight[2].y = yltop ;
154 gdImageFilledPolygon( im , alight, 3 , light01 ) ;
155
156 // reflected addition
157 alight[0].x = 0 ;
158 alight[0].y = yltop + deltay ;
159 alight[1].x = 0 ;
160 alight[1].y = ylbot - deltay ;
161 alight[2].x = XCENT ;
162 alight[2].y = ylbot ;
163 alight[3].x = XCENT ;
164 alight[3].y = yltop ;
165 gdImageFilledPolygon( im , alight, 4 , light02 ) ;
166
167 // reflected triangle
168 alight[0].x = 0 ;
169 alight[0].y = ylbot + deltay ;
170 alight[1].x = 0 ;
171 alight[1].y = ylbot - deltay ;
172 alight[2].x = XCENT ;
173 alight[2].y = ylbot ;
174 gdImageFilledPolygon( im , alight, 3 , light03 ) ;
175 }
176
177 //----------------------------------------
178 void draw_sun() {
179 gdImageFilledRectangle( im, 0, yltop-deltay, 10, ylbot-deltay , light1 );
180 }
181
182 //----------------------------------------
183 void draw_atoms() {
184 int x, y ;
185 double hvd = -HVEL * (double) sign;
186 for( y=ytop ; y< ybot ; y += ASIZE ) {
187
188 if( (y/ASIZE)%3 != 0 ) {
189 x = hyd[y] + (int)( hvd * drand48() ) ;
190 if( ( x > XM3 ) && ( x < XCC ) ) { hyd[y] = x ; }
191 else { x = hyd[y] ; }
192 if( active == 1 ) {
193 gdImageFilledRectangle( im, x, y, x+ASIZE, y+ASIZE, lblue );
194 }
195 }
196 for( x = 0 ; x < WIDE ; x += ASIZE ) {
197 if( (y/ASIZE)%3 == 0 ) {
198 int xd = XM2 + x;
199 gdImageFilledRectangle( im, xd, y, xd+ASIZE, y+ASIZE, gray );
200 }
201 if( nioh[x][y] > ffrac ) {
202 int xn = XM3 + x;
203 gdImageFilledRectangle( im, xn, y, xn+ASIZE, y+ASIZE, brown );
204 }
205 if( wo3[x][y] > ffrac ) {
206 int xw = XM1 + x;
207 gdImageFilledRectangle( im, xw, y, xw+ASIZE, y+ASIZE, dblue );
208 } } } }
209
210 //----------------------------------------
211 void draw_frame() {
212
213 int ffx, fx1, fx2, ffy, fww, fw2, xcc ;
214 int yb1, yb2, yb3, yb4, yb5 ;
215 int xb0, xb1, xb2, xb3, xb4, xb5 ;
216 int xc0, xc1, xc2, xc3, xc4, xc5 ;
217 int yc1, yc2 ;
218
219 ffx = (int) FSZ ;
220 fx1 = (int) (0.7*FSZ) ;
221 fx2 = (int) (0.5*FSZ) ;
222 ffy = (int) (0.7*FSZ) ;
223 fww = (int) (WIDE) ;
224 fw2 = (int) (WIDE/2) ;
225
226 // battery coordinates
227
228 yb1 = ybot + ffy ;
229 yb2 = ybot + 2 * ffy ;
230 yb3 = ybot + 3 * ffy ; // center
231 yb4 = ybot + 4 * ffy ;
232 yb5 = ybot + 5 * ffy ;
233
234 xb0 = XCC - 7*fw2 ;
235 xb1 = XM2 ;
236 xb2 = xb1 + fx2 ;
237 xb3 = xb2 + fx2 ;
238 xb4 = xb3 + fx2 ;
239 xb5 = XCC + fw2 ;
240
241 xc0 = XCC - 5*fww ;
242 xc1 = xc0 + ffx ;
243 xc2 = xc1 + ffx ;
244 xc3 = XCC + 2*fww ;
245 xc4 = xc3 - ffx ;
246 xc5 = xc4 - ffx ;
247 yc1 = yb3 - ffx ;
248 yc2 = yb3 + ffx ;
249
250 gdImageSetThickness( im, 3 );
251
252 gdImageRectangle( im, XM3, ytop, XM2, ybot, brown ); // NIOH
253 gdImageRectangle( im, XM1, ytop, XCC, ybot, dblue ); // WO3
254 gdImageRectangle( im, XM4, ytop, XM3, ybot, white ); //front glass
255 gdImageFilledRectangle( im, XCC, ytop, XP1, ybot, white ); //back reflector
256
257 // battery
258
259 gdImageLine( im, xb0, ybot, xb0, yb3, white );
260 gdImageLine( im, xb0, yb3, xb1, yb3, white );
261 gdImageLine( im, xb1, yb1, xb1, yb5, white );
262 gdImageLine( im, xb2, yb2, xb2, yb4, white );
263 gdImageLine( im, xb3, yb1, xb3, yb5, white );
264 gdImageLine( im, xb4, yb2, xb4, yb4, white );
265 gdImageLine( im, xb5, yb3, xb4, yb3, white );
266 gdImageLine( im, xb5, ybot, xb5, yb3, white );
267
268 // draw plusminus
269
270 gdImageSetThickness( im, 7 );
271
272 if( sign == -1 ) {
273 gdImageLine( im, xc0, yb3, xc2, yb3, red );
274 gdImageLine( im, xc1, yc1, xc1, yc2, red );
275 gdImageLine( im, xc3, yb3, xc5, yb3, green );
276 }
277 else if( sign == 1 ) {
278 gdImageLine( im, xc0, yb3, xc2, yb3, green );
279 gdImageLine( im, xc4, yc1, xc4, yc2, red );
280 gdImageLine( im, xc3, yb3, xc5, yb3, red );
281 }
282 }
283
284 // draw arrow -------------------------------------------------------------
285
286 void arrow( int x0, int y0, int x1, int y1, int color ) {
287 gdPoint ap[3] ;
288 double asize = (double) FSZ ;
289 double ang = atan2( y0-y1 , x0-x1 );
290
291 ap[0].x = x0;
292 ap[0].y = y0;
293 ap[1].x = x0+(int)( asize*( -cos(ang) - 0.5*sin(ang) ));
294 ap[1].y = y0+(int)( asize*( 0.5*cos(ang) - sin(ang) ));
295 ap[2].x = x0+(int)( asize*( -cos(ang) + 0.5*sin(ang) ));
296 ap[2].y = y0+(int)( asize*( -0.5*cos(ang) - sin(ang) ));
297
298 gdImageLine( im, x0, y0, x1, y1, color ) ;
299 gdImageFilledPolygon( im, ap, 3, color ) ;
300 }
301
302 //----------------------------------------
303 void draw_labels() {
304
305 // boxes with material labels
306 gdImageFilledRectangle(im, XL1, YL1, XL2, YL2, brown ) ;// NIOH Label
307 gdImageFilledRectangle(im, XL3, YL1, XL4, YL2, dblue ) ;// WO3 Label
308 gdImageSetThickness(im, 5 );
309 gdImageRectangle(im, XL1, YL3, XL2, YL4, brown ) ;// NIOH Label
310 gdImageRectangle(im, XL3, YL3, XL4, YL4, dblue ) ;// WO3 Label
311 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0,
312 XL1, YL4-FSZ, " Ni(OH)₂ WO₃ " ) ;
313 gdImageStringFT( im, NULL, white, FNT, FSZ, 0.0,
314 XL1, YL2-FSZ, " NIOOH H+WO₃" ) ;
315
316 int xl1 = (XL1+XL2)/2 ;
317 int xl2 = (XL3+XL4)/2 ;
318 int yl1 = YL2 + 20 ;
319 int yl2 = YL3 - 20 ;
320 int xh = (XL2+XL3)/2 - 2*FSZ ;
321 int yh = (YL2+YL3)/2 - 4 ;
322
323 int lpr1 = (int)(201.0-200.0*ffrac) ;
324 int lpr2 = (int)( 1.0+250.0*ffrac) ;
325
326 gdImageStringFT( im, NULL, light[lpr1], FNT, FSZ, 0.0,
327 XL1-FSZ, YL1-3*FSZ, "4.6μPa Light Pressure" );
328 gdImageStringFT( im, NULL, light[lpr2], FNT, FSZ, 0.0,
329 XL1-FSZ, YL4+4*FSZ, "7.8μPa Light Pressure" );
330
331 if( sign == -1 ) {
332 if( active == 1 ) {
333 arrow( xl1, yl1, xl1, yl2, white );
334 arrow( xl2, yl1, xl2, yl2, white );
335 arrow( xl2-15, yl1, xl1+15, yl2, lblue );
336 gdImageStringFT( im, NULL, lblue, FNT, 1.5*FSZ, 0.0, xh, yh, "H+" );
337 }
338 gdImageStringFT( im, NULL, red , FNT, FSZ, 0.0,
339 XL1, YL1-9 , " Anode " );
340 gdImageStringFT( im, NULL, green, FNT, FSZ, 0.0,
341 XL3, YL1-9 , " Cathode" );
342 }
343 else if( sign == 1 ) {
344 if( active == 1 ) {
345 arrow( xl1, yl2, xl1, yl1, white );
346 arrow( xl2, yl2, xl2, yl1, white );
347 arrow( xl1+15, yl2, xl2-15, yl1, lblue );
348 gdImageStringFT( im, NULL, lblue, FNT, 1.5*FSZ, 0.0, xh, yh, "H+" );
349 }
350 gdImageStringFT( im, NULL, green, FNT, FSZ, 0.0,
351 XL1, YL4+FSZ+9 , " Cathode" );
352 gdImageStringFT( im, NULL, red , FNT, FSZ, 0.0,
353 XL3, YL4+FSZ+9 , " Anode " );
354 }
355
356 // title
357 gdImageStringFT( im, NULL, white, FNT, 1.5*FSZ, 0.0, // TITLE
358 (int)(2.0*FSZ), (int)(2.0*FSZ),
359 " Electrochromic Light Shutter" );
360 }
361
362 //=====================================================================
363
364 int main () {
365 FILE *pngout ;
366 char comment[80] ;
367 char dirname[80] ;
368 char framename[80] ;
369 int frame ; // frame count
370 int npics ; // last frame count
371 int i ;
372 pi2 = 8.0*atan(1.0) ; // pi
373 npics = (double)NPICS ;
374
375 sprintf( rmmkdir, "rm -rf %sdir ; mkdir %sdir", NAME, NAME );
376
377 system( rmmkdir ) ; // make directory
378 atom_init() ; // set up atom points
379
380 for( frame = 0 ; frame <= npics ; frame++ ) {
381
382 // sinusoidal fraction variation
383 double frang = pi2*((double)frame)/((double)npics );
384 double offs = acos(5.0/6.0) ;
385
386 ffrac = 0.6*(0.8333-cos( frang ) );
387 if( ffrac < 0.0 ) { ffrac=0.0 ; active=0 ; }
388 else if( ffrac > 1.0 ) { ffrac=1.0 ; active=0 ; }
389 else { active=1 ; }
390
391 if( sin( frang-offs ) > 0.0 ) { sign = 1 ; }
392 else { sign = -1 ; }
393
394 printf( "%04d/%04d\r", frame, npics ); fflush( stdout );
395
396 frame_init() ; // set up colors
397 light_init() ;
398
399 draw_background() ; // draw sunw background
400 draw_light() ; // draw light
401 draw_sun() ; // draw sun
402 draw_atoms() ; // draw atoms
403 draw_frame() ; // draw frame and battery
404 draw_labels() ; // draw title and reaction labels
405
406 sprintf( framename, "%sdir/a%04d.png", NAME , frame );
407 pngout = fopen ( framename , "wb");
408 gdImagePngEx( im, pngout, 1 );
409 gdImageDestroy (im);
410 fclose (pngout);
411 } // end of frame loop
412
413 sprintf( png2swf, "png2swf -o %s.swf -r%3d %sdir/*.png", NAME, rate, NAME );
414 system( png2swf );
415 }
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.