Unify 2D arrows on the shared painter.
Drop orisys.util.draw_arrows; box live and replay both use _paint_shared_flow_arrows with sdk_box_policy when no policy is passed. Recovered box flow uses the same inverse as finger. Verified with shared/tests/test_image_backend.py arrow/idle/recovered cases.
This commit is contained in:
@@ -294,11 +294,10 @@ class AnalysisSession:
|
||||
the pass's own answer — the field is finite only at those cells, and
|
||||
:meth:`serve_policy` refuses a display setting that moves the grid — so the grid
|
||||
travels from the result's provenance. *Which* candidates are active is a display
|
||||
question for the shared finger painter, and ``magnitude`` is stored precisely so it
|
||||
can be asked again later. A box result on the live painter's grid is different: the
|
||||
2D canvas calls ``orisys.util.draw_arrows``, which does not read the display
|
||||
threshold, so the on/off floors stay at that painter's values (2 / 1.5 px). The 3D
|
||||
overlay uses this same policy so the two figures zero at the same strength.
|
||||
question for the shared painter, which re-selects the recovered field. A box
|
||||
result keeps the box grid's on/off floors (2 / 1.5 px) rather than the operator's
|
||||
finger thresholds, so live and replay zero at the same strength. The 3D overlay
|
||||
uses this same policy.
|
||||
|
||||
Without this, a display setting that moves the grid would be refused by
|
||||
``serve_policy`` and then applied to the drawing anyway, re-selecting the recovered
|
||||
@@ -541,12 +540,7 @@ class AnalysisSession:
|
||||
The shared painter re-selects this field, so the inverse divides by that
|
||||
product and the cap stays idempotent: the stored offsets come back exactly.
|
||||
At ``flow_arrow_scale == 1`` that divisor is ``DISPLACEMENT_PX_PER_FLOW`` times
|
||||
the margin.
|
||||
|
||||
The box painter does not re-select. It colours by the displacement *before*
|
||||
the cap, which ``magnitude`` still holds (``|DISPLACEMENT_PX_PER_FLOW * flow|``).
|
||||
Direction comes from ``dx``/``dy``. Float32 magnitude is not exact enough to
|
||||
reproduce a capped offset, which is why only the box grid uses it.
|
||||
the margin. Box and finger use the same inverse; only the policy numbers differ.
|
||||
"""
|
||||
rows = np.asarray(samples.rows, np.int64)
|
||||
cols = np.asarray(samples.cols, np.int64)
|
||||
@@ -563,25 +557,16 @@ class AnalysisSession:
|
||||
# ``NaN`` is the point of the mask, and the selector's tip arithmetic on a
|
||||
# discarded cell is defined to be discarded: say so here rather than let
|
||||
# numpy warn about an invalid cast on every frame.
|
||||
if uses_sdk_box_grid(self.policy):
|
||||
magnitude = np.asarray(samples.magnitude, np.float64)
|
||||
length = np.sqrt(dx * dx + dy * dy)
|
||||
flow_mag = magnitude / DISPLACEMENT_PX_PER_FLOW
|
||||
safe = np.maximum(length, 1e-12)
|
||||
moving = length > 0.0
|
||||
flow[rows, cols, 0] = np.where(moving, dx / safe * flow_mag, 0.0)
|
||||
flow[rows, cols, 1] = np.where(moving, dy / safe * flow_mag, 0.0)
|
||||
else:
|
||||
scale = float(self.policy.flow_arrow_scale)
|
||||
if scale <= 0.0:
|
||||
scale = 1.0
|
||||
divisor = (
|
||||
DISPLACEMENT_PX_PER_FLOW
|
||||
* float(self.policy.flow_length_margin)
|
||||
/ scale
|
||||
)
|
||||
flow[rows, cols, 0] = dx / divisor
|
||||
flow[rows, cols, 1] = dy / divisor
|
||||
scale = float(self.policy.flow_arrow_scale)
|
||||
if scale <= 0.0:
|
||||
scale = 1.0
|
||||
divisor = (
|
||||
DISPLACEMENT_PX_PER_FLOW
|
||||
* float(self.policy.flow_length_margin)
|
||||
/ scale
|
||||
)
|
||||
flow[rows, cols, 0] = dx / divisor
|
||||
flow[rows, cols, 1] = dy / divisor
|
||||
return flow
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user