From 089abb15293c80a1416d9746e27d7bd675d02d7f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 14:24:21 +0200 Subject: [PATCH 1/6] update aperture function to deal with circle and wedge --- apertureTexture.m | 89 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/apertureTexture.m b/apertureTexture.m index f6bba2b..cffff1a 100644 --- a/apertureTexture.m +++ b/apertureTexture.m @@ -1,59 +1,90 @@ function cfg = apertureTexture(action, cfg, thisEvent) - + transparent = [0 0 0 0]; - + switch action - + case 'init' - - % we take the screen height as maximum aperture width if not - % specified. - if ~isfield(cfg.aperture, 'width') || isempty(cfg.aperture.width) - cfg.aperture.width = cfg.screen.winRect(4) / cfg.screen.ppd; + + switch cfg.aperture.type + + case 'circle' + % we take the screen height as maximum aperture width if not + % specified. + if ~isfield(cfg.aperture, 'width') || isempty(cfg.aperture.width) + cfg.aperture.width = cfg.screen.winRect(4) / cfg.screen.ppd; + end + cfg.aperture = degToPix('width', cfg.aperture, cfg); end - cfg.aperture = degToPix('width', cfg.aperture, cfg); - + cfg.aperture.texture = Screen('MakeTexture', cfg.screen.win, ... cfg.color.background(1) * ones(cfg.screen.winRect([4 3]))); - + case 'make' - + + xCenter = cfg.screen.center(1); + yCenter = cfg.screen.center(2); + switch cfg.aperture.type - + case 'none' - + Screen('Fillrect', cfg.aperture.texture, transparent); - + case 'circle' - + diameter = cfg.aperture.widthPix; - - xPos = cfg.screen.center(1); - yPos = cfg.screen.center(2); + if isfield(cfg.aperture, 'xPosPix') - xPos = cfg.screen.center(1) + cfg.aperture.xPosPix; + xCenter = cfg.screen.center(1) + cfg.aperture.xPosPix; end if isfield(cfg.aperture, 'yPosPix') - yPos = cfg.screen.center(2) + cfg.aperture.yPosPix; + yCenter = cfg.screen.center(2) + cfg.aperture.yPosPix; end - + Screen('FillOval', cfg.aperture.texture, transparent, ... CenterRectOnPoint([0 0 repmat(diameter, 1, 2)], ... - xPos, yPos)); + xCenter, yCenter)); + + case 'ring' + + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); + + Screen('FillOval', cfg.aperture.texture, transparent, ... + CenterRectOnPoint( ... + [0 0 repmat(cfg.ring.outerRimPix, 1, 2)], ... + xCenter, yCenter)); + + Screen('FillOval', cfg.aperture.texture, [cfg.color.background 255], ... + CenterRectOnPoint( ... + [0 0 repmat(cfg.ring.innerRimPix, 1, 2)], ... + xCenter, yCenter)); + + case 'wedge' + + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); + + Screen('FillArc', cfg.aperture.texture, transparent, ... + CenterRect( ... + [0 0 repmat(cfg.stimRect(4), 1, 2)], ... + cfg.screen.winRect), ... + thisEvent.angle, ... % start angle + cfg.aperture.width); % arc angle + otherwise error('unknown aperture type: %s.', cfg.aperture.type); - + end - + case 'draw' - + Screen('DrawTexture', cfg.screen.win, cfg.aperture.texture); - + % Screen('DrawTexture', cfg.screen.win, apertureTexture, ... % cfg.screen.winRect, cfg.screen.winRect, current.apertureAngle - 90); - + end - + end From cb32a6f83f3be77deb049c74b1028e19a2846fd2 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 15:33:17 +0200 Subject: [PATCH 2/6] update files from retinotopy aperture refactoring --- .../aperture/apertureTexture.m | 40 +++++++++++- src/aperture/eccenLogSpeed.m | 61 +++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) rename apertureTexture.m => src/aperture/apertureTexture.m (64%) create mode 100644 src/aperture/eccenLogSpeed.m diff --git a/apertureTexture.m b/src/aperture/apertureTexture.m similarity index 64% rename from apertureTexture.m rename to src/aperture/apertureTexture.m index cffff1a..4aec258 100644 --- a/apertureTexture.m +++ b/src/aperture/apertureTexture.m @@ -1,4 +1,4 @@ -function cfg = apertureTexture(action, cfg, thisEvent) +function [cfg, thisEvent] = apertureTexture(action, cfg, thisEvent) transparent = [0 0 0 0]; @@ -15,6 +15,25 @@ cfg.aperture.width = cfg.screen.winRect(4) / cfg.screen.ppd; end cfg.aperture = degToPix('width', cfg.aperture, cfg); + + case 'ring' + + % Set parameters for rings + if strcmp(cfg.aperture.type ,'ring') + % scale of outer ring (exceeding screen until + % inner ring reaches window boarder) + cfg.ring.maxEcc = ... + cfg.screen.FOV / 2 + ... + cfg.aperture.width + ... + log(cfg.screen.FOV / 2 + 1) ; + % ring.CsFuncFact is used to expand with log increasing speed so + % that ring is at ring.maxEcc at end of cycle + cfg.ring.csFuncFact = ... + 1 / ... + ((cfg.ring.maxEcc + exp(1)) * ... + log(cfg.ring.maxEcc + exp(1)) - ... + (cfg.ring.maxEcc + exp(1))) ; + end end cfg.aperture.texture = Screen('MakeTexture', cfg.screen.win, ... @@ -48,6 +67,9 @@ case 'ring' + % expansion speed is log over eccentricity + [cfg] = eccenLogSpeed(cfg, thisEvent.time); + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); Screen('FillOval', cfg.aperture.texture, transparent, ... @@ -62,6 +84,22 @@ case 'wedge' + cycleDuration = cfg.mri.repetitionTime * cfg.volsPerCycle; + + % Update angle for rotation of background and for apperture for wedge + switch cfg.direction + + case '+' + thisEvent.angle = 90 - ... + cfg.aperture.width / 2 + ... + (thisEvent.time / cycleDuration) * 360; + case '-' + thisEvent.angle = 90 - ... + cfg.aperture.width / 2 - ... + (thisEvent.time / cycleDuration) * 360; + + end + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); Screen('FillArc', cfg.aperture.texture, transparent, ... diff --git a/src/aperture/eccenLogSpeed.m b/src/aperture/eccenLogSpeed.m new file mode 100644 index 0000000..1d35604 --- /dev/null +++ b/src/aperture/eccenLogSpeed.m @@ -0,0 +1,61 @@ +function [cfg] = eccenLogSpeed(cfg, time) + % vary CurrScale so that expansion speed is log over eccentricity + % cf. Tootell 1997; Swisher 2007; Warnking 2002 etc + + TR = cfg.mri.repetitionTime; + cycleDuration = TR * cfg.volsPerCycle; + + % CurrScale only influences ring + if strcmp(cfg.aperture.type, 'ring') + + csFuncFact = cfg.ring.csFuncFact; + ringWidthVA = cfg.ring.ringWidthVA; + maxEcc = cfg.ring.maxEcc; + + switch cfg.direction + case '+' + % current visual angle linear in time + outerRimVA = 0 + mod(time, cycleDuration) / cycleDuration * maxEcc; + % ensure some foveal stimulation at beginning (which is hidden by + % fixation cross otherwise) + if outerRimVA < cfg.fixation.size + outerRimVA = cfg.fixation.size + .1; + end + case '-' + outerRimVA = maxEcc - mod(time, cycleDuration) / cycleDuration * maxEcc; + if outerRimVA > maxEcc + outerRimVA = maxEcc; + end + end + + % near-exp visual angle + newOuterRimVA = ((outerRimVA + exp(1)) * log(outerRimVA + exp(1)) - ... + (outerRimVA + exp(1))) * maxEcc * csFuncFact; + outerRimPix = newOuterRimVA * cfg.screen.ppd; % in pixel + + % width of apperture changes logarithmically with eccentricity of inner ring + oldScaleInnerVA = outerRimVA - ringWidthVA; + if oldScaleInnerVA < 0 + oldScaleInnerVA = 0; + end + + % growing with inner ring ecc + ringWidthVA = cfg.aperture.width + log(oldScaleInnerVA + 1); + innerRimVA = newOuterRimVA - ringWidthVA; + + if innerRimVA < 0 + innerRimVA = 0; + end + + % in pixel + innerRimPix = innerRimVA * cfg.screen.ppd; + + % update cfg that we are about to return + cfg.ring.outerRimPix = outerRimPix; + cfg.ring.innerRimPix = innerRimPix; + cfg.ring.ring_outer_rim = newOuterRimVA; + cfg.ring.ring_inner_rim = innerRimVA; + + end + +end From 867aba4f2b2526946f95a2b43051159451a0009e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 15:53:30 +0200 Subject: [PATCH 3/6] refactor fixation from retinotopy --- drawFixation.m | 43 +++++++++++++++++++++++++++++++------------ initFixation.m | 10 +++++----- setDefaultsPTB.m | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/drawFixation.m b/drawFixation.m index ce9d3f0..44304e3 100644 --- a/drawFixation.m +++ b/drawFixation.m @@ -1,16 +1,35 @@ function drawFixation(cfg) % Define the parameters of the fixation cross in `cfg` and `expParameters` - - if strcmp(cfg.fixation.type, 'cross') - - smooth = 1; - - Screen('DrawLines', ... - cfg.screen.win, ... - cfg.fixation.allCoords, ... - cfg.fixation.lineWidthPix, ... - cfg.fixation.color, ... - [cfg.screen.center(1) cfg.screen.center(2)], smooth); + + switch cfg.fixation.type + case 'cross' + + smooth = 1; + + Screen('DrawLines', ... + cfg.screen.win, ... + cfg.fixation.allCoords, ... + cfg.fixation.lineWidthPix, ... + cfg.fixation.color, ... + [cfg.screen.center(1) cfg.screen.center(2)], smooth); + + case 'dot' + + % Draw gap around fixation of 20% the size + Screen('FillOval', ... + cfg.screen.win, ... + cfg.color.background, ... + CenterRect( ... + [0 0 repmat(1.2 * cfg.fixation.widthPix, 1, 2)], ... + cfg.screen.winRect)); + + % Draw fixation + Screen('FillOval', ... + cfg.screen.win, ... + cfg.color.foreground, ... + CenterRect( ... + [0 0 repmat(cfg.fixation.widthPix, 1, 2)], ... + cfg.screen.winRect)); end - + end diff --git a/initFixation.m b/initFixation.m index e85d7b3..d43ccd6 100644 --- a/initFixation.m +++ b/initFixation.m @@ -1,12 +1,12 @@ function cfg = initFixation(cfg) + + % Convert some values from degrees to pixels + cfg.fixation = degToPix('width', cfg.fixation, cfg); + cfg.fixation = degToPix('xDisplacement', cfg.fixation, cfg); + cfg.fixation = degToPix('yDisplacement', cfg.fixation, cfg); if strcmp(cfg.fixation.type, 'cross') - % Convert some values from degrees to pixels - cfg.fixation = degToPix('width', cfg.fixation, cfg); - cfg.fixation = degToPix('xDisplacement', cfg.fixation, cfg); - cfg.fixation = degToPix('yDisplacement', cfg.fixation, cfg); - % Prepare fixation cross cfg.fixation.xCoords = [-cfg.fixation.widthPix cfg.fixation.widthPix 0 0] / 2 + ... cfg.fixation.xDisplacementPix; diff --git a/setDefaultsPTB.m b/setDefaultsPTB.m index 5a172d6..386f3c1 100644 --- a/setDefaultsPTB.m +++ b/setDefaultsPTB.m @@ -35,7 +35,7 @@ fieldsToSet.fixation.xDisplacement = 0; fieldsToSet.fixation.yDisplacement = 0; fieldsToSet.fixation.color = [255 255 255]; - fieldsToSet.fixation.width = 1; + fieldsToSet.fixation.width = 1; % degrees of visual angle fieldsToSet.fixation.lineWidthPix = 5; % define visual apperture field From 71f5f772c5ea555b963b51d81ff7cae6e4fc3b61 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 17:20:12 +0200 Subject: [PATCH 4/6] implement best fixation option --- drawFixation.m | 35 +++++++++++++++++++++++++++++++++++ initFixation.m | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/drawFixation.m b/drawFixation.m index 44304e3..7b7c426 100644 --- a/drawFixation.m +++ b/drawFixation.m @@ -30,6 +30,41 @@ function drawFixation(cfg) CenterRect( ... [0 0 repmat(cfg.fixation.widthPix, 1, 2)], ... cfg.screen.winRect)); + + + case 'bestFixation' + + % Code adapted from: + % What is the best fixation target? + % DOI 10.1016/j.visres.2012.10.012 + + % Draw gap around fixation of 20% the size + Screen('FillOval', ... + cfg.screen.win, ... + cfg.color.background, ... + CenterRect( ... + [0 0 repmat(1.5 * cfg.fixation.widthPix, 1, 2)], ... + cfg.screen.winRect)); + + Screen('FillOval', ... + cfg.screen.win, ... + cfg.color.black, ... + cfg.fixation.outerOval, ... + cfg.fixation.widthPix); + + Screen('DrawLines', ... + cfg.screen.win, ... + cfg.fixation.allCoords, ... + cfg.fixation.widthPix / 3, ... + cfg.color.white, ... + [cfg.screen.center(1) cfg.screen.center(2)]); + + Screen('FillOval', ... + cfg.screen.win, ... + cfg.color.black, ... + cfg.fixation.innerOval, ... + cfg.fixation.widthPix / 3); + end end diff --git a/initFixation.m b/initFixation.m index d43ccd6..d4ff10a 100644 --- a/initFixation.m +++ b/initFixation.m @@ -4,16 +4,36 @@ cfg.fixation = degToPix('width', cfg.fixation, cfg); cfg.fixation = degToPix('xDisplacement', cfg.fixation, cfg); cfg.fixation = degToPix('yDisplacement', cfg.fixation, cfg); - - if strcmp(cfg.fixation.type, 'cross') - - % Prepare fixation cross - cfg.fixation.xCoords = [-cfg.fixation.widthPix cfg.fixation.widthPix 0 0] / 2 + ... - cfg.fixation.xDisplacementPix; - cfg.fixation.yCoords = [0 0 -cfg.fixation.widthPix cfg.fixation.widthPix] / 2 + ... - cfg.fixation.yDisplacementPix; - cfg.fixation.allCoords = [cfg.fixation.xCoords; cfg.fixation.yCoords]; - + + % Prepare fixation cross + xLine = [-cfg.fixation.widthPix cfg.fixation.widthPix 0 0] / 2; + yLine = [0 0 -cfg.fixation.widthPix cfg.fixation.widthPix] / 2; + + cfg.fixation.xCoords = xLine + cfg.fixation.xDisplacementPix; + cfg.fixation.yCoords = yLine + cfg.fixation.yDisplacementPix; + + cfg.fixation.allCoords = [cfg.fixation.xCoords; cfg.fixation.yCoords]; + + switch cfg.fixation.type + + case 'bestFixation' + + % Code adapted from: + % What is the best fixation target? + % DOI 10.1016/j.visres.2012.10.012 + + cfg.fixation.outerOval = [... + cfg.screen.center(1)-cfg.fixation.widthPix/2, ... + cfg.screen.center(2)-cfg.fixation.widthPix/2, ... + cfg.screen.center(1)+cfg.fixation.widthPix/2, ... + cfg.screen.center(2)+cfg.fixation.widthPix/2]; + + cfg.fixation.innerOval = [... + cfg.screen.center(1)-cfg.fixation.widthPix/6, ... + cfg.screen.center(2)-cfg.fixation.widthPix/6, ... + cfg.screen.center(1)+cfg.fixation.widthPix/6, ... + cfg.screen.center(2)+cfg.fixation.widthPix/6]; + end - + end From 51a11e02922e88b418381e04dd1df4c891fa548a Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 17:23:38 +0200 Subject: [PATCH 5/6] mh autofix --- drawFixation.m | 25 ++++----- initFixation.m | 42 +++++++------- src/aperture/apertureTexture.m | 77 +++++++++++++------------- src/aperture/eccenLogSpeed.m | 4 +- src/dot/computeCartCoord.m | 10 ++-- src/dot/computeRadialMotionDirection.m | 9 ++- src/dot/generateNewDotPositions.m | 6 +- src/dot/initDots.m | 2 - src/dot/reseedDots.m | 24 ++++---- src/dot/setDotDirection.m | 6 +- src/dot/updateDots.m | 2 +- tests/test_reseedDots.m | 26 ++++----- 12 files changed, 113 insertions(+), 120 deletions(-) diff --git a/drawFixation.m b/drawFixation.m index 7b7c426..e9897ae 100644 --- a/drawFixation.m +++ b/drawFixation.m @@ -1,20 +1,20 @@ function drawFixation(cfg) % Define the parameters of the fixation cross in `cfg` and `expParameters` - + switch cfg.fixation.type case 'cross' - + smooth = 1; - + Screen('DrawLines', ... cfg.screen.win, ... cfg.fixation.allCoords, ... cfg.fixation.lineWidthPix, ... cfg.fixation.color, ... [cfg.screen.center(1) cfg.screen.center(2)], smooth); - + case 'dot' - + % Draw gap around fixation of 20% the size Screen('FillOval', ... cfg.screen.win, ... @@ -22,7 +22,7 @@ function drawFixation(cfg) CenterRect( ... [0 0 repmat(1.2 * cfg.fixation.widthPix, 1, 2)], ... cfg.screen.winRect)); - + % Draw fixation Screen('FillOval', ... cfg.screen.win, ... @@ -30,10 +30,9 @@ function drawFixation(cfg) CenterRect( ... [0 0 repmat(cfg.fixation.widthPix, 1, 2)], ... cfg.screen.winRect)); - - + case 'bestFixation' - + % Code adapted from: % What is the best fixation target? % DOI 10.1016/j.visres.2012.10.012 @@ -45,20 +44,20 @@ function drawFixation(cfg) CenterRect( ... [0 0 repmat(1.5 * cfg.fixation.widthPix, 1, 2)], ... cfg.screen.winRect)); - + Screen('FillOval', ... cfg.screen.win, ... cfg.color.black, ... cfg.fixation.outerOval, ... cfg.fixation.widthPix); - + Screen('DrawLines', ... cfg.screen.win, ... cfg.fixation.allCoords, ... cfg.fixation.widthPix / 3, ... cfg.color.white, ... [cfg.screen.center(1) cfg.screen.center(2)]); - + Screen('FillOval', ... cfg.screen.win, ... cfg.color.black, ... @@ -66,5 +65,5 @@ function drawFixation(cfg) cfg.fixation.widthPix / 3); end - + end diff --git a/initFixation.m b/initFixation.m index d4ff10a..ae1cdce 100644 --- a/initFixation.m +++ b/initFixation.m @@ -1,39 +1,39 @@ function cfg = initFixation(cfg) - + % Convert some values from degrees to pixels cfg.fixation = degToPix('width', cfg.fixation, cfg); cfg.fixation = degToPix('xDisplacement', cfg.fixation, cfg); cfg.fixation = degToPix('yDisplacement', cfg.fixation, cfg); - + % Prepare fixation cross xLine = [-cfg.fixation.widthPix cfg.fixation.widthPix 0 0] / 2; yLine = [0 0 -cfg.fixation.widthPix cfg.fixation.widthPix] / 2; - + cfg.fixation.xCoords = xLine + cfg.fixation.xDisplacementPix; cfg.fixation.yCoords = yLine + cfg.fixation.yDisplacementPix; - + cfg.fixation.allCoords = [cfg.fixation.xCoords; cfg.fixation.yCoords]; - + switch cfg.fixation.type - + case 'bestFixation' - + % Code adapted from: % What is the best fixation target? % DOI 10.1016/j.visres.2012.10.012 - - cfg.fixation.outerOval = [... - cfg.screen.center(1)-cfg.fixation.widthPix/2, ... - cfg.screen.center(2)-cfg.fixation.widthPix/2, ... - cfg.screen.center(1)+cfg.fixation.widthPix/2, ... - cfg.screen.center(2)+cfg.fixation.widthPix/2]; - - cfg.fixation.innerOval = [... - cfg.screen.center(1)-cfg.fixation.widthPix/6, ... - cfg.screen.center(2)-cfg.fixation.widthPix/6, ... - cfg.screen.center(1)+cfg.fixation.widthPix/6, ... - cfg.screen.center(2)+cfg.fixation.widthPix/6]; - + + cfg.fixation.outerOval = [ ... + cfg.screen.center(1) - cfg.fixation.widthPix / 2, ... + cfg.screen.center(2) - cfg.fixation.widthPix / 2, ... + cfg.screen.center(1) + cfg.fixation.widthPix / 2, ... + cfg.screen.center(2) + cfg.fixation.widthPix / 2]; + + cfg.fixation.innerOval = [ ... + cfg.screen.center(1) - cfg.fixation.widthPix / 6, ... + cfg.screen.center(2) - cfg.fixation.widthPix / 6, ... + cfg.screen.center(1) + cfg.fixation.widthPix / 6, ... + cfg.screen.center(2) + cfg.fixation.widthPix / 6]; + end - + end diff --git a/src/aperture/apertureTexture.m b/src/aperture/apertureTexture.m index 4aec258..d3c8f2b 100644 --- a/src/aperture/apertureTexture.m +++ b/src/aperture/apertureTexture.m @@ -1,13 +1,13 @@ function [cfg, thisEvent] = apertureTexture(action, cfg, thisEvent) - + transparent = [0 0 0 0]; - + switch action - + case 'init' - + switch cfg.aperture.type - + case 'circle' % we take the screen height as maximum aperture width if not % specified. @@ -15,11 +15,11 @@ cfg.aperture.width = cfg.screen.winRect(4) / cfg.screen.ppd; end cfg.aperture = degToPix('width', cfg.aperture, cfg); - + case 'ring' - + % Set parameters for rings - if strcmp(cfg.aperture.type ,'ring') + if strcmp(cfg.aperture.type, 'ring') % scale of outer ring (exceeding screen until % inner ring reaches window boarder) cfg.ring.maxEcc = ... @@ -35,60 +35,60 @@ (cfg.ring.maxEcc + exp(1))) ; end end - + cfg.aperture.texture = Screen('MakeTexture', cfg.screen.win, ... cfg.color.background(1) * ones(cfg.screen.winRect([4 3]))); - + case 'make' - + xCenter = cfg.screen.center(1); yCenter = cfg.screen.center(2); - + switch cfg.aperture.type - + case 'none' - + Screen('Fillrect', cfg.aperture.texture, transparent); - + case 'circle' - + diameter = cfg.aperture.widthPix; - + if isfield(cfg.aperture, 'xPosPix') xCenter = cfg.screen.center(1) + cfg.aperture.xPosPix; end if isfield(cfg.aperture, 'yPosPix') yCenter = cfg.screen.center(2) + cfg.aperture.yPosPix; end - + Screen('FillOval', cfg.aperture.texture, transparent, ... CenterRectOnPoint([0 0 repmat(diameter, 1, 2)], ... xCenter, yCenter)); - + case 'ring' - + % expansion speed is log over eccentricity [cfg] = eccenLogSpeed(cfg, thisEvent.time); - + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); - + Screen('FillOval', cfg.aperture.texture, transparent, ... CenterRectOnPoint( ... [0 0 repmat(cfg.ring.outerRimPix, 1, 2)], ... xCenter, yCenter)); - + Screen('FillOval', cfg.aperture.texture, [cfg.color.background 255], ... CenterRectOnPoint( ... [0 0 repmat(cfg.ring.innerRimPix, 1, 2)], ... xCenter, yCenter)); - + case 'wedge' - + cycleDuration = cfg.mri.repetitionTime * cfg.volsPerCycle; - + % Update angle for rotation of background and for apperture for wedge switch cfg.direction - + case '+' thisEvent.angle = 90 - ... cfg.aperture.width / 2 + ... @@ -97,32 +97,31 @@ thisEvent.angle = 90 - ... cfg.aperture.width / 2 - ... (thisEvent.time / cycleDuration) * 360; - + end - + Screen('Fillrect', cfg.aperture.texture, cfg.color.background); - + Screen('FillArc', cfg.aperture.texture, transparent, ... CenterRect( ... [0 0 repmat(cfg.stimRect(4), 1, 2)], ... cfg.screen.winRect), ... thisEvent.angle, ... % start angle cfg.aperture.width); % arc angle - - + otherwise - + error('unknown aperture type: %s.', cfg.aperture.type); - + end - + case 'draw' - + Screen('DrawTexture', cfg.screen.win, cfg.aperture.texture); - + % Screen('DrawTexture', cfg.screen.win, apertureTexture, ... % cfg.screen.winRect, cfg.screen.winRect, current.apertureAngle - 90); - + end - + end diff --git a/src/aperture/eccenLogSpeed.m b/src/aperture/eccenLogSpeed.m index 1d35604..df00b83 100644 --- a/src/aperture/eccenLogSpeed.m +++ b/src/aperture/eccenLogSpeed.m @@ -16,7 +16,7 @@ case '+' % current visual angle linear in time outerRimVA = 0 + mod(time, cycleDuration) / cycleDuration * maxEcc; - % ensure some foveal stimulation at beginning (which is hidden by + % ensure some foveal stimulation at beginning (which is hidden by % fixation cross otherwise) if outerRimVA < cfg.fixation.size outerRimVA = cfg.fixation.size + .1; @@ -47,7 +47,7 @@ innerRimVA = 0; end - % in pixel + % in pixel innerRimPix = innerRimVA * cfg.screen.ppd; % update cfg that we are about to return diff --git a/src/dot/computeCartCoord.m b/src/dot/computeCartCoord.m index cfe7a64..8aacd65 100644 --- a/src/dot/computeCartCoord.m +++ b/src/dot/computeCartCoord.m @@ -1,7 +1,7 @@ function cartesianCoordinates = computeCartCoord(positions, cfg) cartesianCoordinates = ... - [positions(:,1) + cfg.dot.matrixWidth, ... % x coordinate - positions(:,2) + cfg.dot.matrixWidth]; % y coordinate - -% cartesianCoordinates = positions; -end \ No newline at end of file + [positions(:, 1) + cfg.dot.matrixWidth, ... % x coordinate + positions(:, 2) + cfg.dot.matrixWidth]; % y coordinate + + % cartesianCoordinates = positions; +end diff --git a/src/dot/computeRadialMotionDirection.m b/src/dot/computeRadialMotionDirection.m index f655b29..ef47ed8 100644 --- a/src/dot/computeRadialMotionDirection.m +++ b/src/dot/computeRadialMotionDirection.m @@ -1,13 +1,12 @@ function angleMotion = computeRadialMotionDirection(cfg, dots) - + cartesianCoordinates = computeCartCoord(dots.positions, cfg); - + [angleMotion, ~] = cart2pol(cartesianCoordinates(:, 1), cartesianCoordinates(:, 2)); angleMotion = angleMotion / pi * 180; - + if dots.direction == -666 angleMotion = angleMotion - 180; end - -end +end diff --git a/src/dot/generateNewDotPositions.m b/src/dot/generateNewDotPositions.m index a60f739..92bf28f 100644 --- a/src/dot/generateNewDotPositions.m +++ b/src/dot/generateNewDotPositions.m @@ -1,5 +1,5 @@ function newPositions = generateNewDotPositions(cfg, dotNumber) - + newPositions = rand(dotNumber, 2) * cfg.dot.matrixWidth; - -end \ No newline at end of file + +end diff --git a/src/dot/initDots.m b/src/dot/initDots.m index 8529285..80efb43 100644 --- a/src/dot/initDots.m +++ b/src/dot/initDots.m @@ -64,5 +64,3 @@ dots.speedPixPerFrame = speedPixPerFrame; end - - diff --git a/src/dot/reseedDots.m b/src/dot/reseedDots.m index fe2a128..19dfa5e 100644 --- a/src/dot/reseedDots.m +++ b/src/dot/reseedDots.m @@ -1,22 +1,20 @@ function dots = reseedDots(dots, cfg) - + fixationWidthPix = 0; if isfield(cfg.fixation, 'widthPix') fixationWidthPix = cfg.fixation.widthPix; end - + cartesianCoordinates = computeCartCoord(dots.positions, cfg); [~, radius] = cart2pol(cartesianCoordinates(:, 1), cartesianCoordinates(:, 2)); - - % Create a logical vector to detect any dot that has: % - an xy position inferior to 0 % - an xy position superior to winWidth % - has exceeded its liftime % - is on the fixation cross % - has been been picked to be killed - + N = any([ ... dots.positions > cfg.dot.matrixWidth, ... dots.positions < 0, ... @@ -24,20 +22,20 @@ radius - cfg.dot.sizePix < fixationWidthPix / 2, ... rand(cfg.dot.number, 1) < cfg.dot.proportionKilledPerFrame, ... ], 2) ; - + % If there is any such dot we relocate it to a new random position % and change its lifetime to 1 if any(N) - + dots.positions(N, :) = generateNewDotPositions(cfg, sum(N)); - + dots = setDotDirection(cfg, dots); - + [horVector, vertVector] = decomposeMotion(dots.directionAllDots); dots.speeds = [horVector, vertVector] * dots.speedPixPerFrame; - + dots.time(N, 1) = 1; - + end - -end \ No newline at end of file + +end diff --git a/src/dot/setDotDirection.m b/src/dot/setDotDirection.m index a5e53c2..0d46dd2 100644 --- a/src/dot/setDotDirection.m +++ b/src/dot/setDotDirection.m @@ -4,7 +4,7 @@ % Coherent dots directionAllDots(dots.isSignal) = dots.direction; - + if strcmp(cfg.design.motionType, 'radial') angleMotion = computeRadialMotionDirection(cfg, dots); directionAllDots(dots.isSignal) = angleMotion; @@ -13,7 +13,7 @@ % Random direction for the non coherent dots directionAllDots(~dots.isSignal) = rand(sum(~dots.isSignal), 1) * 360; directionAllDots = rem(directionAllDots, 360); - + dots.directionAllDots = directionAllDots; -end \ No newline at end of file +end diff --git a/src/dot/updateDots.m b/src/dot/updateDots.m index ddeb970..329a81a 100644 --- a/src/dot/updateDots.m +++ b/src/dot/updateDots.m @@ -9,7 +9,7 @@ error(errorStruct); end - + % Add one frame to the dot lifetime to each dot dots.time = dots.time + 1; diff --git a/tests/test_reseedDots.m b/tests/test_reseedDots.m index 5935b81..c8ee8d8 100644 --- a/tests/test_reseedDots.m +++ b/tests/test_reseedDots.m @@ -7,39 +7,39 @@ end function test_reseedDotsBasic() - + dots.lifeTime = 100; cfg.screen.winWidth = 2000; cfg.dot.number = 5; cfg.dot.sizePix = 20; cfg.dot.proportionKilledPerFrame = 0; - + cfg.fixation.widthPix = 20; - + dots.positions = [ ... 694, 100; % OK 490, 2043; % out of frame - -104, 392; % out of frame + -104, 392; % out of frame 492, 402; % OK 1000, 1000; % on the fixation cross ]; - - dots.time = [... + + dots.time = [ ... 6; ... OK 4 ; ... OK 56; ... OK 300; ... % exceeded its life time 50]; % OK - + dots = reseedDots(dots, cfg); - - reseeded = [... + + reseeded = [ ... 6; 1; 1; 1; 1]; - - assertEqual(reseeded, dots.time) - -end \ No newline at end of file + + assertEqual(reseeded, dots.time); + +end From 0fed4ce4f77c61c8fa0d0f781cb7897f0f0cba80 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 4 Aug 2020 17:34:57 +0200 Subject: [PATCH 6/6] update continuous integration --- .travis.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1ff89b8..eb1a738 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,27 +5,10 @@ dist: bionic cache: apt: true # only works with Pro version -env: - global: - - OCTFLAGS="--no-gui --no-window-system --silent" - before_install: - - travis_retry sudo apt-get -y -qq update - - travis_retry sudo apt-get -y install octave - - travis_retry sudo apt-get -y install liboctave-dev - cd .. && git clone https://github.com/florianschanda/miss_hit.git && export PATH=$PATH:`pwd`/miss_hit && cd CPP_PTB -install: - - octave $OCTFLAGS --eval "addpath (pwd); savepath ();" - -before_script: - # Change current directory - - cd tests - jobs: include: - - stage: "Tests and linter" - name: "Unit Tests" # names the first job - script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))" - - script: cd .. && mh_style `pwd` + - script: mh_style `pwd` name: "miss_hit linter" # names the second job \ No newline at end of file