Exemplo n.º 1
0
    def update_xyt(self, x_coord, y_coord, time):
        """
        Track a point.
        If tracking is currently inactive, this function will do nothing.
        """

        if not self._tracking_active:
            return

        _u.validate_func_arg_type(self, "update_xyt", "x_coord", x_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "y_coord", y_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "time", time,
                                  numbers.Number)
        _u.validate_func_arg_not_negative(self, "update_xyt", "time", time)

        self._trajectory['x'].append(x_coord)
        self._trajectory['y'].append(y_coord)
        self._trajectory['time'].append(time)

        if self._log_level:
            expyriment._active_exp._event_file_log(
                "Trajectory,Track_xyt,{0},{1},{2}".format(
                    x_coord, y_coord, time), 2)
    def get_traj_point(self, time):
        """
        Generate the trajectory - get one time point data

        :param time: in seconds
        :return: (x, y, visible)
        """

        _u.validate_func_arg_type(self, "get_traj_point", "time", time,
                                  numbers.Number)
        _u.validate_func_arg_not_negative(self, "get_traj_point", "time", time)

        #-- Handle time-too-large
        total_duration = self.duration
        if self._cyclic:
            time = time % total_duration
        elif time >= total_duration:
            last_segment = self._segments[-1]
            return last_segment['generator'].get_traj_point(
                last_segment['duration'])

        #-- Find relevant segment
        generator, time = self._get_generator_for(time)

        #-- Get point from the relevant segment
        return generator.get_traj_point(time)
Exemplo n.º 3
0
    def set_trajectory(self, traj_id, traj_data):
        """
        Add a single trajectory (or replace an existing one)

        :param traj_id: A logical ID for this trajectory.
        :param traj_data: The trajectory data - a list/tuple of per-timepoint data.
                Per time point, specify a list/tuple of with 3 or 4 elements: time (> 0),
                x coordinate (int), y coordinate (int), and optional "visible" (bool)
        """

        _u.validate_func_arg_anylist(self, "set_trajectory", "traj_data", traj_data, min_length=1)
        if traj_id is None:
            raise TypeError("trajtracker error: {:}.set_trajectory(traj_id=None) is invalid".format(type(self).__name__))

        coords = []
        times = []
        visible = []
        prev_time = -1

        for i in range(len(traj_data)):

            time_point = traj_data[i]

            _u.validate_func_arg_anylist(self, "set_trajectory", "traj_data[%d]" % i, time_point, min_length=3, max_length=4)
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][0]" % i, time_point[0], numbers.Number)
            _u.validate_func_arg_not_negative(self, "set_trajectory", "traj_data[%d][0]" % i, time_point[0])
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][1]" % i, time_point[1], int)
            _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][2]" % i, time_point[2], int)

            time = time_point[0]
            if time <= prev_time:
                raise ValueError(("trajtracker error: {:}.set_trajectory() called with invalid value for trajectory '{:}' " +
                                 "- timepoint {:} appeared after {:}").format(type(self).__name__, traj_id, time, prev_time))

            prev_time = time

            times.append(time)
            coords.append((time_point[1], time_point[2]))

            if len(time_point) == 4:
                _u.validate_func_arg_type(self, "set_trajectory", "traj_data[%d][3]" % i, time_point[3], bool)
                visible.append(time_point[3])
            else:
                visible.append(True)

        self._trajectories[traj_id] = {
            'times': np.array(times),
            'coords': coords,
            'visible': visible,
            'duration': times[-1]
        }

        self._validation_err = None
Exemplo n.º 4
0
    def update_xyt(self, x_coord, y_coord, time):
        """
        Call this method whenever the finger/mouse moves
        """

        _u.validate_func_arg_type(self, "update_xyt", "x_coord", x_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "y_coord", y_coord,
                                  numbers.Number)
        _u.validate_func_arg_type(self, "update_xyt", "time", time,
                                  numbers.Number)
        _u.validate_func_arg_not_negative(self, "update_xyt", "time", time)

        self._remove_far_enough_recent_coords(x_coord, y_coord)

        # remember coordinates
        self._recent_near_coords.append((x_coord, y_coord, time))

        last_angle = self._curr_angle
        self._calc_curr_angle()
        self._check_if_new_curve(last_angle)
