From db46ad2f06512a6ed3b398c54558470b85e41d26 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Wed, 10 May 2023 15:11:55 +0200 Subject: Adding fucntion tot test fixation or saccade. Adding focus attribute to fixation. --- src/argaze/GazeFeatures.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/argaze/GazeFeatures.py b/src/argaze/GazeFeatures.py index 2510cb2..95d90e1 100644 --- a/src/argaze/GazeFeatures.py +++ b/src/argaze/GazeFeatures.py @@ -54,17 +54,25 @@ class GazePosition(): return self.precision is not None + def distance(self, gaze_position) -> float: + """Distance to another gaze positions.""" + + distance = (self.value[0] - gaze_position.value[0])**2 + (self.value[1] - gaze_position.value[1])**2 + distance = numpy.sqrt(distance) + + return distance + def overlap(self, gaze_position, both=False) -> float: """Does this gaze position overlap another gaze position considering its precision? Set both to True to test if the other gaze position overlaps this one too.""" - dist = (self.value[0] - gaze_position.value[0])**2 + (self.value[1] - gaze_position.value[1])**2 - dist = numpy.sqrt(dist) + distance = (self.value[0] - gaze_position.value[0])**2 + (self.value[1] - gaze_position.value[1])**2 + distance = numpy.sqrt(distance) if both: - return dist < min(self.precision, gaze_position.precision) + return distance < min(self.precision, gaze_position.precision) else: - return dist < self.precision + return distance < self.precision def draw(self, frame, color=(0, 255, 255), draw_precision=True): """Draw gaze position point and precision circle.""" @@ -171,10 +179,18 @@ class GazeMovement(): class Fixation(GazeMovement): """Define abstract fixation as gaze movement.""" + focus: tuple = field(init=False) + """Representative position of the fixation.""" + def __post_init__(self): super().__post_init__() +def is_fixation(gaze_movement): + """Is a gaze movement a fixation?""" + + return type(gaze_movement).__bases__[0] == Fixation or type(gaze_movement) == Fixation + class Saccade(GazeMovement): """Define abstract saccade as gaze movement.""" @@ -182,6 +198,11 @@ class Saccade(GazeMovement): super().__post_init__() +def is_saccade(gaze_movement): + """Is a gaze movement a saccade?""" + + return type(gaze_movement).__bases__[0] == Saccade or type(gaze_movement) == Saccade + TimeStampedGazeMovementsType = TypeVar('TimeStampedGazeMovements', bound="TimeStampedGazeMovements") # Type definition for type annotation convenience @@ -260,7 +281,7 @@ class GazeMovementIdentifier(): gaze_movement = self.identify(ts, gaze_position, terminate=(ts == last_ts)) - if isinstance(gaze_movement, Fixation): + if is_fixation(gaze_movement): start_ts, start_position = gaze_movement.positions.first @@ -270,7 +291,7 @@ class GazeMovementIdentifier(): ts_status[ts] = GazeStatus.from_position(position, 'Fixation', len(ts_fixations)) - elif isinstance(gaze_movement, Saccade): + elif is_saccade(gaze_movement): start_ts, start_position = gaze_movement.positions.first @@ -316,13 +337,13 @@ class VisualScanStep(): def __post_init__(self): # First movement have to be a fixation - if type(self.first_fixation).__bases__[0] != Fixation and type(self.first_fixation) != Fixation: + if not is_fixation(self.first_fixation): raise VisualScanStepError('First step movement is not a fixation', self.aoi) # Last movement have to be a saccade - if type(self.last_saccade).__bases__[0] != Saccade and type(self.last_saccade) != Saccade: - + if not is_saccade(self.last_saccade): + raise VisualScanStepError('Last step movement is not a saccade', self.aoi) @property -- cgit v1.1