54 return candidate.item.valid() && std::isfinite(candidate.left_px) &&
55 std::isfinite(candidate.top_px) && std::isfinite(candidate.right_px) &&
56 std::isfinite(candidate.bottom_px) && candidate.left_px < candidate.right_px &&
57 candidate.top_px < candidate.bottom_px;
61 float tolerance)
noexcept {
62 const auto wide_value =
static_cast<double>(value);
63 const auto wide_tolerance =
static_cast<double>(tolerance);
64 return wide_value >=
static_cast<double>(start) - wide_tolerance &&
65 wide_value <
static_cast<double>(end) + wide_tolerance;
69 return x >= candidate.left_px && x < candidate.right_px && y >= candidate.top_px &&
70 y < candidate.bottom_px;
75 return static_cast<double>(start) -
static_cast<double>(value);
77 return static_cast<double>(value) -
static_cast<double>(end);
82 float tolerance)
noexcept {
83 if (x < candidate.left_px)
85 if (x >= candidate.right_px)
88 const auto leading = std::abs(
static_cast<double>(x) -
static_cast<double>(candidate.left_px));
90 std::abs(
static_cast<double>(x) -
static_cast<double>(candidate.right_px));
92 static_cast<double>(candidate.right_px) -
static_cast<double>(candidate.left_px);
93 const auto edge_band = std::min(
static_cast<double>(tolerance), width / 3.0);
95 if (leading <= edge_band)
97 if (trailing <= edge_band)
122[[nodiscard]]
inline std::optional<ProjectedHit>
124 float y_px,
float tolerance_px)
noexcept {
125 if (!std::isfinite(x_px) || !std::isfinite(y_px) || !std::isfinite(tolerance_px) ||
129 std::optional<ProjectedHit> best;
130 auto best_distance_squared = std::numeric_limits<double>::infinity();
131 auto best_contains =
false;
133 for (
const auto& candidate : back_to_front) {
144 candidate.bottom_px);
145 const auto distance_squared = dx * dx + dy * dy;
148 const auto distance_tie = distance_squared == best_distance_squared;
149 const auto wins_boundary_tie = distance_tie && contains && !best_contains;
150 const auto wins_paint_order_tie = distance_tie && contains == best_contains;
151 if (!best || distance_squared < best_distance_squared || wins_boundary_tie ||
152 wins_paint_order_tie) {
153 best_distance_squared = distance_squared;
154 best_contains = contains;
std::optional< ProjectedHit > hit_test_projected_items(std::span< const ProjectedHitCandidate > back_to_front, float x_px, float y_px, float tolerance_px) noexcept
Selects one projected timeline item using already-resolved pixel tolerance.
Definition hit_test.hpp:123
ProjectedHitRegion
The horizontal part of a projected item selected by a hit test.
Definition hit_test.hpp:37
@ LeadingEdge
Left/start edge in projected timeline space.
Definition hit_test.hpp:39
@ Body
Definition hit_test.hpp:38
@ TrailingEdge
Right/end edge in projected timeline space.
Definition hit_test.hpp:40
Definition hit_test.hpp:51
bool inside_half_open(const ProjectedHitCandidate &candidate, float x, float y) noexcept
Definition hit_test.hpp:68
double distance_to_half_open_span(float value, float start, float end) noexcept
Definition hit_test.hpp:73
ProjectedHitRegion region_at(const ProjectedHitCandidate &candidate, float x, float tolerance) noexcept
Definition hit_test.hpp:81
bool valid_candidate(const ProjectedHitCandidate &candidate) noexcept
Definition hit_test.hpp:53
bool inside_expanded_half_open(float value, float start, float end, float tolerance) noexcept
Definition hit_test.hpp:60
ScriptedUiHost is a SequencerUiHost whose playhead is written by the caller instead of an engine,...
Definition edit_intent.hpp:14
Nonzero monotonic identity for a Timeline-owned object.
Definition item_id.hpp:19
One timeline item after a front-end projects it into pixel space.
Definition hit_test.hpp:26
float left_px
Definition hit_test.hpp:28
float bottom_px
Definition hit_test.hpp:31
timeline::ItemId item
Definition hit_test.hpp:27
constexpr bool operator==(const ProjectedHitCandidate &) const =default
float top_px
Definition hit_test.hpp:29
float right_px
Definition hit_test.hpp:30
The identity and region selected from a projected candidate set.
Definition hit_test.hpp:44
timeline::ItemId item
Definition hit_test.hpp:45
constexpr bool operator==(const ProjectedHit &) const =default
ProjectedHitRegion region
Definition hit_test.hpp:46