Exemplo n.º 5
0
    def get_traj_point(self, time):
        """
        Generate the trajectory - get one time point data

        :param time: in seconds
        :return: (x, y, visible)
        """

        self.validate()

        _u.validate_func_arg_type(self, "get_traj_point", "time", time, numbers.Number)
        _u.validate_func_arg_not_negative(self, "get_traj_point", "time", time)

        if self._active_traj_id is None:
            if len(self._trajectories):
                self.active_traj_id = self._trajectories.keys()[0]
            else:
                raise trajtracker.InvalidStateError("{:}.get_traj_point() cannot be called before active_traj_id was set".format(type(self).__name__))

        traj_inf = self._trajectories[self._active_traj_id]

        if time < traj_inf['times'][0]:
            raise ValueError("trajtracker error in {:}.get_traj_point(time={:}): the active trajectory ({:}) starts from time={:}".format(
                type(self).__name__, time, self._active_traj_id, traj_inf['times'][0]))

        #-- Time can't exceed the trajectory duration
        if time > traj_inf['duration']:
            time = time % traj_inf['duration'] if self._cyclic else traj_inf['duration']

        traj_times = traj_inf['times']
        traj_xy = traj_inf['coords']
        traj_visible = traj_inf['visible']


        ind_before_time = np.where(traj_times <= time)[0][-1]
        time_before = traj_times[ind_before_time]

        coord_before = traj_xy[ind_before_time]
        visible_before = traj_visible[ind_before_time]

        if time_before == time:
            ind_after_time = ind_before_time
            time_after = time_before
        else:
            ind_after_time = min(ind_before_time+1, len(traj_times)-1)
            time_after = traj_times[ind_after_time]

        if self._interpolate and time_before != time_after:

            #-- Coordinates: linear interpolation between the two relevant time points
            coord_after = traj_xy[ind_after_time]
            weight_of_after_ind = (time - time_before) / (time_after - time_before)
            weight_of_before_ind = 1 - weight_of_after_ind
            x = int( np.round(coord_before[0] * weight_of_before_ind + coord_after[0] * weight_of_after_ind) )
            y = int( np.round(coord_before[1] * weight_of_before_ind + coord_after[1] * weight_of_after_ind) )

            #-- Visibility: use the value from the closest available time point
            visible_after = traj_visible[ind_after_time]
            visible = visible_before if weight_of_before_ind > weight_of_after_ind else visible_after

            return x, y, visible

        else:
            #-- Return the value of the last time point before "time"
            return coord_before + (visible_before, )
Exemplo n.º 6
0
    def wait_until_exit(self,
                        exp,
                        on_loop_callback=None,
                        on_loop_present=None,
                        event_manager=None,
                        trial_start_time=None,
                        session_start_time=None,
                        max_wait_time=None):
        """
        Wait until the finger leaves the starting area
    
        The *on_loop_xxx* and *event_manager* parameters define what to do on each iteration of the loop that  
        waits for the area to be touched. 
        If neither on_loop_callback nor on_loop_present are provided, the function will wait for 15 ms 
        on each loop iteration.
        
        If several on_loop parameters are provided, they will be invoked in this order:
        *callback - event manager.on_frame() - present()*.
        
        :param exp: The Expyriment experiment object
        :param on_loop_callback: A function to call on each loop iteration. 
                                 If the function returns any value other than *None*, the waiting will
                                 be terminated and that value will be returned.
                                 The function gets 2 arguments: time_in_trial, time_in_session
        :param on_loop_present: A visual object that will be present()ed on each loop iteration.
        :param event_manager: The event manager's on_frame() will be called on each loop iteration.
                              If you provide an event manager, you also have to provide trial_start_time and
                              session_start_time (whose values were obtained by :func:`trajtracker.utils.get_time` 
        :param max_wait_time: Maximal time (in seconds) to wait
        :return: The value returned by the on_loop_callback function (in case it returned anything other than None).
                 Otherwise the function returns None. Use :attr:`~trajtracker.movement.StartPoint.state` to
                 learn about the StartPoint's exit status.
        """

        self._log_func_enters(
            "wait_until_exit",
            ["exp", on_loop_callback, on_loop_present, event_manager])

        _u.validate_func_arg_type(self,
                                  "wait_until_startpoint_touched",
                                  "max_wait_time",
                                  max_wait_time,
                                  numbers.Number,
                                  none_allowed=True)
        _u.validate_func_arg_not_negative(self,
                                          "wait_until_startpoint_touched",
                                          "max_wait_time", max_wait_time)
        if event_manager is not None:
            _u.validate_func_arg_type(self,
                                      "wait_until_startpoint_touched",
                                      "trial_start_time",
                                      trial_start_time,
                                      numbers.Number,
                                      none_allowed=True)
            _u.validate_func_arg_type(self, "wait_until_startpoint_touched",
                                      "session_start_time", session_start_time,
                                      numbers.Number)

        time_started_waiting = u.get_time()

        #-- Wait
        while self._state not in [
                StartPoint.State.start, StartPoint.State.error
        ]:

            curr_time = u.get_time()
            time_in_trial = None if trial_start_time is None else curr_time - trial_start_time
            time_in_session = None if session_start_time is None else curr_time - session_start_time

            if ttrk.env.mouse.check_button_pressed(0):
                #-- Finger still touching screen
                finger_pos = ttrk.env.mouse.position
                self.check_xy(finger_pos[0], finger_pos[1])
            else:
                #-- Finger lifted
                self._log_func_returns("wait_until_exit",
                                       StartPoint.State.aborted)
                self._state = StartPoint.State.aborted
                return None

            if max_wait_time is not None and u.get_time(
            ) - time_started_waiting >= max_wait_time:
                self._state = StartPoint.State.timeout
                self._log_func_returns("wait_until_exit",
                                       StartPoint.State.timeout)
                return None

            # Invoke custom operations on each loop iteration
            if on_loop_callback is not None:
                retval = on_loop_callback(time_in_trial, time_in_session)
                if retval is not None:
                    return retval

            if event_manager is not None:
                event_manager.on_frame(time_in_trial, time_in_session)

            if on_loop_present is not None:
                on_loop_present.present()

            if on_loop_present is None and on_loop_callback is None:
                exp.clock.wait(15)

            xpy.io.Keyboard.process_control_keys()

        self._log_func_returns("wait_until_exit", self._state)
        return None
