Skip to content

2.4.0

Choose a tag to compare

@wdolinar wdolinar released this 04 Sep 05:08

2.4.0 - Sampling the field without tracing through it

One addition, and the behaviour around it. It completes what 2.3.0 started:
a client can now seed glyphs from a viewport lattice and draw them, whether
or not those glyphs go on to follow the flow.

New: SampleVectors / sample_vectors

Reports the field at each of a set of points that has one, without tracing
any of them. This is the interpolation a trace step already performs - one
point-location search per point against the cached triangulation, then the
two bracketing time steps blended at the requested time - exposed for
callers that want the field rather than a path through it.

The case it exists for is a display drawing a glyph per position on a moving
set of positions. ON_GRID placement anchors its lattice to the view and steps
it by the camera's parallel scale, so every pan and every zoom moves all of
them and the field has to be resampled wherever they land. (Rotation alone
does not: it moves neither the anchor nor the step.)

It reuses GetVectorAtLocationAndTime rather than sampling an extractor
alongside the tracer. If the two could disagree, a glyph and the path leaving
it would start from different fields.

Batched, for two reasons: the tracer's search scratch is reused across the
batch instead of reallocated per point, and a per-point call across a
language boundary costs more than the search it would perform.

Only the points that resolved are reported

Each comes back beside its own vector, so there is no no-data marker at the
API at all. A set of positions covering a view is mostly outside the grid or
over inactive cells; reporting those would hand every caller the same
filtering step, and one that forgot it would take XM_NODATA for a velocity.

Both outputs are subsets of the input's order, so a caller that does want to
know which of its points missed can walk the two in step. A miss in the
middle of a batch does not truncate it - the caller pairs glyphs to samples
by position, so a short batch would bind every later glyph to the wrong
sample.

The points kept are exactly the seeds StartTraces will accept, inactive cells
included. Both test the same GetVectorAtLocationAndTime result: StartTraces
to refuse a seed as GTEXIT_SEED_NOT_TRACEABLE, this to leave the point out.
A caller that follows the flow from these points needs no further filtering.

Two time steps are required, as tracing requires them. With fewer, nothing is
reported rather than a partial answer.

The sampled time is clamped to the loaded window

A time outside the two loaded steps reads the nearer one instead of
extrapolating a speed the field never had. That is also where a trace given
the same time comes to rest, so a glyph and the trace leaving it agree.

A non-finite result is rejected the same way a missing one is, because the
sentinel test alone does not catch one: EQ_TOL(NaN, XM_NODATA, 1) is false.
Two routes produce one, both from the caller - a NaN time passes both clamp
comparisons untouched, since NaN compares false against either bound, and two
steps loaded at the same time make the blend window zero, so its weights are
0/0. The guard tests the result rather than either cause, which covers both
and leaves the trace hot path unchanged.

Reports the field, not the tracing: the vector multiplier is not applied,
matching GetSeedMagnitudes. Every reported vector's z is zero, and the
reported points are the caller's own, echoed unchanged, z included - the
tracer is two-dimensional and never reads or writes a z velocity.

One tracer still serves one thread at a time, as everything else on it does.
The point-location search writes scratch held on the tracer, so concurrent
calls race on it even though this method is const.

Compatibility

SampleVectors is declared last in the header, so it appends a vtable slot
rather than shifting the ones above it. It is a pure virtual on a public
abstract class, so an external subclass of XmGridTrace must implement it;
callers using the New() factory are unaffected and need no changes.

This is a minor release for the same reason 2.3.0 was, which added one pure
virtual to this interface, and 2.1.0, which added four.

Dependencies are unchanged from 2.3.0: xmscore 7.0.13, xmsgrid 9.1.1,
xmsinterp 7.0.12, xmsextractor 10.0.10.