1 /*  XNECVIEW - a program for visualizing NEC2 input and output data
2  *
3  *  Copyright (C) 1998-2011, Pieter-Tjerk de Boer -- pa3fwm@amsat.org
4  *
5  *  Distributed on the conditions of version 2 of the GPL: see the files
6  *  README and COPYING, which accompany this source file.
7  */
8 
9 /* ------------------------------------------------------------------------ */
10 
11 
12 #include "config.h"        /* file defining things like default colours etc. */
13 
14 
15 #define VERSION "1.36"
16 
17 
18 typedef struct {     /* structure to describe a point in 3D space */
19    float x,y,z;
20 } Point;
21 
22 typedef struct {     /* structure to describe a straight wire (segment) */
23    Point p0,p1;       /* begin and end point */
24    double rad;        /* radius */
25    int itg;           /* tag number */
26    int ns;            /* number of segments for multi-segment wire; -segmentnumber for single-segment wire that's part of a larger wire (GA and GH cards)  */
27    int abs;           /* absolute segment number of the first segment of this wire */
28    int dispnr;        /* flag: true (nonzero) on any multi-segment wire, and on (a) middle segment for a wire that was split into multiple single-segment wires (GA and GH) */
29 } Wire;
30 
31 typedef struct {     /* structure to describe a surface patch */
32    int type;          /* see below */
33    Point p0,p1,p2,p3; /* corners */
34    Point pc;          /* center */
35    Point pa;          /* tip of outward normal arrow */
36 } Surface;
37 #define SU_rect 1     /* rectangular shape (p2,p3 ignored) */
38 #define SU_arb 2      /* "arbitrary" shape, shown as a set of 8 crossing lines (p2,p3 ignored) */
39 #define SU_tri 3      /* triangle (p3 ignored) */
40 #define SU_quad 4     /* quadrilateral shape */
41 
42 typedef struct {    /* structure to describe an excitation (only voltage sources, EX card) */
43    Wire *wire;        /* pointer to Wire data */
44    int seg;           /* segment number within wire */
45 } Exci;
46 
47 typedef struct {    /* structure to describe a load */
48    Wire *wire;        /* pointer to Wire data */
49    int firstseg;      /* number of first loaded segment within wire */
50    int lastseg;       /* number of last loaded segment within wire */
51 } Load;               /* note: if an LD card specifies a loading which extends over several wires, it is represented here by one Load struct per wire */
52 
53 typedef struct {    /* structure to describe a "network" in the antenna structure; a transmission line is a special case of this */
54    Wire *wire1;       /* pointer to Wire data of one end of the network / transmission line */
55    int seg1;          /* segment number within wire */
56    Wire *wire2;       /* same for the other end of the network / transmission line */
57    int seg2;
58    int type;          /* type: 0 = generic network; 1 = transmission line without phase reversal; -1 = transmission line with phase reversal */
59 } Netw;
60 
61 
62 extern double extr_str;	/* size of the biggest dimension of the structure data to be shown; used for (initial) scaling */
63 extern double extr;	/* size of the biggest dimension of all data to be shown; used for (initial) scaling */
64 
65 extern int quick;         /* flag to indicate that drawing should be rough but quick */
66 extern int redraw;        /* flag which signifies need for redrawing */
67 extern int dragging;      /* flag to indicate that user is dragging the structure */
68 
69                             /* these define the projection: */
70 extern double phi,theta;      /* angles defining direction of eye */
71 extern double zoom;           /* zoom factor */
72 extern double trx,try;        /* 2D-translation, as a fraction of winsize */
73 extern int winsizex,winsizey; /* size of window in pixels */
74 extern int winsize;          /* min(winsizex,winsizey) */
75 
76 extern int gainscale;	     /* type of scaling of gain: */
77 enum { GSlinpower,GSlinvolt,GSarrl,GSlog,numGS };
78 extern char *GSnames[];      /* array with names of gainscales */
79 extern char GSnumbers[][32]; /* array with descriptions of levels of scale lines in plot */
80 
81 extern int gainplot;         /* type of radiation plot: */
82 enum { GPnone,GPslice,GPframe,GPopaque,GPnearfield,numGP };
83 
84 extern int structplot;       /* type of structure plot: */
85 enum { SPnone,SPstruct,SPtags,SPcurrents,SPanim,numSP };
86 
87 extern int scaleplot;        /* flag: plot gain scale? */
88 
89 extern int polarization;     /* polarization for gain and currents displays */
90 enum { POLnone,POLhor,POLvert,POLlhcp,POLrhcp,POLcolour };   /* note: if this order changes, find_fb() may also need to be changed */
91 
92 extern int phasedirlock;     /* flag: is the direction used for calculation phases locked? */
93 extern double phasephi,phasetheta;   /* if so, this is that direction; otherwise, it is identical to phi and theta */
94 
95 extern double phaseoffset;   /* phase offset for currents display */
96 extern int distcor;          /* flag: correct phase for distance to observer? */
97 extern int maxthickness;     /* line thickness used for maximum current in currents display */
98 
99 extern double animphase;     /* phase (in rad) of the "animation" of currents and E and H fields */
100 extern double animfreq;      /* frequency of the animation: number of displayed cycles per second */
101 extern double anim_update_interval;  /* time (in milliseconds) between updates of the animation display */
102 
103 extern double escale;        /* scale factor for the E field */
104 extern double hscale;        /* scale factor for the H field */
105 extern int show_p;           /* flag: display Poynting vector? */
106 extern double qscale;        /* scale factor for the currents */
107 extern double iscale;        /* scale factor for the charges */
108 
109 
110 extern int win2sizex,win2sizey; /* size of freqplot window in pixels */
111 extern int plot2_swr, plot2_z, plot2_z2, plot2_maxgain, plot2_dir, plot2_vgain; /* flags for the each of the frequency plots in window 2 */
112 
113 extern int numwires;
114 extern int maxwires;
115 extern Wire *wires;
116 extern int numsurfaces;
117 extern int maxsurfaces;
118 extern Surface *surfaces;
119 extern int numexcis;
120 extern int maxexcis;
121 extern Exci *excis;
122 extern int numloads;
123 extern int maxloads;
124 extern Load *loads;
125 extern int numnetws;
126 extern int maxnetws;
127 extern Netw *netws;
128 
129 
130 typedef struct {     /* structure to contain, for one direction, the radiated power and polarization information */
131    float total;   /* total radiated power, dBi */
132    float axial;   /* axial ratio, with sign indicating the polarity: + left-hand circular, - right-hand */
133    float tilt;    /* tilt angle of major axis, radians; defined as in NEC output: 0 = vertical, >0 topleft/bottomright */
134 } Gain;
135 
136 typedef struct RAdpattern {    /* structure to contain (far field) radiation pattern for one frequency */
137    double *gtheta;  /* pointer to array of theta values */
138    double *gphi;    /* pointer to array of phi values */
139    Gain **gain;     /* pointer to an array of pointers (one for every phi) to an array of Gain structs (one for every theta at that phi) */
140    Point **gpo;     /* pointer to an array of pointers (one for every phi) to an array of Points (one for every theta at that phi) */
141    int numtheta;    /* number of theta values */
142    int numphi;      /* number of phi values */
143    struct RAdpattern *next;    /* pointer to the next such structure, used if more than one set of radiation pattern data is available for one frequency */
144    double *sin_gtheta;   /* pointer to an array containing the sines of the theta values */
145    double *sin_gphi;     /* ... etc. for phi */
146    double *cos_gtheta;   /* ... and cosines */
147    double *cos_gphi;
148 } Radpattern;
149 
150 
151 typedef struct {   /* structure to contain the current (phase, magnitude, location, direction) information of one segment */
152    /* note: part of the below information is in principle also available in the
153       arrays describing the antenna's structure as read from the NEC input file;
154       however, it seems more consistent to read this structure information now from the
155       NEC output file, so we're sure we have the right data even if the input and output
156       files are (accidentally) from different models.
157    */
158    /* note2: the current in surface patches is also represented by the below structure;
159       basically, a surface patch current is transformed into two equivalent segments,
160       although in many practical cases one of them carries almost no current and can
161       therefore be omitted.
162    */
163    /* note3: for the animations, it is more convenient to have real and imaginary
164       vectors. For segment currents, these obviously point in the same (or opposite)
165       directions, namely along the segment. For surface currents, they are non-
166       trivial; however, we don't need a second segment here (in contrast to the
167       other representation), so only the first 'numanimseg' (see below, Currents
168       structure) segments contain valid data in re[] and im[].
169    */
170    /* note4: although the name suggests otherwise, this structure can also contain
171       charge information.
172    */
173    Point p0,p1;  /* coordinates of segment endpoints */
174    Point c;      /* coordinate of segment center point */
175    float a;     /* amplitude of the current */
176    float phase; /* phase of the current (degrees) */
177    float dist;  /* distance of center of segment from the plane through the origin, perpendicular to the viewing direction; positive if in front of this plane, negative otherwise */
178    float area;  /* area of a surface patch */
179    float re[3],im[3]; /* real and imaginary vector */
180    float q0[3],q1[3]; /* two unity vectors, orthogonal to each other and to the direction of the segment; used for drawing charges */
181    float qre,qim;  /* real and imaginary value of the charge */
182 } Segcur;
183 
184 typedef struct {   /* structure to contain the current distribution for all segments at one frequency */
185    Segcur *s;
186    int maxseg;       /* current size of s[] */
187    int numseg;       /* number of valid entries in s[] */
188    int numanimseg;   /* number of those that are needed for the animations; i.e., excluding the extra segments caused by the decomposition of the surface patch currents */
189    int numrealseg;   /* number of those that are actually segments; so s[numrealseg...numseg-1] are surface patches */
190    double maxI;      /* highest segment current */
191    double maxQ;      /* highest segment charge */
192 } Currents;
193 
194 
195 typedef struct NF { /* structure to contain the electric and magnetic field at some point (near the antenna) */
196    Point p;           /* location of the point */
197    int evalid,hvalid; /* flags to indicate presence of E and H data */
198    float ere[3];     /* real component of E vector */
199    float eim[3];     /* imaginary component of E vector */
200    float hre[3];     /* real component of H vector */
201    float him[3];     /* imaginary component of H vector */
202    float poy[3];     /* time-averaged Poynting vector */
203    struct NF *next;   /* pointer to next datapoint */
204 } Nearfield;
205 
206 
207 
208 /* indices in the element 'd' of the NECoutput structure defined below: */
209 enum {
210    neco_zr, neco_zi,       /* index of real and imaginary part of impedance */
211    neco_zphi, neco_zabs,   /* phi and absolute value of impedance */
212    neco_swr,               /* index of SWR */
213    neco_maxgain, neco_fb,  /* index of maximum gain and corresponding front/back ratio */
214    neco_phi, neco_theta,   /* index direction of maximum gain */
215    neco_vgain, neco_vfb,   /* index of gain in viewing direction and corresponding f/b ratio */
216    neco_vgain2, neco_vfb2, /* same, but taking polarization into account; fb/fb2 as fb1/fb2 below */
217    neco_maxgain_hor, neco_fb_hor1, neco_fb_hor2, neco_phi_hor, neco_theta_hor,
218    neco_maxgain_vert, neco_fb_vert1, neco_fb_vert2, neco_phi_vert, neco_theta_vert,
219    neco_maxgain_lhcp, neco_fb_lhcp1, neco_fb_lhcp2, neco_phi_lhcp, neco_theta_lhcp,
220    neco_maxgain_rhcp, neco_fb_rhcp1, neco_fb_rhcp2, neco_phi_rhcp, neco_theta_rhcp,
221    neco_numdat             /* last element of the enum: number of elements in the array */
222 };
223 /* since (maximum) gain and corresponding quantities are not available in all NECoutput records,
224    the following macro is needed to tell whether a quantity is available always, or only if
225    radiation pattern data is available in the record: */
226 #define ONLY_IF_RP(i) ((i)>=neco_maxgain)
227 /* a constant for more systematic access to the polarization-specific fields: */
228 #define Neco_gsize 5     /* group size */
229 #define Neco_polgain (neco_maxgain_hor-Neco_gsize)
230 #define Neco_polfb1 (neco_fb_hor1-Neco_gsize)
231 #define Neco_polfb2 (neco_fb_hor2-Neco_gsize)
232 #define Neco_polphi (neco_phi_hor-Neco_gsize)
233 #define Neco_poltheta (neco_theta_hor-Neco_gsize)
234 /* now, we can write say  neco_phi_lhcp  as  Neco_gsize*POLlhcp+Neco_polphi  */
235 /* note: fb...1 is f/b ratio for this polarization; fb...2 is same but for back total power is used */
236 
237 typedef struct {    /* structure to contain all output data that NEC produces for one frequency */
238    double f;          /* frequency in MHz */
239    Radpattern *rp;    /* pointer to radiation pattern data, if available; NULL otherwise */
240    double d[neco_numdat];
241    int rpgpovalid;    /* flag: !=0 if the gpo field of *rp already contains valid data for the present settings */
242    Currents *cu;      /* pointer to currents data, if available; NULL otherwise */
243    Nearfield *nf;     /* pointer to nearfield data, if available; NULL otherwise */
244    double maxe,maxh;  /* largest values of E and H in nearfield data */
245 } NECoutput;
246 
247 extern NECoutput *neco;
248 extern int numneco;
249 extern int maxfreqs;
250 
251 extern double globalmaxdb; /* maximum gain, global over all frequencies and all output data files */
252 
253 extern int rp_index;       /* index of the entry in neco[] whose radiation pattern is being shown in the 3D plot */
254 
255 extern double r0;          /* reference impedance for SWR calculations */
256 
257 extern int window1open;
258 extern int window2open;
259 
260 
261 extern char *inputfilename;
262 
263 extern int fontheight;
264 
265 #ifndef GdkColor
266    #include <gdk/gdk.h>
267 #endif
268 #define c_bg    col[0]
269 #define c_axis  col[1]
270 #define c_wire  col[2]
271 #define c_surf  col[3]
272 #define c_back  col[4]
273 #define c_gain  col[5]
274 #define c_scale col[6]
275 #define c_exci  col[7]
276 #define c_load  col[8]
277 #define c_netw  col[9]
278 #define c_inactive col[10]
279 #define c_efield   col[11]
280 #define c_hfield   col[12]
281 #define c_poynting col[13]
282 #define c_qpos     col[14]
283 #define c_qneg     col[15]
284 #define c_gain_lin   col[16]
285 #define c_gain_lhcp  col[17]
286 #define c_gain_rhcp  col[18]
287 #define c_currents (col+19)
288 #define NC NC_phase+19
289 extern GdkColor col[NC];
290 
291 
292 
293 typedef struct {
294    void (*SetLineAttributes)(unsigned int,int,int,int);
295    void (*DrawLine)(double,double,double,double);
296    void (*SetForeground)(GdkColor *);
297    void (*ClearWindow)();
298    void (*DrawString)(double,double,char*,double,double);
299    void (*Complete)();
300    void (*SetClipRectangle)(double,double,double,double);
301    void (*ClearRectangle)(double,double,double,double);
302 } Outdev;
303 
304 extern Outdev *out;   /* pointer to Outdev struct, determines destination of drawing commands issued through the below macros: */
305 
306 #define SetLineAttributes(a,b,c,d) out->SetLineAttributes((a),(b),(c),(d))
307 #define DrawLine(a,b,c,d) out->DrawLine((a),(b),(c),(d))
308 #define SetForeground(a) out->SetForeground(a)
309 #define ClearWindow() out->ClearWindow()
310 #define DrawStringLL(a,b,c) DrawString(a,b,c,0,0)     /* draw text specifying lower left corner */
311 #define DrawStringUL(a,b,c) DrawString(a,b,c,0,1)     /* draw text specifying upper left corner */
312 #define DrawString(a,b,c,d,e) out->DrawString(a,b,c,d,e) /* draw text specifying a corner defined by d and e:
313                                                             d = 0...1 for left...right; e = 0...1 for lower...upper  */
314 #define SetClipRectangle(a,b,c,d) out->SetClipRectangle(a,b,c,d)  /* set clip rectangle to (a,b)..(c,d) */
315 #define ClearRectangle(a,b,c,d) out->ClearRectangle(a,b,c,d)  /* clear part of window */
316 
317 
318 void removecommas(char *p);                 /* change commas in string into spaces */
319 
320 void updateextremes(Point *p);              /* update the value of extr_str with information about this Point */
321 
322 void read_nec_input(FILE *f);               /* read the input file, and update the arrays of wires and surfaces accordingly */
323 
324 int read_nec_output(FILE *f);               /* tries to read NEC output data from f, updates gain distribution arrays; returns 1 if not succesful */
325 
326 void process_nec_output(NECoutput *ne);     /* transform the gain data array into an array of points in 3D space */
327 
328 void calc_vgain(void);                      /* update the vgain records in accordance with the viewing direction */
329 
330 void mark_gpo_invalid(void);                /* mark gpo fields as invalid; must be called after every change of gain scale */
331 
332 void calcswr(NECoutput *ne);                /* calculate the SWR from zr and zi */
333 
334 void calcphiabs(NECoutput *ne);             /* calculate phi and abs of impedance from zr and zi */
335 
336 void initX(int *argcp,char **argv);         /* initialize the X-window stuff */
337 
338 void mainX(int really);                     /* main loop (wait for event, process event, redisplay) */
339 
340 int Pending(void);                          /* test whether events are pending; returns !=0 if present (drawing) action should be interrupted */
341 
342 void reread(void);                          /* reread the input file(s) */
343 
344 void process_optionstring(char *s);         /* process a set of options, contained in the string s */
345 
346 void draw_all(int ie);                      /* draw antenna structure and/or gain pattern; ie=interupt_enable */
347 
348 void calcproj(void);                        /* calculate the projection matrix etc. */
349 
350 int write_png(int which,const char *filename);    /* write window 1 or 2 to an PNG file; return !=0 in case of error */
351 
352 int write_postscript(const char *filename,void (*drawfn)(int),int xsize, int ysize);
353                                             /* write postscript to file; return !=0 in case of error */
354 
355 void draw_all2(int dummy);                  /* draw plot(s) vs. frequency */
356 
357 double xfreq(int x);                        /* return frequency corresponding to X coordinate in frequency plot */
358 int freqx(double f);                        /* return X coordinate corresponding to frequency */
359 int freqindex(double f);                    /* return index in neco[] of data closest to frequency f */
360 
361 void *mymalloc(size_t n);                   /* like malloc(), but exits with error message if memory not available; implementation in parse_output.c */
362 void *myrealloc(void *,size_t n);           /* like realloc(), but exits with error message if memory not available; implementation in parse_output.c */
363 
364 void draw_opaque(Radpattern *);             /* draw radiation pattern as an opaque surface */
365 
366 void setpolcolour(double axial);            /* set the colour corresponding to this axial ratio */
367 
368 char *opaque_impossible(Radpattern *rp);    /* returns NULL if opaque drawing of this Radpattern is possible; otherwise, pointer to string with explanation */
369 
370 
371 /* a macro for conveniently expanding array sizes: */
372 #define EXPAND_IF_NECESSARY(num,max,pointer)                \
373    if (num>=max) {                                          \
374       while (max<num+1) max=max*2;                          \
375       pointer=myrealloc(pointer,max*(sizeof(*pointer)));    \
376    }
377 
378 /* if your system doesn't have the function drem() available, uncomment
379    the following line and recompile (after deleting *.o)
380 */
381 /*  #define drem(x,y) ( (x) - (y)*rint((x)/(y)) )   */
382 
383