diff --git a/cat/src/cat.f90 b/cat/src/cat.f90 index 39f92071ef9879825583701824e7ceeecbec9dc7..12cc51730d3778afed510e2b5376779eb974b273 100644 --- a/cat/src/cat.f90 +++ b/cat/src/cat.f90 @@ -667,7 +667,8 @@ namelist /cat_nl/ nsteps ,ngp ,ngui ,ingp ,insp , & nforc ,kfmin ,kfmax ,aforc ,tforc , & myseed ,ntseri ,nstdout ,jacmthd ,ndiag , & jac_scale ,nsp ,outgp ,outsp ,tstp_mthd , & - nsim ,nuser ,npost ,npert ,apert + nsim ,nuser ,npost ,npert ,apert , & + nguidbg inquire(file=cat_namelist,exist=lcatnl) @@ -1453,16 +1454,16 @@ call guiput("GQ" // char(0), ggui, ngx, ngy, 1) if (npost > 0) then !--- zonal means gguixm(:) = gqxm(:) ! double -> single - call guiput("GQXM" // char(0), gguixm, 1, ngy, 1) ! q + call guiput("GQXM" // char(0), gguixm, ngy, 1, 1) ! q gguixm(:) = gpsixm(:) ! double -> single - call guiput("GPSIXM" // char(0), gguixm, 1, ngy, 1) ! psi + call guiput("GPSIXM" // char(0), gguixm, ngy, 1, 1) ! psi gguixm(:) = guxm(:) ! double -> single - call guiput("GUXM" // char(0), gguixm, 1, ngy, 1) ! u + call guiput("GUXM" // char(0), gguixm, ngy, 1, 1) ! u gguixm(:) = gvxm(:) ! double -> single - call guiput("GVXM" // char(0), gguixm, 1, ngy, 1) ! v + call guiput("GVXM" // char(0), gguixm, ngy, 1, 1) ! v !--- meridional means diff --git a/cat/src/guix11.001 b/cat/src/guix11.001 new file mode 100644 index 0000000000000000000000000000000000000000..e198eb49347d71ebf13f3e4d19f89418f443179a --- /dev/null +++ b/cat/src/guix11.001 @@ -0,0 +1,4763 @@ +/* + guix11 - a GUI for PUMA, PLASIM & CAT + 2016 Edilbert Kirk & Hartmut Borth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +int Debug = 0; // set in initgui + +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#define INT int +#define REAL float +#define INTXU unsigned int +#define INTXS int + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define ROTATE_LEFT (XK_Left) +#define ROTATE_RIGHT (XK_Right) + +#define TOLELO 0x0001 +#define TOLEHI 0x0002 +#define TORILO 0x0004 +#define TORIHI 0x0008 +#define BOLELO 0x0010 +#define BOLEHI 0x0020 +#define BORILO 0x0040 +#define BORIHI 0x0080 +#define TOLEIN 0x0100 +#define TOREIN 0x0200 +#define BOLEIN 0x0400 +#define BOREIN 0x0800 + +#define IPX(l,m,h) (VGAX * (x + (l-m) / (l-h))) +#define IPY(l,m,h) (VGAY * (y + (l-m) / (l-h))) + +#define NUMWIN 9 +#define NUMPAL 13 + +/* Picture types */ + +#define ISOREC 0 +#define ISOHOR 1 +#define ISOCS 2 +#define ISOHOV 3 +#define ISOTS 4 +#define ISOTAB 5 +#define ISOSH 6 +#define ISOLON 7 +#define ISOTRA 8 +#define ISOCOL 9 +#define ISOROT 10 +#define MAPHOR 11 +#define MAPTRA 12 + +/* Models */ + +#define PUMA 0 +#define CAT 4 + +char *IsoNames[] = +{ + "ISOREC", + "ISOHOR", + "ISOCS", + "ISOHOV", + "ISOTS", + "ISOTAB", + "ISOSH", + "ISOLON", + "ISOTRA", + "ISOCOL", + "ISOROT", + "MAPHOR", + "MAPTRA" +}; + +int IsoTypes = sizeof(IsoNames) / sizeof(char *); + +char *PalNames[] = +{ + "AUTO", + "U", + "V", + "T", + "P", + "Q", + "MARST", + "AMPLI", + "VEG", + "OCET", + "OCES", + "DCC", + "DTDT" +}; + +int PalTypes = sizeof(PalNames) / sizeof(char *); + +/* Map projections */ + +#define CYLINDRICAL 0 +#define POLAR 1 +#define AZIMUTHAL 2 + +#define MAXMAPS 3 + +char *ProNames[] = +{ + "CYLINDRICAL", + "POLAR", + "AZIMUTHAL" +}; + + +/* Coordinates of button areas */ + +int ShowQueue = 0; +int ShowOnce = 1; +int OffsetY = 20; + +int Stop_XL; +int Stop_XH; +int Stop_YL; +int Stop_YH; + +int Start_XL; +int Start_XH; +int Start_YL; +int Start_YH; + +int Pause_XL; +int Pause_XH; +int Pause_YL; +int Pause_YH; + +int Help_XL; +int Help_XH; +int Help_YL; +int Help_YH; + +int Minus_XL; +int Minus_XH; +int Minus_YL; +int Minus_YH; + +int FBWD_XL; +int FBWD_XH; +int FBWD_YL; +int FBWD_YH; + +int Plus_XL; +int Plus_XH; +int Plus_YL; +int Plus_YH; + +int FFWD_XL; +int FFWD_XH; +int FFWD_YL; +int FFWD_YH; + +int Parc_XL; +int Parc_XH; +int Parc_XD; +int Parc_YL; +int Parc_YH; +int Parc_YD; + +int Wbox_XL; +int Wbox_XH; +int Wbox_YL; +int Wbox_YH; + +int Grid_XL; +int Grid_XH; +int Grid_YL; +int Grid_YH; + +XPoint StopButton[4] = {{10,10},{40,10},{40,40},{10,40}}; +XPoint StartButton[3] = {{50,10},{80,25},{50,40}}; +XPoint PauseButton1[4] = {{95,10},{102,10},{102,40},{95,40}}; +XPoint PauseButton2[4] = {{108,10},{115,10},{115,40},{108,40}}; + +#define PARCS 100 + +struct ParcStruct +{ + char Name[8]; + float Inc; + float Min; + float Max; + float Val; +}; + +int Parcs; +int cpi = 1; + +struct ParcStruct Parc[PARCS]; + +int screen_num; + +Display *display; +unsigned int ScreenW,ScreenH,ScreenBot; +int SmallScreen; + +static char *progname = "PUMA"; + +int BigEndian; +int ScreenOffset; +int Model; +int CowX = -1; +int CowY = -1; +int CowW; +int CowH; +int NumWin = NUMWIN; +int WinCols = 3; +int WinRows = 3; +int DimT = 100; // Default length of time axis +int DimX; +int DimY; +int DimZ; +int DimXY; +int Uindex = -1; +int Vindex = -1; +int ScreenD; +int OffX; +int OffY = 0; +INTXU WinXSize; +INTXU WinYSize; +int InXSize; +int InYSize; +int Latitudes; +int Lines; +int SizeChanged; +int Shutdown; +int Grid = 1; +int GridLabel = 1; +int WhitePix; +int BlackPix; +int *Flag; +int FlagSize; +int nstep; +int MRpid; +int MRnum; +int wto; +int FirstKey; +int LastKey; +int SymsPerKey; + +REAL arx; +REAL ary; + +KeySym *KeyMap; + +char wtrun[8]; + +unsigned Seed; + +float RotInc = 0.2; +int LineCo[NUMPAL]; +int MapPro[NUMWIN]; +int HovInx[NUMWIN]; +int Indez[NUMWIN]; +int MaxZ[NUMWIN]; +int RedrawFlag[NUMWIN]; +int LevelChanged[NUMWIN]; +int RotLon[NUMWIN]; +double AutoDelta[NUMWIN]; +double AutoXdelt[NUMWIN]; +double AutoLo[NUMWIN]; +REAL *TSdata[NUMWIN]; +REAL *Dmin[NUMWIN]; +REAL *Dmax[NUMWIN]; +REAL *SpeedScale; +XPoint *TSxp[NUMWIN]; + + +#define MAXPAR 16384 +float pax[MAXPAR]; +float pay[MAXPAR]; +long pal[MAXPAR]; + +int Delpar = 8; /* Interval for particle injection */ +int ParInd = 0; +int ColInd = 0; +long TracerColor; + +#define NUMSCALARS 9 + +char TSName[NUMSCALARS][80]; +char TSubsc[NUMSCALARS][80]; +char TSUnit[NUMSCALARS][80]; +char TScale[NUMSCALARS][80]; + +struct PixStruct +{ + int DimX; + int DimY; + Pixmap Pix; +} WinPixMap[NUMWIN]; + +Pixmap pix; + +#define NUMARRAYS 100 + +struct ArrayStruct +{ + char Name[80]; + float *Data; + int DimX; + int DimY; + int DimZ; + int Flag; +} Array[NUMARRAYS]; + +int NumArrays; + +struct WinAttStruct +{ + unsigned int x; + unsigned int y; + unsigned int w; + unsigned int h; + int active; + char array_name[80]; + int Plot; + int Palette; +} WinAtt[NUMWIN]; + +int BorderWidth = 0; +int WM_top_area = 0; // Window manager top area +int WinLM = 0; +int WinRM = 0; +int WinTM = 24; +int WinBM = 0; + +struct ColorStrip +{ + double Lo; + double Hi; + char *Name; + unsigned long pixel; +}; + +#define AUTOCOLORS 14 +struct ColorStrip Autostrip[AUTOCOLORS+1] = +{ + {0.0,0.0,"red"}, + {0.0,0.0,"OrangeRed"}, + {0.0,0.0,"Orange"}, + {0.0,0.0,"yellow"}, + {0.0,0.0,"GreenYellow"}, + {0.0,0.0,"green"}, + {0.0,0.0,"aquamarine"}, + {0.0,0.0,"cyan"}, + {0.0,0.0,"SkyBlue"}, + {0.0,0.0,"blue"}, + {0.0,0.0,"orchid"}, + {0.0,0.0,"magenta"}, + {0.0,0.0,"violet"}, + {0.0,0.0,"DarkViolet"}, + {0.0,0.0,NULL} +}; + +struct ColorStrip Ustrip[] = +{ + {-99.0,-10.0,"red"}, + {-10.0, -5.0,"OrangeRed"}, + { -5.0, 0.0,"Orange"}, + { 0.0, 5.0,"yellow"}, + { 5.0, 10.0,"GreenYellow"}, + { 10.0, 15.0,"green"}, + { 15.0, 20.0,"aquamarine"}, + { 20.0, 25.0,"cyan"}, + { 25.0, 30.0,"SkyBlue"}, + { 30.0, 35.0,"blue"}, + { 35.0, 40.0,"orchid"}, + { 40.0, 45.0,"magenta"}, + { 45.0, 50.0,"violet"}, + { 50.0, 99.0,"DarkViolet"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Qstrip[] = +{ + {-99.0, 0.0,"black"}, + { 0.0, 5.0,"OrangeRed"}, + { 5.0, 10.0,"Orange"}, + { 10.0, 15.0,"yellow"}, + { 15.0, 20.0,"GreenYellow"}, + { 20.0, 25.0,"green"}, + { 25.0, 30.0,"aquamarine"}, + { 30.0, 35.0,"cyan"}, + { 35.0, 40.0,"SkyBlue"}, + { 40.0, 45.0,"blue"}, + { 45.0, 50.0,"orchid"}, + { 50.0, 55.0,"magenta"}, + { 55.0, 60.0,"violet"}, + { 60.0, 99.0,"DarkViolet"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Vstrip[] = +{ + {-99.0,-10.0,"brown"}, + {-10.0, -8.0,"gold"}, + { -8.0, -6.0,"purple"}, + { -6.0, -4.0,"red"}, + { -4.0, -2.0,"OrangeRed"}, + { -2.0, 0.0,"Orange"}, + { 0.0, 2.0,"yellow"}, + { 2.0, 4.0,"GreenYellow"}, + { 4.0, 6.0,"green"}, + { 6.0, 8.0,"aquamarine"}, + { 8.0, 10.0,"cyan"}, + { 10.0, 99.0,"blue"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Tstrip[] = +{ + {-99.0,-50.0,"MidnightBlue"}, + {-50.0,-40.0,"RoyalBlue4"}, + {-40.0,-30.0,"RoyalBlue3"}, + {-30.0,-20.0,"RoyalBlue2"}, + {-20.0,-10.0,"RoyalBlue1"}, + {-10.0, 0.0,"violet"}, + { 0.0, 10.0,"IndianRed1"}, + { 10.0, 20.0,"IndianRed2"}, + { 20.0, 30.0,"IndianRed3"}, + { 30.0, 40.0,"IndianRed4"}, + { 40.0, 50.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Kstrip[] = +{ + {100.0,210.0,"RoyalBlue4"}, + {210.0,220.0,"RoyalBlue3"}, + {220.0,230.0,"RoyalBlue2"}, + {230.0,240.0,"RoyalBlue1"}, + {240.0,250.0,"violet"}, + {250.0,260.0,"IndianRed1"}, + {260.0,270.0,"IndianRed2"}, + {270.0,280.0,"IndianRed3"}, + {280.0,290.0,"IndianRed4"}, + {290.0,400.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Pstrip[] = +{ + { 00.0, 985.0,"RoyalBlue4"}, + { 985.0, 990.0,"RoyalBlue3"}, + { 990.0, 995.0,"RoyalBlue2"}, + { 995.0,1000.0,"RoyalBlue1"}, + {1000.0,1005.0,"violet"}, + {1005.0,1010.0,"IndianRed1"}, + {1010.0,1015.0,"IndianRed2"}, + {1015.0,1020.0,"IndianRed3"}, + {1020.0,1025.0,"IndianRed4"}, + {1025.0,9990.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip MarsTStrip[] = +{ + {-200.0,-90.0,"RoyalBlue4"}, + { -90.0,-80.0,"RoyalBlue3"}, + { -80.0,-70.0,"RoyalBlue2"}, + { -70.0,-60.0,"RoyalBlue1"}, + { -60.0,-50.0,"violet"}, + { -50.0,-40.0,"IndianRed1"}, + { -40.0,-30.0,"IndianRed2"}, + { -30.0,-20.0,"IndianRed3"}, + { -20.0, 0.0,"IndianRed4"}, + { 0.0,100.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip AmpliStrip[] = +{ + { 0.0, 1.0,"DarkBlue"}, + { 8.0, 9.0,"blue"}, + { 8.0, 9.0,"DarkGreen"}, + { 8.0, 9.0,"green"}, + { 8.0, 9.0,"yellow"}, + { 9.0, 10.0,"Orange"}, + { 10.0, 11.0,"OrangeRed"}, + { 11.0, 12.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Vegstrip[] = +{ + {-999.9,0.001,"DarkBlue"}, + { 0.001, 10.0,"brown"}, + { 10.0, 20.0,"SeaGreen4"}, + { 20.0, 30.0,"SeaGreen3"}, + { 30.0, 40.0,"SeaGreen2"}, + { 40.0, 50.0,"SeaGreen1"}, + { 50.0, 60.0,"YellowGreen"}, + { 60.0, 70.0,"green4"}, + { 70.0, 80.0,"green3"}, + { 80.0, 90.0,"green2"}, + { 90.0,999.0,"green1"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Tstripoce[] = +{ + {-99.0, 0.00001,"Black"}, + { 0.00001, 4.0 ,"RoyalBlue4"}, + { 4.0 ,8.0,"RoyalBlue3"}, + { 8.0, 12.0,"RoyalBlue2"}, + { 12.0, 16.0,"RoyalBlue1"}, + { 16.0, 20.0,"violet"}, + { 20.0, 24.0,"IndianRed1"}, + { 24.0, 28.0,"IndianRed2"}, + { 28.0, 32.0,"IndianRed3"}, + { 32.0, 36.0,"IndianRed4"}, + { 36.0, 40.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip Sstripoce[] = +{ + {-99.0, 30.0,"Black"}, + { 30.0, 32.0 ,"RoyalBlue4"}, + { 32.0 ,32.5,"RoyalBlue3"}, + { 32.5, 33.0,"RoyalBlue2"}, + { 33.0, 34.0,"SeaGreen"}, + { 34.0, 34.5,"YellowGreen"}, + { 34.5, 35.0,"LightGreen"}, + { 35.0, 35.5,"Orange"}, + { 35.5, 36.0,"DarkOrange"}, + { 36.0, 36.5,"OrangeRed"}, + { 36.5, 40.0,"red"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip DCCstrip[] = +{ + {-99.0, 0.0, "Black"}, + { 0.0, 10.0,"Yellow"}, + { 10.0, 20.0,"YellowGreen"}, + { 20.0, 30.0,"Green"}, + { 30.0, 40.0,"Aquamarine"}, + { 40.0, 50.0,"Cyan"}, + { 50.0, 60.0,"SkyBlue"}, + { 60.0, 70.0,"Blue"}, + { 70.0, 80.0,"Orchid"}, + { 80.0, 90.0,"Magenta"}, + { 90.0,100.0,"DarkViolet"}, + { 0.0, 0.0,NULL} +}; + +struct ColorStrip DTDTstrip[] = +{ + {-99.0, -5.0,"brown"}, + {- 5.0, -3.0,"gold"}, + { -3.0, -1.5,"purple"}, + { -1.5, -0.5,"red"}, + { -0.5, -0.25,"OrangeRed"}, + { -0.25, 0.0,"Orange"}, + { 0.0, 0.25,"yellow"}, + { 0.25, 0.5,"GreenYellow"}, + { 0.5, 1.5,"green"}, + { 1.5, 3.0,"aquamarine"}, + { 3.0, 5.0,"cyan"}, + { 5.0, 99.0,"blue"}, + { 0.0, 0.0,NULL} +}; + +#define AMPLI_COLS 8 + +struct ColorStrip *Cstrip; +struct ColorStrip *Pallet[NUMPAL] = +{ Autostrip, Ustrip, Vstrip, Tstrip, Pstrip, Qstrip,MarsTStrip,AmpliStrip, + Vegstrip, Tstripoce, Sstripoce, DCCstrip, DTDTstrip}; + +REAL VGAX; +REAL VGAY; +REAL CurVal; + +REAL *Field; // Pointer for ISO data +REAL *Ampli; // Amplitudes of spherical harmonics +XColor *Acol; // Amplitude colors + +Colormap colormap; + +XColor xcolor1,xcolor2; +XColor Red,Green,Blue,Yellow,Grey,LightRed,DarkRed,LightBlue,DarkBlue; +XColor LightGreen,DarkGreen,Dummy; + +unsigned long TSColor[10]; + +Window Win[NUMWIN]; +int win; // Current window +Window Cow; // Control bar +Window HelpWindow; + +XTextProperty WinconName1; +XTextProperty WinconName3; +XTextProperty WinconPause; +XTextProperty WinconReady; +char *PauseTitle = "Run Paused"; +char *ReadyTitle = "Press Start Button"; + +XEvent CowEvent; + +XSizeHints WinSizeHints; +XSizeHints CowSizeHints; +int OutXSize,OutYSize; +int count; +XEvent report; +GC gc; + +/* +char BigFontName[80] = "10x20"; +char FixFontName[80] = "9x15bold"; +char SubFontName[80] = "6x10"; +*/ +char BigFontName[80] = "9x15bold"; +char FixFontName[80] = "8x13"; +char SubFontName[80] = "6x10"; + +XFontStruct *FixFont; +XFontStruct *SubFont; +XFontStruct *BigFont; +int FixFontHeight; +int SubFontHeight; +int BigFontHeight; +int FixFontWidth; +int SubFontWidth; +int BigFontWidth; +int Paused = 0; + +char *display_name = NULL; +XWMHints wm_hints; +XClassHint class_hints; +Atom Delwin; + +char *WindowTitle[NUMWIN]; +XTextProperty WindowName[NUMWIN]; +XTextProperty HelpName; + +char *mona[12] = +{ + "Jan","Feb","Mar", + "Apr","May","Jun", + "Jul","Aug","Sep", + "Oct","Nov","Dec" +}; + +char *wena[7] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}; + +char datch[64]; +char PlanetName[32]; + +char GUI_default[80] = "GUI.cfg"; +char GUI_config[80] = "GUI_last_used.cfg"; + + +#define PSDIM 30 +char *pixelstar[PSDIM] = { +"..............................", +"..............................", +"..............................", +"...**....**....**....**.......", +"...**....**....**....**.......", +"...**....**....**....**.......", +"...**....**....**....**.......", +"...**....**************.......", +"...**....**************.......", +"...**....**....**....**.......", +"...***...**....**....**.......", +"....******.....**....**.......", +".....****......**....**.......", +"..............................", +"..............................", +"..............................", +"..............................", +"..............................", +"..............................", +"..............................", +"..............................", +"..............................", +".......................*......", +"......................***.....", +"...................**.***.**..", +"...................**.***.**..", +"...................**.***.**..", +"...................****.****..", +"...................***...***..", +"...................***...***.."}; + +// Variables used for calculating "frames per second" + +int fps; +int rmuf = 20; // Rotating map update frequency [1/sec] +int rmui = 1; // Rotating map update interval [steps] +int SkipFreq; +int ThisSecond; +int LastSecond; +int LastStep; +int SecEvent; + +int ndatim[6]; /* year, month, day, hour, minute, weekday */ +int LastMinute; /* Last value of ndatim(4) */ +int DeltaTime ; /* Computed timestep interval [min] */ + +struct BMIstruct +{ + int Size; + int Width; + int Height; + short Planes; + short Count; + int Compression; + int SizeImage; + int XPelsPerMeter; + int YPelsPerMeter; + int ClrUsed; + int ClrImportant; +}; + +struct BMIstruct ImageBMI; + +struct MapImageStruct +{ + char *d; // Bitmap data + int w; // Image width + int h; // Image height + int f; // Rotation factor + float l; // Reference longitude + float r; // Rotation speed [deg/step] + XImage *X; // XImage structure +}; + +// Convert an RGB value to an X11 Pixel + +unsigned long create_pixel(long red, long green, long blue) +{ + if (ScreenD == 24) // 24 bit true color + { + return blue | green << 8 | red << 16; + } + else if (ScreenD == 16) // 16 bit RGB 565 + { + return blue >> 3 | (green >> 2) << 5 | (red >> 3) << 11; + } + else return 0; +} + +struct MapImageStruct MapHR; // Hires (2560x1280) Earth image +struct MapImageStruct MapLR[NUMWIN]; + +void ScaleImage(struct MapImageStruct *s, struct MapImageStruct *d) +{ + int a,b,x,y; + unsigned long px; + unsigned long h,w; + double f,g; + + if (d->X) XDestroyImage(d->X); + w = (d->w + 7) & 0xFFF8; + h = d->h; + d->d = malloc(4 * w * h); + d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0, + d->d,w,h,8,0); + + f = (double)s->w / (double)d->w; + g = (double)s->h / (double)d->h; + + for (y = 0 ; y < d->h ; ++y) + for (x = 0 ; x < d->w ; ++x) + { + a = x * f; + b = y * g; + XPutPixel(d->X,x,y,XGetPixel(s->X,a,b)); + } +} + + +void PolarImage(struct MapImageStruct *s, struct MapImageStruct *d) +{ + int a,b,x,y; + unsigned long h,w; + double f,lfa,xnp,ynp,xsp,ysp,dx,dy; + + if (d->X) XDestroyImage(d->X); + w = (d->w + 7) & 0xFFF8; + h = d->h; + d->d = malloc(4 * w * h); + d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0, + d->d,w,h,8,0); + + f = ary * (double)s->h / (double)d->h; + lfa = (s->w-1) / (2.0 * M_PI); + xnp = (d->w) * 0.25; + ynp = (d->h) * 0.50; + xsp = (d->w) * 0.75; + ysp = ynp; + + for (y = 0 ; y < d->h ; ++y) + { + dy = (ynp - y); + for (x = 0 ; x < d->w/2 ; ++x) /* Northern hemisphere */ + { + dx = (xnp - x); + a = atan2(dx,dy) * lfa; + b = sqrt(dx * dx + dy * dy) * f; + if (a < 0.0) a += (s->w); + if (a >= 0 && a < s->w && b >= 0 && b <= s->h/2) + XPutPixel(d->X,x,y,XGetPixel(s->X,a,b)); + else XPutPixel(d->X,x,y,BlackPix); + } + dy = (ysp - y); + for (x = d->w/2 ; x < d->w ; ++x) /* Southern hemisphere */ + { + dx =(x - xsp); + a = atan2(dx,dy) * lfa; + b = s->h - f * sqrt(dx * dx + dy * dy); + if (a < 0.0) a += (s->w); + if (a >= 0 && a < s->w && b >= 0 && b >= s->h/2 && b <= s->h) + XPutPixel(d->X,x,y,XGetPixel(s->X,a,b)); + else XPutPixel(d->X,x,y,BlackPix); + } + } +} + + +void RevOrtho(double R, double lam0, double phi0, int xx, int yy, double *lam, double *phi) +{ + double rho,c,rhoq,x,y; + + x = xx; + y = yy; + + rhoq = x*x + y*y; + rho = sqrt(rhoq); + if (rho > R) + { + *phi = 999.9; + *lam = 999.9; + } + else if (rho > R / 100000.0) + { + c = asin(rho / R); + *phi = asin(cos(c) * sin(phi0) + y * sin(c) * cos(phi0) / rho); + *lam = lam0 + atan2(x * sin(c) , rho * cos(phi0) * cos(c) - y * sin(phi0) * sin(c)); + } + else + { + *phi = phi0; + *lam = lam0; + } + // printf("[%6.1lf / %6.1lf] --> (%6.1lf / %6.1lf)\n",x,y,*lam,*phi); +} + +/* ==================================================== */ +/* AzimuthalImage - Display map in azimuthal projection */ +/* ==================================================== */ + +void AzimuthalImage(struct MapImageStruct *s, struct MapImageStruct *d) +{ + int lam; // lambda pixel coordinate in source image + int phi; // phi pixel coordinate in source image + int x ; // x pixel coordinate in destination image + int y ; // y pixel coordinate in destination image + int dxc; // pixel coordinate of centre position + int dxl; // pixel coordinate of left most position + int dxr; // pixel coordinate of right most position + int dx ; // centre relative x position + int dy ; // centre relative y position + int p00; // euqator + int l00; // reference longitude + + unsigned int dih; // destination image height + unsigned int diw; // destination image width + unsigned int dpw; // destination image padded width + + double rad; // pixel radius of new image + double ysc; // yscale = source height / destination height + double rho; // distance from centre + double xpi; // x scale factor = 2 * PI / width + double ypi; // y scale factor = PI / height + double xrf; + double yrf; + + XImage *sX; // source image + XImage *dX; // destination image + + + // Destroy old image structure inclusive data storage + + if (d->X) XDestroyImage(d->X); + + // Set width of new image + + diw = d->w; + + // Pad width of new image to a multiple of 8 + + dpw = (diw + 7) & 0xFFF8; + + // Set height of new image + + dih = d->h; + + // Allocate space for image data + + d->d = calloc(dpw * dih,4); + + // Create image structure + + dX = d->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0,d->d,dpw,dih,8,0); + sX = s->X; + + p00 = s->h >> 1; + rad = dih >> 1; + dxc = diw >> 1; + dxl = MAX(dxc - rad, 0); + dxr = MIN(dxc + rad, diw); + xpi = s->w / M_PI * 0.5; + ypi = s->h / M_PI; + ysc = (double)s->h / (double)dih; + l00 = (int)((d->l * s->w) / 360 + s->w/2) % s->w; + xrf = (double)diw / pow(2.0,31), + yrf = (double)dih / pow(2.0,31); + + // Paint some stars on the sky + + srandom(Seed); + for (y = 0 ; y < (diw * dih) >> 8 ; ++y) + XPutPixel(dX,xrf*random(),yrf*random(),WhitePix); + + for (y = 0 ; y < dih ; ++y) + { + dy = y - rad; + phi = y * ysc; + for (x = dxl ; x < dxr ; ++x) + { + dx = x - dxc; + rho = sqrt(dx * dx + dy * dy); + if (rho < rad) + { + lam = l00 + xpi * atan2(dx / rad, cos(asin(rho / rad))); + phi = p00 + ypi * asin(dy / rad); + XPutPixel(dX,x,y,XGetPixel(sX,lam,phi)); + } + } + } +} + + +void SwapIEEE16(char W[2]) +{ + char B; + + B = W[0]; W[0] = W[1]; W[1] = B; +} + +void SwapIEEE32(char W[4]) +{ + char B; + + B = W[0]; W[0] = W[3]; W[3] = B; + B = W[1]; W[1] = W[2]; W[2] = B; +} + +int ReadINT(FILE *fpi) +{ + int i,k; + i = fread(&k,sizeof(k),1,fpi); + if (BigEndian) SwapIEEE32((char *)&k); + return k; +} + +short ReadSHORT(FILE *fpi) +{ + short i,k; + i = fread(&k,sizeof(k),1,fpi); + if (BigEndian) SwapIEEE16((char *)&k); + return k; +} + +void ReadImage(struct MapImageStruct *ei, char *filename) +{ + char ch; + int i,n,x,y,z; + long r,g,b; + int FileSize; + int Reserved; + int OffBits; + int PicBytes; + int ImgBytes; + int PadWidth; + int PadBytes; + int bpp; + int byr; + FILE *fp; + unsigned char *BuffImageData; + + if (!(fp = fopen(filename,"r"))) return; + ch = fgetc(fp); + if (ch != 'B') return; + ch = fgetc(fp); + if (ch != 'M') return; + FileSize = ReadINT(fp); + Reserved = ReadINT(fp); + OffBits = ReadINT(fp); + + if (Debug) + { + printf("Properties of %s:\n",filename); + printf("FileSize = %d\n",FileSize); + printf("FileOffset = %d\n",OffBits); + } + + ImageBMI.Size = ReadINT(fp); + ImageBMI.Width = ReadINT(fp); + ImageBMI.Height = ReadINT(fp); + ImageBMI.Planes = ReadSHORT(fp); + ImageBMI.Count = ReadSHORT(fp); + ImageBMI.Compression = ReadINT(fp); + ImageBMI.SizeImage = ReadINT(fp); + ImageBMI.XPelsPerMeter = ReadINT(fp); + ImageBMI.YPelsPerMeter = ReadINT(fp); + ImageBMI.ClrUsed = ReadINT(fp); + ImageBMI.ClrImportant = ReadINT(fp); + + PadWidth = (ImageBMI.Width + 7) & 0xFFF8; + bpp = ImageBMI.Count >> 3; + PadBytes = (4 - ((ImageBMI.Width * bpp) % 4)) % 4 ; + + if (Debug) + { + printf("BMI Size = %d\n",ImageBMI.Size); + printf("BMI Width = %d\n",ImageBMI.Width); + printf("BMI Height = %d\n",ImageBMI.Height); + printf("BMI Planes = %d\n",ImageBMI.Planes); + printf("BMI Count = %d\n",ImageBMI.Count); + printf("BMI ClrUsed = %d\n",ImageBMI.ClrUsed); + printf("Pad Bytes = %d\n",PadBytes); + printf("ScreenD= %d\n",ScreenD); + } + + PicBytes = (bpp * ImageBMI.Width + PadBytes) * ImageBMI.Height; + ImgBytes = 4 * PadWidth * ImageBMI.Height; + ei->d = calloc(ImgBytes,1); + BuffImageData = malloc(PicBytes); + fseek(fp,OffBits,SEEK_SET); + n = fread(BuffImageData,PicBytes,1,fp); + fclose(fp); + + ei->X = XCreateImage(display,CopyFromParent,ScreenD,ZPixmap,0, + ei->d,PadWidth,ImageBMI.Height,8,0); + + for (y = 0 ; y < ImageBMI.Height ; ++y) + for (x = 0 ; x < ImageBMI.Width ; ++x) + { + i = bpp * x + (ImageBMI.Height - 1 - y) * (ImageBMI.Width*bpp+PadBytes); + b = BuffImageData[i ]; + g = BuffImageData[i+1]; + r = BuffImageData[i+2]; + XPutPixel(ei->X, x, y, create_pixel(r,g,b)); + } + free(BuffImageData); + ei->w = ImageBMI.Width; + ei->h = ImageBMI.Height; +} + + +void ntocdat(void) +{ + if (ndatim[1] > 0) + { + if (ndatim[5] >= 0) + sprintf(datch,"%s %2d-%s-%04d %2d:%02d",wena[ndatim[5]],ndatim[2],mona[ndatim[1]-1], + ndatim[0],ndatim[3],ndatim[4]); + else + sprintf(datch,"%2d-%s-%04d %2d:%02d",ndatim[2],mona[ndatim[1]-1], + ndatim[0],ndatim[3],ndatim[4]); + } +} + +/* ============================================== */ +/* CharAlloc - Allocate space for character array */ +/* ============================================== */ + +char *CharAlloc(int bytes,char *array_name) +{ + char *result = NULL; + if (bytes > 0) + { + result = (char *)calloc(bytes, sizeof(char)); + if (!result || Debug) + { + if (!result) printf("*** Out of Memory *** on "); + printf("CharAlloc: at%10p %6d char for %-30.30s\n", + result,bytes,array_name); + } + } + return(result); +} + +/* ======================================= */ +/* IntAlloc - Allocate space for int array */ +/* ======================================= */ + +int *IntAlloc(int words,char *array_name) +{ + int *result = NULL; + if (words > 0) + { + result = (int *) calloc(words, sizeof(int)); + if (!result || Debug) + { + if (!result) printf("*** Out of Memory *** on "); + printf("IntAlloc: at%10p %6d int for %s\n", + result,words,array_name); + } + } + return(result); +} + +/* =========================================== */ +/* FloatAlloc - Allocate space for float array */ +/* =========================================== */ + +float *FloatAlloc(int words, char *array_name) +{ + float *result = NULL; + if (words > 0) + { + result = (float *) calloc(words, sizeof(float)); + if (!result || Debug) + { + if (!result) printf("*** Out of Memory *** on "); + printf("FloatAlloc: at%10p %6d float for %s\n", + result,words,array_name); + } + } + return(result); +} + +/* ========================================== */ +/* SizeAlloc - Allocate space for sized array */ +/* ========================================== */ + +void *SizeAlloc(int words, int Size, char *array_name) +{ + void *result = NULL; + if (words > 0) + { + result = (void *) calloc(words, Size); + if (!result || Debug) + { + if (!result) printf("*** Out of Memory *** on "); + printf("SizeAlloc: at%10p %6d void for %s\n", + result,words,array_name); + } + } + return(result); +} + +void LoadFonts(void) +{ + if ((FixFont = XLoadQueryFont(display,FixFontName)) == NULL) + { + printf("%s: Cannot open %s font\n",progname,FixFontName); + exit(-1); + } + if ((SubFont = XLoadQueryFont(display,SubFontName)) == NULL) + { + SubFont = FixFont; + } + if ((BigFont = XLoadQueryFont(display,BigFontName)) == NULL) + { + if ((BigFont = XLoadQueryFont(display,"10x20")) == NULL) + { + printf("%s: Cannot open %s font\n",progname,BigFontName); + exit(-1); + } + } + FixFontWidth = XTextWidth(FixFont,"X",1); + SubFontWidth = XTextWidth(SubFont,"X",1); + BigFontWidth = XTextWidth(BigFont,"X",1); + FixFontHeight = FixFont->ascent + FixFont->descent; + SubFontHeight = SubFont->ascent + SubFont->descent; + BigFontHeight = BigFont->ascent + BigFont->descent; +} + +int AllocateColorCells(struct ColorStrip cs[]) +{ + int i = 0; + XColor xcolor1,xcolor2; + + while (cs[i].Name) + { + XAllocNamedColor(display,colormap,cs[i].Name,&xcolor1,&xcolor2); + cs[i].pixel = xcolor1.pixel; + ++i; + } + return i; +} + +void CalcButtonAreas(void) +{ + int of,ds,bh,fh,fw,j; + + of = OffsetY; + ds = 10; + bh = 30; + fh = BigFontHeight; + fw = BigFontWidth; + + /* 1. Stop Button */ + + StopButton[0].y += OffsetY; + StopButton[1].y += OffsetY; + StopButton[2].y += OffsetY; + StopButton[3].y += OffsetY; + + Stop_XL = ds; + Stop_XH = Stop_XL + bh; + Stop_YL = of + ds; + Stop_YH = Stop_YL + bh; + + /* 2. Start Button */ + + Start_XL = Stop_XH + ds; + Start_XH = Start_XL + bh; + Start_YL = Stop_YL; + Start_YH = Stop_YH; + + StartButton[0].y += OffsetY; + StartButton[1].y += OffsetY; + StartButton[2].y += OffsetY; + + /* 3. Pause Button */ + + Pause_XL = Start_XH + 15; + Pause_XH = Start_XH + 35; + Pause_YL = Start_YL; + Pause_YH = Start_YH; + + PauseButton1[0].y += OffsetY; + PauseButton1[1].y += OffsetY; + PauseButton1[2].y += OffsetY; + PauseButton1[3].y += OffsetY; + + PauseButton2[0].y += OffsetY; + PauseButton2[1].y += OffsetY; + PauseButton2[2].y += OffsetY; + PauseButton2[3].y += OffsetY; + + /* 4. Help Button */ + + Help_XL = 200; + Help_XH = Help_XL + 5 * fw; + Help_YL = Pause_YL; + Help_YH = Pause_YH; + + /* 5. Minus & FBWD Button */ + + Minus_XL = 300; + Minus_XH = Minus_XL + fh; + Minus_YL = Pause_YL + (bh - fh) / 2; + Minus_YH = Minus_YL + fh; + + FBWD_XH = Minus_XL - ds/2; + FBWD_XL = FBWD_XH - fh; + FBWD_YL = Minus_YL; + FBWD_YH = Minus_YH; + + /* 6. Parameter Change Area */ + + Parc_XL = Minus_XH + ds; + Parc_XH = Parc_XL + fw * 14; + Parc_YL = Minus_YL; + Parc_YH = Minus_YH; + Parc_XD = Parc_XH - Parc_XL; + Parc_YD = Parc_YH - Parc_YL; + + /* 7. Plus & FFWD Button */ + + Plus_XL = Parc_XH + ds; + Plus_XH = Plus_XL + fh; + Plus_YL = Minus_YL; + Plus_YH = Minus_YH; + + FFWD_XL = Plus_XH + ds/2; + FFWD_XH = FFWD_XL + fh; + FFWD_YL = Plus_YL; + FFWD_YH = Plus_YH; + + /* 8. Grid on/off box */ + + Grid_XL = Stop_XL; + Grid_XH = Grid_XL + FixFontHeight; + Grid_YL = Stop_YH + 3 * BigFontHeight / 2; + Grid_YH = Grid_YL + FixFontHeight; + + /* Window status and select boxes */ + + Wbox_XL = 580; + Wbox_XH = Wbox_XL + FixFontHeight; + Wbox_YL = 0; + Wbox_YH = NumWin * FixFontHeight; +} + + +/* Hack for getting information of window decoration */ +/* especially borderwidth and titleheight */ +/* These are properties of the window manager and are */ +/* usually adjustable by the user */ + +void TestWindow(int xx, int yy, int wi, int he, int *x, int *y, + int *X, int *Y, unsigned int *W, unsigned int *H) +{ + unsigned int DepthReturn = 0; + unsigned int BorderReturn = 0; + Window TW,Parent,Child; + + TW = XCreateWindow(display,RootWindow(display,screen_num), + xx,yy,wi,he, // x,y,w,h + 0,CopyFromParent,InputOutput, // border, depth, class + CopyFromParent,0,NULL); // visual, valuemask, attributes + XSelectInput(display,TW,ExposureMask); + XMapWindow(display,TW); + XMoveWindow(display,TW,xx,yy); + XNextEvent(display,&CowEvent); // Wait until WM mapped it + XGetGeometry(display,TW,&Parent,x,y,W,H,&BorderReturn,&DepthReturn); + XTranslateCoordinates(display,TW,Parent,0,0,X,Y,&Child); + XDestroyWindow(display,TW); + + if (Debug) + { + printf("TW[%x][%x]: %4d / %4d %4d x %4d x %2d [%2d:%2d]\n", + (int)TW,(int)Parent,*x,*y,*W,*H,DepthReturn,*X,*Y); + } +} + + +void CreateTestWindow(void) +{ + int X,Y,xp,yp; + unsigned int W,H; + + // Open a test window with displacement x = 100 and y = 100 + // Test the returned coordinates for upper left corner + // and compute left margin (border) and top margin (title bar) + + TestWindow(100,100,100,100,&xp,&yp,&X,&Y,&W,&H); + + // Left margin + + if (X >= 100 && X < 110) WinLM = X - 100; + + // Right margin + + WinRM = WinLM; + + // Top margin + + if (Y >= 100 && Y < 150) WinTM = Y - 100; + else if (Y > 0 && Y < 50) WinTM = Y; + + // Bottom margin + + WinBM = WinLM; + + // Open a full screen test window + // Test the returned coordinates for upper left corner + // the y displacement should be WinTM plus Windowmanager menu bar + + TestWindow(0,0,ScreenW,ScreenH,&xp,&yp,&X,&Y,&W,&H); + + // Window manager menu bar on top + + if (yp > WinTM) WM_top_area = yp - WinTM; + + + // Last usable scan line + + ScreenBot = WM_top_area + WinTM + H; + if (ScreenBot > ScreenH) ScreenBot = ScreenH; + + // Are we running on a 27" iMac :-) + + if (ScreenW == 2560 && ScreenH > 1400) ScreenBot -= 100; + + if (Debug) + { + printf("Screen = %4d x %4d x %2d\n",ScreenW,ScreenH,ScreenD); + printf("ScreenBot = %4d\n",ScreenBot); + printf("Top reserved = %4d\n",WM_top_area); + printf("Bot reserved = %4d\n",ScreenH-ScreenBot); + printf("Left margin = %4d\n",WinLM); + printf("Right margin = %4d\n",WinRM); + printf("Top margin = %4d\n",WinTM); + printf("Bot margin = %4d\n",WinBM); + } +} + + +void TrimCopy(char *Trim, char *Line, int n) +{ + int l; + char *s; + + l = strlen(Line); + Line[--l] = 0; // Remove linefeed + while (Line[l-1] == ' ') Line[--l] = 0; // Remove trailing blanks + s = Line; + while (*s == ' ') ++s; // Remove leading blanks + strncpy(Trim,s,n); +} + + +int ReadConfig(char *filename) +{ + FILE *fp; + int i,w,l,s,p; + char Line[256]; + char Plot[80]; + char Palette[80]; + char Projection[80]; + char Rotation[80]; + char *t; + + fp = fopen(filename,"r"); + if (!fp) return 1; + + w = -2; + s = -1; + p = -1; + while (!feof(fp)) + { + t = fgets(Line,256,fp); + if (Line[0] == '#') continue; + if (strncmp(Line,"[Window " , 8) == 0) w = atoi(Line+8); + if (strncmp(Line,"[Control" , 8) == 0) w = -1; + if (strncmp(Line,"[Scalar " , 8) == 0) s = atoi(Line+8); + if (strncmp(Line,"WinRows =" , 9) == 0) + { + WinRows = atoi(Line+9); + if (WinRows < 1) WinRows = 1; + if (WinRows > 3) WinRows = 3; + NumWin = WinCols * WinRows; + } + if (strncmp(Line,"WinCols =" , 9) == 0) + { + WinCols = atoi(Line+9); + if (WinCols < 1) WinCols = 1; + if (WinCols > 3) WinCols = 3; + NumWin = WinCols * WinRows; + } + if (strncmp(Line,"[Parameter " ,11) == 0) + { + p = atoi(Line+11); + if (p >= Parcs) Parcs = p+1; + } + if (strncmp(Line,"Geometry:",9) == 0 && w >= 0 && w < NUMWIN) + { + sscanf(Line+9,"%d %d %d %d",&WinAtt[w].w,&WinAtt[w].h, + &WinAtt[w].x,&WinAtt[w].y); + WinAtt[w].active = 1; + } + if (strncmp(Line,"Inactive:",9) == 0 && w >= 0 && w < NUMWIN) + { + sscanf(Line+9,"%d %d %d %d",&WinAtt[w].w,&WinAtt[w].h, + &WinAtt[w].x,&WinAtt[w].y); + WinAtt[w].active = 0; + } + if (strncmp(Line,"Geometry:",9) == 0 && w == -1) + { + sscanf(Line+9,"%d %d %d %d",&CowW,&CowH,&CowX,&CowY); + } + if (strncmp(Line,"Title:",6) == 0 && w >= -1 && w < NUMWIN) + { + if (w == -1) TrimCopy(PlanetName,Line+6,sizeof(PlanetName)-1); + else TrimCopy(WindowTitle[w]+wto,Line+6,79-wto); + } + if (strncmp(Line,"Array:",6) == 0 && w >= 0 && w < NUMWIN) + TrimCopy(WinAtt[w].array_name,Line+6,79); + if (strncmp(Line,"Plot:",5) == 0 && w >= 0 && w < NUMWIN) + { + TrimCopy(Plot,Line+5,79); + for (i=0 ; i < IsoTypes ; ++i) + if (!strcmp(Plot,IsoNames[i])) WinAtt[w].Plot = i; + } + if (strncmp(Line,"Projection:",11) == 0 && w >= 0 && w < NUMWIN) + { + TrimCopy(Projection,Line+11,79); + for (i=0 ; i < MAXMAPS ; ++i) + if (!strcmp(Projection,ProNames[i])) MapPro[w] = i; + } + if (strncmp(Line,"Rotation factor:",15) == 0 && w >= 0 && w < NUMWIN) + { + TrimCopy(Rotation,Line+15,79); + MapLR[w].f = atoi(Rotation); + } + if (strncmp(Line,"Palette:",8) == 0 && w >= 0 && w < NUMWIN) + { + TrimCopy(Palette,Line+8,79); + for (i=0 ; i < PalTypes ; ++i) + if (!strcmp(Palette,PalNames[i])) WinAtt[w].Palette = i; + } + + // Dimension for time axis + + if (strncmp(Line,"DimT:" ,5) == 0) DimT = atoi(Line+5); + + // Attributes of scalars for timeseries windows + + if (strncmp(Line,"Name:" ,5) == 0 && s >= 0 && s < NUMSCALARS) + TrimCopy(TSName[s],Line+5,79); + if (strncmp(Line,"Sub:" ,4) == 0 && s >= 0 && s < NUMSCALARS) + TrimCopy(TSubsc[s],Line+4,79); + if (strncmp(Line,"Unit:" ,5) == 0 && s >= 0 && s < NUMSCALARS) + TrimCopy(TSUnit[s],Line+5,79); + if (strncmp(Line,"Scale:",6) == 0 && s >= 0 && s < NUMSCALARS) + TrimCopy(TScale[s],Line+6,79); + + // Attributes of parameter in change menu + + if (strncmp(Line,"ParName:",8) == 0 && p >= 0 && p < PARCS) + TrimCopy(Parc[p].Name,Line+8,6); + if (strncmp(Line,"ParInc:" ,7) == 0 && p >= 0 && p < PARCS) + Parc[p].Inc = atof(Line+7); + if (strncmp(Line,"ParMin:" ,7) == 0 && p >= 0 && p < PARCS) + Parc[p].Min = atof(Line+7); + if (strncmp(Line,"ParMax:" ,7) == 0 && p >= 0 && p < PARCS) + Parc[p].Max = atof(Line+7); + if (strcmp(Parc[p].Name,"SELLON") == 0) Parc[p].Inc = 360.0 / (2.0 * Latitudes); + } + fclose(fp); + return 0; +} + + +void CreateControlWindow(void) +{ + int X,Y,W,H,B,D,x,y; + char Title1[256]; + char *WinconTitle1; + char *WinconTitle3 = {"RUN finished - click on red stop button"}; + Window Rootwin; + Window Child; + + // Create title for control window + + strcpy(Title1,"Unknown model"); + if (Model == 0) // PUMA + { + if (MRpid < 0) + strcpy(Title1,"PUMA - KlimaCampus Hamburg"); + else + sprintf(Title1,"Run %d: PUMA - KlimaCampus Hamburg",MRpid); + } + else if (Model == 1) sprintf(Title1,"SAM - KlimaCampus"); + else if (Model == 2) + { + if (MRpid < 0) + sprintf(Title1,"Planet Simulator (%s) - KlimaCampus",PlanetName); + else + sprintf(Title1,"Run %d: Planet Simulator (%s) - KlimaCampus",MRpid,PlanetName); + } + else if (Model == 3) sprintf(Title1,"Planet Simulator / LSG - KlimaCampus"); + else if (Model == 4) sprintf(Title1,"CAT - Computer Aided Turbulence"); + else printf("*** unknown model number %d in guix11 ***\n",Model); + + WinconTitle1 = Title1; + if (CowW < 920 || CowW > ScreenW) CowW = 920; + if (NumWin < 5) CowH = 6 * FixFontHeight + 5; + else CowH = NumWin * FixFontHeight + 5; + if (CowX < 0 || CowX > ScreenW - CowW) CowX = (ScreenW - CowW) / 2; + if (CowY < 0 || CowY > ScreenBot - CowH - WinTM - WinBM) + CowY = ScreenBot - CowH - WinTM - WinBM; + CowSizeHints.flags = PPosition | PSize | PMinSize | PMaxSize; + CowSizeHints.min_width = CowW; + CowSizeHints.min_height = CowH; + CowSizeHints.max_width = ScreenW - WinLM - WinRM; + CowSizeHints.max_height = CowH; + if (MRnum == 2 && MRpid == 1) CowX += ScreenW; + if (Debug) printf("Control Window %d/%d %dx%d\n",CowX,CowY,CowW,CowH); + Cow = XCreateWindow(display,RootWindow(display,screen_num), // display, parent + CowX,CowY,CowW,CowH, + BorderWidth,CopyFromParent,InputOutput, // border, depth, class + CopyFromParent,0,NULL); // visual, valuemask, attributes + XStringListToTextProperty(&WinconTitle1,1,&WinconName1); + XStringListToTextProperty(&WinconTitle3,1,&WinconName3); + XStringListToTextProperty(&PauseTitle,1,&WinconPause); + XStringListToTextProperty(&ReadyTitle,1,&WinconReady); + XSetWMProtocols(display,Cow,&Delwin,1); + XSetWMProperties(display,Cow,&WinconName1,NULL, + NULL,0,&CowSizeHints,&wm_hints,&class_hints); + XSelectInput(display,Cow,ButtonPressMask | KeyPressMask | ExposureMask); + XMapWindow(display,Cow); +} + + +void ShowStep(void) +{ + char Text[80]; + XSetFont(display, gc, BigFont->fid); + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,Grey.pixel); + + if (Model == CAT) // CAT shows timestep + { + sprintf(Text,"GUI step %9d",ndatim[0]); + XDrawImageString(display,Cow,gc,10,BigFontHeight,Text,strlen(Text)); + } + else // PUMA & PLASIM show date and time + { + ntocdat(); + if (ndatim[5] == 6) XSetForeground(display,gc,Red.pixel); // sunday + XDrawImageString(display,Cow,gc,10,BigFontHeight,datch,strlen(datch)); + XSetForeground(display,gc,BlackPix); + } + + if (ShowQueue) + { + sprintf(Text,"%8d Events ",XPending(display)); + XDrawImageString(display,Cow,gc,10,60 + BigFontHeight,Text,strlen(Text)); + } + else if (fps > 1) + { + if (SkipFreq < 2) sprintf(Text,"%5d fps",fps); + else sprintf(Text,"%5d fps [%d]",fps,SkipFreq); + XDrawImageString(display,Cow,gc,10,60 + BigFontHeight,Text,strlen(Text)); + } +} + + +int FormatVal(char *Name, float V, char *Text) +{ + char Format[80]; + + if (V > 9999.9 || V < -999.9) + { + sprintf(Text,"%6.6s = *****",Name); + return strlen(Text); + } + else if (V > 999.99 ) strcpy(Format,"%6.6s =%6.1f"); + else if (V > 99.999 ) strcpy(Format,"%6.6s =%6.2f"); + else if (V > 9.9999) strcpy(Format,"%6.6s =%6.3f"); + else if (V > 0.0 ) strcpy(Format,"%6.6s =%6.4f"); + else if (V > -9.9 ) strcpy(Format,"%6.6s =%6.3f"); + else if (V > -99.9 ) strcpy(Format,"%6.6s =%6.2f"); + else strcpy(Format,"%6.6s =%6.1f"); + + sprintf(Text,Format,Name,V); + return strlen(Text); +} + + +void ShowParcs(void) +{ + char Text[80]; + int len; + float V; + + XSetFont(display, gc, BigFont->fid); + len = FormatVal(Parc[cpi].Name,Parc[cpi].Val,Text); + + XSetBackground(display,gc,WhitePix); + XSetForeground(display,gc,Red.pixel); + XFillRectangle(display,Cow,gc,Minus_XL,Minus_YL,Minus_XH-Minus_XL,Minus_YH-Minus_YL); + XFillRectangle(display,Cow,gc,FBWD_XL,FBWD_YL,FBWD_XH-FBWD_XL,FBWD_YH-FBWD_YL); + XSetForeground(display,gc,WhitePix); + XFillRectangle(display,Cow,gc,Minus_XL+3,(Minus_YH+Minus_YL)/2-1,Minus_XH-Minus_XL-5,3); + XFillRectangle(display,Cow,gc,FBWD_XL+3,(FBWD_YH+FBWD_YL)/2-1,FBWD_XH-FBWD_XL-5,3); + XSetForeground(display,gc,BlackPix); + XDrawImageString(display,Cow,gc,Parc_XL,Parc_YH-3,Text,len); + XSetForeground(display,gc,Green.pixel); + XFillRectangle(display,Cow,gc,Plus_XL,Plus_YL,Plus_XH-Plus_XL,Plus_YH-Plus_YL); + XFillRectangle(display,Cow,gc,FFWD_XL,FFWD_YL,FFWD_XH-FFWD_XL,FFWD_YH-FFWD_YL); + XSetForeground(display,gc,WhitePix); + XFillRectangle(display,Cow,gc,Plus_XL+3,(Plus_YH+Plus_YL)/2-1,Plus_XH-Plus_XL-5,3); + XFillRectangle(display,Cow,gc,FFWD_XL+3,(FFWD_YH+FFWD_YL)/2-1,FFWD_XH-FFWD_XL-5,3); + XFillRectangle(display,Cow,gc,(Plus_XH+Plus_XL)/2-1,Plus_YL+3,3,Plus_YH-Plus_YL-5); + XFillRectangle(display,Cow,gc,(FFWD_XH+FFWD_XL)/2-1,FFWD_YL+3,3,FFWD_YH-FFWD_YL-5); + XSetForeground(display,gc,BlackPix); + XDrawRectangle(display,Cow,gc,Minus_XL,Minus_YL,Minus_XH-Minus_XL,Minus_YH-Minus_YL); + XDrawRectangle(display,Cow,gc,FBWD_XL,FBWD_YL,FBWD_XH-FBWD_XL,FBWD_YH-FBWD_YL); + XDrawRectangle(display,Cow,gc,Parc_XL-1,Parc_YL-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL); + XDrawRectangle(display,Cow,gc,Plus_XL,Plus_YL,Plus_XH-Plus_XL,Plus_YH-Plus_YL); + XDrawRectangle(display,Cow,gc,FFWD_XL,FFWD_YL,FFWD_XH-FFWD_XL,FFWD_YH-FFWD_YL); + + /* Show next parameter */ + + strcpy(Text," "); + if (cpi < Parcs-1) FormatVal(Parc[cpi+1].Name,Parc[cpi+1].Val,Text); + len = strlen(Text); + + XSetBackground(display,gc,WhitePix); + XSetForeground(display,gc,BlackPix); + XDrawImageString(display,Cow,gc,Parc_XL,2*Parc_YH-Parc_YL-3,Text,len); + XDrawRectangle(display,Cow,gc,Parc_XL-1,Parc_YH-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL); + + /* Show previous parameter */ + + strcpy(Text," "); + if (cpi > 0) FormatVal(Parc[cpi-1].Name,Parc[cpi-1].Val,Text); + len = strlen(Text); + + XSetBackground(display,gc,WhitePix); + XSetForeground(display,gc,BlackPix); + XDrawImageString(display,Cow,gc,Parc_XL,Parc_YL-3,Text,len); + XDrawRectangle(display,Cow,gc,Parc_XL-1,2*Parc_YL-Parc_YH-1,Parc_XH-Parc_XL+1,Parc_YH-Parc_YL); + XSetFont(display, gc, FixFont->fid); + +} + + +void CheckMark(int x, int y, int d) +{ + XDrawLine(display,Cow,gc,x+2,y+2,x+d-1,y+d-1); + XDrawLine(display,Cow,gc,x+3,y+2,x+d-1,y+d-2); + XDrawLine(display,Cow,gc,x+2,y+3,x+d-2,y+d-1); + + XDrawLine(display,Cow,gc,x+d-1,y+1,x+2,y+d-2); + XDrawLine(display,Cow,gc,x+d-2,y+1,x+2,y+d-3); + XDrawLine(display,Cow,gc,x+d-1,y+2,x+3,y+d-2); +} + + +void ShowWindowStatus(void) +{ + char *cp; + char Text[80]; + int len,w,x,d; + + XSetFont(display, gc, FixFont->fid); + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,Grey.pixel); + x = Wbox_XL; + d = FixFontHeight; + for (w=0 ; w < NumWin ; ++w) + { + strncpy(Text,WindowTitle[w]+wto,40); + Text[40] = 0; + cp = strstr(Text,"Level"); + if (cp) *cp = 0; + cp = strstr(Text,"Latitude"); + if (cp) *cp = 0; + len = strlen(Text); + XDrawImageString(display,Cow,gc,x+20,(w+1) * d,Text,len); + } + XSetForeground(display,gc,WhitePix); + for (w=0 ; w < NumWin ; ++w) + { + XFillRectangle(display,Cow,gc,x,w*d,d,d); + } + XSetForeground(display,gc,BlackPix); + for (w=0 ; w < NumWin ; ++w) + { + XDrawRectangle(display,Cow,gc,x,w*d,d,d); + } + for (w=0 ; w < NumWin ; ++w) + if (Win[w]) CheckMark(x,w*d,d); +} + + +void ShowGridStatus(void) +{ + int x,y,d; + + d = FixFontHeight; + x = Grid_XL; + y = Grid_YL; + XSetFont(display, gc, FixFont->fid); + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,Grey.pixel); + XDrawImageString(display,Cow,gc,Grid_XH+FixFontWidth,Grid_YH,"Grid",4); + XSetForeground(display,gc,WhitePix); + XFillRectangle(display,Cow,gc,x,Grid_YL,d,d); + XSetForeground(display,gc,BlackPix); + XDrawRectangle(display,Cow,gc,x,Grid_YL,d,d); + + if (Grid) CheckMark(x,y,d); +} + + +int RedrawControlWindow(void) +{ + char Text[80]; + int status,WinXSize,WinYSize,font_height,width,len; + int i,j,x1,x2,y1,y2,y3; + XWindowAttributes CurAtt; + + status = XGetWindowAttributes(display,Cow,&CurAtt); + WinXSize = CurAtt.width; + WinYSize = CurAtt.height; + + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,WhitePix); + + XSetWindowBackground(display,Cow,Grey.pixel); + XClearWindow(display,Cow); + + /* Red stop button */ + + XSetForeground(display,gc,Red.pixel); + XFillPolygon(display,Cow,gc,StopButton,4,Convex,CoordModeOrigin); + XSetForeground(display,gc,WhitePix); + x1 = StopButton[0].x ; + y1 = StopButton[0].y ; + for (j=0 ; j < PSDIM ; ++j) + for (i=0 ; i < PSDIM ; ++i) + if (pixelstar[j][i] == '*') + XDrawPoint(display,Cow,gc,i+x1,j+y1); + + XSetForeground(display,gc,LightRed.pixel); + x1 = 10; x2 = 40 ; y1 = OffsetY + 10 ; y2 = OffsetY + 40; + XDrawLine(display,Cow,gc,x2 ,y1-1,x2 ,y2 ); + XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1); + XDrawLine(display,Cow,gc,x1-1,y1-1,x2 ,y1-1); + XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2); + XSetForeground(display,gc,DarkRed.pixel); + XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2 ); + XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1); + XDrawLine(display,Cow,gc,x1-1,y2 ,x2 ,y2 ); + XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1); + + // Green <play> button + + XSetForeground(display,gc,Green.pixel); + XFillPolygon(display,Cow,gc,StartButton,3,Convex,CoordModeOrigin); + x1 = 50; x2 = 80 ; y1 = OffsetY + 10 ; y2 = OffsetY + 25; y3 = OffsetY + 40; + XSetForeground(display,gc,LightGreen.pixel); + XDrawLine(display,Cow,gc,x1 ,y1-1,x2 ,y2 ); + XDrawLine(display,Cow,gc,x1 ,y1-2,x2+1,y2 ); + XSetForeground(display,gc,DarkGreen.pixel); + XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y3+1); + XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y3+2); + + // Blue <pause> button + + XSetForeground(display,gc,Blue.pixel); + XFillPolygon(display,Cow,gc,PauseButton1,4,Convex,CoordModeOrigin); + XFillPolygon(display,Cow,gc,PauseButton2,4,Convex,CoordModeOrigin); + + x1 = 95; x2 = 102; y1 = OffsetY + 10; y2 = OffsetY + 40; + XSetForeground(display,gc,DarkBlue.pixel); + XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2 ); + XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1); + XDrawLine(display,Cow,gc,x1-1,y2 ,x2 ,y2 ); + XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1); + XSetForeground(display,gc,LightBlue.pixel); + XDrawLine(display,Cow,gc,x2 ,y1-1,x2 ,y2 ); + XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1); + XDrawLine(display,Cow,gc,x1-1,y1-1,x2 ,y1-1); + XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2); + + x1 = 108; x2 = 115; y1 = OffsetY + 10; y2 = OffsetY + 40; + XSetForeground(display,gc,DarkBlue.pixel); + XDrawLine(display,Cow,gc,x1-1,y1-1,x1-1,y2 ); + XDrawLine(display,Cow,gc,x1-2,y1-2,x1-2,y2+1); + XDrawLine(display,Cow,gc,x1-1,y2 ,x2 ,y2 ); + XDrawLine(display,Cow,gc,x1-2,y2+1,x2+1,y2+1); + XSetForeground(display,gc,LightBlue.pixel); + XDrawLine(display,Cow,gc,x2 ,y1-1,x2 ,y2 ); + XDrawLine(display,Cow,gc,x2+1,y1-2,x2+1,y2+1); + XDrawLine(display,Cow,gc,x1-1,y1-1,x2 ,y1-1); + XDrawLine(display,Cow,gc,x2+1,y2-2,x2+1,y1-2); + + // Help button + + x1 = 200; x2 = x1 + 5 * BigFontWidth; y1 = OffsetY + 10; y2 = y1 + 30; + XSetForeground(display,gc,Red.pixel); + XFillRectangle(display,Cow,gc,x1,y1,x2-x1,y2-y1); + XSetForeground(display,gc,BlackPix); + XDrawRectangle(display,Cow,gc,x1-1,y1-1,x2-x1+1,y2-y1+1); + XSetFont(display,gc,BigFont->fid); + XSetForeground(display,gc,Yellow.pixel); + XSetBackground(display,gc,Red.pixel); + XDrawImageString(display,Cow,gc,x1+BigFontWidth/2,(y1+y2)/2+BigFont->ascent/2,"HELP",4); + + ShowStep(); + ShowParcs(); + ShowWindowStatus(); + ShowGridStatus(); + return 0; +} + + +void ClearTracer(void) +{ + int j; + for (j=0 ; j < MAXPAR ; ++j) + { + pax[j] = -1.0; + pay[j] = -1.0; + } +} + + +int CheckEndianess(void) +{ + union EndianCheck + { + char b[sizeof(int)]; + int i; + } ec; + + ec.i = 8; + return (ec.b[0] == 0); +} + + +void initgui_(int *model, int *debug, int *lats, int *mrpid, int *mrnum, char *plan) +{ + int x,y,w,h; + int argc = 1; + int i,j; + unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ + XGCValues values; + XEvent Event; + struct timeval TimeVal; + + // Check for big endian computer + // The bitmap format ".bmp" ist little endian + + BigEndian = CheckEndianess(); + + // Set seed for random number generator from clock + + gettimeofday(&TimeVal,NULL); + Seed = TimeVal.tv_sec; + + Model = *model; + Debug = *debug; + Latitudes = *lats; + MRpid = *mrpid; + MRnum = *mrnum; + strncpy(PlanetName,plan,sizeof(PlanetName)-1); + + if (MRpid >= 0) + { + sprintf(wtrun,"[%d] ",MRpid); + wto = strlen(wtrun); + } + + if (Debug) printf("initgui(%d,%d)\n",Model,Debug); + if ((display=XOpenDisplay(display_name)) == NULL) + { + fprintf(stderr,"%s: cannot connect to X server %s\n", + progname, XDisplayName(display_name)); + exit(1); + } + screen_num = DefaultScreen(display); + ScreenD = XDefaultDepth(display,screen_num); + ScreenW = DisplayWidth (display,screen_num); + ScreenH = DisplayHeight(display,screen_num); + BlackPix = BlackPixel(display,screen_num); + WhitePix = WhitePixel(display,screen_num); + SmallScreen = ScreenH <= 768; + if (SmallScreen) + { + WinRows = 2; + NumWin = WinCols * WinRows; + Grid = 0; + } + + if (MRnum == 2) ScreenW /= 2; /* Run with two GUI's */ + + /* Fix defaults for multihead displays */ + + if (ScreenH > ScreenW && ScreenH > 1200) ScreenH = 1200; + if (ScreenW > 2 * ScreenH && ScreenW >= 2048) ScreenW /= 2; + + for (i = 0 ; i < NUMWIN ; ++i) + { + WindowTitle[i] = CharAlloc(256,"WindowTitle"); + if (wto == 0) sprintf(WindowTitle[i],"Window %d",i+1); + else sprintf(WindowTitle[i],"%sWindow %d",wtrun,i+1); + WinAtt[i].x = -1; + WinAtt[i].y = -1; + WinAtt[i].w = -1; + WinAtt[i].h = -1; + WinAtt[i].active = 1; + } + + CreateTestWindow(); + + if (MRpid >= 0) sprintf(GUI_default,"GUI_%2.2d.cfg",MRpid); + ReadConfig(GUI_default); + if (MRpid >= 0) sprintf(GUI_config,"GUI_last_used_%2.2d.cfg",MRpid); + ReadConfig(GUI_config); + + LoadFonts(); + CreateControlWindow(); + + OutXSize = (ScreenW-ScreenOffset) / WinCols; + OutYSize = (CowY-ScreenOffset-1-WM_top_area) / WinRows; + WinXSize = OutXSize - WinLM - WinRM; + WinYSize = OutYSize - WinTM - WinBM; + WinSizeHints.flags = PPosition | PSize | PMinSize; + WinSizeHints.min_width = 200; + WinSizeHints.min_height = 100; + if (Debug) + { + printf("Outer windowsize = %dx%d\n",OutXSize,OutYSize); + printf("Inner windowsize = %dx%d\n",WinXSize,WinYSize); + } + + wm_hints.initial_state = NormalState; + wm_hints.input = True; + wm_hints.flags = StateHint | InputHint; + + class_hints.res_name = progname; + class_hints.res_class = "PUMA"; + + Delwin = XInternAtom(display,"WM_DELETE_WINDOW",0); + + ReadImage(&MapHR,"map.bmp"); + + for (i = 0 ; i < NumWin ; ++i) + { + x = WinAtt[i].x; + y = WinAtt[i].y; + w = WinAtt[i].w; + h = WinAtt[i].h; + + if (x < ScreenOffset || x >= ScreenW) x = ScreenOffset+(i%WinCols)*OutXSize; + if (y < ScreenOffset || y >= ScreenH) y = ScreenOffset+(i/WinCols)*OutYSize+WM_top_area; + if (w < WinSizeHints.min_width ) w = WinXSize; + if (h < WinSizeHints.min_height) h = WinYSize; + XStringListToTextProperty(&WindowTitle[i],1,WindowName+i); + if (WinAtt[i].active) + { + if (MRnum == 2 && MRpid == 1) x += ScreenW; + Win[i] = XCreateWindow(display,RootWindow(display,screen_num), // display, parent + x,y,w,h, + BorderWidth,CopyFromParent,InputOutput, // border, depth, class + CopyFromParent,0,NULL); // visual, valuemask, attributes + XSetWMProtocols(display,Win[i],&Delwin,1); + XSetWMProperties(display,Win[i],WindowName+i,NULL, + NULL,0,&WinSizeHints,&wm_hints,&class_hints); + XSelectInput(display,Win[i],ButtonPressMask | KeyPressMask | ExposureMask); + XMapWindow(display,Win[i]); + } + } + + /* Prepare GC */ + + gc = XCreateGC(display, Cow, valuemask, &values); + XSetFont(display, gc, FixFont->fid); + colormap = XDefaultColormap(display,screen_num); + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,WhitePix); + + /* Get keyboard information */ + + XDisplayKeycodes(display,&FirstKey,&LastKey); + KeyMap = XGetKeyboardMapping(display,FirstKey,LastKey-FirstKey+1,&SymsPerKey); + + /* Allocate color cells */ + + for (i=0 ; i < NUMPAL ; ++i) + LineCo[i] = AllocateColorCells(Pallet[i]); + + /* Color cells for control window */ + + XAllocNamedColor(display,colormap,"red" ,&Red ,&Dummy); + XAllocNamedColor(display,colormap,"green" ,&Green ,&Dummy); + XAllocNamedColor(display,colormap,"blue" ,&Blue ,&Dummy); + XAllocNamedColor(display,colormap,"grey" ,&Grey ,&Dummy); + XAllocNamedColor(display,colormap,"yellow" ,&Yellow ,&Dummy); + XAllocNamedColor(display,colormap,"hot pink" ,&LightRed ,&Dummy); + XAllocNamedColor(display,colormap,"dark red" ,&DarkRed ,&Dummy); + XAllocNamedColor(display,colormap,"light blue" ,&LightBlue ,&Dummy); + XAllocNamedColor(display,colormap,"dark blue" ,&DarkBlue ,&Dummy); + XAllocNamedColor(display,colormap,"light green",&LightGreen,&Dummy); + XAllocNamedColor(display,colormap,"dark green" ,&DarkGreen ,&Dummy); + + TSColor[0] = Red.pixel; + TSColor[1] = Green.pixel; + TSColor[2] = Blue.pixel; + TSColor[3] = WhitePix; + TSColor[4] = LightRed.pixel; + TSColor[5] = Grey.pixel; + TSColor[6] = Yellow.pixel; + TSColor[7] = LightBlue.pixel; + TSColor[8] = LightGreen.pixel; + + ClearTracer(); + CalcButtonAreas(); + RedrawControlWindow(); + XSync(display,0); +} + +void FillPoly(int n, REAL Poly[]) +{ + int i; + XPoint xpol[8]; + for (i=0; i < n ; ++i) + { + xpol[i].x = OffX + Poly[i+i ] + 0.5; + xpol[i].y = OffY + Poly[i+i+1] + 0.5; + } + XFillPolygon(display,pix,gc,xpol,n,Convex,CoordModeOrigin); +} + +/* ======= */ +/* IsoArea */ +/* ======= */ + +void IsoArea(INT y, REAL vl, REAL vh, REAL Top[], REAL Bot[], INT Dim) +{ + INT f,x,p; + REAL xl,xr,yt,yb; + REAL Poly[16]; + + // if (Debug) printf("IsoArea %d %10.2f %10.2f %10.2f %10.2f %d\n",y,vl,vh,Top[0],Bot[0],Dim); + for (x=0 ; x < Dim-1 ; x++) + { + Flag[x] = 0; + if (Top[x ] < vl) Flag[x] |= TOLELO; + if (Top[x ] >= vh) Flag[x] |= TOLEHI; + if (Top[x+1] < vl) Flag[x] |= TORILO; + if (Top[x+1] >= vh) Flag[x] |= TORIHI; + if (Bot[x ] < vl) Flag[x] |= BOLELO; + if (Bot[x ] >= vh) Flag[x] |= BOLEHI; + if (Bot[x+1] < vl) Flag[x] |= BORILO; + if (Bot[x+1] >= vh) Flag[x] |= BORIHI; + } + + x = 0; + + while (x < Dim-1) + { + xl = VGAX * x ; + xr = VGAX * (x+1); + yt = VGAY * y ; + yb = VGAY * (y+1); + f = Flag[x]; + + if (f == 0) + { + x++; + while (x < Dim-1 && Flag[x] == 0) + { + x++; + xr = VGAX * x; + } + Poly[0] = Poly[6] = xl; + Poly[1] = Poly[3] = yt; + Poly[2] = Poly[4] = xr; + Poly[5] = Poly[7] = yb; + + FillPoly(4,Poly); + + } + else if (f == (TOLELO | TORILO | BOLELO | BORILO) || + f == (TOLEHI | TORIHI | BOLEHI | BORIHI)) x++; + else if (Top[x] < vl && Top[x+1] >= vl && Bot[x] >= vl && Bot[x+1] < vl) + { + Poly[1] = Poly[3] = yt; + Poly[2] = Poly[4] = xr; + Poly[0] = IPX(Top[x ],vl,Top[x+1]); + Poly[5] = IPY(Top[x+1],vl,Bot[x+1]); + FillPoly(3,Poly); + Poly[1] = Poly[3] = yb; + Poly[2] = Poly[4] = xl; + Poly[0] = IPX(Bot[x ],vl,Bot[x+1]); + Poly[5] = IPY(Top[x ],vl,Bot[x ]); + FillPoly(3,Poly); + ++x; + } + else if (Top[x] >= vl && Top[x+1] < vl && Bot[x] < vl && Bot[x+1] >= vl) + { + Poly[0] = Poly[4] = xl; + Poly[1] = Poly[3] = yt; + Poly[2] = IPX(Top[x ],vl,Top[x+1]); + Poly[5] = IPY(Top[x ],vl,Bot[x ]); + FillPoly(3,Poly); + Poly[0] = Poly[2] = xr; + Poly[3] = Poly[5] = yb; + Poly[1] = IPY(Top[x+1],vl,Bot[x+1]); + Poly[4] = IPX(Bot[x ],vl,Bot[x+1]); + FillPoly(3,Poly); + ++x; + } + else + { + p = 0; + + if (Top[x] < vl) + { + if (Top[x+1] >= vl) + { + Poly[p++] = IPX(Top[x],vl,Top[x+1]); + Poly[p++] = yt; + } + + if (Top[x+1] >= vh) + { + Poly[p++] = IPX(Top[x],vh,Top[x+1]); + Poly[p++] = yt; + } + } + else if (Top[x] >= vh) + { + if (Top[x+1] < vh) + { + Poly[p++] = IPX(Top[x],vh,Top[x+1]); + Poly[p++] = yt; + } + if (Top[x+1] < vl) + { + Poly[p++] = IPX(Top[x],vl,Top[x+1]); + Poly[p++] = yt; + } + } + else + { + Poly[p++] = xl; + Poly[p++] = yt; + if (Top[x+1] < vl) + { + Poly[p++] = IPX(Top[x],vl,Top[x+1]); + Poly[p++] = yt; + } + if (Top[x+1] >= vh) + { + Poly[p++] = IPX(Top[x],vh,Top[x+1]); + Poly[p++] = yt; + } + } + + if (Top[x+1] < vl) + { + if (Bot[x+1] >= vl) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]); + } + + if (Bot[x+1] >= vh) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]); + } + } + else if (Top[x+1] >= vh) + { + if (Bot[x+1] < vh) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]); + } + if (Bot[x+1] < vl) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]); + } + } + else + { + Poly[p++] = xr; + Poly[p++] = yt; + if (Bot[x+1] < vl) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vl,Bot[x+1]); + } + if (Bot[x+1] >= vh) + { + Poly[p++] = xr; + Poly[p++] = IPY(Top[x+1],vh,Bot[x+1]); + } + } + + if (Bot[x+1] < vl) + { + if (Bot[x] >= vl) + { + Poly[p++] = IPX(Bot[x],vl,Bot[x+1]); + Poly[p++] = yb; + } + if (Bot[x] >= vh) + { + Poly[p++] = IPX(Bot[x],vh,Bot[x+1]); + Poly[p++] = yb; + } + } + else if (Bot[x+1] >= vh) + { + if (Bot[x] < vh) + { + Poly[p++] = IPX(Bot[x],vh,Bot[x+1]); + Poly[p++] = yb; + } + if (Bot[x] < vl) + { + Poly[p++] = IPX(Bot[x],vl,Bot[x+1]); + Poly[p++] = yb; + } + } + else + { + Poly[p++] = xr; + Poly[p++] = yb; + if (Bot[x] < vl) + { + Poly[p++] = IPX(Bot[x],vl,Bot[x+1]); + Poly[p++] = yb; + } + if (Bot[x] >= vh) + { + Poly[p++] = IPX(Bot[x],vh,Bot[x+1]); + Poly[p++] = yb; + } + } + + if (Bot[x] < vl) + { + if (Top[x] >= vl) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vl,Bot[x]); + } + + if (Top[x] >= vh) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vh,Bot[x]); + } + } + else if (Bot[x] >= vh) + { + if (Top[x] < vh) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vh,Bot[x]); + } + if (Top[x] < vl) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vl,Bot[x]); + } + } + else + { + Poly[p++] = xl; + Poly[p++] = yb; + if (Top[x] < vl) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vl,Bot[x]); + } + if (Top[x] >= vh) + { + Poly[p++] = xl; + Poly[p++] = IPY(Top[x],vh,Bot[x]); + } + } + FillPoly(p>>1,Poly); + x++; + } + } +} + + +/* ======= */ +/* isoarea */ +/* ======= */ + +void IsoAreas(struct ColorStrip Strip[]) +{ + INT i; + INT y; + REAL *Top; + REAL *Bot; + + i = 0; + while (Strip[i].Name) + { + Top = Field; + Bot = Field + DimX; + XSetForeground(display,gc,Strip[i].pixel); + for (y = 0 ; y < DimY-1 ; y++) + { + IsoArea(y,Strip[i].Lo,Strip[i].Hi,Top,Bot,DimX); + Top += DimX; + Bot += DimX; + } + ++i; + } +} + +/* ======= */ +/* IsoLine */ +/* ======= */ + +void IsoLine(INT y, REAL v, REAL Top[], REAL Bot[], INT Dim) +{ + INT f,x; + REAL xl,xr,yt,yb; + REAL x1,yo,x2,y2,x3,y3,x4,y4; + + for (x=0 ; x < Dim-1 ; x++) + { + Flag[x] = 0; + if (Top[x ] < v) Flag[x] |= TOLELO; + else Flag[x] |= TOLEHI; + if (Top[x+1] < v) Flag[x] |= TORILO; + else Flag[x] |= TORIHI; + if (Bot[x ] < v) Flag[x] |= BOLELO; + else Flag[x] |= BOLEHI; + if (Bot[x+1] < v) Flag[x] |= BORILO; + else Flag[x] |= BORIHI; + } + + x = 0; + + while (x < Dim-1) + { + xl = VGAX * x ; + xr = VGAX * (x+1); + yt = VGAY * y ; + yb = VGAY * (y+1); + f = Flag[x]; + + if (f == 0 || f == (TOLELO | TORILO | BOLELO | BORILO) || + f == (TOLEHI | TORIHI | BOLEHI | BORIHI)) x++; + else if (f == (TOLELO | BORILO | TORIHI | BOLEHI)) + { + x1 = IPX(Top[x ],v,Top[x+1]); + yo = yt; + x2 = xr; + y2 = IPY(Top[x+1],v,Bot[x+1]); + x3 = IPX(Bot[x ],v,Bot[x+1]); + y3 = yb; + x4 = xl; + y4 = IPY(Top[x ],v,Bot[x ]); + XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2); + XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4); + ++x; + } + else if (f == (TORILO | BOLELO | TOLEHI | BORIHI)) + { + x1 = xl; + yo = IPY(Top[x ],v,Bot[x ]); + x2 = IPX(Top[x ],v,Top[x+1]); + y2 = yt; + x3 = xr; + y3 = IPY(Top[x+1],v,Bot[x+1]); + x4 = IPX(Bot[x ],v,Bot[x+1]); + y4 = yb; + XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2); + XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4); + ++x; + } + else + { + x1 = x2 = x3 = x4 = -1; + + if ((Top[x ] < v && Top[x+1] >= v) || (Top[x ] >= v && Top[x+1] < v)) + { + x1 = IPX(Top[x ],v,Top[x+1]); + yo = yt; + } + if ((Top[x+1] < v && Bot[x+1] >= v) || (Top[x+1] >= v && Bot[x+1] < v)) + { + x2 = xr; + y2 = IPY(Top[x+1],v,Bot[x+1]); + } + if ((Bot[x+1] < v && Bot[x ] >= v) || (Bot[x+1] >= v && Bot[x ] < v)) + { + x3 = IPX(Bot[x ],v,Bot[x+1]); + y3 = yb; + } + if ((Bot[x ] < v && Top[x ] >= v) || (Bot[x ] >= v && Top[x ] < v)) + { + x4 = xl; + y4 = IPY(Top[x ],v,Bot[x ]); + } + + if (x1 >= 0 && x2 >= 0 && x3 >= 0 && x4 >= 0) + { + XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2); + XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4); + } + else if (x1 >= 0) + { + if (x2 >= 0) XDrawLine(display,pix,gc,x1,OffY+yo,x2,OffY+y2); + else if (x3 >= 0) XDrawLine(display,pix,gc,x1,OffY+yo,x3,OffY+y3); + else XDrawLine(display,pix,gc,x1,OffY+yo,x4,OffY+y4); + } + else if (x2 >= 0) + { + if (x3 >= 0) XDrawLine(display,pix,gc,x2,OffY+y2,x3,OffY+y3); + else XDrawLine(display,pix,gc,x2,OffY+y2,x4,OffY+y4); + } + else XDrawLine(display,pix,gc,x3,OffY+y3,x4,OffY+y4); + + x++; + } + } +} + + +/* ======== */ +/* IsoLines */ +/* ======== */ + +void IsoLines(struct ColorStrip Strip[],int Colored) +{ + INT i; + INT y; + REAL *Top; + REAL *Bot; + + XSetForeground(display,gc,BlackPix); + i = 0; + while (Strip[i].Name) + { + Top = Field; + Bot = Field + DimX; + if (Colored) XSetForeground(display,gc,Strip[i].pixel); + for (y = 0 ; y < DimY-1 ; y++) + { + IsoLine(y,Strip[i].Lo,Top,Bot,DimX); + Top += DimX; + Bot += DimX; + } + ++i; + } +} + +int AziPoint(int fpx, int fpy, int *x2, int *y2) +{ + int xc,yc; + double flam,fsin,fcos,roa,pil,piy; + + xc = InXSize >> 1; + yc = InYSize >> 1; + roa = MapLR[win].l * InXSize / 360.0; + pil = 2.0 * M_PI / InXSize; + piy = M_PI / InYSize; + + flam = (fpx - xc - roa) * pil; + if (flam < -M_PI) flam += 2.0 * M_PI; + if (flam > M_PI) flam -= 2.0 * M_PI; + if (flam < -M_PI_2 || flam > M_PI_2) return 1; + fsin = sin(flam); + fcos = cos((fpy-yc) * piy); + *x2 = xc + InYSize/2 * fcos * fsin; + *y2 = yc + InYSize/2 * sin((fpy-yc) * piy); + return 0; +} + +void AziLine(int x1, int y1, int x2, int y2) +{ + int a1,b1,a2,b2; + + if (AziPoint(x1,y1,&a1,&b1)) return; + if (AziPoint(x2,y2,&a2,&b2)) return; + XDrawLine(display,pix,gc,a1,b1,a2,b2); +} + + +/* ======= */ +/* MapLine */ +/* ======= */ + +void MapLine(INT y, REAL v, REAL Top[], REAL Bot[], INT Dim) +{ + INT f,x; + REAL xl,xr,yt,yb; + REAL x1,yo,x2,y2,x3,y3,x4,y4; + + for (x=0 ; x < Dim-1 ; x++) + { + Flag[x] = 0; + if (Top[x ] < v) Flag[x] |= TOLELO; + else Flag[x] |= TOLEHI; + if (Top[x+1] < v) Flag[x] |= TORILO; + else Flag[x] |= TORIHI; + if (Bot[x ] < v) Flag[x] |= BOLELO; + else Flag[x] |= BOLEHI; + if (Bot[x+1] < v) Flag[x] |= BORILO; + else Flag[x] |= BORIHI; + } + + x = 0; + + while (x < Dim-1) + { + xl = VGAX * x ; + xr = VGAX * (x+1); + yt = VGAY * y ; + yb = VGAY * (y+1); + f = Flag[x]; + + if (f == 0 || f == (TOLELO | TORILO | BOLELO | BORILO) || + f == (TOLEHI | TORIHI | BOLEHI | BORIHI)) x++; + else if (f == (TOLELO | BORILO | TORIHI | BOLEHI)) + { + x1 = IPX(Top[x ],v,Top[x+1]); + yo = yt; + x2 = xr; + y2 = IPY(Top[x+1],v,Bot[x+1]); + x3 = IPX(Bot[x ],v,Bot[x+1]); + y3 = yb; + x4 = xl; + y4 = IPY(Top[x ],v,Bot[x ]); + AziLine(x1,OffY+yo,x2,OffY+y2); + AziLine(x3,OffY+y3,x4,OffY+y4); + ++x; + } + else if (f == (TORILO | BOLELO | TOLEHI | BORIHI)) + { + x1 = xl; + yo = IPY(Top[x ],v,Bot[x ]); + x2 = IPX(Top[x ],v,Top[x+1]); + y2 = yt; + x3 = xr; + y3 = IPY(Top[x+1],v,Bot[x+1]); + x4 = IPX(Bot[x ],v,Bot[x+1]); + y4 = yb; + AziLine(x1,OffY+yo,x2,OffY+y2); + AziLine(x3,OffY+y3,x4,OffY+y4); + ++x; + } + else + { + x1 = x2 = x3 = x4 = -1; + + if ((Top[x ] < v && Top[x+1] >= v) || (Top[x ] >= v && Top[x+1] < v)) + { + x1 = IPX(Top[x ],v,Top[x+1]); + yo = yt; + } + if ((Top[x+1] < v && Bot[x+1] >= v) || (Top[x+1] >= v && Bot[x+1] < v)) + { + x2 = xr; + y2 = IPY(Top[x+1],v,Bot[x+1]); + } + if ((Bot[x+1] < v && Bot[x ] >= v) || (Bot[x+1] >= v && Bot[x ] < v)) + { + x3 = IPX(Bot[x ],v,Bot[x+1]); + y3 = yb; + } + if ((Bot[x ] < v && Top[x ] >= v) || (Bot[x ] >= v && Top[x ] < v)) + { + x4 = xl; + y4 = IPY(Top[x ],v,Bot[x ]); + } + + if (x1 >= 0 && x2 >= 0 && x3 >= 0 && x4 >= 0) + { + AziLine(x1,OffY+yo,x2,OffY+y2); + AziLine(x3,OffY+y3,x4,OffY+y4); + } + else if (x1 >= 0) + { + if (x2 >= 0) AziLine(x1,OffY+yo,x2,OffY+y2); + else if (x3 >= 0) AziLine(x1,OffY+yo,x3,OffY+y3); + else AziLine(x1,OffY+yo,x4,OffY+y4); + } + else if (x2 >= 0) + { + if (x3 >= 0) AziLine(x2,OffY+y2,x3,OffY+y3); + else AziLine(x2,OffY+y2,x4,OffY+y4); + } + else AziLine(x3,OffY+y3,x4,OffY+y4); + + x++; + } + } +} + + +/* ======== */ +/* MapLines */ +/* ======== */ + +void MapLines(struct ColorStrip Strip[],int Colored) +{ + INT i; + INT y; + REAL *Top; + REAL *Bot; + + XSetForeground(display,gc,BlackPix); + i = 0; + while (Strip[i].Name) + { + Top = Field; + Bot = Field + DimX; + if (Colored) XSetForeground(display,gc,Strip[i].pixel); + for (y = 0 ; y < DimY-1 ; y++) + { + MapLine(y,Strip[i].Lo,Top,Bot,DimX); + Top += DimX; + Bot += DimX; + } + ++i; + } +} + +int polco = 0; + +void poltra(float lam, float phi, float *x, float *y) +{ + REAL xnp,ynp,xsp,ysp,lfa; + + lfa = (2.0 * M_PI) / (InXSize-1) ; + xnp = (InXSize-1) * 0.25; + ynp = (InYSize-1) * 0.50; + xsp = (InXSize-1) * 0.75; + ysp = ynp; + + /* Northern hemisphere */ + + if (phi < ynp) + { + *x = xnp + sin(lam * lfa) * phi; + *y = ynp + cos(lam * lfa) * phi; + } + + /* Souhern hemisphere */ + + else + { + *x = xsp - sin(lam * lfa) * (phi-ysp); + *y = ysp + cos(lam * lfa) * (phi-ysp); + } +} + + +/* ========== */ +/* TracerPlot */ +/* ========== */ + +void TracerPlot(int w) +{ + int j,ipx,ipy,lpy,lpx,jx,jy,ic,ix,iy,ipr; + int xnp,ynp,xsp,ysp,xc,yc; + float *u; + float *v; + float fpx,fpy,du,dv,ppx,ppy,rx,ry,spfac; + float lfa,lam,phi,hpy,fcos,fsin; + float pil,piy; + float roa; + float flam; + float dpx,dpy; + float rary,alpy; + + if (Uindex < 0 || Vindex < 0) return; // Data missing + + Delpar = (8 * 60) / DeltaTime; // Injection interval + if (LevelChanged[w]) ClearTracer(); + LevelChanged[w] = 0; + if (!SpeedScale) SpeedScale = FloatAlloc(DimY,"SpeedScale"); + u = Array[Uindex].Data + Indez[w] * DimXY; + v = Array[Vindex].Data + Indez[w] * DimXY; + + TracerColor = Yellow.pixel; + if (nstep % (8*Delpar) == 0) ColInd++; + if (ColInd >= AUTOCOLORS) ColInd = 0; + TracerColor = Autostrip[ColInd].pixel; + + dpx = (float)(InXSize-1) / (float)(DimX-1); + dpy = (float)(InYSize-1) / (float)(DimY-1); + lpx = InXSize; + lpy = InYSize; + hpy = 0.5 * dpy; + xc = lpx / 2; + yc = lpy / 2; + pil = 2.0 * M_PI / lpx; + piy = M_PI / lpy; + roa = MapLR[w].l * lpx / 360.0; + rary = 1.0 / ary; + alpy = rary * lpy; + ipr = rary * InYSize / 80.0; // Size of tracer dots + + // Compute scale factors + + if (SizeChanged || nstep < 10) + { + for (j=0 ; j < DimY; ++j) + { + SpeedScale[j] = InXSize * DeltaTime * 60.0 / 40000000.0 + / cos((j-0.5*(DimY-1)) * (M_PI/DimY)); + } + SpeedScale[DimY-1] = SpeedScale[0] = SpeedScale[1]; + } + + // Insert new particles + + if (nstep % Delpar == 0) + { + fpx = dpx * (DimX-1) / 2.0; + for (ipy = 0 ; ipy < lpy ; ipy += dpy) + { + ParInd = (ParInd+1) & (MAXPAR-1); + pax[ParInd] = fpx; + pay[ParInd] = ipy + hpy; + pal[ParInd] = TracerColor; + } + } + + // Move particles + + for (j=0 ; j < MAXPAR ; ++j) + if (pax[j] >= 0.0 && pay[j] >= 0.0) + { + jx = rx = pax[j] / dpx; + jy = ry = pay[j] / dpy; + ic = jx + DimX * jy; + ix = ic + 1; + if (jx >= DimX-1) ix -= DimX; + iy = ic + DimX; + if (iy >= DimX * DimY) iy -= DimX; + rx -= jx; + ry -= jy; + + du = u[ic]+(u[ix]-u[ic])*rx+(u[iy]-u[ic])*ry; + dv = v[ic]+(v[ix]-v[ic])*rx+(v[iy]-v[ic])*ry; + spfac = SpeedScale[jy] + (SpeedScale[jy+1]-SpeedScale[jy]) * ry; + du *= spfac; + dv *= spfac; + fpx = pax[j] + du; + fpy = pay[j] + dv; + if (fpx < 0.0) fpx += lpx; + if (fpx >= lpx) fpx -= lpx; + if (fpy < 0.0 || fpy > lpy-1) + { + pay[j] = -1.0; + continue; + } + pax[j] = fpx; + pay[j] = fpy; + ipx = -1; + if (MapPro[w] == POLAR) + { + lfa = (2.0 * M_PI) / lpx; + xnp = (InXSize-1) * 0.25; + ynp = (InYSize-1) * 0.50; + xsp = (InXSize-1) * 0.75; + ysp = ynp; + lam = fpx; + phi = fpy * rary; + if (fpy < 0.5 * lpy) /* Northern hemisphere */ + { + fpx = xnp - sin(lam * lfa) * (phi + hpy); + fpy = ynp - cos(lam * lfa) * (phi + hpy); + } + else /* Souhern hemisphere */ + { + fpx = xsp + sin(lam * lfa) * (alpy - phi + hpy); + fpy = ysp - cos(lam * lfa) * (alpy - phi + hpy); + } + ipx = rintf(fpx); + ipy = rintf(fpy); + } + else if (MapPro[w] == AZIMUTHAL) + { + flam = (fpx - xc - roa) * pil; + if (flam < -M_PI) flam += 2.0 * M_PI; + if (flam > M_PI) flam -= 2.0 * M_PI; + if (flam < -M_PI_2 || flam > M_PI_2) continue; + fsin = sin(flam); + fcos = cos((fpy-yc) * piy); + fpx = xc + lpy/2 * fcos * fsin; + fpy = yc + lpy/2 * sin((fpy-yc) * piy); + ipx = rintf(fpx); + ipy = rintf(fpy); + } + else + { + ipx = rintf(fpx); + ipy = rintf(fpy); + } + if (ipx >= 0) + { + XSetForeground(display,gc,pal[j]); + if (ipr < 2) XDrawPoint(display,pix,gc,ipx,ipy); + else if (ipr == 2) XFillRectangle(display,pix,gc,ipx,ipy,2,2); + else XFillArc(display,pix,gc,ipx,ipy,ipr,ipr,0,360*64); + } + } +} + + +/* ============= */ +/* AmplitudePlot */ +/* ============= */ + +void AmplitudePlot(void) +{ + int i,j,m,n; + int x,y; + int r,dx,dy; + int mmax; + int imax; + REAL Amax,Fac; + + if (!Ampli) Ampli = FloatAlloc(DimX,"Ampli"); + if (!Acol ) Acol = SizeAlloc(DimX,sizeof(XColor),"Acol"); + + Amax = 0.0; + imax = 0; + for (i=0 ; i < DimX ; ++i) + { + Ampli[i] = log (1.0 + sqrt(Field[2*i]*Field[2*i]+Field[2*i+1]*Field[2*i+1])); + Acol[i].pixel = WhitePix; + if (Ampli[i] > Amax && i > DimY) + { + Amax = Ampli[i]; + imax = i; + } + } + + Fac = 0.0; + if (Amax > 1.e-20) Fac = 1.0 / Amax; + for (i=0 ; i < DimX ; ++i) + { + j = AMPLI_COLS * Ampli[i] * Fac; + if (j >= AMPLI_COLS) j = AMPLI_COLS-1; + Acol[i].pixel = AmpliStrip[j].pixel; + } + + dx = WinXSize / 23; + r = (dx+dx) / 3; + mmax = (InYSize / dx) - 1; + XSetForeground(display,gc,BlackPix); + for (m=0,i=0 ; m < mmax ; ++m) + { + y = FixFontHeight + 4 + m * dx; + for (n=m ; n < DimY ; ++n,++i) + if (n < 22) + { + x = dx/2 + n * dx; + XSetForeground(display,gc,Acol[i].pixel); + XFillArc(display,pix,gc,x,y,r,r,0,360*64); + } + } +} + + +void RedrawIsoWindow(int w) +{ + if (WinPixMap[w].Pix) + XCopyArea(display,WinPixMap[w].Pix,Win[w],gc,0,0,WinPixMap[w].DimX,WinPixMap[w].DimY,0,0); +} + + +void CloseWindow(int i) +{ + INTXS X,Y,xp,yp; + unsigned int border,depth; + Window Rootwin,Child; + + if (Win[i]) + { + XGetGeometry(display,Win[i],&Rootwin,&xp,&yp,&WinAtt[i].w,&WinAtt[i].h,&border,&depth); + XTranslateCoordinates(display,Win[i],Rootwin,0,0,&X,&Y,&Child); + WinAtt[i].x = X - WinLM; + WinAtt[i].y = Y - WinTM; + XDestroyWindow(display,Win[i]); + Win[i] = 0; + ShowWindowStatus(); + } +} + +void ReopenWindow(int i) +{ + if (Win[i] == 0) + { + if (WinAtt[i].x < ScreenOffset) WinAtt[i].x = ScreenOffset + OutXSize * (i % WinCols); + if (WinAtt[i].y < ScreenOffset) WinAtt[i].y = ScreenOffset + OutYSize * (i / WinCols); + Win[i] = XCreateSimpleWindow(display,RootWindow(display,screen_num), + WinAtt[i].x,WinAtt[i].y,WinAtt[i].w,WinAtt[i].h, + BorderWidth,BlackPix,WhitePix); + XSetWMProtocols(display,Win[i],&Delwin,1); + XSetWMProperties(display,Win[i],WindowName+i,NULL, + NULL,0,&WinSizeHints,&wm_hints,&class_hints); + XSelectInput(display,Win[i],ButtonPressMask | KeyPressMask | ExposureMask); + XMapWindow(display,Win[i]); + ShowWindowStatus(); + } +} + +char *HelpText[] = +{ + "Key assignment for azimuthal projection ", + "--------------------------------------------", + "<- cursor left : increase westward rotation", + "-> cursor right : increase eastward rotation", + "============================================", + "Key assignment for 3D variables ", + "--------------------------------------------", + "^ cursor up : display next upper level ", + "v cursor down : display next lower level ", + "============================================", + "Key assignment for Lon/Lev or Hovmoeller ", + "--------------------------------------------", + "^ cursor up : switch latitude northwards", + "v cursor down : switch latitude southwards", + "============================================", + "Mouse button assignment ", + "--------------------------------------------", + "Left button : decrease level or latitude", + "Right button : increase level or latitude", + "Middle button : cycle through projections " +}; + +int HelpLines = sizeof(HelpText) / sizeof(char *); + +void DrawHelpWindow(void) +{ + int x,y,j,l; + + XSetForeground(display,gc,Yellow.pixel); + XSetBackground(display,gc,DarkBlue.pixel); + XSetFont(display,gc,BigFont->fid); + + x = BigFontWidth / 2; + for (j=0 ; j < HelpLines ; ++j) + { + y = BigFontHeight / 2 + BigFont->ascent + j * BigFontHeight; + l = strlen(HelpText[j]); + XDrawImageString(display,HelpWindow,gc,x,y,HelpText[j],l); + } +} + +void DisplayHelpWindow(void) +{ + int x,y,w,h; + char *HelpTitle = "Help"; + + w = BigFontWidth * (strlen(HelpText[0])+1); + h = BigFontHeight * (HelpLines + 1); + x = (ScreenW - w) / 2; + y = (ScreenH - h) / 2; + HelpWindow = XCreateSimpleWindow(display,RootWindow(display,screen_num), + x,y,w,h,BorderWidth,Yellow.pixel,DarkBlue.pixel); + XStringListToTextProperty(&HelpTitle,1,&HelpName); + XSetWMProtocols(display,HelpWindow,&Delwin,1); + XSetWMProperties(display,HelpWindow,&HelpName,NULL,NULL,0,NULL,NULL,NULL); + XSelectInput(display,HelpWindow,ButtonPressMask | ExposureMask); + XMapWindow(display,HelpWindow); + XMoveWindow(display,HelpWindow,x,y); + DrawHelpWindow(); +} + +int HitGridButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Grid_XL ) && + (xe->xbutton.x <= Grid_XH ) && + (xe->xbutton.y >= Grid_YL ) && + (xe->xbutton.y <= Grid_YH )); +} + +int HitPauseButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Pause_XL-2 ) && + (xe->xbutton.x <= Pause_XH+2 ) && + (xe->xbutton.y >= Pause_YL-2 ) && + (xe->xbutton.y <= Pause_YH+2 )); +} + +int HitStartButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Start_XL-2 ) && + (xe->xbutton.x <= Start_XH+2 ) && + (xe->xbutton.y >= Start_YL-2 ) && + (xe->xbutton.y <= Start_YH+2 )); +} + +int HitStopButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Stop_XL-2 ) && + (xe->xbutton.x <= Stop_XH+2 ) && + (xe->xbutton.y >= Stop_YL-2 ) && + (xe->xbutton.y <= Stop_YH+2 )); +} + +int HitHelpButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Help_XL-2 ) && + (xe->xbutton.x <= Help_XH+2 ) && + (xe->xbutton.y >= Help_YL-2 ) && + (xe->xbutton.y <= Help_YH+2 )); +} + +int HitPlusButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Plus_XL ) && + (xe->xbutton.x <= Plus_XH ) && + (xe->xbutton.y >= Plus_YL ) && + (xe->xbutton.y <= Plus_YH )); +} + +int HitFFWDButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= FFWD_XL ) && + (xe->xbutton.x <= FFWD_XH ) && + (xe->xbutton.y >= FFWD_YL ) && + (xe->xbutton.y <= FFWD_YH )); +} + +int HitMinusButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Minus_XL ) && + (xe->xbutton.x <= Minus_XH ) && + (xe->xbutton.y >= Minus_YL ) && + (xe->xbutton.y <= Minus_YH )); +} + +int HitFBWDButton(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= FBWD_XL ) && + (xe->xbutton.x <= FBWD_XH ) && + (xe->xbutton.y >= FBWD_YL ) && + (xe->xbutton.y <= FBWD_YH )); +} + +int HitUpperPanel(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Parc_XL ) && + (xe->xbutton.x <= Parc_XH ) && + (xe->xbutton.y >= Parc_YL-Parc_YD ) && + (xe->xbutton.y <= Parc_YL )); +} + +int HitLowerPanel(XEvent* xe) +{ + return ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Parc_XL ) && + (xe->xbutton.x <= Parc_XH ) && + (xe->xbutton.y >= Parc_YH ) && + (xe->xbutton.y <= Parc_YH+Parc_YD)); +} + +int HitWindowSelect(XEvent* xe) +{ + if ( + (xe->xbutton.button == Button1) && + (xe->xbutton.x >= Wbox_XL) && + (xe->xbutton.x <= Wbox_XH) && + (xe->xbutton.y >= Wbox_YL) && + (xe->xbutton.y <= Wbox_YH)) + return (xe->xbutton.y / FixFontHeight); /* Window number */ + else return -1; +} + +void OnMouseClick(void) +{ + int w; + + if (HitStopButton(&CowEvent)) + { + Shutdown = 1; + } + else if (HitStartButton(&CowEvent)) + { + Paused = 0; + XSetWMName(display,Cow,&WinconName1); + } + else if (HitGridButton(&CowEvent)) + { + Grid = !Grid; + ShowGridStatus(); + for (w=0 ; w < NUMWIN ; ++w) RedrawFlag[w] = 1; + } + else if (HitPauseButton(&CowEvent)) + { + if (Paused) + { + Paused = 0; + XSetWMName(display,Cow,&WinconName1); + } + else + { + Paused = 1; + XSetWMName(display,Cow,&WinconPause); + } + } + else if (HitHelpButton(&CowEvent)) + { + if (!HelpWindow) DisplayHelpWindow(); + } + else if ((w = HitWindowSelect(&CowEvent)) >= 0) + { + if (Win[w]) CloseWindow(w); + else ReopenWindow(w); + } + else if (HitPlusButton(&CowEvent)) + { + Parc[cpi].Val += Parc[cpi].Inc; + if (Parc[cpi].Val > Parc[cpi].Max) Parc[cpi].Val = Parc[cpi].Max; + } + else if (HitFFWDButton(&CowEvent)) + { + Parc[cpi].Val += 10.0 * Parc[cpi].Inc; + if (Parc[cpi].Val > Parc[cpi].Max) Parc[cpi].Val = Parc[cpi].Max; + } + else if (HitMinusButton(&CowEvent)) + { + Parc[cpi].Val -= Parc[cpi].Inc; + if (Parc[cpi].Val < Parc[cpi].Min) Parc[cpi].Val = Parc[cpi].Min; + } + else if (HitFBWDButton(&CowEvent)) + { + Parc[cpi].Val -= 10.0 * Parc[cpi].Inc; + if (Parc[cpi].Val < Parc[cpi].Min) Parc[cpi].Val = Parc[cpi].Min; + } + else if (HitUpperPanel(&CowEvent) && cpi > 0) --cpi; + else if (HitLowerPanel(&CowEvent) && cpi < Parcs-1) ++cpi; +} + + +void SwitchIndez(int w, int d) +{ + int jlat; + REAL delphi; + char *lpt; + char levstr[20]; + + if (Indez[w] < 0 || Indez[w] >= MaxZ[w]) + { + if (Debug) printf("### Indez[%d] = %d\n",w,Indez[w]); + if (Debug) printf("### MaxZ[%d] = %d\n",w, MaxZ[w]); + Indez[w] = 0; + } + if (Indez[w]+d < 0 ) return; + if (Indez[w]+d >= MaxZ[w]) return; + Indez[w] += d; + lpt = strstr(WindowTitle[w],"Level"); + if (lpt) + { + sprintf(levstr," %d",Indez[w]+1); + strcpy(lpt+5,levstr); + XStringListToTextProperty(&WindowTitle[w],1,WindowName+w); + XSetWMProperties(display,Win[w],WindowName+w,NULL, + NULL,0,&WinSizeHints,&wm_hints,&class_hints); + LevelChanged[w] = 1; + return; + } + lpt = strstr(WindowTitle[w],"Latitude"); + if (lpt) + { + delphi = 180.0 / MaxZ[w]; + jlat = 90.0 -Indez[w] * delphi - delphi * 0.5; + if (jlat > 0) sprintf(levstr," %dN", jlat); + else sprintf(levstr," %dS",-jlat); + strcpy(lpt+8,levstr); + XStringListToTextProperty(&WindowTitle[w],1,WindowName+w); + XSetWMProperties(display,Win[w],WindowName+w,NULL, + NULL,0,&WinSizeHints,&wm_hints,&class_hints); + return; + } +} + + +void HandleEvents(void) +{ + int w,Key,KeyIndex; + XEvent WinEvent; + + if (nstep == 1) + { + RedrawControlWindow(); + Paused = 1; /* Start in pause mode */ + } + + + do + { + /* Check for Termination */ + + if (XCheckTypedWindowEvent(display,Cow,ClientMessage,&WinEvent)) + { + /* printf("delwin %d\n",WinEvent.xclient.data.l[0]); */ + Shutdown = 1; + return; + } + + /* Check for user request to close windows */ + + for (w=0 ; w < NumWin ; ++w) + if (Win[w]) + { + if (XCheckTypedWindowEvent(display,Win[w],ClientMessage,&WinEvent)) + CloseWindow(w); + } + + /* Check for user request to close help window */ + + if (HelpWindow && XCheckTypedWindowEvent(display,HelpWindow,ClientMessage,&WinEvent)) + { + XDestroyWindow(display,HelpWindow); + HelpWindow = 0; + } + + /* Check for mouse click */ + + if (XCheckTypedWindowEvent(display,Cow,ButtonPress,&CowEvent)) + { + OnMouseClick(); + RedrawControlWindow(); + } + + /* Check for mouseclicks and expose events */ + + for (w=0 ; w < NumWin ; ++w) + if (Win[w]) + { + if (XCheckTypedWindowEvent(display,Win[w],ButtonPress,&CowEvent)) + { + if (CowEvent.xbutton.button == Button1) SwitchIndez(w,-1); + if (CowEvent.xbutton.button == Button3) SwitchIndez(w, 1); + if (CowEvent.xbutton.button == Button2) + { + if (++MapPro[w] >= MAXMAPS) MapPro[w] = 0; + if (MapPro[w] == AZIMUTHAL && + (WinAtt[w].Plot != MAPHOR && WinAtt[w].Plot != MAPTRA)) + MapPro[w] = 0; + } + RedrawFlag[w] = 1; + } + if (XCheckTypedWindowEvent(display,Win[w],KeyPress,&CowEvent)) + { + KeyIndex = (CowEvent.xkey.keycode - FirstKey) * SymsPerKey; + Key = KeyMap[KeyIndex]; + if (Debug) printf("Windows %d got keyindex %d with symbol %x\n",w,KeyIndex,Key); + if (Key == ROTATE_LEFT && MapLR[w].f < 5) MapLR[w].f++; + if (Key == ROTATE_RIGHT && MapLR[w].f > -5) MapLR[w].f--; + MapLR[w].r = MapLR[w].f * RotInc; + if (Key == XK_Up ) SwitchIndez(w,-1); + if (Key == XK_Down) SwitchIndez(w, 1); + } + if (Paused) + if (XCheckTypedWindowEvent(display,Win[w],Expose,&CowEvent)) + RedrawIsoWindow(w); + } + + if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent)) + RedrawControlWindow(); + + if (HelpWindow && XCheckTypedWindowEvent(display,HelpWindow,Expose,&CowEvent)) + DrawHelpWindow(); + + } while (Paused && !Shutdown); +} + +void guiclose_(void) +{ + int w; + + if (MRpid >= 0) return; // Don't wait if multiple instances + XSetWMName(display,Cow,&WinconName3); + + do + { + for (w=0 ; w < NumWin ; ++w) + if (Win[w]) + { + if (XCheckTypedWindowEvent(display,Win[w],Expose,&CowEvent)) + RedrawIsoWindow(w); + } + + if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent)) + RedrawControlWindow(); + } + while (!(XCheckTypedWindowEvent(display,Cow,ButtonPress,&CowEvent) && + HitStopButton(&CowEvent))); + +// XCloseDisplay(display); // segmentation fault on sun compiler! +} + +void SaveConfig(void) +{ + int i; + FILE *scp; + INTXS X,Y,xp,yp; + unsigned int w,W,H,border,depth; + Window Rootwin,Child; + XWindowAttributes RootAtt; + + scp = fopen(GUI_config,"w"); + if (scp == NULL) return; + + /* Save window properties */ + + fprintf(scp,"Hamburg GUI Config File Version 16\n"); + fprintf(scp,"Screen: %dx%d\n\n",ScreenW,ScreenH); + fprintf(scp,"WinRows = %d\n",WinRows); + fprintf(scp,"WinCols = %d\n",WinCols); + for (w=0 ; w < NumWin ; ++w) + { + fprintf(scp,"\n[Window %02d]\n",w); + fprintf(scp,"Array:%s\n",WinAtt[w].array_name); + fprintf(scp,"Plot:%s\n",IsoNames[WinAtt[w].Plot]); + if (WinAtt[w].Plot == ISOHOR || WinAtt[w].Plot == MAPHOR || + WinAtt[w].Plot == ISOTRA || WinAtt[w].Plot == MAPTRA) + { + fprintf(scp,"Projection:%s\n",ProNames[MapPro[w]]); + fprintf(scp,"Rotation factor:%d\n",MapLR[w].f); + } + fprintf(scp,"Palette:%s\n",PalNames[WinAtt[w].Palette]); + fprintf(scp,"Title:%s\n",WindowTitle[w]+wto); + if (Win[w]) + { + XGetGeometry(display,Win[w],&Rootwin,&xp,&yp,&W,&H,&border,&depth); + XTranslateCoordinates(display,Win[w],Rootwin,0,0,&X,&Y,&Child); + fprintf(scp,"Geometry: %4d %4d %4d %4d\n",W,H,X-WinLM,Y-WinTM); + if (Debug) + { + printf("Geometry Window %d [%8x]: %4d / %4d %4d x %4d x %2d | %d\n", + w,(int)Win[w],xp,yp,W,H,depth,border); + printf("Translated UL corner: %4d / %4d\n",X,Y); + } + } + else + fprintf(scp,"Inactive: %4d %4d %4d %4d\n", + WinAtt[w].w,WinAtt[w].h,WinAtt[w].x,WinAtt[w].y); + } + XGetGeometry(display,Cow,&Rootwin,&xp,&yp,&W,&H,&border,&depth); + XTranslateCoordinates(display,Cow,Rootwin,0,0,&X,&Y,&Child); + fprintf(scp,"\n[Control Window]\n"); + fprintf(scp,"Geometry: %4d %4d %4d %4d\n",W,H,X-WinLM,Y-WinTM); + + /* Scalar attributes for timeseries and tables */ + + fprintf(scp,"\n# Scalar attributes for timeseries and table window\n"); + + for (i=0 ; i < Parcs ; ++i) + { + fprintf(scp,"\n[Scalar %02d]\n",i); + fprintf(scp,"Name:%s\n",TSName[i]); + fprintf(scp,"Sub:%s\n",TSubsc[i]); + fprintf(scp,"Unit:%s\n",TSUnit[i]); + fprintf(scp,"Scale:%s\n",TScale[i]); + } + + /* Scalar attributes for timeseries and tables */ + + fprintf(scp,"\n# Parameter attributes for change menu\n"); + + for (i=0 ; i < NUMSCALARS ; ++i) + { + if (strlen(Parc[i].Name) == 0) break; + fprintf(scp,"\n[Parameter %02d]\n",i); + fprintf(scp,"ParName:%s\n",Parc[i].Name); + fprintf(scp,"ParInc:%10.4f\n",Parc[i].Inc); + fprintf(scp,"ParMin:%10.4f\n",Parc[i].Min); + fprintf(scp,"ParMax:%10.4f\n",Parc[i].Max); + } + + fclose(scp); +} + +/* Transform a lambda/hi grid to polar stereographic projection */ +/* Input array a and output array b have identical dimensions */ + +void lp2ps(REAL *a, REAL *b) +{ + int i,j,k,l,k1,l1; + REAL xnp,ynp,xsp,ysp,dx,dy,x,y,lfa,ua,ub; + + lfa = (DimX-1) / (2.0 * M_PI); + xnp = (DimX-1) * 0.25; // Northpole at (xnp,ynp) + ynp = (DimY-1) * 0.50; + xsp = (DimX-1) * 0.75; // Southpole at (xsp,ysp) + ysp = ynp; + + // Interpolate b[i][j] from a[k][l] + + /* Northern hemisphere */ + + for (j = 0 ; j < DimY ; ++j) + for (i = 0 ; i <= DimX/2 ; ++i) + { + dx = arx * (xnp - i); + dy = ary * (ynp - j); + x = atan2(dx,dy) * lfa; // angle + y = sqrt(dx * dx + dy * dy); // distance from NP + if (x < 0.0) x += (DimX-1); + k = x; // integer part + l = y; + k1 = k + 1; + if (k1 >= DimX) k1 = 0; + if (l <= DimY/2+1) // Northern hemisphere + { + ua = (k+1-x) * a[k+l*DimX] + (x-k) * a[k1+l*DimX]; + ub = (k+1-x) * a[k+(l+1)*DimX] + (x-k) * a[k+1+(l+1)*DimX]; + b[i+j*DimX] = (l+1-y) * ua + (y-l) * ub; + } + else b[i+j*DimX] = - 99999.0; + } + + /* Souhern hemisphere */ + + for (j = 0 ; j < DimY ; ++j) + for (i = DimX/2+1 ; i < DimX ; ++i) + { + dx = arx * (i - xsp); + dy = ary * (ysp - j); + x = atan2(dx,dy) * lfa; + y = (DimY-1) - sqrt(dx * dx + dy * dy); + if (x < 0.0) x += (DimX-1); + k = x; + l = y; + k1 = k + 1; + if (k1 >= DimX) k1 = 0; + if (l >= DimY/2-3) + { + ua = (k+1-x) * a[k+l*DimX] + (x-k) * a[k1+l*DimX]; + ub = (k+1-x) * a[k+(l+1)*DimX] + (x-k) * a[k+1+(l+1)*DimX]; + b[i+j*DimX] = (l+1-y) * ua + (y-l) * ub; + } + else b[i+j*DimX] = - 99999.0; + } +} + + +/* ======================================================= */ +/* lp2az - transform lon/lat array to azimuthal projection */ +/* ======================================================= */ + +void lp2az(REAL *a, REAL *b, float laz) +{ + int x,y,dxc,k,k1,l; + REAL dx,dy,lam,rho,rad,phi,ua,ub,l00,p00,xpi,ypi; + + rad = DimY >> 1; + dxc = DimX >> 1; + xpi = DimX / M_PI * 0.5; + ypi = DimY / M_PI; + l00 = (int)((laz * DimX) / 360 + dxc) % DimX; + p00 = DimY / 2; + + for (y = 0 ; y < DimY ; ++y) + { + dy = y - rad; + phi = y; + for (x = 0 ; x < DimX ; ++x) + { + dx = x - dxc; + rho = sqrt(dx * dx + dy * dy); + if (rho < rad) + { + lam = l00 + xpi * atan2(dx / rad, cos(asin(rho / rad))); + phi = p00 + ypi * asin(dy / rad); + k = lam; + k1 = k + 1; + if (k1 >= DimX) k1 = 0; + l = phi; + ua = (k+1-lam) * a[k+ l *DimX] + (lam-k) * a[k1 + l *DimX]; + ub = (k+1-lam) * a[k+(l+1)*DimX] + (lam-k) * a[k+1+(l+1)*DimX]; + b[x+y*DimX] = (l+1-y) * ua + (y-l) * ub; + } + else b[x+y*DimX] = - 99999.0; + } + } +} + +void ShowGridCS(void) +{ + int jlev,jlat,x,y,len; + float dx,dy; + char Text[80]; + + /* Grid for zonal mean cross sections */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dy = (InYSize - OffY) / (DimY - 1.0); + for (jlev = 1 ; jlev < DimY-1 ; ++jlev) + { + y = OffY + jlev * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + dx = (InXSize - OffX) / 6.0; /* Every 30 degrees */ + for (jlat = 1 ; jlat < 6 ; ++jlat) + { + x = OffX + jlat * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,InXSize/2-FixFontWidth,InYSize-FixFont->descent,"EQ",2); + XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"N",1); + XDrawImageString(display,pix,gc,InXSize-FixFontWidth,InYSize-FixFont->descent,"S",1); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridCol(void) +{ + int jlev,jtim,x,y,len; + float dx,dy; + char Text[80]; + + /* Grid for column time series */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dy = (InYSize - OffY) / (DimY - 1.0); + for (jlev = 1 ; jlev < DimY-1 ; ++jlev) + { + y = OffY + jlev * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + dx = (InXSize - OffX) / 4.0; /* 4 slices */ + for (jtim = 1 ; jtim < 4 ; ++jtim) + { + x = OffX + jtim * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,InXSize/2-3*FixFontWidth/2,InYSize-FixFont->descent,"t-2",3); + XDrawImageString(display,pix,gc,InXSize/4-3*FixFontWidth/2,InYSize-FixFont->descent,"t-3",3); + XDrawImageString(display,pix,gc,3*InXSize/4-3*FixFontWidth/2,InYSize-FixFont->descent,"t-1",3); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridLonsi(void) +{ + int jlev,jlat,x,y,len; + float dx,dy; + char Text[80]; + + /* Grid for Longitude Sigma section */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dy = (InYSize - OffY) / (DimY - 1.0); + for (jlev = 1 ; jlev < DimY-1 ; ++jlev) + { + y = OffY + jlev * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + dx = (InXSize - OffX) / 6.0; /* Every 60 degrees */ + for (jlat = 1 ; jlat < 6 ; ++jlat) + { + x = OffX + jlat * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,InXSize/2-3*FixFontWidth/2,InYSize-FixFont->descent,"180",3); + XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"0",1); + XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"360",3); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridCyl(void) +{ + int jlon,jlat,x,y; + float dx,dy; + + /* Grid for cylinder projection */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dy = (InYSize - OffY) / 6.0; + for (jlat = 1 ; jlat < 6 ; ++jlat) + { + y = OffY + jlat * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + dx = (InXSize - OffX) / 6.0; /* Every 30 degrees */ + for (jlon = 1 ; jlon < 6 ; ++jlon) + { + x = OffX + jlon * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,OffX,OffY+(InYSize-OffY)/2+FixFontHeight/2-FixFont->descent,"EQ",2); + XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"N",1); + XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"-180",4); + XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"180",3); + XDrawImageString(display,pix,gc,OffX+(InXSize-OffX)/2-3*FixFontWidth/2,InYSize-FixFont->descent,"0",1); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridHov(void) +{ + int jlon,jlat,x,y,len; + float dx,dy; + char Text[80]; + + /* Grid for Hovmoeller */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dx = (InXSize - OffX) / 6.0; + for (jlon = 1 ; jlon < 6 ; ++jlon) + { + x = OffX + jlon * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + dy = (InYSize - OffY) / 5.0; /* Every 5 days */ + for (jlat = 1 ; jlat < 5 ; ++jlat) + { + y = OffY + jlat * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"0",1); + XDrawImageString(display,pix,gc,InXSize-3*FixFontWidth,InYSize-FixFont->descent,"360",3); + XDrawImageString(display,pix,gc,OffX+(InXSize-OffX)/2-3*FixFontWidth/2,InYSize-FixFont->descent,"180",3); + XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"t0",2); + XDrawImageString(display,pix,gc,OffX,OffY+2*InYSize/5+FixFontHeight/2-FixFont->descent,"t-2",3); + XDrawImageString(display,pix,gc,OffX,OffY+4*InYSize/5+FixFontHeight/2-FixFont->descent,"t-4",3); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridHovT(void) +{ + int jlon,jlat,x,y,len; + float dx,dy; + char Text[80]; + + /* Grid for Hovmoeller */ + + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + dy = (InYSize - OffY) / 6.0; + for (jlat = 1 ; jlat < 6 ; ++jlat) + { + y = OffY + jlat * dy; + XDrawLine(display,pix,gc,OffX,y,InXSize-1,y); + } + dx = (InXSize - OffX) / 5.0; /* Every 5 days */ + for (jlat = 1 ; jlat < 5 ; ++jlat) + { + x = OffX + jlat * dx; + XDrawLine(display,pix,gc,x,OffY,x,InYSize-1); + } + if (GridLabel) + { + XDrawImageString(display,pix,gc,OffX,OffY+FixFontHeight-FixFont->descent,"0",1); + XDrawImageString(display,pix,gc,OffX,OffY+(InYSize-OffY)/2+FixFontHeight/2-FixFont->descent,"180",3); + XDrawImageString(display,pix,gc,OffX,InYSize-FixFont->descent,"360",3); + XDrawImageString(display,pix,gc,InXSize-2*FixFontWidth,InYSize-FixFont->descent,"t0",2); + XDrawImageString(display,pix,gc,3*InXSize/5-3*FixFontWidth/2,InYSize-FixFont->descent,"t-2",3); + XDrawImageString(display,pix,gc, InXSize/5-3*FixFontWidth/2,InYSize-FixFont->descent,"t-4",3); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); +} + +void ShowGridPolar(void) +{ + int dx,dy,x,y,xh,yh,ox,oy; + XPoint pxy[3]; + + /* Grid for polar projection */ + + dx = (InXSize - OffX) / 2; + dy = (InYSize - OffY); + xh = dx / 2; + yh = dy / 2; + ox = dx / 3.414; + oy = dy / 3.414; + + if (Grid) + { + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + XSetLineAttributes(display,gc,1,LineOnOffDash,CapButt,JoinRound); + + /* Northern Hemisphere */ + + XDrawArc(display,pix,gc,OffX+dx/6,OffY+dy/6,2*dx/3,2*dy/3,0,360*64); + XDrawArc(display,pix,gc,OffX+dx/3,OffY+dy/3,dx/3,dy/3,0,360*64); + + XDrawLine(display,pix,gc,OffX,yh,InXSize,yh); + XDrawLine(display,pix,gc,OffX+xh,OffY,OffX+xh,InYSize); + + /* Southern Hemisphere */ + + XDrawArc(display,pix,gc,OffX+7*dx/6,OffY+dy/6,2*dx/3,2*dy/3,0,360*64); + XDrawArc(display,pix,gc,OffX+4*dx/3,OffY+dy/3,dx/3,dy/3,0,360*64); + + x = OffX + dx + xh; + XDrawLine(display,pix,gc,x,OffY,x,InYSize); + + if (GridLabel) + { + x = OffX + xh - FixFontWidth/2; + y = OffY + yh + FixFontHeight/2 - FixFont->descent; + XDrawImageString(display,pix,gc,x,y,"N",1); + XDrawImageString(display,pix,gc,x+dx,y,"S",1); + } + XSetLineAttributes(display,gc,1,LineSolid,CapButt,JoinRound); + } + + /* Octagon mask */ + + XSetForeground(display,gc,BlackPix); + pxy[0].x = pxy[1].x = OffX; + pxy[0].y = pxy[2].y = OffY; + pxy[1].y = OffY + oy; + pxy[2].x = OffX + ox; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); + pxy[0].x = OffX + dx - ox; + pxy[1].x = OffX + dx; + pxy[2].x = OffX + dx + ox; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); + pxy[0].x = InXSize - ox; + pxy[1].x = InXSize; + pxy[2].x = InXSize; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); + + pxy[0].x = pxy[1].x = OffX; + pxy[0].y = pxy[2].y = InYSize; + pxy[1].y = InYSize - oy; + pxy[2].x = OffX + ox; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); + pxy[0].x = OffX + dx - ox; + pxy[1].x = OffX + dx; + pxy[2].x = OffX + dx + ox; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); + pxy[0].x = InXSize - ox; + pxy[1].x = InXSize; + pxy[2].x = InXSize; + XFillPolygon(display,pix,gc,pxy,3,Convex,CoordModeOrigin); +} + + +void AutoPalette(int w, struct ColorStrip Strip[], REAL f[], int Dim) +{ + int i,nbands; + double fmin, fmax, frange, delta, fdelta, xdelta, Lo; + + fmin = fmax = f[0]; + for (i=0; i < Dim ; ++i) + { + if (fmin > f[i]) fmin = f[i]; + if (fmax < f[i]) fmax = f[i]; + } + frange = fmax - fmin; + Lo = 0.0; + xdelta = 0.1; + if (frange > 1.0e-10) + { + delta = frange / AUTOCOLORS; + if (delta > AutoDelta[w] / 1.4 && delta < 1.4 * AutoDelta[w]) + { + xdelta = AutoXdelt[w]; + delta = AutoDelta[w]; + Lo = AutoLo[w]; + } + else + { + fdelta = pow(10.0,rint(log10(delta))); + xdelta = fdelta; + nbands = frange / xdelta; + if (nbands < AUTOCOLORS / 2) xdelta = 0.5 * fdelta; + if (nbands > AUTOCOLORS ) xdelta = 2.0 * fdelta; + nbands = frange / xdelta; + if (nbands > AUTOCOLORS ) xdelta = 5.0 * fdelta; + Lo = xdelta * floor(fmin / xdelta); + AutoDelta[w] = delta; + AutoXdelt[w] = xdelta; + AutoLo[w] = Lo; +/* + if (Debug) + { + printf("Autopalette\n"); + printf(" Range: %14.6e\n",frange); + printf(" delta: %14.6e\n",delta); + printf("fdelta: %14.6e\n",fdelta); + printf("xdelta: %14.6e\n",xdelta); + } +*/ + } + } + Strip[0].Lo = Lo; + for (i=0 ; i < AUTOCOLORS ; ++i) + { + Strip[i+1].Lo = Strip[i].Hi = Strip[i].Lo + xdelta; + // if (Debug) printf("Auto[%2d] = %10.4f - %10.4f\n",i,Strip[i].Lo,Strip[i].Hi); + } + return; +} + + +// Interface routine to model code in FORTRAN + +void guiput_(char *aname, float *array, int *dimx, int *dimy, int *dimz) +{ + int i,nb,nf; + + if (Debug) printf("guiput(%s,%12.4e,%d,%d,%d)\n", + aname,*array,*dimx,*dimy,*dimz); + nf = (*dimx) * (*dimz); + if (*dimy > 0) nf *= (*dimy); + else nf *= 2; + nb = nf * sizeof(float); + for (i=0 ; i < NumArrays ; ++i) + if (!strcmp(aname,Array[i].Name)) break; + if (i == NumArrays) + { + ++NumArrays; + strcpy(Array[i].Name,aname); + Array[i].Data = FloatAlloc(nf,aname); + Array[i].DimX = *dimx; + Array[i].DimY = *dimy; + Array[i].DimZ = *dimz; + if (strcmp(aname,"GU") == 0) Uindex = i; + if (strcmp(aname,"GV") == 0) Vindex = i; + } + if (Array[i].Data) memcpy(Array[i].Data,array,nb); + Array[i].Flag = 1; // Data have changed +} + + +void guisend_(char *aname, float *array, int *dimx, int *dimy, int *dimz) +{ + int i,nb,nf; + + nf = (*dimx) * (*dimz); + if (*dimy > 0) nf *= (*dimy); + else nf *= 2; + nb = nf * sizeof(float); + for (i=0 ; i < NumArrays ; ++i) + if (!strcmp(aname,Array[i].Name)) break; + if (i == NumArrays) + { + ++NumArrays; + strcpy(Array[i].Name,aname); + Array[i].DimX = *dimx; + Array[i].DimY = *dimy; + Array[i].DimZ = *dimz; + } + Array[i].Data = array; + Array[i].Flag = 1; // Data have changed +} + + +// Do the plot + +void iso(int w,int PicType,REAL *field,int dimx,int dimy,int dimz,int pal) +{ + char Text[128]; + + int i,j,k,len,lens,xp,yp,status,x; + int y,dx,r,width,height; + INTXU border,depth; + REAL f,o,ra,rb; + int CapLines; + float *tspt; + XEvent WinEvent; + Window Rootwin,Child; + + // if (Debug) printf("iso(%d,%s,%12.4e,%d,%d,%d,%d)\n",w,IsoNames[PicType],*field,dimx,dimy,dimz,pal); + if (Win[w] == 0) return; + win = w; + + // At high frame rates (SkipFreq > 1) some types are redrawn + // at "SkipFreq" intervals + + if (SkipFreq > 1 && (nstep % SkipFreq) != 0 && + (PicType == ISOCS || PicType == ISOHOR || + PicType == MAPHOR || PicType == ISOCOL || + PicType == ISOREC )) return; + + XGetGeometry(display,Win[w],&Rootwin,&xp,&yp,&WinXSize,&WinYSize, + &border,&depth); + WinAtt[w].w = WinXSize; + WinAtt[w].h = WinYSize; + InXSize = WinXSize - OffX; + InYSize = WinYSize - OffY; + + // Determine aspect ratio of window + // width = 2 * height is optimal (1.0) + + if (InXSize > 2 * InYSize) // wide + { + arx = InXSize / (2.0 * InYSize); + ary = 1.0; + } + else // narrow + { + arx = 1.0; + ary = (2.0 * InYSize) / InXSize; + } + + if (PicType != ISOTRA && PicType != MAPTRA) InYSize -= 20; // Room for colorbar + DimX = dimx; + DimY = dimy; + DimZ = dimz; + if (DimY < 0) DimY = -DimY; // Get NTP1 for ISOSH + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + if (DimY > 1) VGAY = (InYSize-1.0) / (DimY-1.0); + else VGAY = 1.0; + Field = field; + + if (PicType == ISOTRA || PicType == MAPTRA) + { + DimX = dimx; // NLON + DimY = dimy; // NLAT + DimZ = dimz; // NLEV + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (MaxZ[w] < DimZ) + { + MaxZ[w] = DimZ; + Indez[w] = DimZ / 4; + SwitchIndez(w,0); // Initialize title + } + } + + if (PicType == ISOREC || PicType == ISOHOR || PicType == MAPHOR) + { + DimX = dimx; // NLON + DimY = dimy; // NLAT + DimZ = dimz; // NLEV + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (MaxZ[w] < DimZ) + { + MaxZ[w] = DimZ; + Indez[w] = DimZ / 4; + SwitchIndez(w,0); // Initialize title + TSdata[w] = FloatAlloc(DimXY,"ISOLON"); + } + if (MapPro[w] == POLAR) + { + Field = TSdata[w]; + lp2ps(field + Indez[w] * DimXY,Field); + } +/* + else if (MapPro[w] == AZIMUTHAL) + { + Field = TSdata[w]; + lp2az(field + Indez[w] * DimXY,Field,MapLR[w].l); + } +*/ + else Field = field + Indez[w] * DimXY; + } + + if (PicType == ISOLON) + { + DimX = dimx; // NLON + DimY = dimz; // NLEV + DimZ = dimy; // NLAT + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (!TSdata[w]) + { + TSdata[w] = FloatAlloc(DimXY,"ISOLON"); + MaxZ[w] = DimZ; + Indez[w] = DimZ / 4; + SwitchIndez(w,0); // Initialize title + } + Field = TSdata[w]; + for (j=0,i=0,k=DimX*Indez[w] ; j < DimY ; ++j,i+=DimX,k+=DimX*DimZ) + { + memcpy(Field+i,field+k,DimX * sizeof(REAL)); // copy latitude + } + } + + if (PicType == ISOHOV) + { + DimX = dimx; // NLON + DimY = DimT; // time + DimZ = dimy; // NLAT + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (!TSdata[w]) + { + TSdata[w] = FloatAlloc(DimXY,"ISOHOV"); + MaxZ[w] = DimZ; + Indez[w] = DimZ / 4; + SwitchIndez(w,0); // Initialize title + } + Field = TSdata[w]; + memmove(Field+DimX,Field,(DimXY-DimX) * sizeof(REAL)); // scroll array + memcpy(Field,field+Indez[w]*DimX,DimX * sizeof(REAL)); // add line + } + + // Advance write pointer HovInx until end of DimX + // then scroll array and reset pointer + + if (PicType == ISOTS) + { + DimX = DimT; // time + DimY = dimx; // # of variables + DimZ = dimz; + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (!TSdata[w]) + { + TSdata[w] = FloatAlloc(DimXY+DimX,"ISOTS"); + } + tspt = TSdata[w]; + ++HovInx[w]; + if (HovInx[w] >= DimX) + { + HovInx[w] = 0; + memmove(tspt,tspt+DimX,DimXY * sizeof(REAL)); // scroll array + } + for (i=HovInx[w]+DimX-1,j=0 ; j < DimY ; i+=DimX,++j) + tspt[i] = field[j]; // add column + Field = tspt+HovInx[w]; + } + + if (PicType == ISOCOL) + { + DimX = DimT; // time + DimY = dimx; // level + DimZ = dimy; // clickable index + DimXY = DimX * DimY; + VGAX = (InXSize-1.0) / (DimX-1.0); + VGAY = (InYSize-1.0) / (DimY-1.0); + if (!TSdata[w]) + { + TSdata[w] = FloatAlloc(DimXY+DimX,"ISOCOL"); + MaxZ[w] = DimZ; + Indez[w] = DimZ / 2; + SwitchIndez(w,0); // Initialize title + } + tspt = TSdata[w]; + ++HovInx[w]; + if (HovInx[w] >= DimX) + { + HovInx[w] = 0; + memmove(tspt,tspt+DimX,DimXY * sizeof(REAL)); // scroll array + } + for (i=HovInx[w]+DimX-1,j=0 ; j < DimY ; i+=DimX,++j) + tspt[i] = field[j+Indez[w]*DimY]; // add column + Field = tspt+HovInx[w]; + } + + if (DimX > FlagSize) + { + if (Flag) free(Flag); + Flag = IntAlloc(DimX,"Flag"); + FlagSize = DimX; + } + + if (PicType == ISOSH) pal = 1; // ISOSH has its own palette + if (pal < 1 || pal >= NUMPAL) + { + Cstrip = Autostrip; + AutoPalette(w,Cstrip,Field,DimXY); + Lines = AUTOCOLORS; + // printf("Autopalette %d for Win %d\n",pal,w); + } + else + { + Cstrip = Pallet[pal]; + Lines = LineCo[pal]; + } + + SizeChanged = (WinPixMap[w].DimX != WinXSize || WinPixMap[w].DimY != WinYSize); + if (SizeChanged) + { + if (WinPixMap[w].Pix) XFreePixmap(display,WinPixMap[w].Pix); + WinPixMap[w].Pix = XCreatePixmap(display,Win[w],WinXSize,WinYSize,ScreenD); + if (Debug) + printf("CreatePixmap %10x %6d bytes\n", + (unsigned int)WinPixMap[w].Pix,WinXSize*WinYSize); + WinPixMap[w].DimX = WinXSize; + WinPixMap[w].DimY = WinYSize; + } + pix = WinPixMap[w].Pix; /* Set current pixmap */ + + /* Draw colour bar */ + + if ((SizeChanged || Cstrip == Autostrip) && + (PicType == ISOCS || PicType == ISOHOR || + PicType == ISOHOV || PicType == ISOLON || + PicType == ISOCOL || PicType == MAPHOR || + PicType == ISOREC )) + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,InYSize,WinXSize,WinYSize); + + CapLines = WinXSize / (20 + 3 * FixFontWidth); + if (CapLines > Lines) CapLines = Lines; + for (i=0 ; i < CapLines ; ++i) + { + XSetForeground(display,gc,Cstrip[i].pixel); + XFillRectangle(display,pix,gc,OffX+5+i*(WinXSize-20)/(CapLines-1), + OffY+InYSize+5,10,10); + XSetForeground(display,gc,BlackPix); + XDrawRectangle(display,pix,gc,OffX+5+i*(WinXSize-20)/(CapLines-1), + OffY+InYSize+5,10,10); + } + XSetForeground(display,gc,WhitePix); + XSetBackground(display,gc,BlackPix); + rb = Cstrip[CapLines-2].Hi - Cstrip[0].Hi; + for (i=0 ; i < CapLines-1 ; ++i) + { + Text[0] = 0; + ra = Cstrip[i].Hi; + j = ra; + if (j > -1000 && j < 10000) sprintf(Text,"%d",j); + if (ra < 100.0 && ra > -9.99) + { + sprintf(Text,"%4.1f",ra); + if (!strcmp(Text+2,".0")) Text[2] = 0; + } + if (ra < 10.0 && ra >= 0.0) + { + sprintf(Text,"%4.2f",ra); + if (!strcmp(Text+1,".00")) Text[1] = 0; + } + len = strlen(Text); + if (len) + { + width = XTextWidth(FixFont,Text,len); + height = FixFont->ascent + FixFont->descent; + xp = OffX + 10 + (i+0.5) * (WinXSize-20)/(CapLines-1) - width/2; + yp = WinYSize - height + 10; + XDrawImageString(display,pix,gc,xp,yp,Text,len); + } + } + } + + /* Draw mode legend */ + + if (SizeChanged && PicType == ISOSH) + { + dx = WinXSize / 23; + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,WinYSize); + + XSetForeground(display,gc,LightGreen.pixel); + XSetBackground(display,gc,BlackPix); + for (i=0 ; i < 21 ; i+=2) + { + sprintf(Text,"%d",i); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + height = FixFont->ascent + FixFont->descent; + xp = dx + i * dx - width/2 - FixFontWidth/2 + 1; + yp = FixFontHeight; + XDrawImageString(display,pix,gc,xp,yp,Text,len); + } + XSetForeground(display,gc,LightBlue.pixel); + for (i=0 ; i < 21 ; i+=2) + { + sprintf(Text,"%d",i); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + height = FixFont->ascent + FixFont->descent; + xp = WinXSize - width - 2; + yp = 2 * FixFontHeight + i * dx; + if (yp+FixFont->descent > InYSize) break; + XDrawImageString(display,pix,gc,xp,yp,Text,len); + } + strcpy(Text,"n/m"); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + xp = WinXSize - width - 2; + yp = FixFontHeight; + XSetForeground(display,gc,WhitePix); + XDrawImageString(display,pix,gc,xp,yp,Text,len); + strcpy(Text,"High "); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + xp = WinXSize/2 - AMPLI_COLS * 10 - width; + yp = WinYSize - FixFontHeight + 10; + r = FixFontHeight-2; + XSetForeground(display,gc,WhitePix); + if (xp > 0) XDrawImageString(display,pix,gc,xp,yp,Text,len); + strcpy(Text," Low"); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + xp = WinXSize/2 + AMPLI_COLS * 10; + if (xp + width < WinXSize) XDrawImageString(display,pix,gc,xp,yp,Text,len); + yp = InYSize; + XDrawLine(display,pix,gc,OffX,yp,WinXSize,yp); + yp = WinYSize - r - FixFont->descent; + + for (i=0 ; i < AMPLI_COLS ; ++i) + { + xp = WinXSize/2 - AMPLI_COLS * 10 + i * 20; + XSetForeground(display,gc,AmpliStrip[AMPLI_COLS-i-1].pixel); + XFillArc(display,pix,gc,xp,yp,r,r,0,360*64); + } + } + + if (SizeChanged && PicType == ISOTS) /* Timeseries Caption */ + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,InYSize,WinXSize,WinYSize); + XSetBackground(display,gc,BlackPix); + + xp = FixFontWidth; + yp = WinYSize - FixFontHeight + 10; + for (j=0 ; j < DimY ; ++j) + { + if (TSName[j][0]) + { + strcpy(Text,TSName[j]); + len = strlen(Text); + width = XTextWidth(FixFont,Text,len); + XSetForeground(display,gc,TSColor[j]); + XDrawImageString(display,pix,gc,xp,yp,Text,len); + xp += width; + } + if (TSubsc[j][0]) + { + XSetFont(display, gc, SubFont->fid); + strcpy(Text,TSubsc[j]); + len = strlen(Text); + width = XTextWidth(SubFont,Text,len); + XSetForeground(display,gc,TSColor[j]); + XDrawImageString(display,pix,gc,xp,yp,Text,len); + xp += width; + XSetFont(display, gc, FixFont->fid); + } + xp += FixFontWidth; + } + } + + if (SizeChanged && PicType == ISOTAB) /* Table Caption */ + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,WinYSize); + XSetBackground(display,gc,BlackPix); + } + + if (PicType == ISOTS) + { + if (TSxp[w] == NULL) TSxp[w] = SizeAlloc(DimX * DimY , sizeof(XPoint),"TSxp"); + if (Dmin[w] == NULL) Dmin[w] = FloatAlloc(DimY ,"Dmin"); + if (Dmax[w] == NULL) Dmax[w] = FloatAlloc(DimY ,"Dmax"); + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + + for (j=0 ; j < DimY ; ++j) Dmin[w][j] = Dmax[w][j] = field[j]; + if (nstep > 2) + { + for (j=0 ; j < DimY ; ++j) + { + for (i=1 ; i < DimX ; ++i) + { + Dmin[w][j] = MIN(Dmin[w][j],Field[i+j*DimX]); + Dmax[w][j] = MAX(Dmax[w][j],Field[i+j*DimX]); + } + } + } + + if (nstep > 2) + for (j=0 ; j < DimY ; ++j) + { + XSetForeground(display,gc,TSColor[j]); + o = Dmin[w][j]; + if ((Dmax[w][j] - Dmin[w][j]) > 1.0e-20) f = (InYSize-2) / (Dmax[w][j] - Dmin[w][j]); + else f = 1.0; + + for (i=1 ; i < DimX ; ++i) + { + TSxp[w][i].x = VGAX * i; + TSxp[w][i].y = InYSize - 1 - f * (Field[i+j*DimX] - o); + } + XDrawLines(display,pix,gc,TSxp[w]+1,DimX-1,CoordModeOrigin); + } + } + + if (PicType == ISOTAB) + { + XSetForeground(display,gc,BlackPix); + XSetBackground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + XSetFont(display, gc, BigFont->fid); + yp = BigFontHeight; + for (j=0 ; j < DimX ; ++j) + if (TSName[j][0]) + { + XSetForeground(display,gc,TSColor[j]); + xp = BigFontWidth; + strcpy(Text,TSName[j]); + len = strlen(Text); + XDrawImageString(display,pix,gc,xp,yp,Text,len); + xp += XTextWidth(BigFont,Text,len); + if (TSubsc[j][0]) + { + XSetFont(display, gc, FixFont->fid); + XDrawImageString(display,pix,gc,xp,yp,TSubsc[j],strlen(TSubsc[j])); + XSetFont(display, gc, BigFont->fid); + } + xp = 8 * BigFontWidth; + if (TSUnit[j][0]) + { + sprintf(Text,"= %7.3f [%s]",field[j],TSUnit[j]); + if (TScale[j][0]) strcat(Text," 10"); + len = strlen(Text); + XDrawImageString(display,pix,gc,xp,yp,Text,len); + if (TScale[j][0] > ' ') + { + lens = strlen(TScale[j]); + XSetFont(display, gc, FixFont->fid); + XDrawImageString(display,pix,gc,xp+len*BigFontWidth,yp-BigFontHeight+FixFontHeight,TScale[j],lens); + XSetFont(display, gc, BigFont->fid); + } + } + yp += BigFontHeight; + } + XSetFont(display, gc, FixFont->fid); + } + + if (PicType == ISOTRA) + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + if (SizeChanged) ClearTracer(); + TracerPlot(w); + } + if (PicType == MAPTRA) + { + if (SizeChanged) ClearTracer(); + if (MapHR.X) + { + if (MapPro[w] == AZIMUTHAL) + { + if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize || + (nstep % rmui == 0 && MapLR[w].f != 0)) + { + RedrawFlag[w] = 0; + MapLR[w].w = WinXSize; + MapLR[w].h = InYSize; + MapLR[w].l += MapLR[w].r; + if (MapLR[w].l < -180.0) MapLR[w].l += 360.0; + if (MapLR[w].l > 180.0) MapLR[w].l -= 360.0; + AzimuthalImage(&MapHR,&MapLR[w]); + } + } + else + { + if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize) + { + RedrawFlag[w] = 0; + MapLR[w].w = WinXSize; + MapLR[w].h = InYSize; + if (MapPro[w] == 1) PolarImage(&MapHR,&MapLR[w]); + else ScaleImage(&MapHR,&MapLR[w]); + } + } + XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h); + } + else + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + } + TracerPlot(w); + } + + // Now perform the plotting of areas and lines for simple + // rectangles with no transformation/projection involved + + if (PicType == ISOCS || PicType == ISOHOR || + PicType == ISOLON || PicType == ISOCOL || + PicType == ISOREC ) + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + IsoAreas(Cstrip); + IsoLines(Cstrip,0); + } + + // Plotting of azimuthal or polar projection + + if (PicType == MAPHOR) + { + if (MapHR.X) + { + if (MapPro[w] == AZIMUTHAL) + { + if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize || + (nstep % rmui == 0 && MapLR[w].f != 0)) + { + RedrawFlag[w] = 0; + MapLR[w].w = WinXSize; + MapLR[w].h = InYSize; + MapLR[w].l += MapLR[w].r; + if (MapLR[w].l < -180.0) MapLR[w].l += 360.0; + if (MapLR[w].l > 180.0) MapLR[w].l -= 360.0; + AzimuthalImage(&MapHR,&MapLR[w]); + } + XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h); + MapLines(Cstrip,1); + } + else + { + if (RedrawFlag[w] || MapLR[w].w != WinXSize || MapLR[w].h != InYSize) + { + RedrawFlag[w] = 0; + MapLR[w].w = WinXSize; + MapLR[w].h = InYSize; + if (MapPro[w] == 1) PolarImage(&MapHR,&MapLR[w]); + else ScaleImage(&MapHR,&MapLR[w]); + } + XPutImage(display,pix,gc,MapLR[w].X,0,0,0,0,MapLR[w].w,MapLR[w].h); + IsoLines(Cstrip,1); + } + } + else + { + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + IsoLines(Cstrip,1); + } + } + + // Hovmoeller diagram + + if (PicType == ISOHOV) + { + IsoAreas(Cstrip); + } + + // amplitudes of coeeficients of spherical harmonics + + if (PicType == ISOSH) + { + AmplitudePlot(); + } + + if (Grid && PicType == ISOCS) ShowGridCS(); + if (Grid && PicType == ISOLON) ShowGridLonsi(); + if (Grid && PicType == ISOHOV && MapPro[w] == 0) ShowGridHov(); + if (Grid && PicType == ISOHOV && MapPro[w] == 1) ShowGridHovT(); + if (PicType == ISOHOR && MapPro[w] == 1) ShowGridPolar(); + if (Grid && PicType == ISOHOR && MapPro[w] == 0) ShowGridCyl(); + if (Grid && PicType == ISOCOL) ShowGridCol(); + + // copy drawn image into visible display + + XCopyArea(display,pix,Win[w],gc,0,0,WinXSize,WinYSize,0,0); +} + + +/* ==================================================================== */ +/* iguistep - this function is called from the model for every timestep */ +/* ==================================================================== */ + +int iguistep_(float pparcs[],int kdatim[]) +{ + int i,j,w; // Loop indices + struct timeval TimeVal; // Retrieve time info + + if (Debug) printf("iguistep(%12.2e,%d-%d-%d)\n", + pparcs[0],kdatim[0],kdatim[1],kdatim[2]); + nstep++; + memcpy(ndatim,kdatim,sizeof(ndatim)); + DeltaTime = ndatim[4] - LastMinute; + if (DeltaTime < 0) DeltaTime += 60; + if (DeltaTime ==0) DeltaTime = 60; + LastMinute = ndatim[4]; + + // Compute frames per second every 20 calls + + gettimeofday(&TimeVal,NULL); + LastSecond = ThisSecond; + ThisSecond = TimeVal.tv_sec; + + if ((SecEvent = ThisSecond) > LastSecond) + { + fps = nstep - LastStep; + LastStep = nstep; + rmui = fps / rmuf; + if (rmui < 1) rmui = 1; + } + + SkipFreq = 1 + fps / 30; // Reduce plot rate on fast cpu's + if (SkipFreq < 0 || SkipFreq > 10) SkipFreq = 0; + + for (w=0 ; w < NumWin ; ++w) + { + for (j=0 ; j < NumArrays ; ++j) + { + if (!strcmp(WinAtt[w].array_name,Array[j].Name)) + { + if (Array[j].Flag || RedrawFlag[w]) + iso(w,WinAtt[w].Plot,Array[j].Data,Array[j].DimX,Array[j].DimY, + Array[j].DimZ,WinAtt[w].Palette); + } + } + } + + for (i=0 ; i < Parcs ; ++i) Parc[i].Val = pparcs[i]; + ShowStep(); + ShowParcs(); + HandleEvents(); + if (XCheckTypedWindowEvent(display,Cow,Expose,&CowEvent)) + RedrawControlWindow(); + for (i=0 ; i < Parcs ; ++i) pparcs[i] = Parc[i].Val; + + XSync(display,1); + if (Shutdown && MRpid < 1) SaveConfig(); + if (Debug) printf("iguistep returns %d\n",Shutdown); + return Shutdown; +} + +int nresources_(double *ut, double *st, long *mem, long *par, long *paf, + long *swa, long *dr, long *dw) +{ + struct rusage ru; + getrusage(RUSAGE_SELF,&ru); + *ut = ru.ru_utime.tv_sec + 0.000001 * ru.ru_utime.tv_usec; + *st = ru.ru_stime.tv_sec + 0.000001 * ru.ru_stime.tv_usec; + *mem = ru.ru_maxrss; + *par = ru.ru_minflt; + *paf = ru.ru_majflt; + *swa = ru.ru_nswap; + *dr = ru.ru_inblock; + *dw = ru.ru_oublock; + return 1; +} + +/* ------------------------------------------------ */ +/* Stub routines for Absoft Compiler and others, */ +/* which require, that FORTRAN callable C-functions */ +/* are written in uppercase letters only */ +/* ------------------------------------------------ */ + + +void INITGUI(int *model, int *debug, int *lats, int *mrpid, int *mrnum, char *plan) +{ + initgui_(model,debug,lats,mrpid,mrnum,plan); +} + +void GUICLOSE(void) +{ + guiclose_(); +} + +int IGUISTEP(float pparcs[], int kdatim[]) +{ + return iguistep_(pparcs,kdatim); +} + +void GUIPUT(char *aname, float *array, int *dimx, int *dimy, int *dimz) +{ + guiput_(aname, array, dimx, dimy, dimz); +} + +int NRESOURCES(double *ut, double *st, long *mem, long *par, long *paf, + long *swa, long *dr, long *dw) +{ + return nresources_(ut,st,mem,par,paf,swa,dr,dw); +} + +/* ------------------------------------------------ */ +/* Stub routines for IBM Compiler and others, */ +/* which require, that FORTRAN callable C-functions */ +/* are written in lowercase without underscore */ +/* ------------------------------------------------ */ + + +void initgui(int *model, int *debug, int *lats, int *mrpid, int *mrnum, char *plan) +{ + initgui_(model,debug,lats,mrpid,mrnum,plan); +} + +void guiclose(void) +{ + guiclose_(); +} + +int iguistep(float pparcs[], int kdatim[]) +{ + return iguistep_(pparcs,kdatim); +} + +void guiput(char *aname, float *array, int *dimx, int *dimy, int *dimz) +{ + guiput_(aname, array, dimx, dimy, dimz); +} + +int iguinan_(double *p) +{ + return isnan(*p); +} + +int nresources(double *ut, double *st, long *mem, long *par, long *paf, + long *swa, long *dr, long *dw) +{ + return nresources_(ut,st,mem,par,paf,swa,dr,dw); +} diff --git a/cat/src/guix11.c b/cat/src/guix11.c index e198eb49347d71ebf13f3e4d19f89418f443179a..b08ec1d9ecf84f0e2a8b2e9382855efb2667f985 100644 --- a/cat/src/guix11.c +++ b/cat/src/guix11.c @@ -82,6 +82,7 @@ int Debug = 0; // set in initgui #define ISOROT 10 #define MAPHOR 11 #define MAPTRA 12 +#define LINE 13 /* Models */ @@ -102,7 +103,8 @@ char *IsoNames[] = "ISOCOL", "ISOROT", "MAPHOR", - "MAPTRA" + "MAPTRA", + "LINE" }; int IsoTypes = sizeof(IsoNames) / sizeof(char *); @@ -301,8 +303,8 @@ REAL *TSdata[NUMWIN]; REAL *Dmin[NUMWIN]; REAL *Dmax[NUMWIN]; REAL *SpeedScale; -XPoint *TSxp[NUMWIN]; - +XPoint *TSxp[NUMWIN]; // data for timeseries +XPoint *LIxp[NUMWIN]; // data for line plots #define MAXPAR 16384 float pax[MAXPAR]; @@ -2566,6 +2568,55 @@ void IsoLines(struct ColorStrip Strip[],int Colored) } } + +/* ======== */ +/* LinePlot */ +/* ======== */ + +void LinePlot(int w) +{ + int i; + REAL zmin,zmax,zrange,zdelta,f; + + // allocate space for plot data + + if (LIxp[w] == NULL) LIxp[w] = SizeAlloc(DimX, sizeof(XPoint),"LIxp"); + + // compute minimum & maximum for auto scaling + + zmin = zmax = Field[0]; + for (i=1 ; i < DimX ; ++i) + { + zmin = MIN(zmin,Field[i]); + zmax = MAX(zmax,Field[i]); + } + zrange = zmax - zmin; + if (zrange < 1e-10) f = 1.0; + else f = (InYSize-2) / zrange; + + // scale plot data + + for (i=0 ; i < DimX ; ++i) + { + LIxp[w]->x = VGAX * i; + LIxp[w]->y = InYSize - 1 - f * (Field[i] - zmin); + } + + // fill plot area with black + + XSetForeground(display,gc,BlackPix); + XFillRectangle(display,pix,gc,0,0,WinXSize,InYSize); + + // draw data + + XDrawLines(display,pix,gc,LIxp[w],DimX,CoordModeOrigin); +} + + +/* ======== */ +/* AziPoint */ +/* ======== */ + int AziPoint(int fpx, int fpy, int *x2, int *y2) { int xc,yc; @@ -4599,6 +4650,13 @@ void iso(int w,int PicType,REAL *field,int dimx,int dimy,int dimz,int pal) AmplitudePlot(); } + // line plot + + if (PicType == LINE) + { + LinePlot(w); + } + if (Grid && PicType == ISOCS) ShowGridCS(); if (Grid && PicType == ISOLON) ShowGridLonsi(); if (Grid && PicType == ISOHOV && MapPro[w] == 0) ShowGridHov(); diff --git a/most.c b/most.c index 7c21d626e9a98a3a830c10ff5bb5c028785ec5e1..35e4fdd4cfeca94c949f3721191eefafc3b2818b 100644 --- a/most.c +++ b/most.c @@ -1054,6 +1054,8 @@ void InitNamelist(void) NL_r(CAT,"cat","AFORC" , 0.001); NL_r(CAT,"cat","TFORC" , 0.01); NL_i(CAT,"cat","NFORC" , 0); + NL_i(CAT,"cat","NGUIDBG" , 0); + NL_i(CAT,"cat","NPOST" , 0); NL_i(CAT,"cat","NSIM" , 0); NL_i(CAT,"cat","KFMIN" , 0); NL_i(CAT,"cat","KFMAX" , 8);