/* traj.c */ /* * Vis5D system for visualizing five dimensional gridded data sets. * Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul, * Dave Santek, and Andre Battaiola. * * 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. * * As a special exception to the terms of the GNU General Public * License, you are permitted to link Vis5D with (and distribute the * resulting source and executables) the LUI library (copyright by * Stellar Computer Inc. and licensed for distribution with Vis5D), * the McIDAS library, and/or the NetCDF library, where those * libraries are governed by the terms of their own licenses. * * 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 * */ #include "../config.h" #include #include #include #include "globals.h" #include "grid.h" #include "proj.h" #define TRUNC(X) ( (float) (int) (X) ) /* * Initialize the trajectory tracing module. * Return: 1 = ok, 0 = error */ int init_traj( Context ctx ) { int i, j; float lata, lona, latb, lonb, latc, lonc; float d, us, vs; float lat0, lon0, lat1, lon1, lat2, lon2; float midrow, midcol; int var = 0; /* the index of any wind variable */ if (ctx->dpy_ctx->TrajU>=0) var = ctx->dpy_ctx->TrajU; else if (ctx->dpy_ctx->TrajV>=0) var= ctx->dpy_ctx->TrajV; else if (ctx->dpy_ctx->TrajW>=0) var= ctx->dpy_ctx->TrajW; /* Compute initial trajectory step and length values */ switch (ctx->Projection) { case PROJ_GENERIC: ctx->TrajStep = 1.0; ctx->TrajLength = 1.0; break; default: /* TODO: verify this is ok: (seems to work) */ /* This is tricky: compute distance, in meters, from left to */ /* right edge of domain. Do it in two steps to prevent "wrap- */ /* around" when difference in longitudes > 180 degrees. */ midrow = (float) ctx->Nr / 2.0; midcol = (float) ctx->Nc / 2.0; rowcol_to_latlon( ctx, -1, -1, midrow, 0.0, &lat0, &lon0 ); rowcol_to_latlon( ctx, -1, -1, midrow, midcol, &lat1, &lon1 ); rowcol_to_latlon( ctx, -1, -1, midrow, (float) (ctx->Nc-1), &lat2, &lon2 ); d = earth_distance( lat0, lon0, lat1, lon1 ) + earth_distance( lat1, lon1, lat2, lon2 ); ctx->TrajStep = TRUNC( (d / 100.0) / 25.0 ); /* the above was: (float) ctx->Elapsed[1] / 2.0;*/ ctx->TrajLength = 5.0 * ctx->TrajStep; /* the above was: (float) ctx->Elapsed[1]; */ break; } /* These values are set by the user through the trajectory widget */ /* They are just multipliers of the internal values TrajStep and */ /* TrajLength: */ ctx->dpy_ctx->UserTrajStep = ctx->dpy_ctx->UserTrajLength = 1.0; /* * Compute m/s to boxes/s scaling factors for U and V components */ switch (ctx->Projection) { case PROJ_GENERIC: /* for a generic projection, we assume U, and V velocities are in */ /* X per second, where X is the same units used for NorthBound, */ /* WestBound, ctx->RowInc, and ctx->ColInc */ us = 1.0 / ctx->ColInc; vs = -1.0 / ctx->RowInc; for (i=0;iNr;i++) { for (j=0;jNc;j++) { ctx->Uscale[i][j] = us; ctx->Vscale[i][j] = vs; } } break; case PROJ_LINEAR: case PROJ_LAMBERT: case PROJ_STEREO: case PROJ_ROTATED: case PROJ_CYLINDRICAL: case PROJ_SPHERICAL: case PROJ_MERCATOR: for (i=0;iNr;i++) { for (j=0;jNc;j++) { float ii = (float) i; float jj = (float) j; /* Compute U scale */ if (j==0) { rowcol_to_latlon( ctx, 0, var, ii, jj, &lata, &lona ); rowcol_to_latlon( ctx, 0, var, ii, jj+1.0, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else if (j==ctx->Nc-1) { rowcol_to_latlon( ctx, 0, var, ii, jj-1.0, &lata, &lona ); rowcol_to_latlon( ctx, 0, var, ii, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else { rowcol_to_latlon( ctx, 0, var, ii, jj-1.0, &lata, &lona ); rowcol_to_latlon( ctx, 0, var, ii, jj, &latb, &lonb ); rowcol_to_latlon( ctx, 0, var, ii, jj+1.0, &latc, &lonc ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; if (latc > 89.9) latc = 89.9; if (latc < -89.9) latc = -89.9; d = (earth_distance( lata,lona, latb,lonb) + earth_distance( latb,lonb, latc,lonc)) / 2.0; } ctx->Uscale[i][j] = 1.0 / d; /* Compute V scale */ if (i==0) { rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii, jj, &lata, &lona ); rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii+1.0, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else if (j==ctx->Nc-1) { rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii-1.0, jj, &lata, &lona ); rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else { rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii-1.0, jj, &lata, &lona ); rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii, jj, &latb, &lonb ); rowcol_to_latlon( ctx, 0, ctx->dpy_ctx->TrajV, ii+1.0, jj, &latc, &lonc ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; if (latc > 89.9) latc = 89.9; if (latc < -89.9) latc = -89.9; d = (earth_distance( lata,lona, latb,lonb) + earth_distance( latb,lonb, latc,lonc)) / 2.0; } ctx->Vscale[i][j] = -1.0 / d; /* Note negative!!! */ } } break; default: printf("Error in init_traj: Projection=%d\n", ctx->Projection); return 0; } /* * Compute m/s to boxes/s scaling factors for W component */ switch (ctx->VerticalSystem) { case VERT_GENERIC: for (i=0;iMaxNl;i++) { ctx->Wscale[i] = 1.0 / ctx->LevInc; } break; case VERT_EQUAL_KM: for (i=0;iMaxNl;i++) { ctx->Wscale[i] = 1.0 / (ctx->LevInc * 1000.0); } break; case VERT_NONEQUAL_MB: case VERT_NONEQUAL_KM: for (i=0;iMaxNl;i++) { if (i==0) { float hgt1 = gridlevel_to_height( ctx, 1.0 ); float hgt0 = gridlevel_to_height( ctx, 0.0 ); float diff = hgt1-hgt0; if (fabs(diff) < 0.000001) diff = 0.000001; ctx->Wscale[i] = 1.0 / (diff * 1000.0); /* ctx->Wscale[i] = 1.0 / ((hgt1-hgt0) * 1000.0); */ } else if (i==ctx->MaxNl-1) { float hgt1 = gridlevel_to_height( ctx, (float)(ctx->MaxNl-1) ); float hgt0 = gridlevel_to_height( ctx, (float)(ctx->MaxNl-2) ); float diff = hgt1-hgt0; if (fabs(diff) < 0.000001) diff = 0.000001; ctx->Wscale[i] = 1.0 / (diff * 1000.0); /* ctx->Wscale[i] = 1.0 / ((hgt1-hgt0) * 1000.0); */ } else { float a, b; float hgt2 = gridlevel_to_height( ctx, (float)(i+1) ); float hgt1 = gridlevel_to_height( ctx, (float) i ); float hgt0 = gridlevel_to_height( ctx, (float)(i-1) ); float diffa = hgt1-hgt0; float diffb = hgt2-hgt1; if (fabs(diffa) < 0.000001) diffa = 0.000001; if (fabs(diffb) < 0.000001) diffb = 0.000001; a = 1.0 / (diffa * 1000.0); b = 1.0 / (diffb * 1000.0); /* float a = 1.0 / ((hgt1-hgt0) * 1000.0); float b = 1.0 / ((hgt2-hgt1) * 1000.0); */ ctx->Wscale[i] = (a+b) / 2.0; } } break; default: printf("Error in init_traj: ctx->VerticalSystem=%d\n", ctx->VerticalSystem); return 0; } return 1; } /* * Return U, V, and W for a discrete position in time and space. * Return: 1 = ok, 0 = missing data. */ static int get_discrete_uvw( Context ctx, int time, int r, int c, int l, float *uptr, float *vptr, float *wptr ) { float u = get_grid_value( ctx, time, ctx->dpy_ctx->TrajU, r, c, l ); float v = get_grid_value( ctx, time, ctx->dpy_ctx->TrajV, r, c, l ); float w = get_grid_value( ctx, time, ctx->dpy_ctx->TrajW, r, c, l ); if (IS_MISSING(u) || IS_MISSING(v) || IS_MISSING(w)) { /* missing */ return 0; } else { /* return u,v,w in boxes/sec */ *uptr = u * ctx->Uscale[r][c]; *vptr = v * ctx->Vscale[r][c]; *wptr = w * ctx->Wscale[l]; return 1; } } static int get_discrete_uv( Context ctx, int time, int r, int c, int l, float *uptr, float *vptr, float *wptr ) { float u = get_grid_value( ctx, time, ctx->dpy_ctx->TrajU, r, c, l ); float v = get_grid_value( ctx, time, ctx->dpy_ctx->TrajV, r, c, l ); if (IS_MISSING(u) || IS_MISSING(v)) { /* missing */ return 0; } else { /* return u,v,w in boxes/sec */ *uptr = u * ctx->Uscale[r][c]; *vptr = v * ctx->Vscale[r][c]; *wptr = 0; return 1; } } int init_trajPRIME( Display_Context dtx ) { int i, j; float lata, lona, latb, lonb, latc, lonc; float d, us, vs; float lat0, lon0, lat1, lon1, lat2, lon2; float midrow, midcol; int var = 0; dtx->UserTrajStep = dtx->UserTrajLength = 1.0; switch (dtx->Projection) { case PROJ_GENERIC: dtx->TrajStep = 1.0; dtx->TrajLength = 1.0; break; default: /* TODO: verify this is ok: (seems to work) */ /* This is tricky: compute distance, in meters, from left to */ /* right edge of domain. Do it in two steps to prevent "wrap- */ /* around" when difference in longitudes > 180 degrees. */ midrow = (float) dtx->Nr / 2.0; midcol = (float) dtx->Nc / 2.0; rowcolPRIME_to_latlon( dtx, -1, -1, midrow, 0.0, &lat0, &lon0 ); rowcolPRIME_to_latlon( dtx, -1, -1, midrow, midcol, &lat1, &lon1 ); rowcolPRIME_to_latlon( dtx, -1, -1, midrow, (float) (dtx->Nc-1), &lat2, &lon2 ); d = earth_distance( lat0, lon0, lat1, lon1 ) + earth_distance( lat1, lon1, lat2, lon2 ); dtx->TrajStep = TRUNC( (d / 100.0) / 25.0 ); /* the above was: (float) dtx->Elapsed[1] / 2.0;*/ dtx->TrajLength = 5.0 * dtx->TrajStep; /* the above was: (float) dtx->Elapsed[1]; */ break; } /* * Compute m/s to boxes/s scaling factors for U and V components */ switch (dtx->Projection) { case PROJ_GENERIC: /* for a generic projection, we assume U, and V velocities are in */ /* X per second, where X is the same units used for NorthBound, */ /* WestBound, dtx->RowInc, and dtx->ColInc */ us = 1.0 / dtx->ColInc; vs = -1.0 / dtx->RowInc; for (i=0;iNr;i++) { for (j=0;jNc;j++) { dtx->Uscale[i][j] = us; dtx->Vscale[i][j] = vs; } } break; case PROJ_LINEAR: case PROJ_LAMBERT: case PROJ_STEREO: case PROJ_ROTATED: case PROJ_CYLINDRICAL: case PROJ_SPHERICAL: case PROJ_MERCATOR: for (i=0;iNr;i++) { for (j=0;jNc;j++) { float ii = (float) i; float jj = (float) j; /* Compute U scale */ if (j==0) { rowcolPRIME_to_latlon( dtx, 0, var, ii, jj, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, var, ii, jj+1.0, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else if (j==dtx->Nc-1) { rowcolPRIME_to_latlon( dtx, 0, var, ii, jj-1.0, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, var, ii, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else { rowcolPRIME_to_latlon( dtx, 0, var, ii, jj-1.0, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, var, ii, jj, &latb, &lonb ); rowcolPRIME_to_latlon( dtx, 0, var, ii, jj+1.0, &latc, &lonc ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; if (latc > 89.9) latc = 89.9; if (latc < -89.9) latc = -89.9; d = (earth_distance( lata,lona, latb,lonb) + earth_distance( latb,lonb, latc,lonc)) / 2.0; } dtx->Uscale[i][j] = 1.0 / d; /* Compute V scale */ if (i==0) { rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii, jj, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii+1.0, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else if (j==dtx->Nc-1) { rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii-1.0, jj, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii, jj, &latb, &lonb ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; d = earth_distance( lata, lona, latb, lonb ); } else { rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii-1.0, jj, &lata, &lona ); rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii, jj, &latb, &lonb ); rowcolPRIME_to_latlon( dtx, 0, dtx->TrajV, ii+1.0, jj, &latc, &lonc ); /* WLH 3-21-97 */ if (lata > 89.9) lata = 89.9; if (lata < -89.9) lata = -89.9; if (latb > 89.9) latb = 89.9; if (latb < -89.9) latb = -89.9; if (latc > 89.9) latc = 89.9; if (latc < -89.9) latc = -89.9; d = (earth_distance( lata,lona, latb,lonb) + earth_distance( latb,lonb, latc,lonc)) / 2.0; } dtx->Vscale[i][j] = -1.0 / d; /* Note negative!!! */ } } break; default: printf("Error in init_trajPRIME: Projection=%d\n", dtx->Projection); return 0; } /* * Compute m/s to boxes/s scaling factors for W component */ switch (dtx->VerticalSystem) { case VERT_GENERIC: for (i=0;iMaxNl;i++) { dtx->Wscale[i] = 1.0 / dtx->LevInc; } break; case VERT_EQUAL_KM: for (i=0;iMaxNl;i++) { dtx->Wscale[i] = 1.0 / (dtx->LevInc * 1000.0); } break; case VERT_NONEQUAL_MB: case VERT_NONEQUAL_KM: for (i=0;iMaxNl;i++) { if (i==0) { float hgt1 = gridlevelPRIME_to_height( dtx, 1.0 ); float hgt0 = gridlevelPRIME_to_height( dtx, 0.0 ); float diff = hgt1-hgt0; if (fabs(diff) < 0.000001) diff = 0.000001; dtx->Wscale[i] = 1.0 / (diff * 1000.0); /* dtx->Wscale[i] = 1.0 / ((hgt1-hgt0) * 1000.0); */ } else if (i==dtx->MaxNl-1) { float hgt1 = gridlevelPRIME_to_height( dtx, (float)(dtx->MaxNl-1) ); float hgt0 = gridlevelPRIME_to_height( dtx, (float)(dtx->MaxNl-2) ); float diff = hgt1-hgt0; if (fabs(diff) < 0.000001) diff = 0.000001; dtx->Wscale[i] = 1.0 / (diff * 1000.0); /* dtx->Wscale[i] = 1.0 / ((hgt1-hgt0) * 1000.0); */ } else { float a, b; float hgt2 = gridlevelPRIME_to_height( dtx, (float)(i+1) ); float hgt1 = gridlevelPRIME_to_height( dtx, (float) i ); float hgt0 = gridlevelPRIME_to_height( dtx, (float)(i-1) ); float diffa = hgt1-hgt0; float diffb = hgt2-hgt1; if (fabs(diffa) < 0.000001) diffa = 0.000001; if (fabs(diffb) < 0.000001) diffb = 0.000001; a = 1.0 / (diffa * 1000.0); b = 1.0 / (diffb * 1000.0); /* float a = 1.0 / ((hgt1-hgt0) * 1000.0); float b = 1.0 / ((hgt2-hgt1) * 1000.0); */ dtx->Wscale[i] = (a+b) / 2.0; } } break; default: printf("Error in init_trajPRIME: dtx->VerticalSystem=%d\n", dtx->VerticalSystem); return 0; } return 1; } /* * Given two timesteps and a (row,col,lev) position perform a 4-D * interpolation of neighboring values to get the U,V, and W wind * vector components in units of grid boxes/second. * Input: t0, t1 - the two timesteps * at, bt - timestep weights (at+bt=1.0) * row, col, lev - the grid position * Output: u, v, w - the interpolated and scaled wind vector values * Return: 0 = missing data was found, 1 = valid values */ static int get_uvw( Context ctx, int t0, int t1, float at, float bt, float row, float col, float lev, float *u, float *v, float *w, float sl ) { int i, j, k; float bra, ara, bca, aca, bla, ala, aa, ba, ab, bb; float aaaa,abaa,baaa,bbaa,aaba,abba,baba,bbba, aaab,abab,baab,bbab,aabb,abbb,babb,bbbb; float ullll, ullhl, ulhll, ulhhl, uhlll, uhlhl, uhhll, uhhhl, ulllh, ullhh, ulhlh, ulhhh, uhllh, uhlhh, uhhlh, uhhhh; float vllll, vllhl, vlhll, vlhhl, vhlll, vhlhl, vhhll, vhhhl, vlllh, vllhh, vlhlh, vlhhh, vhllh, vhlhh, vhhlh, vhhhh; float wllll, wllhl, wlhll, wlhhl, whlll, whlhl, whhll, whhhl, wlllh, wllhh, wlhlh, wlhhh, whllh, whlhh, whhlh, whhhh; /* calculate weights for interpolating in box */ i = (int) row; j = (int) col; k = (int) lev; bra = row-i; ara = 1.0-bra; bca = col-j; aca = 1.0-bca; bla = lev-k; ala = 1.0-bla; aa = ala*at; ba = bla*at; ab = ala*bt; bb = bla*bt; /* get 16 weights for 4-d box */ /* note 4 a/b's are in order of j,i,k,time */ aaaa = aca*ara*aa; abaa = aca*bra*aa; baaa = bca*ara*aa; bbaa = bca*bra*aa; aaba = aca*ara*ba; abba = aca*bra*ba; baba = bca*ara*ba; bbba = bca*bra*ba; aaab = aca*ara*ab; abab = aca*bra*ab; baab = bca*ara*ab; bbab = bca*bra*ab; aabb = aca*ara*bb; abbb = aca*bra*bb; babb = bca*ara*bb; bbbb = bca*bra*bb; /* get u,v,w grid values at 16 corners of 4-d box */ /* note 4 l/h's are in order of j,i,k,time */ /* return 0 if any missing data is found */ if (!sl){ if (!get_discrete_uvw( ctx, t0, i,j,k, &ullll, &vllll, &wllll )) return 0; if (!get_discrete_uvw( ctx, t0, i,j,k+1, &ullhl, &vllhl, &wllhl )) return 0; if (!get_discrete_uvw( ctx, t0, i+1,j,k, &ulhll, &vlhll, &wlhll )) return 0; if (!get_discrete_uvw( ctx, t0, i+1,j,k+1, &ulhhl, &vlhhl, &wlhhl )) return 0; if (!get_discrete_uvw( ctx, t0, i,j+1,k, &uhlll, &vhlll, &whlll )) return 0; if (!get_discrete_uvw( ctx, t0, i,j+1,k+1, &uhlhl, &vhlhl, &whlhl )) return 0; if (!get_discrete_uvw( ctx, t0, i+1,j+1,k, &uhhll, &vhhll, &whhll )) return 0; if (!get_discrete_uvw( ctx, t0, i+1,j+1,k+1, &uhhhl, &vhhhl, &whhhl )) return 0; if (!get_discrete_uvw( ctx, t1, i,j,k, &ulllh, &vlllh, &wlllh )) return 0; if (!get_discrete_uvw( ctx, t1, i,j,k+1, &ullhh, &vllhh, &wllhh )) return 0; if (!get_discrete_uvw( ctx, t1, i+1,j,k, &ulhlh, &vlhlh, &wlhlh )) return 0; if (!get_discrete_uvw( ctx, t1, i+1,j,k+1, &ulhhh, &vlhhh, &wlhhh )) return 0; if (!get_discrete_uvw( ctx, t1, i,j+1,k, &uhllh, &vhllh, &whllh )) return 0; if (!get_discrete_uvw( ctx, t1, i,j+1,k+1, &uhlhh, &vhlhh, &whlhh )) return 0; if (!get_discrete_uvw( ctx, t1, i+1,j+1,k, &uhhlh, &vhhlh, &whhlh )) return 0; if (!get_discrete_uvw( ctx, t1, i+1,j+1,k+1, &uhhhh, &vhhhh, &whhhh )) return 0; /* interpolate to get wind vector */ *u = aaaa*ullll+aaab*ulllh+aaba*ullhl+aabb*ullhh+ abaa*ulhll+abab*ulhlh+abba*ulhhl+abbb*ulhhh+ baaa*uhlll+baab*uhllh+baba*uhlhl+babb*uhlhh+ bbaa*uhhll+bbab*uhhlh+bbba*uhhhl+bbbb*uhhhh; *v = aaaa*vllll+aaab*vlllh+aaba*vllhl+aabb*vllhh+ abaa*vlhll+abab*vlhlh+abba*vlhhl+abbb*vlhhh+ baaa*vhlll+baab*vhllh+baba*vhlhl+babb*vhlhh+ bbaa*vhhll+bbab*vhhlh+bbba*vhhhl+bbbb*vhhhh; *w = aaaa*wllll+aaab*wlllh+aaba*wllhl+aabb*wllhh+ abaa*wlhll+abab*wlhlh+abba*wlhhl+abbb*wlhhh+ baaa*whlll+baab*whllh+baba*whlhl+babb*whlhh+ bbaa*whhll+bbab*whhlh+bbba*whhhl+bbbb*whhhh; } else{ /* only one level */ if (!get_discrete_uv( ctx, t0, i,j,k, &ullll, &vllll, &wllll )) return 0; if (!get_discrete_uv( ctx, t0, i,j,k, &ullhl, &vllhl, &wllhl )) return 0; if (!get_discrete_uv( ctx, t0, i+1,j,k, &ulhll, &vlhll, &wlhll )) return 0; if (!get_discrete_uv( ctx, t0, i+1,j,k, &ulhhl, &vlhhl, &wlhhl )) return 0; if (!get_discrete_uv( ctx, t0, i,j+1,k, &uhlll, &vhlll, &whlll )) return 0; if (!get_discrete_uv( ctx, t0, i,j+1,k, &uhlhl, &vhlhl, &whlhl )) return 0; if (!get_discrete_uv( ctx, t0, i+1,j+1,k, &uhhll, &vhhll, &whhll )) return 0; if (!get_discrete_uv( ctx, t0, i+1,j+1,k, &uhhhl, &vhhhl, &whhhl )) return 0; if (!get_discrete_uv( ctx, t1, i,j,k, &ulllh, &vlllh, &wlllh )) return 0; if (!get_discrete_uv( ctx, t1, i,j,k, &ullhh, &vllhh, &wllhh )) return 0; if (!get_discrete_uv( ctx, t1, i+1,j,k, &ulhlh, &vlhlh, &wlhlh )) return 0; if (!get_discrete_uv( ctx, t1, i+1,j,k, &ulhhh, &vlhhh, &wlhhh )) return 0; if (!get_discrete_uv( ctx, t1, i,j+1,k, &uhllh, &vhllh, &whllh )) return 0; if (!get_discrete_uv( ctx, t1, i,j+1,k, &uhlhh, &vhlhh, &whlhh )) return 0; if (!get_discrete_uv( ctx, t1, i+1,j+1,k, &uhhlh, &vhhlh, &whhlh )) return 0; if (!get_discrete_uv( ctx, t1, i+1,j+1,k, &uhhhh, &vhhhh, &whhhh )) return 0; /* interpolate to get wind vector */ *u = aaaa*ullll+aaab*ulllh+aaba*ullhl+aabb*ullhh+ abaa*ulhll+abab*ulhlh+abba*ulhhl+abbb*ulhhh+ baaa*uhlll+baab*uhllh+baba*uhlhl+babb*uhlhh+ bbaa*uhhll+bbab*uhhlh+bbba*uhhhl+bbbb*uhhhh; *v = aaaa*vllll+aaab*vlllh+aaba*vllhl+aabb*vllhh+ abaa*vlhll+abab*vlhlh+abba*vlhhl+abbb*vlhhh+ baaa*vhlll+baab*vhllh+baba*vhlhl+babb*vhlhh+ bbaa*vhhll+bbab*vhhlh+bbba*vhhhl+bbbb*vhhhh; *w = 0; } return 1; } /* * Trace a wind trajectory. * Input: row0, col0, lev0 - initial location * time0 - initial timestep * step - integration step size in seconds * max - size of vr,vc,vl,vt arrays * Output: vr, vc, vl - array of trajectory vertices * vt - array of corresponding trajectory vertex times in seconds * elapsed since first time step. * Return: number of elements in vr,vc,vl,vt */ int trace( Context ctx, float row0, float col0, float lev0, int time0, int step, int max, float vr[], float vc[], float vl[], int vt[] ) { float row, col, lev; int time; /* in seconds since first time step */ int itime; /* time step corresponding to 'time' */ int i, vcount, singlelevel; float maxr, maxc, maxl, minl; /* grid bounds */ maxr = (float) (ctx->Nr-1); maxc = (float) (ctx->Nc-1); maxl = (float) (ctx->Nl[ctx->dpy_ctx->TrajU]-1); minl = (float) ctx->Variable[ctx->dpy_ctx->TrajU]->LowLev; /* allow trajs to work if u&v in one level only */ if (maxl == 0 && lev0 == minl){ singlelevel = 1; } else{ singlelevel = 0; } vcount = max; /* TRACE TRAJECTORY BACKWARD (put vertices into array in backward order) */ row = row0; col = col0; lev = lev0; time = ctx->Elapsed[time0]; itime = time0; while (1) { float at, bt, u, v, w; /* test if current position is out of bounds */ if (row<0.0 || row>maxr || col<0.0 || col>maxc || lev<0.0 || lev>maxl || levNumTimes) { if (!get_uvw( ctx, itime, itime, 1.0, 0.0, row, col, lev, &u, &v, &w, singlelevel )) break; } else { if (ctx->Elapsed[itime]==ctx->Elapsed[itime+1]) { /* this should never happen unless the file is screwy */ break; } at = (float) (ctx->Elapsed[itime+1] - time) / (float) (ctx->Elapsed[itime+1]-ctx->Elapsed[itime]); bt = 1.0 - at; if (!get_uvw( ctx, itime, itime+1, at, bt, row, col, lev, &u, &v, &w, singlelevel )) break; } /* update position and time */ col -= u * (float) step; /* pos' = pos + velocity * time */ row -= v * (float) step; lev -= w * (float) step; time -= step; if (timeElapsed[itime]) itime--; } /* MOVE VERTICES FROM END TO BEGINNING OF ARRAY */ i = 0; while (vcountElapsed[time0]; itime = time0; while (1) { float at, bt, u, v, w; /* test if position is out of bounds */ if (row<0.0 || row>maxr || col<0.0 || col>maxc || lev<0.0 || lev>maxl || lev=max) break; /* test if time is out of bounds */ if (time>=ctx->Elapsed[ctx->NumTimes-1]) break; /* get u,v,w vector at current location and time */ if (ctx->Elapsed[itime]==ctx->Elapsed[itime+1]) { /* this should never happen unless the file is screwy */ break; } at = (float) (ctx->Elapsed[itime+1] - time) / (float) (ctx->Elapsed[itime+1]-ctx->Elapsed[itime]); bt = 1.0 - at; if (!get_uvw( ctx, itime, itime+1, at, bt, row, col, lev, &u, &v, &w, singlelevel )) break; /* update position and time */ col += u * (float) step; /* pos' = pos + velocity * time */ row += v * (float) step; lev += w * (float) step; time += step; if (time>ctx->Elapsed[itime+1]) itime++; } /* print the vertex list */ /*for (i=0;i max){ vcount = max; } return vcount; } #define MAX 5000 #define EPS 0.0000000001 #define WSCALE 150.0 #define RADIUS 10.0 /* * Convert a trajectory path to a ribbon. */ int to_ribbon( int num, float xt[], float yt[], float zt[], int itint[], float xn[], float yn[], float zn[] ) { int i, it, ip, il, ih; int iuu, imm, idd, iu, id; float ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz, ex, ey, ez; float cc, dd, ee; float scale; float xr[MAX], yr[MAX], zr[MAX]; int itinr[MAX]; scale = 2.0/WSCALE; for (i=0;i 0.0) { cx=cx+ax; cy=cy+ay; cz=cz+az; } else { cx=cx-ax; cy=cy-ay; cz=cz-az; } /* GET COMPONENT OF (CROSS RIBBON) NORMAL TO ALONG RIBBON */ dx=xn[it]; dy=yn[it]; dz=zn[it]; dd=cx*dx+cy*dy+cz*dz; cx=cx-dd*dx; cy=cy-dd*dy; cz=cz-dd*dz; /* SCALE CROSS RIBBON TO RADIUS LENGTH */ cc = sqrt(cx*cx+cy*cy+cz*cz); if (cc < EPS) cc = EPS; cc = RADIUS/cc; cx=cx*cc; cy=cy*cc; cz=cz*cc; xt[it]=cx; yt[it]=cy; zt[it]=cz; } /* 20 CONTINUE; */ /* NOW DO RIBBONS */ /* DO 40 I=IL,IH */ for (i=il;i