There are several coordinate systems used in NIMH ML for calibration and graphics.
sig is analog voltage or digital input (X & Y) fed from eye trackers or joysticks.
deg is visual degrees measured from the center of the screen. NIMH ML mostly works on this coordinate system in timing scripts.
pix is native pixel coordinates of Windows. The top-left corner is (0,0) and x & y increase as moving toward the bottom-right corner. This is the coordinate system that MGL uses.
norm is normalized coordinates in which both x & y have a value between 0 and 1. It is useful when you design layouts independent of the screen size.
The mlcalibrate class provides methods to manipulate the coordinate systems and convert xy coordinates from one system to another. There are 4 mlcalibrate objects that users can access in the timing script: EyeCal, Eye2Cal, JoyCal and Joy2Cal.
xy_deg = EyeCal.sig2deg(xy_sig, offset); % The offset should be [0 0].
EyeCal.translate(xy_offset); % Translate the system so that xy_offset becomes a new (0,0).
EyeCal.rotate(theta); % Rotate the coordinates system by theta (in degrees).
EyeCal.custom_calfunc(@function_handle); % For user manipulation of calibration.
The sig2deg method is device-dependent. It works only when the calibration process is complete. There are three methods that can affect how sig2deg works. The translate method updates the calibration matrix so that the given coordinates become a new origin of the system. The rotate method turns the axes on the origin by the given angle. With the custom_calfunc method, you can plug in a custom function to manipulate the calibration. For example, if you want to move the origin to [3 3], you can write a timing script as below.
new_origin = [3 3]; % in degrees
JoyCal.custom_calfunc(@custom_joy);
...
...
...
function xy_deg = custom_joy(xy_deg) % note that input and output are both in degrees
n = size(xy_deg,1);
xy_deg = xy_deg + repmat(new_origin, n, 1);
end
The difference between JoyCal.translate([3 3]) and the above code is that the former brings [3 3] to [0 0] and the latter moves [0 0] to [3 3].
Additionally the following methods are available. Except sig2pix, all methods are device-independent. In other words, the results will be the same, no matter which object you use among EyeCal, Eye2Cal, JoyCal and Joy2Cal to call them.
xy_pix = EyeCal.sig2pix(xy_sig, offset); % this is a conjugation of sig2deg and deg2pix
xy_deg = EyeCal.pix2deg(xy_pix);
xy_pix = EyeCal.deg2pix(xy_deg);
xy_deg = EyeCal.subject2deg(xy); % get the degree coordinates of a point on the subject screen
xy_pix = EyeCal.subject2pix(xy);
xy_deg = EyeCal.control2deg(xy); % get the degree coordinates of a point on the control screen
xy_pix = EyeCal.control2pix(xy);
xy_deg = EyeCal.norm2deg(xy);
xy_pix = EyeCal.norm2pix(xy);
wh_deg = EyeCal.norm2size(wh); % convert the normalized size (width & height) to visual degrees
In the scene framework, you can access Tracker's mlcalibrate object inside the adapter like the following.
classdef YourAdapter < mladapter
properties
Position
end
properties (SetAccess = protected)
ScreenPosition
end
methods
function obj = YourAdapter(varargin)
obj = obj@mladapter(varargin{:});
end
function set.Position(obj,xy_deg)
obj.Position = xy_deg;
% If the tracker of the adapter chain is EyeTracker, obj.Tracker.CalFun indicates EyeCal.
obj.ScreenPosition = obj.Tracker.CalFun.deg2pix(xy_deg);
end
end
end