Exemplo n.º 7
0
    def wait_until_startpoint_touched(self,
                                      exp,
                                      on_loop_callback=None,
                                      on_loop_present=None,
                                      event_manager=None,
                                      trial_start_time=None,
                                      session_start_time=None,
                                      max_wait_time=None):
        """
        Wait until the starting point is touched.
        
        The *on_loop_xxx* and *event_manager* parameters define what to do on each iteration of the loop that  
        waits for the area to be touched. 
        If neither on_loop_callback nor on_loop_present are provided, the function will wait for 15 ms 
        on each loop iteration.
        
        If several on_loop parameters are provided, they will be invoked in this order:
        *callback - event manager.on_frame() - present()*.
        
        :param exp: The Expyriment experiment object
        :param on_loop_callback: A function (without arguments) to call on each loop iteration.
                                If the function returns any value other than *None*, the waiting will
                                be terminated and that value will be returned.
        :param on_loop_present: A visual object that will be present()ed on each loop iteration.
        :param event_manager: The event manager's on_frame() will be called on each loop iteration.
                              If you provide an event manager, you also have to provide trial_start_time and
                              session_start_time (whose values were obtained by :func:`trajtracker.utils.get_time`
        :param max_wait_time: Maximal time (in seconds) to wait
        :return: The value returned by the on_loop_callback function (in case it returned anything other than None).
                 Otherwise the function returns None. Use :attr:`~trajtracker.movement.StartPoint.state` to
                 learn about the StartPoint's exit status.
        """

        self._log_func_enters(
            "wait_until_startpoint_touched",
            ["exp", on_loop_callback, on_loop_present, event_manager])

        _u.validate_func_arg_type(self,
                                  "wait_until_startpoint_touched",
                                  "max_wait_time",
                                  max_wait_time,
                                  numbers.Number,
                                  none_allowed=True)
        _u.validate_func_arg_not_negative(self,
                                          "wait_until_startpoint_touched",
                                          "max_wait_time", max_wait_time)
        if event_manager is not None:
            _u.validate_func_arg_type(self,
                                      "wait_until_startpoint_touched",
                                      "trial_start_time",
                                      trial_start_time,
                                      numbers.Number,
                                      none_allowed=True)
            _u.validate_func_arg_type(self, "wait_until_startpoint_touched",
                                      "session_start_time", session_start_time,
                                      numbers.Number)

        if self._state != StartPoint.State.reset:
            raise ttrk.InvalidStateError(
                "{:}.wait_until_startpoint_touched() was called without calling reset() first"
                .format(_u.get_type_name(self)))

        time_started_waiting = u.get_time()

        # The "StartPoint" object is expected to run through these states, in this order:
        # State.reset - after the trial initialized
        # State.mouse_up - after the mouse/finger was unclicked/lifted
        # State.init - when the screen was touched/clicked (this is when this function returns)

        while True:

            if not ttrk.env.mouse.check_button_pressed(
                    0) and self._state == StartPoint.State.reset:
                # Mouse/finger is UP
                self._state = StartPoint.State.mouse_up
                self._log_write_if(ttrk.log_debug,
                                   "Mouse unclicked. Setting state=mouse_up",
                                   True)

            elif ttrk.env.mouse.check_button_pressed(
                    0) and self._state == StartPoint.State.mouse_up:
                # Mouse/finger touched the screen
                finger_pos = ttrk.env.mouse.position
                self.check_xy(finger_pos[0], finger_pos[1])

            if max_wait_time is not None and u.get_time(
            ) - time_started_waiting >= max_wait_time:
                self._log_func_returns("wait_until_startpoint_touched", False)
                self._state = StartPoint.State.timeout
                return None

            if self._state == StartPoint.State.init:
                break  # Screen touched - we're done here

            # Invoke custom operations on each loop iteration

            if on_loop_callback is not None:
                retval = on_loop_callback()
                if retval is not None:
                    return retval

            if event_manager is not None:
                curr_time = u.get_time()
                event_manager.on_frame(
                    None if trial_start_time is None else curr_time -
                    trial_start_time, curr_time - session_start_time)

            if on_loop_present is not None:
                on_loop_present.present()

            if on_loop_present is None and on_loop_callback is None:
                exp.clock.wait(15)

            xpy.io.Keyboard.process_control_keys()

        self._log_func_returns("wait_until_startpoint_touched", True)
        return None