// this example uses one KDTable in two different ways. There is a one-time call to
// kNearestRows to gather the nearest points for every point. Then, for each mouse move,
// there is a call to kNearestRows to find the nearest point to the cursor.
dim = 200; // how many random points to create
xx = J( dim, 1, 5 + 90 * Random uniform() );
yy = J( dim, 1, 5 + 90 * Random uniform() );
data = xx || yy; // matrix needed to generate KDTable is built by concatenating the coordinates
table = KDTable( data ); // this builds a KDTable from the data, do it once because it takes time
{nearRows, dist} = table << kNearestRows( 9 ); // pre-locate 9 nearest points to every point. mutant spider!
creepy = 0; // a little less creepy, by default
// creepy notes: this might be creepier still if the 9 nearest neighbors were re-looked-up
// with respect to the *cursor*. In this example, the 9 nearest neighbors are with respect to
// the *data point* nearest the cursor. This causes ALL the spider legs to move to different
// data points at the same time, which isn't what spiders do. See the cloud example.
exx = 50; // initial location of
exy = 50; // mouse handle
hand = J( 1, 2, 0 ); // handle script keeps hand matrix up-to-date
hand[1] = exx; // the hand matrix is sent to kdtable on every move
hand[2] = exy; // to find the closest point to the handle
{rows, dist} = table << kNearestRows( 1, hand ); // point near cursor
iCursor = rows[1]; // remember the point nearest the cursor/handle
New Window( "Drag handle to find neighbors",
cb = Check Box( {"Creepy"}, creepy = cb << Get(); g< 0, // got one. draw the spider legs
If( creepy == 0,
if ( exx < 30 & exy > 70, textcolor("red");text( {2,97}, "check box"));
x = [0, 0]; x[1] = xx[iCursor]; // x and y are each two elements; the point near the cursor is in
y = [0, 0]; y[1] = yy[iCursor]; // the first element. the following loop fills in the second point...
,
x = [0, 0]; x[1] = exx;// x and y are each two elements; the point near the cursor is in
y = [0, 0]; y[1] = exy;// the first element. the following loop fills in the second point...
);
For( iNear = 1, iNear <= ncols(nearRows), iNear++, // nearRows has the indexes of the points near the cursor
x[2] = xx[nearRows[iCursor,iNear]]; // each of the near by points has needs a blue line segment from
y[2] = yy[nearRows[iCursor,iNear]]; // cursor to itself
Pen Color( "Blue" );
Pen Size( 3 );
Line( x, y );
);
);
if ( exx ==50 & exy==50, textcolor("red");text( {50,50}, " <--drag square box"));
// work around issue where handle is black on black background
Marker( combinestates(Color State( if(g<