Making a visualization of the wind, similar to some that have appeared online for every hurricane recently.
JSL below with the parameters turned down for better interactive performance.
The model the code is using for the wind field is designed to make a pretty visualization and does not represent reality.
The vectors for the video look like this; the visualization changes when you drag the vectors.
The script uses Mouse Trap to position the arrows
NTRAIL = 50;
NPARTICLES = 1000;
SLOWER=50;
SMOOTHING = 9;
NBINS=15;
WINDFIELDSIZE = 40;
PARTICLESIZE = 1;
FADEPOWER = 1.5;
FADEMIN=20/255;
graphxsize=1920/2;
graphysize=1080/2;
dx = J( WINDFIELDSIZE, WINDFIELDSIZE, 0 );
dy = J( WINDFIELDSIZE, WINDFIELDSIZE, 0 );
Parallel Assign( {SLOWER=SLOWER}, dx[r( -1, 1 ), c( -1, 1 )] = Sin( r ) / SLOWER );
Parallel Assign( {SLOWER=SLOWER}, dy[r( -1, 1 ), c( -1, 1 )] = Sin( c ) / SLOWER );
windlist = {{{0.171875, 0.0458333333333334}, {0.15125, -0.715}}, {{0.171875, -0.9075},
{0.763125, -0.348333333333333}}, {{-0.859375, -0.504166666666667}, {-0.1925, -0.9075
}}, {{-0.385, 0.889166666666667}, {-0.955625, 0.119166666666667}}, {{0.78375, -0.165
}, {0.268125, 0.128333333333333}}, {{-0.240625, 0.0458333333333334}, {-0.78375,
-0.22}}, {{0.86625, -0.0183333333333333}, {0.2475, 0.8525}}, {{-0.144375,
-0.705833333333333}, {-0.2475, -0.0641666666666667}}};
caprow=.;
capcol=.;
ReleaseFunction = Function( {x, y},
{},
caprow = capcol = .;
Parallel Assign(
{SLOWER = SLOWER, windlist = windlist},
dx[r( -1, 1 ), c( -1, 1 )] = (x = 0 ; totalscale = 0 ; For( iwind = 1, iwind <= N Items( windlist ), iwind += 1,
cx = (windlist[iwind][1][1] + windlist[iwind][2][1]) / 2;
cy = (windlist[iwind][1][2] + windlist[iwind][2][2]) / 2;
dx = windlist[iwind][2][1] - windlist[iwind][1][1];
scale = 1 / (Sqrt( (c - cx) ^ 2 + (r - cy) ^ 2 ) + .001);
totalscale += scale;
x += dx * scale;
) ; x / totalscale / SLOWER)
);
Parallel Assign(
{SLOWER = SLOWER, windlist = windlist},
dy[r( -1, 1 ), c( -1, 1 )] = (y = 0 ; totalscale = 0 ; For( iwind = 1, iwind <= N Items( windlist ), iwind += 1,
cx = (windlist[iwind][1][1] + windlist[iwind][2][1]) / 2;
cy = (windlist[iwind][1][2] + windlist[iwind][2][2]) / 2;
dy = windlist[iwind][2][2] - windlist[iwind][1][2];
scale = 1 / (Sqrt( (c - cx) ^ 2 + (r - cy) ^ 2 ) + .001);
totalscale += scale;
y += dy * scale;
) ; y / totalscale / SLOWER)
);
);
ReleaseFunction(0,0);
New Window( "Example",
Graph Box(
X Scale( -1.1, 1.1 ),
Y Scale( -1.1, 1.1 ),
Pen Size( 4 );
For( iwind = 1, iwind <= N Items( windlist ), iwind += 1,
Arrow( windlist[iwind][1], windlist[iwind][2] )
);
Mousetrap(
Function( {x, y},
{irow, nearrow = ., icol, nearcol = ., dist, neardist = 1e9},
If( Is Missing( caprow ),
For( irow = 1, irow <= N Items( windlist ), irow += 1,
For( icol = 1, icol <= 2, icol += 1,
dist = Sqrt( (windlist[irow][icol][1] - x) ^ 2 + (windlist[irow][icol][2] - y) ^ 2 );
If( dist < neardist,
nearrow = irow;
nearcol = icol;
neardist = dist;
);
)
);
If( !Is Missing( nearrow ),
caprow = nearrow;
capcol = nearcol;
);
);
If( !Is Missing( caprow ) & !Is Missing( capcol ),
windlist[caprow][capcol][1] = x;
windlist[caprow][capcol][2] = y;
);
)
,
ReleaseFunction(x,y)
);
)
);
SPREAD=1/NBINS;
density = J( NBINS, NBINS, 0 );
_DX_ = 1;
_DY_ = 2;
_COLOR_ = 3;
_TRAILIDX_ = 4;
_TRAIL_ = 5;
_X_ = _TRAIL_;
_Y_ = _TRAIL_ + 1;
OUTOFPLAY = 99;
DFRACTION=SMOOTHING;
NFRACTION = DFRACTION-1;
tran = J( NTRAIL, 1, 0 );
Parallel Assign( {FADEPOWER=FADEPOWER,FADEMIN=FADEMIN^(1/FADEPOWER)}, tran[r( 1, FADEMIN ), c] = r ^ FADEPOWER );
_STRAIL_ = 2;
particles = J( NPARTICLES , _TRAIL_ - 1 + _STRAIL_ * NTRAIL, OUTOFPLAY );
particles[0, _DX_] = 0;
particles[0, _DY_] = 0;
particles[0, _TRAILIDX_] = NTRAIL;
ExpectedParticlesPerBin = NPARTICLES/nitems(density);
New Window( "Example",
g = Graph Box(
Frame Size( graphxsize, graphysize ),
X Scale( -1.1, 1.1 ),
Y Scale( -1.1, 1.1 ),
suppressaxes,
<<Marker Size( PARTICLESIZE ),
<<backgroundcolor( RGB Color( 0, .1, .2 ) ),
minDenLocs = Loc( density == Min( density ) );
minDenYLocs = Floor( (minDenLocs - 1) / N Cols( Density ) + 1 );
minDenXLocs = minDenLocs - (minDenYLocs - 1) * N Cols( Density );
yymin = .5;
yymax = N Rows( Density ) + .5;
minDenYLocs = 2 * ((minDenYLocs - yymin) / (yymax - yymin)) - 1;
xxmin = .5;
xxmax = N Cols( Density ) + .5;
minDenXLocs = 2 * ((minDenXLocs - xxmin) / (xxmax - xxmin)) - 1;
density[0, 0] = 0;
For( i = 1, i <= N Rows( particles ), i += 1,
fadeIdx = particles[i, _TRAILIDX_];
If(
fadeIdx > NTRAIL,
particles[i, (_TRAIL_ + (_STRAIL_ * 1)) :: (_TRAIL_ + _STRAIL_ * (NTRAIL) - 1)] = particles[i, (_TRAIL_ + (_STRAIL_ * 0)) :: (_TRAIL_ + _STRAIL_ * (NTRAIL - 1) - 1)];
nn = (particles[i, _TRAILIDX_] -= 1);
If( nn == NTRAIL,
rr = Random Integer( 1, N Rows( minDenXLocs ) );
tx = particles[i, _X_ + _STRAIL_ * (NTRAIL - 1)] = Max( -.999, Min( .999, Random Normal( minDenXLocs[rr], SPREAD ) ) );
ty = particles[i, _Y_ + _STRAIL_ * (NTRAIL - 1)] = Max( -.999, Min( .999, Random Normal( minDenYLocs[rr], SPREAD ) ) );
idx = 1 + Round( (N Cols( dx ) - 1) * ((tx + 1) / 2) );
idy = 1 + Round( (N Rows( dx ) - 1) * ((ty + 1) / 2) );
particles[i, _DX_] = dx[idy, idx];
particles[i, _DY_] = dy[idy, idx];
);
, fadeIdx >= 1,
If( fadeIdx > 1,
(particles[i, _TRAILIDX_] -= 1);
particles[i, (_X_ :: _Y_) + _STRAIL_ * (fadeIdx - 2)] = particles[i, (_X_ :: _Y_) + _STRAIL_ * (fadeIdx-1)] + particles[i, _DX_::_DY_];
,
particles[i, (_TRAIL_ + (_STRAIL_ * 1)) :: (_TRAIL_ + _STRAIL_ * (NTRAIL) - 1)] = particles[i, (_TRAIL_ + (_STRAIL_ * 0)) :: (_TRAIL_ + _STRAIL_ * (NTRAIL - 1) - 1)];
particles[i, (_X_ :: _Y_) + _STRAIL_ * (fadeIdx - 1)] = particles[i, (_X_ :: _Y_) + _STRAIL_ * (fadeIdx-0)] + particles[i, _DX_::_DY_];
);
If(
!(-1 < particles[i, _X_ + _STRAIL_ * (fadeIdx - 1)] < 1) | !(-1 < particles[i, _Y_ + _STRAIL_ * (fadeIdx - 1)] < 1) |
Sqrt( particles[i, _DX_] ^ 2 + particles[i, _DY_] ^ 2 ) < .0001,
particles[i, _TRAILIDX_] = 2 * NTRAIL;
particles[i, _X_ + _STRAIL_ * (1 - 1)] = OUTOFPLAY;
particles[i, _Y_ + _STRAIL_ * (1 - 1)] = OUTOFPLAY;
particles[i, _DX_] = 0;
particles[i, _DY_] = 0;
,
idx = 1 + Round( (N Cols( dx ) - 1) * ((particles[i, _X_ + _STRAIL_ * (fadeIdx - 1)] + 1) / 2) );
idy = 1 + Round( (N Rows( dx ) - 1) * ((particles[i, _Y_ + _STRAIL_ * (fadeIdx - 1)] + 1) / 2) );
particles[i, _DX_] = (NFRACTION * particles[i, _DX_] + dx[idy, idx]) / DFRACTION;
particles[i, _DY_] = (NFRACTION * particles[i, _DY_] + dy[idy, idx]) / DFRACTION;
yyy = 1 + Round( (N Rows( density ) - 1) * ((particles[i, _Y_ + _STRAIL_ * (fadeIdx - 1)] + 1) / 2) );
xxx = 1 + Round( (N Cols( density ) - 1) * ((particles[i, _X_ + _STRAIL_ * (fadeIdx - 1)] + 1) / 2) );
q=((density[yyy, xxx] += 1))/ExpectedParticlesPerBin;
if( q*randomuniform()>2,
particles[i, _TRAILIDX_] = 2 * NTRAIL;
particles[i, _X_ + _STRAIL_ * (1 - 1)] = OUTOFPLAY;
particles[i, _Y_ + _STRAIL_ * (1 - 1)] = OUTOFPLAY;
particles[i, _DX_] = 0;
particles[i, _DY_] = 0;
);
);
,
Throw( "???" )
);
);
For( i = NTRAIL, i >= 1, i -= 1,
Transparency( tran[i] );
Marker( Color State( "white" ), particles[0, _X_ + _STRAIL_ * (i - 1)], particles[0, _Y_ + _STRAIL_ * (i - 1)] );
);
)
);
wait(.01);
picno = 1e6;
while(1, g << inval<<updatewindow;wait(0);
);