PUMA  219
Portable University Model of the Atmosphere
/Users/home/WC/puma/src/pumax.c
Go to the documentation of this file.
00001 /*
00002     pumax - a GUI for PUMA & PLASIM
00003     (c) 2007 Edilbert Kirk (E.Kirk@gmx.de)
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00020 int Debug = 0; // set in initgui
00021 
00022 #include <ctype.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <math.h>
00027 #include <sys/time.h>
00028 #include <sys/resource.h>
00029 #include <X11/Xlib.h>
00030 #include <X11/Xutil.h>
00031 #include <X11/Xos.h>
00032 #include <X11/Xatom.h>
00033 #include <X11/keysym.h>
00034 
00035 #define INT int
00036 #define REAL float
00037 #define INTXU unsigned int
00038 #define INTXS int
00039 
00040 #ifndef MIN
00041 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00042 #endif
00043 
00044 #ifndef MAX
00045 #define MAX(a,b) ((a) > (b) ? (a) : (b))
00046 #endif
00047 
00048 #define ROTATE_LEFT  (XK_Left)
00049 #define ROTATE_RIGHT (XK_Right)
00050 
00051 #define TOLELO 0x0001
00052 #define TOLEHI 0x0002
00053 #define TORILO 0x0004
00054 #define TORIHI 0x0008
00055 #define BOLELO 0x0010
00056 #define BOLEHI 0x0020
00057 #define BORILO 0x0040
00058 #define BORIHI 0x0080
00059 #define TOLEIN 0x0100
00060 #define TOREIN 0x0200
00061 #define BOLEIN 0x0400
00062 #define BOREIN 0x0800
00063 
00064 #define IPX(l,m,h) (VGAX * (x + (l-m) / (l-h)))
00065 #define IPY(l,m,h) (VGAY * (y + (l-m) / (l-h)))
00066 
00067 #define NUMWIN 9
00068 #define NUMPAL 13
00069 
00070 /* Picture types */
00071 
00072 #define ISOHOR  0
00073 #define ISOCS   1
00074 #define ISOHOV  2
00075 #define ISOTS   3
00076 #define ISOTAB  4
00077 #define ISOSH   5
00078 #define ISOLON  6
00079 #define ISOTRA  7
00080 #define ISOCOL  8
00081 #define ISOROT  9
00082 #define MAPHOR 10
00083 #define MAPTRA 11
00084 
00085 /* Models */
00086 
00087 #define PUMA   0
00088 
00089 char *IsoNames[] =
00090 {
00091    "ISOHOR",
00092    "ISOCS",
00093    "ISOHOV",
00094    "ISOTS",
00095    "ISOTAB",
00096    "ISOSH",
00097    "ISOLON",
00098    "ISOTRA",
00099    "ISOCOL",
00100    "ISOROT",
00101    "MAPHOR",
00102    "MAPTRA"
00103 };
00104 
00105 int IsoTypes = sizeof(IsoNames) / sizeof(char *);
00106 
00107 char *PalNames[] =
00108 {
00109    "AUTO",
00110    "U",
00111    "V",
00112    "T",
00113    "P",
00114    "Q",
00115    "MARST",
00116    "AMPLI",
00117    "VEG",
00118    "OCET",
00119    "OCES",
00120    "DCC",
00121    "DTDT"
00122 };
00123 
00124 int PalTypes = sizeof(PalNames) / sizeof(char *);
00125 
00126 /* Map projections */
00127 
00128 #define CYLINDRICAL 0
00129 #define POLAR       1
00130 #define AZIMUTHAL   2
00131 
00132 #define MAXMAPS     3
00133 
00134 char *ProNames[] =
00135 {
00136    "CYLINDRICAL",
00137    "POLAR",
00138    "AZIMUTHAL"
00139 };
00140 
00141 
00142 /* Coordinates of button areas */
00143 
00144 int ShowQueue = 0;
00145 int ShowOnce  = 1;
00146 int OffsetY = 20;
00147 
00148 int Stop_XL;
00149 int Stop_XH;
00150 int Stop_YL;
00151 int Stop_YH;
00152 
00153 int Start_XL;
00154 int Start_XH;
00155 int Start_YL;
00156 int Start_YH;
00157 
00158 int Pause_XL;
00159 int Pause_XH;
00160 int Pause_YL;
00161 int Pause_YH;
00162 
00163 int Help_XL;
00164 int Help_XH;
00165 int Help_YL;
00166 int Help_YH;
00167 
00168 int Minus_XL;
00169 int Minus_XH;
00170 int Minus_YL;
00171 int Minus_YH;
00172 
00173 int FBWD_XL;
00174 int FBWD_XH;
00175 int FBWD_YL;
00176 int FBWD_YH;
00177 
00178 int Plus_XL;
00179 int Plus_XH;
00180 int Plus_YL;
00181 int Plus_YH;
00182 
00183 int FFWD_XL;
00184 int FFWD_XH;
00185 int FFWD_YL;
00186 int FFWD_YH;
00187 
00188 int Parc_XL;
00189 int Parc_XH;
00190 int Parc_XD;
00191 int Parc_YL;
00192 int Parc_YH;
00193 int Parc_YD;
00194 
00195 int Wbox_XL;
00196 int Wbox_XH;
00197 int Wbox_YL;
00198 int Wbox_YH;
00199 
00200 int Grid_XL;
00201 int Grid_XH;
00202 int Grid_YL;
00203 int Grid_YH;
00204 
00205 XPoint StopButton[4] = {{10,10},{40,10},{40,40},{10,40}};
00206 XPoint StartButton[3] = {{50,10},{80,25},{50,40}};
00207 XPoint PauseButton1[4] = {{95,10},{102,10},{102,40},{95,40}};
00208 XPoint PauseButton2[4] = {{108,10},{115,10},{115,40},{108,40}};
00209 
00210 #define PARCS 100
00211 
00212 struct ParcStruct
00213 {
00214    char Name[8];
00215    float Inc;
00216    float Min;
00217    float Max;
00218    float Val;
00219 };
00220 
00221 int Parcs;
00222 int cpi = 1;
00223 
00224 struct ParcStruct Parc[PARCS];
00225 
00226 int screen_num;
00227 
00228 Display *display;
00229 unsigned int ScreenW,ScreenH,ScreenBot;
00230 int SmallScreen;
00231 
00232 static char *progname = "PUMA";
00233 
00234 int BigEndian;
00235 int ScreenOffset;
00236 int Model;
00237 int CowX = -1;
00238 int CowY = -1;
00239 int CowW;
00240 int CowH;
00241 int NumWin = NUMWIN;
00242 int WinCols = 3;
00243 int WinRows = 3;
00244 int DimT = 100; // Default length of time axis
00245 int DimX;
00246 int DimY;
00247 int DimZ;
00248 int DimXY;
00249 int Uindex = -1;
00250 int Vindex = -1;
00251 int ScreenD;
00252 int OffX;
00253 int OffY = 0;
00254 INTXU WinXSize;
00255 INTXU WinYSize;
00256 int InXSize;
00257 int InYSize;
00258 int Latitudes;
00259 int Lines;
00260 int SizeChanged;
00261 int Shutdown;
00262 int Grid = 1;
00263 int GridLabel = 1;
00264 int WhitePix;
00265 int BlackPix;
00266 int *Flag;
00267 int FlagSize;
00268 int nstep;
00269 int MRpid;
00270 int MRnum;
00271 int wto;
00272 int FirstKey;
00273 int LastKey;
00274 int SymsPerKey;
00275 
00276 KeySym *KeyMap;
00277 
00278 char wtrun[8];
00279 
00280 unsigned Seed;
00281 
00282 float RotInc = 0.2;
00283 int LineCo[NUMPAL];
00284 int MapPro[NUMWIN];
00285 int HovInx[NUMWIN];
00286 int Indez[NUMWIN];
00287 int MaxZ[NUMWIN];
00288 int RedrawFlag[NUMWIN];
00289 int LevelChanged[NUMWIN];
00290 int RotLon[NUMWIN];
00291 double AutoDelta[NUMWIN];
00292 double AutoXdelt[NUMWIN];
00293 double AutoLo[NUMWIN];
00294 REAL *TSdata[NUMWIN];
00295 REAL *Dmin[NUMWIN];
00296 REAL *Dmax[NUMWIN];
00297 REAL *SpeedScale;
00298 XPoint *TSxp[NUMWIN];
00299 
00300 
00301 #define MAXPAR 16384
00302 float pax[MAXPAR];
00303 float pay[MAXPAR];
00304 long  pal[MAXPAR];
00305 
00306 int Delpar = 8; /* Interval for particle injection */
00307 int ParInd = 0;
00308 int ColInd = 0;
00309 long TracerColor;
00310 
00311 #define NUMSCALARS 9
00312 
00313 char TSName[NUMSCALARS][80];
00314 char TSubsc[NUMSCALARS][80];
00315 char TSUnit[NUMSCALARS][80];
00316 char TScale[NUMSCALARS][80];
00317 
00318 struct PixStruct
00319 {
00320    int DimX;
00321    int DimY;
00322    Pixmap Pix;
00323 } WinPixMap[NUMWIN];
00324 
00325 Pixmap pix;
00326 
00327 #define NUMARRAYS 100
00328 
00329 struct ArrayStruct
00330 {
00331    char Name[80];
00332    float *Data;
00333    int DimX;
00334    int DimY;
00335    int DimZ;
00336    int Flag;
00337 } Array[NUMARRAYS];
00338 
00339 int NumArrays;
00340 
00341 struct WinAttStruct
00342 {
00343    unsigned int x;
00344    unsigned int y;
00345    unsigned int w;
00346    unsigned int h;
00347    int active;
00348    char array_name[80];
00349    int Plot;
00350    int Palette;
00351 } WinAtt[NUMWIN];
00352 
00353 int BorderWidth =  0;
00354 int WM_top_area =  0; // Window manager top    area
00355 int WinLM       =  0;
00356 int WinRM       =  0;
00357 int WinTM       = 24;
00358 int WinBM       =  0;
00359 
00360 struct ColorStrip
00361 {
00362    double  Lo;
00363    double  Hi;
00364    char *Name;
00365    unsigned long pixel;
00366 };
00367 
00368 #define AUTOCOLORS 14
00369 struct ColorStrip Autostrip[AUTOCOLORS+1] =
00370 {
00371    {0.0,0.0,"red"},
00372    {0.0,0.0,"OrangeRed"},
00373    {0.0,0.0,"Orange"},
00374    {0.0,0.0,"yellow"},
00375    {0.0,0.0,"GreenYellow"},
00376    {0.0,0.0,"green"},
00377    {0.0,0.0,"aquamarine"},
00378    {0.0,0.0,"cyan"},
00379    {0.0,0.0,"SkyBlue"},
00380    {0.0,0.0,"blue"},
00381    {0.0,0.0,"orchid"},
00382    {0.0,0.0,"magenta"},
00383    {0.0,0.0,"violet"},
00384    {0.0,0.0,"DarkViolet"},
00385    {0.0,0.0,NULL}
00386 };
00387 
00388 struct ColorStrip Ustrip[] =
00389 {
00390    {-99.0,-10.0,"red"},
00391    {-10.0, -5.0,"OrangeRed"},
00392    { -5.0,  0.0,"Orange"},
00393    {  0.0,  5.0,"yellow"},
00394    {  5.0, 10.0,"GreenYellow"},
00395    { 10.0, 15.0,"green"},
00396    { 15.0, 20.0,"aquamarine"},
00397    { 20.0, 25.0,"cyan"},
00398    { 25.0, 30.0,"SkyBlue"},
00399    { 30.0, 35.0,"blue"},
00400    { 35.0, 40.0,"orchid"},
00401    { 40.0, 45.0,"magenta"},
00402    { 45.0, 50.0,"violet"},
00403    { 50.0, 99.0,"DarkViolet"},
00404    {  0.0,  0.0,NULL}
00405 };
00406 
00407 struct ColorStrip Qstrip[] =
00408 {
00409    {-99.0,  0.0,"black"},
00410    {  0.0,  5.0,"OrangeRed"},
00411    {  5.0, 10.0,"Orange"},
00412    { 10.0, 15.0,"yellow"},
00413    { 15.0, 20.0,"GreenYellow"},
00414    { 20.0, 25.0,"green"},
00415    { 25.0, 30.0,"aquamarine"},
00416    { 30.0, 35.0,"cyan"},
00417    { 35.0, 40.0,"SkyBlue"},
00418    { 40.0, 45.0,"blue"},
00419    { 45.0, 50.0,"orchid"},
00420    { 50.0, 55.0,"magenta"},
00421    { 55.0, 60.0,"violet"},
00422    { 60.0, 99.0,"DarkViolet"},
00423    {  0.0,  0.0,NULL}
00424 };
00425 
00426 struct ColorStrip Vstrip[] =
00427 {
00428    {-99.0,-10.0,"brown"},
00429    {-10.0, -8.0,"gold"},
00430    { -8.0, -6.0,"purple"},
00431    { -6.0, -4.0,"red"},
00432    { -4.0, -2.0,"OrangeRed"},
00433    { -2.0,  0.0,"Orange"},
00434    {  0.0,  2.0,"yellow"},
00435    {  2.0,  4.0,"GreenYellow"},
00436    {  4.0,  6.0,"green"},
00437    {  6.0,  8.0,"aquamarine"},
00438    {  8.0, 10.0,"cyan"},
00439    { 10.0, 99.0,"blue"},
00440    {  0.0,  0.0,NULL}
00441 };
00442 
00443 struct ColorStrip Tstrip[] =
00444 {
00445    {-99.0,-50.0,"MidnightBlue"},
00446    {-50.0,-40.0,"RoyalBlue4"},
00447    {-40.0,-30.0,"RoyalBlue3"},
00448    {-30.0,-20.0,"RoyalBlue2"},
00449    {-20.0,-10.0,"RoyalBlue1"},
00450    {-10.0,  0.0,"violet"},
00451    {  0.0, 10.0,"IndianRed1"},
00452    { 10.0, 20.0,"IndianRed2"},
00453    { 20.0, 30.0,"IndianRed3"},
00454    { 30.0, 40.0,"IndianRed4"},
00455    { 40.0, 50.0,"red"},
00456    {  0.0,  0.0,NULL}
00457 };
00458 
00459 struct ColorStrip Kstrip[] =
00460 {
00461    {100.0,210.0,"RoyalBlue4"},
00462    {210.0,220.0,"RoyalBlue3"},
00463    {220.0,230.0,"RoyalBlue2"},
00464    {230.0,240.0,"RoyalBlue1"},
00465    {240.0,250.0,"violet"},
00466    {250.0,260.0,"IndianRed1"},
00467    {260.0,270.0,"IndianRed2"},
00468    {270.0,280.0,"IndianRed3"},
00469    {280.0,290.0,"IndianRed4"},
00470    {290.0,400.0,"red"},
00471    {  0.0,  0.0,NULL}
00472 };
00473 
00474 struct ColorStrip Pstrip[] =
00475 {
00476    {  00.0, 985.0,"RoyalBlue4"},
00477    { 985.0, 990.0,"RoyalBlue3"},
00478    { 990.0, 995.0,"RoyalBlue2"},
00479    { 995.0,1000.0,"RoyalBlue1"},
00480    {1000.0,1005.0,"violet"},
00481    {1005.0,1010.0,"IndianRed1"},
00482    {1010.0,1015.0,"IndianRed2"},
00483    {1015.0,1020.0,"IndianRed3"},
00484    {1020.0,1025.0,"IndianRed4"},
00485    {1025.0,9990.0,"red"},
00486    {  0.0,  0.0,NULL}
00487 };
00488 
00489 struct ColorStrip MarsTStrip[] =
00490 {
00491    {-200.0,-90.0,"RoyalBlue4"},
00492    { -90.0,-80.0,"RoyalBlue3"},
00493    { -80.0,-70.0,"RoyalBlue2"},
00494    { -70.0,-60.0,"RoyalBlue1"},
00495    { -60.0,-50.0,"violet"},
00496    { -50.0,-40.0,"IndianRed1"},
00497    { -40.0,-30.0,"IndianRed2"},
00498    { -30.0,-20.0,"IndianRed3"},
00499    { -20.0,  0.0,"IndianRed4"},
00500    {   0.0,100.0,"red"},
00501    {   0.0,  0.0,NULL}
00502 };
00503 
00504 struct ColorStrip AmpliStrip[] =
00505 {
00506    {   0.0,  1.0,"DarkBlue"},
00507    {   8.0,  9.0,"blue"},
00508    {   8.0,  9.0,"DarkGreen"},
00509    {   8.0,  9.0,"green"},
00510    {   8.0,  9.0,"yellow"},
00511    {   9.0, 10.0,"Orange"},
00512    {  10.0, 11.0,"OrangeRed"},
00513    {  11.0, 12.0,"red"},
00514    {   0.0,  0.0,NULL}
00515 };
00516 
00517 struct ColorStrip Vegstrip[] =
00518 {
00519    {-999.9,0.001,"DarkBlue"},
00520    { 0.001, 10.0,"brown"},
00521    {  10.0, 20.0,"SeaGreen4"},
00522    {  20.0, 30.0,"SeaGreen3"},
00523    {  30.0, 40.0,"SeaGreen2"},
00524    {  40.0, 50.0,"SeaGreen1"},
00525    {  50.0, 60.0,"YellowGreen"},
00526    {  60.0, 70.0,"green4"},
00527    {  70.0, 80.0,"green3"},
00528    {  80.0, 90.0,"green2"},
00529    {  90.0,999.0,"green1"},
00530    {   0.0,  0.0,NULL}
00531 };
00532 
00533 struct ColorStrip Tstripoce[] =
00534 {
00535    {-99.0, 0.00001,"Black"},
00536    { 0.00001, 4.0 ,"RoyalBlue4"},
00537    { 4.0 ,8.0,"RoyalBlue3"},
00538    { 8.0, 12.0,"RoyalBlue2"},
00539    { 12.0, 16.0,"RoyalBlue1"},
00540    { 16.0, 20.0,"violet"},
00541    { 20.0, 24.0,"IndianRed1"},
00542    { 24.0, 28.0,"IndianRed2"},
00543    { 28.0, 32.0,"IndianRed3"},
00544    { 32.0, 36.0,"IndianRed4"},
00545    { 36.0, 40.0,"red"},
00546    {  0.0,  0.0,NULL}
00547 };
00548 
00549 struct ColorStrip Sstripoce[] =
00550 {
00551    {-99.0, 30.0,"Black"},
00552    { 30.0, 32.0 ,"RoyalBlue4"},
00553    { 32.0 ,32.5,"RoyalBlue3"},
00554    { 32.5, 33.0,"RoyalBlue2"},
00555    { 33.0, 34.0,"SeaGreen"},
00556    { 34.0, 34.5,"YellowGreen"},
00557    { 34.5, 35.0,"LightGreen"},
00558    { 35.0, 35.5,"Orange"},
00559    { 35.5, 36.0,"DarkOrange"},
00560    { 36.0, 36.5,"OrangeRed"},
00561    { 36.5, 40.0,"red"},
00562    {  0.0,  0.0,NULL}
00563 };
00564 
00565 struct ColorStrip DCCstrip[] =
00566 {
00567    {-99.0, 0.0, "Black"},
00568    {  0.0, 10.0,"Yellow"},
00569    { 10.0, 20.0,"YellowGreen"},
00570    { 20.0, 30.0,"Green"},
00571    { 30.0, 40.0,"Aquamarine"},
00572    { 40.0, 50.0,"Cyan"},
00573    { 50.0, 60.0,"SkyBlue"},
00574    { 60.0, 70.0,"Blue"},
00575    { 70.0, 80.0,"Orchid"},
00576    { 80.0, 90.0,"Magenta"},
00577    { 90.0,100.0,"DarkViolet"},
00578    { 0.0, 0.0,NULL}
00579 };
00580 
00581 struct ColorStrip DTDTstrip[] =
00582 {
00583    {-99.0,  -5.0,"brown"},
00584    {- 5.0,  -3.0,"gold"},
00585    { -3.0,  -1.5,"purple"},
00586    { -1.5,  -0.5,"red"},
00587    { -0.5,  -0.25,"OrangeRed"},
00588    { -0.25,  0.0,"Orange"},
00589    {  0.0,   0.25,"yellow"},
00590    {  0.25,  0.5,"GreenYellow"},
00591    {  0.5,   1.5,"green"},
00592    {  1.5,   3.0,"aquamarine"},
00593    {  3.0,   5.0,"cyan"},
00594    {  5.0, 99.0,"blue"},
00595    {  0.0,  0.0,NULL}
00596 };
00597 
00598 #define AMPLI_COLS 8
00599 
00600 struct ColorStrip *Cstrip;
00601 struct ColorStrip *Pallet[NUMPAL] =
00602 { Autostrip, Ustrip, Vstrip, Tstrip, Pstrip, Qstrip,MarsTStrip,AmpliStrip,
00603   Vegstrip, Tstripoce, Sstripoce, DCCstrip, DTDTstrip};
00604 
00605 REAL VGAX;
00606 REAL VGAY;
00607 REAL CurVal;
00608 
00609 REAL *Field;  // Pointer for ISO data
00610 REAL *Ampli;  // Amplitudes of spherical harmonics
00611 XColor *Acol; // Amplitude colors
00612 
00613 Colormap colormap;
00614 
00615 XColor xcolor1,xcolor2;
00616 XColor Red,Green,Blue,Yellow,Grey,LightRed,DarkRed,LightBlue,DarkBlue;
00617 XColor LightGreen,DarkGreen,Dummy;
00618 
00619 unsigned long TSColor[10];
00620 
00621 Window Win[NUMWIN];
00622 int    win; // Current window
00623 Window Cow; // Control bar
00624 Window HelpWindow;
00625 
00626 XTextProperty WinconName1;
00627 XTextProperty WinconName3;
00628 XTextProperty WinconPause;
00629 XTextProperty WinconReady;
00630 char *PauseTitle = "Run Paused";
00631 char *ReadyTitle = "Press Start Button";
00632 
00633 XEvent CowEvent;
00634 
00635 XSizeHints WinSizeHints;
00636 XSizeHints CowSizeHints;
00637 int OutXSize,OutYSize;
00638 int count;
00639 XEvent report;
00640 GC gc;
00641 
00642 /*
00643 char BigFontName[80] = "10x20";
00644 char FixFontName[80] = "9x15bold";
00645 char SubFontName[80] = "6x10";
00646 */
00647 char BigFontName[80] = "9x15bold";
00648 char FixFontName[80] = "8x13";
00649 char SubFontName[80] = "6x10";
00650 
00651 XFontStruct *FixFont;
00652 XFontStruct *SubFont;
00653 XFontStruct *BigFont;
00654 int FixFontHeight;
00655 int SubFontHeight;
00656 int BigFontHeight;
00657 int FixFontWidth;
00658 int SubFontWidth;
00659 int BigFontWidth;
00660 int Paused = 0;
00661 
00662 char *display_name = NULL;
00663 XWMHints wm_hints;
00664 XClassHint class_hints;
00665 Atom Delwin;
00666 
00667 char *WindowTitle[NUMWIN];
00668 XTextProperty WindowName[NUMWIN];
00669 XTextProperty HelpName;
00670 
00671 char *mona[12] =
00672 {
00673    "Jan","Feb","Mar",
00674    "Apr","May","Jun",
00675    "Jul","Aug","Sep",
00676    "Oct","Nov","Dec"
00677 };
00678 
00679 char *wena[7] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
00680 
00681 char datch[64];
00682 char PlanetName[32] = "Earth";
00683 
00684 char GUI_default[80] = "GUI.cfg";
00685 char GUI_config[80] = "GUI_last_used.cfg";
00686 
00687 
00688 #define PSDIM 30
00689 char *pixelstar[PSDIM]  = {
00690 "..............................",
00691 "..............................",
00692 "..............................",
00693 "...**....**....**....**.......",
00694 "...**....**....**....**.......",
00695 "...**....**....**....**.......",
00696 "...**....**....**....**.......",
00697 "...**....**************.......",
00698 "...**....**************.......",
00699 "...**....**....**....**.......",
00700 "...***...**....**....**.......",
00701 "....******.....**....**.......",
00702 ".....****......**....**.......",
00703 "..............................",
00704 "..............................",
00705 "..............................",
00706 "..............................",
00707 "..............................",
00708 "..............................",
00709 "..............................",
00710 "..............................",
00711 "..............................",
00712 ".......................*......",
00713 "......................***.....",
00714 "...................**.***.**..",
00715 "...................**.***.**..",
00716 "...................**.***.**..",
00717 "...................****.****..",
00718 "...................***...***..",
00719 "...................***...***.."};
00720 
00721 // Variables used for calculating "frames per second"
00722 
00723 int fps;
00724 int rmuf = 20;  // Rotating map update frequency [1/sec]
00725 int rmui =  1;  // Rotating map update interval  [steps]
00726 int SkipFreq;
00727 int ThisSecond;
00728 int LastSecond;
00729 int LastStep;
00730 int SecEvent;
00731 
00732 int ndatim[6];  /* year, month, day, hour, minute, weekday */
00733 int LastMinute; /* Last value of ndatim(4)                 */
00734 int DeltaTime ; /* Computed timestep interval [min]        */
00735 
00736 struct BMIstruct
00737 {
00738    int   Size;
00739    int   Width;
00740    int   Height;
00741    short Planes;
00742    short Count;
00743    int   Compression;
00744    int   SizeImage;
00745    int   XPelsPerMeter;
00746    int   YPelsPerMeter;
00747    int   ClrUsed;
00748    int   ClrImportant;
00749 };
00750 
00751 struct BMIstruct ImageBMI;
00752 
00753 struct MapImageStruct
00754 {
00755    char   *d; // Bitmap data
00756    int     w; // Image width
00757    int     h; // Image height
00758    int     f; // Rotation factor
00759    float   l; // Reference longitude
00760    float   r; // Rotation speed [deg/step]
00761    XImage *X; // XImage structure
00762 };
00763 
00764 // Convert an RGB value to an X11 Pixel
00765 
00766 unsigned long create_pixel(long red, long green, long blue)
00767 {
00768    if (ScreenD == 24)       // 24 bit true color
00769    {
00770        return red | green << 8 | blue << 16;
00771    }
00772    else if (ScreenD == 16)  // 16 bit RGB 565
00773    {
00774       return red >> 3 | (green >> 2) << 5 | (blue >> 3) << 11;
00775    }
00776    else return 0;
00777 }
00778 
00779 struct MapImageStruct MapHR; // Hires (2560x1280) Earth image
00780 struct MapImageStruct MapLR[NUMWIN];
00781 
00782 void ScaleImage(struct MapImageStruct *s, struct MapImageStruct *d)
00783 {
00784    int a,b,x,y;
00785    unsigned long px;
00786    unsigned long h,w;
00787    double f,g;
00788 
00789    if (d->X) XDestroyImage(d->X);
00790    w = (d->w + 7) & 0xFFF8;
00791    h =  d->h;
00792    d->d = malloc(4 * w * h);
00793    d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0,
00794                   d->d,w,h,8,0);
00795 
00796    f = (double)s->w / (double)d->w;
00797    g = (double)s->h / (double)d->h;
00798 
00799    for (y = 0 ; y < d->h ; ++y)
00800    for (x = 0 ; x < d->w ; ++x)
00801    {
00802        a = x * f;
00803        b = y * g;
00804        XPutPixel(d->X,x,y,XGetPixel(s->X,a,b));
00805    }
00806 }
00807 
00808 
00809 void PolarImage(struct MapImageStruct *s, struct MapImageStruct *d)
00810 {
00811    int a,b,x,y;
00812    unsigned long h,w;
00813    double f,lfa,xnp,ynp,xsp,ysp,dx,dy;
00814 
00815    if (d->X) XDestroyImage(d->X);
00816    w = (d->w + 7) & 0xFFF8;
00817    h =  d->h;
00818    d->d = malloc(4 * w * h);
00819    d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0,
00820                   d->d,w,h,8,0);
00821 
00822    f   = (double)s->h / (double)d->h;
00823    lfa = (s->w-1) / (2.0 * M_PI);
00824    xnp = (d->w) * 0.25;
00825    ynp = (d->h) * 0.50;
00826    xsp = (d->w) * 0.75;
00827    ysp = ynp;
00828 
00829    for (y = 0 ; y < d->h   ; ++y)
00830    {
00831       dy = ynp - y;
00832       for (x = 0 ; x < d->w/2 ; ++x) /* Northern hemisphere */
00833       {
00834          dx = xnp - x;
00835          a = atan2(dx,dy) * lfa;
00836          b = sqrt(dx * dx + dy * dy) * f;
00837          if (a < 0.0) a += (s->w);
00838          if (a >= 0 && a < s->w && b >= 0 && b <= s->h/2)
00839               XPutPixel(d->X,x,y,XGetPixel(s->X,a,b));
00840          else XPutPixel(d->X,x,y,BlackPix);
00841       }
00842       dy = ysp - y;
00843       for (x = d->w/2 ; x < d->w ; ++x) /* Southern hemisphere */
00844       {
00845          dx = x - xsp;
00846          a = atan2(dx,dy) * lfa;
00847          b = s->h - f * sqrt(dx * dx + dy * dy);
00848          if (a < 0.0) a += (s->w);
00849          if (a >= 0 && a < s->w && b >= 0 && b >= s->h/2 && b <= s->h)
00850               XPutPixel(d->X,x,y,XGetPixel(s->X,a,b));
00851          else XPutPixel(d->X,x,y,BlackPix);
00852       }
00853    }
00854 }
00855 
00856 
00857 void RevOrtho(double R, double lam0, double phi0, int xx, int yy, double *lam, double *phi)
00858 {
00859    double rho,c,rhoq,x,y;
00860 
00861    x = xx;
00862    y = yy;
00863 
00864    rhoq = x*x + y*y;
00865    rho  = sqrt(rhoq);
00866    if (rho > R)
00867    {
00868       *phi = 999.9;
00869       *lam = 999.9;
00870    }
00871    else if (rho > R / 100000.0)
00872    {
00873       c   = asin(rho / R);
00874       *phi = asin(cos(c) * sin(phi0) + y * sin(c) * cos(phi0) / rho);
00875       *lam = lam0 + atan2(x * sin(c) , rho * cos(phi0) * cos(c) - y * sin(phi0) * sin(c));
00876    }
00877    else
00878    {
00879       *phi = phi0;
00880       *lam = lam0;
00881    }
00882    // printf("[%6.1lf / %6.1lf] --> (%6.1lf / %6.1lf)\n",x,y,*lam,*phi);
00883 }
00884 
00885 /* ==================================================== */
00886 /* AzimuthalImage - Display map in azimuthal projection */
00887 /* ==================================================== */
00888 
00889 void AzimuthalImage(struct MapImageStruct *s, struct MapImageStruct *d)
00890 {
00891    int lam;           // lambda pixel coordinate in source image
00892    int phi;           // phi    pixel coordinate in source image
00893    int x  ;           // x      pixel coordinate in destination image
00894    int y  ;           // y      pixel coordinate in destination image
00895    int dxc;           // pixel coordinate of centre     position
00896    int dxl;           // pixel coordinate of left  most position
00897    int dxr;           // pixel coordinate of right most position
00898    int dx ;           // centre relative x position
00899    int dy ;           // centre relative y position
00900    int p00;           // euqator
00901    int l00;           // reference longitude
00902    
00903    unsigned int dih;  // destination image height
00904    unsigned int diw;  // destination image width
00905    unsigned int dpw;  // destination image padded width
00906 
00907    double rad;        // pixel radius of new image
00908    double ysc;        // yscale = source height / destination height
00909    double rho;        // distance from centre
00910    double xpi;        // x scale factor = 2 * PI / width
00911    double ypi;        // y scale factor =     PI / height
00912    double xrf;
00913    double yrf;
00914 
00915    XImage *sX;        // source      image
00916    XImage *dX;        // destination image
00917 
00918 
00919    // Destroy old image structure inclusive data storage
00920 
00921    if (d->X) XDestroyImage(d->X);
00922 
00923    // Set width of new image
00924 
00925    diw = d->w;
00926 
00927    // Pad width of new image to a multiple of 8
00928 
00929    dpw = (diw + 7) & 0xFFF8;
00930 
00931    // Set height of new image
00932 
00933    dih =  d->h;
00934 
00935    // Allocate space for image data
00936 
00937    d->d = calloc(dpw * dih,4);
00938 
00939    // Create image structure
00940 
00941    dX = d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0,d->d,dpw,dih,8,0);
00942    sX = s->X;
00943 
00944    p00 = s->h >> 1;
00945    rad = dih  >> 1;
00946    dxc = diw  >> 1;
00947    dxl = MAX(dxc - rad,   0);
00948    dxr = MIN(dxc + rad, diw);
00949    xpi = s->w / M_PI * 0.5;
00950    ypi = s->h / M_PI;
00951    ysc = (double)s->h / (double)dih;
00952    l00 = (int)((d->l * s->w) / 360 + s->w/2) % s->w;
00953    xrf = (double)diw / pow(2.0,31),
00954    yrf = (double)dih / pow(2.0,31);
00955 
00956    // Paint some stars on the sky
00957 
00958    srandom(Seed);
00959    for (y = 0 ; y < (diw * dih) >> 8  ; ++y)
00960       XPutPixel(dX,xrf*random(),yrf*random(),WhitePix);
00961 
00962    for (y = 0 ; y < dih ; ++y)
00963    {
00964       dy  = y - rad;
00965       phi = y * ysc;
00966       for (x = dxl ; x < dxr ; ++x)
00967       {
00968          dx = x - dxc;
00969          rho = sqrt(dx * dx + dy * dy);
00970          if (rho < rad)
00971          {
00972             lam = l00 + xpi * atan2(dx / rad, cos(asin(rho / rad)));
00973             phi = p00 + ypi *  asin(dy / rad);
00974             XPutPixel(dX,x,y,XGetPixel(sX,lam,phi));
00975          }
00976       }
00977    }
00978 }
00979 
00980 
00981 void SwapIEEE16(char W[2])
00982 {
00983    char B;
00984 
00985    B = W[0]; W[0] = W[1]; W[1] = B; 
00986 }
00987 
00988 void SwapIEEE32(char W[4])
00989 {
00990    char B;
00991 
00992    B = W[0]; W[0] = W[3]; W[3] = B; 
00993    B = W[1]; W[1] = W[2]; W[2] = B; 
00994 }
00995 
00996 int ReadINT(FILE *fpi)
00997 {
00998    int k;
00999    fread(&k,sizeof(k),1,fpi);
01000    if (BigEndian) SwapIEEE32((char *)&k);
01001    return k;
01002 }
01003 
01004 short ReadSHORT(FILE *fpi)
01005 {
01006    short k;
01007    fread(&k,sizeof(k),1,fpi);
01008    if (BigEndian) SwapIEEE16((char *)&k);
01009    return k;
01010 }
01011 
01012 void ReadImage(struct MapImageStruct *ei, char *filename)
01013 {
01014    char ch;
01015    int i,n,x,y,z;
01016    long r,g,b;
01017    int FileSize;
01018    int Reserved;
01019    int OffBits;
01020    int PicBytes;
01021    int ImgBytes;
01022    int PadWidth;
01023    int PadBytes;
01024    int bpp;
01025    int byr;
01026    FILE *fp;
01027    unsigned char *BuffImageData;
01028 
01029    if (!(fp = fopen(filename,"r"))) return;
01030    ch = fgetc(fp);
01031    if (ch != 'B') return;
01032    ch = fgetc(fp);
01033    if (ch != 'M') return;
01034    FileSize = ReadINT(fp);
01035    Reserved = ReadINT(fp);
01036    OffBits  = ReadINT(fp);
01037 
01038    if (Debug)
01039    {
01040       printf("Properties of %s:\n",filename);
01041       printf("FileSize   = %d\n",FileSize);
01042       printf("FileOffset = %d\n",OffBits);
01043    }
01044 
01045    ImageBMI.Size          = ReadINT(fp);
01046    ImageBMI.Width         = ReadINT(fp);
01047    ImageBMI.Height        = ReadINT(fp);
01048    ImageBMI.Planes        = ReadSHORT(fp);
01049    ImageBMI.Count         = ReadSHORT(fp);
01050    ImageBMI.Compression   = ReadINT(fp);
01051    ImageBMI.SizeImage     = ReadINT(fp);
01052    ImageBMI.XPelsPerMeter = ReadINT(fp);
01053    ImageBMI.YPelsPerMeter = ReadINT(fp);
01054    ImageBMI.ClrUsed       = ReadINT(fp);
01055    ImageBMI.ClrImportant  = ReadINT(fp);
01056 
01057    PadWidth = (ImageBMI.Width + 7) & 0xFFF8;
01058    bpp      =  ImageBMI.Count >> 3;
01059    PadBytes = (4 - ((ImageBMI.Width * bpp) % 4)) % 4 ;
01060 
01061    if (Debug)
01062    {
01063       printf("BMI Size     = %d\n",ImageBMI.Size);
01064       printf("BMI Width    = %d\n",ImageBMI.Width);
01065       printf("BMI Height   = %d\n",ImageBMI.Height);
01066       printf("BMI Planes   = %d\n",ImageBMI.Planes);
01067       printf("BMI Count    = %d\n",ImageBMI.Count);
01068       printf("BMI ClrUsed  = %d\n",ImageBMI.ClrUsed);
01069       printf("Pad Bytes    = %d\n",PadBytes);
01070       printf("ScreenD= %d\n",ScreenD);
01071    }
01072 
01073    PicBytes = (bpp * ImageBMI.Width + PadBytes) * ImageBMI.Height;
01074    ImgBytes = 4 * PadWidth * ImageBMI.Height;
01075    ei->d = calloc(ImgBytes,1);
01076    BuffImageData = malloc(PicBytes);
01077    n = fread(BuffImageData,PicBytes,1,fp);
01078    fclose(fp);  
01079    
01080    ei->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0,
01081                   ei->d,PadWidth,ImageBMI.Height,8,0);
01082 
01083    for (y = 0 ; y < ImageBMI.Height ; ++y)
01084    for (x = 0 ; x < ImageBMI.Width  ; ++x)
01085    {
01086        i = bpp * x + (ImageBMI.Height - 1 - y) * (ImageBMI.Width*bpp+PadBytes);
01087        r = BuffImageData[i  ];
01088        g = BuffImageData[i+1];
01089        b = BuffImageData[i+2];
01090        XPutPixel(ei->X, x, y, create_pixel(r,g,b));
01091    }
01092    free(BuffImageData);
01093    ei->w = ImageBMI.Width;
01094    ei->h = ImageBMI.Height;
01095 }
01096 
01097 
01098 void ntocdat(void)
01099 {
01100    if (ndatim[1] > 0)
01101    {
01102       if (ndatim[5] >= 0)
01103          sprintf(datch,"%s %2d-%s-%04d %2d:%02d",wena[ndatim[5]],ndatim[2],mona[ndatim[1]-1],
01104            ndatim[0],ndatim[3],ndatim[4]);
01105       else
01106       sprintf(datch,"%2d-%s-%04d %2d:%02d",ndatim[2],mona[ndatim[1]-1],
01107            ndatim[0],ndatim[3],ndatim[4]);
01108    }
01109 }
01110 
01111 /* ============================================== */
01112 /* CharAlloc - Allocate space for character array */
01113 /* ============================================== */
01114 
01115 char *CharAlloc(int bytes,char *array_name)
01116 {
01117    char *result = NULL;
01118    if (bytes > 0)
01119    {
01120       result = (char *)calloc(bytes, sizeof(char));
01121       if (!result || Debug)
01122       {
01123          if (!result) printf("*** Out of Memory *** on ");
01124          printf("CharAlloc:  at%10p %6d char for %-30.30s\n",
01125                 result,bytes,array_name);
01126       }
01127    }
01128    return(result);
01129 }
01130 
01131 /* ======================================= */
01132 /* IntAlloc - Allocate space for int array */
01133 /* ======================================= */
01134 
01135 int *IntAlloc(int words,char *array_name)
01136 {
01137    int *result = NULL;
01138    if (words > 0)
01139    {
01140       result = (int *) calloc(words, sizeof(int));
01141       if (!result || Debug)
01142       {
01143          if (!result) printf("*** Out of Memory *** on ");
01144          printf("IntAlloc:   at%10p %6d int for %s\n",
01145                result,words,array_name);
01146       }
01147    }
01148    return(result);
01149 }
01150 
01151 /* =========================================== */
01152 /* FloatAlloc - Allocate space for float array */
01153 /* =========================================== */
01154 
01155 float *FloatAlloc(int words, char *array_name)
01156 {
01157    float *result = NULL;
01158    if (words > 0)
01159    {
01160       result = (float *) calloc(words, sizeof(float));
01161       if (!result || Debug)
01162       {
01163          if (!result) printf("*** Out of Memory *** on ");
01164          printf("FloatAlloc: at%10p %6d float for %s\n",
01165                result,words,array_name);
01166       }
01167    }
01168    return(result);
01169 }
01170 
01171 /* ========================================== */
01172 /* SizeAlloc - Allocate space for sized array */
01173 /* ========================================== */
01174 
01175 void *SizeAlloc(int words, int Size, char *array_name)
01176 {
01177    void *result = NULL;
01178    if (words > 0)
01179    {
01180       result = (void *) calloc(words, Size);
01181       if (!result || Debug)
01182       {
01183          if (!result) printf("*** Out of Memory *** on ");
01184          printf("SizeAlloc:  at%10p %6d void for %s\n",
01185                result,words,array_name);
01186       }
01187    }
01188    return(result);
01189 }
01190 
01191 void LoadFonts(void)
01192 {
01193    if ((FixFont = XLoadQueryFont(display,FixFontName)) == NULL)
01194    {
01195       printf("%s: Cannot open %s font\n",progname,FixFontName);
01196       exit(-1);
01197    }
01198    if ((SubFont = XLoadQueryFont(display,SubFontName)) == NULL)
01199    {
01200       SubFont = FixFont;
01201    }
01202    if ((BigFont = XLoadQueryFont(display,BigFontName)) == NULL)
01203    {
01204       if ((BigFont = XLoadQueryFont(display,"10x20")) == NULL)
01205       {
01206          printf("%s: Cannot open %s font\n",progname,BigFontName);
01207          exit(-1);
01208       }
01209    }
01210    FixFontWidth  = XTextWidth(FixFont,"X",1);
01211    SubFontWidth  = XTextWidth(SubFont,"X",1);
01212    BigFontWidth  = XTextWidth(BigFont,"X",1);
01213    FixFontHeight = FixFont->ascent + FixFont->descent;
01214    SubFontHeight = SubFont->ascent + SubFont->descent;
01215    BigFontHeight = BigFont->ascent + BigFont->descent;
01216 }
01217 
01218 int AllocateColorCells(struct ColorStrip cs[])
01219 {
01220    int i = 0;
01221    XColor xcolor1,xcolor2;
01222 
01223    while (cs[i].Name)
01224    {
01225       XAllocNamedColor(display,colormap,cs[i].Name,&xcolor1,&xcolor2);
01226       cs[i].pixel = xcolor1.pixel;
01227       ++i;
01228    }   
01229    return i;
01230 }
01231 
01232 void CalcButtonAreas(void)
01233 {
01234    int of,ds,bh,fh,fw,j;
01235 
01236    of = OffsetY;
01237    ds = 10;
01238    bh = 30;
01239    fh = BigFontHeight;
01240    fw = BigFontWidth;
01241 
01242    /* 1. Stop Button */
01243 
01244    StopButton[0].y += OffsetY;
01245    StopButton[1].y += OffsetY;
01246    StopButton[2].y += OffsetY;
01247    StopButton[3].y += OffsetY;
01248 
01249    Stop_XL = ds;
01250    Stop_XH = Stop_XL + bh;
01251    Stop_YL = of + ds;
01252    Stop_YH = Stop_YL + bh;
01253 
01254    /* 2. Start Button */
01255 
01256    Start_XL = Stop_XH  + ds;
01257    Start_XH = Start_XL + bh;
01258    Start_YL = Stop_YL;
01259    Start_YH = Stop_YH;
01260 
01261    StartButton[0].y += OffsetY;
01262    StartButton[1].y += OffsetY;
01263    StartButton[2].y += OffsetY;
01264 
01265    /* 3. Pause Button */
01266 
01267    Pause_XL = Start_XH + 15;
01268    Pause_XH = Start_XH + 35;
01269    Pause_YL = Start_YL;
01270    Pause_YH = Start_YH;
01271 
01272    PauseButton1[0].y += OffsetY;
01273    PauseButton1[1].y += OffsetY;
01274    PauseButton1[2].y += OffsetY;
01275    PauseButton1[3].y += OffsetY;
01276 
01277    PauseButton2[0].y += OffsetY;
01278    PauseButton2[1].y += OffsetY;
01279    PauseButton2[2].y += OffsetY;
01280    PauseButton2[3].y += OffsetY;
01281 
01282    /* 4. Help  Button */
01283 
01284    Help_XL = 200;
01285    Help_XH = Help_XL + 5 * fw;
01286    Help_YL = Pause_YL;
01287    Help_YH = Pause_YH;
01288 
01289    /* 5. Minus & FBWD Button */
01290 
01291    Minus_XL = 300;
01292    Minus_XH = Minus_XL + fh;
01293    Minus_YL = Pause_YL + (bh - fh) / 2;
01294    Minus_YH = Minus_YL + fh;
01295 
01296    FBWD_XH = Minus_XL - ds/2;
01297    FBWD_XL = FBWD_XH - fh;
01298    FBWD_YL = Minus_YL;
01299    FBWD_YH = Minus_YH;
01300 
01301    /* 6. Parameter Change Area */
01302 
01303    Parc_XL = Minus_XH + ds;
01304    Parc_XH = Parc_XL  + fw * 14;
01305    Parc_YL = Minus_YL;
01306    Parc_YH = Minus_YH;
01307    Parc_XD = Parc_XH - Parc_XL;
01308    Parc_YD = Parc_YH - Parc_YL;
01309 
01310    /* 7. Plus & FFWD Button */
01311 
01312    Plus_XL = Parc_XH + ds;
01313    Plus_XH = Plus_XL + fh;
01314    Plus_YL = Minus_YL;
01315    Plus_YH = Minus_YH;
01316 
01317    FFWD_XL = Plus_XH + ds/2;
01318    FFWD_XH = FFWD_XL + fh;
01319    FFWD_YL = Plus_YL;
01320    FFWD_YH = Plus_YH;
01321 
01322    /* 8. Grid on/off box */
01323 
01324    Grid_XL = Stop_XL;
01325    Grid_XH = Grid_XL + FixFontHeight;
01326    Grid_YL = Stop_YH + 3 * BigFontHeight / 2;
01327    Grid_YH = Grid_YL + FixFontHeight;
01328 
01329    /* Window status and select boxes */
01330 
01331    Wbox_XL = 580;
01332    Wbox_XH = Wbox_XL + FixFontHeight;
01333    Wbox_YL =   0;
01334    Wbox_YH = NumWin  * FixFontHeight;
01335 }
01336 
01337 
01338 /* Hack for getting information of window decoration  */
01339 /* especially borderwidth and titleheight             */
01340 /* These are properties of the window manager and are */
01341 /* usually adjustable by the user                     */
01342 
01343 void TestWindow(int xx, int yy, int wi, int he, int *x, int *y,
01344                 int *X, int *Y, unsigned int *W, unsigned int *H)
01345 {
01346    unsigned int DepthReturn  = 0;
01347    unsigned int BorderReturn = 0;
01348    Window TW,Parent,Child;
01349    
01350    TW = XCreateWindow(display,RootWindow(display,screen_num),
01351         xx,yy,wi,he,                   // x,y,w,h
01352         0,CopyFromParent,InputOutput,  // border, depth, class
01353           CopyFromParent,0,NULL);      // visual, valuemask, attributes
01354    XSelectInput(display,TW,ExposureMask);
01355    XMapWindow(display,TW);           
01356    XMoveWindow(display,TW,xx,yy);
01357    XNextEvent(display,&CowEvent);            // Wait until WM mapped it
01358    XGetGeometry(display,TW,&Parent,x,y,W,H,&BorderReturn,&DepthReturn);
01359    XTranslateCoordinates(display,TW,Parent,0,0,X,Y,&Child);
01360    XDestroyWindow(display,TW);
01361 
01362    if (Debug)
01363    {
01364       printf("TW[%x][%x]: %4d / %4d   %4d x %4d x %2d [%2d:%2d]\n",
01365               (int)TW,(int)Parent,*x,*y,*W,*H,DepthReturn,*X,*Y);
01366    }
01367 }
01368 
01369 
01370 void CreateTestWindow(void)
01371 {
01372    int X,Y,xp,yp;
01373    unsigned int W,H;
01374    
01375    // Open a test window with displacement x = 100 and y = 100
01376    // Test the returned coordinates for upper left corner
01377    // and compute left margin (border) and top margin (title bar)
01378 
01379    TestWindow(100,100,100,100,&xp,&yp,&X,&Y,&W,&H);
01380 
01381    // Left margin
01382 
01383    if (X >= 100 && X < 110) WinLM = X - 100;
01384 
01385    // Right margin
01386 
01387    WinRM = WinLM;
01388 
01389    // Top margin
01390 
01391         if (Y >= 100 && Y < 150) WinTM = Y - 100;
01392    else if (Y >    0 && Y <  50) WinTM = Y;
01393 
01394    // Bottom margin
01395 
01396    WinBM = WinLM;
01397 
01398    // Open a full screen test window
01399    // Test the returned coordinates for upper left corner
01400    // the y displacement should be WinTM plus Windowmanager menu bar
01401 
01402    TestWindow(0,0,ScreenW,ScreenH,&xp,&yp,&X,&Y,&W,&H);
01403 
01404    // Window manager menu bar on top
01405 
01406    if (yp > WinTM) WM_top_area = yp - WinTM;
01407 
01408 
01409    // Last usable scan line
01410 
01411    ScreenBot = WM_top_area + WinTM + H;
01412    if (ScreenBot > ScreenH) ScreenBot = ScreenH;
01413 
01414    // Are we running on a 27" iMac :-)
01415 
01416    if (ScreenW == 2560 && ScreenH > 1400) ScreenBot -= 100;
01417 
01418    if (Debug)
01419    {
01420       printf("Screen       = %4d x %4d x %2d\n",ScreenW,ScreenH,ScreenD);
01421       printf("ScreenBot    = %4d\n",ScreenBot);
01422       printf("Top reserved = %4d\n",WM_top_area);
01423       printf("Bot reserved = %4d\n",ScreenH-ScreenBot);
01424       printf("Left  margin = %4d\n",WinLM);
01425       printf("Right margin = %4d\n",WinRM);
01426       printf("Top   margin = %4d\n",WinTM);
01427       printf("Bot   margin = %4d\n",WinBM);
01428    }
01429 }
01430 
01431 
01432 void TrimCopy(char *Trim, char *Line, int n)
01433 {
01434    int l;
01435    char *s;
01436 
01437    l = strlen(Line);
01438    Line[--l] = 0;                          // Remove linefeed
01439    while (Line[l-1] == ' ') Line[--l] = 0; // Remove trailing blanks
01440    s = Line;
01441    while (*s == ' ') ++s;                  // Remove leading blanks
01442    strncpy(Trim,s,n);
01443 }
01444 
01445 
01446 int ReadConfig(char *filename)
01447 {
01448    FILE *fp;
01449    int i,w,l,s,p;
01450    char Line[256];
01451    char Plot[80];
01452    char Palette[80];
01453    char Projection[80];
01454    char Rotation[80];
01455    char *t;
01456 
01457    fp = fopen(filename,"r");
01458    if (!fp) return 1;
01459 
01460    w = -2;
01461    s = -1;
01462    p = -1;
01463    while (!feof(fp))
01464    {
01465       t = fgets(Line,256,fp);
01466       if (Line[0] == '#') continue;
01467       if (strncmp(Line,"[Window "    , 8) == 0) w = atoi(Line+8);
01468       if (strncmp(Line,"[Control"    , 8) == 0) w = -1;
01469       if (strncmp(Line,"[Scalar "    , 8) == 0) s = atoi(Line+8);
01470       if (strncmp(Line,"WinRows ="   , 9) == 0)
01471       {
01472          WinRows = atoi(Line+9);
01473          if (WinRows < 1) WinRows = 1;
01474          if (WinRows > 3) WinRows = 3;
01475          NumWin = WinCols * WinRows;
01476       }
01477       if (strncmp(Line,"WinCols ="   , 9) == 0)
01478       {
01479          WinCols = atoi(Line+9);
01480          if (WinCols < 1) WinCols = 1;
01481          if (WinCols > 3) WinCols = 3;
01482          NumWin = WinCols * WinRows;
01483       }
01484       if (strncmp(Line,"[Parameter " ,11) == 0)
01485       {
01486          p = atoi(Line+11);
01487          if (p >= Parcs) Parcs = p+1;
01488       }
01489       if (strncmp(Line,"Geometry:",9) == 0 && w >= 0 && w < NUMWIN)
01490       {
01491          sscanf(Line+9,"%d %d %d %d",&WinAtt[w].w,&WinAtt[w].h,
01492                                      &WinAtt[w].x,&WinAtt[w].y);
01493          WinAtt[w].active = 1;
01494       }
01495       if (strncmp(Line,"Inactive:",9) == 0 && w >= 0 && w < NUMWIN)
01496       {
01497          sscanf(Line+9,"%d %d %d %d",&WinAtt[w].w,&WinAtt[w].h,
01498                                      &WinAtt[w].x,&WinAtt[w].y);
01499          WinAtt[w].active = 0;
01500       }
01501       if (strncmp(Line,"Geometry:",9) == 0 && w == -1)
01502       {
01503          sscanf(Line+9,"%d %d %d %d",&CowW,&CowH,&CowX,&CowY);
01504       }
01505       if (strncmp(Line,"Title:",6) == 0 && w >= -1 && w < NUMWIN)
01506       {
01507          if (w == -1) TrimCopy(PlanetName,Line+6,sizeof(PlanetName)-1);
01508          else         TrimCopy(WindowTitle[w]+wto,Line+6,79-wto);
01509       }
01510       if (strncmp(Line,"Array:",6) == 0 && w >= 0 && w < NUMWIN)
01511          TrimCopy(WinAtt[w].array_name,Line+6,79);
01512       if (strncmp(Line,"Plot:",5) == 0 && w >= 0 && w < NUMWIN)
01513       {
01514          TrimCopy(Plot,Line+5,79);
01515          for (i=0 ; i < IsoTypes ; ++i)
01516             if (!strcmp(Plot,IsoNames[i])) WinAtt[w].Plot = i;
01517       }
01518       if (strncmp(Line,"Projection:",11) == 0 && w >= 0 && w < NUMWIN)
01519       {
01520          TrimCopy(Projection,Line+11,79);
01521          for (i=0 ; i < MAXMAPS ; ++i)
01522             if (!strcmp(Projection,ProNames[i])) MapPro[w] = i;
01523       }
01524       if (strncmp(Line,"Rotation factor:",15) == 0 && w >= 0 && w < NUMWIN)
01525       {
01526          TrimCopy(Rotation,Line+15,79);
01527          MapLR[w].f = atoi(Rotation);
01528       }
01529       if (strncmp(Line,"Palette:",8) == 0 && w >= 0 && w < NUMWIN)
01530       {
01531          TrimCopy(Palette,Line+8,79);
01532          for (i=0 ; i < PalTypes ; ++i)
01533             if (!strcmp(Palette,PalNames[i])) WinAtt[w].Palette = i;
01534       }
01535 
01536       // Dimension for time axis
01537 
01538       if (strncmp(Line,"DimT:" ,5) == 0) DimT = atoi(Line+5);
01539 
01540       // Attributes of scalars for timeseries windows
01541 
01542       if (strncmp(Line,"Name:" ,5) == 0 && s >= 0 && s < NUMSCALARS)
01543          TrimCopy(TSName[s],Line+5,79);
01544       if (strncmp(Line,"Sub:"  ,4) == 0 && s >= 0 && s < NUMSCALARS)
01545          TrimCopy(TSubsc[s],Line+4,79);
01546       if (strncmp(Line,"Unit:" ,5) == 0 && s >= 0 && s < NUMSCALARS)
01547          TrimCopy(TSUnit[s],Line+5,79);
01548       if (strncmp(Line,"Scale:",6) == 0 && s >= 0 && s < NUMSCALARS)
01549          TrimCopy(TScale[s],Line+6,79);
01550 
01551       // Attributes of parameter in change menu
01552 
01553       if (strncmp(Line,"ParName:",8) == 0 && p >= 0 && p < PARCS)
01554          TrimCopy(Parc[p].Name,Line+8,6);
01555       if (strncmp(Line,"ParInc:" ,7) == 0 && p >= 0 && p < PARCS)
01556          Parc[p].Inc = atof(Line+7);
01557       if (strncmp(Line,"ParMin:" ,7) == 0 && p >= 0 && p < PARCS)
01558          Parc[p].Min = atof(Line+7);
01559       if (strncmp(Line,"ParMax:" ,7) == 0 && p >= 0 && p < PARCS)
01560          Parc[p].Max = atof(Line+7);
01561       if (strcmp(Parc[p].Name,"SELLON") == 0) Parc[p].Inc = 360.0 / (2.0 * Latitudes);
01562    }
01563    fclose(fp);
01564    return 0;
01565 }
01566 
01567 
01568 void CreateControlWindow(void)
01569 {
01570    int X,Y,W,H,B,D,x,y;
01571    char Title1[256];
01572    char *WinconTitle1;
01573    char *WinconTitle3 = {"RUN finished - click on red stop button"};
01574    Window Rootwin;
01575    Window Child;
01576 
01577    strcpy(Title1,"Unknown model");
01578    if (Model == 0) // PUMA
01579    {
01580       if (MRpid < 0) 
01581          strcpy(Title1,"PUMA - KlimaCampus Hamburg");
01582       else
01583          sprintf(Title1,"Run %d: PUMA - KlimaCampus Hamburg",MRpid);
01584    }
01585    else if (Model == 1) sprintf(Title1,"SAM - KlimaCampus");
01586    else if (Model == 2)
01587    {
01588        if (MRpid < 0)
01589        sprintf(Title1,"Planet Simulator (%s) - KlimaCampus",PlanetName);
01590        else
01591        sprintf(Title1,"Run %d: Planet Simulator (%s) - KlimaCampus",MRpid,PlanetName);
01592    }
01593    else if (Model == 3) sprintf(Title1,"Planet Simulator / LSG - KlimaCampus");
01594    else printf("*** unknown model number %d in pumax ***\n",Model);
01595    WinconTitle1 = Title1;
01596    if (CowW < 920 || CowW > ScreenW) CowW = 920;
01597    if (NumWin < 5) CowH = 6 * FixFontHeight + 5;
01598    else            CowH = NumWin * FixFontHeight + 5;
01599    if (CowX < 0 || CowX > ScreenW - CowW) CowX = (ScreenW - CowW) / 2;
01600    if (CowY < 0 || CowY > ScreenBot - CowH - WinTM - WinBM) CowY = ScreenBot - CowH - WinTM - WinBM;
01601    CowSizeHints.flags      = PPosition | PSize | PMinSize | PMaxSize;
01602    CowSizeHints.min_width  = CowW;
01603    CowSizeHints.min_height = CowH;
01604    CowSizeHints.max_width  = ScreenW - WinLM - WinRM;
01605    CowSizeHints.max_height = CowH;
01606    if (MRnum == 2 && MRpid == 1) CowX += ScreenW;
01607    if (Debug) printf("Control Window %d/%d %dx%d\n",CowX,CowY,CowW,CowH);
01608    Cow = XCreateWindow(display,RootWindow(display,screen_num), // display, parent
01609                CowX,CowY,CowW,CowH,
01610                BorderWidth,CopyFromParent,InputOutput,         // border, depth, class
01611                CopyFromParent,0,NULL);                         // visual, valuemask, attributes
01612    XStringListToTextProperty(&WinconTitle1,1,&WinconName1);
01613    XStringListToTextProperty(&WinconTitle3,1,&WinconName3);
01614    XStringListToTextProperty(&PauseTitle,1,&WinconPause);
01615    XStringListToTextProperty(&ReadyTitle,1,&WinconReady);
01616    XSetWMProtocols(display,Cow,&Delwin,1);
01617    XSetWMProperties(display,Cow,&WinconName1,NULL,
01618                 NULL,0,&CowSizeHints,&wm_hints,&class_hints);
01619    XSelectInput(display,Cow,ButtonPressMask | KeyPressMask | ExposureMask);
01620    XMapWindow(display,Cow);
01621 }
01622 
01623 
01624 void ShowStep(void)
01625 {
01626    char Text[80];
01627    XSetFont(display, gc, BigFont->fid);
01628    XSetForeground(display,gc,BlackPix);
01629    XSetBackground(display,gc,Grey.pixel);
01630    ntocdat();
01631    if (ndatim[5] == 6) XSetForeground(display,gc,Red.pixel); // sunday
01632    XDrawImageString(display,Cow,gc,10,BigFontHeight,datch,strlen(datch));
01633    XSetForeground(display,gc,BlackPix);
01634    if (ShowQueue)
01635    {
01636       sprintf(Text,"%8d Events   ",XPending(display));
01637       XDrawImageString(display,Cow,gc,10,60 + BigFontHeight,Text,strlen(Text));
01638    }
01639    else if (fps > 1)
01640    {
01641       if (SkipFreq < 2) sprintf(Text,"%5d fps",fps);
01642       else sprintf(Text,"%5d fps [%d]",fps,SkipFreq);
01643       XDrawImageString(display,Cow,gc,10,60 + BigFontHeight,Text,strlen(Text));
01644    }
01645 }
01646 
01647 
01648 int FormatVal(char *Name, float V, char *Text)
01649 {
01650    char Format[80];
01651 
01652    if (V > 9999.9 || V < -999.9)
01653    {
01654       sprintf(Text,"%6.6s = *****",Name);
01655       return strlen(Text);
01656    }
01657    else if (V > 999.99  ) strcpy(Format,"%6.6s =%6.1f");
01658    else if (V >  99.999 ) strcpy(Format,"%6.6s =%6.2f");
01659    else if (V >   9.9999) strcpy(Format,"%6.6s =%6.3f");
01660    else if (V >   0.0   ) strcpy(Format,"%6.6s =%6.4f");
01661    else if (V >  -9.9   ) strcpy(Format,"%6.6s =%6.3f");
01662    else if (V > -99.9   ) strcpy(Format,"%6.6s =%6.2f");
01663    else                   strcpy(Format,"%6.6s =%6.1f");
01664 
01665    sprintf(Text,Format,Name,V);
01666    return strlen(Text);
01667 }
01668 
01669 
01670 void ShowParcs(void)
01671 {
01672    char Text[80];
01673    int len;
01674    float V;
01675 
01676    XSetFont(display, gc, BigFont->fid);
01677    len = FormatVal(Parc[cpi].Name,Parc[cpi].Val,Text);
01678 
01679    XSetBackground(display,gc,WhitePix);
01680    XSetForeground(display,gc,Red.pixel);
01681    XFillRectangle(display,Cow,gc,Minus_XL,Minus_YL,Minus_XH-Minus_XL,Minus_YH-Minus_YL);
01682    XFillRectangle(display,Cow,gc,FBWD_XL,FBWD_YL,FBWD_XH-FBWD_XL,FBWD_YH-FBWD_YL);
01683    XSetForeground(display,gc,WhitePix);
01684    XFillRectangle(display,Cow,gc,Minus_XL+3,(Minus_YH+Minus_YL)/2-1,Minus_XH-Minus_XL-5,3);
01685    XFillRectangle(display,Cow,gc,FBWD_XL+3,(FBWD_YH+FBWD_YL)/2-1,FBWD_XH-FBWD_XL-5,3);
01686    XSetForeground(display,gc,BlackPix);
01687    XDrawImageString(display,Cow,gc,Parc_XL,Parc_YH-3,Text,len);
01688    XSetForeground(display,gc,Green.pixel);
01689    XFillRectangle(display,Cow,gc,Plus_XL,Plus_YL,Plus_XH-Plus_XL,Plus_YH-Plus_YL);
01690    XFillRectangle(display,Cow,gc,FFWD_XL,FFWD_YL,FFWD_XH-FFWD_XL,FFWD_YH-FFWD_YL);
01691    XSetForeground(display,gc,WhitePix);
01692    XFillRectangle(display,Cow,gc,Plus_XL+3,(Plus_YH+Plus_YL)/2-1,Plus_XH-Plus_XL-5,3);
01693    XFillRectangle(display,Cow,gc,FFWD_XL+3,(FFWD_YH+FFWD_YL)/2-1,FFWD_XH-FFWD_XL-5,3);
01694    XFillRectangle(display,Cow,gc,(Plus_XH+Plus_XL)/2-1,Plus_YL+3,3,Plus_YH-Plus_YL-5);
01695    XFillRectangle(display,Cow,gc,(FFWD_XH+FFWD_XL)/2-1,FFWD_YL+3,3,FFWD_YH-FFWD_YL-5);
01696    XSetForeground(display,gc,BlackPix);
01697    XDrawRectangle(display,Cow,gc,Minus_XL,Minus_YL,Minus_XH-Minus_XL,Minus_YH-Minus_YL);
01698    XDrawRectangle(display,Cow,gc,FBWD_XL,FBWD_YL,FBWD_XH-FBWD_XL,FBWD_YH-FBWD_YL);
01699    XDrawRectangle(display,Cow,gc,Parc_XL-1,Parc_YL-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL);
01700    XDrawRectangle(display,Cow,gc,Plus_XL,Plus_YL,Plus_XH-Plus_XL,Plus_YH-Plus_YL);
01701    XDrawRectangle(display,Cow,gc,FFWD_XL,FFWD_YL,FFWD_XH-FFWD_XL,FFWD_YH-FFWD_YL);
01702 
01703    /* Show next parameter */
01704 
01705    strcpy(Text,"              ");
01706    if (cpi < Parcs-1) FormatVal(Parc[cpi+1].Name,Parc[cpi+1].Val,Text);
01707    len = strlen(Text);
01708 
01709    XSetBackground(display,gc,WhitePix);
01710    XSetForeground(display,gc,BlackPix);
01711    XDrawImageString(display,Cow,gc,Parc_XL,2*Parc_YH-Parc_YL-3,Text,len);
01712    XDrawRectangle(display,Cow,gc,Parc_XL-1,Parc_YH-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL);
01713 
01714    /* Show previous parameter */
01715 
01716    strcpy(Text,"              ");
01717    if (cpi > 0) FormatVal(Parc[cpi-1].Name,Parc[cpi-1].Val,Text);
01718    len = strlen(Text);
01719 
01720    XSetBackground(display,gc,WhitePix);
01721    XSetForeground(display,gc,BlackPix);
01722    XDrawImageString(display,Cow,gc,Parc_XL,Parc_YL-3,Text,len);
01723    XDrawRectangle(display,Cow,gc,Parc_XL-1,2*Parc_YL-Parc_YH-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL);
01724    XSetFont(display, gc, FixFont->fid);
01725 
01726 }
01727 
01728 
01729 void CheckMark(int x, int y, int d)
01730 {
01731    XDrawLine(display,Cow,gc,x+2,y+2,x+d-1,y+d-1);
01732    XDrawLine(display,Cow,gc,x+3,y+2,x+d-1,y+d-2);
01733    XDrawLine(display,Cow,gc,x+2,y+3,x+d-2,y+d-1);
01734 
01735    XDrawLine(display,Cow,gc,x+d-1,y+1,x+2,y+d-2);
01736    XDrawLine(display,Cow,gc,x+d-2,y+1,x+2,y+d-3);
01737    XDrawLine(display,Cow,gc,x+d-1,y+2,x+3,y+d-2);
01738 }
01739 
01740 
01741 void ShowWindowStatus(void)
01742 {
01743    char *cp;
01744    char Text[80];
01745    int len,w,x,d;
01746 
01747    XSetFont(display, gc, FixFont->fid);
01748    XSetForeground(display,gc,BlackPix);
01749    XSetBackground(display,gc,Grey.pixel);
01750    x = Wbox_XL;
01751    d = FixFontHeight;
01752    for (w=0 ; w < NumWin ; ++w)
01753    {
01754       strncpy(Text,WindowTitle[w]+wto,40);
01755       Text[40] = 0;
01756       cp = strstr(Text,"Level");
01757       if (cp) *cp = 0;
01758       cp = strstr(Text,"Latitude");
01759       if (cp) *cp = 0;
01760       len = strlen(Text);
01761       XDrawImageString(display,Cow,gc,x+20,(w+1) * d,Text,len);
01762    }
01763    XSetForeground(display,gc,WhitePix);
01764    for (w=0 ; w < NumWin ; ++w)
01765    {
01766       XFillRectangle(display,Cow,gc,x,w*d,d,d);
01767    }
01768    XSetForeground(display,gc,BlackPix);
01769    for (w=0 ; w < NumWin ; ++w)
01770    {
01771       XDrawRectangle(display,Cow,gc,x,w*d,d,d);
01772    }
01773    for (w=0 ; w < NumWin ; ++w)
01774    if (Win[w]) CheckMark(x,w*d,d);
01775 }
01776 
01777 
01778 void ShowGridStatus(void)
01779 {
01780    int x,y,d;
01781 
01782    d = FixFontHeight;
01783    x = Grid_XL;
01784    y = Grid_YL;
01785    XSetFont(display, gc, FixFont->fid);
01786    XSetForeground(display,gc,BlackPix);
01787    XSetBackground(display,gc,Grey.pixel);
01788    XDrawImageString(display,Cow,gc,Grid_XH+FixFontWidth,Grid_YH,"Grid",4);
01789    XSetForeground(display,gc,WhitePix);
01790    XFillRectangle(display,Cow,gc,x,Grid_YL,d,d);
01791    XSetForeground(display,gc,BlackPix);
01792    XDrawRectangle(display,Cow,gc,x,Grid_YL,d,d);
01793 
01794    if (Grid) CheckMark(x,y,d);
01795 }
01796 
01797       
01798 int RedrawControlWindow(void)
01799 {
01800    char Text[80];
01801    int status,WinXSize,WinYSize,font_height,width,len;
01802    int i,j,x1,x2,y1,y2,y3;
01803    XWindowAttributes CurAtt;
01804 
01805    status = XGetWindowAttributes(display,Cow,&CurAtt);
01806    WinXSize = CurAtt.width;
01807    WinYSize = CurAtt.height;
01808    
01809    XSetForeground(display,gc,BlackPix);
01810    XSetBackground(display,gc,WhitePix);
01811 
01812    XSetWindowBackground(display,Cow,Grey.pixel);
01813    XClearWindow(display,Cow);
01814 
01815    /* Red stop button */
01816 
01817    XSetForeground(display,gc,Red.pixel);
01818    XFillPolygon(display,Cow,gc,StopButton,4,Convex,CoordModeOrigin);
01819    XSetForeground(display,gc,WhitePix);
01820    x1 = StopButton[0].x ;
01821    y1 = StopButton[0].y ;
01822    for (j=0 ; j < PSDIM ; ++j)
01823    for (i=0 ; i < PSDIM ; ++i)
01824    if (pixelstar[j][i] == '*')
01825       XDrawPoint(display,Cow,gc,i+x1,j+y1);
01826   
01827    XSetForeground(display,gc,LightRed.pixel);
01828    x1 = 10; x2 = 40 ; y1 = OffsetY + 10 ; y2 = OffsetY + 40;
01829    XDrawLine(display,Cow,gc,x2  ,y1-1,x2  ,y2  );
01830    XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1);
01831    XDrawLine(display,Cow,gc,x1-1,y1-1,x2  ,y1-1);
01832    XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2);
01833    XSetForeground(display,gc,DarkRed.pixel);
01834    XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2  );
01835    XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1);
01836    XDrawLine(display,Cow,gc,x1-1,y2  ,x2  ,y2  );
01837    XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1);
01838 
01839    // Green <play> button
01840 
01841    XSetForeground(display,gc,Green.pixel);
01842    XFillPolygon(display,Cow,gc,StartButton,3,Convex,CoordModeOrigin);
01843    x1 = 50; x2 = 80 ; y1 = OffsetY + 10 ; y2 = OffsetY + 25; y3 = OffsetY + 40;
01844    XSetForeground(display,gc,LightGreen.pixel);
01845    XDrawLine(display,Cow,gc,x1  ,y1-1,x2  ,y2  );
01846    XDrawLine(display,Cow,gc,x1  ,y1-2,x2+1,y2  );
01847    XSetForeground(display,gc,DarkGreen.pixel);
01848    XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y3+1);
01849    XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y3+2);
01850 
01851    // Blue <pause> button
01852 
01853    XSetForeground(display,gc,Blue.pixel);
01854    XFillPolygon(display,Cow,gc,PauseButton1,4,Convex,CoordModeOrigin);
01855    XFillPolygon(display,Cow,gc,PauseButton2,4,Convex,CoordModeOrigin);
01856    
01857    x1 = 95; x2 = 102; y1 = OffsetY + 10; y2 = OffsetY + 40;
01858    XSetForeground(display,gc,DarkBlue.pixel);
01859    XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2  );
01860    XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1);
01861    XDrawLine(display,Cow,gc,x1-1,y2  ,x2  ,y2  );
01862    XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1);
01863    XSetForeground(display,gc,LightBlue.pixel);
01864    XDrawLine(display,Cow,gc,x2  ,y1-1,x2  ,y2  );
01865    XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1);
01866    XDrawLine(display,Cow,gc,x1-1,y1-1,x2  ,y1-1);
01867    XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2);
01868 
01869    x1 = 108; x2 = 115; y1 = OffsetY + 10; y2 = OffsetY + 40;
01870    XSetForeground(display,gc,DarkBlue.pixel);
01871    XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2  );
01872    XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1);
01873    XDrawLine(display,Cow,gc,x1-1,y2  ,x2  ,y2  );
01874    XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1);
01875    XSetForeground(display,gc,LightBlue.pixel);
01876    XDrawLine(display,Cow,gc,x2  ,y1-1,x2  ,y2  );
01877    XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1);
01878    XDrawLine(display,Cow,gc,x1-1,y1-1,x2  ,y1-1);
01879    XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2);
01880 
01881    // Help button
01882 
01883    x1 = 200; x2 = x1 + 5 * BigFontWidth; y1 = OffsetY + 10; y2 = y1 + 30;
01884    XSetForeground(display,gc,Red.pixel);
01885    XFillRectangle(display,Cow,gc,x1,y1,x2-x1,y2-y1);
01886    XSetForeground(display,gc,BlackPix);
01887    XDrawRectangle(display,Cow,gc,x1-1,y1-1,x2-x1+1,y2-y1+1);
01888    XSetFont(display,gc,BigFont->fid);
01889    XSetForeground(display,gc,Yellow.pixel);
01890    XSetBackground(display,gc,Red.pixel);
01891    XDrawImageString(display,Cow,gc,x1+BigFontWidth/2,(y1+y2)/2+BigFont->ascent/2,"HELP",4);
01892 
01893    ShowStep();
01894    ShowParcs();
01895    ShowWindowStatus();
01896    ShowGridStatus();
01897    return 0;
01898 }
01899 
01900 
01901 void ClearTracer(void)
01902 {
01903    int j;
01904    for (j=0 ; j < MAXPAR ; ++j)
01905    {
01906       pax[j] = -1.0;
01907       pay[j] = -1.0;
01908    }
01909 }
01910 
01911 
01912 int CheckEndianess(void)
01913 {
01914    union EndianCheck
01915    {
01916       char b[sizeof(int)];
01917       int  i;
01918    } ec;
01919 
01920    ec.i = 8; 
01921    return (ec.b[0] == 0);
01922 }
01923 
01924 
01925 void initgui_(int *model, int *debug, int *lats, int *mrpid, int *mrnum)
01926 {
01927    int x,y,w,h;
01928    int argc = 1;
01929    int i,j;
01930    unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
01931    XGCValues values;
01932    XEvent Event;
01933    struct timeval TimeVal;
01934 
01935    // Check for big endian computer
01936    // The bitmap format ".bmp" ist little endian
01937 
01938    BigEndian = CheckEndianess();
01939 
01940    // Set seed for random number generator from clock
01941 
01942    gettimeofday(&TimeVal,NULL);
01943    Seed = TimeVal.tv_sec;
01944    
01945    Model = *model;
01946    Debug = *debug;
01947    Latitudes = *lats;
01948    MRpid = *mrpid;
01949    MRnum = *mrnum;
01950 
01951    if (MRpid >= 0)
01952    {
01953       sprintf(wtrun,"[%d] ",MRpid);
01954       wto = strlen(wtrun);
01955    }
01956 
01957    if (Debug) printf("initgui(%d,%d)\n",Model,Debug);
01958    if ((display=XOpenDisplay(display_name)) == NULL)
01959    {
01960       fprintf(stderr,"%s: cannot connect to X server %s\n", 
01961               progname, XDisplayName(display_name));
01962       exit(1);
01963    }
01964    screen_num = DefaultScreen(display);
01965    ScreenD  = XDefaultDepth(display,screen_num);
01966    ScreenW  = DisplayWidth (display,screen_num);
01967    ScreenH  = DisplayHeight(display,screen_num);
01968    BlackPix = BlackPixel(display,screen_num);
01969    WhitePix = WhitePixel(display,screen_num);
01970    SmallScreen = ScreenH <= 768;
01971    if (SmallScreen)
01972    {
01973       WinRows = 2;
01974       NumWin  = WinCols * WinRows;
01975       Grid = 0;
01976    }
01977 
01978    if (MRnum == 2) ScreenW /= 2; /* Run with two GUI's */
01979 
01980    /* Fix defaults for multihead displays */
01981 
01982    if (ScreenH > ScreenW && ScreenH > 1200) ScreenH = 1200;
01983    if (ScreenW > 2 * ScreenH && ScreenW >= 2048) ScreenW /= 2;
01984 
01985    for (i = 0 ; i < NUMWIN ; ++i)
01986    {
01987       WindowTitle[i] = CharAlloc(256,"WindowTitle");
01988       if (wto == 0) sprintf(WindowTitle[i],"Window %d",i+1);
01989       else          sprintf(WindowTitle[i],"%sWindow %d",wtrun,i+1);
01990       WinAtt[i].x = -1;
01991       WinAtt[i].y = -1;
01992       WinAtt[i].w = -1;
01993       WinAtt[i].h = -1;
01994       WinAtt[i].active = 1;
01995    }
01996 
01997    CreateTestWindow();
01998 
01999    if (MRpid >= 0) sprintf(GUI_default,"GUI_%2.2d.cfg",MRpid);
02000    ReadConfig(GUI_default);
02001    if (MRpid >= 0) sprintf(GUI_config,"GUI_last_used_%2.2d.cfg",MRpid);
02002    ReadConfig(GUI_config);
02003 
02004    LoadFonts();
02005    CreateControlWindow();
02006 
02007    OutXSize = (ScreenW-ScreenOffset) / WinCols;
02008    OutYSize = (CowY-ScreenOffset-1-WM_top_area)  / WinRows;
02009    WinXSize = OutXSize - WinLM - WinRM;
02010    WinYSize = OutYSize - WinTM - WinBM;
02011    WinSizeHints.flags      = PPosition | PSize | PMinSize;
02012    WinSizeHints.min_width  = 200;
02013    WinSizeHints.min_height = 100;
02014    if (Debug)
02015    {
02016       printf("Outer windowsize = %dx%d\n",OutXSize,OutYSize);
02017       printf("Inner windowsize = %dx%d\n",WinXSize,WinYSize);
02018    }
02019 
02020    wm_hints.initial_state = NormalState;
02021    wm_hints.input = True;
02022    wm_hints.flags = StateHint | InputHint;
02023    
02024    class_hints.res_name = progname;
02025    class_hints.res_class = "PUMA";
02026 
02027    Delwin = XInternAtom(display,"WM_DELETE_WINDOW",0);
02028 
02029    ReadImage(&MapHR,"map.bmp");
02030 
02031    for (i = 0 ; i < NumWin ; ++i)
02032    {
02033       x = WinAtt[i].x;
02034       y = WinAtt[i].y;
02035       w = WinAtt[i].w;
02036       h = WinAtt[i].h;
02037 
02038       if (x < ScreenOffset || x >= ScreenW) x = ScreenOffset+(i%WinCols)*OutXSize;
02039       if (y < ScreenOffset || y >= ScreenH) y = ScreenOffset+(i/WinCols)*OutYSize+WM_top_area;
02040       if (w <  WinSizeHints.min_width ) w = WinXSize;
02041       if (h <  WinSizeHints.min_height) h = WinYSize;
02042       XStringListToTextProperty(&WindowTitle[i],1,WindowName+i);
02043       if (WinAtt[i].active)
02044       {
02045          if (MRnum == 2 && MRpid == 1) x += ScreenW;
02046          Win[i] = XCreateWindow(display,RootWindow(display,screen_num), // display, parent
02047                   x,y,w,h,
02048                   BorderWidth,CopyFromParent,InputOutput,         // border, depth, class
02049                   CopyFromParent,0,NULL);                         // visual, valuemask, attributes
02050          XSetWMProtocols(display,Win[i],&Delwin,1);
02051          XSetWMProperties(display,Win[i],WindowName+i,NULL,
02052                 NULL,0,&WinSizeHints,&wm_hints,&class_hints);
02053          XSelectInput(display,Win[i],ButtonPressMask | KeyPressMask | ExposureMask);
02054          XMapWindow(display,Win[i]);
02055       }
02056    }
02057 
02058    /* Prepare GC */
02059 
02060    gc = XCreateGC(display, Cow, valuemask, &values);
02061    XSetFont(display, gc, FixFont->fid);
02062    colormap = XDefaultColormap(display,screen_num);
02063    XSetForeground(display,gc,BlackPix);
02064    XSetBackground(display,gc,WhitePix);
02065 
02066    /* Get keyboard information */
02067 
02068    XDisplayKeycodes(display,&FirstKey,&LastKey);
02069    KeyMap = XGetKeyboardMapping(display,FirstKey,LastKey-FirstKey+1,&SymsPerKey);
02070 
02071    /* Allocate color cells */
02072 
02073    for (i=0 ; i < NUMPAL ; ++i)
02074       LineCo[i] = AllocateColorCells(Pallet[i]);
02075   
02076    /* Color cells for control window */
02077 
02078    XAllocNamedColor(display,colormap,"red"        ,&Red       ,&Dummy);
02079    XAllocNamedColor(display,colormap,"green"      ,&Green     ,&Dummy);
02080    XAllocNamedColor(display,colormap,"blue"       ,&Blue      ,&Dummy);
02081    XAllocNamedColor(display,colormap,"grey"       ,&Grey      ,&Dummy);
02082    XAllocNamedColor(display,colormap,"yellow"     ,&Yellow    ,&Dummy);
02083    XAllocNamedColor(display,colormap,"hot pink"   ,&LightRed  ,&Dummy);
02084    XAllocNamedColor(display,colormap,"dark red"   ,&DarkRed   ,&Dummy);
02085    XAllocNamedColor(display,colormap,"light blue" ,&LightBlue ,&Dummy);
02086    XAllocNamedColor(display,colormap,"dark blue"  ,&DarkBlue  ,&Dummy);
02087    XAllocNamedColor(display,colormap,"light green",&LightGreen,&Dummy);
02088    XAllocNamedColor(display,colormap,"dark green" ,&DarkGreen ,&Dummy);
02089 
02090    TSColor[0] = Red.pixel;
02091    TSColor[1] = Green.pixel;
02092    TSColor[2] = Blue.pixel;
02093    TSColor[3] = WhitePix;
02094    TSColor[4] = LightRed.pixel;
02095    TSColor[5] = Grey.pixel;
02096    TSColor[6] = Yellow.pixel;
02097    TSColor[7] = LightBlue.pixel;
02098    TSColor[8] = LightGreen.pixel;
02099 
02100    ClearTracer();
02101    CalcButtonAreas();
02102    RedrawControlWindow();
02103    XSync(display,0);
02104 }
02105 
02106 void FillPoly(int n, REAL Poly[])
02107 {
02108    int i;
02109    XPoint xpol[8];
02110    for (i=0; i < n ; ++i)
02111    {
02112       xpol[i].x = OffX + Poly[i+i  ] + 0.5;
02113       xpol[i].y = OffY + Poly[i+i+1] + 0.5;
02114    }
02115    XFillPolygon(display,pix,gc,xpol,n,Convex,CoordModeOrigin);
02116 }
02117 
02118 /* ======= */
02119 /* IsoArea */
02120 /* ======= */
02121 
02122 void IsoArea(INT y, REAL vl, REAL vh, REAL Top[], REAL Bot[], INT Dim)
02123 {
02124    INT  f,x,p;
02125    REAL xl,xr,yt,yb;
02126    REAL Poly[16];
02127 
02128    // if (Debug) printf("IsoArea %d %10.2f %10.2f %10.2f %10.2f %d\n",y,vl,vh,Top[0],Bot[0],Dim);
02129    for (x=0 ; x < Dim-1 ; x++)
02130    {
02131       Flag[x] = 0;
02132       if (Top[x  ] <  vl) Flag[x] |= TOLELO;
02133       if (Top[x  ] >= vh) Flag[x] |= TOLEHI;
02134       if (Top[x+1] <  vl) Flag[x] |= TORILO;
02135       if (Top[x+1] >= vh) Flag[x] |= TORIHI;
02136       if (Bot[x  ] <  vl) Flag[x] |= BOLELO;
02137       if (Bot[x  ] >= vh) Flag[x] |= BOLEHI;
02138       if (Bot[x+1] <  vl) Flag[x] |= BORILO;
02139       if (Bot[x+1] >= vh) Flag[x] |= BORIHI;
02140    }
02141 
02142    x = 0;
02143 
02144    while (x < Dim-1)
02145    {
02146       xl = VGAX *  x   ;
02147       xr = VGAX * (x+1);
02148       yt = VGAY *  y   ;
02149       yb = VGAY * (y+1);
02150       f  = Flag[x];
02151 
02152       if (f == 0)
02153       {
02154          x++;
02155          while (x < Dim-1 && Flag[x] == 0)
02156          {
02157             x++;
02158             xr = VGAX * x;
02159          }
02160          Poly[0] = Poly[6] = xl;
02161          Poly[1] = Poly[3] = yt;
02162          Poly[2] = Poly[4] = xr;
02163          Poly[5] = Poly[7] = yb;
02164 
02165          FillPoly(4,Poly);
02166 
02167       }
02168       else if (f == (TOLELO | TORILO | BOLELO | BORILO) ||
02169                f == (TOLEHI | TORIHI | BOLEHI | BORIHI))   x++;
02170       else if (Top[x] < vl && Top[x+1] >= vl && Bot[x] >= vl && Bot[x+1] < vl)
02171       {
02172          Poly[1] = Poly[3] = yt;
02173          Poly[2] = Poly[4] = xr;
02174          Poly[0] = IPX(Top[x  ],vl,Top[x+1]);
02175          Poly[5] = IPY(Top[x+1],vl,Bot[x+1]);
02176          FillPoly(3,Poly);
02177          Poly[1] = Poly[3] = yb;
02178          Poly[2] = Poly[4] = xl;
02179          Poly[0] = IPX(Bot[x  ],vl,Bot[x+1]);
02180          Poly[5] = IPY(Top[x  ],vl,Bot[x  ]);
02181          FillPoly(3,Poly);
02182          ++x;
02183       }
02184       else if (Top[x] >= vl && Top[x+1] < vl && Bot[x] < vl && Bot[x+1] >= vl)
02185       {
02186          Poly[0] = Poly[4] = xl;
02187          Poly[1] = Poly[3] = yt;
02188          Poly[2] = IPX(Top[x  ],vl,Top[x+1]);
02189          Poly[5] = IPY(Top[x  ],vl,Bot[x  ]);
02190          FillPoly(3,Poly);
02191          Poly[0] = Poly[2] = xr;
02192          Poly[3] = Poly[5] = yb;
02193          Poly[1] = IPY(Top[x+1],vl,Bot[x+1]);
02194          Poly[4] = IPX(Bot[x  ],vl,Bot[x+1]);
02195          FillPoly(3,Poly);
02196          ++x;
02197       }
02198       else
02199       {
02200          p = 0;
02201 
02202          if (Top[x] < vl)
02203          {
02204             if (Top[x+1] >= vl)
02205             {
02206                Poly[p++] = IPX(Top[x],vl,Top[x+1]);
02207                Poly[p++] = yt;
02208             }
02209 
02210             if (Top[x+1] >= vh)
02211             {
02212                Poly[p++] = IPX(Top[x],vh,Top[x+1]);
02213                Poly[p++] = yt;
02214             }
02215          }
02216          else if (Top[x] >= vh)
02217          {
02218             if (Top[x+1] < vh)
02219             {
02220                Poly[p++] = IPX(Top[x],vh,Top[x+1]);
02221                Poly[p++] = yt;
02222             }
02223             if (Top[x+1] < vl)
02224             {
02225                Poly[p++] = IPX(Top[x],vl,Top[x+1]);
02226                Poly[p++] = yt;
02227             }
02228          }
02229          else
02230          {
02231             Poly[p++] = xl;
02232             Poly[p++] = yt;
02233             if (Top[x+1] < vl)
02234             {
02235                Poly[p++] = IPX(Top[x],vl,Top[x+1]);
02236                Poly[p++] = yt;
02237             }
02238             if (Top[x+1] >= vh)
02239             {
02240                Poly[p++] = IPX(Top[x],vh,Top[x+1]);
02241                Poly[p++] = yt;
02242             }
02243          }
02244 
02245          if (Top[x+1] < vl)
02246          {
02247             if (Bot[x+1] >= vl)
02248             {
02249                Poly[p++] = xr;
02250                Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]);
02251             }
02252 
02253             if (Bot[x+1] >= vh)
02254             {
02255                Poly[p++] = xr;
02256                Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]);
02257             }
02258          }
02259          else if (Top[x+1] >= vh)
02260          {
02261             if (Bot[x+1] < vh)
02262             {
02263                Poly[p++] = xr;
02264                Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]);
02265             }
02266             if (Bot[x+1] < vl)
02267             {
02268                Poly[p++] = xr;
02269                Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]);
02270             }
02271          }
02272          else
02273          {
02274             Poly[p++] = xr;
02275             Poly[p++] = yt;
02276             if (Bot[x+1] < vl)
02277             {
02278                Poly[p++] = xr;
02279                Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]);
02280             }
02281             if (Bot[x+1] >= vh)
02282             {
02283                Poly[p++] = xr;
02284                Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]);
02285             }
02286          }
02287 
02288          if (Bot[x+1] < vl)
02289          {
02290             if (Bot[x] >= vl)
02291             {
02292                Poly[p++] = IPX(Bot[x],vl,Bot[x+1]);
02293                Poly[p++] = yb;
02294             }
02295             if (Bot[x] >= vh)
02296             {
02297                Poly[p++] = IPX(Bot[x],vh,Bot[x+1]);
02298                Poly[p++] = yb;
02299             }
02300          }
02301          else if (Bot[x+1] >= vh)
02302          {
02303             if (Bot[x] < vh)
02304             {
02305                Poly[p++] = IPX(Bot[x],vh,Bot[x+1]);
02306                Poly[p++] = yb;
02307             }
02308             if (Bot[x] < vl)
02309             {
02310                Poly[p++] = IPX(Bot[x],vl,Bot[x+1]);
02311                Poly[p++] = yb;
02312             }
02313          }
02314          else
02315          {
02316             Poly[p++] = xr;
02317             Poly[p++] = yb;
02318             if (Bot[x] < vl)
02319             {
02320                Poly[p++] = IPX(Bot[x],vl,Bot[x+1]);
02321                Poly[p++] = yb;
02322             }
02323             if (Bot[x] >= vh)
02324             {
02325                Poly[p++] = IPX(Bot[x],vh,Bot[x+1]);
02326                Poly[p++] = yb;
02327             }
02328          }
02329 
02330          if (Bot[x] < vl)
02331          {
02332             if (Top[x] >= vl)
02333             {
02334                Poly[p++] = xl;
02335                Poly[p++] = IPY(Top[x],vl,Bot[x]);
02336             }
02337 
02338             if (Top[x] >= vh)
02339             {
02340                Poly[p++] = xl;
02341                Poly[p++] = IPY(Top[x],vh,Bot[x]);
02342             }
02343          }
02344          else if (Bot[x] >= vh)
02345          {
02346             if (Top[x] < vh)
02347             {
02348                Poly[p++] = xl;
02349                Poly[p++] = IPY(Top[x],vh,Bot[x]);
02350             }
02351             if (Top[x] < vl)
02352             {
02353                Poly[p++] = xl;
02354                Poly[p++] = IPY(Top[x],vl,Bot[x]);
02355             }
02356          }
02357          else
02358          {
02359             Poly[p++] = xl;
02360             Poly[p++] = yb;
02361             if (Top[x] < vl)
02362             {
02363                Poly[p++] = xl;
02364                Poly[p++] = IPY(Top[x],vl,Bot[x]);
02365             }
02366             if (Top[x] >= vh)
02367             {
02368                Poly[p++] = xl;
02369                Poly[p++] = IPY(Top[x],vh,Bot[x]);
02370             }
02371          }
02372          FillPoly(p>>1,Poly);
02373          x++;
02374       }
02375    }
02376 }
02377 
02378 
02379 /* ======= */
02380 /* isoarea */
02381 /* ======= */
02382 
02383 void IsoAreas(struct ColorStrip Strip[])
02384 {
02385    INT  i;
02386    INT  y;
02387    REAL *Top;
02388    REAL *Bot;
02389 
02390    i = 0;
02391    while (Strip[i].Name)
02392    {
02393       Top = Field;
02394       Bot = Field + DimX;
02395       XSetForeground(display,gc,Strip[i].pixel);
02396       for (y = 0 ; y < DimY-1 ; y++)
02397       {
02398          IsoArea(y,Strip[i].Lo,Strip[i].Hi,Top,Bot,DimX);
02399          Top += DimX;
02400          Bot += DimX;
02401       }
02402       ++i;
02403    }
02404 }
02405 
02406 /* ======= */
02407 /* IsoLine */
02408 /* ======= */
02409 
02410 void IsoLine(INT y, REAL v, REAL Top[], REAL Bot[], INT Dim)
02411 {
02412    INT  f,x;
02413    REAL xl,xr,yt,yb;
02414    REAL x1,yo,x2,y2,x3,y3,x4,y4;
02415 
02416    for (x=0 ; x < Dim-1 ; x++)
02417    {
02418       Flag[x] = 0;
02419       if (Top[x  ] <  v) Flag[x] |= TOLELO;
02420       else               Flag[x] |= TOLEHI;
02421       if (Top[x+1] <  v) Flag[x] |= TORILO;
02422       else               Flag[x] |= TORIHI;
02423       if (Bot[x  ] <  v) Flag[x] |= BOLELO;
02424       else               Flag[x] |= BOLEHI;
02425       if (Bot[x+1] <  v) Flag[x] |= BORILO;
02426       else               Flag[x] |= BORIHI;
02427    }
02428 
02429    x = 0;
02430 
02431    while (x < Dim-1)
02432    {
02433       xl = VGAX *  x   ;
02434       xr = VGAX * (x+1);
02435       yt = VGAY *  y   ;
02436       yb = VGAY * (y+1);
02437       f  = Flag[x];
02438 
02439       if (f == 0 || f == (TOLELO | TORILO | BOLELO | BORILO) ||
02440                     f == (TOLEHI | TORIHI | BOLEHI | BORIHI))   x++;
02441       else if (f == (TOLELO | BORILO | TORIHI | BOLEHI))
02442       {
02443          x1 = IPX(Top[x  ],v,Top[x+1]);
02444          yo = yt;
02445          x2 = xr;
02446          y2 = IPY(Top[x+1],v,Bot[x+1]);
02447          x3 = IPX(Bot[x  ],v,Bot[x+1]);
02448          y3 = yb;
02449          x4 = xl;
02450          y4 = IPY(Top[x  ],v,Bot[x  ]);
02451          XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2);
02452          XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4);
02453          ++x;
02454       }
02455       else if (f == (TORILO | BOLELO | TOLEHI | BORIHI))
02456       {
02457          x1 = xl;
02458          yo = IPY(Top[x  ],v,Bot[x  ]);
02459          x2 = IPX(Top[x  ],v,Top[x+1]);
02460          y2 = yt;
02461          x3 = xr;
02462          y3 = IPY(Top[x+1],v,Bot[x+1]);
02463          x4 = IPX(Bot[x  ],v,Bot[x+1]);
02464          y4 = yb;
02465          XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2);
02466          XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4);
02467          ++x;
02468       }
02469       else
02470       {
02471          x1 = x2 = x3 = x4 = -1;
02472 
02473          if (Top[x  ] < v && Top[x+1] >= v || Top[x  ] >= v && Top[x+1] < v)
02474          {
02475             x1 = IPX(Top[x  ],v,Top[x+1]);
02476             yo = yt;
02477          }
02478          if (Top[x+1] < v && Bot[x+1] >= v || Top[x+1] >= v && Bot[x+1] < v)
02479          {
02480             x2 = xr;
02481             y2 = IPY(Top[x+1],v,Bot[x+1]);
02482          }
02483          if (Bot[x+1] < v && Bot[x  ] >= v || Bot[x+1] >= v && Bot[x  ] < v)
02484          {
02485             x3 = IPX(Bot[x  ],v,Bot[x+1]);
02486             y3 = yb;
02487          }
02488          if (Bot[x  ] < v && Top[x  ] >= v || Bot[x  ] >= v && Top[x  ] < v)
02489          {
02490             x4 = xl;
02491             y4 = IPY(Top[x  ],v,Bot[x  ]);
02492          }
02493 
02494          if (x1 >= 0 && x2 >= 0 && x3 >= 0 && x4 >= 0)
02495          {
02496             XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2);
02497             XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4);
02498          }
02499          else if (x1 >= 0)
02500          {
02501             if      (x2 >= 0) XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2);
02502             else if (x3 >= 0) XDrawLine(display,pix,gc,x1,OffY+yo,x3,OffY+y3);
02503             else              XDrawLine(display,pix,gc,x1,OffY+yo,x4,OffY+y4);
02504          }
02505          else if (x2 >= 0)
02506          {
02507             if (x3 >= 0) XDrawLine(display,pix,gc,x2,OffY+y2,x3,OffY+y3);
02508             else         XDrawLine(display,pix,gc,x2,OffY+y2,x4,OffY+y4);
02509          }
02510          else XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4);
02511 
02512          x++;
02513       }
02514    }
02515 }
02516 
02517 
02518 /* ======== */
02519 /* IsoLines */
02520 /* ======== */
02521 
02522 void IsoLines(struct ColorStrip Strip[],int Colored)
02523 {
02524    INT  i;
02525    INT  y;
02526    REAL *Top;
02527    REAL *Bot;
02528 
02529    XSetForeground(display,gc,BlackPix);
02530    i = 0;
02531    while (Strip[i].Name)
02532    {
02533       Top = Field;
02534       Bot = Field + DimX;
02535       if (Colored) XSetForeground(display,gc,Strip[i].pixel);
02536       for (y = 0 ; y < DimY-1 ; y++)
02537       {
02538          IsoLine(y,Strip[i].Lo,Top,Bot,DimX);
02539          Top += DimX;
02540          Bot += DimX;
02541       }
02542       ++i;
02543    }
02544 }
02545 
02546 int AziPoint(int fpx, int fpy, int *x2, int *y2)
02547 {
02548    int xc,yc;
02549    double flam,fsin,fcos,roa,pil,piy;
02550 
02551    xc  = InXSize >> 1;
02552    yc  = InYSize >> 1;
02553    roa = MapLR[win].l * InXSize / 360.0;
02554    pil = 2.0 * M_PI / InXSize;
02555    piy = M_PI / InYSize;
02556 
02557    flam = (fpx - xc - roa) * pil;
02558    if (flam < -M_PI) flam += 2.0 * M_PI;
02559    if (flam >  M_PI) flam -= 2.0 * M_PI;
02560    if (flam < -M_PI_2 || flam > M_PI_2) return 1;
02561    fsin = sin(flam);
02562    fcos = cos((fpy-yc) * piy);
02563    *x2  = xc + InYSize/2 * fcos * fsin;
02564    *y2  = yc + InYSize/2 * sin((fpy-yc) * piy);
02565    return 0;
02566 }
02567 
02568 void AziLine(int x1, int y1, int x2, int y2)
02569 {
02570    int a1,b1,a2,b2;
02571 
02572    if (AziPoint(x1,y1,&a1,&b1)) return;
02573    if (AziPoint(x2,y2,&a2,&b2)) return;
02574    XDrawLine(display,pix,gc,a1,b1,a2,b2);
02575 }
02576 
02577 
02578 /* ======= */
02579 /* MapLine */
02580 /* ======= */
02581 
02582 void MapLine(INT y, REAL v, REAL Top[], REAL Bot[], INT Dim)
02583 {
02584    INT  f,x;
02585    REAL xl,xr,yt,yb;
02586    REAL x1,yo,x2,y2,x3,y3,x4,y4;
02587 
02588    for (x=0 ; x < Dim-1 ; x++)
02589    {
02590       Flag[x] = 0;
02591       if (Top[x  ] <  v) Flag[x] |= TOLELO;
02592       else               Flag[x] |= TOLEHI;
02593       if (Top[x+1] <  v) Flag[x] |= TORILO;
02594       else               Flag[x] |= TORIHI;
02595       if (Bot[x  ] <  v) Flag[x] |= BOLELO;
02596       else               Flag[x] |= BOLEHI;
02597       if (Bot[x+1] <  v) Flag[x] |= BORILO;
02598       else               Flag[x] |= BORIHI;
02599    }
02600 
02601    x = 0;
02602 
02603    while (x < Dim-1)
02604    {
02605       xl = VGAX *  x   ;
02606       xr = VGAX * (x+1);
02607       yt = VGAY *  y   ;
02608       yb = VGAY * (y+1);
02609       f  = Flag[x];
02610 
02611       if (f == 0 || f == (TOLELO | TORILO | BOLELO | BORILO) ||
02612                     f == (TOLEHI | TORIHI | BOLEHI | BORIHI))   x++;
02613       else if (f == (TOLELO | BORILO | TORIHI | BOLEHI))
02614       {
02615          x1 = IPX(Top[x  ],v,Top[x+1]);
02616          yo = yt;
02617          x2 = xr;
02618          y2 = IPY(Top[x+1],v,Bot[x+1]);
02619          x3 = IPX(Bot[x  ],v,Bot[x+1]);
02620          y3 = yb;
02621          x4 = xl;
02622          y4 = IPY(Top[x  ],v,Bot[x  ]);
02623          AziLine(x1,OffY+yo,x2,OffY+y2);
02624          AziLine(x3,OffY+y3,x4,OffY+y4);
02625          ++x;
02626       }
02627       else if (f == (TORILO | BOLELO | TOLEHI | BORIHI))
02628       {
02629          x1 = xl;
02630          yo = IPY(Top[x  ],v,Bot[x  ]);
02631          x2 = IPX(Top[x  ],v,Top[x+1]);
02632          y2 = yt;
02633          x3 = xr;
02634          y3 = IPY(Top[x+1],v,Bot[x+1]);
02635          x4 = IPX(Bot[x  ],v,Bot[x+1]);
02636          y4 = yb;
02637          AziLine(x1,OffY+yo,x2,OffY+y2);
02638          AziLine(x3,OffY+y3,x4,OffY+y4);
02639          ++x;
02640       }
02641       else
02642       {
02643          x1 = x2 = x3 = x4 = -1;
02644 
02645          if (Top[x  ] < v && Top[x+1] >= v || Top[x  ] >= v && Top[x+1] < v)
02646          {
02647             x1 = IPX(Top[x  ],v,Top[x+1]);
02648             yo = yt;
02649          }
02650          if (Top[x+1] < v && Bot[x+1] >= v || Top[x+1] >= v && Bot[x+1] < v)
02651          {
02652             x2 = xr;
02653             y2 = IPY(Top[x+1],v,Bot[x+1]);
02654          }
02655          if (Bot[x+1] < v && Bot[x  ] >= v || Bot[x+1] >= v && Bot[x  ] < v)
02656          {
02657             x3 = IPX(Bot[x  ],v,Bot[x+1]);
02658             y3 = yb;
02659          }
02660          if (Bot[x  ] < v && Top[x  ] >= v || Bot[x  ] >= v && Top[x  ] < v)
02661          {
02662             x4 = xl;
02663             y4 = IPY(Top[x  ],v,Bot[x  ]);
02664          }
02665 
02666          if (x1 >= 0 && x2 >= 0 && x3 >= 0 && x4 >= 0)
02667          {
02668             AziLine(x1,OffY+yo,x2,OffY+y2);
02669             AziLine(x3,OffY+y3,x4,OffY+y4);
02670          }
02671          else if (x1 >= 0)
02672          {
02673             if      (x2 >= 0) AziLine(x1,OffY+yo,x2,OffY+y2);
02674             else if (x3 >= 0) AziLine(x1,OffY+yo,x3,OffY+y3);
02675             else              AziLine(x1,OffY+yo,x4,OffY+y4);
02676          }
02677          else if (x2 >= 0)
02678          {
02679             if (x3 >= 0) AziLine(x2,OffY+y2,x3,OffY+y3);
02680             else         AziLine(x2,OffY+y2,x4,OffY+y4);
02681          }
02682          else AziLine(x3,OffY+y3,x4,OffY+y4);
02683 
02684          x++;
02685       }
02686    }
02687 }
02688 
02689 
02690 /* ======== */
02691 /* MapLines */
02692 /* ======== */
02693 
02694 void MapLines(struct ColorStrip Strip[],int Colored)
02695 {
02696    INT  i;
02697    INT  y;
02698    REAL *Top;
02699    REAL *Bot;
02700 
02701    XSetForeground(display,gc,BlackPix);
02702    i = 0;
02703    while (Strip[i].Name)
02704    {
02705       Top = Field;
02706       Bot = Field + DimX;
02707       if (Colored) XSetForeground(display,gc,Strip[i].pixel);
02708       for (y = 0 ; y < DimY-1 ; y++)
02709       {
02710          MapLine(y,Strip[i].Lo,Top,Bot,DimX);
02711          Top += DimX;
02712          Bot += DimX;
02713       }
02714       ++i;
02715    }
02716 }
02717 
02718 int polco = 0;
02719 
02720 void poltra(float lam, float phi, float *x, float *y)
02721 {
02722    REAL xnp,ynp,xsp,ysp,lfa;
02723 
02724    lfa = (2.0 * M_PI) / (InXSize-1) ;
02725    xnp = (InXSize-1) * 0.25;
02726    ynp = (InYSize-1) * 0.50;
02727    xsp = (InXSize-1) * 0.75;
02728    ysp = ynp;
02729 
02730    /* Northern hemisphere */
02731 
02732    if (phi < ynp)
02733    {
02734       *x = xnp + sin(lam * lfa) * phi;
02735       *y = ynp + cos(lam * lfa) * phi;
02736    }
02737 
02738    /* Souhern hemisphere */
02739 
02740    else
02741    {
02742       *x = xsp - sin(lam * lfa) * (phi-ysp);
02743       *y = ysp + cos(lam * lfa) * (phi-ysp);
02744    }
02745 }
02746 
02747 
02748 /* ========== */
02749 /* TracerPlot */
02750 /* ========== */
02751 
02752 void TracerPlot(int w)
02753 {
02754    int j,ipx,ipy,lpy,lpx,jx,jy,ic,ix,iy,ipr;
02755    int xnp,ynp,xsp,ysp,xc,yc;
02756    float *u;
02757    float *v;
02758    float fpx,fpy,du,dv,ppx,ppy,rx,ry,spfac;
02759    float lfa,lam,phi,hpy,fcos,fsin;
02760    float pil,piy;
02761    float roa;
02762    float flam;
02763    float dpx,dpy;
02764 
02765    if (Uindex < 0 || Vindex < 0) return; // Data missing
02766 
02767    Delpar = (8 * 60) / DeltaTime; // Injection interval
02768    if (LevelChanged[w]) ClearTracer();
02769    LevelChanged[w] = 0;
02770    if (!SpeedScale) SpeedScale = FloatAlloc(DimY,"SpeedScale");
02771    u = Array[Uindex].Data + Indez[w] * DimXY;
02772    v = Array[Vindex].Data + Indez[w] * DimXY;
02773 
02774    TracerColor = Yellow.pixel;
02775    if (nstep % (8*Delpar) == 0) ColInd++;
02776    if (ColInd >= AUTOCOLORS) ColInd = 0;
02777    TracerColor = Autostrip[ColInd].pixel;
02778 
02779    dpx = (float)(InXSize-1) / (float)(DimX-1);
02780    dpy = (float)(InYSize-1) / (float)(DimY-1);
02781    lpx = InXSize;
02782    lpy = InYSize;
02783    hpy = 0.5 * dpy;
02784    xc  = lpx / 2;
02785    yc  = lpy / 2;
02786    ipr = InXSize / 400;
02787    pil = 2.0 * M_PI / lpx;
02788    piy = M_PI / lpy;
02789    roa = MapLR[w].l * lpx / 360.0;
02790 
02791    // Compute scale factors
02792 
02793    if (SizeChanged || nstep < 10)
02794    {
02795       for (j=0 ; j < DimY; ++j)
02796       {
02797          SpeedScale[j] = InXSize * DeltaTime * 60.0 / 40000000.0 
02798                        / cos((j-0.5*(DimY-1)) * (M_PI/DimY));
02799       }
02800       SpeedScale[DimY-1] = SpeedScale[0] = SpeedScale[1];
02801    }
02802 
02803    // Insert new particles
02804 
02805    if (nstep % Delpar == 0)
02806    {
02807       fpx = dpx * (DimX-1) / 2.0;
02808       for (ipy = 0 ; ipy < lpy ; ipy += dpy)
02809       {
02810          ParInd = (ParInd+1) & (MAXPAR-1);
02811          pax[ParInd] = fpx;
02812          pay[ParInd] = ipy + hpy;
02813          pal[ParInd] = TracerColor;
02814       }
02815    }
02816 
02817   // Move particles
02818 
02819   for (j=0 ; j < MAXPAR ; ++j)
02820   if (pax[j] >= 0.0 && pay[j] >= 0.0)
02821   {
02822      jx = rx = pax[j] / dpx;
02823      jy = ry = pay[j] / dpy;
02824      ic = jx + DimX * jy;
02825      ix = ic + 1;
02826      if (jx >= DimX-1) ix -= DimX;
02827      iy = ic + DimX;
02828      if (iy >= DimX * DimY) iy -= DimX;
02829      rx -= jx;
02830      ry -= jy;
02831 
02832      du = u[ic]+(u[ix]-u[ic])*rx+(u[iy]-u[ic])*ry;
02833      dv = v[ic]+(v[ix]-v[ic])*rx+(v[iy]-v[ic])*ry;
02834      spfac = SpeedScale[jy] + (SpeedScale[jy+1]-SpeedScale[jy]) * ry;
02835      du *= spfac;
02836      dv *= spfac;
02837      fpx = pax[j] + du;
02838      fpy = pay[j] + dv;
02839      if (fpx <  0.0) fpx += lpx;
02840      if (fpx >= lpx) fpx -= lpx;
02841      if (fpy < 0.0 || fpy > lpy-1)
02842      {
02843         pay[j] = -1.0;
02844         continue;
02845      }
02846      pax[j] = fpx;
02847      pay[j] = fpy;
02848      ipx    =  -1;
02849      if (MapPro[w] == POLAR)
02850      {
02851        lfa = (2.0 * M_PI) / lpx;
02852        xnp = (InXSize-1) * 0.25;
02853        ynp = (InYSize-1) * 0.50;
02854        xsp = (InXSize-1) * 0.75;
02855        ysp = ynp;
02856        lam = fpx;
02857        phi = fpy;
02858        if (phi < 0.5 * lpy) /* Northern hemisphere */
02859        {
02860           fpx = xnp - sin(lam * lfa) * (phi + hpy);
02861           fpy = ynp - cos(lam * lfa) * (phi + hpy);
02862        }
02863        else                 /* Souhern hemisphere */
02864        {
02865           fpx = xsp + sin(lam * lfa) * (lpy - phi + hpy);
02866           fpy = ysp - cos(lam * lfa) * (lpy - phi + hpy);
02867        }
02868        ipx = rintf(fpx);
02869        ipy = rintf(fpy);
02870      }
02871      else if (MapPro[w] == AZIMUTHAL)
02872      {
02873         flam = (fpx - xc - roa) * pil;
02874         if (flam < -M_PI) flam += 2.0 * M_PI;
02875         if (flam >  M_PI) flam -= 2.0 * M_PI;
02876         if (flam < -M_PI_2 || flam > M_PI_2) continue;
02877         fsin = sin(flam);
02878         fcos = cos((fpy-yc) * piy);
02879         fpx  = xc + lpy/2 * fcos * fsin;
02880         fpy  = yc + lpy/2 * sin((fpy-yc) * piy);
02881         ipx  = rintf(fpx);
02882         ipy  = rintf(fpy);
02883      }
02884      else
02885      {
02886         ipx = rintf(fpx);
02887         ipy = rintf(fpy);
02888      }
02889      if (ipx >= 0)
02890      {
02891         XSetForeground(display,gc,pal[j]);
02892         if (ipr < 2) XDrawPoint(display,pix,gc,ipx,ipy);
02893         else if (ipr == 2) XFillRectangle(display,pix,gc,ipx,ipy,2,2);
02894         else XFillArc(display,pix,gc,ipx,ipy,ipr,ipr,0,360*64);
02895      }
02896   }
02897 }
02898 
02899 
02900 /* ============= */
02901 /* AmplitudePlot */
02902 /* ============= */
02903 
02904 void AmplitudePlot(void)
02905 {
02906    int i,j,m,n;
02907    int x,y;
02908    int r,dx,dy;
02909    int mmax;
02910    int imax;
02911    REAL Amax,Fac;
02912 
02913    if (!Ampli) Ampli = FloatAlloc(DimX,"Ampli");
02914    if (!Acol ) Acol  = SizeAlloc(DimX,sizeof(XColor),"Acol");
02915 
02916    Amax = 0.0;
02917    imax = 0;
02918    for (i=0 ; i < DimX ; ++i)
02919    {
02920       Ampli[i] = log (1.0 + sqrt(Field[2*i]*Field[2*i]+Field[2*i+1]*Field[2*i+1]));
02921       Acol[i].pixel = WhitePix;
02922       if (Ampli[i] > Amax && i > DimY)
02923       {
02924          Amax = Ampli[i];
02925          imax = i;
02926       }
02927    }
02928 
02929    Fac = 0.0;
02930    if (Amax > 1.e-20) Fac = 1.0 / Amax;
02931    for (i=0 ; i < DimX ; ++i)
02932    {
02933       j = AMPLI_COLS * Ampli[i] * Fac;
02934       if (j >= AMPLI_COLS) j = AMPLI_COLS-1;
02935       Acol[i].pixel = AmpliStrip[j].pixel;
02936    }
02937 
02938    dx = WinXSize / 23;
02939    r  = (dx+dx) / 3;
02940    mmax = (InYSize / dx) - 1;
02941    XSetForeground(display,gc,BlackPix);
02942    for (m=0,i=0 ; m < mmax ; ++m)
02943    {
02944       y = FixFontHeight + 4 + m * dx;
02945       for (n=m ; n < DimY ; ++n,++i)
02946       if (n < 22)
02947       {
02948          x = dx/2 + n * dx;
02949          XSetForeground(display,gc,Acol[i].pixel);
02950          XFillArc(display,pix,gc,x,y,r,r,0,360*64);
02951       }
02952    }
02953 }
02954 
02955 
02956 void RedrawIsoWindow(int w)
02957 {
02958    if (WinPixMap[w].Pix)
02959    XCopyArea(display,WinPixMap[w].Pix,Win[w],gc,0,0,WinPixMap[w].DimX,WinPixMap[w].DimY,0,0);
02960 }
02961 
02962 
02963 void CloseWindow(int i)
02964 {
02965    INTXS X,Y,xp,yp;
02966    unsigned int border,depth;
02967    Window Rootwin,Child;
02968 
02969    if (Win[i])
02970    {
02971        XGetGeometry(display,Win[i],&Rootwin,&xp,&yp,&WinAtt[i].w,&WinAtt[i].h,&border,&depth);
02972        XTranslateCoordinates(display,Win[i],Rootwin,0,0,&X,&Y,&Child);
02973        WinAtt[i].x =  X - WinLM;
02974        WinAtt[i].y =  Y - WinTM;
02975        XDestroyWindow(display,Win[i]);
02976        Win[i] = 0;
02977        ShowWindowStatus();
02978    }
02979 }
02980 
02981 void ReopenWindow(int i)
02982 {
02983    if (Win[i] == 0)
02984    {
02985       if (WinAtt[i].x < ScreenOffset) WinAtt[i].x = ScreenOffset + OutXSize * (i % WinCols);
02986       if (WinAtt[i].y < ScreenOffset) WinAtt[i].y = ScreenOffset + OutYSize * (i / WinCols);
02987       Win[i] = XCreateSimpleWindow(display,RootWindow(display,screen_num), 
02988                WinAtt[i].x,WinAtt[i].y,WinAtt[i].w,WinAtt[i].h,
02989                BorderWidth,BlackPix,WhitePix);
02990       XSetWMProtocols(display,Win[i],&Delwin,1);
02991       XSetWMProperties(display,Win[i],WindowName+i,NULL,
02992                 NULL,0,&WinSizeHints,&wm_hints,&class_hints);
02993       XSelectInput(display,Win[i],ButtonPressMask | KeyPressMask | ExposureMask);
02994       XMapWindow(display,Win[i]);
02995       ShowWindowStatus();
02996    }
02997 }
02998 
02999 char *HelpText[] =
03000 {
03001    "Key assignment for azimuthal projection     ",
03002    "--------------------------------------------",
03003    "<- cursor left  : increase westward rotation",
03004    "-> cursor right : increase eastward rotation",
03005    "============================================",
03006    "Key assignment for 3D variables             ",
03007    "--------------------------------------------",
03008    "^  cursor up    : display next upper level  ",
03009    "v  cursor down  : display next lower level  ",
03010    "============================================",
03011    "Key assignment for Lon/Lev or Hovmoeller    ",
03012    "--------------------------------------------",
03013    "^  cursor up    : switch latitude northwards",
03014    "v  cursor down  : switch latitude southwards",
03015    "============================================",
03016    "Mouse button assignment                     ",
03017    "--------------------------------------------",
03018    "Left   button   : decrease level or latitude",
03019    "Right  button   : increase level or latitude",
03020    "Middle button   : cycle through projections "
03021 };
03022 
03023 int HelpLines = sizeof(HelpText) / sizeof(char *);
03024 
03025 void DrawHelpWindow(void)
03026 {
03027    int x,y,j,l;
03028 
03029    XSetForeground(display,gc,Yellow.pixel);
03030    XSetBackground(display,gc,DarkBlue.pixel);
03031    XSetFont(display,gc,BigFont->fid);
03032 
03033    x = BigFontWidth / 2;
03034    for (j=0 ; j < HelpLines ; ++j)
03035    {
03036       y = BigFontHeight / 2 + BigFont->ascent + j * BigFontHeight;
03037       l = strlen(HelpText[j]);
03038       XDrawImageString(display,HelpWindow,gc,x,y,HelpText[j],l);
03039    }
03040 }
03041 
03042 void DisplayHelpWindow(void)
03043 {
03044    int x,y,w,h;
03045    char *HelpTitle = "Help";
03046 
03047    w = BigFontWidth  * (strlen(HelpText[0])+1);
03048    h = BigFontHeight * (HelpLines + 1);
03049    x = (ScreenW - w) / 2;
03050    y = (ScreenH - h) / 2;
03051    HelpWindow = XCreateSimpleWindow(display,RootWindow(display,screen_num), 
03052                 x,y,w,h,BorderWidth,Yellow.pixel,DarkBlue.pixel);
03053    XStringListToTextProperty(&HelpTitle,1,&HelpName);
03054    XSetWMProtocols(display,HelpWindow,&Delwin,1);
03055    XSetWMProperties(display,HelpWindow,&HelpName,NULL,NULL,0,NULL,NULL,NULL);
03056    XSelectInput(display,HelpWindow,ButtonPressMask | ExposureMask);
03057    XMapWindow(display,HelpWindow);
03058    XMoveWindow(display,HelpWindow,x,y);
03059    DrawHelpWindow();
03060 }
03061 
03062 int HitGridButton(XEvent* xe)
03063 {
03064    return (
03065    (xe->xbutton.button == Button1) &&
03066    (xe->xbutton.x >= Grid_XL  ) &&
03067    (xe->xbutton.x <= Grid_XH  ) &&
03068    (xe->xbutton.y >= Grid_YL  ) &&
03069    (xe->xbutton.y <= Grid_YH  ));
03070 }
03071 
03072 int HitPauseButton(XEvent* xe)
03073 {
03074    return (
03075    (xe->xbutton.button == Button1) &&
03076    (xe->xbutton.x >= Pause_XL-2  ) &&
03077    (xe->xbutton.x <= Pause_XH+2  ) &&
03078    (xe->xbutton.y >= Pause_YL-2  ) &&
03079    (xe->xbutton.y <= Pause_YH+2  ));
03080 }
03081 
03082 int HitStartButton(XEvent* xe)
03083 {
03084    return (
03085    (xe->xbutton.button == Button1) &&
03086    (xe->xbutton.x >= Start_XL-2  ) &&
03087    (xe->xbutton.x <= Start_XH+2  ) &&
03088    (xe->xbutton.y >= Start_YL-2  ) &&
03089    (xe->xbutton.y <= Start_YH+2  ));
03090 }
03091 
03092 int HitStopButton(XEvent* xe)
03093 {
03094    return (
03095    (xe->xbutton.button == Button1) &&
03096    (xe->xbutton.x >= Stop_XL-2   ) &&
03097    (xe->xbutton.x <= Stop_XH+2   ) &&
03098    (xe->xbutton.y >= Stop_YL-2   ) &&
03099    (xe->xbutton.y <= Stop_YH+2   ));
03100 }
03101 
03102 int HitHelpButton(XEvent* xe)
03103 {
03104    return (
03105    (xe->xbutton.button == Button1) &&
03106    (xe->xbutton.x >= Help_XL-2   ) &&
03107    (xe->xbutton.x <= Help_XH+2   ) &&
03108    (xe->xbutton.y >= Help_YL-2   ) &&
03109    (xe->xbutton.y <= Help_YH+2   ));
03110 }
03111 
03112 int HitPlusButton(XEvent* xe)
03113 {
03114    return (
03115    (xe->xbutton.button == Button1) &&
03116    (xe->xbutton.x >= Plus_XL  ) &&
03117    (xe->xbutton.x <= Plus_XH  ) &&
03118    (xe->xbutton.y >= Plus_YL  ) &&
03119    (xe->xbutton.y <= Plus_YH  ));
03120 }
03121 
03122 int HitFFWDButton(XEvent* xe)
03123 {
03124    return (
03125    (xe->xbutton.button == Button1) &&
03126    (xe->xbutton.x >= FFWD_XL  ) &&
03127    (xe->xbutton.x <= FFWD_XH  ) &&
03128    (xe->xbutton.y >= FFWD_YL  ) &&
03129    (xe->xbutton.y <= FFWD_YH  ));
03130 }
03131 
03132 int HitMinusButton(XEvent* xe)
03133 {
03134    return (
03135    (xe->xbutton.button == Button1) &&
03136    (xe->xbutton.x >= Minus_XL  ) &&
03137    (xe->xbutton.x <= Minus_XH  ) &&
03138    (xe->xbutton.y >= Minus_YL  ) &&
03139    (xe->xbutton.y <= Minus_YH  ));
03140 }
03141 
03142 int HitFBWDButton(XEvent* xe)
03143 {
03144    return (
03145    (xe->xbutton.button == Button1) &&
03146    (xe->xbutton.x >= FBWD_XL  ) &&
03147    (xe->xbutton.x <= FBWD_XH  ) &&
03148    (xe->xbutton.y >= FBWD_YL  ) &&
03149    (xe->xbutton.y <= FBWD_YH  ));
03150 }
03151 
03152 int HitUpperPanel(XEvent* xe)
03153 {
03154    return (
03155    (xe->xbutton.button == Button1) &&
03156    (xe->xbutton.x >= Parc_XL  ) &&
03157    (xe->xbutton.x <= Parc_XH  ) &&
03158    (xe->xbutton.y >= Parc_YL-Parc_YD  ) &&
03159    (xe->xbutton.y <= Parc_YL  ));
03160 }
03161 
03162 int HitLowerPanel(XEvent* xe)
03163 {
03164    return (
03165    (xe->xbutton.button == Button1) &&
03166    (xe->xbutton.x >= Parc_XL  ) &&
03167    (xe->xbutton.x <= Parc_XH  ) &&
03168    (xe->xbutton.y >= Parc_YH  ) &&
03169    (xe->xbutton.y <= Parc_YH+Parc_YD));
03170 }
03171 
03172 int HitWindowSelect(XEvent* xe)
03173 {
03174    if (
03175    (xe->xbutton.button == Button1) &&
03176    (xe->xbutton.x >= Wbox_XL) &&
03177    (xe->xbutton.x <= Wbox_XH) &&
03178    (xe->xbutton.y >= Wbox_YL) &&
03179    (xe->xbutton.y <= Wbox_YH))
03180       return (xe->xbutton.y / FixFontHeight); /* Window number */
03181    else return -1;
03182 }
03183 
03184 void OnMouseClick(void)
03185 {
03186    int w;
03187 
03188    if (HitStopButton(&CowEvent))
03189    {
03190       Shutdown = 1;
03191    }
03192    else if (HitStartButton(&CowEvent))
03193    {
03194       Paused = 0;
03195       XSetWMName(display,Cow,&WinconName1);
03196    }
03197    else if (HitGridButton(&CowEvent))
03198    {
03199       Grid = !Grid;
03200       ShowGridStatus();
03201       for (w=0 ; w < NUMWIN ; ++w) RedrawFlag[w] = 1;
03202    }
03203    else if (HitPauseButton(&CowEvent))
03204    {
03205       if (Paused)
03206       {
03207          Paused = 0;
03208          XSetWMName(display,Cow,&WinconName1);
03209       }
03210       else
03211       {
03212          Paused = 1;
03213          XSetWMName(display,Cow,&WinconPause);
03214       }
03215    }
03216    else if (HitHelpButton(&CowEvent))
03217    {
03218       if (!HelpWindow) DisplayHelpWindow();
03219    }
03220    else if ((w = HitWindowSelect(&CowEvent)) >= 0)
03221    {
03222       if (Win[w]) CloseWindow(w);
03223       else        ReopenWindow(w);
03224    }
03225    else if (HitPlusButton(&CowEvent))
03226    {
03227       Parc[cpi].Val += Parc[cpi].Inc;
03228       if (Parc[cpi].Val > Parc[cpi].Max) Parc[cpi].Val = Parc[cpi].Max;
03229    }
03230    else if (HitFFWDButton(&CowEvent))
03231    {
03232       Parc[cpi].Val += 10.0 * Parc[cpi].Inc;
03233       if (Parc[cpi].Val > Parc[cpi].Max) Parc[cpi].Val = Parc[cpi].Max;
03234    }
03235    else if (HitMinusButton(&CowEvent))
03236    {
03237        Parc[cpi].Val -= Parc[cpi].Inc;
03238       if (Parc[cpi].Val < Parc[cpi].Min) Parc[cpi].Val = Parc[cpi].Min;
03239    }
03240    else if (HitFBWDButton(&CowEvent))
03241    {
03242        Parc[cpi].Val -= 10.0 * Parc[cpi].Inc;
03243       if (Parc[cpi].Val < Parc[cpi].Min) Parc[cpi].Val = Parc[cpi].Min;
03244    }
03245    else if (HitUpperPanel(&CowEvent) && cpi > 0) --cpi;
03246    else if (HitLowerPanel(&CowEvent) && cpi < Parcs-1) ++cpi;
03247 }
03248 
03249 
03250 void SwitchIndez(int w, int d)
03251 {
03252    int jlat;
03253    REAL delphi;
03254    char *lpt;
03255    char levstr[20];
03256 
03257    if (Indez[w] < 0 || Indez[w] >= MaxZ[w])
03258    {
03259       if (Debug) printf("### Indez[%d] = %d\n",w,Indez[w]);
03260       if (Debug) printf("###  MaxZ[%d] = %d\n",w, MaxZ[w]);
03261       Indez[w] = 0;
03262    }
03263    if (Indez[w]+d <  0      ) return;
03264    if (Indez[w]+d >= MaxZ[w]) return;
03265    Indez[w] += d;
03266    lpt = strstr(WindowTitle[w],"Level");
03267    if (lpt)
03268    {
03269       sprintf(levstr," %d",Indez[w]+1);
03270       strcpy(lpt+5,levstr);
03271       XStringListToTextProperty(&WindowTitle[w],1,WindowName+w);
03272       XSetWMProperties(display,Win[w],WindowName+w,NULL,
03273                 NULL,0,&WinSizeHints,&wm_hints,&class_hints);
03274       LevelChanged[w] = 1;
03275       return;
03276    }
03277    lpt = strstr(WindowTitle[w],"Latitude");
03278    if (lpt)
03279    {
03280       delphi = 180.0 / MaxZ[w];
03281       jlat = 90.0 -Indez[w] * delphi - delphi * 0.5;
03282       if (jlat > 0) sprintf(levstr," %dN", jlat);
03283       else          sprintf(levstr," %dS",-jlat);
03284       strcpy(lpt+8,levstr);
03285       XStringListToTextProperty(&WindowTitle[w],1,WindowName+w);
03286       XSetWMProperties(display,Win[w],WindowName+w,NULL,
03287                 NULL,0,&WinSizeHints,&wm_hints,&class_hints);
03288       return;
03289    }
03290 }
03291 
03292 
03293 void HandleEvents(void)
03294 {
03295    int w,Key,KeyIndex;
03296    XEvent WinEvent;
03297 
03298    if (nstep == 1)
03299    {
03300       RedrawControlWindow();
03301       Paused = 1; /* Start in pause mode */
03302    }
03303 
03304 
03305    do
03306    {
03307       /* Check for Termination */
03308 
03309       if (XCheckTypedWindowEvent(display,Cow,ClientMessage,&WinEvent))
03310       {
03311          /* printf("delwin %d\n",WinEvent.xclient.data.l[0]); */
03312          Shutdown = 1;
03313          return;
03314       }
03315 
03316       /* Check for user request to close windows */
03317 
03318       for (w=0 ; w < NumWin ; ++w)
03319       if (Win[w])
03320       {
03321          if (XCheckTypedWindowEvent(display,Win[w],ClientMessage,&WinEvent))
03322          CloseWindow(w);
03323       }
03324 
03325       /* Check for user request to close help window */
03326 
03327       if (HelpWindow && XCheckTypedWindowEvent(display,HelpWindow,ClientMessage,&WinEvent))
03328       {
03329          XDestroyWindow(display,HelpWindow);
03330          HelpWindow = 0;
03331       }
03332 
03333       /* Check for mouse click */
03334 
03335       if (XCheckTypedWindowEvent(display,Cow,ButtonPress,&CowEvent))
03336       {
03337          OnMouseClick();
03338          RedrawControlWindow();
03339       }
03340 
03341       /* Check for mouseclicks and expose events */
03342 
03343       for (w=0 ; w < NumWin ; ++w)
03344       if (Win[w])
03345       {
03346          if (XCheckTypedWindowEvent(display,Win[w],ButtonPress,&CowEvent))
03347          {
03348            if (CowEvent.xbutton.button == Button1) SwitchIndez(w,-1);
03349            if (CowEvent.xbutton.button == Button3) SwitchIndez(w, 1);
03350            if (CowEvent.xbutton.button == Button2)
03351            {
03352               if (++MapPro[w] >= MAXMAPS) MapPro[w] = 0;
03353               if (MapPro[w] == AZIMUTHAL &&
03354                  (WinAtt[w].Plot != MAPHOR && WinAtt[w].Plot != MAPTRA))
03355                  MapPro[w] = 0;
03356            }
03357            RedrawFlag[w] = 1;
03358          }
03359          if (XCheckTypedWindowEvent(display,Win[w],KeyPress,&CowEvent))
03360          {
03361             KeyIndex = (CowEvent.xkey.keycode - FirstKey) * SymsPerKey;
03362             Key = KeyMap[KeyIndex];
03363             if (Debug) printf("Windows %d got keyindex %d with symbol %x\n",w,KeyIndex,Key);
03364             if (Key == ROTATE_LEFT  && MapLR[w].f <  5) MapLR[w].f++;
03365             if (Key == ROTATE_RIGHT && MapLR[w].f > -5) MapLR[w].f--;
03366             MapLR[w].r = MapLR[w].f * RotInc;
03367             if (Key == XK_Up  ) SwitchIndez(w,-1);
03368             if (Key == XK_Down) SwitchIndez(w, 1);
03369          }
03370          if (Paused)
03371          if (XCheckTypedWindowEvent(display,Win[w],Expose,&CowEvent))
03372                      RedrawIsoWindow(w);
03373       }
03374 
03375       if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent))
03376          RedrawControlWindow();
03377 
03378       if (HelpWindow && XCheckTypedWindowEvent(display,HelpWindow,Expose,&CowEvent))
03379          DrawHelpWindow();
03380 
03381    } while (Paused && !Shutdown);
03382 }
03383 
03384 void guiclose_(void)
03385 {
03386    int w;
03387 
03388    if (MRpid >= 0) return; // Don't wait if multiple instances
03389    XSetWMName(display,Cow,&WinconName3);
03390 
03391    do
03392    {
03393       for (w=0 ; w < NumWin ; ++w)
03394       if (Win[w])
03395       {
03396          if (XCheckTypedWindowEvent(display,Win[w],Expose,&CowEvent))
03397                      RedrawIsoWindow(w);
03398       }
03399 
03400       if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent))
03401          RedrawControlWindow();
03402    }
03403    while (!(XCheckTypedWindowEvent(display,Cow,ButtonPress,&CowEvent) &&
03404             HitStopButton(&CowEvent)));
03405      
03406 // XCloseDisplay(display); // segmentation fault on sun compiler!
03407 }
03408 
03409 void SaveConfig(void)
03410 {
03411    int i;
03412    FILE *scp;
03413    INTXS X,Y,xp,yp;
03414    unsigned int w,W,H,border,depth;
03415    Window Rootwin,Child;
03416    XWindowAttributes RootAtt;
03417 
03418    scp = fopen(GUI_config,"w");
03419    if (scp == NULL) return;
03420 
03421    /* Save window properties */
03422 
03423    fprintf(scp,"Hamburg GUI Config File Version 16\n");
03424    fprintf(scp,"Screen: %dx%d\n\n",ScreenW,ScreenH);
03425    fprintf(scp,"WinRows = %d\n",WinRows);
03426    fprintf(scp,"WinCols = %d\n",WinCols);
03427    for (w=0 ; w < NumWin ; ++w)
03428    {
03429       fprintf(scp,"\n[Window %02d]\n",w);
03430       fprintf(scp,"Array:%s\n",WinAtt[w].array_name);
03431       fprintf(scp,"Plot:%s\n",IsoNames[WinAtt[w].Plot]);
03432       if (WinAtt[w].Plot == ISOHOR || WinAtt[w].Plot == MAPHOR ||
03433           WinAtt[w].Plot == ISOTRA || WinAtt[w].Plot == MAPTRA)
03434       {
03435          fprintf(scp,"Projection:%s\n",ProNames[MapPro[w]]);
03436          fprintf(scp,"Rotation factor:%d\n",MapLR[w].f);
03437       }
03438       fprintf(scp,"Palette:%s\n",PalNames[WinAtt[w].Palette]);
03439       fprintf(scp,"Title:%s\n",WindowTitle[w]+wto);
03440       if (Win[w])
03441       {
03442          XGetGeometry(display,Win[w],&Rootwin,&xp,&yp,&W,&H,&border,&depth);
03443          XTranslateCoordinates(display,Win[w],Rootwin,0,0,&X,&Y,&Child);
03444          fprintf(scp,"Geometry: %4d %4d %4d %4d\n",W,H,X-WinLM,Y-WinTM);
03445          if (Debug)
03446          {
03447             printf("Geometry Window %d   [%8x]: %4d / %4d   %4d x %4d x %2d | %d\n",
03448                   w,(int)Win[w],xp,yp,W,H,depth,border);
03449             printf("Translated UL corner: %4d / %4d\n",X,Y);
03450          }
03451       }
03452       else
03453          fprintf(scp,"Inactive: %4d %4d %4d %4d\n",
03454                  WinAtt[w].w,WinAtt[w].h,WinAtt[w].x,WinAtt[w].y);
03455    }
03456    XGetGeometry(display,Cow,&Rootwin,&xp,&yp,&W,&H,&border,&depth);
03457    XTranslateCoordinates(display,Cow,Rootwin,0,0,&X,&Y,&Child);
03458    fprintf(scp,"\n[Control Window]\n");
03459    fprintf(scp,"Geometry: %4d %4d %4d %4d\n",W,H,X-WinLM,Y-WinTM);
03460 
03461    /* Scalar attributes for timeseries and tables */
03462 
03463    fprintf(scp,"\n# Scalar attributes for timeseries and table window\n");
03464 
03465    for (i=0 ; i < Parcs ; ++i)
03466    {
03467       fprintf(scp,"\n[Scalar %02d]\n",i);
03468       fprintf(scp,"Name:%s\n",TSName[i]);
03469       fprintf(scp,"Sub:%s\n",TSubsc[i]);
03470       fprintf(scp,"Unit:%s\n",TSUnit[i]);
03471       fprintf(scp,"Scale:%s\n",TScale[i]);
03472    }
03473 
03474    /* Scalar attributes for timeseries and tables */
03475 
03476     fprintf(scp,"\n# Parameter attributes for change menu\n");
03477 
03478    for (i=0 ; i < NUMSCALARS ; ++i)
03479    {
03480       if (strlen(Parc[i].Name) == 0) break;
03481       fprintf(scp,"\n[Parameter %02d]\n",i);
03482       fprintf(scp,"ParName:%s\n",Parc[i].Name);
03483       fprintf(scp,"ParInc:%10.4f\n",Parc[i].Inc);
03484       fprintf(scp,"ParMin:%10.4f\n",Parc[i].Min);
03485       fprintf(scp,"ParMax:%10.4f\n",Parc[i].Max);
03486    }
03487 
03488    fclose(scp);
03489 }
03490 
03491 
03492 void lp2ps(REAL *a, REAL *b)
03493 {
03494    int i,j,k,l,k1,l1;
03495    REAL xnp,ynp,xsp,ysp,dx,dy,x,y,lfa,ua,ub;
03496 
03497    lfa = (DimX-1) / (2.0 * M_PI);
03498    xnp = (DimX-1) * 0.25;
03499    ynp = (DimY-1) * 0.50;
03500    xsp = (DimX-1) * 0.75;
03501    ysp = ynp;
03502 
03503    /* Northern hemisphere */
03504 
03505    for (j = 0 ; j <  DimY   ; ++j)
03506    for (i = 0 ; i <= DimX/2 ; ++i)
03507    {
03508       dx = xnp - i;
03509       dy = ynp - j;
03510       x = atan2(dx,dy) * lfa;
03511       y = sqrt(dx * dx + dy * dy);
03512       if (x < 0.0) x += (DimX-1);
03513       k = x;
03514       l = y;
03515       k1 = k + 1;
03516       if (k1 >= DimX) k1 = 0;
03517       if (l <= DimY/2+1)
03518       {
03519          ua = (k+1-x) *  a[k+l*DimX] + (x-k) * a[k1+l*DimX];
03520          ub = (k+1-x) * a[k+(l+1)*DimX] + (x-k) * a[k+1+(l+1)*DimX];
03521          b[i+j*DimX] = (l+1-y) * ua + (y-l) * ub;
03522       }
03523       else b[i+j*DimX] = - 99999.0;
03524    }
03525 
03526    /* Souhern hemisphere */
03527 
03528    for (j = 0        ; j < DimY ; ++j)
03529    for (i = DimX/2+1 ; i < DimX ; ++i)
03530    {
03531       dx = i - xsp;
03532       dy = ysp - j;
03533       x = atan2(dx,dy) * lfa;
03534       y = (DimY-1) - sqrt(dx * dx + dy * dy);
03535       if (x < 0.0) x += (DimX-1);
03536       k = x;
03537       l = y;
03538       k1 = k + 1;
03539       if (k1 >= DimX) k1 = 0;
03540       if (l >= DimY/2-3)
03541       {
03542          ua = (k+1-x) *  a[k+l*DimX] + (x-k) * a[k1+l*DimX];
03543          ub = (k+1-x) * a[k+(l+1)*DimX] + (x-k) * a[k+1+(l+1)*DimX];
03544          b[i+j*DimX] = (l+1-y) * ua + (y-l) * ub;
03545       }
03546       else b[i+j*DimX] = - 99999.0;
03547    }
03548 }
03549 
03550 
03551 /* ======================================================= */
03552 /* lp2az - transform lon/lat array to azimuthal projection */
03553 /* ======================================================= */
03554 
03555 void lp2az(REAL *a, REAL *b, float laz)
03556 {
03557    int x,y,dxc,k,k1,l;
03558    REAL dx,dy,lam,rho,rad,phi,ua,ub,l00,p00,xpi,ypi;
03559 
03560    rad = DimY >> 1;
03561    dxc = DimX >> 1;
03562    xpi = DimX / M_PI * 0.5;
03563    ypi = DimY / M_PI;
03564    l00 =  (int)((laz * DimX) / 360 + dxc) % DimX;
03565    p00 = DimY / 2;
03566 
03567    for (y = 0 ; y < DimY ; ++y)
03568    {
03569       dy  = y - rad;
03570       phi = y;
03571       for (x = 0 ; x < DimX ; ++x)
03572       {
03573          dx = x - dxc;
03574          rho = sqrt(dx * dx + dy * dy);
03575          if (rho < rad)
03576          {
03577             lam = l00 + xpi * atan2(dx / rad, cos(asin(rho / rad)));
03578             phi = p00 + ypi *  asin(dy / rad);
03579             k = lam;
03580             k1 = k + 1;
03581             if (k1 >= DimX) k1 = 0;
03582             l = phi;
03583             ua = (k+1-lam) * a[k+ l   *DimX] + (lam-k) * a[k1 + l   *DimX];
03584             ub = (k+1-lam) * a[k+(l+1)*DimX] + (lam-k) * a[k+1+(l+1)*DimX];
03585             b[x+y*DimX] = (l+1-y) * ua + (y-l) * ub;
03586          }
03587          else b[x+y*DimX] = - 99999.0;
03588       }
03589    }
03590 }
03591 
03592 void ShowGridCS(void)
03593 {
03594    int jlev,jlat,x,y,len;
03595    float dx,dy;
03596    char Text[80];
03597 
03598    /* Grid for zonal mean cross sections */
03599 
03600    XSetForeground(display,gc,WhitePix);
03601    XSetBackground(display,gc,BlackPix);
03602    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03603    dy = (InYSize - OffY) / (DimY - 1.0);
03604    for (jlev = 1 ; jlev < DimY-1 ; ++jlev)
03605    {
03606       y = OffY + jlev * dy;
03607       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03608    }
03609    dx = (InXSize - OffX) / 6.0; /* Every 30 degrees */
03610    for (jlat = 1 ; jlat < 6 ; ++jlat)
03611    {
03612       x = OffX + jlat * dx;
03613       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03614    }
03615    if (GridLabel)
03616    {
03617       XDrawImageString(display,pix,gc,InXSize/2-FixFontWidth,InYSize-FixFont->descent,"EQ",2);
03618       XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"N",1);
03619       XDrawImageString(display,pix,gc,InXSize-FixFontWidth,InYSize-FixFont->descent,"S",1);
03620    }
03621    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03622 }
03623 
03624 void ShowGridCol(void)
03625 {
03626    int jlev,jtim,x,y,len;
03627    float dx,dy;
03628    char Text[80];
03629 
03630    /* Grid for column time series */
03631 
03632    XSetForeground(display,gc,WhitePix);
03633    XSetBackground(display,gc,BlackPix);
03634    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03635    dy = (InYSize - OffY) / (DimY - 1.0);
03636    for (jlev = 1 ; jlev < DimY-1 ; ++jlev)
03637    {
03638       y = OffY + jlev * dy;
03639       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03640    }
03641    dx = (InXSize - OffX) / 4.0; /* 4 slices */
03642    for (jtim = 1 ; jtim < 4 ; ++jtim)
03643    {
03644       x = OffX + jtim * dx;
03645       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03646    }
03647    if (GridLabel)
03648    {
03649       XDrawImageString(display,pix,gc,InXSize/2-3*FixFontWidth/2,InYSize-FixFont->descent,"t-2",3);
03650       XDrawImageString(display,pix,gc,InXSize/4-3*FixFontWidth/2,InYSize-FixFont->descent,"t-3",3);
03651       XDrawImageString(display,pix,gc,3*InXSize/4-3*FixFontWidth/2,InYSize-FixFont->descent,"t-1",3);
03652    }
03653    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03654 }
03655 
03656 void ShowGridLonsi(void)
03657 {
03658    int jlev,jlat,x,y,len;
03659    float dx,dy;
03660    char Text[80];
03661 
03662    /* Grid for Longitude Sigma section */
03663 
03664    XSetForeground(display,gc,WhitePix);
03665    XSetBackground(display,gc,BlackPix);
03666    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03667    dy = (InYSize - OffY) / (DimY - 1.0);
03668    for (jlev = 1 ; jlev < DimY-1 ; ++jlev)
03669    {
03670       y = OffY + jlev * dy;
03671       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03672    }
03673    dx = (InXSize - OffX) / 6.0; /* Every 60 degrees */
03674    for (jlat = 1 ; jlat < 6 ; ++jlat)
03675    {
03676       x = OffX + jlat * dx;
03677       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03678    }
03679    if (GridLabel)
03680    {
03681       XDrawImageString(display,pix,gc,InXSize/2-3*FixFontWidth/2,InYSize-FixFont->descent,"180",3);
03682       XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"0",1);
03683       XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"360",3);
03684    }
03685    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03686 }
03687 
03688 void ShowGridCyl(void)
03689 {
03690    int jlon,jlat,x,y;
03691    float dx,dy;
03692 
03693    /* Grid for cylinder projection */
03694 
03695    XSetForeground(display,gc,WhitePix);
03696    XSetBackground(display,gc,BlackPix);
03697    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03698    dy = (InYSize - OffY) / 6.0;
03699    for (jlat = 1 ; jlat < 6 ; ++jlat)
03700    {
03701       y = OffY + jlat * dy;
03702       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03703    }
03704    dx = (InXSize - OffX) / 6.0; /* Every 30 degrees */
03705    for (jlon = 1 ; jlon < 6 ; ++jlon)
03706    {
03707       x = OffX + jlon * dx;
03708       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03709    }
03710    if (GridLabel)
03711    {
03712       XDrawImageString(display,pix,gc,OffX,OffY+(InYSize-OffY)/2+FixFontHeight/2-FixFont->descent,"EQ",2);
03713       XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"N",1);
03714       XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"-180",4);
03715       XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"180",3);
03716       XDrawImageString(display,pix,gc,OffX+(InXSize-OffX)/2-3*FixFontWidth/2,InYSize-FixFont->descent,"0",1);
03717    }
03718    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03719 }
03720 
03721 void ShowGridHov(void)
03722 {
03723    int jlon,jlat,x,y,len;
03724    float dx,dy;
03725    char Text[80];
03726 
03727    /* Grid for Hovmoeller */
03728 
03729    XSetForeground(display,gc,WhitePix);
03730    XSetBackground(display,gc,BlackPix);
03731    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03732    dx = (InXSize - OffX) / 6.0;
03733    for (jlon = 1 ; jlon < 6 ; ++jlon)
03734    {
03735       x = OffX + jlon * dx;
03736       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03737    }
03738    dy = (InYSize - OffY) / 5.0; /* Every 5 days */
03739    for (jlat = 1 ; jlat < 5 ; ++jlat)
03740    {
03741       y = OffY + jlat * dy;
03742       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03743    }
03744    if (GridLabel)
03745    {
03746       XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"0",1);
03747       XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"360",3);
03748       XDrawImageString(display,pix,gc,OffX+(InXSize-OffX)/2-3*FixFontWidth/2,InYSize-FixFont->descent,"180",3);
03749       XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"t0",2);
03750       XDrawImageString(display,pix,gc,OffX,OffY+2*InYSize/5+FixFontHeight/2-FixFont->descent,"t-2",3);
03751       XDrawImageString(display,pix,gc,OffX,OffY+4*InYSize/5+FixFontHeight/2-FixFont->descent,"t-4",3);
03752    }
03753    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03754 }
03755 
03756 void ShowGridHovT(void)
03757 {
03758    int jlon,jlat,x,y,len;
03759    float dx,dy;
03760    char Text[80];
03761 
03762    /* Grid for Hovmoeller */
03763 
03764    XSetForeground(display,gc,WhitePix);
03765    XSetBackground(display,gc,BlackPix);
03766    XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03767    dy = (InYSize - OffY) / 6.0;
03768    for (jlat = 1 ; jlat < 6 ; ++jlat)
03769    {
03770       y = OffY + jlat * dy;
03771       XDrawLine(display,pix,gc,OffX,y,InXSize-1,y);
03772    }
03773    dx = (InXSize - OffX) / 5.0; /* Every 5 days */
03774    for (jlat = 1 ; jlat < 5 ; ++jlat)
03775    {
03776       x = OffX + jlat * dx;
03777       XDrawLine(display,pix,gc,x,OffY,x,InYSize-1);
03778    }
03779    if (GridLabel)
03780    {
03781       XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"0",1);
03782       XDrawImageString(display,pix,gc,OffX,OffY+(InYSize-OffY)/2+FixFontHeight/2-FixFont->descent,"180",3);
03783       XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"360",3);
03784       XDrawImageString(display,pix,gc,InXSize-2*FixFontWidth,InYSize-FixFont->descent,"t0",2);
03785       XDrawImageString(display,pix,gc,3*InXSize/5-3*FixFontWidth/2,InYSize-FixFont->descent,"t-2",3);
03786       XDrawImageString(display,pix,gc,  InXSize/5-3*FixFontWidth/2,InYSize-FixFont->descent,"t-4",3);
03787    }
03788    XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03789 }
03790 
03791 void ShowGridPolar(void)
03792 {
03793    int dx,dy,x,y,xh,yh,ox,oy;
03794    XPoint pxy[3];
03795 
03796    /* Grid for polar projection */
03797 
03798    dx = (InXSize - OffX) / 2;
03799    dy = (InYSize - OffY);
03800    xh = dx / 2;
03801    yh = dy / 2;
03802    ox = dx / 3.414;
03803    oy = dy / 3.414;
03804 
03805    if (Grid)
03806    {
03807       XSetForeground(display,gc,WhitePix);
03808       XSetBackground(display,gc,BlackPix);
03809       XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound);
03810    
03811       /* Northern Hemisphere */
03812    
03813       XDrawArc(display,pix,gc,OffX+dx/6,OffY+dy/6,2*dx/3,2*dy/3,0,360*64);
03814       XDrawArc(display,pix,gc,OffX+dx/3,OffY+dy/3,dx/3,dy/3,0,360*64);
03815    
03816       XDrawLine(display,pix,gc,OffX,yh,InXSize,yh);
03817       XDrawLine(display,pix,gc,OffX+xh,OffY,OffX+xh,InYSize);
03818    
03819       /* Southern Hemisphere */
03820    
03821       XDrawArc(display,pix,gc,OffX+7*dx/6,OffY+dy/6,2*dx/3,2*dy/3,0,360*64);
03822       XDrawArc(display,pix,gc,OffX+4*dx/3,OffY+dy/3,dx/3,dy/3,0,360*64);
03823    
03824       x = OffX + dx + xh;
03825       XDrawLine(display,pix,gc,x,OffY,x,InYSize);
03826    
03827       if (GridLabel)
03828       {
03829          x  = OffX + xh - FixFontWidth/2;
03830          y  = OffY + yh + FixFontHeight/2 - FixFont->descent;
03831          XDrawImageString(display,pix,gc,x,y,"N",1);
03832          XDrawImageString(display,pix,gc,x+dx,y,"S",1);
03833       }
03834       XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound);
03835    }
03836 
03837    /* Octagon mask */
03838 
03839    XSetForeground(display,gc,BlackPix);
03840    pxy[0].x = pxy[1].x = OffX;
03841    pxy[0].y = pxy[2].y = OffY;
03842    pxy[1].y = OffY + oy;
03843    pxy[2].x = OffX + ox;
03844    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03845    pxy[0].x = OffX + dx - ox;
03846    pxy[1].x = OffX + dx;
03847    pxy[2].x = OffX + dx + ox;
03848    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03849    pxy[0].x = InXSize - ox;
03850    pxy[1].x = InXSize;
03851    pxy[2].x = InXSize;
03852    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03853 
03854    pxy[0].x = pxy[1].x = OffX;
03855    pxy[0].y = pxy[2].y = InYSize;
03856    pxy[1].y = InYSize - oy;
03857    pxy[2].x = OffX + ox;
03858    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03859    pxy[0].x = OffX + dx - ox;
03860    pxy[1].x = OffX + dx;
03861    pxy[2].x = OffX + dx + ox;
03862    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03863    pxy[0].x = InXSize - ox;
03864    pxy[1].x = InXSize;
03865    pxy[2].x = InXSize;
03866    XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin);
03867 }
03868 
03869 
03870 void AutoPalette(int w, struct ColorStrip Strip[], REAL f[], int Dim)
03871 {
03872    int i,nbands;
03873    double fmin, fmax, frange, delta, fdelta, xdelta, Lo;
03874 
03875    fmin = fmax = f[0];
03876    for (i=0; i < Dim ; ++i)
03877    {
03878       if (fmin > f[i]) fmin = f[i];
03879       if (fmax < f[i]) fmax = f[i];
03880    }
03881    frange = fmax - fmin;
03882    Lo     = 0.0;
03883    xdelta = 0.1;
03884    if (frange > 1.0e-10)
03885    {
03886        delta  = frange / AUTOCOLORS;
03887        if (delta > AutoDelta[w] / 1.4 && delta < 1.4 * AutoDelta[w])
03888        {
03889           xdelta = AutoXdelt[w];
03890           delta  = AutoDelta[w];
03891           Lo     = AutoLo[w];
03892        }
03893        else
03894        {
03895           fdelta = pow(10.0,rint(log10(delta)));
03896           xdelta = fdelta;
03897           nbands = frange / xdelta;
03898           if (nbands < AUTOCOLORS / 2) xdelta = 0.5 * fdelta;
03899           if (nbands > AUTOCOLORS    ) xdelta = 2.0 * fdelta;
03900           nbands = frange / xdelta;
03901           if (nbands > AUTOCOLORS    ) xdelta = 5.0 * fdelta;
03902           Lo = xdelta * floor(fmin / xdelta);
03903           AutoDelta[w] = delta;
03904           AutoXdelt[w] = xdelta;
03905           AutoLo[w]    = Lo;
03906 /*
03907           if (Debug)
03908           {
03909              printf("Autopalette\n");
03910              printf(" Range: %14.6e\n",frange);
03911              printf(" delta: %14.6e\n",delta);
03912              printf("fdelta: %14.6e\n",fdelta);
03913              printf("xdelta: %14.6e\n",xdelta);
03914           }
03915 */
03916        }
03917    }
03918    Strip[0].Lo = Lo;
03919    for (i=0 ; i < AUTOCOLORS ; ++i)
03920    {
03921        Strip[i+1].Lo = Strip[i].Hi = Strip[i].Lo + xdelta;
03922        // if (Debug) printf("Auto[%2d] = %10.4f - %10.4f\n",i,Strip[i].Lo,Strip[i].Hi);
03923    }
03924    return;
03925 }
03926 
03927 
03928 // Interface routine to model code in FORTRAN
03929 
03930 void guiput_(char *aname, float *array, int *dimx, int *dimy, int *dimz)
03931 {
03932    int i,nb,nf;
03933 
03934    if (Debug) printf("guiput(%s,%12.4e,%d,%d,%d)\n",
03935                      aname,*array,*dimx,*dimy,*dimz);
03936    nf = (*dimx) * (*dimz);
03937    if (*dimy > 0) nf *= (*dimy);
03938    else           nf *= 2;
03939    nb = nf * sizeof(float);
03940    for (i=0 ; i < NumArrays ; ++i)
03941       if (!strcmp(aname,Array[i].Name)) break;
03942    if (i == NumArrays)
03943    {
03944       ++NumArrays;
03945       strcpy(Array[i].Name,aname);
03946       Array[i].Data = FloatAlloc(nf,aname);
03947       Array[i].DimX = *dimx;
03948       Array[i].DimY = *dimy;
03949       Array[i].DimZ = *dimz;
03950       if (strcmp(aname,"GU") == 0) Uindex = i;
03951       if (strcmp(aname,"GV") == 0) Vindex = i;
03952    }
03953    if (Array[i].Data) memcpy(Array[i].Data,array,nb);
03954    Array[i].Flag = 1; // Data have changed
03955 }
03956 
03957 
03958 void guisend_(char *aname, float *array, int *dimx, int *dimy, int *dimz)
03959 {
03960    int i,nb,nf;
03961 
03962    nf = (*dimx) * (*dimz);
03963    if (*dimy > 0) nf *= (*dimy);
03964    else           nf *= 2;
03965    nb = nf * sizeof(float);
03966    for (i=0 ; i < NumArrays ; ++i)
03967       if (!strcmp(aname,Array[i].Name)) break;
03968    if (i == NumArrays)
03969    {
03970       ++NumArrays;
03971       strcpy(Array[i].Name,aname);
03972       Array[i].DimX = *dimx;
03973       Array[i].DimY = *dimy;
03974       Array[i].DimZ = *dimz;
03975    }
03976    Array[i].Data = array;
03977    Array[i].Flag = 1; // Data have changed
03978 }
03979 
03980 
03981 // Do the plot
03982 
03983 void iso(int w,int PicType,REAL *field,int dimx,int dimy,int dimz,int pal)
03984 {
03985    char Text[128];
03986 
03987    int i,j,k,len,lens,xp,yp,status,x;
03988    int y,dx,r,width,height;
03989    INTXU border,depth;
03990    REAL f,o,ra,rb;
03991    int CapLines;
03992    float *tspt;
03993    XEvent WinEvent;
03994    Window Rootwin,Child;
03995 
03996    // if (Debug) printf("iso(%d,%s,%12.4e,%d,%d,%d,%d)\n",w,IsoNames[PicType],*field,dimx,dimy,dimz,pal);
03997    if (Win[w] == 0) return;
03998    win = w;
03999    if (SkipFreq > 1 && (nstep % SkipFreq) != 0 && 
04000       (PicType == ISOCS || PicType == ISOHOR || PicType == MAPHOR || PicType == ISOCOL)) return;
04001    XGetGeometry(display,Win[w],&Rootwin,&xp,&yp,&WinXSize,&WinYSize,
04002                 &border,&depth);
04003    WinAtt[w].w = WinXSize;
04004    WinAtt[w].h = WinYSize;
04005    InXSize = WinXSize - OffX;
04006    InYSize = WinYSize - OffY;
04007    if (PicType != ISOTRA && PicType != MAPTRA) InYSize -= 20; // Room for colorbar
04008    DimX  = dimx;
04009    DimY  = dimy;
04010    DimZ  = dimz;
04011    if (DimY < 0) DimY = -DimY; // Get NTP1 for ISOSH
04012    DimXY = DimX * DimY;
04013    VGAX  = (InXSize-1.0) / (DimX-1.0);
04014    if (DimY > 1) VGAY  = (InYSize-1.0) / (DimY-1.0);
04015    else          VGAY  = 1.0;
04016    Field = field;
04017 
04018    if (PicType == ISOTRA || PicType == MAPTRA)
04019    {
04020       DimX  = dimx; // NLON
04021       DimY  = dimy; // NLAT
04022       DimZ  = dimz; // NLEV
04023       DimXY = DimX * DimY;
04024       VGAX  = (InXSize-1.0) / (DimX-1.0);
04025       VGAY  = (InYSize-1.0) / (DimY-1.0);
04026       if (MaxZ[w] < DimZ)
04027       {
04028          MaxZ[w]   = DimZ;
04029          Indez[w]  = DimZ / 4;
04030          SwitchIndez(w,0); // Initialize title
04031       }
04032    }
04033 
04034    if (PicType == ISOHOR || PicType == MAPHOR)
04035    {
04036       DimX  = dimx; // NLON
04037       DimY  = dimy; // NLAT
04038       DimZ  = dimz; // NLEV
04039       DimXY = DimX * DimY;
04040       VGAX  = (InXSize-1.0) / (DimX-1.0);
04041       VGAY  = (InYSize-1.0) / (DimY-1.0);
04042       if (MaxZ[w] < DimZ)
04043       {
04044          MaxZ[w]   = DimZ;
04045          Indez[w]  = DimZ / 4;
04046          SwitchIndez(w,0); // Initialize title
04047          TSdata[w] = FloatAlloc(DimXY,"ISOLON");
04048       }
04049       if (MapPro[w] == POLAR)
04050       {
04051          Field = TSdata[w];
04052          lp2ps(field + Indez[w] * DimXY,Field);
04053       }
04054 /*
04055       else if (MapPro[w] == AZIMUTHAL)
04056       {
04057          Field = TSdata[w];
04058          lp2az(field + Indez[w] * DimXY,Field,MapLR[w].l);
04059       }
04060 */
04061       else Field = field + Indez[w] * DimXY;
04062    }
04063 
04064    if (PicType == ISOLON)
04065    {
04066       DimX  = dimx; // NLON
04067       DimY  = dimz; // NLEV
04068       DimZ  = dimy; // NLAT
04069       DimXY = DimX * DimY;
04070       VGAX  = (InXSize-1.0) / (DimX-1.0);
04071       VGAY  = (InYSize-1.0) / (DimY-1.0);
04072       if (!TSdata[w])
04073       {
04074          TSdata[w] = FloatAlloc(DimXY,"ISOLON");
04075          MaxZ[w]   = DimZ;
04076          Indez[w]  = DimZ / 4;
04077          SwitchIndez(w,0); // Initialize title
04078       }
04079       Field = TSdata[w];
04080       for (j=0,i=0,k=DimX*Indez[w] ; j < DimY ; ++j,i+=DimX,k+=DimX*DimZ)
04081       {
04082          memcpy(Field+i,field+k,DimX * sizeof(REAL)); // copy latitude
04083       }
04084    }
04085 
04086    if (PicType == ISOHOV)
04087    {
04088       DimX  = dimx; // NLON
04089       DimY  = DimT; // time
04090       DimZ  = dimy; // NLAT
04091       DimXY = DimX * DimY;
04092       VGAX  = (InXSize-1.0) / (DimX-1.0);
04093       VGAY  = (InYSize-1.0) / (DimY-1.0);
04094       if (!TSdata[w])
04095       {
04096          TSdata[w] = FloatAlloc(DimXY,"ISOHOV");
04097          MaxZ[w]   = DimZ;
04098          Indez[w]  = DimZ / 4;
04099          SwitchIndez(w,0); // Initialize title
04100       }
04101       Field = TSdata[w];
04102       memmove(Field+DimX,Field,(DimXY-DimX) * sizeof(REAL)); // scroll array
04103       memcpy(Field,field+Indez[w]*DimX,DimX * sizeof(REAL)); // add line
04104    }
04105 
04106    // Advance write pointer HovInx until end of DimX
04107    // then scroll array and reset pointer
04108 
04109    if (PicType == ISOTS)
04110    {
04111       DimX  = DimT; // time
04112       DimY  = dimx; // # of variables
04113       DimZ  = dimz;
04114       DimXY = DimX * DimY;
04115       VGAX  = (InXSize-1.0) / (DimX-1.0);
04116       VGAY  = (InYSize-1.0) / (DimY-1.0);
04117       if (!TSdata[w])
04118       {
04119          TSdata[w] = FloatAlloc(DimXY+DimX,"ISOTS");
04120       }
04121       tspt  = TSdata[w];
04122       ++HovInx[w];
04123       if (HovInx[w] >= DimX)
04124       {
04125           HovInx[w] = 0;
04126           memmove(tspt,tspt+DimX,DimXY * sizeof(REAL)); // scroll array
04127       }
04128       for (i=HovInx[w]+DimX-1,j=0 ; j < DimY ; i+=DimX,++j)
04129          tspt[i] = field[j];                                  // add column
04130       Field = tspt+HovInx[w];
04131    }
04132 
04133    if (PicType == ISOCOL)
04134    {
04135       DimX  = DimT; // time
04136       DimY  = dimx; // level
04137       DimZ  = dimy; // clickable index
04138       DimXY = DimX * DimY;
04139       VGAX  = (InXSize-1.0) / (DimX-1.0);
04140       VGAY  = (InYSize-1.0) / (DimY-1.0);
04141       if (!TSdata[w])
04142       {
04143          TSdata[w] = FloatAlloc(DimXY+DimX,"ISOCOL");
04144          MaxZ[w]   = DimZ;
04145          Indez[w]  = DimZ / 2;
04146          SwitchIndez(w,0); // Initialize title
04147       }
04148       tspt  = TSdata[w];
04149       ++HovInx[w];
04150       if (HovInx[w] >= DimX)
04151       {
04152           HovInx[w] = 0;
04153           memmove(tspt,tspt+DimX,DimXY * sizeof(REAL)); // scroll array
04154       }
04155       for (i=HovInx[w]+DimX-1,j=0 ; j < DimY ; i+=DimX,++j)
04156          tspt[i] = field[j+Indez[w]*DimY];                                  // add column
04157       Field = tspt+HovInx[w];
04158    }
04159 
04160    if (DimX > FlagSize)
04161    {
04162       if (Flag) free(Flag);
04163       Flag = IntAlloc(DimX,"Flag");
04164       FlagSize = DimX;
04165    }
04166 
04167    if (PicType == ISOSH) pal = 1; // ISOSH has its own palette
04168    if (pal < 1 || pal >= NUMPAL)
04169    {
04170       Cstrip = Autostrip;
04171       AutoPalette(w,Cstrip,Field,DimXY);
04172       Lines  = AUTOCOLORS;
04173       // printf("Autopalette %d for Win %d\n",pal,w);
04174    }
04175    else
04176    {
04177       Cstrip = Pallet[pal];
04178       Lines  = LineCo[pal];
04179    }
04180 
04181    SizeChanged = (WinPixMap[w].DimX != WinXSize || WinPixMap[w].DimY != WinYSize);
04182    if (SizeChanged)
04183    {
04184       if (WinPixMap[w].Pix) XFreePixmap(display,WinPixMap[w].Pix);
04185       WinPixMap[w].Pix = XCreatePixmap(display,Win[w],WinXSize,WinYSize,ScreenD);
04186       if (Debug)
04187          printf("CreatePixmap  %10x %6d bytes\n",
04188                (unsigned int)WinPixMap[w].Pix,WinXSize*WinYSize);
04189       WinPixMap[w].DimX = WinXSize;
04190       WinPixMap[w].DimY = WinYSize;
04191    }
04192    pix = WinPixMap[w].Pix; /* Set current pixmap */
04193 
04194    /* Draw colour bar */
04195    
04196    if ((SizeChanged || Cstrip == Autostrip) &&
04197        (PicType == ISOCS  || PicType == ISOHOR ||
04198         PicType == ISOHOV || PicType == ISOLON ||
04199         PicType == ISOCOL || PicType == MAPHOR ))
04200    {
04201       XSetForeground(display,gc,BlackPix);
04202       XFillRectangle(display,pix,gc,0,InYSize,WinXSize,WinYSize);
04203 
04204       CapLines = WinXSize / (20 + 3 * FixFontWidth);
04205       if (CapLines > Lines) CapLines = Lines;
04206       for (i=0 ; i < CapLines ; ++i)
04207       {
04208          XSetForeground(display,gc,Cstrip[i].pixel);
04209          XFillRectangle(display,pix,gc,OffX+5+i*(WinXSize-20)/(CapLines-1),
04210                         OffY+InYSize+5,10,10);
04211          XSetForeground(display,gc,BlackPix);
04212          XDrawRectangle(display,pix,gc,OffX+5+i*(WinXSize-20)/(CapLines-1),
04213                         OffY+InYSize+5,10,10);
04214       }
04215       XSetForeground(display,gc,WhitePix);
04216       XSetBackground(display,gc,BlackPix);
04217       rb = Cstrip[CapLines-2].Hi - Cstrip[0].Hi;
04218       for (i=0 ; i < CapLines-1 ; ++i)
04219       {
04220          Text[0] = 0;
04221          ra = Cstrip[i].Hi;
04222          j = ra;
04223          if (j > -1000 && j < 10000) sprintf(Text,"%d",j);
04224          if (ra < 100.0 && ra > -9.99)
04225          {
04226             sprintf(Text,"%4.1f",ra);
04227             if (!strcmp(Text+2,".0")) Text[2] = 0;
04228          }
04229          if (ra < 10.0 && ra >= 0.0)
04230          {
04231             sprintf(Text,"%4.2f",ra);
04232             if (!strcmp(Text+1,".00")) Text[1] = 0;
04233          }
04234          len    = strlen(Text);
04235          if (len)
04236          {
04237             width  = XTextWidth(FixFont,Text,len);
04238             height = FixFont->ascent + FixFont->descent;
04239             xp     = OffX + 10 + (i+0.5) * (WinXSize-20)/(CapLines-1) - width/2;
04240             yp     = WinYSize - height + 10;
04241             XDrawImageString(display,pix,gc,xp,yp,Text,len);
04242          }
04243       }
04244    }
04245 
04246    /* Draw mode legend */
04247    
04248    if (SizeChanged && PicType == ISOSH)
04249    {
04250       dx = WinXSize / 23;
04251       XSetForeground(display,gc,BlackPix);
04252       XFillRectangle(display,pix,gc,0,0,WinXSize,WinYSize);
04253 
04254       XSetForeground(display,gc,LightGreen.pixel);
04255       XSetBackground(display,gc,BlackPix);
04256       for (i=0 ; i < 21 ; i+=2)
04257       {
04258          sprintf(Text,"%d",i);
04259          len    = strlen(Text);
04260          width  = XTextWidth(FixFont,Text,len);
04261          height = FixFont->ascent + FixFont->descent;
04262          xp     = dx + i * dx - width/2 - FixFontWidth/2 + 1;
04263          yp     = FixFontHeight;
04264          XDrawImageString(display,pix,gc,xp,yp,Text,len);
04265       }
04266       XSetForeground(display,gc,LightBlue.pixel);
04267       for (i=0 ; i < 21 ; i+=2)
04268       {
04269          sprintf(Text,"%d",i);
04270          len    = strlen(Text);
04271          width  = XTextWidth(FixFont,Text,len);
04272          height = FixFont->ascent + FixFont->descent;
04273          xp     = WinXSize - width - 2;
04274          yp     = 2 * FixFontHeight + i * dx;
04275          if (yp+FixFont->descent > InYSize) break;
04276          XDrawImageString(display,pix,gc,xp,yp,Text,len);
04277       }
04278       strcpy(Text,"n/m");
04279       len    = strlen(Text);
04280       width  = XTextWidth(FixFont,Text,len);
04281       xp     = WinXSize - width - 2;
04282       yp     = FixFontHeight;
04283       XSetForeground(display,gc,WhitePix);
04284       XDrawImageString(display,pix,gc,xp,yp,Text,len);
04285       strcpy(Text,"High ");
04286       len    = strlen(Text);
04287       width  = XTextWidth(FixFont,Text,len);
04288       xp     = WinXSize/2 - AMPLI_COLS * 10 - width;
04289       yp     = WinYSize - FixFontHeight + 10;
04290       r      = FixFontHeight-2;
04291       XSetForeground(display,gc,WhitePix);
04292       if (xp > 0) XDrawImageString(display,pix,gc,xp,yp,Text,len);
04293       strcpy(Text," Low");
04294       len    = strlen(Text);
04295       width  = XTextWidth(FixFont,Text,len);
04296       xp     = WinXSize/2 + AMPLI_COLS * 10;
04297       if (xp + width < WinXSize) XDrawImageString(display,pix,gc,xp,yp,Text,len);
04298       yp     = InYSize;
04299       XDrawLine(display,pix,gc,OffX,yp,WinXSize,yp);
04300       yp     = WinYSize - r -  FixFont->descent;
04301 
04302       for (i=0 ; i < AMPLI_COLS ; ++i)
04303       {
04304          xp = WinXSize/2 - AMPLI_COLS * 10 + i * 20;
04305          XSetForeground(display,gc,AmpliStrip[AMPLI_COLS-i-1].pixel);
04306          XFillArc(display,pix,gc,xp,yp,r,r,0,360*64);
04307       }
04308    }
04309 
04310    if (SizeChanged && PicType == ISOTS) /* Timeseries Caption */
04311    {
04312       XSetForeground(display,gc,BlackPix);
04313       XFillRectangle(display,pix,gc,0,InYSize,WinXSize,WinYSize);
04314       XSetBackground(display,gc,BlackPix);
04315 
04316       xp = FixFontWidth;
04317       yp = WinYSize - FixFontHeight + 10;
04318       for (j=0 ; j < DimY ; ++j)
04319       {
04320          if (TSName[j][0])
04321          {
04322             strcpy(Text,TSName[j]);
04323             len    = strlen(Text);
04324             width  = XTextWidth(FixFont,Text,len);
04325             XSetForeground(display,gc,TSColor[j]);
04326             XDrawImageString(display,pix,gc,xp,yp,Text,len);
04327             xp += width;
04328          }
04329          if (TSubsc[j][0])
04330          {
04331             XSetFont(display, gc, SubFont->fid);
04332             strcpy(Text,TSubsc[j]);
04333             len    = strlen(Text);
04334             width  = XTextWidth(SubFont,Text,len);
04335             XSetForeground(display,gc,TSColor[j]);
04336             XDrawImageString(display,pix,gc,xp,yp,Text,len);
04337             xp += width;
04338             XSetFont(display, gc, FixFont->fid);
04339          }
04340          xp += FixFontWidth;
04341       }
04342    }
04343 
04344    if (SizeChanged && PicType == ISOTAB) /* Table Caption */
04345    {
04346       XSetForeground(display,gc,BlackPix);
04347       XFillRectangle(display,pix,gc,0,0,WinXSize,WinYSize);
04348       XSetBackground(display,gc,BlackPix);
04349    }
04350 
04351    if (PicType == ISOTS) 
04352    {
04353       if (TSxp[w] == NULL) TSxp[w] = SizeAlloc(DimX * DimY , sizeof(XPoint),"TSxp");
04354       if (Dmin[w] == NULL) Dmin[w] = FloatAlloc(DimY ,"Dmin");
04355       if (Dmax[w] == NULL) Dmax[w] = FloatAlloc(DimY ,"Dmax");
04356       XSetForeground(display,gc,BlackPix);
04357       XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04358 
04359       for (j=0 ; j < DimY ; ++j) Dmin[w][j] = Dmax[w][j] = field[j];
04360       if (nstep > 2)
04361       {
04362          for (j=0 ; j < DimY ; ++j)
04363          {
04364             for (i=1 ; i < DimX ; ++i)
04365             {
04366                Dmin[w][j] = MIN(Dmin[w][j],Field[i+j*DimX]);
04367                Dmax[w][j] = MAX(Dmax[w][j],Field[i+j*DimX]);
04368             }
04369          }
04370       }
04371 
04372       if (nstep > 2)
04373       for (j=0 ; j < DimY ; ++j)
04374       {
04375          XSetForeground(display,gc,TSColor[j]);
04376          o = Dmin[w][j];
04377          if ((Dmax[w][j] - Dmin[w][j]) > 1.0e-20) f = (InYSize-2) / (Dmax[w][j] - Dmin[w][j]);
04378          else f = 1.0;
04379    
04380          for (i=1 ; i < DimX ; ++i)
04381          {
04382             TSxp[w][i].x = VGAX * i;
04383             TSxp[w][i].y = InYSize - 1 - f * (Field[i+j*DimX] - o);
04384          }
04385          XDrawLines(display,pix,gc,TSxp[w]+1,DimX-1,CoordModeOrigin);
04386       }
04387    }
04388 
04389    if (PicType == ISOTAB) 
04390    {
04391       XSetForeground(display,gc,BlackPix);
04392       XSetBackground(display,gc,BlackPix);
04393       XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04394       XSetFont(display, gc, BigFont->fid);
04395       yp = BigFontHeight;
04396       for (j=0 ; j < DimX ; ++j)
04397       if (TSName[j][0])
04398       {
04399          XSetForeground(display,gc,TSColor[j]);
04400          xp = BigFontWidth;
04401          strcpy(Text,TSName[j]);
04402          len = strlen(Text);
04403          XDrawImageString(display,pix,gc,xp,yp,Text,len);
04404          xp += XTextWidth(BigFont,Text,len);
04405          if (TSubsc[j][0])
04406          {
04407             XSetFont(display, gc, FixFont->fid);
04408             XDrawImageString(display,pix,gc,xp,yp,TSubsc[j],strlen(TSubsc[j]));
04409             XSetFont(display, gc, BigFont->fid);
04410          }
04411          xp = 8 * BigFontWidth;
04412          if (TSUnit[j][0])
04413          {
04414             sprintf(Text,"= %7.3f [%s]",field[j],TSUnit[j]);
04415             if (TScale[j][0]) strcat(Text," 10");
04416             len = strlen(Text);
04417             XDrawImageString(display,pix,gc,xp,yp,Text,len);
04418             if (TScale[j][0] > ' ')
04419             {
04420                lens = strlen(TScale[j]);
04421                XSetFont(display, gc, FixFont->fid);
04422                XDrawImageString(display,pix,gc,xp+len*BigFontWidth,yp-BigFontHeight+FixFontHeight,TScale[j],lens);
04423                XSetFont(display, gc, BigFont->fid);
04424             }
04425          }
04426          yp += BigFontHeight;
04427       }
04428       XSetFont(display, gc, FixFont->fid);
04429    }
04430 
04431    if (PicType == ISOTRA)
04432    {
04433       XSetForeground(display,gc,BlackPix);
04434       XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04435       if (SizeChanged) ClearTracer();
04436       TracerPlot(w);
04437    }
04438    if (PicType == MAPTRA)
04439    {
04440       if (SizeChanged) ClearTracer();
04441       if (MapHR.X)
04442       {
04443          if (MapPro[w] == AZIMUTHAL)
04444          {
04445             if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize ||
04446                (nstep % rmui == 0 && MapLR[w].f != 0))
04447             {
04448                RedrawFlag[w] = 0;
04449                MapLR[w].w    = WinXSize;
04450                MapLR[w].h    = InYSize;
04451                MapLR[w].l   += MapLR[w].r;
04452                if (MapLR[w].l < -180.0) MapLR[w].l += 360.0;
04453                if (MapLR[w].l >  180.0) MapLR[w].l -= 360.0;
04454                AzimuthalImage(&MapHR,&MapLR[w]);
04455             }
04456          }
04457          else
04458          {
04459             if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize)
04460             {
04461                RedrawFlag[w] = 0;
04462                MapLR[w].w  = WinXSize;
04463                MapLR[w].h  = InYSize;
04464                if (MapPro[w] == 1) PolarImage(&MapHR,&MapLR[w]);
04465                else                ScaleImage(&MapHR,&MapLR[w]);
04466             }
04467          }
04468          XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h);
04469       }
04470       else
04471       {
04472          XSetForeground(display,gc,BlackPix);
04473          XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04474       }
04475       TracerPlot(w);
04476    }
04477    if (PicType == ISOCS || PicType == ISOHOR || PicType == ISOLON || PicType == ISOCOL)
04478    {
04479       XSetForeground(display,gc,BlackPix);
04480       XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04481       IsoAreas(Cstrip);
04482       IsoLines(Cstrip,0);
04483    }
04484    if (PicType == MAPHOR)
04485    {
04486       if (MapHR.X)
04487       {
04488          if (MapPro[w] == AZIMUTHAL)
04489          {
04490             if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize ||
04491                (nstep % rmui == 0 && MapLR[w].f != 0))
04492             {
04493                RedrawFlag[w] = 0;
04494                MapLR[w].w    = WinXSize;
04495                MapLR[w].h    = InYSize;
04496                MapLR[w].l   += MapLR[w].r;
04497                if (MapLR[w].l < -180.0) MapLR[w].l += 360.0;
04498                if (MapLR[w].l >  180.0) MapLR[w].l -= 360.0;
04499                AzimuthalImage(&MapHR,&MapLR[w]);
04500             }
04501             XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h);
04502             MapLines(Cstrip,1);
04503          }
04504          else
04505          {
04506             if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize)
04507             {
04508                RedrawFlag[w] = 0;
04509                MapLR[w].w  = WinXSize;
04510                MapLR[w].h  = InYSize;
04511                if (MapPro[w] == 1) PolarImage(&MapHR,&MapLR[w]);
04512                else                ScaleImage(&MapHR,&MapLR[w]);
04513             }
04514             XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h);
04515             IsoLines(Cstrip,1);
04516          }
04517       }
04518       else
04519       {
04520          XSetForeground(display,gc,BlackPix);
04521          XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize);
04522          IsoLines(Cstrip,1);
04523       }
04524    }
04525    if (PicType == ISOHOV)
04526    {
04527       IsoAreas(Cstrip);
04528    }
04529    
04530    if (PicType == ISOSH)
04531    {
04532       AmplitudePlot();     
04533    }
04534 
04535    if (Grid && PicType == ISOCS) ShowGridCS();
04536    if (Grid && PicType == ISOLON) ShowGridLonsi();
04537    if (Grid && PicType == ISOHOV && MapPro[w] == 0) ShowGridHov();
04538    if (Grid && PicType == ISOHOV && MapPro[w] == 1) ShowGridHovT();
04539    if (PicType == ISOHOR &&  MapPro[w] == 1) ShowGridPolar();
04540    if (Grid && PicType == ISOHOR && MapPro[w] == 0) ShowGridCyl();
04541    if (Grid && PicType == ISOCOL) ShowGridCol();
04542 
04543    XCopyArea(display,pix,Win[w],gc,0,0,WinXSize,WinYSize,0,0);
04544 }
04545 
04546 
04547 /* ==================================================================== */
04548 /* iguistep - this function is called from the model for every timestep */
04549 /* ==================================================================== */
04550 
04551 int iguistep_(float pparcs[],int kdatim[])
04552 {
04553    int i,j,w;               // Loop indices
04554    struct timeval TimeVal;  // Retrieve time info
04555 
04556    if (Debug) printf("iguistep(%12.2e,%d-%d-%d)\n",
04557                      pparcs[0],kdatim[0],kdatim[1],kdatim[2]);
04558    nstep++;
04559    memcpy(ndatim,kdatim,sizeof(ndatim));
04560    DeltaTime = ndatim[4] - LastMinute;
04561    if (DeltaTime < 0) DeltaTime += 60;
04562    if (DeltaTime ==0) DeltaTime  = 60;
04563    LastMinute = ndatim[4];
04564 
04565    // Compute frames per second every 20 calls
04566 
04567    gettimeofday(&TimeVal,NULL);
04568    LastSecond = ThisSecond;
04569    ThisSecond = TimeVal.tv_sec;
04570 
04571    if (SecEvent = ThisSecond > LastSecond)
04572    {
04573       fps      = nstep - LastStep;
04574       LastStep = nstep;
04575       rmui     = fps / rmuf;
04576       if (rmui < 1) rmui = 1;
04577    }
04578 
04579    SkipFreq = 1 + fps / 30; // Reduce plot rate on fast cpu's
04580    if (SkipFreq < 0 || SkipFreq > 10) SkipFreq = 0;
04581 
04582    for (w=0 ; w < NumWin ; ++w)
04583    {
04584       for (j=0 ; j < NumArrays ; ++j)
04585       {
04586          if (!strcmp(WinAtt[w].array_name,Array[j].Name))
04587          {
04588             if (Array[j].Flag || RedrawFlag[w])
04589             iso(w,WinAtt[w].Plot,Array[j].Data,Array[j].DimX,Array[j].DimY,
04590                                  Array[j].DimZ,WinAtt[w].Palette);
04591          }
04592       }
04593    }
04594 
04595    for (i=0 ; i < Parcs ; ++i) Parc[i].Val = pparcs[i];
04596    ShowStep();
04597    ShowParcs();
04598    HandleEvents();
04599    if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent))
04600       RedrawControlWindow();
04601    for (i=0 ; i < Parcs ; ++i) pparcs[i] = Parc[i].Val;
04602 
04603    XSync(display,1);
04604    if (Shutdown && MRpid < 1) SaveConfig();
04605    if (Debug) printf("iguistep returns %d\n",Shutdown);
04606    return Shutdown;
04607 }
04608 
04609 int nresources_(double *ut, double *st, long *mem, long *par, long *paf,
04610                long *swa, long *dr, long *dw)
04611 {
04612    struct rusage ru;
04613    getrusage(RUSAGE_SELF,&ru);
04614    *ut = ru.ru_utime.tv_sec + 0.000001 * ru.ru_utime.tv_usec;
04615    *st = ru.ru_stime.tv_sec + 0.000001 * ru.ru_stime.tv_usec;
04616    *mem = ru.ru_maxrss;
04617    *par = ru.ru_minflt;
04618    *paf = ru.ru_majflt;
04619    *swa = ru.ru_nswap;
04620    *dr  = ru.ru_inblock;
04621    *dw  = ru.ru_oublock;
04622    return 1;
04623 }
04624 
04625 /* ------------------------------------------------ */
04626 /* Stub routines for Absoft Compiler and others,    */
04627 /* which require, that FORTRAN callable C-functions */
04628 /* are written in uppercase letters only            */
04629 /* ------------------------------------------------ */
04630 
04631 
04632 void INITGUI(int *model, int *debug, int *lats, int *mrpid, int *mrnum)
04633 {
04634    initgui_(model,debug,lats,mrpid,mrnum);
04635 }
04636 
04637 void GUICLOSE(void)
04638 {
04639    guiclose_();
04640 }
04641 
04642 int IGUISTEP(float pparcs[], int kdatim[])
04643 {
04644    return iguistep_(pparcs,kdatim);
04645 }
04646 
04647 void GUIPUT(char *aname, float *array, int *dimx, int *dimy, int *dimz)
04648 {
04649    guiput_(aname, array, dimx, dimy, dimz);
04650 }
04651 
04652 int NRESOURCES(double *ut, double *st, long *mem, long *par, long *paf,
04653                long *swa, long *dr, long *dw)
04654 {
04655    return nresources_(ut,st,mem,par,paf,swa,dr,dw);
04656 }
04657 
04658 /* ------------------------------------------------ */
04659 /* Stub routines for IBM Compiler and others,       */
04660 /* which require, that FORTRAN callable C-functions */
04661 /* are written in lowercase without underscore      */
04662 /* ------------------------------------------------ */
04663 
04664 
04665 void initgui(int *model, int *debug, int *lats, int *mrpid, int *mrnum)
04666 {
04667    initgui_(model,debug,lats,mrpid,mrnum);
04668 }
04669 
04670 void guiclose(void)
04671 {
04672    guiclose_();
04673 }
04674 
04675 int iguistep(float pparcs[], int kdatim[])
04676 {
04677    return iguistep_(pparcs,kdatim);
04678 }
04679 
04680 void guiput(char *aname, float *array, int *dimx, int *dimy, int *dimz)
04681 {
04682    guiput_(aname, array, dimx, dimy, dimz);
04683 }
04684 
04685 int iguinan_(double *p)
04686 {
04687    return isnan(*p);
04688 }
04689 
04690 int nresources(double *ut, double *st, long *mem, long *par, long *paf,
04691               long *swa, long *dr, long *dw)
04692 {
04693    return nresources_(ut,st,mem,par,paf,swa,dr,dw);
04694 }