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