What is under point (x, y) of the window (-1 to 1 across it, y up: as
the event handler's positions), nearest first (see the module
documentation): none before the first frame. tolerance: how close
lines, markers and frames' origins must be, in window units (logical
pixels; default 4), beyond half a line's width or a marker's size.
kinds: only hits of these kinds (PICK_*; the others aren't tested).
nearest: only the nearest hit (cheaper: what is deeper than a hit
found is skipped, e.g. to pick on every mouse move). Frames and
artists can be left out (set_pickable(.false.)).
What was clicked, from a WindowEventHandler extension's button_press
(registered with window%set_event_handler(handler)):
subroutine on_click(self, window, x, y, button)
class(ClickPicker), intent(inout) :: self
class(WindowProxy), intent(inout) :: window
real(wp), intent(in) :: x, y
integer, intent(in) :: button
type(PickHit), allocatable :: hits(:)
call window%pick(x, y, hits)
if (size(hits) == 0) return
select case (hits(1)%kind)
case (PICK_CURVE)
write(*, '(a,f0.1,a)') 'picked the orbit at t = ', hits(1)%time, ' s'
case (PICK_BODY)
write(*, '(a,2f8.2)') 'picked '//hits(1)%frame%name()//' at lat, lon (deg) ', &
hits(1)%latitude * 180.0_wp / pi, hits(1)%longitude * 180.0_wp / pi
end select
end subroutine on_click
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(WindowProxy), | intent(in), | target | :: | self | ||
| real(kind=wp), | intent(in) | :: | x |
-1 to 1 across the window, y up |
||
| real(kind=wp), | intent(in) | :: | y |
-1 to 1 across the window, y up |
||
| type(PickHit), | intent(out), | allocatable | :: | hits(:) |
what is there, nearest first |
|
| real(kind=wp), | intent(in), | optional | :: | tolerance |
window units (default 4) |
|
| integer, | intent(in), | optional | :: | kinds(:) |
PICK_* (default: all) |
|
| logical, | intent(in), | optional | :: | nearest |
default false |
subroutine window_pick(self, x, y, hits, tolerance, kinds, nearest) class(WindowProxy), intent(in), target :: self real(wp), intent(in) :: x, y !! -1 to 1 across the window, y up type(PickHit), allocatable, intent(out) :: hits(:) !! what is there, nearest first real(wp), intent(in), optional :: tolerance !! window units (default 4) integer, intent(in), optional :: kinds(:) !! PICK_* (default: all) logical, intent(in), optional :: nearest !! default false class(ReferenceFrame), pointer :: root type(PickCamera) :: cam type(PickHit) :: h integer :: n, i, j logical :: only_nearest n = 0 only_nearest = .false. if (present(nearest)) only_nearest = nearest allocate(hits(8)) root => null() if (associated(self%scene)) root => self%scene%frame() if (.not. associated(root) .or. .not. view_camera(self, x, y, cam)) then hits = hits(1:0) return end if cam%tolerance = 4.0_wp * cam%pixel_ratio if (present(tolerance)) cam%tolerance = tolerance * cam%pixel_ratio if (present(kinds)) then cam%kinds = 0 do i = 1, size(kinds) if (kinds(i) >= 0 .and. kinds(i) < bit_size(cam%kinds)) cam%kinds = ibset(cam%kinds, kinds(i)) end do end if call pick_frame(root, identity_matrix()) ! (the root frame's coordinates: the camera's) do i = 2, n ! nearest first h = hits(i) j = i - 1 do while (j >= 1) if (hits(j)%distance <= h%distance) exit hits(j + 1) = hits(j) j = j - 1 end do hits(j + 1) = h end do hits = hits(1:n) contains !> Frame f (at transform m to the root) and its children, under each of !> their parents. recursive subroutine pick_frame(f, m) class(ReferenceFrame), intent(in), target :: f !! the frame (with its children) real(wp), intent(in) :: m(4,4) !! f's transform to the root frame class(ReferenceFrame), pointer :: c integer :: k, best if (f%pickable()) call f%pick(cam, m, hits, n) if (only_nearest .and. n > 1) then ! (keep the nearest; skip what is deeper) best = minloc(hits(1:n)%distance, dim=1) hits(1) = hits(best) n = 1 end if if (only_nearest .and. n == 1) cam%max_depth = hits(1)%distance do k = 1, f%num_children() c => f%child(k) call pick_frame(c, matmul(m, c%local_matrix())) end do end subroutine pick_frame end subroutine window_pick