1 /*
2 * xnec2c - GTK2-based version of nec2c, the C translation of NEC2
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* draw_radiation.c
20 *
21 * Code for drawing radiation patterns
22 */
23
24 #include "draw_radiation.h"
25 #include "shared.h"
26
27 /* For coloring rad pattern */
28 static double *red = NULL, *grn = NULL, *blu = NULL;
29
30 /* Buffered points in 3d (xyz) space
31 * forming the radiation pattern */
32 static point_3d_t *point_3d = NULL;
33
34 /*-----------------------------------------------------------------------*/
35
36 /* Draw_Radiation()
37 *
38 * Draws the radiation pattern or near E/H fields
39 */
40 void
Draw_Radiation(GtkWidget * drawingarea)41 Draw_Radiation( GtkWidget *drawingarea )
42 {
43 /* Abort if xnec2c may be quit by user */
44 if( isFlagSet(MAIN_QUIT) || isFlagClear(ENABLE_EXCITN) )
45 return;
46
47 /* Cairo context */
48 cairo_t *cr = gdk_cairo_create( rdpattern_pixmap );
49
50 /* Clear pixmap */
51 cairo_set_source_rgb( cr, BLACK );
52 cairo_rectangle(
53 cr, 0.0, 0.0,
54 (double)rdpattern_proj_params.pixmap_width,
55 (double)rdpattern_proj_params.pixmap_height);
56 cairo_fill( cr );
57
58 /* Draw rad pattern or E/H fields */
59 if( isFlagSet(DRAW_GAIN) )
60 Draw_Radiation_Pattern();
61 else if( isFlagSet(DRAW_EHFIELD) )
62 Draw_Near_Field();
63
64 /* Render pixmap to screen */
65 gdk_window_set_back_pixmap( drawingarea->window,
66 rdpattern_pixmap, FALSE );
67 gdk_window_clear( drawingarea->window );
68
69 /* Display frequency step */
70 Display_Fstep( rdpattern_fstep_entry, calc_data.fstep );
71
72 /* Wait for GTK to complete its tasks */
73 while( g_main_context_iteration(NULL, FALSE) );
74
75 cairo_destroy( cr );
76 } /* Draw_Radiation() */
77
78 /*-----------------------------------------------------------------------*/
79
80 /* Draw_Radiation_Pattern()
81 *
82 * Draws the radiation pattern as a frame of line
83 * segmants joining the points defined by spherical
84 * co-ordinates theta, phi and r = gain(theta, phi)
85 */
86 void
Draw_Radiation_Pattern(void)87 Draw_Radiation_Pattern( void )
88 {
89 /* Abort if rad pattern cannot be drawn */
90 if( isFlagClear(ENABLE_RDPAT) || (calc_data.fstep < 0) )
91 return;
92
93 /* Line segments to draw on Screen */
94 GdkSegment segm;
95
96 int
97 idx,
98 nth, /* Theta step count */
99 nph, /* Phi step count */
100 col_idx, /* Index to rad pattern color buffers */
101 pts_idx; /* Index to rad pattern 3d-points buffer */
102
103
104 /* Frequency step and polarization type */
105 int fstep, pol;
106
107 /* Theta and phi angles defining a rad pattern point
108 * and distance of its projection from xyz origin */
109 double theta, phi, r, r_min, r_range;
110
111 /* theta and phi step in rads */
112 double dth = (double)fpat.dth * (double)TA;
113 double dph = (double)fpat.dph * (double)TA;
114
115 /* Used to set text in labels */
116 gchar txt[7];
117
118 /* Cairo context */
119 cairo_t *cr = gdk_cairo_create( rdpattern_pixmap );
120
121 fstep = calc_data.fstep;
122 pol = calc_data.pol_type;
123
124 /* Change drawing if newer rad pattern data */
125 if( isFlagSet(DRAW_NEW_RDPAT) )
126 {
127 size_t mreq = ((size_t)(fpat.nth * fpat.nph)) * sizeof(point_3d_t);
128 mem_realloc( (void **)&point_3d, mreq, "in draw_radiation.c" );
129 mreq = (size_t)((fpat.nth-1) * fpat.nph + (fpat.nph-1) * fpat.nth);
130 mreq *= sizeof(double);
131 mem_realloc( (void **)&red, mreq, "in draw_radiation.c" );
132 mem_realloc( (void **)&grn, mreq, "in draw_radiation.c" );
133 mem_realloc( (void **)&blu, mreq, "in draw_radiation.c" );
134
135 ClearFlag( DRAW_NEW_RDPAT );
136
137 /* Distance of rdpattern point furthest from xyz origin */
138 idx = rad_pattern[fstep].max_gain_idx[pol];
139 rdpattern_proj_params.r_max = Scale_Gain(
140 rad_pattern[fstep].gtot[idx], fstep, idx);
141
142 /* Distance of rdpattern point nearest to xyz origin */
143 idx = rad_pattern[fstep].min_gain_idx[pol];
144 r_min = Scale_Gain(
145 rad_pattern[fstep].gtot[idx], fstep, idx);
146
147 /* Range of scaled rdpattern gain values */
148 r_range = rdpattern_proj_params.r_max - r_min;
149
150 /* Set radiation pattern projection parametrs */
151 New_Projection_Parameters(
152 rdpattern_pixmap_width,
153 rdpattern_pixmap_height,
154 &rdpattern_proj_params );
155
156 /*** Convert radiation pattern values
157 * to points in 3d space in x,y,z axis ***/
158 pts_idx = 0;
159 phi = (double)(fpat.phis * TA); /* In rads */
160
161 /* Step phi angle */
162 for( nph = 0; nph < fpat.nph; nph++ )
163 {
164 theta = (double)(fpat.thets * TA); /* In rads */
165
166 /* Step theta angle */
167 for( nth = 0; nth < fpat.nth; nth++ )
168 {
169 /* Distance of pattern point from the xyz origin */
170 r = Scale_Gain(
171 rad_pattern[fstep].gtot[pts_idx], fstep, pts_idx );
172
173 /* Distance of pattern point from xyz origin */
174 point_3d[pts_idx].r = r;
175
176 /* Distance of point's projection on xyz axis, from origin */
177 point_3d[pts_idx].z = r * cos(theta);
178 r *= sin(theta);
179 point_3d[pts_idx].x = r * cos(phi);
180 point_3d[pts_idx].y = r * sin(phi);
181
182 /* Step theta in rads */
183 theta += dth;
184
185 /* Step 3d points index */
186 pts_idx++;
187 } /* for( nth = 0; nth < fpat.nth; nth++ ) */
188
189 /* Step phi in rads */
190 phi += dph;
191 } /* for( nph = 0; nph < fpat.nph; nph++ ) */
192
193 /* Calculate RGB value for rad pattern seg.
194 * The average gain value of the two points
195 * marking each line segment is used here */
196
197 /* Pattern segment color in theta direction */
198 col_idx = pts_idx = 0;
199 for( nph = 0; nph < fpat.nph; nph++ )
200 {
201 for( nth = 1; nth < fpat.nth; nth++ )
202 {
203 Value_to_Color(
204 &red[col_idx], &grn[col_idx], &blu[col_idx],
205 (point_3d[pts_idx].r+point_3d[pts_idx+1].r)/2.0-r_min,
206 r_range );
207 col_idx++;
208 pts_idx++;
209
210 } /* for( nph = 0; nph < fpat.nph; nph++ ) */
211
212 /* Needed because of "index look-ahead" above */
213 pts_idx++;
214
215 } /* for( nth = 1; nth < fpat.nth; nth++ ) */
216
217 /* Pattern segment color in phi direction */
218 for( nth = 0; nth < fpat.nth; nth++ )
219 {
220 pts_idx = nth;
221 for( nph = 1; nph < fpat.nph; nph++ )
222 {
223 Value_to_Color(
224 &red[col_idx], &grn[col_idx], &blu[col_idx],
225 (point_3d[pts_idx].r +
226 point_3d[pts_idx+fpat.nth].r)/2.0-r_min,
227 r_range );
228 col_idx++;
229
230 /* Needed because of "index look-ahead" above */
231 pts_idx += fpat.nth;
232
233 } /* for( nth = 0; nth < fpat.nth; nth++ ) */
234 } /* for( nph = 1; nph < fpat.nph; nph++ ) */
235
236 /* Show max gain on color code bar */
237 snprintf( txt, 7, "%6f", rad_pattern[fstep].max_gain[pol] );
238 gtk_label_set_text(
239 GTK_LABEL(lookup_widget(rdpattern_window,
240 "rdpattern_colorcode_maxlabel")), txt );
241
242 /* Show min gain on color code bar */
243 snprintf( txt, 5, "%4f", rad_pattern[fstep].min_gain[pol] );
244 gtk_label_set_text(
245 GTK_LABEL(lookup_widget(rdpattern_window,
246 "rdpattern_colorcode_minlabel")), txt );
247
248 } /* if( isFlagSet(DRAW_NEWRDPAT) ) ) */
249
250 /* Draw xyz axes to Screen */
251 Draw_XYZ_Axes( rdpattern_pixmap, rdpattern_proj_params );
252
253 /* Overlay structure on Near Field pattern */
254 if( isFlagSet(OVERLAY_STRUCT) )
255 {
256 /* Save structure pixmap and params pointers */
257 GdkPixmap *pixmap = structure_pixmap;
258 projection_parameters_t params = structure_proj_params;
259
260 /* Divert structure drawing to rad pattern area */
261 structure_pixmap = rdpattern_pixmap;
262 structure_proj_params = rdpattern_proj_params;
263 structure_proj_params.r_max = params.r_max;
264 structure_proj_params.xy_scale =
265 params.xy_scale1 * rdpattern_proj_params.xy_zoom;
266
267 /* Process and draw geometry if enabled */
268 Process_Wire_Segments();
269 Process_Surface_Patches();
270 Draw_Surface_Patches( structure_segs+data.n, data.m );
271 Draw_Wire_Segments( structure_segs, data.n );
272
273 /* Restore structure pixmap and params */
274 structure_pixmap = pixmap;
275 structure_proj_params = params;
276 } /* if( isFlagSet(OVERLAY_STRUCT) ) */
277
278 /*** Draw rad pattern on screen ***/
279 /* Draw segments along theta direction */
280 col_idx = pts_idx = 0;
281 for( nph = 0; nph < fpat.nph; nph++ )
282 {
283 for( nth = 1; nth < fpat.nth; nth++ )
284 {
285 /* Project line segment to Screen */
286 Set_Gdk_Segment(
287 &segm,
288 &rdpattern_proj_params,
289 point_3d[pts_idx].x,
290 point_3d[pts_idx].y,
291 point_3d[pts_idx].z,
292 point_3d[pts_idx+1].x,
293 point_3d[pts_idx+1].y,
294 point_3d[pts_idx+1].z );
295 pts_idx++;
296
297 /* Draw segment */
298 cairo_set_source_rgb( cr, red[col_idx], grn[col_idx], blu[col_idx] );
299 Cairo_Draw_Line( cr, segm.x1, segm.y1, segm.x2, segm.y2 );
300 col_idx++;
301
302 } /* for( nth = 1; nth < fpat.nth; nth++ ) */
303
304 pts_idx++;
305 } /* for( nph = 0; nph < fpat.nph; nph++ ) */
306
307 /* Draw segments along phi direction */
308 for( nth = 0; nth < fpat.nth; nth++ )
309 {
310 pts_idx = nth;
311 for( nph = 1; nph < fpat.nph; nph++ )
312 {
313 /* Project line segment to Screen */
314 Set_Gdk_Segment(
315 &segm,
316 &rdpattern_proj_params,
317 point_3d[pts_idx].x,
318 point_3d[pts_idx].y,
319 point_3d[pts_idx].z,
320 point_3d[pts_idx+fpat.nth].x,
321 point_3d[pts_idx+fpat.nth].y,
322 point_3d[pts_idx+fpat.nth].z );
323
324 /* Draw segment */
325 cairo_set_source_rgb( cr, red[col_idx], grn[col_idx], blu[col_idx] );
326 Cairo_Draw_Line( cr, segm.x1, segm.y1, segm.x2, segm.y2 );
327 col_idx++;
328
329 /* Needed because drawing segments "looks ahead"
330 * in the 3d points buffer in the above loop */
331 pts_idx += fpat.nth;
332
333 } /* for( nph = 1; nph < fpat.nph; nph++ ) */
334 } /* for( nth = 0; nth < fpat.nth; nth++ ) */
335
336 /* Show gain in direction of viewer */
337 Show_Viewer_Gain(
338 rdpattern_window,
339 "rdpattern_viewer_gain",
340 rdpattern_proj_params );
341
342 cairo_destroy( cr );
343 } /* Draw_Radiation_Pattern() */
344
345 /*-----------------------------------------------------------------------*/
346
347 /* Draw_Near_Field()
348 *
349 * Draws near E/H fields and Poynting vector
350 */
351 void
Draw_Near_Field(void)352 Draw_Near_Field( void )
353 {
354 int idx, npts; /* Number of points to plot */
355 double
356 fx, fy, fz, /* Co-ordinates of "free" end of field lines */
357 fscale; /* Scale factor for equalizing field line segments */
358
359 /* Scale factor ref, for normalizing field strength values */
360 static double dr;
361
362 /* Co-ordinates of Poynting vectors */
363 static double *pov_x = NULL, *pov_y = NULL;
364 static double *pov_z = NULL, *pov_r = NULL;
365
366 /* Range of Poynting vector values,
367 * its max and min and log of max/min */
368 static double pov_max = 0, max;
369
370 /* Used to set text in labels */
371 gchar txt[9];
372
373 /* Line segments to draw on Screen */
374 GdkSegment segm;
375
376 /* For coloring field lines */
377 double xred = 0.0, xgrn = 0.0, xblu = 0.0;
378
379 /* Abort if drawing a near field pattern is not possible */
380 if( isFlagClear(ENABLE_NEAREH) || !near_field.valid )
381 return;
382
383 /* Cairo context */
384 cairo_t *cr = gdk_cairo_create( rdpattern_pixmap );
385
386 /* Initialize projection parameters */
387 if( isFlagSet(DRAW_NEW_EHFIELD) )
388 {
389 /* Reference for scale factor used in
390 * normalizing field strength values */
391 if( fpat.near ) /* Spherical co-ordinates */
392 dr = (double)fpat.dxnr;
393 else /* Rectangular co-ordinates */
394 dr = sqrt(
395 (double)fpat.dxnr * (double)fpat.dxnr +
396 (double)fpat.dynr * (double)fpat.dynr +
397 (double)fpat.dznr * (double)fpat.dznr )/1.75;
398
399 /* Set radiation pattern projection parametrs */
400 /* Distance of field point furthest from xyz origin */
401 rdpattern_proj_params.r_max = near_field.r_max + dr;
402 New_Projection_Parameters(
403 rdpattern_pixmap_width,
404 rdpattern_pixmap_height,
405 &rdpattern_proj_params );
406
407 ClearFlag( DRAW_NEW_EHFIELD );
408
409 } /* if( isFlagSet( DRAW_NEW_EHFIELD ) */
410
411 /* Draw xyz axes to Screen */
412 Draw_XYZ_Axes( rdpattern_pixmap, rdpattern_proj_params );
413
414 /* Overlay structure on Near Field pattern */
415 if( isFlagSet(OVERLAY_STRUCT) )
416 {
417 /* Save structure pixmap and params pointers */
418 GdkPixmap *pixmap = structure_pixmap;
419 projection_parameters_t params = structure_proj_params;
420
421 /* Divert structure drawing to rad pattern area */
422 structure_pixmap = rdpattern_pixmap;
423 structure_proj_params = rdpattern_proj_params;
424
425 /* Process and draw geometry if enabled */
426 Process_Wire_Segments();
427 Process_Surface_Patches();
428 Draw_Surface_Patches( structure_segs+data.n, data.m );
429 Draw_Wire_Segments( structure_segs, data.n );
430
431 /* Restore structure pixmap and params */
432 structure_pixmap = pixmap;
433 structure_proj_params = params;
434 } /* if( isFlagSet(OVERLAY_STRUCT) ) */
435
436 /* Step thru near field values */
437 npts = fpat.nrx * fpat.nry * fpat.nrz;
438 for( idx = 0; idx < npts; idx++ )
439 {
440 /*** Draw Near E Field ***/
441 if( isFlagSet(DRAW_EFIELD) && (fpat.nfeh & NEAR_EFIELD) )
442 {
443 /* Set gc attributes for segment */
444 Value_to_Color( &xred, &xgrn, &xblu,
445 near_field.er[idx], near_field.max_er );
446
447 /* Scale factor for each field point, to make
448 * near field direction lines equal-sized */
449 fscale = dr / near_field.er[idx];
450
451 /* Scaled field values are used to set one end of a
452 * line segment that represents direction of field.
453 * The other end is set by the field point co-ordinates */
454 fx = near_field.px[idx] + near_field.erx[idx] * fscale;
455 fy = near_field.py[idx] + near_field.ery[idx] * fscale;
456 fz = near_field.pz[idx] + near_field.erz[idx] * fscale;
457
458 /* Project new line segment of
459 * phi chain to the Screen */
460 Set_Gdk_Segment(
461 &segm, &rdpattern_proj_params,
462 near_field.px[idx], near_field.py[idx], near_field.pz[idx],
463 fx, fy, fz );
464
465 /* Draw segment */
466 cairo_set_source_rgb( cr, xred, xgrn, xblu );
467 Cairo_Draw_Line( cr, segm.x1, segm.y1, segm.x2, segm.y2 );
468
469 } /* if( isFlagSet(DRAW_EFIELD) && (fpat.nfeh & NEAR_EFIELD) ) */
470
471 /*** Draw Near H Field ***/
472 if( isFlagSet(DRAW_HFIELD) && (fpat.nfeh & NEAR_HFIELD) )
473 {
474 /* Set gc attributes for segment */
475 Value_to_Color( &xred, &xgrn, &xblu,
476 near_field.hr[idx], near_field.max_hr );
477
478 /* Scale factor for each field point, to make
479 * near field direction lines equal-sized */
480 fscale = dr / near_field.hr[idx];
481
482 /* Scaled field values are used to set one end of a
483 * line segment that represents direction of field.
484 * The other end is set by the field point co-ordinates */
485 fx = near_field.px[idx] + near_field.hrx[idx] * fscale;
486 fy = near_field.py[idx] + near_field.hry[idx] * fscale;
487 fz = near_field.pz[idx] + near_field.hrz[idx] * fscale;
488
489 /* Project new line segment of
490 * phi chain to the Screen */
491 Set_Gdk_Segment(
492 &segm, &rdpattern_proj_params,
493 near_field.px[idx], near_field.py[idx], near_field.pz[idx],
494 fx, fy, fz );
495
496 /* Draw segment */
497 cairo_set_source_rgb( cr, xred, xgrn, xblu );
498 Cairo_Draw_Line( cr, segm.x1, segm.y1, segm.x2, segm.y2 );
499
500 } /* if( isFlagSet(DRAW_HFIELD) && (fpat.nfeh & NEAR_HFIELD) ) */
501
502 /*** Draw Poynting Vector ***/
503 if( isFlagSet(DRAW_POYNTING) &&
504 (fpat.nfeh & NEAR_EFIELD) &&
505 (fpat.nfeh & NEAR_HFIELD) )
506 {
507 int ipv; /* Mem request and index */
508
509 /* Allocate on new near field matrix size */
510 if( isFlagSet(ALLOC_PNTING_BUFF) )
511 {
512 size_t mreq = (size_t)npts * sizeof( double );
513 mem_realloc( (void **)&pov_x, mreq, "in draw_radiation.c" );
514 mem_realloc( (void **)&pov_y, mreq, "in draw_radiation.c" );
515 mem_realloc( (void **)&pov_z, mreq, "in draw_radiation.c" );
516 mem_realloc( (void **)&pov_r, mreq, "in draw_radiation.c" );
517 ClearFlag( ALLOC_PNTING_BUFF );
518 }
519
520 /* Calculate Poynting vector and its max and min */
521 pov_max = 0;
522 for( ipv = 0; ipv < npts; ipv++ )
523 {
524 pov_x[ipv] =
525 near_field.ery[ipv] * near_field.hrz[ipv] -
526 near_field.hry[ipv] * near_field.erz[ipv];
527 pov_y[ipv] =
528 near_field.erz[ipv] * near_field.hrx[ipv] -
529 near_field.hrz[ipv] * near_field.erx[ipv];
530 pov_z[ipv] =
531 near_field.erx[ipv] * near_field.hry[ipv] -
532 near_field.hrx[ipv] * near_field.ery[ipv];
533 pov_r[ipv] = sqrt(
534 pov_x[ipv] * pov_x[ipv] +
535 pov_y[ipv] * pov_y[ipv] +
536 pov_z[ipv] * pov_z[ipv] );
537 if( pov_max < pov_r[ipv] )
538 pov_max = pov_r[ipv];
539 } /* for( ipv = 0; ipv < npts; ipv++ ) */
540
541 /* Set gc attributes for segment */
542 Value_to_Color( &xred, &xgrn, &xblu, pov_r[idx], pov_max );
543
544 /* Scale factor for each field point, to make
545 * near field direction lines equal-sized */
546 fscale = dr / pov_r[idx];
547
548 /* Scaled field values are used to set one end of a
549 * line segment that represents direction of field.
550 * The other end is set by the field point co-ordinates */
551 fx = near_field.px[idx] + pov_x[idx] * fscale;
552 fy = near_field.py[idx] + pov_y[idx] * fscale;
553 fz = near_field.pz[idx] + pov_z[idx] * fscale;
554
555 /* Project new line segment of
556 * Poynting vector to the Screen */
557 Set_Gdk_Segment(
558 &segm,
559 &rdpattern_proj_params,
560 near_field.px[idx], near_field.py[idx],
561 near_field.pz[idx], fx, fy, fz );
562
563 /* Draw segment */
564 cairo_set_source_rgb( cr, xred, xgrn, xblu );
565 Cairo_Draw_Line( cr, segm.x1, segm.y1, segm.x2, segm.y2 );
566
567 } /* if( isFlagSet(DRAW_POYNTING) ) */
568
569 } /* for( idx = 0; idx < npts; idx++ ) */
570
571 if( isFlagSet(NEAREH_ANIMATE) )
572 {
573 cairo_destroy( cr );
574 return;
575 }
576
577 /* Show max field strength on color code bar */
578 if( isFlagSet(DRAW_EFIELD) )
579 max = near_field.max_er;
580 else if( isFlagSet(DRAW_HFIELD) )
581 max = near_field.max_hr;
582 else if( isFlagSet(DRAW_POYNTING) )
583 max = pov_max;
584
585 snprintf( txt, sizeof(txt), "%8.2E", max );
586 gtk_label_set_text(
587 GTK_LABEL(lookup_widget(rdpattern_window,
588 "rdpattern_colorcode_maxlabel")), txt );
589
590 /* Show min field strength on color code bar */
591 gtk_label_set_text(
592 GTK_LABEL(lookup_widget(rdpattern_window,
593 "rdpattern_colorcode_minlabel")), "0" );
594
595 cairo_destroy( cr );
596 } /* Draw_Near_Field() */
597
598 /*-----------------------------------------------------------------------*/
599
600 gboolean
Animate_Near_Field(gpointer udata)601 Animate_Near_Field( gpointer udata )
602 {
603 /* omega*t = 2*pi*f*t = Time-varying phase of excitation */
604 static double wt = 0.0;
605 int idx, npts;
606
607 if( isFlagClear(NEAREH_ANIMATE) )
608 return( FALSE );
609
610 /* Number of points in near fields */
611 npts = fpat.nrx * fpat.nry * fpat.nrz;
612 for( idx = 0; idx < npts; idx++ )
613 {
614 if( isFlagSet(DRAW_EFIELD) || isFlagSet(DRAW_POYNTING) )
615 {
616 /* Real component of complex E field strength */
617 near_field.erx[idx] = near_field.ex[idx] *
618 cos( wt + near_field.fex[idx] );
619 near_field.ery[idx] = near_field.ey[idx] *
620 cos( wt + near_field.fey[idx] );
621 near_field.erz[idx] = near_field.ez[idx] *
622 cos( wt + near_field.fez[idx] );
623 /* Near total electric field vector */
624 near_field.er[idx] = sqrt(
625 near_field.erx[idx] * near_field.erx[idx] +
626 near_field.ery[idx] * near_field.ery[idx] +
627 near_field.erz[idx] * near_field.erz[idx] );
628 if( near_field.max_er < near_field.er[idx] )
629 near_field.max_er = near_field.er[idx];
630 }
631
632 if( isFlagSet(DRAW_HFIELD) || isFlagSet(DRAW_POYNTING) )
633 {
634 /* Real component of complex H field strength */
635 near_field.hrx[idx] = near_field.hx[idx] *
636 cos( wt + near_field.fhx[idx] );
637 near_field.hry[idx] = near_field.hy[idx] *
638 cos( wt + near_field.fhy[idx] );
639 near_field.hrz[idx] = near_field.hz[idx] *
640 cos( wt + near_field.fhz[idx] );
641 /* Near total magnetic field vector*/
642 near_field.hr[idx] = sqrt(
643 near_field.hrx[idx] * near_field.hrx[idx] +
644 near_field.hry[idx] * near_field.hry[idx] +
645 near_field.hrz[idx] * near_field.hrz[idx] );
646 if( near_field.max_hr < near_field.hr[idx] )
647 near_field.max_hr = near_field.hr[idx];
648 }
649
650 } /* for( idx = 0; idx < npts; idx++ ) */
651
652 /* Increment excitation phase, keep < 2pi */
653 wt += near_field.anim_step;
654 if( wt >= (double)TP )
655 wt = 0.0;
656
657 Draw_Radiation( rdpattern_drawingarea );
658
659 return( TRUE );
660
661 } /* Animate_Near_Field() */
662
663 /*-----------------------------------------------------------------------*/
664
665 /* Scale_Gain()
666 *
667 * Scales radiation pattern gain according to selected style
668 * ( ARRL style, logarithmic or linear voltage/power )
669 */
670 static int gain_style = GS_LINP;
671
672 double
Scale_Gain(double gain,int fstep,int idx)673 Scale_Gain( double gain, int fstep, int idx )
674 {
675 /* Scaled rad pattern gain and pol factor */
676 double scaled_rad = 0.0;
677
678 gain += Polarization_Factor( calc_data.pol_type, fstep, idx );
679
680 switch( gain_style )
681 {
682 case GS_LINP:
683 scaled_rad = pow(10.0, (gain/10.0));
684 break;
685
686 case GS_LINV:
687 scaled_rad = pow(10.0, (gain/20.0));
688 break;
689
690 case GS_ARRL:
691 scaled_rad = exp( 0.058267 * gain );
692 break;
693
694 case GS_LOG:
695 scaled_rad = gain;
696 if( scaled_rad < -40 )
697 scaled_rad = 0.0;
698 else
699 scaled_rad = scaled_rad /40.0 + 1.0;
700
701 } /* switch( gain_style ) */
702
703 return( scaled_rad );
704
705 } /* Scale_Gain() */
706
707 /*-----------------------------------------------------------------------*/
708
709 /* Polarization_Factor()
710 *
711 * Calculates polarization factor from axial
712 * ratio and tilt of polarization ellipse
713 */
714 double
Polarization_Factor(int pol_type,int fstep,int idx)715 Polarization_Factor( int pol_type, int fstep, int idx )
716 {
717 double axrt, axrt2, tilt2, polf = 1.0;
718
719 switch( pol_type )
720 {
721 case POL_TOTAL:
722 polf = 1.0;
723 break;
724
725 case POL_HORIZ:
726 axrt2 = rad_pattern[fstep].axrt[idx];
727 axrt2 *= axrt2;
728 tilt2 = sin( rad_pattern[fstep].tilt[idx] );
729 tilt2 *= tilt2;
730 polf = (axrt2 + (1.0 - axrt2) * tilt2) / (1.0 + axrt2);
731 break;
732
733 case POL_VERT:
734 axrt2 = rad_pattern[fstep].axrt[idx];
735 axrt2 *= axrt2;
736 tilt2 = cos( rad_pattern[fstep].tilt[idx] );
737 tilt2 *= tilt2;
738 polf = (axrt2 + (1.0 - axrt2) * tilt2) / (1.0 + axrt2);
739 break;
740
741 case POL_LHCP:
742 axrt = rad_pattern[fstep].axrt[idx];
743 axrt2 = axrt * axrt;
744 polf = (1.0 + 2.0 * axrt + axrt2) / 2.0 / (1.0 + axrt2);
745 break;
746
747 case POL_RHCP:
748 axrt = rad_pattern[fstep].axrt[idx];
749 axrt2 = axrt * axrt;
750 polf = (1.0 - 2.0 * axrt + axrt2) / 2.0 / (1.0 + axrt2);
751 }
752
753 if( polf < 1.0E-200 ) polf = 1.0E-200;
754 polf = 10.0 * log10( polf );
755
756 return( polf );
757 } /* Polarization_Factor() */
758
759 /*-----------------------------------------------------------------------*/
760
761 /* Set_Polarization()
762 *
763 * Sets the polarization type of gain to be plotted
764 */
765
766 void
Set_Polarization(int pol)767 Set_Polarization( int pol )
768 {
769 calc_data.pol_type = pol;
770
771 Set_Window_Labels();
772
773 /* Trigger a redraw of drawingareas */
774 if( isFlagSet(DRAW_ENABLED) )
775 Draw_Radiation( rdpattern_drawingarea );
776
777 if( isFlagSet(PLOT_ENABLED) )
778 Plot_Frequency_Data();
779
780 /* Show gain in direction of viewer */
781 Show_Viewer_Gain( main_window,
782 "main_gain_entry", structure_proj_params );
783
784 /* Enable redraw of rad pattern */
785 SetFlag( DRAW_NEW_RDPAT );
786
787 } /* Set_Polarization() */
788
789 /*-----------------------------------------------------------------------*/
790
791 /* Set_Gain_Style()
792 *
793 * Sets the radiation pattern Gain scaling style
794 */
795 void
Set_Gain_Style(int gs)796 Set_Gain_Style( int gs )
797 {
798 gain_style = gs;
799
800 Set_Window_Labels();
801
802 /* Trigger a redraw of drawingarea */
803 if( isFlagSet(DRAW_ENABLED) )
804 {
805 /* Enable redraw of rad pattern */
806 SetFlag( DRAW_NEW_RDPAT );
807 Draw_Radiation( rdpattern_drawingarea );
808 }
809
810 } /* Set_Gain_Style() */
811
812 /*-----------------------------------------------------------------------*/
813
814 /* New_Radiation_Projection_Angle()
815 *
816 * Calculates new projection parameters when a
817 * structure projection angle (Wr or Wi) changes
818 */
819 void
New_Radiation_Projection_Angle(void)820 New_Radiation_Projection_Angle(void)
821 {
822 /* sin and cos of rad pattern rotation and inclination angles */
823 rdpattern_proj_params.sin_wr = sin(rdpattern_proj_params.Wr/(double)TD);
824 rdpattern_proj_params.cos_wr = cos(rdpattern_proj_params.Wr/(double)TD);
825 rdpattern_proj_params.sin_wi = sin(rdpattern_proj_params.Wi/(double)TD);
826 rdpattern_proj_params.cos_wi = cos(rdpattern_proj_params.Wi/(double)TD);
827
828 /* Trigger a redraw of radiation drawingarea */
829 if( isFlagSet(DRAW_ENABLED) )
830 Draw_Radiation( rdpattern_drawingarea );
831
832 /* Trigger a redraw of plots drawingarea if doing "viewer" gain */
833 if( isFlagSet(PLOT_ENABLED) && isFlagSet(PLOT_GVIEWER) )
834 Plot_Frequency_Data();
835
836 } /* New_Radiation_Projection_Angle() */
837
838 /*-----------------------------------------------------------------------*/
839
840 /* Redo_Radiation_Pattern()
841 *
842 * Refreshes radiation pattern on new frequency in spinbutton
843 */
844 gboolean
Redo_Radiation_Pattern(gpointer udata)845 Redo_Radiation_Pattern( gpointer udata )
846 {
847 /* Redo radiation pattern for a new frequency. Below
848 * makes calcs use the extra buffer in rad_pattern */
849 calc_data.fstep = calc_data.nfrq;
850 New_Frequency();
851
852 /* Redraw radiation pattern on screen */
853 if( isFlagSet(DRAW_ENABLED) )
854 Draw_Radiation( rdpattern_drawingarea );
855
856 return FALSE;
857
858 } /* Redo_Radiation_Pattern() */
859
860 /*-----------------------------------------------------------------------*/
861
862 /* Viewer_Gain()
863 *
864 * Calculate gain in direction of viewer
865 * (e.g. Perpenticular to the Screen)
866 */
867 double
Viewer_Gain(projection_parameters_t proj_parameters,int fstep)868 Viewer_Gain( projection_parameters_t proj_parameters, int fstep )
869 {
870 double phi, gain;
871 int nth, nph, idx;
872
873 /* Calculate theta step from proj params */
874 phi = proj_parameters.Wr;
875 if( fpat.dth == 0.0 ) nth = 0;
876 else
877 {
878 double theta;
879 theta = fabs( 90.0 - proj_parameters.Wi );
880 if( theta > 180.0 )
881 {
882 theta = 360.0 - theta;
883 phi -= 180.0;
884 }
885
886 if( (gnd.ksymp == 2) &&
887 (theta > 90.01) &&
888 (gnd.ifar != 1) )
889 return( -999.99 );
890
891 nth = (int)( (theta - fpat.thets) / fpat.dth + 0.5 );
892 if( (nth >= fpat.nth) || (nth < 0) )
893 nth = fpat.nth-1;
894 }
895
896 /* Calculate phi step from proj params */
897 if( fpat.dph == 0.0 ) nph = 0;
898 else
899 {
900 while( phi < 0.0 ) phi += 360.0;
901 nph = (int)( (phi - fpat.phis) / fpat.dph + 0.5 );
902 if( (nph >= fpat.nph) || (nph < 0) )
903 nph = fpat.nph-1;
904 }
905
906 idx = nth + nph * fpat.nth;
907 gain = rad_pattern[fstep].gtot[idx] +
908 Polarization_Factor(calc_data.pol_type, fstep, idx);
909 if( gain < -999.99 ) gain = -999.99;
910
911 return( gain );
912
913 } /* Viewer_Gain() */
914
915 /*-----------------------------------------------------------------------*/
916
917 /* Rdpattern_Window_Killed()
918 *
919 * Cleans up after the rad pattern window is closed
920 */
921 void
Rdpattern_Window_Killed(void)922 Rdpattern_Window_Killed( void )
923 {
924 if( animate_dialog != NULL )
925 {
926 gtk_widget_destroy( animate_dialog );
927 animate_dialog = NULL;
928 ClearFlag( NEAREH_ANIMATE );
929 g_source_remove( anim_tag );
930 anim_tag = 0;
931 }
932
933 if( isFlagSet(DRAW_ENABLED) )
934 {
935 ClearFlag( DRAW_FLAGS );
936 rdpattern_drawingarea = NULL;
937 rdpattern_window = NULL;
938 Free_Draw_Buffers();
939
940 gtk_check_menu_item_set_active(
941 GTK_CHECK_MENU_ITEM(lookup_widget(
942 main_window, "main_rdpattern")), FALSE );
943 }
944
945 } /* Rdpattern_Window_Killed() */
946
947 /*-----------------------------------------------------------------------*/
948
949 /* Set_Window_Labels()
950 *
951 * Sets radiation pattern window labels
952 * according to what is being drawn.
953 */
954 void
Set_Window_Labels(void)955 Set_Window_Labels( void )
956 {
957 char *pol_type[NUM_POL] =
958 {
959 _("Total Gain"),
960 _("Horizontal Polarization"),
961 _("Vertical Polarization"),
962 _("RH Circular Polarization"),
963 _("LH Circular Polarization")
964 };
965
966 char *scale[NUM_SCALES] =
967 {
968 _("Linear Power"),
969 _("Linear Voltage"),
970 _("ARRL Scale"),
971 _("Logarithmic Scale")
972 };
973
974 char txt[64];
975 size_t s = sizeof( txt );
976
977 if( isFlagSet(DRAW_ENABLED) )
978 {
979 /* Set window labels */
980 Strlcpy( txt, _("Radiation Patterns"), s );
981 if( isFlagSet(DRAW_GAIN) )
982 {
983 Strlcpy( txt, _("Radiation Pattern: - "), s );
984 Strlcat( txt, pol_type[calc_data.pol_type], s );
985 Strlcat( txt, " - ", s );
986 Strlcat( txt, scale[gain_style], s );
987 }
988 else if( isFlagSet(DRAW_EHFIELD) )
989 {
990 Strlcpy( txt, _("Near Fields:"), s );
991 if( isFlagSet(DRAW_EFIELD) )
992 Strlcat( txt, _(" - E Field"), s );
993 if( isFlagSet(DRAW_HFIELD) )
994 Strlcat( txt, _(" - H Field"), s );
995 if( isFlagSet(DRAW_POYNTING) )
996 Strlcat( txt, _(" - Poynting Vector"), s );
997 }
998
999 gtk_label_set_text( GTK_LABEL(lookup_widget(
1000 rdpattern_window, "rdpattern_label")), txt );
1001
1002 } /* if( isFlagSet(DRAW_ENABLED) ) */
1003
1004 if( isFlagSet(PLOT_ENABLED) )
1005 {
1006 Strlcpy( txt, _("Frequency Data Plots - "), s );
1007 Strlcat( txt, pol_type[calc_data.pol_type], s );
1008 gtk_label_set_text( GTK_LABEL(lookup_widget(
1009 freqplots_window, "freqplots_label")), txt );
1010 }
1011
1012 } /* Set_Window_Labels() */
1013
1014 /*-----------------------------------------------------------------------*/
1015
1016 /* Alloc_Rdpattern_Buffers
1017 *
1018 * Allocates memory to the radiation pattern buffers
1019 */
1020 void
Alloc_Rdpattern_Buffers(int nfrq,int nth,int nph)1021 Alloc_Rdpattern_Buffers( int nfrq, int nth, int nph )
1022 {
1023 int idx;
1024 size_t mreq;
1025 static int last_nfrq = 0;
1026
1027 /* Free old gain buffers first */
1028 for( idx = 0; idx < last_nfrq; idx++ )
1029 {
1030 free_ptr( (void **)&rad_pattern[idx].gtot );
1031 free_ptr( (void **)&rad_pattern[idx].max_gain );
1032 free_ptr( (void **)&rad_pattern[idx].min_gain );
1033 free_ptr( (void **)&rad_pattern[idx].max_gain_tht );
1034 free_ptr( (void **)&rad_pattern[idx].max_gain_phi );
1035 free_ptr( (void **)&rad_pattern[idx].max_gain_idx );
1036 free_ptr( (void **)&rad_pattern[idx].min_gain_idx );
1037 free_ptr( (void **)&rad_pattern[idx].axrt );
1038 free_ptr( (void **)&rad_pattern[idx].tilt );
1039 free_ptr( (void **)&rad_pattern[idx].sens );
1040 }
1041 last_nfrq = nfrq;
1042
1043 /* Allocate rad pattern buffers */
1044 mreq = (size_t)nfrq * sizeof(rad_pattern_t);
1045 mem_realloc( (void **)&rad_pattern, mreq, "in draw_radiation.c" );
1046 for( idx = 0; idx < nfrq; idx++ )
1047 {
1048 /* Memory request for allocs */
1049 mreq = (size_t)(nph * nth) * sizeof(double);
1050 rad_pattern[idx].gtot = NULL;
1051 mem_alloc( (void **)&(rad_pattern[idx].gtot), mreq, "in draw_radiation.c" );
1052 rad_pattern[idx].axrt = NULL;
1053 mem_alloc( (void **)&(rad_pattern[idx].axrt), mreq, "in draw_radiation.c" );
1054 rad_pattern[idx].tilt = NULL;
1055 mem_alloc( (void **)&(rad_pattern[idx].tilt), mreq, "in draw_radiation.c" );
1056
1057 mreq = NUM_POL * sizeof(double);
1058 rad_pattern[idx].max_gain = NULL;
1059 mem_alloc( (void **)&(rad_pattern[idx].max_gain), mreq, "in draw_radiation.c" );
1060 rad_pattern[idx].min_gain = NULL;
1061 mem_alloc( (void **)&(rad_pattern[idx].min_gain), mreq, "in draw_radiation.c" );
1062 rad_pattern[idx].max_gain_tht = NULL;
1063 mem_alloc( (void **)&(rad_pattern[idx].max_gain_tht), mreq, "in draw_radiation.c" );
1064 rad_pattern[idx].max_gain_phi = NULL;
1065 mem_alloc( (void **)&(rad_pattern[idx].max_gain_phi), mreq, "in draw_radiation.c" );
1066
1067 mreq = NUM_POL * sizeof(int);
1068 rad_pattern[idx].max_gain_idx = NULL;
1069 mem_alloc( (void **)&(rad_pattern[idx].max_gain_idx), mreq, "in draw_radiation.c" );
1070 rad_pattern[idx].min_gain_idx = NULL;
1071 mem_alloc( (void **)&(rad_pattern[idx].min_gain_idx), mreq, "in draw_radiation.c" );
1072
1073 rad_pattern[idx].sens = NULL;
1074 mreq = (size_t)(nph * nth) * sizeof(int);
1075 mem_alloc( (void **)&(rad_pattern[idx].sens), mreq, "in draw_radiation.c" );
1076 }
1077
1078 } /* Alloc_Rdpattern_Buffers() */
1079
1080 /*-----------------------------------------------------------------------*/
1081
1082 /* Alloc_Nearfield_Buffers
1083 *
1084 * Allocates memory to the radiation pattern buffers
1085 */
1086 void
Alloc_Nearfield_Buffers(int n1,int n2,int n3)1087 Alloc_Nearfield_Buffers( int n1, int n2, int n3 )
1088 {
1089 size_t mreq;
1090
1091 if( isFlagClear(ALLOC_NEAREH_BUFF) ) return;
1092 ClearFlag( ALLOC_NEAREH_BUFF );
1093
1094 /* Memory request for allocations */
1095 mreq = (size_t)(n1 * n2 * n3) * sizeof( double );
1096
1097 /* Allocate near field buffers */
1098 if( fpat.nfeh & NEAR_EFIELD )
1099 {
1100 mem_realloc( (void **)&near_field.ex, mreq, "in draw_radiation.c" );
1101 mem_realloc( (void **)&near_field.ey, mreq, "in draw_radiation.c" );
1102 mem_realloc( (void **)&near_field.ez, mreq, "in draw_radiation.c" );
1103 mem_realloc( (void **)&near_field.fex, mreq, "in draw_radiation.c" );
1104 mem_realloc( (void **)&near_field.fey, mreq, "in draw_radiation.c" );
1105 mem_realloc( (void **)&near_field.fez, mreq, "in draw_radiation.c" );
1106 mem_realloc( (void **)&near_field.erx, mreq, "in draw_radiation.c" );
1107 mem_realloc( (void **)&near_field.ery, mreq, "in draw_radiation.c" );
1108 mem_realloc( (void **)&near_field.erz, mreq, "in draw_radiation.c" );
1109 mem_realloc( (void **)&near_field.er, mreq, "in draw_radiation.c" );
1110 }
1111
1112 if( fpat.nfeh & NEAR_HFIELD )
1113 {
1114 mem_realloc( (void **)&near_field.hx, mreq, "in draw_radiation.c" );
1115 mem_realloc( (void **)&near_field.hy, mreq, "in draw_radiation.c" );
1116 mem_realloc( (void **)&near_field.hz, mreq, "in draw_radiation.c" );
1117 mem_realloc( (void **)&near_field.fhx, mreq, "in draw_radiation.c" );
1118 mem_realloc( (void **)&near_field.fhy, mreq, "in draw_radiation.c" );
1119 mem_realloc( (void **)&near_field.fhz, mreq, "in draw_radiation.c" );
1120 mem_realloc( (void **)&near_field.hrx, mreq, "in draw_radiation.c" );
1121 mem_realloc( (void **)&near_field.hry, mreq, "in draw_radiation.c" );
1122 mem_realloc( (void **)&near_field.hrz, mreq, "in draw_radiation.c" );
1123 mem_realloc( (void **)&near_field.hr, mreq, "in draw_radiation.c" );
1124 }
1125
1126 mem_realloc( (void **)&near_field.px, mreq, "in draw_radiation.c" );
1127 mem_realloc( (void **)&near_field.py, mreq, "in draw_radiation.c" );
1128 mem_realloc( (void **)&near_field.pz, mreq, "in draw_radiation.c" );
1129
1130 } /* Alloc_Nearfield_Buffers() */
1131
1132 /*-----------------------------------------------------------------------*/
1133
1134 /* Free_Draw_Buffers()
1135 *
1136 * Frees the buffers used for drawing
1137 */
1138 void
Free_Draw_Buffers(void)1139 Free_Draw_Buffers( void )
1140 {
1141 free_ptr( (void **)&point_3d );
1142 free_ptr( (void **)&red );
1143 free_ptr( (void **)&grn );
1144 free_ptr( (void **)&blu );
1145 }
1146
1147 /*-----------------------------------------------------------------------*/
1148
1149