package edu.cmu.cs.eyetrack.analysis.score;
import java.util.List;
import edu.cmu.cs.eyetrack.analysis.score.compare.PointComparator;
import edu.cmu.cs.eyetrack.analysis.score.distance.DistanceFunction;
import edu.cmu.cs.eyetrack.analysis.struct.Trajectory;
import edu.cmu.cs.eyetrack.analysis.struct.tobii.TobiiFrame;
import edu.cmu.cs.eyetrack.analysis.struct.trackit.TrackItFrame;
import edu.cmu.cs.eyetrack.analysis.struct.trackit.Trial;
import edu.cmu.cs.eyetrack.helper.Util;
import edu.cmu.cs.eyetrack.test.SingleRunScore;
public class PointByPointScorer extends Scorer{
public PointByPointScorer(PointComparator pFunc, DistanceFunction dist) {
super(pFunc, dist);
}
public String getName() {
return "Point-by-Point Distance Scorer";
}
/**
* Calculates the point-by-point scores (based on distances between the points, possibly lagged by some time) and returns
* a run score, for a gaze trajectory and a Track-It gold standard file
* @param actual
* @param subject
* @param recordList
* @return
*/
public SingleRunScore calcScore(Trajectory<TrackItFrame> actual, Trajectory<TobiiFrame> subject, List<Double> recordList) {
if( subject.getLengthMS() < actual.getLengthMS()) {
Util.dPrint("Couldn't parse Spacebar-delimited Tobii file correctly; skipping trial here.\nPlease ignore any child with this message!");
SingleRunScore record = new SingleRunScore();
record.setFrameCountOnTarget(0);
record.setFrameCountOverall(-1);
record.setScore(Double.NaN);
return record;
}
long validFrameCount = 0;
long totalFrameCount = 0;
double totalScore = 0.0;
long wallclockOffset = subject.getTimestampRecStart();
for(TobiiFrame subjFrame : subject.getFrames()) {
totalFrameCount++;
// If neither of the subject's eyes were found in this frame, skip it
if(subjFrame.getValidityLeft() == 4 || subjFrame.getValidityRight() == 4) {
if(recordList != null) {
recordList.add(null);
}
continue;
}
long timestamp = subjFrame.getTimestamp();
double frameScore = pFunc.score(dist, timestamp, wallclockOffset, actual, subject);
// If the Tobii data goes beyond when the objects were on screen and moving, cut
// off the scoring function
if( timestamp - wallclockOffset > actual.getLengthMS()) {
break;
}
validFrameCount++;
totalScore += frameScore;
if(recordList != null) {
recordList.add(frameScore);
}
}
// If normalizing only on valid frames . . .
double score = totalScore / validFrameCount;
System.err.println("Score: " + score);
// If normalizing on all frames . . .
//double score = totalScore / subject.getFrames().size();
SingleRunScore record = new SingleRunScore();
record.setFrameCountOnTarget(validFrameCount);
record.setFrameCountOverall(totalFrameCount);
record.setScore(score);
return record;
}
@Override
public boolean calcFixationStats(SingleRunScore record, Trial actual, Trajectory<TobiiFrame> subject) {
// TODO implement this? Is it okay to just return nothing here? Probably
return false;
}
}